forked from ansible/ansible
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
network_put and network_get modules (ansible#39592)
* Initial commit * Socket Timeout and dest file handler * sftp handling * module name change as per review * multiple thread tmp file overwite problem * Integration test suite for network_put * add additional testcase for dest argument * fix pylint/pep8/modules warnings * add socket timeout for get_file * network_get module * pep8 issue on network_get * Review comments
- Loading branch information
Showing
12 changed files
with
543 additions
and
5 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#!/usr/bin/python | ||
# -*- coding: utf-8 -*- | ||
|
||
# (c) 2018, Ansible by Red Hat, inc | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
from __future__ import absolute_import, division, print_function | ||
__metaclass__ = type | ||
|
||
|
||
ANSIBLE_METADATA = {'metadata_version': '1.1', | ||
'status': ['preview'], | ||
'supported_by': 'network'} | ||
|
||
|
||
DOCUMENTATION = """ | ||
--- | ||
module: network_get | ||
version_added: "2.6" | ||
author: "Deepak Agrawal (@dagrawal)" | ||
short_description: Copy files from a network device to Ansible Controller | ||
description: | ||
- This module provides functionlity to copy file from network device to | ||
ansible controller. | ||
options: | ||
src: | ||
description: | ||
- Specifies the source file. The path to the source file can either be | ||
the full path on the network device or a relative path as per path | ||
supported by destination network device. | ||
required: true | ||
protocol: | ||
description: | ||
- Protocol used to transfer file. | ||
default: scp | ||
choices: ['scp', 'sftp'] | ||
dest: | ||
description: | ||
- Specifies the destination file. The path to the destination file can | ||
either be the full path on the Ansible control host or a relative | ||
path from the playbook or role root directory. | ||
default: | ||
- Same filename as specified in src. The path will be playbook root | ||
or role root directory if playbook is part of a role. | ||
requirements: | ||
- "scp" | ||
notes: | ||
- Some devices need specific configurations to be enabled before scp can work | ||
These configuration should be pre-configued before using this module | ||
e.g ios - C(ip scp server enable) | ||
- User privileage to do scp on network device should be pre-configured | ||
e.g. ios - need user privileage 15 by default for allowing scp | ||
- Default destination of source file | ||
""" | ||
|
||
EXAMPLES = """ | ||
- name: copy file from the network device to ansible controller | ||
network_get: | ||
src: running_cfg_ios1.txt | ||
- name: copy file from ios to common location at /tmp | ||
network_put: | ||
src: running_cfg_sw1.txt | ||
dest : /tmp/ios1.txt | ||
""" | ||
|
||
RETURN = """ | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#!/usr/bin/python | ||
# -*- coding: utf-8 -*- | ||
|
||
# (c) 2018, Ansible by Red Hat, inc | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
from __future__ import absolute_import, division, print_function | ||
__metaclass__ = type | ||
|
||
|
||
ANSIBLE_METADATA = {'metadata_version': '1.1', | ||
'status': ['preview'], | ||
'supported_by': 'network'} | ||
|
||
|
||
DOCUMENTATION = """ | ||
--- | ||
module: network_put | ||
version_added: "2.6" | ||
author: "Deepak Agrawal (@dagrawal)" | ||
short_description: Copy files from Ansibe controller to a network device | ||
description: | ||
- This module provides functionlity to copy file from Ansible controller to | ||
network devices. | ||
options: | ||
src: | ||
description: | ||
- Specifies the source file. The path to the source file can either be | ||
the full path on the Ansible control host or a relative path from the | ||
playbook or role root directory. | ||
required: true | ||
protocol: | ||
description: | ||
- Protocol used to transfer file. | ||
default: scp | ||
choices: ['scp', 'sftp'] | ||
dest: | ||
description: | ||
- Specifies the destination file. The path to destination file can | ||
either be the full path or relative path as supported by network_os. | ||
default: | ||
- Filename from src and at default directory of user shell on | ||
network_os. | ||
required: no | ||
requirements: | ||
- "scp" | ||
notes: | ||
- Some devices need specific configurations to be enabled before scp can work | ||
These configuration should be pre-configued before using this module | ||
e.g ios - C(ip scp server enable). | ||
- User privileage to do scp on network device should be pre-configured | ||
e.g. ios - need user privileage 15 by default for allowing scp. | ||
- Default destination of source file. | ||
""" | ||
|
||
EXAMPLES = """ | ||
- name: copy file from ansible controller to a network device | ||
network_put: | ||
src: running_cfg_ios1.txt | ||
- name: copy file at root dir of flash in slot 3 of sw1(ios) | ||
network_put: | ||
src: running_cfg_sw1.txt | ||
protocol: sftp | ||
dest : flash3:/running_cfg_sw1.txt | ||
""" | ||
|
||
RETURN = """ | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# (c) 2018, Ansible Inc, | ||
# | ||
# This file is part of Ansible | ||
# | ||
# Ansible is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# Ansible is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. | ||
from __future__ import (absolute_import, division, print_function) | ||
__metaclass__ = type | ||
|
||
import copy | ||
import os | ||
import time | ||
import re | ||
|
||
from ansible.module_utils._text import to_text | ||
from ansible.module_utils.connection import Connection | ||
from ansible.errors import AnsibleError | ||
from ansible.plugins.action import ActionBase | ||
from ansible.module_utils.six.moves.urllib.parse import urlsplit | ||
|
||
try: | ||
from __main__ import display | ||
except ImportError: | ||
from ansible.utils.display import Display | ||
display = Display() | ||
|
||
|
||
class ActionModule(ActionBase): | ||
|
||
def run(self, tmp=None, task_vars=None): | ||
socket_path = None | ||
play_context = copy.deepcopy(self._play_context) | ||
play_context.network_os = self._get_network_os(task_vars) | ||
|
||
result = super(ActionModule, self).run(task_vars=task_vars) | ||
|
||
if play_context.connection != 'network_cli': | ||
# It is supported only with network_cli | ||
result['failed'] = True | ||
result['msg'] = ('please use network_cli connection type for network_get module') | ||
return result | ||
|
||
try: | ||
src = self._task.args.get('src') | ||
except KeyError as exc: | ||
return {'failed': True, 'msg': 'missing required argument: %s' % exc} | ||
|
||
# Get destination file if specified | ||
dest = self._task.args.get('dest') | ||
|
||
if dest is None: | ||
dest = self._get_default_dest(src) | ||
else: | ||
dest = self._handle_dest_path(dest) | ||
|
||
# Get proto | ||
proto = self._task.args.get('protocol') | ||
if proto is None: | ||
proto = 'scp' | ||
|
||
sock_timeout = play_context.timeout | ||
|
||
if socket_path is None: | ||
socket_path = self._connection.socket_path | ||
|
||
conn = Connection(socket_path) | ||
|
||
try: | ||
out = conn.get_file( | ||
source=src, destination=dest, | ||
proto=proto, timeout=sock_timeout | ||
) | ||
except Exception as exc: | ||
result['failed'] = True | ||
result['msg'] = ('Exception received : %s' % exc) | ||
|
||
result['changed'] = True | ||
result['destination'] = dest | ||
return result | ||
|
||
def _handle_dest_path(self, dest): | ||
working_path = self._get_working_path() | ||
|
||
if os.path.isabs(dest) or urlsplit('dest').scheme: | ||
dst = dest | ||
else: | ||
dst = self._loader.path_dwim_relative(working_path, '', dest) | ||
|
||
return dst | ||
|
||
def _get_src_filename_from_path(self, src_path): | ||
filename_list = re.split('/|:', src_path) | ||
return filename_list[-1] | ||
|
||
def _get_working_path(self): | ||
cwd = self._loader.get_basedir() | ||
if self._task._role is not None: | ||
cwd = self._task._role._role_path | ||
return cwd | ||
|
||
def _get_default_dest(self, src_path): | ||
dest_path = self._get_working_path() | ||
src_fname = self._get_src_filename_from_path(src_path) | ||
filename = '%s/%s' % (dest_path, src_fname) | ||
return filename | ||
|
||
def _get_network_os(self, task_vars): | ||
if 'network_os' in self._task.args and self._task.args['network_os']: | ||
display.vvvv('Getting network OS from task argument') | ||
network_os = self._task.args['network_os'] | ||
elif self._play_context.network_os: | ||
display.vvvv('Getting network OS from inventory') | ||
network_os = self._play_context.network_os | ||
elif 'network_os' in task_vars.get('ansible_facts', {}) and task_vars['ansible_facts']['network_os']: | ||
display.vvvv('Getting network OS from fact') | ||
network_os = task_vars['ansible_facts']['network_os'] | ||
else: | ||
raise AnsibleError('ansible_network_os must be specified on this host to use platform agnostic modules') | ||
|
||
return network_os |
Oops, something went wrong.