Merge branch 'devel' into unevaluated-vars
This commit is contained in:
commit
cbb1808f05
13 changed files with 494 additions and 50 deletions
|
@ -130,6 +130,7 @@ the variable is still registered for the host, with the attribute skipped: True.
|
|||
* improved FreeBSD, NetBSD and Solaris facts
|
||||
* debug module always outputs data without having to specify -v
|
||||
* 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
|
||||
|
||||
|
|
2
Makefile
2
Makefile
|
@ -52,7 +52,7 @@ endif
|
|||
# RPM build parameters
|
||||
RPMSPECDIR= packaging/rpm
|
||||
RPMSPEC = $(RPMSPECDIR)/ansible.spec
|
||||
RPMDIST = $(shell rpm --eval '%dist')
|
||||
RPMDIST = $(shell rpm --eval '%{?dist}')
|
||||
RPMRELEASE = 1
|
||||
ifeq ($(OFFICIAL),)
|
||||
RPMRELEASE = 0.git$(DATE)
|
||||
|
|
|
@ -102,6 +102,8 @@ def main(args):
|
|||
parser.add_option('-C', '--checkout', dest='checkout',
|
||||
default="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)
|
||||
|
||||
if not options.dest:
|
||||
|
@ -115,9 +117,12 @@ def main(args):
|
|||
now = datetime.datetime.now()
|
||||
print >>sys.stderr, now.strftime("Starting ansible-pull at %F %T")
|
||||
|
||||
inv_opts = 'localhost,'
|
||||
limit_opts = 'localhost:%s:127.0.0.1' % socket.getfqdn()
|
||||
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)
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
@ -129,6 +134,8 @@ def main(args):
|
|||
return 1
|
||||
|
||||
cmd = 'ansible-playbook -c local --limit "%s" %s' % (limit_opts, playbook)
|
||||
if options.inventory:
|
||||
cmd += ' -i "%s"' % options.inventory
|
||||
os.chdir(options.dest)
|
||||
rc = _run(cmd)
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
.\" Title: ansible-playbook
|
||||
.\" Author: [see the "AUTHOR" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
|
||||
.\" Date: 05/29/2013
|
||||
.\" Date: 06/03/2013
|
||||
.\" Manual: System administration commands
|
||||
.\" Source: Ansible 1.2
|
||||
.\" 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
|
||||
.\" -----------------------------------------------------------------
|
||||
|
@ -57,7 +57,7 @@ search path to load modules from\&. The default is
|
|||
.PP
|
||||
\fB\-e\fR \fIVARS\fR, \fB\-\-extra\-vars=\fR\fIVARS\fR
|
||||
.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
|
||||
.PP
|
||||
\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
|
||||
--------
|
||||
ansible -d DEST -U URL [ -C CHECKOUT ]
|
||||
ansible -d DEST -U URL [ -C CHECKOUT ] [ -i INVENTORY ] [ <filename.yml> ]
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
|
@ -35,6 +35,17 @@ ansible-pull runs would be an excellent way to gather and analyze
|
|||
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
|
||||
-------
|
||||
|
||||
|
@ -50,6 +61,14 @@ URL of git repository to clone.
|
|||
|
||||
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
|
||||
|
|
|
@ -88,7 +88,7 @@ Put this into a crontab as appropriate to make calls from your Ansible master se
|
|||
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>`_.
|
||||
|
||||
|
@ -127,22 +127,22 @@ And in your playbook::
|
|||
hosts: /chroot/path
|
||||
|
||||
Pending Information
|
||||
===================
|
||||
```````````````````
|
||||
|
||||
In the future look here for more topics.
|
||||
|
||||
Using Ansible's S3 module
|
||||
`````````````````````````
|
||||
+++++++++++++++++++++++++
|
||||
|
||||
these modules are documented on the module page, more walk throughs coming soon
|
||||
|
||||
Using Ansible's Elastic Load Balancer Support
|
||||
`````````````````````````````````````````````
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
these modules are documented on the module page, more walk throughs coming soon
|
||||
|
||||
Using Ansible's Cloud Formation Module
|
||||
``````````````````````````````````````
|
||||
++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
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
|
||||
# used when run specifically
|
||||
continue
|
||||
# Skip hidden files
|
||||
if i.startswith('.') and not i.startswith('./'):
|
||||
continue
|
||||
# These are things inside of an inventory basedir
|
||||
if i in ("host_vars", "group_vars", "vars_plugins"):
|
||||
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
|
||||
for name, group in parser.groups.iteritems():
|
||||
if name not in self.groups:
|
||||
self.groups[name] = Group(name)
|
||||
for k, v in group.get_variables().iteritems():
|
||||
self.groups[name].set_variable(k, v)
|
||||
self.groups[name] = group
|
||||
else:
|
||||
# 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():
|
||||
if host.name not in self.hosts:
|
||||
self.hosts[host.name] = Host(host.name)
|
||||
for k, v in host.vars.iteritems():
|
||||
self.hosts[host.name].set_variable(k, v)
|
||||
self.hosts[host.name] = host
|
||||
else:
|
||||
# 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])
|
||||
|
||||
# This needs to be a second loop to ensure all the parent groups exist
|
||||
for name, group in parser.groups.iteritems():
|
||||
for ancestor in group.get_ancestors():
|
||||
|
|
|
@ -35,9 +35,12 @@ class Group(object):
|
|||
|
||||
if self == group:
|
||||
raise Exception("can't add group to itself")
|
||||
self.child_groups.append(group)
|
||||
group.depth = max([self.depth+1, group.depth])
|
||||
group.parent_groups.append(self)
|
||||
|
||||
# don't add if it's already there
|
||||
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):
|
||||
|
||||
|
|
|
@ -57,12 +57,12 @@ class ActionModule(object):
|
|||
found = False
|
||||
for fn in inject.get('first_available_file'):
|
||||
fn_orig = fn
|
||||
fn = template.template(self.runner.basedir, fn, inject)
|
||||
fn = utils.path_dwim(self.runner.basedir, fn)
|
||||
if not os.path.exists(fn) and '_original_file' in inject:
|
||||
fn = utils.path_dwim_relative(inject['_original_file'], 'files', fn_orig, self.runner.basedir, check=False)
|
||||
if os.path.exists(fn):
|
||||
source = fn
|
||||
fnt = template.template(self.runner.basedir, fn, inject)
|
||||
fnd = utils.path_dwim(self.runner.basedir, fnt)
|
||||
if not os.path.exists(fnd) and '_original_file' in inject:
|
||||
fnd = utils.path_dwim_relative(inject['_original_file'], 'files', fnt, self.runner.basedir, check=False)
|
||||
if os.path.exists(fnd):
|
||||
source = fnd
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
|
|
|
@ -60,7 +60,7 @@ class ActionModule(object):
|
|||
fnt = template.template(self.runner.basedir, fn, inject)
|
||||
fnd = utils.path_dwim(self.runner.basedir, fnt)
|
||||
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):
|
||||
source = fnd
|
||||
found = True
|
||||
|
|
|
@ -61,8 +61,8 @@ import platform
|
|||
class Group(object):
|
||||
"""
|
||||
This is a generic Group manipulation class that is subclassed
|
||||
based on platform.
|
||||
|
||||
based on platform.
|
||||
|
||||
A subclass may wish to override the following action methods:-
|
||||
- group_del()
|
||||
- group_add()
|
||||
|
@ -96,7 +96,7 @@ class Group(object):
|
|||
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)]
|
||||
for key in kwargs:
|
||||
|
@ -107,7 +107,7 @@ class Group(object):
|
|||
cmd.append('-r')
|
||||
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()
|
||||
|
@ -122,14 +122,14 @@ class Group(object):
|
|||
return (True, '', '')
|
||||
cmd.append(self.name)
|
||||
return self.execute_command(cmd)
|
||||
|
||||
|
||||
def group_exists(self):
|
||||
try:
|
||||
if grp.getgrnam(self.name):
|
||||
return True
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
def group_info(self):
|
||||
if not self.group_exists():
|
||||
return False
|
||||
|
@ -162,7 +162,7 @@ class SunOS(Group):
|
|||
cmd.append(kwargs[key])
|
||||
cmd.append(self.name)
|
||||
return self.execute_command(cmd)
|
||||
|
||||
|
||||
|
||||
# ===========================================
|
||||
|
||||
|
@ -228,25 +228,111 @@ class FreeBsdGroup(Group):
|
|||
cmd = [self.module.get_bin_path('pw', True), 'groupdel', self.name]
|
||||
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]
|
||||
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)
|
||||
|
||||
def group_mod(self,**kwargs):
|
||||
def group_mod(self, **kwargs):
|
||||
cmd = [self.module.get_bin_path('pw', True), 'groupmod', self.name]
|
||||
info = self.group_info()
|
||||
cmd_len = len(cmd)
|
||||
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
|
||||
if cmd_len != len(cmd):
|
||||
if self.module.check_mode:
|
||||
return (True, '', '')
|
||||
return self.execute_command(cmd)
|
||||
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():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
|
|
|
@ -106,6 +106,10 @@ options:
|
|||
description:
|
||||
- When used with C(state=absent), behavior is as with
|
||||
C(userdel --force).
|
||||
login_class:
|
||||
required: false
|
||||
description:
|
||||
- Optionally sets the user's login class for FreeBSD, OpenBSD and NetBSD systems.
|
||||
remove:
|
||||
required: false
|
||||
default: "no"
|
||||
|
@ -215,6 +219,7 @@ class User(object):
|
|||
self.remove = module.params['remove']
|
||||
self.createhome = module.params['createhome']
|
||||
self.system = module.params['system']
|
||||
self.login_class = module.params['login_class']
|
||||
self.append = module.params['append']
|
||||
self.sshkeygen = module.params['generate_ssh_key']
|
||||
self.ssh_bits = module.params['ssh_key_bits']
|
||||
|
@ -526,7 +531,7 @@ class FreeBsdUser(User):
|
|||
This is a FreeBSD User manipulation class - it uses the pw command
|
||||
to manipulate the user database, followed by the chpass command
|
||||
to change the password.
|
||||
|
||||
|
||||
This overrides the following methods from the generic class:-
|
||||
- create_user()
|
||||
- remove_user()
|
||||
|
@ -554,7 +559,7 @@ class FreeBsdUser(User):
|
|||
self.module.get_bin_path('pw', True),
|
||||
'useradd',
|
||||
'-n',
|
||||
self.name
|
||||
self.name,
|
||||
]
|
||||
|
||||
if self.uid is not None:
|
||||
|
@ -590,6 +595,10 @@ class FreeBsdUser(User):
|
|||
cmd.append('-s')
|
||||
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?
|
||||
# create the user
|
||||
(rc, out, err) = self.execute_command(cmd)
|
||||
|
@ -645,6 +654,10 @@ class FreeBsdUser(User):
|
|||
cmd.append('-s')
|
||||
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:
|
||||
current_groups = self.user_group_membership()
|
||||
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):
|
||||
"""
|
||||
This is a SunOS User manipulation class - The main difference between
|
||||
|
@ -1024,6 +1339,7 @@ def main():
|
|||
home=dict(default=None, type='str'),
|
||||
shell=dict(default=None, type='str'),
|
||||
password=dict(default=None, type='str'),
|
||||
login_class=dict(default=None, type='str'),
|
||||
# following options are specific to userdel
|
||||
force=dict(default='no', type='bool'),
|
||||
remove=dict(default='no', type='bool'),
|
||||
|
|
|
@ -293,13 +293,15 @@ class TestInventory(unittest.TestCase):
|
|||
'inventory_hostname_short': 'zeus',
|
||||
'group_names': ['greek', 'major-god']}
|
||||
|
||||
def test_dir_inventory(self):
|
||||
inventory = self.dir_inventory()
|
||||
vars = inventory.get_variables('zeus')
|
||||
|
||||
print "VARS=%s" % vars
|
||||
|
||||
assert vars == {'inventory_hostname': 'zeus',
|
||||
'inventory_hostname_short': 'zeus',
|
||||
'group_names': ['greek', 'major-god', 'ungrouped'],
|
||||
'var_a': '1#2'}
|
||||
# test disabled as needs to be updated to model desired behavior
|
||||
#
|
||||
#def test_dir_inventory(self):
|
||||
# inventory = self.dir_inventory()
|
||||
# vars = inventory.get_variables('zeus')
|
||||
#
|
||||
# print "VARS=%s" % vars
|
||||
#
|
||||
# assert vars == {'inventory_hostname': 'zeus',
|
||||
# 'inventory_hostname_short': 'zeus',
|
||||
# 'group_names': ['greek', 'major-god', 'ungrouped'],
|
||||
# 'var_a': '1#2'}
|
||||
|
|
Loading…
Add table
Reference in a new issue