Add option to use a remote source
The config template action plugin assumes that the local node is supplying a configuration file that will be used to copy content to a target node. This change gives the module the ability to change configuration files on target nodes using all remote sources. The new boolean option, `remote_src` has been added to enable or disable this functionality. When enabled, the module will retrieve content from the target node and load it as "user_content". By pre-loading it in the user content the module will function normally without any major structural changes or performance impact. Change-Id: Id9c7e16fb935c2da0b32b7cf53449f68bd1e9c89 Signed-off-by: Kevin Carter <kecarter@redhat.com>
This commit is contained in:
parent
28a6032612
commit
73aa099f0a
@ -38,6 +38,7 @@ import tempfile as tmpfilelib
|
|||||||
|
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
from ansible.module_utils.parsing.convert_bool import boolean
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible import errors
|
from ansible import errors
|
||||||
from ansible.parsing.yaml.dumper import AnsibleDumper
|
from ansible.parsing.yaml.dumper import AnsibleDumper
|
||||||
@ -611,17 +612,30 @@ class ActionModule(ActionBase):
|
|||||||
file_path = self._loader.get_basedir()
|
file_path = self._loader.get_basedir()
|
||||||
|
|
||||||
user_source = self._task.args.get('src')
|
user_source = self._task.args.get('src')
|
||||||
# (alextricity25) It's possible that the user could pass in a datatype
|
remote_src = boolean(
|
||||||
# and not always a string. In this case we don't want the datatype
|
self._task.args.get('remote_src', False),
|
||||||
# python representation to be printed out to the file, but rather we
|
strict=False
|
||||||
# want the serialized version.
|
)
|
||||||
_user_content = self._task.args.get('content')
|
if remote_src:
|
||||||
|
slurpee = self._execute_module(
|
||||||
|
module_name='slurp',
|
||||||
|
module_args=dict(src=user_source),
|
||||||
|
task_vars=task_vars
|
||||||
|
)
|
||||||
|
_content = base64.b64decode(slurpee['content'])
|
||||||
|
_user_content = _content.decode('utf-8')
|
||||||
|
else:
|
||||||
|
# (alextricity25) It's possible that the user could pass in a
|
||||||
|
# datatype and not always a string. In this case we don't want
|
||||||
|
# the datatype python representation to be printed out to the
|
||||||
|
# file, but rather we want the serialized version.
|
||||||
|
_user_content = self._task.args.get('content')
|
||||||
|
|
||||||
# If the data type of the content input is a dictionary, it's
|
# If the data type of the content input is a dictionary, it's
|
||||||
# converted dumped as json if config_type is 'json'.
|
# converted dumped as json if config_type is 'json'.
|
||||||
if isinstance(_user_content, dict):
|
if isinstance(_user_content, dict):
|
||||||
if self._task.args.get('config_type') == 'json':
|
if self._task.args.get('config_type') == 'json':
|
||||||
_user_content = json.dumps(_user_content)
|
_user_content = json.dumps(_user_content)
|
||||||
|
|
||||||
user_content = str(_user_content)
|
user_content = str(_user_content)
|
||||||
if not user_source:
|
if not user_source:
|
||||||
@ -671,6 +685,7 @@ class ActionModule(ActionBase):
|
|||||||
ignore_none_type = self._task.args.get('ignore_none_type', True)
|
ignore_none_type = self._task.args.get('ignore_none_type', True)
|
||||||
|
|
||||||
default_section = self._task.args.get('default_section', 'DEFAULT')
|
default_section = self._task.args.get('default_section', 'DEFAULT')
|
||||||
|
remote_src = self._task.args.get('remote_src', False)
|
||||||
|
|
||||||
yml_multilines = self._task.args.get('yml_multilines', False)
|
yml_multilines = self._task.args.get('yml_multilines', False)
|
||||||
|
|
||||||
@ -683,7 +698,8 @@ class ActionModule(ActionBase):
|
|||||||
list_extend=list_extend,
|
list_extend=list_extend,
|
||||||
ignore_none_type=ignore_none_type,
|
ignore_none_type=ignore_none_type,
|
||||||
default_section=default_section,
|
default_section=default_section,
|
||||||
yml_multilines=yml_multilines
|
yml_multilines=yml_multilines,
|
||||||
|
remote_src=remote_src
|
||||||
)
|
)
|
||||||
|
|
||||||
def run(self, tmp=None, task_vars=None):
|
def run(self, tmp=None, task_vars=None):
|
||||||
@ -838,6 +854,10 @@ class ActionModule(ActionBase):
|
|||||||
new_module_args.pop('ignore_none_type', None)
|
new_module_args.pop('ignore_none_type', None)
|
||||||
new_module_args.pop('default_section', None)
|
new_module_args.pop('default_section', None)
|
||||||
new_module_args.pop('yml_multilines', None)
|
new_module_args.pop('yml_multilines', None)
|
||||||
|
|
||||||
|
# While this is in the copy module we dont want to use it.
|
||||||
|
new_module_args.pop('remote_src', None)
|
||||||
|
|
||||||
# Content from config_template is converted to src
|
# Content from config_template is converted to src
|
||||||
new_module_args.pop('content', None)
|
new_module_args.pop('content', None)
|
||||||
|
|
||||||
|
@ -64,6 +64,17 @@ options:
|
|||||||
section that will appear at the top of the configuration file. For
|
section that will appear at the top of the configuration file. For
|
||||||
example 'global'.
|
example 'global'.
|
||||||
default: 'DEFAULT'
|
default: 'DEFAULT'
|
||||||
|
remote_src:
|
||||||
|
description:
|
||||||
|
- Influence whether the template needs to be transferred or already is
|
||||||
|
present remotely.
|
||||||
|
- If false, it will search the originating machine.
|
||||||
|
- If true, it will go to the remote/target machine to inject the
|
||||||
|
template. If the remote source does not exist the module will fail.
|
||||||
|
choices:
|
||||||
|
- True
|
||||||
|
- False
|
||||||
|
default: false
|
||||||
|
|
||||||
author: Kevin Carter
|
author: Kevin Carter
|
||||||
"""
|
"""
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- The ability to set `remote_src` has been added to the `config_template`
|
||||||
|
action plugin. This option will instruct the `config_template` action
|
||||||
|
plugin to use an already remote file as its source content.
|
10
tests/files/test_remote_src_multistropts.ini.expected
Normal file
10
tests/files/test_remote_src_multistropts.ini.expected
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[multistropts]
|
||||||
|
test = test1
|
||||||
|
test = test2
|
||||||
|
test = test3
|
||||||
|
|
||||||
|
[remote_src_section]
|
||||||
|
test = output
|
||||||
|
|
||||||
|
[testsection]
|
||||||
|
test = output
|
@ -188,6 +188,44 @@
|
|||||||
that:
|
that:
|
||||||
- _multistropts_file == _multistropts_expected_file
|
- _multistropts_file == _multistropts_expected_file
|
||||||
|
|
||||||
|
# Test remote_src
|
||||||
|
- name: Template remote source using overrides
|
||||||
|
config_template:
|
||||||
|
src: /tmp/test_multistropts.ini
|
||||||
|
dest: /tmp/test_remote_src_multistropts.ini
|
||||||
|
remote_src: true
|
||||||
|
config_overrides:
|
||||||
|
remote_src_section:
|
||||||
|
test: output
|
||||||
|
config_type: ini
|
||||||
|
- name: Create expected MultiStrOpts file
|
||||||
|
copy:
|
||||||
|
src: files/test_remote_src_multistropts.ini.expected
|
||||||
|
dest: /tmp/test_remote_src_multistropts.ini.expected
|
||||||
|
|
||||||
|
- name: Read test_remote_src_multistropts.ini
|
||||||
|
slurp:
|
||||||
|
src: /tmp/test_remote_src_multistropts.ini
|
||||||
|
register: multistropts_file
|
||||||
|
- name: Read test_remote_src_multistropts.ini.expected
|
||||||
|
slurp:
|
||||||
|
src: /tmp/test_remote_src_multistropts.ini.expected
|
||||||
|
register: multistropts_expected_file
|
||||||
|
- name: Set content facts
|
||||||
|
set_fact:
|
||||||
|
_remote_src_file: "{{ (multistropts_file.content | b64decode).strip() }}"
|
||||||
|
_remote_src_expected_file: "{{ (multistropts_expected_file.content | b64decode).strip() }}"
|
||||||
|
- name: Show rendered file
|
||||||
|
debug:
|
||||||
|
msg: "multistropts rendered - {{ _remote_src_file }}"
|
||||||
|
- name: Show expected file
|
||||||
|
debug:
|
||||||
|
msg: "multistropts expected - {{ _remote_src_expected_file }}"
|
||||||
|
- name: Compare files
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- _remote_src_file == _remote_src_expected_file
|
||||||
|
|
||||||
# Test content attribute with a dictionary input and config_type equal to 'json'
|
# Test content attribute with a dictionary input and config_type equal to 'json'
|
||||||
- name: Template test JSON template with content attribute
|
- name: Template test JSON template with content attribute
|
||||||
config_template:
|
config_template:
|
||||||
|
Loading…
Reference in New Issue
Block a user