summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Sprygada <privateip@users.noreply.github.com>2016-08-30 15:05:18 -0400
committerJohn R Barker <john@johnrbarker.com>2016-08-30 20:05:18 +0100
commit6543bb4bdd7d4b28cdecd6a2f2e19590e229440c (patch)
tree7db05fbe59dd4c280da447b641e5a81d5c6e86f3
parent2538c70d468eb9972023a395d77269fb2ed2b59a (diff)
downloadansible-modules-core-6543bb4bdd7d4b28cdecd6a2f2e19590e229440c.tar.gz
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)
-rw-r--r--network/nxos/nxos_nxapi.py470
1 files changed, 253 insertions, 217 deletions
diff --git a/network/nxos/nxos_nxapi.py b/network/nxos/nxos_nxapi.py
index 88b0b915..feec8a6d 100644
--- a/network/nxos/nxos_nxapi.py
+++ b/network/nxos/nxos_nxapi.py
@@ -19,221 +19,229 @@
DOCUMENTATION = """
---
-module: nxos_nxapi
+module: nxos_nxapi
version_added: "2.1"
-author: "Chris Houseknecht (@chouseknecht)"
+author: "Peter Sprygada (@privateip)"
short_description: Manage NXAPI configuration on an NXOS device.
description:
- - Use to enable or disable NXAPI access, set the port and state
- of http and https servers, and enable or disable the sandbox.
- - When enabling NXAPI access the default is to enable HTTP on port
- 80, enable HTTPS on port 443, and enable the web based UI sandbox.
- Use the options below to override the default configuration.
+ - Configures the NXAPI feature on devices running Cisco NXOS. The
+ NXAPI feature is absent from the configuration by default. Since
+ this module manages the NXAPI feature it only supports the use
+ of the C(Cli) transport.
extends_documentation_fragment: nxos
options:
- state:
- description:
- - Set to started or stopped. A state of started will
- enable NXAPI access, and a state of stopped will
- disable or shutdown all NXAPI access.
- choices:
- - started
- - stopped
- required: false
- default: started
- http_port:
- description:
- - Port on which the HTTP server will listen.
- required: false
- default: 80
- https_port:
- description:
- - Port on which the HTTPS server will listen.
- required: false
- default: 443
- http:
- description:
- - Enable/disable HTTP server.
- required: false
- default: true
- choices:
- - true
- - false
- aliases:
- - enable_http
- https:
- description:
- - Enable/disable HTTPS server.
- required: false
- choices:
- - true
- - false
- default: true
- aliases:
- - enable_https
- sandbox:
- description:
- - Enable/disable NXAPI web based UI for entering commands.
- required: false
- default: true
- choices:
- - true
- - false
- aliases:
- - enable_sandbox
+ http_port:
+ description:
+ - Configure the port with which the HTTP server will listen on
+ for requests. By default, NXAPI will bind the HTTP service
+ to the standard HTTP port 80. This argument accepts valid
+ port values in the range of 1 to 65535.
+ required: false
+ default: 80
+ http:
+ description:
+ - Controls the operating state of the HTTP protocol as one of the
+ underlying transports for NXAPI. By default, NXAPI will enable
+ the HTTP transport when the feature is first configured. To
+ disable the use of the HTTP transport, set the value of this
+ argument to False.
+ required: false
+ default: yes
+ choices: ['yes', 'no']
+ aliases: ['enable_http']
+ https_port:
+ description:
+ - Configure the port with which the HTTPS server will listen on
+ for requests. By default, NXAPI will bind the HTTPS service
+ to the standard HTTPS port 443. This argument accepts valid
+ port values in the range of 1 to 65535.
+ required: false
+ default: 443
+ https:
+ description:
+ - Controls the operating state of the HTTPS protocol as one of the
+ underlying transports for NXAPI. By default, NXAPI will disable
+ the HTTPS transport when the feature is first configured. To
+ enable the use of the HTTPS transport, set the value of this
+ argument to True.
+ required: false
+ default: yes
+ choices: ['yes', 'no']
+ aliases: ['enable_https']
+ sandbox:
+ description:
+ - The NXAPI feature provides a web base UI for developers for
+ entering commands. This feature is initially disabled when
+ the NXAPI feature is configured for the first time. When the
+ C(sandbox) argument is set to True, the developer sandbox URL
+ will accept requests and when the value is set to False, the
+ sandbox URL is unavailable.
+ required: false
+ default: no
+ choices: ['yes', 'no']
+ 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 = """
- - name: Enable NXAPI access with default configuration
- nxos_nxapi:
- provider: {{ provider }}
-
- - name: Enable NXAPI with no HTTP, HTTPS at port 9443 and sandbox disabled
- nxos_nxapi:
- enable_http: false
- https_port: 9443
- enable_sandbox: no
- provider: {{ provider }}
-
- - name: shutdown NXAPI access
- nxos_nxapi:
- state: stopped
- provider: {{ provider }}
+# Note: examples below use the following provider dict to handle
+# transport and authentication to the node.
+vars:
+ cli:
+ host: "{{ inventory_hostname }}"
+ username: admin
+ password: admin
+
+- name: Enable NXAPI access with default configuration
+ nxos_nxapi:
+ provider: {{ cli }}
+
+- name: Enable NXAPI with no HTTP, HTTPS at port 9443 and sandbox disabled
+ nxos_nxapi:
+ enable_http: false
+ https_port: 9443
+ https: yes
+ enable_sandbox: no
+ provider: {{ cli }}
+
+- name: remove NXAPI configuration
+ nxos_nxapi:
+ state: absent
+ provider: {{ cli }}
"""
RETURN = """
-changed:
- description:
- - Indicates if commands were sent to the device.
- returned: always
- type: boolean
- sample: false
-
-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: {...}
+updates:
+ description:
+ - Returns the list of commands that need to be pushed into the remote
+ device to satisfy the arguments
+ returned: always
+ type: list
+ sample: ['no feature nxapi']
"""
-
-
-def http_commands(protocol, port, enable, config):
- port_config = config.get('{0}_port'.format(protocol), None)
- changed = False
- commands = []
- if port_config is None and enable:
- # enable
- changed = True
- commands.append('nxapi {0} port {1}'.format(protocol, port))
- elif port_config is not None:
- if not enable:
- # disable
- commands.append('no nxapi {0}'.format(protocol))
- changed = True
- elif port_config != port:
- # update port
- commands.append('nxapi {0} port {1}'.format(protocol, port))
- changed = True
- return commands, changed
-
-
-def execute_commands(module, commands):
- if not module.params.get('check_mode'):
- module.configure(commands)
-
-
-def get_nxapi_state(module):
- features = module.execute(['show feature | grep nxapi'])[0]
- if re.search('disabled', features) is None:
- return 'started'
- return 'stopped'
-
-
-def config_server(module):
-
- nxapi_state = get_nxapi_state(module)
-
- config = dict()
- if nxapi_state == 'started':
- config = module.from_json(module.execute(['show nxapi | json'])[0])
-
- state = module.params.get('state')
- result = dict(changed=False, _config=config, commands=[])
- commands = []
-
- if config.get('nxapi_status', 'Disabled') == 'Disabled':
- if state == 'started':
- # enable nxapi and get the new default config
- commands.append('feature nxapi')
- result['_config'] = dict()
- result['changed'] = True
- if module.params.get('check_mode'):
- # make an assumption about default state
- config['http_port'] = 80
- config['sandbox_status'] = 'Disabled'
- else:
- # get the default config
- execute_commands(module, commands)
- config = module.from_json(module.execute(['show nxapi | json'])[0])
- else:
- # nxapi already disabled
- return result
- elif config.get('nxapi_status', 'Disabled') == 'Enabled' and state == 'stopped':
- # disable nxapi and exit
- commands.append('no feature nxapi')
+import re
+import time
+
+from ansible.module_utils.netcfg import NetworkConfig, dumps
+from ansible.module_utils.nxos import NetworkModule, NetworkError
+from ansible.module_utils.basic import get_exception
+
+PRIVATE_KEYS_RE = re.compile('__.+__')
+
+def invoke(name, *args, **kwargs):
+ func = globals().get(name)
+ if func:
+ return func(*args, **kwargs)
+
+def present(module, commands):
+ commands.append('feature nxapi')
+ setters = set()
+ for key, value in module.argument_spec.iteritems():
+ setter = value.get('setter') or 'set_%s' % key
+ if setter not in setters:
+ setters.add(setter)
+ if module.params[key] is not None:
+ invoke(setter, module, commands)
+
+def absent(module, commands):
+ commands.append('no feature nxapi')
+
+def set_http(module, commands):
+ port = module.params['http_port']
+ if not 0 <= port <= 65535:
+ module.fail_json(msg='http_port must be between 1 and 65535')
+ elif module.params['http'] is True:
+ commands.append('nxapi http port %s' % port)
+ elif module.params['http'] is False:
+ commands.append('no nxapi http')
+
+def set_https(module, commands):
+ port = module.params['https_port']
+ if not 0 <= port <= 65535:
+ module.fail_json(msg='https_port must be between 1 and 65535')
+ elif module.params['https'] is True:
+ commands.append('nxapi https port %s' % port)
+ elif module.params['https'] is False:
+ commands.append('no nxapi https')
+
+def set_sandbox(module, commands):
+ if module.params['sandbox'] is True:
+ commands.append('nxapi sandbox')
+ elif module.params['sandbox'] is False:
+ commands.append('no nxapi sandbox')
+
+def get_config(module):
+ contents = module.params['config']
+ if not contents:
+ try:
+ contents = module.cli(['show running-config nxapi all'])[0]
+ except NetworkError:
+ contents = None
+ config = NetworkConfig(indent=2)
+ if contents:
+ config.load(contents)
+ return config
+
+def load_checkpoint(module, result):
+ try:
+ 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['commands'] = commands
- execute_commands(module, commands)
- return result
-
- # configure http and https
- for protocol in ['http', 'https']:
- cmds, chg = http_commands(protocol, module.params['{0}_port'.format(protocol)],
- 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 clean_result(result):
+ # 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]
def main():
@@ -241,28 +249,56 @@ def main():
"""
argument_spec = dict(
- state=dict(default='started', choices=['started', 'stopped']),
- http_port=dict(default=80, type='int'),
- https_port=dict(default=443, type='int'),
- http=dict(aliases=['enable_http'], default=True, type='bool'),
- https=dict(aliases=['enable_https'], default=True, type='bool'),
- sandbox=dict(aliases=['enable_sandbox'], default=True, type='bool'),
+ http=dict(aliases=['enable_http'], default=True, type='bool', setter='set_http'),
+ http_port=dict(default=80, type='int', setter='set_http'),
+
+ https=dict(aliases=['enable_https'], default=False, type='bool', setter='set_https'),
+ https_port=dict(default=443, type='int', setter='set_https'),
+
+ sandbox=dict(aliases=['enable_sandbox'], default=False, type='bool'),
# 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,
- supports_check_mode=True)
+ module = NetworkModule(argument_spec=argument_spec,
+ 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__':
main()
-