First implementation of 'fallback' parameter

Implemented & documented for EOS & NXOS
This commit is contained in:
Nathaniel Case 2016-03-31 14:17:49 -04:00
parent 2e55b3567b
commit dbc49ad95b
5 changed files with 68 additions and 33 deletions

View file

@ -516,6 +516,18 @@ def is_executable(path):
or stat.S_IXOTH & os.stat(path)[stat.ST_MODE])
class AnsibleFallbackNotFound(Exception):
pass
def env_fallback(*args, **kwargs):
''' Load value from environment '''
for arg in args:
if arg in os.environ:
return os.environ[arg]
else:
raise AnsibleFallbackNotFound
class AnsibleModule(object):
def __init__(self, argument_spec, bypass_checks=False, no_log=False,
check_invalid_arguments=True, mutually_exclusive=None, required_together=None,
@ -550,6 +562,7 @@ class AnsibleModule(object):
self._load_constants()
self._load_params()
self._set_fallbacks()
# append to legal_inputs and then possibly check against them
try:
@ -1421,6 +1434,23 @@ class AnsibleModule(object):
if k not in self.params:
self.params[k] = default
def _set_fallbacks(self):
for k,v in self.argument_spec.items():
fallback = v.get('fallback', (None,))
fallback_strategy = fallback[0]
fallback_args = []
fallback_kwargs = {}
if k not in self.params and fallback_strategy is not None:
for item in fallback[1:]:
if isinstance(item, dict):
fallback_kwargs = item
else:
fallback_args = item
try:
self.params[k] = fallback_strategy(*fallback_args, **fallback_kwargs)
except AnsibleFallbackNotFound:
continue
def _load_params(self):
''' read the input and set the params attribute'''
if MODULE_COMPLEX_ARGS is None:

View file

@ -20,7 +20,7 @@ import os
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.shell import Shell, Command, HAS_PARAMIKO
from ansible.module_utils.netcfg import parse
from ansible.module_utils.urls import fetch_url
@ -30,24 +30,16 @@ NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
NET_COMMON_ARGS = dict(
host=dict(required=True),
port=dict(type='int'),
username=dict(required=True),
password=dict(no_log=True),
ssh_keyfile=dict(type='path'),
authorize=dict(default=False, type='bool'),
auth_pass=dict(no_log=True),
username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
authorize=dict(default=False, fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'),
auth_pass=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS'])),
transport=dict(default='cli', choices=['cli', 'eapi']),
use_ssl=dict(default=True, type='bool'),
provider=dict(type='dict')
)
NET_ENV_ARGS = dict(
username='ANSIBLE_NET_USERNAME',
password='ANSIBLE_NET_PASSWORD',
ssh_keyfile='ANSIBLE_NET_SSH_KEYFILE',
authorize='ANSIBLE_NET_AUTHORIZE',
auth_pass='ANSIBLE_NET_AUTH_PASS',
)
CLI_PROMPTS_RE = [
re.compile(r"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"),
re.compile(r"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$")
@ -200,9 +192,6 @@ class NetworkModule(AnsibleModule):
if key in NET_COMMON_ARGS:
if self.params.get(key) is None and value is not None:
self.params[key] = value
for key, env_var in NET_ENV_ARGS.items():
if self.params.get(key) is None and env_var in os.environ:
self.params[key] = os.environ[env_var]
def connect(self):
try:

View file

@ -21,7 +21,7 @@ import re
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.shell import Shell, HAS_PARAMIKO
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.netcfg import parse
NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
@ -29,8 +29,9 @@ NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
NET_COMMON_ARGS = dict(
host=dict(required=True),
port=dict(type='int'),
username=dict(required=True),
password=dict(no_log=True),
username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
transport=dict(default='cli', choices=['cli', 'nxapi']),
use_ssl=dict(default=False, type='bool'),
validate_certs=dict(default=True, type='bool'),
@ -165,11 +166,11 @@ class Cli(object):
username = self.module.params['username']
password = self.module.params['password']
key_filename = self.module.params['ssh_keyfile']
try:
self.shell = Shell(prompts_re=CLI_PROMPTS_RE, errors_re=CLI_ERRORS_RE,
kickstart=False)
self.shell.open(host, port=port, username=username, password=password)
self.shell = Shell(prompts_re=CLI_PROMPTS_RE, errors_re=CLI_ERRORS_RE, kickstart=False)
self.shell.open(host, port=port, username=username, password=password, key_filename=key_filename)
except Exception, exc:
msg = 'failed to connect to %s:%s - %s' % (host, port, str(exc))
self.module.fail_json(msg=msg)

View file

@ -41,26 +41,31 @@ options:
- Configures the usename to use to authenticate the connection to
the remote device. The value of I(username) is used to authenticate
either the CLI login or the eAPI authentication depending on which
transport is used.
required: true
transport is used. If the value is not specified in the task, the
value of environment variable ANSIBLE_NET_USERNAME will be used instead.
required: false
password:
description:
- Specifies the password to use to authenticate the connection to
the remote device. This is a common argument used for either I(cli)
or I(eapi) transports.
or I(eapi) transports. If the value is not specified in the task, the
value of environment variable ANSIBLE_NET_PASSWORD will be used instead.
required: false
default: null
ssh_keyfile:
description:
- Specifies the SSH keyfile to use to authenticate the connection to
the remote device. This argument is only used for I(cli) transports.
If the value is not specified in the task, the value of environment
variable ANSIBLE_NET_SSH_KEYFILE will be used instead.
required: false
default: null
authorize:
description:
- Instructs the module to enter priviledged mode on the remote device
before sending any commands. If not specified, the device will
attempt to excecute all commands in non-priviledged mode.
attempt to excecute all commands in non-priviledged mode. If the value
is not specified in the task, the value of environment variable
ANSIBLE_NET_AUTHORIZE will be used instead.
required: false
default: no
choices: ['yes', 'no']
@ -68,7 +73,8 @@ options:
description:
- Specifies the password to use if required to enter privileged mode
on the remote device. If I(authorize) is false, then this argument
does nothing
does nothing. If the value is not specified in the task, the value of
environment variable ANSIBLE_NET_AUTH_PASS will be used instead.
required: false
default: none
transport:

View file

@ -41,15 +41,24 @@ options:
- Configures the usename to use to authenticate the connection to
the remote device. The value of I(username) is used to authenticate
either the CLI login or the nxapi authentication depending on which
transport is used.
required: true
transport is used. If the value is not specified in the task, the
value of environment variable ANSIBLE_NET_USERNAME will be used instead.
required: false
password:
description:
- Specifies the password to use when authentication the connection to
- Specifies the password to use to authenticate the connection to
the remote device. This is a common argument used for either I(cli)
or I(nxapi) transports.
or I(nxapi) transports. If the value is not specified in the task, the
value of environment variable ANSIBLE_NET_PASSWORD will be used instead.
required: false
default: null
ssh_keyfile:
description:
- Specifies the SSH key to use to authenticate the connection to
the remote device. This argument is only used for the I(cli)
transport. If the value is not specified in the task, the
value of environment variable ANSIBLE_NET_SSH_KEYFILE will be used instead.
required: false
transport:
description:
- Configures the transport connection to use when connecting to the