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.
This commit is contained in:
Adrian Likins 2017-08-02 11:04:01 -04:00 committed by GitHub
parent c85b36d220
commit 27a015f0ad
4 changed files with 172 additions and 36 deletions

View file

@ -111,16 +111,31 @@ def get_collector_names(valid_subsets=None,
additional_subsets = set()
exclude_subsets = set()
for subset in gather_subset:
subset_id = subset
# total always starts with the min set, then
# 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':
additional_subsets.update(valid_subsets)
continue
if subset_id.startswith('!'):
subset = subset[1:]
if subset == 'min':
exclude_subsets.update(minimal_gather_subset)
continue
if subset == 'all':
exclude_subsets.update(valid_subsets)
exclude_subsets.update(valid_subsets - minimal_gather_subset)
continue
exclude = True
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" %
(subset, ", ".join(sorted(valid_subsets))))
explicitly_added.add(subset)
additional_subsets.add(subset)
if not additional_subsets:
additional_subsets.update(valid_subsets)
additional_subsets.difference_update(exclude_subsets)
additional_subsets.update(minimal_gather_subset)
additional_subsets.difference_update(exclude_subsets - explicitly_added)
return additional_subsets

View file

@ -23,13 +23,16 @@ options:
version_added: "2.1"
description:
- "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.
Values can also be used with an initial C(!) to specify that
that specific subset should not be collected. For instance:
!hardware, !network, !virtual, !ohai, !facter. Note that a few
facts are always collected. Use the filter parameter if you do
not want to display those."
!hardware, !network, !virtual, !ohai, !facter. If !all is specified
then only the min subset is collected. To avoid collecting even the
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
default: 'all'
gather_timeout:
@ -93,18 +96,27 @@ EXAMPLES = """
# Display only facts returned by 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.
# 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'
# 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.
# 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'
# 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).
# ansible windows -m setup -a "fact_path='c:\\custom_facts'"
"""

View file

@ -1,5 +1,4 @@
---
- hosts: facthost7
tags: [ 'fact_negation' ]
connection: local
@ -12,9 +11,6 @@
- "!hardware"
register: not_hardware_facts
- name: debug setup with not hardware
debug:
var: not_hardware_facts
- hosts: facthost0
tags: [ 'fact_min' ]
@ -67,6 +63,7 @@
- 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"'
- 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"'
- 'ansible_env|default("UNDEF_ENV") == "UNDEF_ENV"'
- 'ansible_pkg_mgr|default("UNDEF_PKG_MGR") == "UNDEF_PKG_MGR"'
- hosts: facthost11
tags: [ 'fact_min' ]
@ -111,7 +108,10 @@
- name: Test that only retrieving minimal facts work
assert:
that:
# from the min set, which should still collect
- '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_mounts|default("UNDEF_HW") == "UNDEF_HW"'
- 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"'
@ -198,10 +198,16 @@
- name: Test that negation of fact subsets work
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 still collect
- 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"'
- 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"'
- 'ansible_mounts|default("UNDEF_HW") == "UNDEF_HW"'
- 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"'
- 'ansible_env|default("UNDEF_ENV") != "UNDEF_ENV"'
- hosts: facthost8
tags: [ 'fact_mixed_negation_addition' ]
@ -217,6 +223,46 @@
- 'ansible_mounts|default("UNDEF_HW") == "UNDEF_HW"'
- '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
tags: [ 'fact_local']
connection: local

View file

@ -37,14 +37,14 @@ class TestGetCollectorNames(unittest.TestCase):
def test_empty_sets(self):
res = collector.get_collector_names(valid_subsets=frozenset([]),
minimal_gather_subset=frozenset([]),
gather_subset=set([]))
gather_subset=[])
self.assertIsInstance(res, set)
self.assertEqual(res, set([]))
def test_empty_valid_and_min_with_all_gather_subset(self):
res = collector.get_collector_names(valid_subsets=frozenset([]),
minimal_gather_subset=frozenset([]),
gather_subset=set(['all']))
gather_subset=['all'])
self.assertIsInstance(res, set)
self.assertEqual(res, set([]))
@ -52,10 +52,48 @@ class TestGetCollectorNames(unittest.TestCase):
valid_subsets = frozenset(['my_fact'])
res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=frozenset([]),
gather_subset=set(['all']))
gather_subset=['all'])
self.assertIsInstance(res, set)
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):
my_fact = 'my_fact'
valid_subsets = frozenset([my_fact])
@ -63,7 +101,7 @@ class TestGetCollectorNames(unittest.TestCase):
res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['all']))
gather_subset=['all'])
self.assertIsInstance(res, set)
self.assertEqual(res, set(['my_fact']))
@ -74,7 +112,7 @@ class TestGetCollectorNames(unittest.TestCase):
# even with '!all', the minimal_gather_subset should be returned
res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['all']))
gather_subset=['all'])
self.assertIsInstance(res, set)
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
res = collector.get_collector_names(valid_subsets=valid_subsets,
minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['!all']))
gather_subset=['!all'])
self.assertIsInstance(res, set)
self.assertEqual(res, set(['my_fact']))
def test_gather_subset_excludes(self):
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
res = collector.get_collector_names(valid_subsets=valid_subsets,
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)
# my_facts is in minimal_gather_subset, so always returned
self.assertEqual(res, set(['my_fact', 'something_else']))
# min_another is in minimal_gather_subset, so always returned
self.assertEqual(res, set(['min_another']))
def test_gather_subset_excludes_ordering(self):
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,
minimal_gather_subset=minimal_gather_subset,
gather_subset=set(['!all', 'whatever']))
gather_subset=['!all', 'whatever'])
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(['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):
valid_subsets = frozenset(['my_fact', 'something_else'])
@ -122,7 +186,7 @@ class TestGetCollectorNames(unittest.TestCase):
collector.get_collector_names,
valid_subsets=valid_subsets,
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):
@ -145,13 +209,13 @@ class TestCollectorClassesFromGatherSubset(unittest.TestCase):
def test(self):
res = self._classes(all_collector_classes=default_collectors.collectors,
gather_subset=set(['!all']))
gather_subset=['!all'])
self.assertIsInstance(res, list)
self.assertEqual(res, [])
def test_env(self):
res = self._classes(all_collector_classes=default_collectors.collectors,
gather_subset=set(['env']))
gather_subset=['env'])
self.assertIsInstance(res, list)
self.assertEqual(res, [default_collectors.EnvFactCollector])
@ -181,7 +245,7 @@ class TestCollectorClassesFromGatherSubset(unittest.TestCase):
def test_collector_specified_multiple_times(self):
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.assertIn(default_collectors.PlatformFactCollector,
res)
@ -193,4 +257,4 @@ class TestCollectorClassesFromGatherSubset(unittest.TestCase):
'Bad subset.*unknown_collector.*given to Ansible.*allowed\:.*all,.*env.*',
self._classes,
all_collector_classes=default_collectors.collectors,
gather_subset=set(['env', 'unknown_collector']))
gather_subset=['env', 'unknown_collector'])