diff --git a/action/config_template.py b/action/config_template.py index 00ddd8b..63cd217 100644 --- a/action/config_template.py +++ b/action/config_template.py @@ -38,6 +38,7 @@ import tempfile as tmpfilelib from ansible.plugins.action import ActionBase 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 errors from ansible.parsing.yaml.dumper import AnsibleDumper @@ -611,17 +612,30 @@ class ActionModule(ActionBase): file_path = self._loader.get_basedir() user_source = self._task.args.get('src') - # (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') + remote_src = boolean( + self._task.args.get('remote_src', False), + strict=False + ) + 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 - # converted dumped as json if config_type is 'json'. - if isinstance(_user_content, dict): - if self._task.args.get('config_type') == 'json': - _user_content = json.dumps(_user_content) + # If the data type of the content input is a dictionary, it's + # converted dumped as json if config_type is 'json'. + if isinstance(_user_content, dict): + if self._task.args.get('config_type') == 'json': + _user_content = json.dumps(_user_content) user_content = str(_user_content) if not user_source: @@ -671,6 +685,7 @@ class ActionModule(ActionBase): ignore_none_type = self._task.args.get('ignore_none_type', True) 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) @@ -683,7 +698,8 @@ class ActionModule(ActionBase): list_extend=list_extend, ignore_none_type=ignore_none_type, default_section=default_section, - yml_multilines=yml_multilines + yml_multilines=yml_multilines, + remote_src=remote_src ) 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('default_section', 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 new_module_args.pop('content', None) diff --git a/library/config_template b/library/config_template index 93a2662..bc1f3b7 100644 --- a/library/config_template +++ b/library/config_template @@ -64,6 +64,17 @@ options: section that will appear at the top of the configuration file. For example 'global'. 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 """ diff --git a/releasenotes/notes/add-remote_src-option-6418d4e5552cb88c.yaml b/releasenotes/notes/add-remote_src-option-6418d4e5552cb88c.yaml new file mode 100644 index 0000000..9f09290 --- /dev/null +++ b/releasenotes/notes/add-remote_src-option-6418d4e5552cb88c.yaml @@ -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. diff --git a/tests/files/test_remote_src_multistropts.ini.expected b/tests/files/test_remote_src_multistropts.ini.expected new file mode 100644 index 0000000..67827e6 --- /dev/null +++ b/tests/files/test_remote_src_multistropts.ini.expected @@ -0,0 +1,10 @@ +[multistropts] +test = test1 +test = test2 +test = test3 + +[remote_src_section] +test = output + +[testsection] +test = output diff --git a/tests/test-common-tasks.yml b/tests/test-common-tasks.yml index d5b08ee..4b73159 100644 --- a/tests/test-common-tasks.yml +++ b/tests/test-common-tasks.yml @@ -188,6 +188,44 @@ that: - _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' - name: Template test JSON template with content attribute config_template: