adds the cli transport back to the ios modules (#20949)

the cli transport was initially removed to aid in the transition to
network_cli.  This adds the function back to the provider can be
specified.
pull/20963/head
Peter Sprygada 8 years ago committed by GitHub
parent 246cd041d8
commit e19c2f6a6d

@ -46,15 +46,12 @@ ios_cli_argument_spec = {
'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True),
'authorize': dict(default=False, fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'), 'authorize': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'),
'auth_pass': dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS'])), 'auth_pass': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS']), no_log=True),
'timeout': dict(type='int', default=10), 'timeout': dict(type='int', default=10),
'provider': dict(type='dict'), 'provider': dict(type='dict'),
# deprecated in Ansible 2.3
'transport': dict(),
} }
def check_args(module): def check_args(module):
@ -79,8 +76,6 @@ class Cli(CliBase):
re.compile(r"[^\r\n]+ not found", re.I), re.compile(r"[^\r\n]+ not found", re.I),
] ]
NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
def __init__(self, module): def __init__(self, module):
self._module = module self._module = module
super(Cli, self).__init__() super(Cli, self).__init__()
@ -106,7 +101,12 @@ class Cli(CliBase):
def authorize(self): def authorize(self):
passwd = self._module.params['auth_pass'] passwd = self._module.params['auth_pass']
self.execute(Command('enable', prompt=self.NET_PASSWD_RE, response=passwd)) if passwd:
prompt = "[\r\n]?Password: $"
self.exec_command(dict(command='enable', prompt=prompt, response=passwd))
else:
self.exec_command('enable')
def connection(module): def connection(module):

@ -35,9 +35,7 @@ description:
commands that are not already configured. The config source can commands that are not already configured. The config source can
be a set of commands or a template. be a set of commands or a template.
deprecated: Deprecated in 2.2. Use M(ios_config) instead. deprecated: Deprecated in 2.2. Use M(ios_config) instead.
notes: extends_documentation_fragment: ios
- Provider arguments are no longer supported. Network tasks should now
specify connection plugin network_cli instead.
options: options:
src: src:
description: description:
@ -126,22 +124,35 @@ delta:
type: str type: str
sample: "0:00:10.469466" sample: "0:00:10.469466"
""" """
from functools import partial
from ansible.module_utils import ios
from ansible.module_utils import ios_cli
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.local import LocalAnsibleModule from ansible.module_utils.local import LocalAnsibleModule
from ansible.module_utils.network_common import ComplexList
from ansible.module_utils.netcli import Conditional
from ansible.module_utils.six import string_types
from ansible.module_utils.netcfg import NetworkConfig, dumps from ansible.module_utils.netcfg import NetworkConfig, dumps
from ansible.module_utils.ios import get_config, load_config
from ansible.module_utils.network import NET_TRANSPORT_ARGS, _transitional_argument_spec
SHARED_LIB = 'ios'
def check_args(module): def get_ansible_module():
warnings = list() if SHARED_LIB == 'ios':
for key in NET_TRANSPORT_ARGS: return LocalAnsibleModule
if module.params[key]: return AnsibleModule
warnings.append(
'network provider arguments are no longer supported. Please ' def invoke(name, *args, **kwargs):
'use connection: network_cli for the task' obj = globals().get(SHARED_LIB)
) func = getattr(obj, name)
break return func(*args, **kwargs)
return warnings
load_config = partial(invoke, 'load_config')
get_config = partial(invoke, 'get_config')
def check_args(module, warnings):
if SHARED_LIB == 'ios_cli':
ios_cli.check_args(module)
def get_current_config(module): def get_current_config(module):
if module.params['config']: if module.params['config']:
@ -163,23 +174,23 @@ def main():
config=dict(), config=dict(),
) )
# Removed the use of provider arguments in 2.3 due to network_cli argument_spec.update(ios_cli.ios_cli_argument_spec)
# connection plugin. To be removed in 2.5
argument_spec.update(_transitional_argument_spec())
mutually_exclusive = [('config', 'backup'), ('config', 'force')] mutually_exclusive = [('config', 'backup'), ('config', 'force')]
module = LocalAnsibleModule(argument_spec=argument_spec, cls = get_ansible_module()
module = cls(argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive, mutually_exclusive=mutually_exclusive,
supports_check_mode=True) supports_check_mode=True)
warnings = check_args(module) warnings = list()
check_args(module, warnings)
result = dict(changed=False, warnings=warnings)
candidate = NetworkConfig(contents=module.params['src'], indent=1) candidate = NetworkConfig(contents=module.params['src'], indent=1)
result = {'changed': False} result = {'changed': False}
if warnings:
result['warnings'] = warnings
if module.params['backup']: if module.params['backup']:
result['__backup__'] = get_config(module=module) result['__backup__'] = get_config(module=module)
@ -203,4 +214,5 @@ def main():
module.exit_json(**result) module.exit_json(**result)
if __name__ == '__main__': if __name__ == '__main__':
SHARED_LIB = 'ios_cli'
main() main()

@ -35,9 +35,7 @@ description:
before returning or timing out if the condition is not met. before returning or timing out if the condition is not met.
- This module does not support running commands in configuration mode. - This module does not support running commands in configuration mode.
Please use M(ios_config) to configure IOS devices. Please use M(ios_config) to configure IOS devices.
notes: extends_documentation_fragment: ios
- Provider arguments are no longer supported. Network tasks should now
specify connection plugin network_cli instead.
options: options:
commands: commands:
description: description:
@ -149,13 +147,33 @@ delta:
""" """
import time import time
from functools import partial
from ansible.module_utils import ios
from ansible.module_utils import ios_cli
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.local import LocalAnsibleModule from ansible.module_utils.local import LocalAnsibleModule
from ansible.module_utils.ios import run_commands
from ansible.module_utils.network_common import ComplexList from ansible.module_utils.network_common import ComplexList
from ansible.module_utils.netcli import Conditional from ansible.module_utils.netcli import Conditional
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
VALID_KEYS = ['command', 'output'] SHARED_LIB = 'ios'
def get_ansible_module():
if SHARED_LIB == 'ios':
return LocalAnsibleModule
return AnsibleModule
def invoke(name, *args, **kwargs):
obj = globals().get(SHARED_LIB)
func = getattr(obj, name)
return func(*args, **kwargs)
run_commands = partial(invoke, 'run_commands')
def check_args(module, warnings):
if SHARED_LIB == 'ios_cli':
ios_cli.check_args(module)
def to_lines(stdout): def to_lines(stdout):
for item in stdout: for item in stdout:
@ -186,7 +204,9 @@ def parse_commands(module, warnings):
return commands return commands
def main(): def main():
spec = dict( """main entry point for module execution
"""
argument_spec = dict(
# { command: <str>, prompt: <str>, response: <str> } # { command: <str>, prompt: <str>, response: <str> }
commands=dict(type='list', required=True), commands=dict(type='list', required=True),
@ -197,10 +217,16 @@ def main():
interval=dict(default=1, type='int') interval=dict(default=1, type='int')
) )
module = LocalAnsibleModule(argument_spec=spec, argument_spec.update(ios_cli.ios_cli_argument_spec)
supports_check_mode=True)
cls = get_ansible_module()
module = cls(argument_spec=argument_spec, supports_check_mode=True)
warnings = list() warnings = list()
check_args(module, warnings)
result = {'changed': False}
commands = parse_commands(module, warnings) commands = parse_commands(module, warnings)
wait_for = module.params['wait_for'] or list() wait_for = module.params['wait_for'] or list()
@ -243,4 +269,5 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
SHARED_LIB = 'ios_cli'
main() main()

@ -33,9 +33,7 @@ description:
for segmenting configuration into sections. This module provides for segmenting configuration into sections. This module provides
an implementation for working with IOS configuration sections in an implementation for working with IOS configuration sections in
a deterministic way. a deterministic way.
notes: extends_documentation_fragment: ios
- Provider arguments are no longer supported. Network tasks should now
specify connection plugin network_cli instead.
options: options:
lines: lines:
description: description:
@ -223,14 +221,39 @@ delta:
import re import re
import time import time
from functools import partial
from ansible.module_utils import ios
from ansible.module_utils import ios_cli
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.local import LocalAnsibleModule from ansible.module_utils.local import LocalAnsibleModule
from ansible.module_utils.ios import load_config, get_config, run_commands from ansible.module_utils.network_common import ComplexList
from ansible.module_utils.netcli import Conditional
from ansible.module_utils.six import string_types
from ansible.module_utils.netcfg import NetworkConfig, dumps from ansible.module_utils.netcfg import NetworkConfig, dumps
from ansible.module_utils.six import iteritems from ansible.module_utils.six import iteritems
from ansible.module_utils.network import NET_TRANSPORT_ARGS, _transitional_argument_spec
SHARED_LIB = 'ios'
def get_ansible_module():
if SHARED_LIB == 'ios':
return LocalAnsibleModule
return AnsibleModule
def invoke(name, *args, **kwargs):
obj = globals().get(SHARED_LIB)
func = getattr(obj, name)
return func(*args, **kwargs)
run_commands = partial(invoke, 'run_commands')
load_config = partial(invoke, 'load_config')
get_config = partial(invoke, 'get_config')
def check_args(module, warnings): def check_args(module, warnings):
if SHARED_LIB == 'ios_cli':
ios_cli.check_args(module)
if module.params['multiline_delimiter']: if module.params['multiline_delimiter']:
if len(module.params['multiline_delimiter']) != 1: if len(module.params['multiline_delimiter']) != 1:
module.fail_json(msg='multiline_delimiter value can only be a ' module.fail_json(msg='multiline_delimiter value can only be a '
@ -240,14 +263,6 @@ def check_args(module, warnings):
'please use match=none instead. This argument will ' 'please use match=none instead. This argument will '
'be removed in the future') 'be removed in the future')
for key in NET_TRANSPORT_ARGS:
if module.params[key]:
warnings.append(
'network provider arguments are no longer supported. Please '
'use connection: network_cli for the task'
)
break
def extract_banners(config): def extract_banners(config):
banners = {} banners = {}
banner_cmds = re.findall(r'^banner (\w+)', config, re.M) banner_cmds = re.findall(r'^banner (\w+)', config, re.M)
@ -335,7 +350,7 @@ def main():
save=dict(type='bool', default=False), save=dict(type='bool', default=False),
) )
argument_spec.update(_transitional_argument_spec()) argument_spec.update(ios_cli.ios_cli_argument_spec)
mutually_exclusive = [('lines', 'src')] mutually_exclusive = [('lines', 'src')]
@ -343,11 +358,15 @@ def main():
('match', 'exact', ['lines']), ('match', 'exact', ['lines']),
('replace', 'block', ['lines'])] ('replace', 'block', ['lines'])]
module = LocalAnsibleModule(argument_spec=argument_spec, cls = get_ansible_module()
module = cls(argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive, mutually_exclusive=mutually_exclusive,
required_if=required_if, required_if=required_if,
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
if module.params['force'] is True: if module.params['force'] is True:
module.params['match'] = 'none' module.params['match'] = 'none'
@ -409,4 +428,5 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
SHARED_LIB = 'ios_cli'
main() main()

@ -15,9 +15,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# #
ANSIBLE_METADATA = {'status': ['preview'], ANSIBLE_METADATA = {
'status': ['preview'],
'supported_by': 'core', 'supported_by': 'core',
'version': '1.0'} 'version': '1.0'
}
DOCUMENTATION = """ DOCUMENTATION = """
--- ---
@ -140,32 +142,58 @@ ansible_net_neighbors:
type: dict type: dict
""" """
import re import re
import itertools
import ansible.module_utils.ios from functools import partial
from ansible.module_utils.network import NetworkModule
from ansible.module_utils import ios
from ansible.module_utils import ios_cli
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.local import LocalAnsibleModule
from ansible.module_utils.six import iteritems from ansible.module_utils.six import iteritems
from ansible.module_utils.six.moves import zip from ansible.module_utils.six.moves import zip
SHARED_LIB = 'ios'
def get_ansible_module():
if SHARED_LIB == 'ios':
return LocalAnsibleModule
return AnsibleModule
def invoke(name, *args, **kwargs):
obj = globals().get(SHARED_LIB)
func = getattr(obj, name)
return func(*args, **kwargs)
run_commands = partial(invoke, 'run_commands')
def check_args(module, warnings):
if SHARED_LIB == 'ios_cli':
ios_cli.check_args(module)
class FactsBase(object): class FactsBase(object):
COMMANDS = list()
def __init__(self, module): def __init__(self, module):
self.module = module self.module = module
self.facts = dict() self.facts = dict()
self.failed_commands = list() self.responses = None
def run(self, cmd):
try:
return self.module.cli(cmd)[0]
except:
self.failed_commands.append(cmd)
def populate(self):
self.responses = run_commands(self.module, self.COMMANDS, check_rc=False)
def run(self, cmd):
return run_commands(self.module, cmd, check_rc=False)
class Default(FactsBase): class Default(FactsBase):
COMMANDS = ['show version']
def populate(self): def populate(self):
data = self.run('show version') super(Default, self).populate()
data = self.responses[0]
if data: if data:
self.facts['version'] = self.parse_version(data) self.facts['version'] = self.parse_version(data)
self.facts['serialnum'] = self.parse_serialnum(data) self.facts['serialnum'] = self.parse_serialnum(data)
@ -201,12 +229,18 @@ class Default(FactsBase):
class Hardware(FactsBase): class Hardware(FactsBase):
COMMANDS = [
'dir | include Directory',
'show memory statistics | include Processor'
]
def populate(self): def populate(self):
data = self.run('dir | include Directory') super(Hardware, self).populate()
data = self.responses[0]
if data: if data:
self.facts['filesystems'] = self.parse_filesystems(data) self.facts['filesystems'] = self.parse_filesystems(data)
data = self.run('show memory statistics | include Processor') data = self.responses[1]
if data: if data:
match = re.findall(r'\s(\d+)\s', data) match = re.findall(r'\s(\d+)\s', data)
if match: if match:
@ -219,33 +253,44 @@ class Hardware(FactsBase):
class Config(FactsBase): class Config(FactsBase):
COMMANDS = ['show running-config']
def populate(self): def populate(self):
data = self.run('show running-config') super(Config, self).populate()
data = self.responses[0]
if data: if data:
self.facts['config'] = data self.facts['config'] = data
class Interfaces(FactsBase): class Interfaces(FactsBase):
COMMANDS = [
'show interfaces',
'show ipv6 interface',
'show lldp'
]
def populate(self): def populate(self):
super(Interfaces, self).populate()
self.facts['all_ipv4_addresses'] = list() self.facts['all_ipv4_addresses'] = list()
self.facts['all_ipv6_addresses'] = list() self.facts['all_ipv6_addresses'] = list()
data = self.run('show interfaces') data = self.responses[0]
if data: if data:
interfaces = self.parse_interfaces(data) interfaces = self.parse_interfaces(data)
self.facts['interfaces'] = self.populate_interfaces(interfaces) self.facts['interfaces'] = self.populate_interfaces(interfaces)
data = self.run('show ipv6 interface') data = self.responses[1]
if data: if data:
data = self.parse_interfaces(data) data = self.parse_interfaces(data)
self.populate_ipv6_interfaces(data) self.populate_ipv6_interfaces(data)
data = self.run('show lldp') data = self.responses[2]
if 'LLDP is not enabled' not in data: if data:
neighbors = self.run('show lldp neighbors detail') neighbors = self.run('show lldp neighbors detail')
if neighbors: if neighbors:
self.facts['neighbors'] = self.parse_neighbors(neighbors) self.facts['neighbors'] = self.parse_neighbors(neighbors[0])
def populate_interfaces(self, interfaces): def populate_interfaces(self, interfaces):
facts = dict() facts = dict()
@ -392,11 +437,19 @@ FACT_SUBSETS = dict(
VALID_SUBSETS = frozenset(FACT_SUBSETS.keys()) VALID_SUBSETS = frozenset(FACT_SUBSETS.keys())
def main(): def main():
spec = dict( """main entry point for module execution
"""
argument_spec = dict(
gather_subset=dict(default=['!config'], type='list') gather_subset=dict(default=['!config'], type='list')
) )
module = NetworkModule(argument_spec=spec, supports_check_mode=True) argument_spec.update(ios_cli.ios_cli_argument_spec)
cls = get_ansible_module()
module = cls(argument_spec=argument_spec, supports_check_mode=True)
warnings = list()
check_args(module, warnings)
gather_subset = module.params['gather_subset'] gather_subset = module.params['gather_subset']
@ -438,24 +491,18 @@ def main():
for key in runable_subsets: for key in runable_subsets:
instances.append(FACT_SUBSETS[key](module)) instances.append(FACT_SUBSETS[key](module))
failed_commands = list()
try:
for inst in instances: for inst in instances:
inst.populate() inst.populate()
failed_commands.extend(inst.failed_commands)
facts.update(inst.facts) facts.update(inst.facts)
except Exception:
exc = get_exception()
module.fail_json(msg=str(exc))
ansible_facts = dict() ansible_facts = dict()
for key, value in iteritems(facts): for key, value in iteritems(facts):
key = 'ansible_net_%s' % key key = 'ansible_net_%s' % key
ansible_facts[key] = value ansible_facts[key] = value
module.exit_json(ansible_facts=ansible_facts, failed_commands=failed_commands) module.exit_json(ansible_facts=ansible_facts)
if __name__ == '__main__': if __name__ == '__main__':
SHARED_LIB = 'ios_cli'
main() main()

Loading…
Cancel
Save