add a 'min' type for gather_subset to collect nothing (#27085)

previously gather_subset=['!all'] would still gather the
min set of facts, and there was no way to collect no facts.

The 'min' specifier in gather_subset is equilivent to
exclude the minimal_gather_subset facts as well.

   gather_subset=['!all', '!min'] will collect no facts

This also lets explicitly added gather_subsets override excludes.

   gather_subset=['pkg_mgr', '!all', '!min'] will collect only the pkg_mgr
fact.
pull/27649/head
Adrian Likins 7 years ago committed by GitHub
parent c85b36d220
commit 27a015f0ad

@ -111,16 +111,31 @@ def get_collector_names(valid_subsets=None,
additional_subsets = set() additional_subsets = set()
exclude_subsets = set() exclude_subsets = set()
for subset in gather_subset: # total always starts with the min set, then
subset_id = subset # adds of the additions in gather_subset, then
# excludes all of the excludes, then add any explicitly
# requested subsets.
gather_subset_with_min = ['min']
gather_subset_with_min.extend(gather_subset)
# subsets we mention in gather_subset explicitly, except for 'all'/'min'
explicitly_added = set()
for subset in gather_subset_with_min:
subset_id = subset
if subset_id == 'min':
additional_subsets.update(minimal_gather_subset)
continue
if subset_id == 'all': if subset_id == 'all':
additional_subsets.update(valid_subsets) additional_subsets.update(valid_subsets)
continue continue
if subset_id.startswith('!'): if subset_id.startswith('!'):
subset = subset[1:] subset = subset[1:]
if subset == 'min':
exclude_subsets.update(minimal_gather_subset)
continue
if subset == 'all': if subset == 'all':
exclude_subsets.update(valid_subsets) exclude_subsets.update(valid_subsets - minimal_gather_subset)
continue continue
exclude = True exclude = True
else: else:
@ -137,14 +152,13 @@ def get_collector_names(valid_subsets=None,
raise TypeError("Bad subset '%s' given to Ansible. gather_subset options allowed: all, %s" % raise TypeError("Bad subset '%s' given to Ansible. gather_subset options allowed: all, %s" %
(subset, ", ".join(sorted(valid_subsets)))) (subset, ", ".join(sorted(valid_subsets))))
explicitly_added.add(subset)
additional_subsets.add(subset) additional_subsets.add(subset)
if not additional_subsets: if not additional_subsets:
additional_subsets.update(valid_subsets) additional_subsets.update(valid_subsets)
additional_subsets.difference_update(exclude_subsets) additional_subsets.difference_update(exclude_subsets - explicitly_added)
additional_subsets.update(minimal_gather_subset)
return additional_subsets return additional_subsets

@ -23,13 +23,16 @@ options:
version_added: "2.1" version_added: "2.1"
description: description:
- "if supplied, restrict the additional facts collected to the given subset. - "if supplied, restrict the additional facts collected to the given subset.
Possible values: all, hardware, network, virtual, ohai, and Possible values: all, min, hardware, network, virtual, ohai, and
facter Can specify a list of values to specify a larger subset. facter Can specify a list of values to specify a larger subset.
Values can also be used with an initial C(!) to specify that Values can also be used with an initial C(!) to specify that
that specific subset should not be collected. For instance: that specific subset should not be collected. For instance:
!hardware, !network, !virtual, !ohai, !facter. Note that a few !hardware, !network, !virtual, !ohai, !facter. If !all is specified
facts are always collected. Use the filter parameter if you do then only the min subset is collected. To avoid collecting even the
not want to display those." min subset, specify !all and !min subsets. To collect only specific facts,
use !all, !min, and specify the particular fact subsets.
Use the filter parameter if you do not want to display some collected
facts."
required: false required: false
default: 'all' default: 'all'
gather_timeout: gather_timeout:
@ -93,18 +96,27 @@ EXAMPLES = """
# Display only facts returned by facter. # Display only facts returned by facter.
# ansible all -m setup -a 'filter=facter_*' # ansible all -m setup -a 'filter=facter_*'
# Collect only facts returned by facter.
# ansible all -m setup -a 'gather_subset=!all,!any,facter'
# Display only facts about certain interfaces. # Display only facts about certain interfaces.
# ansible all -m setup -a 'filter=ansible_eth[0-2]' # ansible all -m setup -a 'filter=ansible_eth[0-2]'
# Restrict additional gathered facts to network and virtual. # Restrict additional gathered facts to network and virtual (includes default minimum facts)
# ansible all -m setup -a 'gather_subset=network,virtual' # ansible all -m setup -a 'gather_subset=network,virtual'
# Collect only network and virtual (excludes default minimum facts)
# ansible all -m setup -a 'gather_subset=!all,!any,network,virtual'
# Do not call puppet facter or ohai even if present. # Do not call puppet facter or ohai even if present.
# ansible all -m setup -a 'gather_subset=!facter,!ohai' # ansible all -m setup -a 'gather_subset=!facter,!ohai'
# Only collect the minimum amount of facts: # Only collect the default minimum amount of facts:
# ansible all -m setup -a 'gather_subset=!all' # ansible all -m setup -a 'gather_subset=!all'
# Collect no facts, even the default minimum subset of facts:
# ansible all -m setup -a 'gather_subset=!all,!min'
# Display facts from Windows hosts with custom facts stored in C(C:\\custom_facts). # Display facts from Windows hosts with custom facts stored in C(C:\\custom_facts).
# ansible windows -m setup -a "fact_path='c:\\custom_facts'" # ansible windows -m setup -a "fact_path='c:\\custom_facts'"
""" """

@ -1,5 +1,4 @@
--- ---
- hosts: facthost7 - hosts: facthost7
tags: [ 'fact_negation' ] tags: [ 'fact_negation' ]
connection: local connection: local
@ -12,9 +11,6 @@
- "!hardware" - "!hardware"
register: not_hardware_facts register: not_hardware_facts
- name: debug setup with not hardware
debug:
var: not_hardware_facts
- hosts: facthost0 - hosts: facthost0
tags: [ 'fact_min' ] tags: [ 'fact_min' ]
@ -67,6 +63,7 @@
- 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"'
- 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"'
- 'ansible_env|default("UNDEF_ENV") == "UNDEF_ENV"' - 'ansible_env|default("UNDEF_ENV") == "UNDEF_ENV"'
- 'ansible_pkg_mgr|default("UNDEF_PKG_MGR") == "UNDEF_PKG_MGR"'
- hosts: facthost11 - hosts: facthost11
tags: [ 'fact_min' ] tags: [ 'fact_min' ]
@ -111,7 +108,10 @@
- name: Test that only retrieving minimal facts work - name: Test that only retrieving minimal facts work
assert: assert:
that: that:
# from the min set, which should still collect
- 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"'
- 'ansible_env|default("UNDEF_ENV") != "UNDEF_ENV"'
# non min facts that are not collected
- 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"'
- 'ansible_mounts|default("UNDEF_HW") == "UNDEF_HW"' - 'ansible_mounts|default("UNDEF_HW") == "UNDEF_HW"'
- 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"'
@ -198,10 +198,16 @@
- name: Test that negation of fact subsets work - name: Test that negation of fact subsets work
assert: assert:
that: that:
# network, not collected since it is not in min
- 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"'
# not collecting virt, should be undef
- 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"'
# mounts/devices are collected by hardware, so should be not collected and undef
- 'ansible_mounts|default("UNDEF_MOUNTS") == "UNDEF_MOUNTS"'
- 'ansible_devices|default("UNDEF_DEVICES") == "UNDEF_DEVICES"'
# from the min set, which should still collect
- 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"'
- 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' - 'ansible_env|default("UNDEF_ENV") != "UNDEF_ENV"'
- 'ansible_mounts|default("UNDEF_HW") == "UNDEF_HW"'
- 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"'
- hosts: facthost8 - hosts: facthost8
tags: [ 'fact_mixed_negation_addition' ] tags: [ 'fact_mixed_negation_addition' ]
@ -217,6 +223,46 @@
- 'ansible_mounts|default("UNDEF_HW") == "UNDEF_HW"' - 'ansible_mounts|default("UNDEF_HW") == "UNDEF_HW"'
- 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"'
- hosts: facthost14
tags: [ 'fact_mixed_negation_addition_min' ]
connection: local
gather_subset: "!all,!min,network"
gather_facts: yes
tasks:
- name: Test that negation and additional subsets work together for min subset
assert:
that:
- 'ansible_user_id|default("UNDEF_MIN") == "UNDEF_MIN"'
- 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"'
- 'ansible_default_ipv4|default("UNDEF_DEFAULT_IPV4") != "UNDEF_DEFAULT_IPV4"'
- 'ansible_all_ipv4_addresses|default("UNDEF_ALL_IPV4") != "UNDEF_ALL_IPV4"'
- 'ansible_mounts|default("UNDEF_HW") == "UNDEF_HW"'
- 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"'
- 'ansible_env|default("UNDEF_ENV") == "UNDEF_ENV"'
- hosts: facthost15
tags: [ 'fact_negate_all_min_add_pkg_mgr' ]
connection: local
gather_subset: "!all,!min,pkg_mgr"
gather_facts: yes
tasks:
- name: Test that negation and additional subsets work together for min subset
assert:
that:
# network, not collected since it is not in min
- 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"'
# not collecting virt, should be undef
- 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"'
# mounts/devices are collected by hardware, so should be not collected and undef
- 'ansible_mounts|default("UNDEF_MOUNTS") == "UNDEF_MOUNTS"'
- 'ansible_devices|default("UNDEF_DEVICES") == "UNDEF_DEVICES"'
# from the min set, which should not collect
- 'ansible_user_id|default("UNDEF_MIN") == "UNDEF_MIN"'
- 'ansible_env|default("UNDEF_ENV") == "UNDEF_ENV"'
# the pkg_mgr fact we requested explicitly
- 'ansible_pkg_mgr|default("UNDEF_PKG_MGR") != "UNDEF_PKGMGR"'
- hosts: facthost9 - hosts: facthost9
tags: [ 'fact_local'] tags: [ 'fact_local']
connection: local connection: local

@ -37,14 +37,14 @@ class TestGetCollectorNames(unittest.TestCase):
def test_empty_sets(self): def test_empty_sets(self):
res = collector.get_collector_names(valid_subsets=frozenset([]), res = collector.get_collector_names(valid_subsets=frozenset([]),
minimal_gather_subset=frozenset([]), minimal_gather_subset=frozenset([]),
gather_subset=set([])) gather_subset=[])
self.assertIsInstance(res, set) self.assertIsInstance(res, set)
self.assertEqual(res, set([])) self.assertEqual(res, set([]))
def test_empty_valid_and_min_with_all_gather_subset(self): def test_empty_valid_and_min_with_all_gather_subset(self):
res = collector.get_collector_names(valid_subsets=frozenset([]), res = collector.get_collector_names(valid_subsets=frozenset([]),
minimal_gather_subset=frozenset([]), minimal_gather_subset=frozenset([]),
gather_subset=set(['all'])) gather_subset=['all'])
self.assertIsInstance(res, set) self.assertIsInstance(res, set)
self.assertEqual(res, set([])) self.assertEqual(res, set([]))
@ -52,10 +52,48 @@ class TestGetCollectorNames(unittest.TestCase):
valid_subsets = frozenset(['my_fact']) valid_subsets = frozenset(['my_fact'])
res = collector.get_collector_names(valid_subsets=valid_subsets, res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=frozenset([]), minimal_gather_subset=frozenset([]),
gather_subset=set(['all'])) gather_subset=['all'])
self.assertIsInstance(res, set) self.assertIsInstance(res, set)
self.assertEqual(res, set(['my_fact'])) self.assertEqual(res, set(['my_fact']))
def _compare_res(self, gather_subset1, gather_subset2,
valid_subsets=None, min_subset=None):
valid_subsets = valid_subsets or frozenset()
minimal_gather_subset = min_subset or frozenset()
res1 = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset,
gather_subset=gather_subset1)
res2 = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset,
gather_subset=gather_subset2)
return res1, res2
def test_not_all_other_order(self):
valid_subsets = frozenset(['min_fact', 'something_else', 'whatever'])
minimal_gather_subset = frozenset(['min_fact'])
res1, res2 = self._compare_res(['!all', 'whatever'],
['whatever', '!all'],
valid_subsets=valid_subsets,
min_subset=minimal_gather_subset)
self.assertEqual(res1, res2)
self.assertEqual(res1, set(['min_fact', 'whatever']))
def test_not_all_other_order_min(self):
valid_subsets = frozenset(['min_fact', 'something_else', 'whatever'])
minimal_gather_subset = frozenset(['min_fact'])
res1, res2 = self._compare_res(['!min_fact', 'whatever'],
['whatever', '!min_fact'],
valid_subsets=valid_subsets,
min_subset=minimal_gather_subset)
self.assertEqual(res1, res2)
self.assertEqual(res1, set(['whatever']))
def test_one_minimal_with_all_gather_subset(self): def test_one_minimal_with_all_gather_subset(self):
my_fact = 'my_fact' my_fact = 'my_fact'
valid_subsets = frozenset([my_fact]) valid_subsets = frozenset([my_fact])
@ -63,7 +101,7 @@ class TestGetCollectorNames(unittest.TestCase):
res = collector.get_collector_names(valid_subsets=valid_subsets, res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset, minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['all'])) gather_subset=['all'])
self.assertIsInstance(res, set) self.assertIsInstance(res, set)
self.assertEqual(res, set(['my_fact'])) self.assertEqual(res, set(['my_fact']))
@ -74,7 +112,7 @@ class TestGetCollectorNames(unittest.TestCase):
# even with '!all', the minimal_gather_subset should be returned # even with '!all', the minimal_gather_subset should be returned
res = collector.get_collector_names(valid_subsets=valid_subsets, res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset, minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['all'])) gather_subset=['all'])
self.assertIsInstance(res, set) self.assertIsInstance(res, set)
self.assertEqual(res, set(['my_fact', 'something_else', 'whatever'])) self.assertEqual(res, set(['my_fact', 'something_else', 'whatever']))
@ -85,21 +123,23 @@ class TestGetCollectorNames(unittest.TestCase):
# even with '!all', the minimal_gather_subset should be returned # even with '!all', the minimal_gather_subset should be returned
res = collector.get_collector_names(valid_subsets=valid_subsets, res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset, minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['!all'])) gather_subset=['!all'])
self.assertIsInstance(res, set) self.assertIsInstance(res, set)
self.assertEqual(res, set(['my_fact'])) self.assertEqual(res, set(['my_fact']))
def test_gather_subset_excludes(self): def test_gather_subset_excludes(self):
valid_subsets = frozenset(['my_fact', 'something_else', 'whatever']) valid_subsets = frozenset(['my_fact', 'something_else', 'whatever'])
minimal_gather_subset = frozenset(['my_fact']) minimal_gather_subset = frozenset(['min_fact', 'min_another'])
# even with '!all', the minimal_gather_subset should be returned # even with '!all', the minimal_gather_subset should be returned
res = collector.get_collector_names(valid_subsets=valid_subsets, res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset, minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['all', '!my_fact', '!whatever'])) # gather_subset=set(['all', '!my_fact', '!whatever']))
# gather_subset=['all', '!my_fact', '!whatever'])
gather_subset=['!min_fact', '!whatever'])
self.assertIsInstance(res, set) self.assertIsInstance(res, set)
# my_facts is in minimal_gather_subset, so always returned # min_another is in minimal_gather_subset, so always returned
self.assertEqual(res, set(['my_fact', 'something_else'])) self.assertEqual(res, set(['min_another']))
def test_gather_subset_excludes_ordering(self): def test_gather_subset_excludes_ordering(self):
valid_subsets = frozenset(['my_fact', 'something_else', 'whatever']) valid_subsets = frozenset(['my_fact', 'something_else', 'whatever'])
@ -107,11 +147,35 @@ class TestGetCollectorNames(unittest.TestCase):
res = collector.get_collector_names(valid_subsets=valid_subsets, res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset, minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['!all', 'whatever'])) gather_subset=['!all', 'whatever'])
self.assertIsInstance(res, set) self.assertIsInstance(res, set)
# excludes are higher precedence than includes, so !all excludes everything # excludes are higher precedence than includes, so !all excludes everything
# and then minimal_gather_subset is added. so '!all', 'other' == '!all' # and then minimal_gather_subset is added. so '!all', 'other' == '!all'
self.assertEqual(res, set(['my_fact'])) self.assertEqual(res, set(['my_fact', 'whatever']))
def test_gather_subset_excludes_min(self):
valid_subsets = frozenset(['min_fact', 'something_else', 'whatever'])
minimal_gather_subset = frozenset(['min_fact'])
res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset,
gather_subset=['whatever', '!min'])
self.assertIsInstance(res, set)
# excludes are higher precedence than includes, so !all excludes everything
# and then minimal_gather_subset is added. so '!all', 'other' == '!all'
self.assertEqual(res, set(['whatever']))
def test_gather_subset_excludes_min_and_all(self):
valid_subsets = frozenset(['min_fact', 'something_else', 'whatever'])
minimal_gather_subset = frozenset(['min_fact'])
res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset,
gather_subset=['whatever', '!all', '!min'])
self.assertIsInstance(res, set)
# excludes are higher precedence than includes, so !all excludes everything
# and then minimal_gather_subset is added. so '!all', 'other' == '!all'
self.assertEqual(res, set(['whatever']))
def test_invaid_gather_subset(self): def test_invaid_gather_subset(self):
valid_subsets = frozenset(['my_fact', 'something_else']) valid_subsets = frozenset(['my_fact', 'something_else'])
@ -122,7 +186,7 @@ class TestGetCollectorNames(unittest.TestCase):
collector.get_collector_names, collector.get_collector_names,
valid_subsets=valid_subsets, valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset, minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['my_fact', 'not_a_valid_gather_subset'])) gather_subset=['my_fact', 'not_a_valid_gather_subset'])
class TestCollectorClassesFromGatherSubset(unittest.TestCase): class TestCollectorClassesFromGatherSubset(unittest.TestCase):
@ -145,13 +209,13 @@ class TestCollectorClassesFromGatherSubset(unittest.TestCase):
def test(self): def test(self):
res = self._classes(all_collector_classes=default_collectors.collectors, res = self._classes(all_collector_classes=default_collectors.collectors,
gather_subset=set(['!all'])) gather_subset=['!all'])
self.assertIsInstance(res, list) self.assertIsInstance(res, list)
self.assertEqual(res, []) self.assertEqual(res, [])
def test_env(self): def test_env(self):
res = self._classes(all_collector_classes=default_collectors.collectors, res = self._classes(all_collector_classes=default_collectors.collectors,
gather_subset=set(['env'])) gather_subset=['env'])
self.assertIsInstance(res, list) self.assertIsInstance(res, list)
self.assertEqual(res, [default_collectors.EnvFactCollector]) self.assertEqual(res, [default_collectors.EnvFactCollector])
@ -181,7 +245,7 @@ class TestCollectorClassesFromGatherSubset(unittest.TestCase):
def test_collector_specified_multiple_times(self): def test_collector_specified_multiple_times(self):
res = self._classes(all_collector_classes=default_collectors.collectors, res = self._classes(all_collector_classes=default_collectors.collectors,
gather_subset=set(['platform', 'all', 'machine'])) gather_subset=['platform', 'all', 'machine'])
self.assertIsInstance(res, list) self.assertIsInstance(res, list)
self.assertIn(default_collectors.PlatformFactCollector, self.assertIn(default_collectors.PlatformFactCollector,
res) res)
@ -193,4 +257,4 @@ class TestCollectorClassesFromGatherSubset(unittest.TestCase):
'Bad subset.*unknown_collector.*given to Ansible.*allowed\:.*all,.*env.*', 'Bad subset.*unknown_collector.*given to Ansible.*allowed\:.*all,.*env.*',
self._classes, self._classes,
all_collector_classes=default_collectors.collectors, all_collector_classes=default_collectors.collectors,
gather_subset=set(['env', 'unknown_collector'])) gather_subset=['env', 'unknown_collector'])

Loading…
Cancel
Save