From 75b687247aa6fd7c5c06f182d15582ac9ed45a9a Mon Sep 17 00:00:00 2001 From: Michel Blanc Date: Wed, 20 Feb 2013 17:53:14 +0100 Subject: [PATCH 1/6] Adds filter option to setup module Adds facts filtering using fnmatch, via the 'filter' option. Usage: ansible -m setup -a 'filter=ansible_*_mb' --- library/setup | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/library/setup b/library/setup index 5119b086479..130e5e39a04 100644 --- a/library/setup +++ b/library/setup @@ -20,6 +20,7 @@ import array import fcntl +import fnmatch import glob import platform import re @@ -30,7 +31,13 @@ DOCUMENTATION = ''' --- module: setup short_description: Gathers facts about remote hosts -options: {} +options: + filter: + description: + - a filter that will be applied to the keys; only key matching filter will + be returned. The filter should be a shell-style wildcard. + required: false + default: * description: - This module is automatically called by playbooks to gather useful variables about remote hosts that can be used in playbooks. It can also be @@ -1084,9 +1091,12 @@ def run_setup(module): setup_options = {} facts = ansible_facts() + filtr = module.params['filter'] for (k, v) in facts.items(): - setup_options["ansible_%s" % k.replace('-', '_')] = v + k = "ansible_%s" % k.replace('-', '_') + if fnmatch.fnmatch(k, module.params['filter']): + setup_options[k] = v # if facter is installed, and we can use --json because # ruby-json is ALSO installed, include facter data in the JSON @@ -1100,7 +1110,9 @@ def run_setup(module): facter = False if facter: for (k,v) in facter_ds.items(): - setup_options["facter_%s" % k] = v + k = "facter_%s" % k + if fnmatch.fnmatch(k, module.params['filter']): + setup_options[k] = v # ditto for ohai, but just top level string keys # because it contains a lot of nested stuff we can't use for @@ -1117,7 +1129,8 @@ def run_setup(module): for (k,v) in ohai_ds.items(): if type(v) == str or type(v) == unicode: k2 = "ohai_%s" % k.replace('-', '_') - setup_options[k2] = v + if fnmatch.fnmatch(k2, module.params['filter']): + setup_options[k2] = v setup_result = {} setup_result['ansible_facts'] = setup_options @@ -1130,7 +1143,9 @@ def run_setup(module): def main(): global module module = AnsibleModule( - argument_spec = dict(), + argument_spec = dict( + filter=dict(default="*", required=False), + ), supports_check_mode = True, ) data = run_setup(module) From 5f4a24557ba2eaa7afbbf3a20e590d5ae7e2d191 Mon Sep 17 00:00:00 2001 From: Michel Blanc Date: Wed, 20 Feb 2013 17:57:59 +0100 Subject: [PATCH 2/6] Adds example for filter option in setup module Added an example on how to filter keys returned by the module. --- library/setup | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/setup b/library/setup index 130e5e39a04..6e70b983fcb 100644 --- a/library/setup +++ b/library/setup @@ -55,6 +55,8 @@ notes: examples: - code: ansible all -m setup --tree /tmp/facts description: Obtain facts from all hosts and store them indexed by I(hostname) at C(/tmp/facts). + - code: ansible all -m setup -a 'filter=ansible_*_mb' + description: Obtain I(only) facts regarding memory from all hosts and output them. author: Michael DeHaan ''' From 139e06d9afa08e17500a963302dda246916150f6 Mon Sep 17 00:00:00 2001 From: Michel Blanc Date: Wed, 20 Feb 2013 18:13:05 +0100 Subject: [PATCH 3/6] Added more examples for the filter option in setup Added examples covering all available globs Added a use case of filtering only facts returned by facter --- library/setup | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/library/setup b/library/setup index 6e70b983fcb..3b82de4d239 100644 --- a/library/setup +++ b/library/setup @@ -52,11 +52,20 @@ notes: bubbled up to the caller. Using the ansible facts and choosing to not install I(facter) and I(ohai) means you can avoid Ruby-dependencies on your remote systems. (See also M(facter) and M(ohai).) + - The filter option filters only the first level subkey below ansible_facts. examples: - code: ansible all -m setup --tree /tmp/facts description: Obtain facts from all hosts and store them indexed by I(hostname) at C(/tmp/facts). - code: ansible all -m setup -a 'filter=ansible_*_mb' - description: Obtain I(only) facts regarding memory from all hosts and output them. + description: Obtain I(only) facts regarding memory found by ansible on all hosts and output them. + - code: ansible all -m setup -a 'filter=facter_*' + description: Display I(only) facts returned by facter. + - code: ansible all -m setup -a 'filter=ansible_eth[0-2]' + description: Displays ansible facts abouts ethernet interfaces eth0, eth1, and eth2. + - code: ansible all -m setup -a 'filter=ansible_eth?' + description: Displays ansible facts abouts ethernet interfaces eth0 through eth9 (but not eth10). + - code: ansible all -m setup -a 'filter=ansible_eth[!0]' + description: Displays ansible facts abouts all ethernet interfaces but eth0. author: Michael DeHaan ''' From 627577ecc91afe90d644f301852f9a5c6b489370 Mon Sep 17 00:00:00 2001 From: Michel Blanc Date: Wed, 20 Feb 2013 19:12:01 +0100 Subject: [PATCH 4/6] Fixes unused var and avoid reassigning keys Changed code so key doesn't get reassigned in loop Made use of filtr variable --- library/setup | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/setup b/library/setup index 3b82de4d239..4dddd4384a1 100644 --- a/library/setup +++ b/library/setup @@ -1105,9 +1105,9 @@ def run_setup(module): filtr = module.params['filter'] for (k, v) in facts.items(): - k = "ansible_%s" % k.replace('-', '_') - if fnmatch.fnmatch(k, module.params['filter']): - setup_options[k] = v + k2 = "ansible_%s" % k.replace('-', '_') + if fnmatch.fnmatch(k2, filtr): + setup_options[k2] = v # if facter is installed, and we can use --json because # ruby-json is ALSO installed, include facter data in the JSON @@ -1121,9 +1121,9 @@ def run_setup(module): facter = False if facter: for (k,v) in facter_ds.items(): - k = "facter_%s" % k - if fnmatch.fnmatch(k, module.params['filter']): - setup_options[k] = v + k2 = "facter_%s" % k + if fnmatch.fnmatch(k2, filtr): + setup_options[k2] = v # ditto for ohai, but just top level string keys # because it contains a lot of nested stuff we can't use for @@ -1140,7 +1140,7 @@ def run_setup(module): for (k,v) in ohai_ds.items(): if type(v) == str or type(v) == unicode: k2 = "ohai_%s" % k.replace('-', '_') - if fnmatch.fnmatch(k2, module.params['filter']): + if fnmatch.fnmatch(k2, filtr): setup_options[k2] = v setup_result = {} From 7c270078f426a44e2e32e53cb8fa5a6e730a4cd7 Mon Sep 17 00:00:00 2001 From: Michel Blanc Date: Thu, 21 Feb 2013 01:10:25 +0100 Subject: [PATCH 5/6] Moved key filtering Key filtering moved before returning results --- library/setup | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/library/setup b/library/setup index 4dddd4384a1..b6c67fb1723 100644 --- a/library/setup +++ b/library/setup @@ -1102,12 +1102,9 @@ def run_setup(module): setup_options = {} facts = ansible_facts() - filtr = module.params['filter'] for (k, v) in facts.items(): - k2 = "ansible_%s" % k.replace('-', '_') - if fnmatch.fnmatch(k2, filtr): - setup_options[k2] = v + setup_options["ansible_%s" % k.replace('-', '_')] = v # if facter is installed, and we can use --json because # ruby-json is ALSO installed, include facter data in the JSON @@ -1121,9 +1118,7 @@ def run_setup(module): facter = False if facter: for (k,v) in facter_ds.items(): - k2 = "facter_%s" % k - if fnmatch.fnmatch(k2, filtr): - setup_options[k2] = v + setup_options["facter_%s" % k] = v # ditto for ohai, but just top level string keys # because it contains a lot of nested stuff we can't use for @@ -1140,11 +1135,13 @@ def run_setup(module): for (k,v) in ohai_ds.items(): if type(v) == str or type(v) == unicode: k2 = "ohai_%s" % k.replace('-', '_') - if fnmatch.fnmatch(k2, filtr): - setup_options[k2] = v + setup_options[k2] = v - setup_result = {} - setup_result['ansible_facts'] = setup_options + setup_result = { 'ansible_facts': {} } + + for (k,v) in setup_options.items(): + if fnmatch.fnmatch(k, module.params['filter']): + setup_result['ansible_facts'][k] = v # hack to keep --verbose from showing all the setup module results setup_result['verbose_override'] = True From 92c679142f62484b9cd1dd0427122026aa6f2a9f Mon Sep 17 00:00:00 2001 From: Michel Blanc Date: Fri, 22 Feb 2013 17:41:18 +0100 Subject: [PATCH 6/6] Optimizes using fnmatch only if needed Skips fnmatch'ing if there is only a '*' in filter. --- library/setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/setup b/library/setup index b6c67fb1723..5863eac7c59 100644 --- a/library/setup +++ b/library/setup @@ -1140,7 +1140,7 @@ def run_setup(module): setup_result = { 'ansible_facts': {} } for (k,v) in setup_options.items(): - if fnmatch.fnmatch(k, module.params['filter']): + if module.params['filter'] == '*' or fnmatch.fnmatch(k, module.params['filter']): setup_result['ansible_facts'][k] = v # hack to keep --verbose from showing all the setup module results