Merge branch 'devel' into unevaluated-vars

pull/3066/head
Lorin Hochstein 11 years ago
commit cbb1808f05

@ -130,6 +130,7 @@ the variable is still registered for the host, with the attribute skipped: True.
* improved FreeBSD, NetBSD and Solaris facts * improved FreeBSD, NetBSD and Solaris facts
* debug module always outputs data without having to specify -v * debug module always outputs data without having to specify -v
* fix for sysctl module creating new keys (must specify checks=none) * fix for sysctl module creating new keys (must specify checks=none)
* NetBSD and OpenBSD support for the user and groups modules
1.1 "Mean Street" -- 4/2/2013 1.1 "Mean Street" -- 4/2/2013

@ -52,7 +52,7 @@ endif
# RPM build parameters # RPM build parameters
RPMSPECDIR= packaging/rpm RPMSPECDIR= packaging/rpm
RPMSPEC = $(RPMSPECDIR)/ansible.spec RPMSPEC = $(RPMSPECDIR)/ansible.spec
RPMDIST = $(shell rpm --eval '%dist') RPMDIST = $(shell rpm --eval '%{?dist}')
RPMRELEASE = 1 RPMRELEASE = 1
ifeq ($(OFFICIAL),) ifeq ($(OFFICIAL),)
RPMRELEASE = 0.git$(DATE) RPMRELEASE = 0.git$(DATE)

@ -102,6 +102,8 @@ def main(args):
parser.add_option('-C', '--checkout', dest='checkout', parser.add_option('-C', '--checkout', dest='checkout',
default="HEAD", default="HEAD",
help='Branch/Tag/Commit to checkout. Defaults to HEAD.') help='Branch/Tag/Commit to checkout. Defaults to HEAD.')
parser.add_option('-i', '--inventory-file', dest='inventory',
help="specify inventory host file")
options, args = parser.parse_args(args) options, args = parser.parse_args(args)
if not options.dest: if not options.dest:
@ -115,9 +117,12 @@ def main(args):
now = datetime.datetime.now() now = datetime.datetime.now()
print >>sys.stderr, now.strftime("Starting ansible-pull at %F %T") print >>sys.stderr, now.strftime("Starting ansible-pull at %F %T")
inv_opts = 'localhost,'
limit_opts = 'localhost:%s:127.0.0.1' % socket.getfqdn() limit_opts = 'localhost:%s:127.0.0.1' % socket.getfqdn()
git_opts = "repo=%s dest=%s version=%s" % (options.url, options.dest, options.checkout) git_opts = "repo=%s dest=%s version=%s" % (options.url, options.dest, options.checkout)
cmd = 'ansible all -c local --limit "%s" -m git -a "%s"' % (limit_opts, git_opts) cmd = 'ansible all -c local -i "%s" --limit "%s" -m git -a "%s"' % (
inv_opts, limit_opts, git_opts
)
rc = _run(cmd) rc = _run(cmd)
if rc != 0: if rc != 0:
return rc return rc
@ -129,6 +134,8 @@ def main(args):
return 1 return 1
cmd = 'ansible-playbook -c local --limit "%s" %s' % (limit_opts, playbook) cmd = 'ansible-playbook -c local --limit "%s" %s' % (limit_opts, playbook)
if options.inventory:
cmd += ' -i "%s"' % options.inventory
os.chdir(options.dest) os.chdir(options.dest)
rc = _run(cmd) rc = _run(cmd)

@ -2,12 +2,12 @@
.\" Title: ansible-playbook .\" Title: ansible-playbook
.\" Author: [see the "AUTHOR" section] .\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/> .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: 05/29/2013 .\" Date: 06/03/2013
.\" Manual: System administration commands .\" Manual: System administration commands
.\" Source: Ansible 1.2 .\" Source: Ansible 1.2
.\" Language: English .\" Language: English
.\" .\"
.TH "ANSIBLE\-PLAYBOOK" "1" "05/29/2013" "Ansible 1\&.2" "System administration commands" .TH "ANSIBLE\-PLAYBOOK" "1" "06/03/2013" "Ansible 1\&.2" "System administration commands"
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
.\" * set default formatting .\" * set default formatting
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
@ -57,7 +57,7 @@ search path to load modules from\&. The default is
.PP .PP
\fB\-e\fR \fIVARS\fR, \fB\-\-extra\-vars=\fR\fIVARS\fR \fB\-e\fR \fIVARS\fR, \fB\-\-extra\-vars=\fR\fIVARS\fR
.RS 4 .RS 4
Extra variables to inject into a playbook, in key=value key=value format\&. Extra variables to inject into a playbook, in key=value key=value format or as quoted JSON (hashes and arrays)\&.
.RE .RE
.PP .PP
\fB\-f\fR \fINUM\fR, \fB\-\-forks=\fR\fINUM\fR \fB\-f\fR \fINUM\fR, \fB\-\-forks=\fR\fINUM\fR

@ -12,7 +12,7 @@ ansible-pull - set up a remote copy of ansible on each managed node
SYNOPSIS SYNOPSIS
-------- --------
ansible -d DEST -U URL [ -C CHECKOUT ] ansible -d DEST -U URL [ -C CHECKOUT ] [ -i INVENTORY ] [ <filename.yml> ]
DESCRIPTION DESCRIPTION
@ -35,6 +35,17 @@ ansible-pull runs would be an excellent way to gather and analyze
remote logs from ansible-pull. remote logs from ansible-pull.
OPTIONAL ARGUMENT
-----------------
*filename.yml*::
The name of one the YAML format files to run as an ansible playbook. This can
be a relative path within the git checkout. If not provided, ansible-pull
will look for a playbook based on the host's fully-qualified domain name and
finally a playbook named *local.yml*.
OPTIONS OPTIONS
------- -------
@ -50,6 +61,14 @@ URL of git repository to clone.
Branch/Tag/Commit to checkout. Defaults to 'HEAD'. Branch/Tag/Commit to checkout. Defaults to 'HEAD'.
*-i* 'PATH', *--inventory=*'PATH'::
The 'PATH' to the inventory hosts file. This can be a relative path within
the git checkout.
*--purge*::
Purge the git checkout after the playbook is run.
AUTHOR AUTHOR

@ -88,7 +88,7 @@ Put this into a crontab as appropriate to make calls from your Ansible master se
Pull Configuration Pull Configuration
++++++++++++++++++ ++++++++++++++++++
For some the delay between refreshing host information and acting on that host information (i.e. running Ansible tasks against the hosts) may be too long. This may be the case in such scenarios where EC2 AutoScaling is being used to scalethe number of instances as a result of a particular event. Such an event may require that hosts come online and are configured as soon as possible (even a 1 minute delay may be undesirable). Its possible to pre-bake machine images which contain the necessary ansible-pull script and components to pull and run a playbook via git. The machine images could be configured to run ansible-pull upon boot as part of the bootstrapping procedure. For some the delay between refreshing host information and acting on that host information (i.e. running Ansible tasks against the hosts) may be too long. This may be the case in such scenarios where EC2 AutoScaling is being used to scale the number of instances as a result of a particular event. Such an event may require that hosts come online and are configured as soon as possible (even a 1 minute delay may be undesirable). Its possible to pre-bake machine images which contain the necessary ansible-pull script and components to pull and run a playbook via git. The machine images could be configured to run ansible-pull upon boot as part of the bootstrapping procedure.
More information on pull-mode playbooks can be found `here <http://ansible.cc/docs/playbooks2.html#pull-mode-playbooks>`_. More information on pull-mode playbooks can be found `here <http://ansible.cc/docs/playbooks2.html#pull-mode-playbooks>`_.
@ -127,22 +127,22 @@ And in your playbook::
hosts: /chroot/path hosts: /chroot/path
Pending Information Pending Information
=================== ```````````````````
In the future look here for more topics. In the future look here for more topics.
Using Ansible's S3 module Using Ansible's S3 module
````````````````````````` +++++++++++++++++++++++++
these modules are documented on the module page, more walk throughs coming soon these modules are documented on the module page, more walk throughs coming soon
Using Ansible's Elastic Load Balancer Support Using Ansible's Elastic Load Balancer Support
````````````````````````````````````````````` +++++++++++++++++++++++++++++++++++++++++++++
these modules are documented on the module page, more walk throughs coming soon these modules are documented on the module page, more walk throughs coming soon
Using Ansible's Cloud Formation Module Using Ansible's Cloud Formation Module
`````````````````````````````````````` ++++++++++++++++++++++++++++++++++++++
these modules are documented on the module page, more walk throughs coming soon these modules are documented on the module page, more walk throughs coming soon

@ -48,6 +48,9 @@ class InventoryDirectory(object):
# this file is generated on a failed playbook and should only be # this file is generated on a failed playbook and should only be
# used when run specifically # used when run specifically
continue continue
# Skip hidden files
if i.startswith('.') and not i.startswith('./'):
continue
# These are things inside of an inventory basedir # These are things inside of an inventory basedir
if i in ("host_vars", "group_vars", "vars_plugins"): if i in ("host_vars", "group_vars", "vars_plugins"):
continue continue
@ -62,15 +65,22 @@ class InventoryDirectory(object):
# This takes a lot of code because we can't directly use any of the objects, as they have to blend # This takes a lot of code because we can't directly use any of the objects, as they have to blend
for name, group in parser.groups.iteritems(): for name, group in parser.groups.iteritems():
if name not in self.groups: if name not in self.groups:
self.groups[name] = Group(name) self.groups[name] = group
for k, v in group.get_variables().iteritems(): else:
self.groups[name].set_variable(k, v) # group is already there, copy variables
# note: depth numbers on duplicates may be bogus
for k, v in group.get_variables().iteritems():
self.groups[name].set_variable(k, v)
for host in group.get_hosts(): for host in group.get_hosts():
if host.name not in self.hosts: if host.name not in self.hosts:
self.hosts[host.name] = Host(host.name) self.hosts[host.name] = host
for k, v in host.vars.iteritems(): else:
self.hosts[host.name].set_variable(k, v) # host is already there, copy variables
# note: depth numbers on duplicates may be bogus
for k, v in host.vars.iteritems():
self.hosts[host.name].set_variable(k, v)
self.groups[name].add_host(self.hosts[host.name]) self.groups[name].add_host(self.hosts[host.name])
# This needs to be a second loop to ensure all the parent groups exist # This needs to be a second loop to ensure all the parent groups exist
for name, group in parser.groups.iteritems(): for name, group in parser.groups.iteritems():
for ancestor in group.get_ancestors(): for ancestor in group.get_ancestors():

@ -35,9 +35,12 @@ class Group(object):
if self == group: if self == group:
raise Exception("can't add group to itself") raise Exception("can't add group to itself")
self.child_groups.append(group)
group.depth = max([self.depth+1, group.depth]) # don't add if it's already there
group.parent_groups.append(self) if not group in self.child_groups:
self.child_groups.append(group)
group.depth = max([self.depth+1, group.depth])
group.parent_groups.append(self)
def add_host(self, host): def add_host(self, host):

@ -57,12 +57,12 @@ class ActionModule(object):
found = False found = False
for fn in inject.get('first_available_file'): for fn in inject.get('first_available_file'):
fn_orig = fn fn_orig = fn
fn = template.template(self.runner.basedir, fn, inject) fnt = template.template(self.runner.basedir, fn, inject)
fn = utils.path_dwim(self.runner.basedir, fn) fnd = utils.path_dwim(self.runner.basedir, fnt)
if not os.path.exists(fn) and '_original_file' in inject: if not os.path.exists(fnd) and '_original_file' in inject:
fn = utils.path_dwim_relative(inject['_original_file'], 'files', fn_orig, self.runner.basedir, check=False) fnd = utils.path_dwim_relative(inject['_original_file'], 'files', fnt, self.runner.basedir, check=False)
if os.path.exists(fn): if os.path.exists(fnd):
source = fn source = fnd
found = True found = True
break break
if not found: if not found:

@ -60,7 +60,7 @@ class ActionModule(object):
fnt = template.template(self.runner.basedir, fn, inject) fnt = template.template(self.runner.basedir, fn, inject)
fnd = utils.path_dwim(self.runner.basedir, fnt) fnd = utils.path_dwim(self.runner.basedir, fnt)
if not os.path.exists(fnd) and '_original_file' in inject: if not os.path.exists(fnd) and '_original_file' in inject:
fnd = utils.path_dwim_relative(inject['_original_file'], 'templates', fn_orig, self.runner.basedir, check=False) fnd = utils.path_dwim_relative(inject['_original_file'], 'templates', fnt, self.runner.basedir, check=False)
if os.path.exists(fnd): if os.path.exists(fnd):
source = fnd source = fnd
found = True found = True

@ -228,25 +228,111 @@ class FreeBsdGroup(Group):
cmd = [self.module.get_bin_path('pw', True), 'groupdel', self.name] cmd = [self.module.get_bin_path('pw', True), 'groupdel', self.name]
return self.execute_command(cmd) return self.execute_command(cmd)
def group_add(self,**kwargs): def group_add(self, **kwargs):
cmd = [self.module.get_bin_path('pw', True), 'groupadd', self.name] cmd = [self.module.get_bin_path('pw', True), 'groupadd', self.name]
if self.gid is not None: if self.gid is not None:
cmd.append('-g %d' % int(self.gid)) cmd.append('-g %d' % int(self.gid))
return self.execute_command(cmd) return self.execute_command(cmd)
def group_mod(self,**kwargs): def group_mod(self, **kwargs):
cmd = [self.module.get_bin_path('pw', True), 'groupmod', self.name] cmd = [self.module.get_bin_path('pw', True), 'groupmod', self.name]
info = self.group_info() info = self.group_info()
cmd_len = len(cmd) cmd_len = len(cmd)
if self.gid is not None and int(self.gid) != info[2]: if self.gid is not None and int(self.gid) != info[2]:
cmd.append('-g %d' % int(self.gid)) cmd.append('-g %d' % int(self.gid))
# modify the group if cmd will do anything # modify the group if cmd will do anything
if cmd_len != len(cmd): if cmd_len != len(cmd):
if self.module.check_mode:
return (True, '', '')
return self.execute_command(cmd) return self.execute_command(cmd)
return (None, '', '') return (None, '', '')
# =========================================== # ===========================================
class OpenBsdGroup(Group):
"""
This is a OpenBSD Group manipulation class.
This overrides the following methods from the generic class:-
- group_del()
- group_add()
- group_mod()
"""
platform = 'OpenBSD'
distribution = None
GROUPFILE = '/etc/group'
def group_del(self):
cmd = [self.module.get_bin_path('groupdel', True), self.name]
return self.execute_command(cmd)
def group_add(self, **kwargs):
cmd = [self.module.get_bin_path('groupadd', True)]
if self.gid is not None:
cmd.append('-g')
cmd.append('%d' % int(self.gid))
cmd.append(self.name)
return self.execute_command(cmd)
def group_mod(self, **kwargs):
cmd = [self.module.get_bin_path('groupmod', True)]
info = self.group_info()
cmd_len = len(cmd)
if self.gid is not None and int(self.gid) != info[2]:
cmd.append('-g')
cmd.append('%d' % int(self.gid))
if len(cmd) == 1:
return (None, '', '')
if self.module.check_mode:
return (True, '', '')
cmd.append(self.name)
return self.execute_command(cmd)
# ===========================================
class NetBsdGroup(Group):
"""
This is a NetBSD Group manipulation class.
This overrides the following methods from the generic class:-
- group_del()
- group_add()
- group_mod()
"""
platform = 'NetBSD'
distribution = None
GROUPFILE = '/etc/group'
def group_del(self):
cmd = [self.module.get_bin_path('groupdel', True), self.name]
return self.execute_command(cmd)
def group_add(self, **kwargs):
cmd = [self.module.get_bin_path('groupadd', True)]
if self.gid is not None:
cmd.append('-g')
cmd.append('%d' % int(self.gid))
cmd.append(self.name)
return self.execute_command(cmd)
def group_mod(self, **kwargs):
cmd = [self.module.get_bin_path('groupmod', True)]
info = self.group_info()
cmd_len = len(cmd)
if self.gid is not None and int(self.gid) != info[2]:
cmd.append('-g')
cmd.append('%d' % int(self.gid))
if len(cmd) == 1:
return (None, '', '')
if self.module.check_mode:
return (True, '', '')
cmd.append(self.name)
return self.execute_command(cmd)
# ===========================================
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec = dict(

@ -106,6 +106,10 @@ options:
description: description:
- When used with C(state=absent), behavior is as with - When used with C(state=absent), behavior is as with
C(userdel --force). C(userdel --force).
login_class:
required: false
description:
- Optionally sets the user's login class for FreeBSD, OpenBSD and NetBSD systems.
remove: remove:
required: false required: false
default: "no" default: "no"
@ -215,6 +219,7 @@ class User(object):
self.remove = module.params['remove'] self.remove = module.params['remove']
self.createhome = module.params['createhome'] self.createhome = module.params['createhome']
self.system = module.params['system'] self.system = module.params['system']
self.login_class = module.params['login_class']
self.append = module.params['append'] self.append = module.params['append']
self.sshkeygen = module.params['generate_ssh_key'] self.sshkeygen = module.params['generate_ssh_key']
self.ssh_bits = module.params['ssh_key_bits'] self.ssh_bits = module.params['ssh_key_bits']
@ -554,7 +559,7 @@ class FreeBsdUser(User):
self.module.get_bin_path('pw', True), self.module.get_bin_path('pw', True),
'useradd', 'useradd',
'-n', '-n',
self.name self.name,
] ]
if self.uid is not None: if self.uid is not None:
@ -590,6 +595,10 @@ class FreeBsdUser(User):
cmd.append('-s') cmd.append('-s')
cmd.append(self.shell) cmd.append(self.shell)
if self.login_class is not None:
cmd.append('-L')
cmd.append(self.login_class)
# system cannot be handled currently - should we error if its requested? # system cannot be handled currently - should we error if its requested?
# create the user # create the user
(rc, out, err) = self.execute_command(cmd) (rc, out, err) = self.execute_command(cmd)
@ -645,6 +654,10 @@ class FreeBsdUser(User):
cmd.append('-s') cmd.append('-s')
cmd.append(self.shell) cmd.append(self.shell)
if self.login_class is not None:
cmd.append('-L')
cmd.append(self.login_class)
if self.groups is not None: if self.groups is not None:
current_groups = self.user_group_membership() current_groups = self.user_group_membership()
groups = self.get_groups_set() groups = self.get_groups_set()
@ -690,6 +703,308 @@ class FreeBsdUser(User):
# =========================================== # ===========================================
class OpenBSDUser(User):
"""
This is a OpenBSD User manipulation class.
Main differences are that OpenBSD:-
- has no concept of "system" account.
- has no force delete user
This overrides the following methods from the generic class:-
- create_user()
- remove_user()
- modify_user()
"""
platform = 'OpenBSD'
distribution = None
SHADOWFILE = '/etc/master.passwd'
def create_user(self):
cmd = [self.module.get_bin_path('useradd', True)]
if self.uid is not None:
cmd.append('-u')
cmd.append(self.uid)
if self.non_unique:
cmd.append('-o')
if self.group is not None:
if not self.group_exists(self.group):
self.module.fail_json(msg="Group %s does not exist" % self.group)
cmd.append('-g')
cmd.append(self.group)
if self.groups is not None:
groups = self.get_groups_set()
cmd.append('-G')
cmd.append(','.join(groups))
if self.comment is not None:
cmd.append('-c')
cmd.append(self.comment)
if self.home is not None:
cmd.append('-d')
cmd.append(self.home)
if self.shell is not None:
cmd.append('-s')
cmd.append(self.shell)
if self.login_class is not None:
cmd.append('-L')
cmd.append(self.login_class)
if self.password is not None:
cmd.append('-p')
cmd.append(self.password)
if self.createhome:
cmd.append('-m')
cmd.append(self.name)
return self.execute_command(cmd)
def remove_user_userdel(self):
cmd = [self.module.get_bin_path('userdel', True)]
if self.remove:
cmd.append('-r')
cmd.append(self.name)
return self.execute_command(cmd)
def modify_user(self):
cmd = [self.module.get_bin_path('usermod', True)]
info = self.user_info()
if self.uid is not None and info[2] != int(self.uid):
cmd.append('-u')
cmd.append(self.uid)
if self.non_unique:
cmd.append('-o')
if self.group is not None:
if not self.group_exists(self.group):
self.module.fail_json(msg="Group %s does not exist" % self.group)
ginfo = self.group_info(self.group)
if info[3] != ginfo[2]:
cmd.append('-g')
cmd.append(self.group)
if self.groups is not None:
current_groups = self.user_group_membership()
groups_need_mod = False
groups_option = '-G'
groups = []
if self.groups == '':
if current_groups and not self.append:
groups_need_mod = True
else:
groups = self.get_groups_set()
group_diff = set(current_groups).symmetric_difference(groups)
if group_diff:
if self.append:
for g in groups:
if g in group_diff:
groups_option = '-S'
groups_need_mod = True
break
else:
groups_need_mod = True
if groups_need_mod:
cmd.append(groups_option)
cmd.append(','.join(groups))
if self.comment is not None and info[4] != self.comment:
cmd.append('-c')
cmd.append(self.comment)
if self.home is not None and info[5] != self.home:
cmd.append('-d')
cmd.append(self.home)
if self.shell is not None and info[6] != self.shell:
cmd.append('-s')
cmd.append(self.shell)
if self.login_class is not None:
cmd.append('-L')
cmd.append(self.login_class)
if self.password is not None and info[1] != self.password:
cmd.append('-p')
cmd.append(self.password)
# skip if no changes to be made
if len(cmd) == 1:
return (None, '', '')
elif self.module.check_mode:
return (0, '', '')
cmd.append(self.name)
return self.execute_command(cmd)
# ===========================================
class NetBSDUser(User):
"""
This is a NetBSD User manipulation class.
Main differences are that NetBSD:-
- has no concept of "system" account.
- has no force delete user
This overrides the following methods from the generic class:-
- create_user()
- remove_user()
- modify_user()
"""
platform = 'NetBSD'
distribution = None
SHADOWFILE = '/etc/master.passwd'
def create_user(self):
cmd = [self.module.get_bin_path('useradd', True)]
if self.uid is not None:
cmd.append('-u')
cmd.append(self.uid)
if self.non_unique:
cmd.append('-o')
if self.group is not None:
if not self.group_exists(self.group):
self.module.fail_json(msg="Group %s does not exist" % self.group)
cmd.append('-g')
cmd.append(self.group)
if self.groups is not None:
groups = self.get_groups_set()
if len(groups) > 16:
self.module.fail_json(msg="Too many groups (%d) NetBSD allows for 16 max." % len(groups))
cmd.append('-G')
cmd.append(','.join(groups))
if self.comment is not None:
cmd.append('-c')
cmd.append(self.comment)
if self.home is not None:
cmd.append('-d')
cmd.append(self.home)
if self.shell is not None:
cmd.append('-s')
cmd.append(self.shell)
if self.login_class is not None:
cmd.append('-L')
cmd.append(self.login_class)
if self.password is not None:
cmd.append('-p')
cmd.append(self.password)
if self.createhome:
cmd.append('-m')
cmd.append(self.name)
return self.execute_command(cmd)
def remove_user_userdel(self):
cmd = [self.module.get_bin_path('userdel', True)]
if self.remove:
cmd.append('-r')
cmd.append(self.name)
return self.execute_command(cmd)
def modify_user(self):
cmd = [self.module.get_bin_path('usermod', True)]
info = self.user_info()
if self.uid is not None and info[2] != int(self.uid):
cmd.append('-u')
cmd.append(self.uid)
if self.non_unique:
cmd.append('-o')
if self.group is not None:
if not self.group_exists(self.group):
self.module.fail_json(msg="Group %s does not exist" % self.group)
ginfo = self.group_info(self.group)
if info[3] != ginfo[2]:
cmd.append('-g')
cmd.append(self.group)
if self.groups is not None:
current_groups = self.user_group_membership()
groups_need_mod = False
groups = []
if self.groups == '':
if current_groups and not self.append:
groups_need_mod = True
else:
groups = self.get_groups_set()
group_diff = set(current_groups).symmetric_difference(groups)
if group_diff:
if self.append:
for g in groups:
if g in group_diff:
groups = set(current_groups).union(groups)
groups_need_mod = True
break
else:
groups_need_mod = True
if groups_need_mod:
if len(groups) > 16:
self.module.fail_json(msg="Too many groups (%d) NetBSD allows for 16 max." % len(groups))
cmd.append('-G')
cmd.append(','.join(groups))
if self.comment is not None and info[4] != self.comment:
cmd.append('-c')
cmd.append(self.comment)
if self.home is not None and info[5] != self.home:
cmd.append('-d')
cmd.append(self.home)
if self.shell is not None and info[6] != self.shell:
cmd.append('-s')
cmd.append(self.shell)
if self.login_class is not None:
cmd.append('-L')
cmd.append(self.login_class)
if self.password is not None and info[1] != self.password:
cmd.append('-p')
cmd.append(self.password)
# skip if no changes to be made
if len(cmd) == 1:
return (None, '', '')
elif self.module.check_mode:
return (0, '', '')
cmd.append(self.name)
return self.execute_command(cmd)
# ===========================================
class SunOS(User): class SunOS(User):
""" """
This is a SunOS User manipulation class - The main difference between This is a SunOS User manipulation class - The main difference between
@ -1024,6 +1339,7 @@ def main():
home=dict(default=None, type='str'), home=dict(default=None, type='str'),
shell=dict(default=None, type='str'), shell=dict(default=None, type='str'),
password=dict(default=None, type='str'), password=dict(default=None, type='str'),
login_class=dict(default=None, type='str'),
# following options are specific to userdel # following options are specific to userdel
force=dict(default='no', type='bool'), force=dict(default='no', type='bool'),
remove=dict(default='no', type='bool'), remove=dict(default='no', type='bool'),

@ -293,13 +293,15 @@ class TestInventory(unittest.TestCase):
'inventory_hostname_short': 'zeus', 'inventory_hostname_short': 'zeus',
'group_names': ['greek', 'major-god']} 'group_names': ['greek', 'major-god']}
def test_dir_inventory(self): # test disabled as needs to be updated to model desired behavior
inventory = self.dir_inventory() #
vars = inventory.get_variables('zeus') #def test_dir_inventory(self):
# inventory = self.dir_inventory()
print "VARS=%s" % vars # vars = inventory.get_variables('zeus')
#
assert vars == {'inventory_hostname': 'zeus', # print "VARS=%s" % vars
'inventory_hostname_short': 'zeus', #
'group_names': ['greek', 'major-god', 'ungrouped'], # assert vars == {'inventory_hostname': 'zeus',
'var_a': '1#2'} # 'inventory_hostname_short': 'zeus',
# 'group_names': ['greek', 'major-god', 'ungrouped'],
# 'var_a': '1#2'}

Loading…
Cancel
Save