Add backup parameter to cli_config (#50206)

* Add backup parameter to cli_config

* Add a unit test for cli_config backup
This commit is contained in:
Nathaniel Case
2018-12-21 09:55:14 -05:00
committed by GitHub
parent 92de28756d
commit 0b3aa75b7f
5 changed files with 206 additions and 2 deletions

View File

@@ -45,6 +45,17 @@ options:
Use I(net_put) or I(nxos_file_copy) module to copy the flat file
to remote device and then use set the fullpath to this argument.
type: 'str'
backup:
description:
- This argument will cause the module to create a full backup of
the current running config from the remote device before any
changes are made. The backup file is written to the C(backup)
folder in the playbook root directory or role root directory, if
playbook is part of an ansible role. If the directory does not exist,
it is created.
type: bool
default: 'no'
version_added: "2.8"
rollback:
description:
- The C(rollback) argument instructs the module to rollback the
@@ -140,6 +151,11 @@ commands:
returned: always
type: list
sample: ['interface Loopback999', 'no shutdown']
backup_path:
description: The full path to the backup file
returned: when backup is yes
type: str
sample: /playbooks/ansible/backup/hostname_config.2016-07-16@22:28:34
"""
import json
@@ -284,6 +300,7 @@ def main():
"""main entry point for execution
"""
argument_spec = dict(
backup=dict(default=False, type='bool'),
config=dict(type='str'),
commit=dict(type='bool'),
replace=dict(type='str'),
@@ -297,7 +314,7 @@ def main():
)
mutually_exclusive = [('config', 'rollback')]
required_one_of = [['config', 'rollback']]
required_one_of = [['backup', 'config', 'rollback']]
module = AnsibleModule(argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive,
@@ -323,6 +340,9 @@ def main():
candidate = to_text(module.params['config'])
running = connection.get_config(flags=flags)
if module.params['backup']:
result['__backup__'] = running
try:
result.update(run(module, capabilities, connection, candidate, running))
except Exception as exc:

View File

@@ -19,13 +19,54 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import glob
import os
import re
import time
from ansible.plugins.action.normal import ActionModule as _ActionModule
PRIVATE_KEYS_RE = re.compile('__.+__')
class ActionModule(_ActionModule):
def run(self, tmp=None, task_vars=None):
if self._play_context.connection != 'network_cli':
return {'failed': True, 'msg': 'Connection type %s is not valid for cli_config module' % self._play_context.connection}
return super(ActionModule, self).run(task_vars=task_vars)
result = super(ActionModule, self).run(task_vars=task_vars)
if self._task.args.get('backup') and result.get('__backup__'):
# User requested backup and no error occurred in module.
# NOTE: If there is a parameter error, _backup key may not be in results.
filepath = self._write_backup(task_vars['inventory_hostname'],
result['__backup__'])
result['backup_path'] = filepath
# strip out any keys that have two leading and two trailing
# underscore characters
for key in list(result.keys()):
if PRIVATE_KEYS_RE.match(key):
del result[key]
return result
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 _write_backup(self, host, contents):
backup_path = self._get_working_path() + '/backup'
if not os.path.exists(backup_path):
os.mkdir(backup_path)
for existing_backup in glob.glob('%s/%s_config.*' % (backup_path, host)):
os.remove(existing_backup)
tstamp = time.strftime("%Y-%m-%d@%H:%M:%S", time.localtime(time.time()))
filename = '%s/%s_config.%s' % (backup_path, host, tstamp)
open(filename, 'w').write(contents)
return filename