refactors nxos module to use persistent connections (#21470)

This completes the refactor of the nxos modules to use the persistent
connection.  It also updates all of the nxos modules to use the
new connection module and preserves use of nxapi as well.
This commit is contained in:
Peter Sprygada 2017-02-15 11:43:09 -05:00 committed by GitHub
parent eb1453a366
commit 21d993a4b8
72 changed files with 2301 additions and 12933 deletions

View file

@ -16,9 +16,11 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'core',
'version': '1.0'}
ANSIBLE_METADATA = {
'status': ['preview'],
'supported_by': 'core',
'version': '1.0'
}
DOCUMENTATION = """
---
@ -31,7 +33,6 @@ description:
read from the device. This module includes an
argument that will cause the module to wait for a specific condition
before returning or timing out if the condition is not met.
extends_documentation_fragment: nxos
options:
commands:
description:
@ -152,37 +153,53 @@ failed_conditions:
type: list
sample: ['...', '...']
"""
import ansible.module_utils.nxos
import time
from ansible.module_utils.basic import get_exception
from ansible.module_utils.network import NetworkModule, NetworkError
from ansible.module_utils.netcli import CommandRunner
from ansible.module_utils.netcli import FailedConditionsError
from ansible.module_utils.netcli import FailedConditionalError
from ansible.module_utils.netcli import AddCommandError, AddConditionError
VALID_KEYS = ['command', 'output', 'prompt', 'response']
from ansible.module_utils.nxos import run_commands
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import string_types
from ansible.module_utils.netcli import Conditional
from ansible.module_utils.network_common import ComplexList
from ansible.module_utils.nxos import nxos_argument_spec, check_args
def to_lines(stdout):
lines = list()
for item in stdout:
if isinstance(item, basestring):
item = str(item).split('\n')
yield item
lines.append(item)
return lines
def parse_commands(module):
for cmd in module.params['commands']:
if isinstance(cmd, basestring):
cmd = dict(command=cmd, output=None)
elif 'command' not in cmd:
module.fail_json(msg='command keyword argument is required')
elif cmd.get('output') not in [None, 'text', 'json']:
module.fail_json(msg='invalid output specified for command')
elif not set(cmd.keys()).issubset(VALID_KEYS):
module.fail_json(msg='unknown keyword specified')
yield cmd
def parse_commands(module, warnings):
transform = ComplexList(dict(
command=dict(key=True),
output=dict(),
prompt=dict(),
response=dict()
), module)
commands = transform(module.params['commands'])
for index, item in enumerate(commands):
if module.check_mode and not item['command'].startswith('show'):
warnings.append(
'Only show commands are supported when using check_mode, not '
'executing %s' % item['command']
)
return commands
def to_cli(obj):
cmd = obj['command']
if obj.get('output') == 'json':
cmd += ' | json'
return cmd
def main():
spec = dict(
"""entry point for module execution
"""
argument_spec = dict(
# { command: <str>, output: <str>, prompt: <str>, response: <str> }
commands=dict(type='list', required=True),
@ -193,66 +210,56 @@ def main():
interval=dict(default=1, type='int')
)
module = NetworkModule(argument_spec=spec,
argument_spec.update(nxos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
commands = list(parse_commands(module))
conditionals = module.params['wait_for'] or list()
result = {'changed': False}
warnings = list()
runner = CommandRunner(module)
for cmd in commands:
if module.check_mode and not cmd['command'].startswith('show'):
warnings.append('only show commands are supported when using '
'check mode, not executing `%s`' % cmd['command'])
else:
if cmd['command'].startswith('conf'):
module.fail_json(msg='nxos_command does not support running '
'config mode commands. Please use '
'nxos_config instead')
try:
runner.add_command(**cmd)
except AddCommandError:
exc = get_exception()
warnings.append('duplicate command detected: %s' % cmd)
try:
for item in conditionals:
runner.add_conditional(item)
except AddConditionError:
exc = get_exception()
module.fail_json(msg=str(exc), condition=exc.condition)
runner.retries = module.params['retries']
runner.interval = module.params['interval']
runner.match = module.params['match']
try:
runner.run()
except FailedConditionsError:
exc = get_exception()
module.fail_json(msg=str(exc), failed_conditions=exc.failed_conditions)
except FailedConditionalError:
exc = get_exception()
module.fail_json(msg=str(exc), failed_conditional=exc.failed_conditional)
except NetworkError:
exc = get_exception()
module.fail_json(msg=str(exc), **exc.kwargs)
result = dict(changed=False)
result['stdout'] = list()
for cmd in commands:
try:
output = runner.get_command(cmd['command'], cmd.get('output'))
except ValueError:
output = 'command not executed due to check_mode, see warnings'
result['stdout'].append(output)
check_args(module, warnings)
commands = parse_commands(module, warnings)
result['warnings'] = warnings
result['stdout_lines'] = list(to_lines(result['stdout']))
wait_for = module.params['wait_for'] or list()
try:
conditionals = [Conditional(c) for c in wait_for]
except AttributeError:
exc = get_exception()
module.fail_json(msg=str(exc))
retries = module.params['retries']
interval = module.params['interval']
match = module.params['match']
while retries > 0:
responses = run_commands(module, commands)
for item in list(conditionals):
if item(responses):
if match == 'any':
conditionals = list()
break
conditionals.remove(item)
if not conditionals:
break
time.sleep(interval)
retries -= 1
if conditionals:
failed_conditions = [item.raw for item in conditionals]
msg = 'One or more conditional statements have not be satisfied'
module.fail_json(msg=msg, failed_conditions=failed_conditions)
result.update({
'stdout': responses,
'stdout_lines': to_lines(responses)
})
module.exit_json(**result)