diff --git a/docsite/rst/glossary.rst b/docsite/rst/glossary.rst index d05481a621e..74ff5d50e7f 100644 --- a/docsite/rst/glossary.rst +++ b/docsite/rst/glossary.rst @@ -71,8 +71,7 @@ Facts Facts are simply things that are discovered about remote nodes. While they can be used in playbooks and templates just like variables, facts are things that are inferred, rather than set. Facts are automatically discovered by Ansible when running plays by executing the internal 'setup' module on the remote nodes. You never have to call the setup module explicitly, it just runs, but it can be disabled to save time if it is -not needed. For the convenience of users who are switching from other configuration management systems, the fact module will also pull in facts from the 'ohai' and 'facter' -tools if they are installed, which are fact libraries from Chef and Puppet, respectively. +not needed or you can tell ansible to collect only a subset of the full facts via the `gather_subset:` option. For the convenience of users who are switching from other configuration management systems, the fact module will also pull in facts from the 'ohai' and 'facter' tools if they are installed, which are fact libraries from Chef and Puppet, respectively. (These may also be disabled via `gather_subset:`) Filter Plugin +++++++++++++ @@ -399,7 +398,7 @@ An optional conditional statement attached to a task that is used to determine i Van Halen +++++++++ -For no particular reason, other than the fact that Michael really likes them, all Ansible releases are codenamed after Van Halen songs. There is no preference given to David Lee Roth vs. Sammy Lee Hagar-era songs, and instrumentals are also allowed. It is unlikely that there will ever be a Jump release, but a Van Halen III codename release is possible. You never know. +For no particular reason, other than the fact that Michael really likes them, all Ansible 0.x and 1.x releases are codenamed after Van Halen songs. There is no preference given to David Lee Roth vs. Sammy Lee Hagar-era songs, and instrumentals are also allowed. It is unlikely that there will ever be a Jump release, but a Van Halen III codename release is possible. You never know. Vars (Variables) ++++++++++++++++ diff --git a/docsite/rst/intro_configuration.rst b/docsite/rst/intro_configuration.rst index 0bc6fbfad7b..419eeaf5f9d 100644 --- a/docsite/rst/intro_configuration.rst +++ b/docsite/rst/intro_configuration.rst @@ -353,6 +353,32 @@ This option can be useful for those wishing to save fact gathering time. Both 's gathering = smart +.. versionadded:: 2.1 + +You can specify a subset of gathered facts using the following option:: + + gather_subset = all + +:all: gather all subsets (the default) +:network: gather network facts +:hardware: gather hardware facts (longest facts to retrieve) +:virtual: gather facts about virtual machines hosted on the machine +:ohai: gather facts from ohai +:facter: gather facts from facter + +You can combine them using a comma separated list (ex: network,virtual,facter) + +You can also disable specific subsets by prepending with a `!` like this:: + + # Don't gather hardware facts, facts from chef's ohai or puppet's facter + gather_subset = !hardware,!ohai,!facter + +A set of basic facts are always collected no matter which additional subsets +are selected. If you want to collect the minimal amount of facts, use +`!all`:: + + gather_subset = !all + hash_behaviour ============== @@ -367,7 +393,7 @@ official examples repos do not use this setting:: The valid values are either 'replace' (the default) or 'merge'. -.. versionadded: '2.0' +.. versionadded:: 2.0 If you want to merge hashes without changing the global settings, use the `combine` filter described in :doc:`playbooks_filters`. @@ -585,7 +611,7 @@ The directory will be created if it does not already exist. roles_path ========== -.. versionadded: '1.4' +.. versionadded:: 1.4 The roles path indicate additional directories beyond the 'roles/' subdirectory of a playbook project to search to find Ansible roles. For instance, if there was a source control repository of common roles and a different repository of playbooks, you might diff --git a/examples/ansible.cfg b/examples/ansible.cfg index 8465ccca4bb..fe60bc71aa0 100644 --- a/examples/ansible.cfg +++ b/examples/ansible.cfg @@ -31,6 +31,18 @@ # explicit - do not gather by default, must say gather_facts: True #gathering = implicit +# by default retrieve all facts subsets +# all - gather all subsets +# network - gather min and network facts +# hardware - gather hardware facts (longest facts to retrieve) +# virtual - gather min and virtual facts +# facter - import facts from facter +# ohai - import facts from ohai +# You can combine them using comma (ex: network,virtual) +# You can negate them using ! (ex: !hardware,!facter,!ohai) +# A minimal set of facts is always gathered. +#gather_subset = all + # additional paths to search for roles in, colon separated #roles_path = /etc/ansible/roles diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 4def61e1aa0..365bda04d06 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -156,6 +156,7 @@ DEFAULT_PRIVATE_ROLE_VARS = get_config(p, DEFAULTS, 'private_role_vars', 'ANSIBL DEFAULT_JINJA2_EXTENSIONS = get_config(p, DEFAULTS, 'jinja2_extensions', 'ANSIBLE_JINJA2_EXTENSIONS', None) DEFAULT_EXECUTABLE = get_config(p, DEFAULTS, 'executable', 'ANSIBLE_EXECUTABLE', '/bin/sh') DEFAULT_GATHERING = get_config(p, DEFAULTS, 'gathering', 'ANSIBLE_GATHERING', 'implicit').lower() +DEFAULT_GATHER_SUBSET = get_config(p, DEFAULTS, 'gather_subset', 'ANSIBLE_GATHER_SUBSET', 'all').lower() DEFAULT_LOG_PATH = get_config(p, DEFAULTS, 'log_path', 'ANSIBLE_LOG_PATH', '', ispath=True) DEFAULT_FORCE_HANDLERS = get_config(p, DEFAULTS, 'force_handlers', 'ANSIBLE_FORCE_HANDLERS', False, boolean=True) DEFAULT_INVENTORY_IGNORE = get_config(p, DEFAULTS, 'inventory_ignore_extensions', 'ANSIBLE_INVENTORY_IGNORE', ["~", ".orig", ".bak", ".ini", ".cfg", ".retry", ".pyc", ".pyo"], islist=True) diff --git a/lib/ansible/executor/play_iterator.py b/lib/ansible/executor/play_iterator.py index 83abb40bbc1..e47d88ed7f4 100644 --- a/lib/ansible/executor/play_iterator.py +++ b/lib/ansible/executor/play_iterator.py @@ -151,11 +151,20 @@ class PlayIterator: self._play = play self._blocks = [] + # Default options to gather + gather_subset = C.DEFAULT_GATHER_SUBSET + + # Retrieve subset to gather + if self._play.gather_subset is not None: + gather_subset = self._play.gather_subset + setup_block = Block(play=self._play) setup_task = Task(block=setup_block) setup_task.action = 'setup' setup_task.tags = ['always'] - setup_task.args = {} + setup_task.args = { + 'gather_subset': gather_subset, + } setup_task.set_loader(self._play._loader) setup_block.block = [setup_task] diff --git a/lib/ansible/module_utils/facts.py b/lib/ansible/module_utils/facts.py index 835ebd74d80..4612816f53d 100644 --- a/lib/ansible/module_utils/facts.py +++ b/lib/ansible/module_utils/facts.py @@ -159,10 +159,14 @@ class Facts(object): { 'path' : '/usr/local/sbin/pkg', 'name' : 'pkgng' }, ] - def __init__(self, load_on_init=True): + def __init__(self, module, load_on_init=True): + self.module = module self.facts = {} - + ### TODO: Eventually, these should all get moved to populate(). But + # some of the values are currently being used by other subclasses (for + # instance, os_family and distribution). Have to sort out what to do + # about those first. if load_on_init: self.get_platform_facts() self.get_distribution_facts() @@ -215,14 +219,14 @@ class Facts(object): elif self.facts['system'] == 'AIX': # Attempt to use getconf to figure out architecture # fall back to bootinfo if needed - if module.get_bin_path('getconf'): - rc, out, err = module.run_command([module.get_bin_path('getconf'), - 'MACHINE_ARCHITECTURE']) + getconf_bin = self.module.get_bin_path('getconf') + if getconf_bin: + rc, out, err = self.module.run_command([getconf_bin, 'MACHINE_ARCHITECTURE']) data = out.split('\n') self.facts['architecture'] = data[0] else: - rc, out, err = module.run_command([module.get_bin_path('bootinfo'), - '-p']) + bootinfo_bin = self.module.get_bin_path('bootinfo') + rc, out, err = self.module.run_command([bootinfo_bin, '-p']) data = out.split('\n') self.facts['architecture'] = data[0] elif self.facts['system'] == 'OpenBSD': @@ -230,7 +234,7 @@ class Facts(object): def get_local_facts(self): - fact_path = module.params.get('fact_path', None) + fact_path = self.module.params.get('fact_path', None) if not fact_path or not os.path.exists(fact_path): return @@ -243,7 +247,7 @@ class Facts(object): # try to read it as json first # if that fails read it with ConfigParser # if that fails, skip it - rc, out, err = module.run_command(fn) + rc, out, err = self.module.run_command(fn) else: out = get_file_content(fn, default='') @@ -294,20 +298,20 @@ class Facts(object): # as it's much cleaner than this massive if-else if self.facts['system'] == 'AIX': self.facts['distribution'] = 'AIX' - rc, out, err = module.run_command("/usr/bin/oslevel") + rc, out, err = self.module.run_command("/usr/bin/oslevel") data = out.split('.') self.facts['distribution_version'] = data[0] self.facts['distribution_release'] = data[1] elif self.facts['system'] == 'HP-UX': self.facts['distribution'] = 'HP-UX' - rc, out, err = module.run_command("/usr/sbin/swlist |egrep 'HPUX.*OE.*[AB].[0-9]+\.[0-9]+'", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/sbin/swlist |egrep 'HPUX.*OE.*[AB].[0-9]+\.[0-9]+'", use_unsafe_shell=True) data = re.search('HPUX.*OE.*([AB].[0-9]+\.[0-9]+)\.([0-9]+).*', out) if data: self.facts['distribution_version'] = data.groups()[0] self.facts['distribution_release'] = data.groups()[1] elif self.facts['system'] == 'Darwin': self.facts['distribution'] = 'MacOSX' - rc, out, err = module.run_command("/usr/bin/sw_vers -productVersion") + rc, out, err = self.module.run_command("/usr/bin/sw_vers -productVersion") data = out.split()[-1] self.facts['distribution_version'] = data elif self.facts['system'] == 'FreeBSD': @@ -321,7 +325,7 @@ class Facts(object): elif self.facts['system'] == 'OpenBSD': self.facts['distribution'] = 'OpenBSD' self.facts['distribution_release'] = platform.release() - rc, out, err = module.run_command("/sbin/sysctl -n kern.version") + rc, out, err = self.module.run_command("/sbin/sysctl -n kern.version") match = re.match('OpenBSD\s[0-9]+.[0-9]+-(\S+)\s.*', out) if match: self.facts['distribution_version'] = match.groups()[0] @@ -411,7 +415,7 @@ class Facts(object): self.facts['distribution_release'] = ora_prefix + data break - uname_rc, uname_out, uname_err = module.run_command(['uname', '-v']) + uname_rc, uname_out, uname_err = self.module.run_command(['uname', '-v']) distribution_version = None if 'SmartOS' in data: self.facts['distribution'] = 'SmartOS' @@ -577,7 +581,7 @@ class Facts(object): # try various forms of querying pid 1 proc_1 = get_file_content('/proc/1/comm') if proc_1 is None: - rc, proc_1, err = module.run_command("ps -p 1 -o comm|tail -n 1", use_unsafe_shell=True) + rc, proc_1, err = self.module.run_command("ps -p 1 -o comm|tail -n 1", use_unsafe_shell=True) else: proc_1 = os.path.basename(proc_1) @@ -610,7 +614,7 @@ class Facts(object): elif self.facts['system'] == 'Linux': if self._check_systemd(): self.facts['service_mgr'] = 'systemd' - elif module.get_bin_path('initctl') and os.path.exists("/etc/init/"): + elif self.module.get_bin_path('initctl') and os.path.exists("/etc/init/"): self.facts['service_mgr'] = 'upstart' elif os.path.realpath('/sbin/rc') == '/sbin/openrc': self.facts['service_mgr'] = 'openrc' @@ -622,9 +626,9 @@ class Facts(object): self.facts['service_mgr'] = 'service' def get_lsb_facts(self): - lsb_path = module.get_bin_path('lsb_release') + lsb_path = self.module.get_bin_path('lsb_release') if lsb_path: - rc, out, err = module.run_command([lsb_path, "-a"]) + rc, out, err = self.module.run_command([lsb_path, "-a"]) if rc == 0: self.facts['lsb'] = {} for line in out.split('\n'): @@ -732,7 +736,7 @@ class Facts(object): def _check_systemd(self): # tools must be installed - if module.get_bin_path('systemctl'): + if self.module.get_bin_path('systemctl'): # this should show if systemd is the boot init system, if checking init faild to mark as systemd # these mirror systemd's own sd_boot test http://www.freedesktop.org/software/systemd/man/sd_booted.html @@ -844,9 +848,6 @@ class Hardware(Facts): subclass = sc return super(cls, subclass).__new__(subclass, *arguments, **keyword) - def __init__(self): - Facts.__init__(self) - def populate(self): return self.facts @@ -871,9 +872,6 @@ class LinuxHardware(Hardware): # Now we have all of these in a dict structure MEMORY_FACTS = ORIGINAL_MEMORY_FACTS.union(('Buffers', 'Cached', 'SwapCached')) - def __init__(self): - Hardware.__init__(self) - def populate(self): self.get_cpu_facts() self.get_memory_facts() @@ -1057,7 +1055,7 @@ class LinuxHardware(Hardware): else: # Fall back to using dmidecode, if available - dmi_bin = module.get_bin_path('dmidecode') + dmi_bin = self.module.get_bin_path('dmidecode') DMI_DICT = { 'bios_date': 'bios-release-date', 'bios_version': 'bios-version', @@ -1070,7 +1068,7 @@ class LinuxHardware(Hardware): } for (k, v) in DMI_DICT.items(): if dmi_bin is not None: - (rc, out, err) = module.run_command('%s -s %s' % (dmi_bin, v)) + (rc, out, err) = self.module.run_command('%s -s %s' % (dmi_bin, v)) if rc == 0: # Strip out commented lines (specific dmidecode output) thisvalue = ''.join([ line for line in out.split('\n') if not line.startswith('#') ]) @@ -1099,9 +1097,9 @@ class LinuxHardware(Hardware): uuid = uuids[fields[0]] else: uuid = 'NA' - lsblkPath = module.get_bin_path("lsblk") + lsblkPath = self.module.get_bin_path("lsblk") if lsblkPath: - rc, out, err = module.run_command("%s -ln --output UUID %s" % (lsblkPath, fields[0]), use_unsafe_shell=True) + rc, out, err = self.module.run_command("%s -ln --output UUID %s" % (lsblkPath, fields[0]), use_unsafe_shell=True) if rc == 0: uuid = out.strip() @@ -1120,9 +1118,9 @@ class LinuxHardware(Hardware): def get_device_facts(self): self.facts['devices'] = {} - lspci = module.get_bin_path('lspci') + lspci = self.module.get_bin_path('lspci') if lspci: - rc, pcidata, err = module.run_command([lspci, '-D']) + rc, pcidata, err = self.module.run_command([lspci, '-D']) else: pcidata = None @@ -1175,7 +1173,7 @@ class LinuxHardware(Hardware): part['sectorsize'] = get_file_content(part_sysdir + "/queue/logical_block_size") if not part['sectorsize']: part['sectorsize'] = get_file_content(part_sysdir + "/queue/hw_sector_size",512) - part['size'] = module.pretty_bytes((float(part['sectors']) * float(part['sectorsize']))) + part['size'] = self.module.pretty_bytes((float(part['sectors']) * float(part['sectorsize']))) d['partitions'][partname] = part d['rotational'] = get_file_content(sysdir + "/queue/rotational") @@ -1192,7 +1190,7 @@ class LinuxHardware(Hardware): d['sectorsize'] = get_file_content(sysdir + "/queue/logical_block_size") if not d['sectorsize']: d['sectorsize'] = get_file_content(sysdir + "/queue/hw_sector_size",512) - d['size'] = module.pretty_bytes(float(d['sectors']) * float(d['sectorsize'])) + d['size'] = self.module.pretty_bytes(float(d['sectors']) * float(d['sectorsize'])) d['host'] = "" @@ -1227,14 +1225,14 @@ class LinuxHardware(Hardware): def get_lvm_facts(self): """ Get LVM Facts if running as root and lvm utils are available """ - if os.getuid() == 0 and module.get_bin_path('vgs'): + if os.getuid() == 0 and self.module.get_bin_path('vgs'): lvm_util_options = '--noheadings --nosuffix --units g' - vgs_path = module.get_bin_path('vgs') + vgs_path = self.module.get_bin_path('vgs') #vgs fields: VG #PV #LV #SN Attr VSize VFree vgs={} if vgs_path: - rc, vg_lines, err = module.run_command( '%s %s' % (vgs_path, lvm_util_options)) + rc, vg_lines, err = self.module.run_command( '%s %s' % (vgs_path, lvm_util_options)) for vg_line in vg_lines.splitlines(): items = vg_line.split() vgs[items[0]] = {'size_g':items[-2], @@ -1242,12 +1240,12 @@ class LinuxHardware(Hardware): 'num_lvs': items[2], 'num_pvs': items[1]} - lvs_path = module.get_bin_path('lvs') + lvs_path = self.module.get_bin_path('lvs') #lvs fields: #LV VG Attr LSize Pool Origin Data% Move Log Copy% Convert lvs = {} if lvs_path: - rc, lv_lines, err = module.run_command( '%s %s' % (lvs_path, lvm_util_options)) + rc, lv_lines, err = self.module.run_command( '%s %s' % (lvs_path, lvm_util_options)) for lv_line in lv_lines.splitlines(): items = lv_line.split() lvs[items[0]] = {'size_g': items[3], 'vg': items[1]} @@ -1262,9 +1260,6 @@ class SunOSHardware(Hardware): """ platform = 'SunOS' - def __init__(self): - Hardware.__init__(self) - def populate(self): self.get_cpu_facts() self.get_memory_facts() @@ -1277,7 +1272,7 @@ class SunOSHardware(Hardware): def get_cpu_facts(self): physid = 0 sockets = {} - rc, out, err = module.run_command("/usr/bin/kstat cpu_info") + rc, out, err = self.module.run_command("/usr/bin/kstat cpu_info") self.facts['processor'] = [] for line in out.split('\n'): if len(line) < 1: @@ -1318,11 +1313,11 @@ class SunOSHardware(Hardware): self.facts['processor_count'] = len(self.facts['processor']) def get_memory_facts(self): - rc, out, err = module.run_command(["/usr/sbin/prtconf"]) + rc, out, err = self.module.run_command(["/usr/sbin/prtconf"]) for line in out.split('\n'): if 'Memory size' in line: self.facts['memtotal_mb'] = line.split()[2] - rc, out, err = module.run_command("/usr/sbin/swap -s") + rc, out, err = self.module.run_command("/usr/sbin/swap -s") allocated = long(out.split()[1][:-1]) reserved = long(out.split()[5][:-1]) used = long(out.split()[8][:-1]) @@ -1361,9 +1356,6 @@ class OpenBSDHardware(Hardware): platform = 'OpenBSD' DMESG_BOOT = '/var/run/dmesg.boot' - def __init__(self): - Hardware.__init__(self) - def populate(self): self.sysctl = self.get_sysctl() self.get_memory_facts() @@ -1373,7 +1365,7 @@ class OpenBSDHardware(Hardware): return self.facts def get_sysctl(self): - rc, out, err = module.run_command(["/sbin/sysctl", "hw"]) + rc, out, err = self.module.run_command(["/sbin/sysctl", "hw"]) if rc != 0: return dict() sysctl = dict() @@ -1402,7 +1394,7 @@ class OpenBSDHardware(Hardware): # procs memory page disks traps cpu # r b w avm fre flt re pi po fr sr wd0 fd0 int sys cs us sy id # 0 0 0 47512 28160 51 0 0 0 0 0 1 0 116 89 17 0 1 99 - rc, out, err = module.run_command("/usr/bin/vmstat") + rc, out, err = self.module.run_command("/usr/bin/vmstat") if rc == 0: self.facts['memfree_mb'] = long(out.splitlines()[-1].split()[4]) / 1024 self.facts['memtotal_mb'] = long(self.sysctl['hw.usermem']) / 1024 / 1024 @@ -1411,7 +1403,7 @@ class OpenBSDHardware(Hardware): # total: 69268 1K-blocks allocated, 0 used, 69268 available # And for older OpenBSD: # total: 69268k bytes allocated = 0k used, 69268k available - rc, out, err = module.run_command("/sbin/swapctl -sk") + rc, out, err = self.module.run_command("/sbin/swapctl -sk") if rc == 0: swaptrans = maketrans(' ', ' ') data = out.split() @@ -1422,7 +1414,7 @@ class OpenBSDHardware(Hardware): processor = [] dmesg_boot = get_file_content(OpenBSDHardware.DMESG_BOOT) if not dmesg_boot: - rc, dmesg_boot, err = module.run_command("/sbin/dmesg") + rc, dmesg_boot, err = self.module.run_command("/sbin/dmesg") i = 0 for line in dmesg_boot.splitlines(): if line.split(' ', 1)[0] == 'cpu%i:' % i: @@ -1454,9 +1446,6 @@ class FreeBSDHardware(Hardware): platform = 'FreeBSD' DMESG_BOOT = '/var/run/dmesg.boot' - def __init__(self): - Hardware.__init__(self) - def populate(self): self.get_cpu_facts() self.get_memory_facts() @@ -1470,12 +1459,12 @@ class FreeBSDHardware(Hardware): def get_cpu_facts(self): self.facts['processor'] = [] - rc, out, err = module.run_command("/sbin/sysctl -n hw.ncpu") + rc, out, err = self.module.run_command("/sbin/sysctl -n hw.ncpu") self.facts['processor_count'] = out.strip() dmesg_boot = get_file_content(FreeBSDHardware.DMESG_BOOT) if not dmesg_boot: - rc, dmesg_boot, err = module.run_command("/sbin/dmesg") + rc, dmesg_boot, err = self.module.run_command("/sbin/dmesg") for line in dmesg_boot.split('\n'): if 'CPU:' in line: cpu = re.sub(r'CPU:\s+', r"", line) @@ -1485,7 +1474,7 @@ class FreeBSDHardware(Hardware): def get_memory_facts(self): - rc, out, err = module.run_command("/sbin/sysctl vm.stats") + rc, out, err = self.module.run_command("/sbin/sysctl vm.stats") for line in out.split('\n'): data = line.split() if 'vm.stats.vm.v_page_size' in line: @@ -1500,7 +1489,7 @@ class FreeBSDHardware(Hardware): # Device 1M-blocks Used Avail Capacity # /dev/ada0p3 314368 0 314368 0% # - rc, out, err = module.run_command("/usr/sbin/swapinfo -k") + rc, out, err = self.module.run_command("/usr/sbin/swapinfo -k") lines = out.split('\n') if len(lines[-1]) == 0: lines.pop() @@ -1524,7 +1513,7 @@ class FreeBSDHardware(Hardware): def get_device_facts(self): sysdir = '/dev' self.facts['devices'] = {} - drives = re.compile('(ada?\d+|da\d+|a?cd\d+)') #TODO: rc, disks, err = module.run_command("/sbin/sysctl kern.disks") + drives = re.compile('(ada?\d+|da\d+|a?cd\d+)') #TODO: rc, disks, err = self.module.run_command("/sbin/sysctl kern.disks") slices = re.compile('(ada?\d+s\d+\w*|da\d+s\d+\w*)') if os.path.isdir(sysdir): dirlist = sorted(os.listdir(sysdir)) @@ -1542,7 +1531,7 @@ class FreeBSDHardware(Hardware): Use dmidecode executable if available''' # Fall back to using dmidecode, if available - dmi_bin = module.get_bin_path('dmidecode') + dmi_bin = self.module.get_bin_path('dmidecode') DMI_DICT = dict( bios_date='bios-release-date', bios_version='bios-version', @@ -1555,7 +1544,7 @@ class FreeBSDHardware(Hardware): ) for (k, v) in DMI_DICT.items(): if dmi_bin is not None: - (rc, out, err) = module.run_command('%s -s %s' % (dmi_bin, v)) + (rc, out, err) = self.module.run_command('%s -s %s' % (dmi_bin, v)) if rc == 0: # Strip out commented lines (specific dmidecode output) self.facts[k] = ''.join([ line for line in out.split('\n') if not line.startswith('#') ]) @@ -1586,9 +1575,6 @@ class NetBSDHardware(Hardware): platform = 'NetBSD' MEMORY_FACTS = ['MemTotal', 'SwapTotal', 'MemFree', 'SwapFree'] - def __init__(self): - Hardware.__init__(self) - def populate(self): self.get_cpu_facts() self.get_memory_facts() @@ -1664,9 +1650,6 @@ class AIX(Hardware): """ platform = 'AIX' - def __init__(self): - Hardware.__init__(self) - def populate(self): self.get_cpu_facts() self.get_memory_facts() @@ -1677,7 +1660,7 @@ class AIX(Hardware): self.facts['processor'] = [] - rc, out, err = module.run_command("/usr/sbin/lsdev -Cc processor") + rc, out, err = self.module.run_command("/usr/sbin/lsdev -Cc processor") if out: i = 0 for line in out.split('\n'): @@ -1690,19 +1673,19 @@ class AIX(Hardware): i += 1 self.facts['processor_count'] = int(i) - rc, out, err = module.run_command("/usr/sbin/lsattr -El " + cpudev + " -a type") + rc, out, err = self.module.run_command("/usr/sbin/lsattr -El " + cpudev + " -a type") data = out.split(' ') self.facts['processor'] = data[1] - rc, out, err = module.run_command("/usr/sbin/lsattr -El " + cpudev + " -a smt_threads") + rc, out, err = self.module.run_command("/usr/sbin/lsattr -El " + cpudev + " -a smt_threads") data = out.split(' ') self.facts['processor_cores'] = int(data[1]) def get_memory_facts(self): pagesize = 4096 - rc, out, err = module.run_command("/usr/bin/vmstat -v") + rc, out, err = self.module.run_command("/usr/bin/vmstat -v") for line in out.split('\n'): data = line.split() if 'memory pages' in line: @@ -1715,7 +1698,7 @@ class AIX(Hardware): # Device 1M-blocks Used Avail Capacity # /dev/ada0p3 314368 0 314368 0% # - rc, out, err = module.run_command("/usr/sbin/lsps -s") + rc, out, err = self.module.run_command("/usr/sbin/lsps -s") if out: lines = out.split('\n') data = lines[1].split() @@ -1725,7 +1708,7 @@ class AIX(Hardware): 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") + rc, out, err = self.module.run_command("/usr/sbin/lsattr -El sys0 -a fwversion") data = out.split() self.facts['firmware_version'] = data[1].strip('IBM,') @@ -1745,9 +1728,6 @@ class HPUX(Hardware): platform = 'HP-UX' - def __init__(self): - Hardware.__init__(self) - def populate(self): self.get_cpu_facts() self.get_memory_facts() @@ -1756,31 +1736,31 @@ class HPUX(Hardware): def get_cpu_facts(self): if self.facts['architecture'] == '9000/800': - rc, out, err = module.run_command("ioscan -FkCprocessor | wc -l", use_unsafe_shell=True) + rc, out, err = self.module.run_command("ioscan -FkCprocessor | wc -l", use_unsafe_shell=True) self.facts['processor_count'] = int(out.strip()) #Working with machinfo mess elif self.facts['architecture'] == 'ia64': if self.facts['distribution_version'] == "B.11.23": - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | grep 'Number of CPUs'", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | grep 'Number of CPUs'", use_unsafe_shell=True) self.facts['processor_count'] = int(out.strip().split('=')[1]) - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | grep 'processor family'", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | grep 'processor family'", use_unsafe_shell=True) self.facts['processor'] = re.search('.*(Intel.*)', out).groups()[0].strip() - rc, out, err = module.run_command("ioscan -FkCprocessor | wc -l", use_unsafe_shell=True) + rc, out, err = self.module.run_command("ioscan -FkCprocessor | wc -l", use_unsafe_shell=True) self.facts['processor_cores'] = int(out.strip()) if self.facts['distribution_version'] == "B.11.31": #if machinfo return cores strings release B.11.31 > 1204 - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | grep core | wc -l", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | grep core | wc -l", use_unsafe_shell=True) if out.strip()== '0': - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | grep Intel", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | grep Intel", use_unsafe_shell=True) self.facts['processor_count'] = int(out.strip().split(" ")[0]) #If hyperthreading is active divide cores by 2 - rc, out, err = module.run_command("/usr/sbin/psrset | grep LCPU", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/sbin/psrset | grep LCPU", use_unsafe_shell=True) data = re.sub(' +',' ',out).strip().split(' ') if len(data) == 1: hyperthreading = 'OFF' else: hyperthreading = data[1] - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | grep logical", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | grep logical", use_unsafe_shell=True) data = out.strip().split(" ") if hyperthreading == 'ON': self.facts['processor_cores'] = int(data[0])/2 @@ -1789,54 +1769,54 @@ class HPUX(Hardware): self.facts['processor_cores'] = self.facts['processor_count'] else: self.facts['processor_cores'] = int(data[0]) - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | grep Intel |cut -d' ' -f4-", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | grep Intel |cut -d' ' -f4-", use_unsafe_shell=True) self.facts['processor'] = out.strip() else: - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | egrep 'socket[s]?$' | tail -1", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | egrep 'socket[s]?$' | tail -1", use_unsafe_shell=True) self.facts['processor_count'] = int(out.strip().split(" ")[0]) - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | grep -e '[0-9] core' | tail -1", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | grep -e '[0-9] core' | tail -1", use_unsafe_shell=True) self.facts['processor_cores'] = int(out.strip().split(" ")[0]) - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | grep Intel", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | grep Intel", use_unsafe_shell=True) self.facts['processor'] = out.strip() def get_memory_facts(self): pagesize = 4096 - rc, out, err = module.run_command("/usr/bin/vmstat | tail -1", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/bin/vmstat | tail -1", use_unsafe_shell=True) data = int(re.sub(' +',' ',out).split(' ')[5].strip()) self.facts['memfree_mb'] = pagesize * data / 1024 / 1024 if self.facts['architecture'] == '9000/800': try: - rc, out, err = module.run_command("grep Physical /var/adm/syslog/syslog.log") + rc, out, err = self.module.run_command("grep Physical /var/adm/syslog/syslog.log") data = re.search('.*Physical: ([0-9]*) Kbytes.*',out).groups()[0].strip() self.facts['memtotal_mb'] = int(data) / 1024 except AttributeError: #For systems where memory details aren't sent to syslog or the log has rotated, use parsed #adb output. Unfortunately /dev/kmem doesn't have world-read, so this only works as root. if os.access("/dev/kmem", os.R_OK): - rc, out, err = module.run_command("echo 'phys_mem_pages/D' | adb -k /stand/vmunix /dev/kmem | tail -1 | awk '{print $2}'", use_unsafe_shell=True) + rc, out, err = self.module.run_command("echo 'phys_mem_pages/D' | adb -k /stand/vmunix /dev/kmem | tail -1 | awk '{print $2}'", use_unsafe_shell=True) if not err: data = out self.facts['memtotal_mb'] = int(data) / 256 else: - rc, out, err = module.run_command("/usr/contrib/bin/machinfo | grep Memory", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo | grep Memory", use_unsafe_shell=True) data = re.search('Memory[\ :=]*([0-9]*).*MB.*',out).groups()[0].strip() self.facts['memtotal_mb'] = int(data) - rc, out, err = module.run_command("/usr/sbin/swapinfo -m -d -f -q") + rc, out, err = self.module.run_command("/usr/sbin/swapinfo -m -d -f -q") self.facts['swaptotal_mb'] = int(out.strip()) - rc, out, err = module.run_command("/usr/sbin/swapinfo -m -d -f | egrep '^dev|^fs'", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/sbin/swapinfo -m -d -f | egrep '^dev|^fs'", use_unsafe_shell=True) swap = 0 for line in out.strip().split('\n'): swap += int(re.sub(' +',' ',line).split(' ')[3].strip()) self.facts['swapfree_mb'] = swap def get_hw_facts(self): - rc, out, err = module.run_command("model") + rc, out, err = self.module.run_command("model") self.facts['model'] = out.strip() if self.facts['architecture'] == 'ia64': separator = ':' if self.facts['distribution_version'] == "B.11.23": separator = '=' - rc, out, err = module.run_command("/usr/contrib/bin/machinfo |grep -i 'Firmware revision' | grep -v BMC", use_unsafe_shell=True) + rc, out, err = self.module.run_command("/usr/contrib/bin/machinfo |grep -i 'Firmware revision' | grep -v BMC", use_unsafe_shell=True) self.facts['firmware_version'] = out.split(separator)[1].strip() @@ -1853,9 +1833,6 @@ class Darwin(Hardware): """ platform = 'Darwin' - def __init__(self): - Hardware.__init__(self) - def populate(self): self.sysctl = self.get_sysctl() self.get_mac_facts() @@ -1864,7 +1841,7 @@ class Darwin(Hardware): return self.facts def get_sysctl(self): - rc, out, err = module.run_command(["/usr/sbin/sysctl", "hw", "machdep", "kern"]) + rc, out, err = self.module.run_command(["/usr/sbin/sysctl", "hw", "machdep", "kern"]) if rc != 0: return dict() sysctl = dict() @@ -1875,7 +1852,7 @@ class Darwin(Hardware): return sysctl def get_system_profile(self): - rc, out, err = module.run_command(["/usr/sbin/system_profiler", "SPHardwareDataType"]) + rc, out, err = self.module.run_command(["/usr/sbin/system_profiler", "SPHardwareDataType"]) if rc != 0: return dict() system_profile = dict() @@ -1886,7 +1863,7 @@ class Darwin(Hardware): return system_profile def get_mac_facts(self): - rc, out, err = module.run_command("sysctl hw.model") + rc, out, err = self.module.run_command("sysctl hw.model") if rc == 0: self.facts['model'] = out.splitlines()[-1].split()[1] self.facts['osversion'] = self.sysctl['kern.osversion'] @@ -1904,7 +1881,7 @@ class Darwin(Hardware): def get_memory_facts(self): self.facts['memtotal_mb'] = long(self.sysctl['hw.memsize']) / 1024 / 1024 - rc, out, err = module.run_command("sysctl hw.usermem") + rc, out, err = self.module.run_command("sysctl hw.usermem") if rc == 0: self.facts['memfree_mb'] = long(out.splitlines()[-1].split()[1]) / 1024 / 1024 @@ -1935,10 +1912,6 @@ class Network(Facts): subclass = sc return super(cls, subclass).__new__(subclass, *arguments, **keyword) - def __init__(self, module): - self.module = module - Facts.__init__(self) - def populate(self): return self.facts @@ -1952,9 +1925,6 @@ class LinuxNetwork(Network): """ platform = 'Linux' - def __init__(self, module): - Network.__init__(self, module) - def populate(self): ip_path = self.module.get_bin_path('ip') if ip_path is None: @@ -1986,7 +1956,7 @@ class LinuxNetwork(Network): continue if v == 'v6' and not socket.has_ipv6: continue - rc, out, err = module.run_command(command[v]) + rc, out, err = self.module.run_command(command[v]) if not out: # v6 routing may result in # RTNETLINK answers: Invalid argument @@ -2146,7 +2116,7 @@ class LinuxNetwork(Network): if not address == '::1': ips['all_ipv6_addresses'].append(address) - ip_path = module.get_bin_path("ip") + ip_path = self.module.get_bin_path("ip") args = [ip_path, 'addr', 'show', 'primary', device] rc, stdout, stderr = self.module.run_command(args) @@ -2181,16 +2151,13 @@ class GenericBsdIfconfigNetwork(Network): """ platform = 'Generic_BSD_Ifconfig' - def __init__(self, module): - Network.__init__(self, module) - def populate(self): - ifconfig_path = module.get_bin_path('ifconfig') + ifconfig_path = self.module.get_bin_path('ifconfig') if ifconfig_path is None: return self.facts - route_path = module.get_bin_path('route') + route_path = self.module.get_bin_path('route') if route_path is None: return self.facts @@ -2229,7 +2196,7 @@ class GenericBsdIfconfigNetwork(Network): if v == 'v6' and not socket.has_ipv6: continue - rc, out, err = module.run_command(command[v]) + rc, out, err = self.module.run_command(command[v]) if not out: # v6 routing may result in # RTNETLINK answers: Invalid argument @@ -2256,7 +2223,7 @@ class GenericBsdIfconfigNetwork(Network): # FreeBSD, DragonflyBSD, NetBSD, OpenBSD and OS X all implicitly add '-a' # when running the command 'ifconfig'. # Solaris must explicitly run the command 'ifconfig -a'. - rc, out, err = module.run_command([ifconfig_path, ifconfig_options]) + rc, out, err = self.module.run_command([ifconfig_path, ifconfig_options]) for line in out.split('\n'): @@ -2402,9 +2369,6 @@ class HPUXNetwork(Network): """ platform = 'HP-UX' - def __init__(self, module): - Network.__init__(self, module) - def populate(self): netstat_path = self.module.get_bin_path('netstat') if netstat_path is None: @@ -2417,7 +2381,7 @@ class HPUXNetwork(Network): return self.facts def get_default_interfaces(self): - rc, out, err = module.run_command("/usr/bin/netstat -nr") + rc, out, err = self.module.run_command("/usr/bin/netstat -nr") lines = out.split('\n') for line in lines: words = line.split() @@ -2428,7 +2392,7 @@ class HPUXNetwork(Network): def get_interfaces_info(self): interfaces = {} - rc, out, err = module.run_command("/usr/bin/netstat -ni") + rc, out, err = self.module.run_command("/usr/bin/netstat -ni") lines = out.split('\n') for line in lines: words = line.split() @@ -2444,7 +2408,7 @@ class HPUXNetwork(Network): 'address': address } return interfaces -class DarwinNetwork(GenericBsdIfconfigNetwork, Network): +class DarwinNetwork(GenericBsdIfconfigNetwork): """ This is the Mac OS X/Darwin Network Class. It uses the GenericBsdIfconfigNetwork unchanged @@ -2468,21 +2432,21 @@ class DarwinNetwork(GenericBsdIfconfigNetwork, Network): current_if['media_options'] = self.get_options(words[3]) -class FreeBSDNetwork(GenericBsdIfconfigNetwork, Network): +class FreeBSDNetwork(GenericBsdIfconfigNetwork): """ This is the FreeBSD Network Class. It uses the GenericBsdIfconfigNetwork unchanged. """ platform = 'FreeBSD' -class DragonFlyNetwork(GenericBsdIfconfigNetwork, Network): +class DragonFlyNetwork(GenericBsdIfconfigNetwork): """ This is the DragonFly Network Class. It uses the GenericBsdIfconfigNetwork unchanged. """ platform = 'DragonFly' -class AIXNetwork(GenericBsdIfconfigNetwork, Network): +class AIXNetwork(GenericBsdIfconfigNetwork): """ This is the AIX Network Class. It uses the GenericBsdIfconfigNetwork unchanged. @@ -2490,9 +2454,9 @@ class AIXNetwork(GenericBsdIfconfigNetwork, Network): platform = 'AIX' def get_default_interfaces(self, route_path): - netstat_path = module.get_bin_path('netstat') + netstat_path = self.module.get_bin_path('netstat') - rc, out, err = module.run_command([netstat_path, '-nr']) + rc, out, err = self.module.run_command([netstat_path, '-nr']) interface = dict(v4 = {}, v6 = {}) @@ -2517,14 +2481,14 @@ class AIXNetwork(GenericBsdIfconfigNetwork, Network): all_ipv4_addresses = [], all_ipv6_addresses = [], ) - rc, out, err = module.run_command([ifconfig_path, ifconfig_options]) + rc, out, err = self.module.run_command([ifconfig_path, ifconfig_options]) for line in out.split('\n'): if line: words = line.split() - # only this condition differs from GenericBsdIfconfigNetwork + # only this condition differs from GenericBsdIfconfigNetwork if re.match('^\w*\d*:', line): current_if = self.parse_interface_line(words) interfaces[ current_if['device'] ] = current_if @@ -2546,16 +2510,16 @@ class AIXNetwork(GenericBsdIfconfigNetwork, Network): self.parse_inet6_line(words, current_if, ips) else: self.parse_unknown_line(words, current_if, ips) - uname_path = module.get_bin_path('uname') + uname_path = self.module.get_bin_path('uname') if uname_path: - rc, out, err = module.run_command([uname_path, '-W']) + rc, out, err = self.module.run_command([uname_path, '-W']) # don't bother with wpars it does not work # zero means not in wpar if not rc and out.split()[0] == '0': if current_if['macaddress'] == 'unknown' and re.match('^en', current_if['device']): - entstat_path = module.get_bin_path('entstat') + entstat_path = self.module.get_bin_path('entstat') if entstat_path: - rc, out, err = module.run_command([entstat_path, current_if['device'] ]) + rc, out, err = self.module.run_command([entstat_path, current_if['device'] ]) if rc != 0: break for line in out.split('\n'): @@ -2570,9 +2534,9 @@ class AIXNetwork(GenericBsdIfconfigNetwork, Network): current_if['type'] = 'ether' # device must have mtu attribute in ODM if 'mtu' not in current_if: - lsattr_path = module.get_bin_path('lsattr') + lsattr_path = self.module.get_bin_path('lsattr') if lsattr_path: - rc, out, err = module.run_command([lsattr_path,'-El', current_if['device'] ]) + rc, out, err = self.module.run_command([lsattr_path,'-El', current_if['device'] ]) if rc != 0: break for line in out.split('\n'): @@ -2590,7 +2554,7 @@ class AIXNetwork(GenericBsdIfconfigNetwork, Network): current_if['macaddress'] = 'unknown' # will be overwritten later return current_if -class OpenBSDNetwork(GenericBsdIfconfigNetwork, Network): +class OpenBSDNetwork(GenericBsdIfconfigNetwork): """ This is the OpenBSD Network Class. It uses the GenericBsdIfconfigNetwork. @@ -2605,7 +2569,7 @@ class OpenBSDNetwork(GenericBsdIfconfigNetwork, Network): def parse_lladdr_line(self, words, current_if, ips): current_if['macaddress'] = words[1] -class SunOSNetwork(GenericBsdIfconfigNetwork, Network): +class SunOSNetwork(GenericBsdIfconfigNetwork): """ This is the SunOS Network Class. It uses the GenericBsdIfconfigNetwork. @@ -2626,7 +2590,7 @@ class SunOSNetwork(GenericBsdIfconfigNetwork, Network): all_ipv4_addresses = [], all_ipv6_addresses = [], ) - rc, out, err = module.run_command([ifconfig_path, '-a']) + rc, out, err = self.module.run_command([ifconfig_path, '-a']) for line in out.split('\n'): @@ -2710,9 +2674,6 @@ class Virtual(Facts): subclass = sc return super(cls, subclass).__new__(subclass, *arguments, **keyword) - def __init__(self): - Facts.__init__(self) - def populate(self): return self.facts @@ -2724,9 +2685,6 @@ class LinuxVirtual(Virtual): """ platform = 'Linux' - def __init__(self): - Virtual.__init__(self) - def populate(self): self.get_virtual_facts() return self.facts @@ -2843,9 +2801,9 @@ class LinuxVirtual(Virtual): self.facts['virtualization_type'] = 'powervm_lx86' elif re.match('^vendor_id.*IBM/S390', line): self.facts['virtualization_type'] = 'PR/SM' - lscpu = module.get_bin_path('lscpu') + lscpu = self.module.get_bin_path('lscpu') if lscpu: - rc, out, err = module.run_command(["lscpu"]) + rc, out, err = self.module.run_command(["lscpu"]) if rc == 0: for line in out.split("\n"): data = line.split(":", 1) @@ -2893,9 +2851,6 @@ class FreeBSDVirtual(Virtual): """ platform = 'FreeBSD' - def __init__(self): - Virtual.__init__(self) - def populate(self): self.get_virtual_facts() return self.facts @@ -2915,9 +2870,6 @@ class OpenBSDVirtual(Virtual): """ platform = 'OpenBSD' - def __init__(self): - Virtual.__init__(self) - def populate(self): self.get_virtual_facts() return self.facts @@ -2934,21 +2886,18 @@ class HPUXVirtual(Virtual): """ platform = 'HP-UX' - def __init__(self): - Virtual.__init__(self) - def populate(self): self.get_virtual_facts() return self.facts def get_virtual_facts(self): if os.path.exists('/usr/sbin/vecheck'): - rc, out, err = module.run_command("/usr/sbin/vecheck") + rc, out, err = self.module.run_command("/usr/sbin/vecheck") if rc == 0: self.facts['virtualization_type'] = 'guest' self.facts['virtualization_role'] = 'HP vPar' if os.path.exists('/opt/hpvm/bin/hpvminfo'): - rc, out, err = module.run_command("/opt/hpvm/bin/hpvminfo") + rc, out, err = self.module.run_command("/opt/hpvm/bin/hpvminfo") if rc == 0 and re.match('.*Running.*HPVM vPar.*', out): self.facts['virtualization_type'] = 'guest' self.facts['virtualization_role'] = 'HPVM vPar' @@ -2959,7 +2908,7 @@ class HPUXVirtual(Virtual): self.facts['virtualization_type'] = 'host' self.facts['virtualization_role'] = 'HPVM' if os.path.exists('/usr/sbin/parstatus'): - rc, out, err = module.run_command("/usr/sbin/parstatus") + rc, out, err = self.module.run_command("/usr/sbin/parstatus") if rc == 0: self.facts['virtualization_type'] = 'guest' self.facts['virtualization_role'] = 'HP nPar' @@ -2974,15 +2923,12 @@ class SunOSVirtual(Virtual): """ platform = 'SunOS' - def __init__(self): - Virtual.__init__(self) - def populate(self): self.get_virtual_facts() return self.facts def get_virtual_facts(self): - rc, out, err = module.run_command("/usr/sbin/prtdiag") + rc, out, err = self.module.run_command("/usr/sbin/prtdiag") for line in out.split('\n'): if 'VMware' in line: self.facts['virtualization_type'] = 'vmware' @@ -2998,7 +2944,7 @@ class SunOSVirtual(Virtual): self.facts['virtualization_role'] = 'guest' # Check if it's a zone if os.path.exists("/usr/bin/zonename"): - rc, out, err = module.run_command("/usr/bin/zonename") + rc, out, err = self.module.run_command("/usr/bin/zonename") if out.rstrip() != "global": self.facts['container'] = 'zone' # Check if it's a branded zone (i.e. Solaris 8/9 zone) @@ -3007,7 +2953,7 @@ class SunOSVirtual(Virtual): # If it's a zone check if we can detect if our global zone is itself virtualized. # Relies on the "guest tools" (e.g. vmware tools) to be installed if 'container' in self.facts and self.facts['container'] == 'zone': - rc, out, err = module.run_command("/usr/sbin/modinfo") + rc, out, err = self.module.run_command("/usr/sbin/modinfo") for line in out.split('\n'): if 'VMware' in line: self.facts['virtualization_type'] = 'vmware' @@ -3019,7 +2965,7 @@ class SunOSVirtual(Virtual): if os.path.exists("/usr/sbin/virtinfo"): # The output of virtinfo is different whether we are on a machine with logical # domains ('LDoms') on a T-series or domains ('Domains') on a M-series. Try LDoms first. - rc, out, err = module.run_command("/usr/sbin/virtinfo -p") + rc, out, err = self.module.run_command("/usr/sbin/virtinfo -p") # The output contains multiple lines with different keys like this: # DOMAINROLE|impl=LDoms|control=false|io=false|service=false|root=false # The output may also be not formatted and the returncode is set to 0 regardless of the error condition: @@ -3040,6 +2986,52 @@ class SunOSVirtual(Virtual): except ValueError: pass +class Ohai(Facts): + """ + This is a subclass of Facts for including information gathered from Ohai. + """ + + def populate(self): + self.run_ohai() + return self.facts + + def run_ohai(self): + ohai_path = self.module.get_bin_path('ohai') + if ohai_path is None: + return + rc, out, err = self.module.run_command(ohai_path) + try: + self.facts.update(json.loads(out)) + except: + pass + +class Facter(Facts): + """ + This is a subclass of Facts for including information gathered from Facter. + """ + def populate(self): + self.run_facter() + return self.facts + + def run_facter(self): + facter_path = self.module.get_bin_path('facter', opt_dirs=['/opt/puppetlabs/bin']) + cfacter_path = self.module.get_bin_path('cfacter', opt_dirs=['/opt/puppetlabs/bin']) + # Prefer to use cfacter if available + if cfacter_path is not None: + facter_path = cfacter_path + + if facter_path is None: + return + + # if facter is installed, and we can use --json because + # ruby-json is ALSO installed, include facter data in the JSON + rc, out, err = self.module.run_command(facter_path + " --puppet --json") + try: + self.facts = json.loads(out) + except: + pass + + def get_file_content(path, default=None, strip=True): data = default if os.path.exists(path) and os.access(path, os.R_OK): @@ -3068,61 +3060,69 @@ def get_file_lines(path): ret = [] return ret -def ansible_facts(module): +def ansible_facts(module, gather_subset): facts = {} - facts.update(Facts().populate()) - facts.update(Hardware().populate()) - facts.update(Network(module).populate()) - facts.update(Virtual().populate()) + facts['gather_subset'] = list(gather_subset) + facts.update(Facts(module).populate()) + for subset in gather_subset: + facts.update(FACT_SUBSETS[subset](module).populate()) return facts -# =========================================== - def get_all_facts(module): setup_options = dict(module_setup=True) - facts = ansible_facts(module) - for (k, v) in facts.items(): - setup_options["ansible_%s" % k.replace('-', '_')] = v + # Retrieve module parameters + gather_subset = module.params['gather_subset'] + + # Retrieve all facts elements + additional_subsets = set() + exclude_subsets = set() + for subset in gather_subset: + if subset == 'all': + additional_subsets.update(VALID_SUBSETS) + continue + if subset.startswith('!'): + subset = subset[1:] + if subset == 'all': + exclude_subsets.update(VALID_SUBSETS) + continue + exclude = True + else: + exclude = False - # Look for the path to the facter, cfacter, and ohai binaries and set - # the variable to that path. + if subset not in VALID_SUBSETS: + raise TypeError("Bad subset '%s' given to Ansible. gather_subset options allowed: all, %s" % (subset, ", ".join(FACT_SUBSETS.keys()))) - facter_path = module.get_bin_path('facter') - cfacter_path = module.get_bin_path('cfacter') - ohai_path = module.get_bin_path('ohai') + if exclude: + exclude_subsets.add(subset) + else: + additional_subsets.add(subset) - # Prefer to use cfacter if available - if cfacter_path is not None: - facter_path = cfacter_path - # if facter is installed, and we can use --json because - # ruby-json is ALSO installed, include facter data in the JSON + if not additional_subsets: + additional_subsets.update(VALID_SUBSETS) - if facter_path is not None: - rc, out, err = module.run_command(facter_path + " --json") - facter = True - try: - facter_ds = json.loads(out) - except: - facter = False - if facter: - for (k,v) in facter_ds.items(): - setup_options["facter_%s" % k] = v + additional_subsets.difference_update(exclude_subsets) - # ditto for ohai + # facter and ohai are given a different prefix than other subsets + if 'facter' in additional_subsets: + additional_subsets.difference_update(('facter',)) + facter_ds = FACT_SUBSETS['facter'](module, load_on_init=False).populate() + if facter_ds: + for (k, v) in facter_ds.items(): + setup_options['facter_%s' % k.replace('-', '_')] = v - if ohai_path is not None: - rc, out, err = module.run_command(ohai_path) - ohai = True - try: - ohai_ds = json.loads(out) - except: - ohai = False - if ohai: - for (k,v) in ohai_ds.items(): - k2 = "ohai_%s" % k.replace('-', '_') - setup_options[k2] = v + if 'ohai' in additional_subsets: + additional_subsets.difference_update(('ohai',)) + ohai_ds = FACT_SUBSETS['ohai'](module, load_on_init=False).populate() + if ohai_ds: + for (k, v) in ohai_ds.items(): + setup_options['ohai_%s' % k.replace('-', '_')] = v + + facts = ansible_facts(module, additional_subsets) + + for (k, v) in facts.items(): + setup_options["ansible_%s" % k.replace('-', '_')] = v setup_result = { 'ansible_facts': {} } @@ -3134,3 +3134,14 @@ def get_all_facts(module): setup_result['_ansible_verbose_override'] = True return setup_result + +# Allowed fact subset for gather_subset options and what classes they use +# Note: have to define this at the bottom as it references classes defined earlier in this file +FACT_SUBSETS = dict( + hardware=Hardware, + network=Network, + virtual=Virtual, + ohai=Ohai, + facter=Facter, +) +VALID_SUBSETS = frozenset(FACT_SUBSETS.keys()) diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py index d3752adf2f3..c9fd2e84b45 100644 --- a/lib/ansible/playbook/base.py +++ b/lib/ansible/playbook/base.py @@ -334,7 +334,10 @@ class Base: if value is None: value = [] elif not isinstance(value, list): - value = [ value ] + if isinstance(value, string_types): + value = value.split(',') + else: + value = [ value ] if attribute.listof is not None: for item in value: if not isinstance(item, attribute.listof): @@ -346,11 +349,15 @@ class Base: elif attribute.isa == 'set': if value is None: value = set() - else: - if not isinstance(value, (list, set)): + elif not isinstance(value, (list, set)): + if isinstance(value, string_types): + value = value.split(',') + else: + # Making a list like this handles strings of + # text and bytes properly value = [ value ] - if not isinstance(value, set): - value = set(value) + if not isinstance(value, set): + value = set(value) elif attribute.isa == 'dict': if value is None: value = dict() diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py index c354b745496..b917985bdc6 100644 --- a/lib/ansible/playbook/play.py +++ b/lib/ansible/playbook/play.py @@ -64,6 +64,7 @@ class Play(Base, Taggable, Become): # Connection _gather_facts = FieldAttribute(isa='bool', default=None, always_post_validate=True) + _gather_subset = FieldAttribute(isa='list', default=None, always_post_validate=True) _hosts = FieldAttribute(isa='list', required=True, listof=string_types, always_post_validate=True) _name = FieldAttribute(isa='string', default='', always_post_validate=True) diff --git a/test/integration/Makefile b/test/integration/Makefile index 07b2d3c78cb..331022ce516 100644 --- a/test/integration/Makefile +++ b/test/integration/Makefile @@ -23,7 +23,7 @@ VAULT_PASSWORD_FILE = vault-password CONSUL_RUNNING := $(shell python consul_running.py) EUID := $(shell id -u -r) -all: setup test_test_infra parsing test_var_precedence unicode test_templating_settings environment non_destructive destructive includes blocks pull check_mode test_hash test_handlers test_group_by test_vault test_tags test_lookup_paths no_log test_connection +all: setup test_test_infra parsing test_var_precedence unicode test_templating_settings environment non_destructive destructive includes blocks pull check_mode test_hash test_handlers test_group_by test_vault test_tags test_lookup_paths no_log test_connection test_gathering_facts test_test_infra: [ "$$(ansible-playbook -i $(INVENTORY) test_test_infra.yml -e @$(VARS_FILE) $(CREDENTIALS_ARG) $(TEST_FLAGS) | fgrep works | xargs)" = "msg: fail works (True) msg: assert works (True)" ] @@ -70,6 +70,9 @@ unicode: setup test_templating_settings: setup ansible-playbook test_templating_settings.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS) +test_gathering_facts: setup + ansible-playbook test_gathering_facts.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) -v $(TEST_FLAGS) + environment: setup ansible-playbook test_environment.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) $(TEST_FLAGS) diff --git a/test/integration/inventory b/test/integration/inventory index bee36ce022e..b833343839c 100644 --- a/test/integration/inventory +++ b/test/integration/inventory @@ -4,6 +4,9 @@ testhost2 ansible_ssh_host=127.0.0.1 ansible_connection=local # For testing delegate_to testhost3 ansible_ssh_host=127.0.0.3 testhost4 ansible_ssh_host=127.0.0.4 +# For testing fact gathering +facthost[0:7] ansible_host=1270.0.0.1 ansible_connection=local + # the following inline declarations are accompanied # by (preferred) group_vars/ and host_vars/ variables diff --git a/test/integration/test_gathering_facts.yml b/test/integration/test_gathering_facts.yml new file mode 100644 index 00000000000..8e93be0a8c5 --- /dev/null +++ b/test/integration/test_gathering_facts.yml @@ -0,0 +1,116 @@ +--- + +- hosts: facthost0 + tags: [ 'fact_min' ] + connection: local + gather_subset: "!all" + gather_facts: yes + tasks: + - name: Test that only retrieving minimal facts work + assert: + that: + - '"{{ ansible_user_id|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_interfaces|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_mounts|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_virtualization_role|default("UNDEF") }}" == "UNDEF"' + +- hosts: facthost1 + tags: [ 'fact_network' ] + connection: local + gather_subset: "network" + gather_facts: yes + tasks: + - name: Test that retrieving network facts work + assert: + that: + - '"{{ ansible_user_id|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_interfaces|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_mounts|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_virtualization_role|default("UNDEF") }}" == "UNDEF"' + +- hosts: facthost2 + tags: [ 'fact_hardware' ] + connection: local + gather_subset: "hardware" + gather_facts: yes + tasks: + - name: Test that retrieving hardware facts work + assert: + that: + - '"{{ ansible_user_id|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_interfaces|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_mounts|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_virtualization_role|default("UNDEF") }}" == "UNDEF"' + +- hosts: facthost3 + tags: [ 'fact_virtual' ] + connection: local + gather_subset: "virtual" + gather_facts: yes + tasks: + - name: Test that retrieving virtualization facts work + assert: + that: + - '"{{ ansible_user_id|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_interfaces|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_mounts|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_virtualization_role|default("UNDEF") }}" != "UNDEF"' + +- hosts: facthost4 + tags: [ 'fact_comma_string' ] + connection: local + gather_subset: "virtual,network" + gather_facts: yes + tasks: + - name: Test that retrieving virtualization and network as a string works + assert: + that: + - '"{{ ansible_user_id|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_interfaces|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_mounts|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_virtualization_role|default("UNDEF") }}" != "UNDEF"' + +- hosts: facthost5 + tags: [ 'fact_yaml_list' ] + connection: local + gather_subset: + - virtual + - network + gather_facts: yes + tasks: + - name: Test that retrieving virtualization and network as a string works + assert: + that: + - '"{{ ansible_user_id|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_interfaces|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_mounts|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_virtualization_role|default("UNDEF") }}" != "UNDEF"' + +- hosts: facthost6 + tags: [ 'fact_negation' ] + connection: local + gather_subset: "!hardware" + gather_facts: yes + tasks: + - name: Test that negation of fact subsets work + assert: + that: + - '"{{ ansible_user_id|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_interfaces|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_mounts|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_virtualization_role|default("UNDEF") }}" != "UNDEF"' + +- hosts: facthost7 + tags: [ 'fact_mixed_negation_addition' ] + connection: local + gather_subset: "!hardware,network" + gather_facts: yes + tasks: + - name: Test that negation and additional subsets work together + assert: + that: + - '"{{ ansible_user_id|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_interfaces|default("UNDEF") }}" != "UNDEF"' + - '"{{ ansible_mounts|default("UNDEF") }}" == "UNDEF"' + - '"{{ ansible_virtualization_role|default("UNDEF") }}" == "UNDEF"' +