update nxos_nxapi module with minor enhancements (#4573)

* added new config argument
* added states present and absent
* update to use network shared modules

Tested on NXOS 7.3(0)D1(1)
reviewable/pr18780/r1
Peter Sprygada 8 years ago committed by John R Barker
parent 2538c70d46
commit 6543bb4bdd

@ -19,221 +19,229 @@
DOCUMENTATION = """ DOCUMENTATION = """
--- ---
module: nxos_nxapi module: nxos_nxapi
version_added: "2.1" version_added: "2.1"
author: "Chris Houseknecht (@chouseknecht)" author: "Peter Sprygada (@privateip)"
short_description: Manage NXAPI configuration on an NXOS device. short_description: Manage NXAPI configuration on an NXOS device.
description: description:
- Use to enable or disable NXAPI access, set the port and state - Configures the NXAPI feature on devices running Cisco NXOS. The
of http and https servers, and enable or disable the sandbox. NXAPI feature is absent from the configuration by default. Since
- When enabling NXAPI access the default is to enable HTTP on port this module manages the NXAPI feature it only supports the use
80, enable HTTPS on port 443, and enable the web based UI sandbox. of the C(Cli) transport.
Use the options below to override the default configuration.
extends_documentation_fragment: nxos extends_documentation_fragment: nxos
options: options:
state: http_port:
description: description:
- Set to started or stopped. A state of started will - Configure the port with which the HTTP server will listen on
enable NXAPI access, and a state of stopped will for requests. By default, NXAPI will bind the HTTP service
disable or shutdown all NXAPI access. to the standard HTTP port 80. This argument accepts valid
choices: port values in the range of 1 to 65535.
- started required: false
- stopped default: 80
required: false http:
default: started description:
http_port: - Controls the operating state of the HTTP protocol as one of the
description: underlying transports for NXAPI. By default, NXAPI will enable
- Port on which the HTTP server will listen. the HTTP transport when the feature is first configured. To
required: false disable the use of the HTTP transport, set the value of this
default: 80 argument to False.
https_port: required: false
description: default: yes
- Port on which the HTTPS server will listen. choices: ['yes', 'no']
required: false aliases: ['enable_http']
default: 443 https_port:
http: description:
description: - Configure the port with which the HTTPS server will listen on
- Enable/disable HTTP server. for requests. By default, NXAPI will bind the HTTPS service
required: false to the standard HTTPS port 443. This argument accepts valid
default: true port values in the range of 1 to 65535.
choices: required: false
- true default: 443
- false https:
aliases: description:
- enable_http - Controls the operating state of the HTTPS protocol as one of the
https: underlying transports for NXAPI. By default, NXAPI will disable
description: the HTTPS transport when the feature is first configured. To
- Enable/disable HTTPS server. enable the use of the HTTPS transport, set the value of this
required: false argument to True.
choices: required: false
- true default: yes
- false choices: ['yes', 'no']
default: true aliases: ['enable_https']
aliases: sandbox:
- enable_https description:
sandbox: - The NXAPI feature provides a web base UI for developers for
description: entering commands. This feature is initially disabled when
- Enable/disable NXAPI web based UI for entering commands. the NXAPI feature is configured for the first time. When the
required: false C(sandbox) argument is set to True, the developer sandbox URL
default: true will accept requests and when the value is set to False, the
choices: sandbox URL is unavailable.
- true required: false
- false default: no
aliases: choices: ['yes', 'no']
- enable_sandbox aliases: ['enable_sandbox']
config:
description:
- The C(config) argument provides an optional argument to
specify the device running-config to used as the basis for
configuring the remote system. The C(config) argument accepts
a string value that represents the device configuration.
required: false
default: null
version_added: "2.2"
state:
description:
- The C(state) argument controls whether or not the NXAPI
feature is configured on the remote device. When the value
is C(present) the NXAPI feature configuration is present in
the device running-config. When the values is C(absent) the
feature configuration is removed from the running-config.
choices: ['present', 'absent']
required: false
default: present
""" """
EXAMPLES = """ EXAMPLES = """
- name: Enable NXAPI access with default configuration # Note: examples below use the following provider dict to handle
nxos_nxapi: # transport and authentication to the node.
provider: {{ provider }} vars:
cli:
- name: Enable NXAPI with no HTTP, HTTPS at port 9443 and sandbox disabled host: "{{ inventory_hostname }}"
nxos_nxapi: username: admin
enable_http: false password: admin
https_port: 9443
enable_sandbox: no - name: Enable NXAPI access with default configuration
provider: {{ provider }} nxos_nxapi:
provider: {{ cli }}
- name: shutdown NXAPI access
nxos_nxapi: - name: Enable NXAPI with no HTTP, HTTPS at port 9443 and sandbox disabled
state: stopped nxos_nxapi:
provider: {{ provider }} enable_http: false
https_port: 9443
https: yes
enable_sandbox: no
provider: {{ cli }}
- name: remove NXAPI configuration
nxos_nxapi:
state: absent
provider: {{ cli }}
""" """
RETURN = """ RETURN = """
changed: updates:
description: description:
- Indicates if commands were sent to the device. - Returns the list of commands that need to be pushed into the remote
returned: always device to satisfy the arguments
type: boolean returned: always
sample: false type: list
sample: ['no feature nxapi']
commands:
description:
- Set of commands to be executed on remote device. If run in check mode,
commands will not be executed.
returned: always
type: list
sample: [
'nxapi feature',
'nxapi http port 8080'
]
_config:
description:
- Configuration found on the device prior ro any commands being executed.
returned: always
type: object
sample: {...}
""" """
import re
import time
def http_commands(protocol, port, enable, config):
port_config = config.get('{0}_port'.format(protocol), None) from ansible.module_utils.netcfg import NetworkConfig, dumps
changed = False from ansible.module_utils.nxos import NetworkModule, NetworkError
commands = [] from ansible.module_utils.basic import get_exception
if port_config is None and enable:
# enable PRIVATE_KEYS_RE = re.compile('__.+__')
changed = True
commands.append('nxapi {0} port {1}'.format(protocol, port)) def invoke(name, *args, **kwargs):
elif port_config is not None: func = globals().get(name)
if not enable: if func:
# disable return func(*args, **kwargs)
commands.append('no nxapi {0}'.format(protocol))
changed = True def present(module, commands):
elif port_config != port: commands.append('feature nxapi')
# update port setters = set()
commands.append('nxapi {0} port {1}'.format(protocol, port)) for key, value in module.argument_spec.iteritems():
changed = True setter = value.get('setter') or 'set_%s' % key
return commands, changed if setter not in setters:
setters.add(setter)
if module.params[key] is not None:
def execute_commands(module, commands): invoke(setter, module, commands)
if not module.params.get('check_mode'):
module.configure(commands) def absent(module, commands):
commands.append('no feature nxapi')
def get_nxapi_state(module): def set_http(module, commands):
features = module.execute(['show feature | grep nxapi'])[0] port = module.params['http_port']
if re.search('disabled', features) is None: if not 0 <= port <= 65535:
return 'started' module.fail_json(msg='http_port must be between 1 and 65535')
return 'stopped' elif module.params['http'] is True:
commands.append('nxapi http port %s' % port)
elif module.params['http'] is False:
def config_server(module): commands.append('no nxapi http')
nxapi_state = get_nxapi_state(module) def set_https(module, commands):
port = module.params['https_port']
config = dict() if not 0 <= port <= 65535:
if nxapi_state == 'started': module.fail_json(msg='https_port must be between 1 and 65535')
config = module.from_json(module.execute(['show nxapi | json'])[0]) elif module.params['https'] is True:
commands.append('nxapi https port %s' % port)
state = module.params.get('state') elif module.params['https'] is False:
result = dict(changed=False, _config=config, commands=[]) commands.append('no nxapi https')
commands = []
def set_sandbox(module, commands):
if config.get('nxapi_status', 'Disabled') == 'Disabled': if module.params['sandbox'] is True:
if state == 'started': commands.append('nxapi sandbox')
# enable nxapi and get the new default config elif module.params['sandbox'] is False:
commands.append('feature nxapi') commands.append('no nxapi sandbox')
result['_config'] = dict()
result['changed'] = True def get_config(module):
if module.params.get('check_mode'): contents = module.params['config']
# make an assumption about default state if not contents:
config['http_port'] = 80 try:
config['sandbox_status'] = 'Disabled' contents = module.cli(['show running-config nxapi all'])[0]
else: except NetworkError:
# get the default config contents = None
execute_commands(module, commands) config = NetworkConfig(indent=2)
config = module.from_json(module.execute(['show nxapi | json'])[0]) if contents:
else: config.load(contents)
# nxapi already disabled return config
return result
elif config.get('nxapi_status', 'Disabled') == 'Enabled' and state == 'stopped': def load_checkpoint(module, result):
# disable nxapi and exit try:
commands.append('no feature nxapi') checkpoint = result['__checkpoint__']
module.cli(['rollback running-config checkpoint %s' % checkpoint,
'no checkpoint %s' % checkpoint], output='text')
except KeyError:
module.fail_json(msg='unable to rollback, checkpoint not found')
except NetworkError:
exc = get_exception()
msg = 'unable to rollback configuration'
module.fail_json(msg=msg, checkpoint=checkpoint, **exc.kwargs)
def load_config(module, commands, result):
# create a config checkpoint
checkpoint = 'ansible_%s' % int(time.time())
module.cli(['checkpoint %s' % checkpoint], output='text')
result['__checkpoint__'] = checkpoint
# load the config into the device
module.config.load_config(commands)
# load was successfully, remove the config checkpoint
module.cli(['no checkpoint %s' % checkpoint])
def load(module, commands, result):
candidate = NetworkConfig(indent=2, contents='\n'.join(commands))
config = get_config(module)
configobjs = candidate.difference(config)
if configobjs:
commands = dumps(configobjs, 'commands').split('\n')
result['updates'] = commands
if not module.check_mode:
load_config(module, commands, result)
result['changed'] = True result['changed'] = True
result['commands'] = commands
execute_commands(module, commands) def clean_result(result):
return result # strip out any keys that have two leading and two trailing
# underscore characters
# configure http and https for key in result.keys():
for protocol in ['http', 'https']: if PRIVATE_KEYS_RE.match(key):
cmds, chg = http_commands(protocol, module.params['{0}_port'.format(protocol)], del result[key]
module.params[protocol], config)
if chg:
commands += cmds
result['changed'] = True
# configure sandbox
config_sandbox = config.get('sandbox_status', None)
enable_sandbox = module.params.get('sandbox')
if config_sandbox is None:
# there is no prior state, so we must set one
result['changed'] = True
if enable_sandbox:
commands.append('nxapi sandbox')
else:
commands.append('no nxapi sandbox')
else:
# there is a prior state, so be idempotent
if config_sandbox == 'Enabled' and not enable_sandbox:
# turn off sandbox
commands.append('no nxapi sandbox')
result['changed'] = True
elif config_sandbox == 'Disabled' and enable_sandbox:
# turn on sandbox
commands.append('nxapi sandbox')
result['changed'] = True
if len(commands) > 0:
# something requires change
result['commands'] = commands
execute_commands(module, commands)
return result
def main(): def main():
@ -241,28 +249,56 @@ def main():
""" """
argument_spec = dict( argument_spec = dict(
state=dict(default='started', choices=['started', 'stopped']), http=dict(aliases=['enable_http'], default=True, type='bool', setter='set_http'),
http_port=dict(default=80, type='int'), http_port=dict(default=80, type='int', setter='set_http'),
https_port=dict(default=443, type='int'),
http=dict(aliases=['enable_http'], default=True, type='bool'), https=dict(aliases=['enable_https'], default=False, type='bool', setter='set_https'),
https=dict(aliases=['enable_https'], default=True, type='bool'), https_port=dict(default=443, type='int', setter='set_https'),
sandbox=dict(aliases=['enable_sandbox'], default=True, type='bool'),
sandbox=dict(aliases=['enable_sandbox'], default=False, type='bool'),
# Only allow configuration of NXAPI using cli transpsort # Only allow configuration of NXAPI using cli transpsort
transport=dict(required=True, choices=['cli']) transport=dict(required=True, choices=['cli']),
config=dict(),
# Support for started and stopped is for backwards capability only and
# will be removed in a future version
state=dict(default='present', choices=['started', 'stopped', 'present', 'absent'])
) )
module = get_module(argument_spec=argument_spec, module = NetworkModule(argument_spec=argument_spec,
supports_check_mode=True) connect_on_load=False,
supports_check_mode=True)
result = config_server(module) state = module.params['state']
return module.exit_json(**result) warnings = list()
result = dict(changed=False, warnings=warnings)
if state == 'started':
state = 'present'
warnings.append('state=started is deprecated and will be removed in a '
'a future release. Please use state=present instead')
elif state == 'stopped':
state = 'absent'
warnings.append('state=stopped is deprecated and will be removed in a '
'a future release. Please use state=absent instead')
commands = list()
invoke(state, module, commands)
try:
load(module, commands, result)
except (ValueError, NetworkError):
load_checkpoint(module, result)
exc = get_exception()
module.fail_json(msg=str(exc), **exc.kwargs)
clean_result(result)
module.exit_json(**result)
from ansible.module_utils.basic import *
from ansible.module_utils.shell import *
from ansible.module_utils.nxos import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()

Loading…
Cancel
Save