diff --git a/lib/ansible/modules/network/files/net_put.py b/lib/ansible/modules/network/files/net_put.py index 6333e3cd6f9..14dafe32e1f 100644 --- a/lib/ansible/modules/network/files/net_put.py +++ b/lib/ansible/modules/network/files/net_put.py @@ -42,6 +42,15 @@ options: - Filename from src and at default directory of user shell on network_os. required: no + mode: + description: + - Set the file transfer mode. If mode is set to 'template' then src + file will go through jinja2 template engine to replace any vars if + present in src file. If mode is set to 'binary' then file will be + copied as it is to destination device. + default: binary + choices: ['binary', 'template'] + version_added: "2.7" requirements: - "scp" diff --git a/lib/ansible/plugins/action/net_put.py b/lib/ansible/plugins/action/net_put.py index 0706a251dcb..c6bedc9bf99 100644 --- a/lib/ansible/plugins/action/net_put.py +++ b/lib/ansible/plugins/action/net_put.py @@ -50,18 +50,13 @@ class ActionModule(ActionBase): result['msg'] = ('please use network_cli connection type for net_put module') return result - src_file_path_name = self._task.args.get('src') - - try: - self._handle_template() - except ValueError as exc: - return dict(failed=True, msg=to_text(exc)) - try: src = self._task.args.get('src') except KeyError as exc: return {'failed': True, 'msg': 'missing required argument: %s' % exc} + src_file_path_name = src + # Get destination file if specified dest = self._task.args.get('dest') @@ -70,22 +65,38 @@ class ActionModule(ActionBase): if proto is None: proto = 'scp' - sock_timeout = play_context.timeout + # Get mode if set + mode = self._task.args.get('mode') + if mode is None: + mode = 'binary' - # Now src has resolved file write to disk in current diectory for scp - filename = str(uuid.uuid4()) - cwd = self._loader.get_basedir() - output_file = cwd + '/' + filename - with open(output_file, 'w') as f: - f.write(src) + if mode == 'template': + try: + self._handle_template() + except ValueError as exc: + return dict(failed=True, msg=to_text(exc)) + + # Now src has resolved file write to disk in current diectory for scp + src = self._task.args.get('src') + filename = str(uuid.uuid4()) + cwd = self._loader.get_basedir() + output_file = cwd + '/' + filename + with open(output_file, 'w') as f: + f.write(src) + else: + try: + output_file = self._get_binary_src_file(src) + except ValueError as exc: + return dict(failed=True, msg=to_text(exc)) if socket_path is None: socket_path = self._connection.socket_path conn = Connection(socket_path) + sock_timeout = conn.get_option('persistent_command_timeout') + if dest is None: dest = src_file_path_name - try: out = conn.copy_file( source=output_file, destination=dest, @@ -101,8 +112,10 @@ class ActionModule(ActionBase): result['failed'] = True result['msg'] = ('Exception received : %s' % exc) - # Cleanup tmp file expanded wih ansible vars - os.remove(output_file) + if mode == 'template': + # Cleanup tmp file expanded wih ansible vars + os.remove(output_file) + result['changed'] = True return result @@ -165,3 +178,18 @@ class ActionModule(ActionBase): raise AnsibleError('ansible_network_os must be specified on this host to use platform agnostic modules') return network_os + + def _get_binary_src_file(self, src): + working_path = self._get_working_path() + + if os.path.isabs(src) or urlsplit('src').scheme: + source = src + else: + source = self._loader.path_dwim_relative(working_path, 'templates', src) + if not source: + source = self._loader.path_dwim_relative(working_path, src) + + if not os.path.exists(source): + raise ValueError('path specified in src not found') + + return source diff --git a/test/integration/targets/ios_file/tests/cli/net_put.yaml b/test/integration/targets/ios_file/tests/cli/net_put.yaml index b0e70f8df46..81e8bcaea1f 100644 --- a/test/integration/targets/ios_file/tests/cli/net_put.yaml +++ b/test/integration/targets/ios_file/tests/cli/net_put.yaml @@ -31,4 +31,20 @@ that: - result.changed == true +- name: copy file with non-ascii characters to ios in template mode(Fail case) + net_put: + src: nonascii.bin + mode: 'template' + register: result + ignore_errors: true + +- name: copy file with non-ascii characters to ios in default mode(binary) + net_put: + src: nonascii.bin + register: result + +- assert: + that: + - result.changed == true + - debug: msg="END ios cli/net_put.yaml on connection={{ ansible_connection }}"