diff --git a/lib/ansible/module_utils/eos.py b/lib/ansible/module_utils/eos.py index 2d87d93c45..39771d0f9c 100644 --- a/lib/ansible/module_utils/eos.py +++ b/lib/ansible/module_utils/eos.py @@ -20,20 +20,16 @@ import re from ansible.module_utils.basic import json, get_exception, AnsibleModule -from ansible.module_utils.network import NetCli, NetworkError, get_module, Command +from ansible.module_utils.network import Command, NetCli, NetworkError, get_module from ansible.module_utils.network import add_argument, register_transport, to_list from ansible.module_utils.netcfg import NetworkConfig from ansible.module_utils.urls import fetch_url, url_argument_spec -NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) - EAPI_FORMATS = ['json', 'text'] add_argument('use_ssl', dict(default=True, type='bool')) add_argument('validate_certs', dict(default=True, type='bool')) -ModuleStub = AnsibleModule - def argument_spec(): return dict( # config options @@ -204,7 +200,7 @@ class Eapi(EosConfigMixin): def __init__(self): self.url = None - self.url_args = ModuleStub(url_argument_spec()) + self.url_args = AnsibleModule(url_argument_spec()) self.url_args.fail_json = self._error self.enable = None self.default_output = 'json' @@ -343,17 +339,11 @@ class Cli(NetCli, EosConfigMixin): re.compile(r"[^\r\n]\/bin\/(?:ba)?sh") ] - def __init__(self): - super(Cli, self).__init__() + NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) def connect(self, params, **kwargs): super(Cli, self).connect(params, kickstart=True, **kwargs) self.shell.send('terminal length 0') - self._connected = True - - def authorize(self, params, **kwargs): - passwd = params['auth_pass'] - self.execute(Command('enable', prompt=NET_PASSWD_RE, response=passwd)) ### implementation of network.Cli ### diff --git a/lib/ansible/module_utils/ios.py b/lib/ansible/module_utils/ios.py index 08cf9f8fc4..a58ce10a75 100644 --- a/lib/ansible/module_utils/ios.py +++ b/lib/ansible/module_utils/ios.py @@ -19,163 +19,61 @@ import re -from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception -from ansible.module_utils.shell import Shell, ShellError, Command, HAS_PARAMIKO -from ansible.module_utils.netcfg import parse +from ansible.module_utils.network import Command, NetCli, NetworkError, get_module +from ansible.module_utils.network import register_transport, to_list -NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) +class Cli(NetCli): + CLI_PROMPTS_RE = [ + re.compile(r"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), + re.compile(r"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$") + ] -NET_COMMON_ARGS = dict( - host=dict(required=True), - port=dict(default=22, type='int'), - 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'])), - provider=dict(), - timeout=dict(default=10, type='int') -) + CLI_ERRORS_RE = [ + re.compile(r"% ?Error"), + re.compile(r"% ?Bad secret"), + re.compile(r"invalid input", re.I), + re.compile(r"(?:incomplete|ambiguous) command", re.I), + re.compile(r"connection timed out", re.I), + re.compile(r"[^\r\n]+ not found", re.I), + re.compile(r"'[^']' +returned error code: ?\d+"), + ] -CLI_PROMPTS_RE = [ - re.compile(r"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), - re.compile(r"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$") -] + NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) -CLI_ERRORS_RE = [ - re.compile(r"% ?Error"), - re.compile(r"% ?Bad secret"), - re.compile(r"invalid input", re.I), - re.compile(r"(?:incomplete|ambiguous) command", re.I), - re.compile(r"connection timed out", re.I), - re.compile(r"[^\r\n]+ not found", re.I), - re.compile(r"'[^']' +returned error code: ?\d+"), -] + def connect(self, params, **kwargs): + super(Cli, self).connect(params, kickstart=False, **kwargs) + self.shell.send('terminal length 0') + ### implementation of network.Cli ### -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() + def configure(self, commands, **kwargs): + cmds = ['configure terminal'] + cmds.extend(to_list(commands)) + cmds.append('end') + responses = self.execute(cmds) + return responses[1:-1] -class Cli(object): - - def __init__(self, module): - self.module = module - self.shell = None - - def connect(self, **kwargs): - host = self.module.params['host'] - port = self.module.params['port'] or 22 - - username = self.module.params['username'] - password = self.module.params['password'] - key_filename = self.module.params['ssh_keyfile'] - timeout = self.module.params['timeout'] - - allow_agent = (key_filename is not None) or (key_filename is None and password is None) - - try: - self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE, - errors_re=CLI_ERRORS_RE) - self.shell.open(host, port=port, username=username, - password=password, key_filename=key_filename, - allow_agent=allow_agent, timeout=timeout) - except ShellError: - e = get_exception() - msg = 'failed to connect to %s:%s - %s' % (host, port, str(e)) - self.module.fail_json(msg=msg) - - def authorize(self): - passwd = self.module.params['auth_pass'] - self.send(Command('enable', prompt=NET_PASSWD_RE, response=passwd)) - - def send(self, commands): - try: - return self.shell.send(commands) - except ShellError: - e = get_exception() - self.module.fail_json(msg=e.message, commands=commands) - - -class NetworkModule(AnsibleModule): - - def __init__(self, *args, **kwargs): - super(NetworkModule, self).__init__(*args, **kwargs) - self.connection = None - self._config = None - self._connected = False - - @property - def connected(self): - return self._connected - - @property - def config(self): - if not self._config: - self._config = self.get_config() - return self._config - - def _load_params(self): - super(NetworkModule, self)._load_params() - provider = self.params.get('provider') or dict() - for key, value in provider.items(): - if key in NET_COMMON_ARGS: - if self.params.get(key) is None and value is not None: - self.params[key] = value - - def connect(self): - self.connection = Cli(self) - - self.connection.connect() - self.connection.send('terminal length 0') - - if self.params['authorize']: - self.connection.authorize() - - self._connected = True - - def configure(self, commands): - commands = to_list(commands) - commands.insert(0, 'configure terminal') - responses = self.execute(commands) - responses.pop(0) - return responses - - def execute(self, commands, **kwargs): - if not self.connected: - self.connect() - return self.connection.send(commands, **kwargs) - - def disconnect(self): - self.connection.close() - self._connected = False - - def parse_config(self, cfg): - return parse(cfg, indent=1) - - def get_config(self): + def get_config(self, params, **kwargs): cmd = 'show running-config' - if self.params.get('include_defaults'): + if params.get('include_defaults'): cmd += ' all' return self.execute(cmd)[0] + def load_config(self, commands, commit=False, **kwargs): + raise NotImplementedError -def get_module(**kwargs): - """Return instance of NetworkModule - """ - argument_spec = NET_COMMON_ARGS.copy() - if kwargs.get('argument_spec'): - argument_spec.update(kwargs['argument_spec']) - kwargs['argument_spec'] = argument_spec + def replace_config(self, commands, **kwargs): + raise NotImplementedError - module = NetworkModule(**kwargs) + def commit_config(self, **kwargs): + raise NotImplementedError - if not HAS_PARAMIKO: - module.fail_json(msg='paramiko is required but does not appear to be installed') + def abort_config(self, **kwargs): + raise NotImplementedError - return module + def run_commands(self, commands): + cmds = to_list(commands) + responses = self.execute(cmds) + return responses +Cli = register_transport('cli', default=True)(Cli) diff --git a/lib/ansible/module_utils/iosxr.py b/lib/ansible/module_utils/iosxr.py index b84a44e96b..33c5888447 100644 --- a/lib/ansible/module_utils/iosxr.py +++ b/lib/ansible/module_utils/iosxr.py @@ -19,144 +19,60 @@ import re -from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception -from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO -from ansible.module_utils.netcfg import parse +from ansible.module_utils.network import Command, NetCli, NetworkError, get_module +from ansible.module_utils.network import register_transport, to_list -NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) +class Cli(NetCli): + CLI_PROMPTS_RE = [ + re.compile(r"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), + re.compile(r"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$") + ] -NET_COMMON_ARGS = dict( - host=dict(required=True), - port=dict(default=22, type='int'), - 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'), - provider=dict() -) + CLI_ERRORS_RE = [ + re.compile(r"% ?Error"), + re.compile(r"% ?Bad secret"), + re.compile(r"invalid input", re.I), + re.compile(r"(?:incomplete|ambiguous) command", re.I), + re.compile(r"connection timed out", re.I), + re.compile(r"[^\r\n]+ not found", re.I), + re.compile(r"'[^']' +returned error code: ?\d+"), + ] -CLI_PROMPTS_RE = [ - re.compile(r"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), - re.compile(r"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$") -] + NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) -CLI_ERRORS_RE = [ - re.compile(r"% ?Error"), - re.compile(r"% ?Bad secret"), - re.compile(r"invalid input", re.I), - re.compile(r"(?:incomplete|ambiguous) command", re.I), - re.compile(r"connection timed out", re.I), - re.compile(r"[^\r\n]+ not found", re.I), - re.compile(r"'[^']' +returned error code: ?\d+"), -] + def connect(self, params, **kwargs): + super(Cli, self).connect(params, kickstart=False, **kwargs) + self.shell.send('terminal length 0') + ### implementation of network.Cli ### -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() + def configure(self, commands, **kwargs): + cmds = ['configure'] + cmds.extend(to_list(commands)) + cmds.append('end') + responses = self.execute(cmds) + return responses[1:-1] -class Cli(object): + def get_config(self, params, **kwargs): + return self.run_commands('show running-config')[0] - def __init__(self, module): - self.module = module - self.shell = None + def load_config(self, commands, commit=False, **kwargs): + raise NotImplementedError - def connect(self, **kwargs): - host = self.module.params['host'] - port = self.module.params['port'] or 22 + def replace_config(self, commands, **kwargs): + raise NotImplementedError - username = self.module.params['username'] - password = self.module.params['password'] - key_filename = self.module.params['ssh_keyfile'] + def commit_config(self, **kwargs): + command = 'commit' + self.run_commands([command]) - try: - self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE, errors_re=CLI_ERRORS_RE) - self.shell.open(host, port=port, username=username, password=password, key_filename=key_filename) - except ShellError: - e = get_exception() - msg = 'failed to connect to %s:%s - %s' % (host, port, str(e)) - self.module.fail_json(msg=msg) + def abort_config(self, **kwargs): + command = 'abort' + self.run_commands([command]) - def send(self, commands): - try: - return self.shell.send(commands) - except ShellError: - e = get_exception() - self.module.fail_json(msg=e.message, commands=commands) - - -class NetworkModule(AnsibleModule): - - def __init__(self, *args, **kwargs): - super(NetworkModule, self).__init__(*args, **kwargs) - self.connection = None - self._config = None - self._connected = False - - @property - def connected(self): - return self._connected - - @property - def config(self): - if not self._config: - self._config = self.get_config() - return self._config - - def _load_params(self): - super(NetworkModule, self)._load_params() - provider = self.params.get('provider') or dict() - for key, value in provider.items(): - if key in NET_COMMON_ARGS: - if self.params.get(key) is None and value is not None: - self.params[key] = value - - def connect(self): - self.connection = Cli(self) - - self.connection.connect() - self.connection.send('terminal length 0') - self._connected = True - - def configure(self, commands): - commands = to_list(commands) - commands.insert(0, 'configure terminal') - commands.append('commit') - responses = self.execute(commands) - responses.pop(0) - responses.pop() + def run_commands(self, commands): + cmds = to_list(commands) + responses = self.execute(cmds) return responses - - def execute(self, commands, **kwargs): - if not self.connected: - self.connect() - return self.connection.send(commands, **kwargs) - - def disconnect(self): - self.connection.close() - self._connected = False - - def parse_config(self, cfg): - return parse(cfg, indent=1) - - def get_config(self): - return self.execute('show running-config')[0] - -def get_module(**kwargs): - """Return instance of NetworkModule - """ - argument_spec = NET_COMMON_ARGS.copy() - if kwargs.get('argument_spec'): - argument_spec.update(kwargs['argument_spec']) - kwargs['argument_spec'] = argument_spec - - module = NetworkModule(**kwargs) - - if not HAS_PARAMIKO: - module.fail_json(msg='paramiko is required but does not appear to be installed') - - return module +Cli = register_transport('cli', default=True)(Cli) diff --git a/lib/ansible/module_utils/network.py b/lib/ansible/module_utils/network.py index d3cedf997e..4d80de7b03 100644 --- a/lib/ansible/module_utils/network.py +++ b/lib/ansible/module_utils/network.py @@ -237,6 +237,10 @@ class NetCli(object): self._connected = False self.shell.close() + def authorize(self, params, **kwargs): + passwd = params['auth_pass'] + self.execute(Command('enable', prompt=self.NET_PASSWD_RE, response=passwd)) + def execute(self, commands, **kwargs): try: return self.shell.send(commands)