From 1b2ad94496e38cc9f75cf95da3da01c0b2ad7201 Mon Sep 17 00:00:00 2001 From: Alvaro Aleman Date: Thu, 12 Jan 2017 16:49:04 +0100 Subject: [PATCH] Configurable fact path (#18147) * Make fact_path configurable * Add docs for fact_path * Add tests for localfacts * Default fact gathering settings in PlayContext --- docs/docsite/rst/intro_configuration.rst | 11 +++++ docs/docsite/rst/playbooks_variables.rst | 1 + lib/ansible/constants.py | 1 + lib/ansible/executor/play_iterator.py | 10 ++++- lib/ansible/playbook/play.py | 1 + lib/ansible/playbook/play_context.py | 5 +++ test/integration/inventory | 2 +- .../gathering_facts/test_gathering_facts.yml | 45 +++++++++++++++++++ 8 files changed, 73 insertions(+), 3 deletions(-) diff --git a/docs/docsite/rst/intro_configuration.rst b/docs/docsite/rst/intro_configuration.rst index 10663f3cfdf..debf369680d 100644 --- a/docs/docsite/rst/intro_configuration.rst +++ b/docs/docsite/rst/intro_configuration.rst @@ -387,6 +387,17 @@ is very very conservative:: forks = 5 +.. _fact_path: + +fact_path +========= + +This option allows you to globally configure a custom path for :ref:`_local_facts`:: + + fact_path = /home/centos/ansible_facts.d + +The default is to use the default from the `setup module `_: ``/etc/ansible/facts.d`` + .. _gathering: gathering diff --git a/docs/docsite/rst/playbooks_variables.rst b/docs/docsite/rst/playbooks_variables.rst index 6d7ab168f52..47cc23ee7c8 100644 --- a/docs/docsite/rst/playbooks_variables.rst +++ b/docs/docsite/rst/playbooks_variables.rst @@ -454,6 +454,7 @@ For instance, what if you want users to be able to control some aspect about how If a remotely managed system has an ``/etc/ansible/facts.d`` directory, any files in this directory ending in ``.fact``, can be JSON, INI, or executable files returning JSON, and these can supply local facts in Ansible. +An alternate directory can be specified using the ``fact_path`` play directive. For instance assume a ``/etc/ansible/facts.d/preferences.fact``:: diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 2a121e9d754..a754ad4e0a5 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -201,6 +201,7 @@ DEFAULT_ROLES_PATH = get_config(p, DEFAULTS, 'roles_path', 'ANSIBLE DEFAULT_REMOTE_TMP = get_config(p, DEFAULTS, 'remote_tmp', 'ANSIBLE_REMOTE_TEMP', '~/.ansible/tmp') DEFAULT_LOCAL_TMP = get_config(p, DEFAULTS, 'local_tmp', 'ANSIBLE_LOCAL_TEMP', '~/.ansible/tmp', value_type='tmppath') DEFAULT_MODULE_NAME = get_config(p, DEFAULTS, 'module_name', None, 'command') +DEFAULT_FACT_PATH = get_config(p, DEFAULTS, 'fact_path', 'ANSIBLE_FACT_PATH', None, value_type='path') DEFAULT_FORKS = get_config(p, DEFAULTS, 'forks', 'ANSIBLE_FORKS', 5, value_type='integer') DEFAULT_MODULE_ARGS = get_config(p, DEFAULTS, 'module_args', 'ANSIBLE_MODULE_ARGS', '') DEFAULT_MODULE_LANG = get_config(p, DEFAULTS, 'module_lang', 'ANSIBLE_MODULE_LANG', os.getenv('LANG', 'en_US.UTF-8')) diff --git a/lib/ansible/executor/play_iterator.py b/lib/ansible/executor/play_iterator.py index a8d92533f93..702dd7a5c75 100644 --- a/lib/ansible/executor/play_iterator.py +++ b/lib/ansible/executor/play_iterator.py @@ -163,8 +163,9 @@ class PlayIterator: self._task_uuid_cache = dict() # Default options to gather - gather_subset = C.DEFAULT_GATHER_SUBSET - gather_timeout = C.DEFAULT_GATHER_TIMEOUT + gather_subset = play_context.gather_subset + gather_timeout = play_context.gather_timeout + fact_path = play_context.fact_path # Retrieve subset to gather if self._play.gather_subset is not None: @@ -172,6 +173,9 @@ class PlayIterator: # Retrieve timeout for gather if self._play.gather_timeout is not None: gather_timeout = self._play.gather_timeout + # Retrieve fact_path + if self._play.fact_path is not None: + fact_path = self._play.fact_path setup_block = Block(play=self._play) setup_task = Task(block=setup_block) @@ -183,6 +187,8 @@ class PlayIterator: } if gather_timeout: setup_task.args['gather_timeout'] = gather_timeout + if fact_path: + setup_task.args['fact_path'] = fact_path setup_task.set_loader(self._play._loader) setup_block.block = [setup_task] diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py index 542344033ad..1f9c0bc4448 100644 --- a/lib/ansible/playbook/play.py +++ b/lib/ansible/playbook/play.py @@ -64,6 +64,7 @@ class Play(Base, Taggable, Become): _accelerate_port = FieldAttribute(isa='int', default=5099, always_post_validate=True) # Connection + _fact_path = FieldAttribute(isa='string', default=None) _gather_facts = FieldAttribute(isa='bool', default=None, always_post_validate=True) _gather_subset = FieldAttribute(isa='barelist', default=None, always_post_validate=True) _gather_timeout = FieldAttribute(isa='int', default=None, always_post_validate=True) diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py index cf2b7b481ec..f3660be3b7a 100644 --- a/lib/ansible/playbook/play_context.py +++ b/lib/ansible/playbook/play_context.py @@ -208,6 +208,11 @@ class PlayContext(Base): _step = FieldAttribute(isa='bool', default=False) _diff = FieldAttribute(isa='bool', default=False) + # Fact gathering settings + _gather_subset = FieldAttribute(isa='string', default=C.DEFAULT_GATHER_SUBSET) + _gather_timeout = FieldAttribute(isa='string', default=C.DEFAULT_GATHER_TIMEOUT) + _fact_path = FieldAttribute(isa='string', default=C.DEFAULT_FACT_PATH) + def __init__(self, play=None, options=None, passwords=None, connection_lockfd=None): super(PlayContext, self).__init__() diff --git a/test/integration/inventory b/test/integration/inventory index ee9e07a92bc..1e2a7bd7497 100644 --- a/test/integration/inventory +++ b/test/integration/inventory @@ -5,7 +5,7 @@ testhost2 ansible_ssh_host=127.0.0.1 ansible_connection=local testhost3 ansible_ssh_host=127.0.0.3 testhost4 ansible_ssh_host=127.0.0.4 # For testing fact gathering -facthost[0:8] ansible_host=1270.0.0.1 ansible_connection=local +facthost[0:9] ansible_host=1270.0.0.1 ansible_connection=local [binary_modules] testhost_binary_modules ansible_host=127.0.0.1 ansible_connection=local diff --git a/test/integration/targets/gathering_facts/test_gathering_facts.yml b/test/integration/targets/gathering_facts/test_gathering_facts.yml index 4b935434b3d..bfa5cf36875 100644 --- a/test/integration/targets/gathering_facts/test_gathering_facts.yml +++ b/test/integration/targets/gathering_facts/test_gathering_facts.yml @@ -129,3 +129,48 @@ - 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' - 'ansible_mounts|default("UNDEF_HW") == "UNDEF_HW"' - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' + +- hosts: facthost9 + tags: [ 'fact_local'] + connection: local + gather_facts: no + tasks: + - name: Create fact directories + become: true + with_items: + - /etc/ansible/facts.d + - /tmp/custom_facts.d + file: + state: directory + path: "{{ item }}" + mode: '0777' + - name: Deploy local facts + with_items: + - path: /etc/ansible/facts.d/testfact.fact + content: '{ "fact_dir": "default" }' + - path: /tmp/custom_facts.d/testfact.fact + content: '{ "fact_dir": "custom" }' + copy: + dest: "{{ item.path }}" + content: "{{ item.content }}" + +- hosts: facthost9 + tags: [ 'fact_local'] + connection: local + gather_facts: yes + tasks: + - name: Test reading facts from default fact_path + assert: + that: + - '"{{ ansible_local.testfact.fact_dir }}" == "default"' + +- hosts: facthost9 + tags: [ 'fact_local'] + connection: local + gather_facts: yes + fact_path: /tmp/custom_facts.d + tasks: + - name: Test reading facts from custom fact_path + assert: + that: + - '"{{ ansible_local.testfact.fact_dir }}" == "custom"'