mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Fixes for broken asa_config module (#27218)
* Fixes for broken asa_config module * strip() prompt before checking
This commit is contained in:
parent
40eb349ac6
commit
089226e372
5 changed files with 136 additions and 50 deletions
|
@ -103,9 +103,10 @@ def to_commands(module, commands):
|
||||||
|
|
||||||
|
|
||||||
def run_commands(module, commands, check_rc=True):
|
def run_commands(module, commands, check_rc=True):
|
||||||
commands = to_commands(module, to_list(commands))
|
|
||||||
connection = get_connection(module)
|
connection = get_connection(module)
|
||||||
|
|
||||||
|
commands = to_commands(module, to_list(commands))
|
||||||
|
|
||||||
responses = list()
|
responses = list()
|
||||||
|
|
||||||
for cmd in commands:
|
for cmd in commands:
|
||||||
|
@ -116,9 +117,13 @@ def run_commands(module, commands, check_rc=True):
|
||||||
|
|
||||||
|
|
||||||
def get_config(module, flags=[]):
|
def get_config(module, flags=[]):
|
||||||
cmd = 'show running-config '
|
passwords = module.params['passwords']
|
||||||
cmd += ' '.join(flags)
|
if passwords:
|
||||||
cmd = cmd.strip()
|
cmd = 'more system:running-config'
|
||||||
|
else:
|
||||||
|
cmd = 'show running-config '
|
||||||
|
cmd += ' '.join(flags)
|
||||||
|
cmd = cmd.strip()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return _DEVICE_CONFIGS[cmd]
|
return _DEVICE_CONFIGS[cmd]
|
||||||
|
|
|
@ -172,7 +172,6 @@ vars:
|
||||||
password: cisco
|
password: cisco
|
||||||
authorize: yes
|
authorize: yes
|
||||||
auth_pass: cisco
|
auth_pass: cisco
|
||||||
transport: cli
|
|
||||||
|
|
||||||
---
|
---
|
||||||
- asa_config:
|
- asa_config:
|
||||||
|
@ -216,30 +215,14 @@ backup_path:
|
||||||
returned: when backup is yes
|
returned: when backup is yes
|
||||||
type: string
|
type: string
|
||||||
sample: /playbooks/ansible/backup/asa_config.2016-07-16@22:28:34
|
sample: /playbooks/ansible/backup/asa_config.2016-07-16@22:28:34
|
||||||
responses:
|
|
||||||
description: The set of responses from issuing the commands on the device
|
|
||||||
returned: when not check_mode
|
|
||||||
type: list
|
|
||||||
sample: ['...', '...']
|
|
||||||
"""
|
"""
|
||||||
import traceback
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.asa import asa_argument_spec, check_args
|
||||||
from ansible.module_utils.network import NetworkModule, NetworkError
|
from ansible.module_utils.asa import get_config, load_config, run_commands
|
||||||
from ansible.module_utils.netcfg import NetworkConfig, dumps
|
from ansible.module_utils.netcfg import NetworkConfig, dumps
|
||||||
from ansible.module_utils._text import to_native
|
from ansible.module_utils._text import to_native
|
||||||
|
|
||||||
|
|
||||||
def get_config(module):
|
|
||||||
contents = module.params['config']
|
|
||||||
if not contents:
|
|
||||||
if module.params['defaults']:
|
|
||||||
include = 'defaults'
|
|
||||||
elif module.params['passwords']:
|
|
||||||
include = 'passwords'
|
|
||||||
else:
|
|
||||||
include = None
|
|
||||||
contents = module.config.get_config(include=include)
|
|
||||||
return NetworkConfig(indent=1, contents=contents)
|
|
||||||
|
|
||||||
def get_candidate(module):
|
def get_candidate(module):
|
||||||
candidate = NetworkConfig(indent=1)
|
candidate = NetworkConfig(indent=1)
|
||||||
|
@ -256,11 +239,14 @@ def run(module, result):
|
||||||
path = module.params['parents']
|
path = module.params['parents']
|
||||||
|
|
||||||
candidate = get_candidate(module)
|
candidate = get_candidate(module)
|
||||||
|
|
||||||
if match != 'none':
|
if match != 'none':
|
||||||
config = get_config(module)
|
contents = module.params['config']
|
||||||
configobjs = candidate.difference(config, path=path, match=match,
|
if not contents:
|
||||||
replace=replace)
|
contents = get_config(module)
|
||||||
|
config = NetworkConfig(indent=1, contents=contents)
|
||||||
|
configobjs = candidate.difference(config, path=path, match=match,
|
||||||
|
replace=replace)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
configobjs = candidate.items
|
configobjs = candidate.items
|
||||||
|
|
||||||
|
@ -279,7 +265,7 @@ def run(module, result):
|
||||||
# send the configuration commands to the device and merge
|
# send the configuration commands to the device and merge
|
||||||
# them with the current running config
|
# them with the current running config
|
||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
result['responses'] = module.config.load_config(commands)
|
load_config(module, commands)
|
||||||
result['changed'] = True
|
result['changed'] = True
|
||||||
|
|
||||||
if module.params['save']:
|
if module.params['save']:
|
||||||
|
@ -310,27 +296,30 @@ def main():
|
||||||
save=dict(type='bool', default=False),
|
save=dict(type='bool', default=False),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
argument_spec.update(asa_argument_spec)
|
||||||
|
|
||||||
mutually_exclusive = [('lines', 'src'), ('defaults', 'passwords')]
|
mutually_exclusive = [('lines', 'src'), ('defaults', 'passwords')]
|
||||||
|
|
||||||
required_if = [('match', 'strict', ['lines']),
|
required_if = [('match', 'strict', ['lines']),
|
||||||
('match', 'exact', ['lines']),
|
('match', 'exact', ['lines']),
|
||||||
('replace', 'block', ['lines'])]
|
('replace', 'block', ['lines'])]
|
||||||
|
|
||||||
module = NetworkModule(argument_spec=argument_spec,
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
connect_on_load=False,
|
|
||||||
mutually_exclusive=mutually_exclusive,
|
mutually_exclusive=mutually_exclusive,
|
||||||
required_if=required_if,
|
required_if=required_if,
|
||||||
supports_check_mode=True)
|
supports_check_mode=True)
|
||||||
|
|
||||||
result = dict(changed=False)
|
result = {'changed': False}
|
||||||
|
|
||||||
|
check_args(module)
|
||||||
|
|
||||||
|
config = None
|
||||||
|
|
||||||
|
|
||||||
if module.params['backup']:
|
if module.params['backup']:
|
||||||
result['__backup__'] = module.config.get_config()
|
result['__backup__'] = get_config(module)
|
||||||
|
|
||||||
try:
|
run(module, result)
|
||||||
run(module, result)
|
|
||||||
except NetworkError as e:
|
|
||||||
module.fail_json(msg=to_native(e), exception=traceback.format_exc(), **e.kwargs)
|
|
||||||
|
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
|
@ -77,11 +77,6 @@ class ActionModule(_ActionModule):
|
||||||
|
|
||||||
result = super(ActionModule, self).run(tmp, task_vars)
|
result = super(ActionModule, self).run(tmp, task_vars)
|
||||||
|
|
||||||
# take the shell out of enable mode
|
|
||||||
if pc.become:
|
|
||||||
req = json.dumps(request_builder('get', 'disable'))
|
|
||||||
out = connection.exec_command(req)
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def load_provider(self):
|
def load_provider(self):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright 2015 Peter Sprygada <psprygada@ansible.com>
|
# (c) 2017, Red Hat, Inc.
|
||||||
#
|
#
|
||||||
# This file is part of Ansible
|
# This file is part of Ansible
|
||||||
#
|
#
|
||||||
|
@ -19,9 +19,94 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
from ansible.plugins.action import ActionBase
|
import os
|
||||||
from ansible.plugins.action.net_config import ActionModule as NetActionModule
|
import re
|
||||||
|
import time
|
||||||
|
import glob
|
||||||
|
|
||||||
|
from ansible.plugins.action.asa import ActionModule as _ActionModule
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
|
from ansible.module_utils.six.moves.urllib.parse import urlsplit
|
||||||
|
from ansible.utils.vars import merge_hash
|
||||||
|
|
||||||
|
PRIVATE_KEYS_RE = re.compile('__.+__')
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(NetActionModule, ActionBase):
|
class ActionModule(_ActionModule):
|
||||||
pass
|
|
||||||
|
def run(self, tmp=None, task_vars=None):
|
||||||
|
|
||||||
|
if self._task.args.get('src'):
|
||||||
|
try:
|
||||||
|
self._handle_template()
|
||||||
|
except ValueError as exc:
|
||||||
|
return dict(failed=True, msg=exc.message)
|
||||||
|
|
||||||
|
result = super(ActionModule, self).run(tmp, 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 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 fn in glob.glob('%s/%s*' % (backup_path, host)):
|
||||||
|
os.remove(fn)
|
||||||
|
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
|
||||||
|
|
||||||
|
def _handle_template(self):
|
||||||
|
src = self._task.args.get('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')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(source, 'r') as f:
|
||||||
|
template_data = to_text(f.read())
|
||||||
|
except IOError:
|
||||||
|
return dict(failed=True, msg='unable to load src file')
|
||||||
|
|
||||||
|
# Create a template search path in the following order:
|
||||||
|
# [working_path, self_role_path, dependent_role_paths, dirname(source)]
|
||||||
|
searchpath = [working_path]
|
||||||
|
if self._task._role is not None:
|
||||||
|
searchpath.append(self._task._role._role_path)
|
||||||
|
if hasattr(self._task, "_block:"):
|
||||||
|
dep_chain = self._task._block.get_dep_chain()
|
||||||
|
if dep_chain is not None:
|
||||||
|
for role in dep_chain:
|
||||||
|
searchpath.append(role._role_path)
|
||||||
|
searchpath.append(os.path.dirname(source))
|
||||||
|
self._templar.environment.loader.searchpath = searchpath
|
||||||
|
self._task.args['src'] = self._templar.template(template_data)
|
||||||
|
|
|
@ -36,11 +36,22 @@ class TerminalModule(TerminalBase):
|
||||||
|
|
||||||
terminal_stderr_re = [
|
terminal_stderr_re = [
|
||||||
re.compile(r"error:", re.I),
|
re.compile(r"error:", re.I),
|
||||||
re.compile(r"^Removing.* not allowed")
|
re.compile(br"Removing.* not allowed, it is being used")
|
||||||
]
|
]
|
||||||
|
|
||||||
def on_authorize(self, passwd=None):
|
def on_open_shell(self):
|
||||||
if self._get_prompt().endswith(b'#'):
|
if self._get_prompt().endswith(b'#'):
|
||||||
|
self.disable_pager()
|
||||||
|
|
||||||
|
def disable_pager(self):
|
||||||
|
cmd = {u'command': u'no terminal pager'}
|
||||||
|
try:
|
||||||
|
self._exec_cli_command(u'no terminal pager')
|
||||||
|
except AnsibleConnectionFailure:
|
||||||
|
raise AnsibleConnectionFailure('unable to disable terminal pager')
|
||||||
|
|
||||||
|
def on_authorize(self, passwd=None):
|
||||||
|
if self._get_prompt().strip().endswith(b'#'):
|
||||||
return
|
return
|
||||||
|
|
||||||
cmd = {u'command': u'enable'}
|
cmd = {u'command': u'enable'}
|
||||||
|
@ -52,6 +63,7 @@ class TerminalModule(TerminalBase):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._exec_cli_command(to_bytes(json.dumps(cmd), errors='surrogate_or_strict'))
|
self._exec_cli_command(to_bytes(json.dumps(cmd), errors='surrogate_or_strict'))
|
||||||
self._exec_cli_command(u'no terminal pager')
|
|
||||||
except AnsibleConnectionFailure:
|
except AnsibleConnectionFailure:
|
||||||
raise AnsibleConnectionFailure('unable to elevate privilege to enable mode')
|
raise AnsibleConnectionFailure('unable to elevate privilege to enable mode')
|
||||||
|
|
||||||
|
self.disable_pager()
|
||||||
|
|
Loading…
Add table
Reference in a new issue