diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index 1af0bdb01a9..f202dba0282 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -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: diff --git a/lib/ansible/module_utils/eos.py b/lib/ansible/module_utils/eos.py index 33597a782c7..0321b6e2dc9 100644 --- a/lib/ansible/module_utils/eos.py +++ b/lib/ansible/module_utils/eos.py @@ -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: diff --git a/lib/ansible/module_utils/nxos.py b/lib/ansible/module_utils/nxos.py index 9c38c13c056..0ff29c53bec 100644 --- a/lib/ansible/module_utils/nxos.py +++ b/lib/ansible/module_utils/nxos.py @@ -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) diff --git a/lib/ansible/utils/module_docs_fragments/eos.py b/lib/ansible/utils/module_docs_fragments/eos.py index d54b3940db8..80a89e53fa1 100644 --- a/lib/ansible/utils/module_docs_fragments/eos.py +++ b/lib/ansible/utils/module_docs_fragments/eos.py @@ -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: diff --git a/lib/ansible/utils/module_docs_fragments/nxos.py b/lib/ansible/utils/module_docs_fragments/nxos.py index d2d5343b395..6eae302d9bb 100644 --- a/lib/ansible/utils/module_docs_fragments/nxos.py +++ b/lib/ansible/utils/module_docs_fragments/nxos.py @@ -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