From 6a89177a597b852f5655fced01f90d8c24f26018 Mon Sep 17 00:00:00 2001 From: Mark Maas Date: Thu, 14 Feb 2013 12:45:08 +0100 Subject: [PATCH] Added support for AIX 5.3 and 6.1 A collegue of mine has added basix AIX support to the setup, user and group modules. We have tested this on AIX 5.3 and 6.1 and it works "as advertised" --- library/group | 42 ++++++++++++++ library/setup | 112 ++++++++++++++++++++++++++++++------ library/user | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+), 17 deletions(-) diff --git a/library/group b/library/group index 8f3dec41fa..f297cbaea5 100644 --- a/library/group +++ b/library/group @@ -164,6 +164,48 @@ class SunOS(Group): # =========================================== +class AIX(Group): + """ + This is a AIX Group manipulation class. + + This overrides the following methods from the generic class:- + - group_del() + - group_add() + - group_mod() + """ + + platform = 'AIX' + distribution = None + GROUPFILE = '/etc/group' + + def group_del(self): + cmd = [self.module.get_bin_path('rmgroup', True), self.name] + return self.execute_command(cmd) + + def group_add(self, **kwargs): + cmd = [self.module.get_bin_path('mkgroup', True)] + for key in kwargs: + if key == 'gid' and kwargs[key] is not None: + cmd.append('id='+kwargs[key]) + elif key == 'system' and kwargs[key] == 'yes': + cmd.append('-a') + cmd.append(self.name) + return self.execute_command(cmd) + + def group_mod(self, **kwargs): + cmd = [self.module.get_bin_path('chgroup', True)] + info = self.group_info() + for key in kwargs: + if key == 'gid': + if kwargs[key] is not None and info[2] != int(kwargs[key]): + cmd.append('id='+kwargs[key]) + if len(cmd) == 1: + return (None, '', '') + cmd.append(self.name) + return self.execute_command(cmd) + +# =========================================== + def main(): module = AnsibleModule( argument_spec = dict( diff --git a/library/setup b/library/setup index 791bb06721..465f2ff538 100644 --- a/library/setup +++ b/library/setup @@ -119,27 +119,39 @@ class Facts(object): self.facts['architecture'] = self.facts['machine'] if self.facts['system'] == 'Linux': self.get_distribution_facts() + elif self.facts['system'] == 'AIX': + rc, out, err = module.run_command("/usr/sbin/bootinfo -p") + data = out.split('\n') + self.facts['architecture'] = data[0] + # platform.dist() is deprecated in 2.6 # in 2.6 and newer, you should use platform.linux_distribution() def get_distribution_facts(self): - dist = platform.dist() - self.facts['distribution'] = dist[0].capitalize() or 'NA' - self.facts['distribution_version'] = dist[1] or 'NA' - self.facts['distribution_release'] = dist[2] or 'NA' - # Try to handle the exceptions now ... - for (path, name) in Facts.OSDIST_DICT.items(): - if os.path.exists(path): - if self.facts['distribution'] == 'Fedora': - pass - elif name == 'RedHat': - data = get_file_content(path) - if 'Red Hat' in data: - self.facts['distribution'] = name - else: - self.facts['distribution'] = data.split()[0] - else: - self.facts['distribution'] = name + if self.facts['system'] == 'AIX': + self.facts['distribution'] = 'AIX' + rc, out, err = module.run_command("/usr/bin/oslevel") + data = out.split('.') + self.facts['distribution_version'] = data[0] + self.facts['distribution_release'] = data[1] + else: + dist = platform.dist() + self.facts['distribution'] = dist[0].capitalize() or 'NA' + self.facts['distribution_version'] = dist[1] or 'NA' + self.facts['distribution_release'] = dist[2] or 'NA' + # Try to handle the exceptions now ... + for (path, name) in Facts.OSDIST_DICT.items(): + if os.path.exists(path): + if self.facts['distribution'] == 'Fedora': + pass + elif name == 'RedHat': + data = get_file_content(path) + if 'Red Hat' in data: + self.facts['distribution'] = name + else: + self.facts['distribution'] = data.split()[0] + else: + self.facts['distribution'] = name def get_cmdline(self): data = get_file_content('/proc/cmdline') @@ -602,6 +614,72 @@ class FreeBSDHardware(Hardware): if s: self.facts['devices'][d.group(1)].append(s.group(1)) +class AIX(Hardware): + """ + AIX-specific subclass of Hardware. Defines memory and CPU facts: + - memfree_mb + - memtotal_mb + - swapfree_mb + - swaptotal_mb + - processor (a list) + - processor_cores + - processor_count + """ + platform = 'AIX' + + def __init__(self): + Hardware.__init__(self) + + def populate(self): + self.get_cpu_facts() + self.get_memory_facts() + self.get_dmi_facts() + return self.facts + + def get_cpu_facts(self): + self.facts['processor'] = [] + rc, out, err = module.run_command("/usr/sbin/lsattr -El proc0 -a type") + data = out.split(' ') + self.facts['processor'] = data[1] + rc, out, err = module.run_command("/usr/sbin/lsattr -El proc0 -a smt_threads") + data = out.split(' ') + self.facts['processor_cores'] = int(data[1]) + rc, out, err = module.run_command("/usr/sbin/lsdev -Cc processor") + i = 0 + for line in out.split('\n'): + data = line.split(':') + if 'Available' in line: + i += 1 + self.facts['processor_count'] = int(i) + + def get_memory_facts(self): + pagesize = 4096 + rc, out, err = module.run_command("/usr/bin/vmstat -v") + for line in out.split('\n'): + data = line.split() + if 'memory pages' in line: + pagecount = long(data[0]) + if 'free pages' in line: + freecount = long(data[0]) + self.facts['memtotal_mb'] = pagesize * pagecount / 1024 / 1024 + self.facts['memfree_mb'] = pagesize * freecount / 1024 / 1024 + # Get swapinfo. swapinfo output looks like: + # Device 1M-blocks Used Avail Capacity + # /dev/ada0p3 314368 0 314368 0% + # + rc, out, err = module.run_command("/usr/sbin/lsps -s") + lines = out.split('\n') + data = lines[1].split() + swaptotal_mb = long(data[0].rstrip('MB')) + percused = int(data[1].rstrip('%')) + self.facts['swaptotal_mb'] = swaptotal_mb + self.facts['swapfree_mb'] = long(swaptotal_mb * ( 100 - percused ) / 100) + + def get_dmi_facts(self): + rc, out, err = module.run_command("/usr/sbin/lsattr -El sys0 -a fwversion") + data = out.split() + self.facts['firmware_version'] = data[1].strip('IBM,') + class Network(Facts): """ This is a generic Network subclass of Facts. This should be further diff --git a/library/user b/library/user index 5f08a1b100..7e057cdee6 100644 --- a/library/user +++ b/library/user @@ -807,6 +807,159 @@ class SunOS(User): # =========================================== +class AIX(User): + """ + This is a AIX User manipulation class. + + This overrides the following methods from the generic class:- + - create_user() + - remove_user() + - modify_user() + """ + + platform = 'AIX' + distribution = None + SHADOWFILE = '/etc/security/passwd' + + def remove_user(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 create_user_useradd(self, command_name='useradd'): + cmd = [self.module.get_bin_path(command_name, True)] + + if self.uid is not None: + cmd.append('-u') + cmd.append(self.uid) + + 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: + for g in self.groups.split(','): + if not self.group_exists(g): + self.module.fail_json(msg="Group %s does not exist" % (g)) + cmd.append('-G') + cmd.append(self.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.createhome: + cmd.append('-m') + + if self.system: + cmd.append('-r') + + cmd.append(self.name) + (rc, out, err) = self.execute_command(cmd) + + # set password with chpasswd + if self.password is not None: + cmd = [] + cmd.append('echo "'+self.name+':'+self.password+'" |') + cmd.append(self.module.get_bin_path('chpasswd', True)) + cmd.append('-e') + cmd.append('-c') + self.execute_command(' '.join(cmd)) + + return (rc, out, err) + + def modify_user_usermod(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.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 = self.groups.split(',') + for g in groups: + if not self.group_exists(g): + self.module.fail_json(msg="Group %s does not exist" % (g)) + + group_diff = set(sorted(current_groups)).symmetric_difference(set(sorted(groups))) + groups_need_mod = False + + if group_diff: + if self.append: + for g in groups: + if g in group_diff: + groups.extend(current_groups) + set(groups) + groups_need_mod = True + break + else: + groups_need_mod = True + + if groups_need_mod: + 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) + + + # skip if no changes to be made + if len(cmd) == 1: + (rc, out, err) = (None, '', '') + else: + cmd.append(self.name) + (rc, out, err) = self.execute_command(cmd) + + # set password with chpasswd + if self.password is not None and info[1] != self.password: + cmd = [] + cmd.append('echo "'+self.name+':'+self.password+'" |') + cmd.append(self.module.get_bin_path('chpasswd', True)) + cmd.append('-e') + cmd.append('-c') + (rc2, out2, err2) = self.execute_command(' '.join(cmd)) + else: + (rc2, out2, err2) = (None, '', '') + + if rc != None: + return (rc, out+out2, err+err2) + else: + return (rc2, out+out2, err+err2) + +# =========================================== + def main(): ssh_defaults = { 'bits': '2048',