Refactor ios cliconf plugin and ios_config module (#39695)

* Refactor ios cliconf plugin and ios_config module

*  Refactor ios cliconf plugin to support generic network_config module
*  Refactor ios_config module to work with cliconf api's
*  Enable command and response logging in cliconf pulgin
*  cliconf api documentation

* Fix unit test and other minor changes

* Doc update

* Fix CI failure

* Add default flag related changes

* Minor changes

* redact input command logging by default
This commit is contained in:
Ganesh Nalawade 2018-06-06 11:12:45 +05:30 committed by GitHub
commit ba4b12358c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 473 additions and 182 deletions

View file

@ -291,17 +291,14 @@ backup_path:
type: string
sample: /playbooks/ansible/backup/ios_config.2016-07-16@22:28:34
"""
import re
import time
import json
from ansible.module_utils.network.ios.ios import run_commands, get_config, load_config
from ansible.module_utils.network.ios.ios import get_defaults_flag
from ansible.module_utils.network.ios.ios import run_commands, get_config
from ansible.module_utils.network.ios.ios import get_defaults_flag, get_connection
from ansible.module_utils.network.ios.ios import ios_argument_spec
from ansible.module_utils.network.ios.ios import check_args as ios_check_args
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.parsing import Conditional
from ansible.module_utils.network.common.config import NetworkConfig, dumps
from ansible.module_utils.six import iteritems
def check_args(module, warnings):
@ -312,70 +309,29 @@ def check_args(module, warnings):
'single character')
def extract_banners(config):
banners = {}
banner_cmds = re.findall(r'^banner (\w+)', config, re.M)
for cmd in banner_cmds:
regex = r'banner %s \^C(.+?)(?=\^C)' % cmd
match = re.search(regex, config, re.S)
if match:
key = 'banner %s' % cmd
banners[key] = match.group(1).strip()
def get_candidate_config(module):
candidate = ''
if module.params['src']:
candidate = module.params['src']
for cmd in banner_cmds:
regex = r'banner %s \^C(.+?)(?=\^C)' % cmd
match = re.search(regex, config, re.S)
if match:
config = config.replace(str(match.group(1)), '')
elif module.params['lines']:
candidate_obj = NetworkConfig(indent=1)
parents = module.params['parents'] or list()
candidate_obj.add(module.params['lines'], parents=parents)
candidate = dumps(candidate_obj, 'raw')
config = re.sub(r'banner \w+ \^C\^C', '!! banner removed', config)
return (config, banners)
def diff_banners(want, have):
candidate = {}
for key, value in iteritems(want):
if value != have.get(key):
candidate[key] = value
return candidate
def load_banners(module, banners):
delimiter = module.params['multiline_delimiter']
for key, value in iteritems(banners):
key += ' %s' % delimiter
for cmd in ['config terminal', key, value, delimiter, 'end']:
obj = {'command': cmd, 'sendonly': True}
run_commands(module, [cmd])
time.sleep(0.1)
run_commands(module, ['\n'])
def get_running_config(module, current_config=None, flags=None):
contents = module.params['running_config']
if not contents:
running = module.params['running_config']
if not running:
if not module.params['defaults'] and current_config:
contents, banners = extract_banners(current_config.config_text)
running = current_config
else:
contents = get_config(module, flags=flags)
contents, banners = extract_banners(contents)
return NetworkConfig(indent=1, contents=contents), banners
running = get_config(module, flags=flags)
def get_candidate(module):
candidate = NetworkConfig(indent=1)
banners = {}
if module.params['src']:
src, banners = extract_banners(module.params['src'])
candidate.load(src)
elif module.params['lines']:
parents = module.params['parents'] or list()
candidate.add(module.params['lines'], parents=parents)
return candidate, banners
return running
def save_config(module, result):
@ -445,7 +401,9 @@ def main():
result['warnings'] = warnings
config = None
contents = None
flags = get_defaults_flag(module) if module.params['defaults'] else []
connection = get_connection(module)
if module.params['backup'] or (module._diff and module.params['diff_against'] == 'running'):
contents = get_config(module, flags=flags)
@ -458,20 +416,16 @@ def main():
replace = module.params['replace']
path = module.params['parents']
candidate, want_banners = get_candidate(module)
candidate = get_candidate_config(module)
running = get_running_config(module, contents, flags=flags)
if match != 'none':
config, have_banners = get_running_config(module, config, flags=flags)
path = module.params['parents']
configobjs = candidate.difference(config, path=path, match=match, replace=replace)
else:
configobjs = candidate.items
have_banners = {}
response = connection.get_diff(candidate=candidate, running=running, match=match, diff_ignore_lines=None, path=path, replace=replace)
diff = json.loads(response)
config_diff = diff['config_diff']
banner_diff = diff['banner_diff']
banners = diff_banners(want_banners, have_banners)
if configobjs or banners:
commands = dumps(configobjs, 'commands').split('\n')
if config_diff or banner_diff:
commands = config_diff.split('\n')
if module.params['before']:
commands[:0] = module.params['before']
@ -481,15 +435,15 @@ def main():
result['commands'] = commands
result['updates'] = commands
result['banners'] = banners
result['banners'] = banner_diff
# send the configuration commands to the device and merge
# them with the current running config
if not module.check_mode:
if commands:
load_config(module, commands)
if banners:
load_banners(module, banners)
connection.edit_config(commands)
if banner_diff:
connection.edit_banner(json.dumps(banner_diff), multiline_delimiter=module.params['multiline_delimiter'])
result['changed'] = True
@ -556,6 +510,5 @@ def main():
module.exit_json(**result)
if __name__ == '__main__':
main()