From 2e65c1ebb7ab66d028efb30c20d1662150466de1 Mon Sep 17 00:00:00 2001 From: Dhivyap Date: Tue, 22 Oct 2019 14:06:34 +0530 Subject: [PATCH] Bug fixes- Dellos modules (#63272) --- .../module_utils/network/dellos10/dellos10.py | 59 ++++++++++------- .../module_utils/network/dellos6/dellos6.py | 66 ++++++++++++------- .../module_utils/network/dellos9/dellos9.py | 57 ++++++++++------ .../network/dellos10/dellos10_command.py | 64 +++++++++--------- .../network/dellos6/dellos6_command.py | 64 +++++++++--------- .../network/dellos9/dellos9_command.py | 64 +++++++++--------- lib/ansible/plugins/cliconf/dellos10.py | 26 ++++++++ lib/ansible/plugins/cliconf/dellos6.py | 28 +++++++- lib/ansible/plugins/cliconf/dellos9.py | 26 ++++++++ lib/ansible/plugins/terminal/dellos6.py | 6 ++ 10 files changed, 295 insertions(+), 165 deletions(-) diff --git a/lib/ansible/module_utils/network/dellos10/dellos10.py b/lib/ansible/module_utils/network/dellos10/dellos10.py index 99651d61a4e..dd5a040339d 100644 --- a/lib/ansible/module_utils/network/dellos10/dellos10.py +++ b/lib/ansible/module_utils/network/dellos10/dellos10.py @@ -29,12 +29,12 @@ # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -import re +import json from ansible.module_utils._text import to_text from ansible.module_utils.basic import env_fallback from ansible.module_utils.network.common.utils import to_list, ComplexList -from ansible.module_utils.connection import exec_command +from ansible.module_utils.connection import Connection, ConnectionError, exec_command from ansible.module_utils.network.common.config import NetworkConfig, ConfigLine _DEVICE_CONFIGS = {} @@ -71,6 +71,35 @@ dellos10_top_spec = { dellos10_argument_spec.update(dellos10_top_spec) +def get_provider_argspec(): + return dellos10_provider_spec + + +def get_connection(module): + if hasattr(module, '_dellos10_connection'): + return module._dellos10_connection + + capabilities = get_capabilities(module) + network_api = capabilities.get('network_api') + if network_api == 'cliconf': + module._dellos10_connection = Connection(module._socket_path) + else: + module.fail_json(msg='Invalid connection type %s' % network_api) + + return module._dellos10_connection + + +def get_capabilities(module): + if hasattr(module, '_dellos10_capabilities'): + return module._dellos10_capabilities + try: + capabilities = Connection(module._socket_path).get_capabilities() + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) + module._dellos10_capabilities = json.loads(capabilities) + return module._dellos10_capabilities + + def check_args(module, warnings): pass @@ -78,7 +107,7 @@ def check_args(module, warnings): def get_config(module, flags=None): flags = [] if flags is None else flags - cmd = 'show running-config ' + cmd = 'show running-configuration ' cmd += ' '.join(flags) cmd = cmd.strip() @@ -93,26 +122,12 @@ def get_config(module, flags=None): return cfg -def to_commands(module, commands): - spec = { - 'command': dict(key=True), - 'prompt': dict(), - 'answer': dict() - } - transform = ComplexList(spec, module) - return transform(commands) - - def run_commands(module, commands, check_rc=True): - responses = list() - commands = to_commands(module, to_list(commands)) - for cmd in commands: - cmd = module.jsonify(cmd) - rc, out, err = exec_command(module, cmd) - if check_rc and rc != 0: - module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), rc=rc) - responses.append(to_text(out, errors='surrogate_or_strict')) - return responses + connection = get_connection(module) + try: + return connection.run_commands(commands=commands, check_rc=check_rc) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc)) def load_config(module, commands): diff --git a/lib/ansible/module_utils/network/dellos6/dellos6.py b/lib/ansible/module_utils/network/dellos6/dellos6.py index 60d4db594fa..545a82757f9 100644 --- a/lib/ansible/module_utils/network/dellos6/dellos6.py +++ b/lib/ansible/module_utils/network/dellos6/dellos6.py @@ -30,11 +30,12 @@ # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # import re +import json from ansible.module_utils._text import to_text from ansible.module_utils.basic import env_fallback from ansible.module_utils.network.common.utils import to_list, ComplexList -from ansible.module_utils.connection import exec_command +from ansible.module_utils.connection import Connection, ConnectionError, exec_command from ansible.module_utils.network.common.config import NetworkConfig, ConfigLine, ignore_line _DEVICE_CONFIGS = {} @@ -71,6 +72,35 @@ dellos6_top_spec = { dellos6_argument_spec.update(dellos6_top_spec) +def get_provider_argspec(): + return dellos6_provider_spec + + +def get_connection(module): + if hasattr(module, '_dellos6_connection'): + return module._dellos6_connection + + capabilities = get_capabilities(module) + network_api = capabilities.get('network_api') + if network_api == 'cliconf': + module._dellos6_connection = Connection(module._socket_path) + else: + module.fail_json(msg='Invalid connection type %s' % network_api) + + return module._dellos6_connection + + +def get_capabilities(module): + if hasattr(module, '_dellos6_capabilities'): + return module._dellos6_capabilities + try: + capabilities = Connection(module._socket_path).get_capabilities() + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) + module._dellos6_capabilities = json.loads(capabilities) + return module._dellos6_capabilities + + def check_args(module, warnings): pass @@ -93,26 +123,12 @@ def get_config(module, flags=None): return cfg -def to_commands(module, commands): - spec = { - 'command': dict(key=True), - 'prompt': dict(), - 'answer': dict() - } - transform = ComplexList(spec, module) - return transform(commands) - - def run_commands(module, commands, check_rc=True): - responses = list() - commands = to_commands(module, to_list(commands)) - for cmd in commands: - cmd = module.jsonify(cmd) - rc, out, err = exec_command(module, cmd) - if check_rc and rc != 0: - module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), rc=rc) - responses.append(to_text(out, errors='surrogate_or_strict')) - return responses + connection = get_connection(module) + try: + return connection.run_commands(commands=commands, check_rc=check_rc) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc)) def load_config(module, commands): @@ -152,16 +168,16 @@ def os6_parse(lines, indent=None, comment_tokens=None): re.compile(r'datacenter-bridging.*$'), re.compile(r'line (console|telnet|ssh).*$'), re.compile(r'ip ssh !(server).*$'), + re.compile(r'(ip|mac|management|arp) access-list.*$'), re.compile(r'ip dhcp pool.*$'), re.compile(r'ip vrf !(forwarding).*$'), - re.compile(r'(ip|mac|management|arp) access-list.*$'), re.compile(r'ipv6 (dhcp pool|router).*$'), re.compile(r'mail-server.*$'), re.compile(r'vpc domain.*$'), re.compile(r'router.*$'), re.compile(r'route-map.*$'), re.compile(r'policy-map.*$'), - re.compile(r'class-map match-all.*$'), + re.compile(r'((class-map match-(all|any))|(class\s)).*$'), re.compile(r'captive-portal.*$'), re.compile(r'admin-profile.*$'), re.compile(r'link-dependency group.*$'), @@ -172,7 +188,9 @@ def os6_parse(lines, indent=None, comment_tokens=None): re.compile(r'address-family.*$'), re.compile(r'spanning-tree mst configuration.*$'), re.compile(r'logging (?!.*(cli-command|buffered|console|email|facility|file|monitor|protocol|snmp|source-interface|traps|web-session)).*$'), - re.compile(r'(radius-server|tacacs-server) host.*$')] + re.compile(r'(radius-server|tacacs-server) host.*$'), + re.compile(r'radius server (auth|acct).*$'), + re.compile(r'aaa server radius dynamic-author.*$')] childline = re.compile(r'^exit$') config = list() @@ -184,8 +202,6 @@ def os6_parse(lines, indent=None, comment_tokens=None): cfg = ConfigLine(text) cfg.raw = line if not text or ignore_line(text, comment_tokens): - parent = list() - children = [] continue else: diff --git a/lib/ansible/module_utils/network/dellos9/dellos9.py b/lib/ansible/module_utils/network/dellos9/dellos9.py index f8a0027a3d5..764c881b106 100644 --- a/lib/ansible/module_utils/network/dellos9/dellos9.py +++ b/lib/ansible/module_utils/network/dellos9/dellos9.py @@ -29,12 +29,12 @@ # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -import re +import json from ansible.module_utils._text import to_text from ansible.module_utils.basic import env_fallback from ansible.module_utils.network.common.utils import to_list, ComplexList -from ansible.module_utils.connection import exec_command +from ansible.module_utils.connection import Connection, ConnectionError, exec_command from ansible.module_utils.network.common.config import NetworkConfig, ConfigLine _DEVICE_CONFIGS = {} @@ -71,6 +71,35 @@ dellos9_top_spec = { dellos9_argument_spec.update(dellos9_top_spec) +def get_provider_argspec(): + return dellos9_provider_spec + + +def get_connection(module): + if hasattr(module, '_dellos9_connection'): + return module._dellos9_connection + + capabilities = get_capabilities(module) + network_api = capabilities.get('network_api') + if network_api == 'cliconf': + module._dellos9_connection = Connection(module._socket_path) + else: + module.fail_json(msg='Invalid connection type %s' % network_api) + + return module._dellos9_connection + + +def get_capabilities(module): + if hasattr(module, '_dellos9_capabilities'): + return module._dellos9_capabilities + try: + capabilities = Connection(module._socket_path).get_capabilities() + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) + module._dellos9_capabilities = json.loads(capabilities) + return module._dellos9_capabilities + + def check_args(module, warnings): pass @@ -93,26 +122,12 @@ def get_config(module, flags=None): return cfg -def to_commands(module, commands): - spec = { - 'command': dict(key=True), - 'prompt': dict(), - 'answer': dict() - } - transform = ComplexList(spec, module) - return transform(commands) - - def run_commands(module, commands, check_rc=True): - responses = list() - commands = to_commands(module, to_list(commands)) - for cmd in commands: - cmd = module.jsonify(cmd) - rc, out, err = exec_command(module, cmd) - if check_rc and rc != 0: - module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), rc=rc) - responses.append(to_text(out, errors='surrogate_or_strict')) - return responses + connection = get_connection(module) + try: + return connection.run_commands(commands=commands, check_rc=check_rc) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc)) def load_config(module, commands): diff --git a/lib/ansible/modules/network/dellos10/dellos10_command.py b/lib/ansible/modules/network/dellos10/dellos10_command.py index 939809ca729..64894c4823b 100644 --- a/lib/ansible/modules/network/dellos10/dellos10_command.py +++ b/lib/ansible/modules/network/dellos10/dellos10_command.py @@ -35,7 +35,11 @@ options: configured provider. The resulting output from the command is returned. If the I(wait_for) argument is provided, the module is not returned until the condition is satisfied or - the number of retries has expired. + the number of retries has expired. If a command sent to the + device requires answering a prompt, it is possible to pass + a dict containing I(command), I(answer) and I(prompt). + Common answers are 'yes' or "\\r" (carriage return, must be + double quotes). See examples. type: list required: true wait_for: @@ -43,7 +47,7 @@ options: - List of conditions to evaluate against the output of the command. The task will wait for each condition to be true before moving forward. If the conditional is not true - within the configured number of I(retries), the task fails. + within the configured number of retries, the task fails. See examples. type: list version_added: "2.2" @@ -57,7 +61,7 @@ options: satisfied. type: str default: all - choices: [ all, any ] + choices: [ 'all', 'any' ] version_added: "2.5" retries: description: @@ -102,6 +106,13 @@ tasks: wait_for: - result[0] contains OS10 - result[1] contains Ethernet + + - name: run commands that require answering a prompt + dellos10_command: + commands: + - command: 'reload' + prompt: '[confirm yes/no]: ?$' + answer: 'no' """ RETURN = """ @@ -128,39 +139,26 @@ warnings: """ import time +from ansible.module_utils._text import to_text from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network.common.parsing import Conditional +from ansible.module_utils.network.common.utils import transform_commands, to_lines from ansible.module_utils.network.dellos10.dellos10 import run_commands from ansible.module_utils.network.dellos10.dellos10 import dellos10_argument_spec, check_args -from ansible.module_utils.network.common.utils import ComplexList -from ansible.module_utils.network.common.parsing import Conditional -from ansible.module_utils.six import string_types - - -def to_lines(stdout): - for item in stdout: - if isinstance(item, string_types): - item = str(item).split('\n') - yield item def parse_commands(module, warnings): - command = ComplexList(dict( - command=dict(key=True), - prompt=dict(), - answer=dict() - ), module) - commands = command(module.params['commands']) - for index, item in enumerate(commands): - if module.check_mode and not item['command'].startswith('show'): - warnings.append( - 'only show commands are supported when using check mode, not ' - 'executing `%s`' % item['command'] - ) - elif item['command'].startswith('conf'): - module.fail_json( - msg='dellos10_command does not support running config mode ' - 'commands. Please use dellos10_config instead' - ) + commands = transform_commands(module) + + if module.check_mode: + for item in list(commands): + if not item['command'].startswith('show'): + warnings.append( + 'Only show commands are supported when using check mode, not ' + 'executing %s' % item['command'] + ) + commands.remove(item) + return commands @@ -191,8 +189,11 @@ def main(): result['warnings'] = warnings wait_for = module.params['wait_for'] or list() - conditionals = [Conditional(c) for c in wait_for] + try: + conditionals = [Conditional(c) for c in wait_for] + except AttributeError as exc: + module.fail_json(msg=to_text(exc)) retries = module.params['retries'] interval = module.params['interval'] match = module.params['match'] @@ -219,7 +220,6 @@ def main(): module.fail_json(msg=msg, failed_conditions=failed_conditions) result.update({ - 'changed': False, 'stdout': responses, 'stdout_lines': list(to_lines(responses)) }) diff --git a/lib/ansible/modules/network/dellos6/dellos6_command.py b/lib/ansible/modules/network/dellos6/dellos6_command.py index 3b9aa9aad1b..4c1933756b0 100644 --- a/lib/ansible/modules/network/dellos6/dellos6_command.py +++ b/lib/ansible/modules/network/dellos6/dellos6_command.py @@ -34,7 +34,11 @@ options: configured provider. The resulting output from the command is returned. If the I(wait_for) argument is provided, the module is not returned until the condition is satisfied or - the number of retries has expired. + the number of retries has expired. If a command sent to the + device requires answering a prompt, it is possible to pass + a dict containing I(command), I(answer) and I(prompt). + Common answers are 'yes' or "\\r" (carriage return, must be + double quotes). See examples. type: list required: true wait_for: @@ -42,7 +46,7 @@ options: - List of conditions to evaluate against the output of the command. The task will wait for each condition to be true before moving forward. If the conditional is not true - within the configured number of I(retries), the task fails. + within the configured number of retries, the task fails. See examples. type: list version_added: "2.2" @@ -56,7 +60,7 @@ options: satisfied. type: str default: all - choices: [ all, any ] + choices: [ 'all', 'any' ] version_added: "2.5" retries: description: @@ -101,6 +105,13 @@ tasks: wait_for: - result[0] contains Dell - result[1] contains Access + + - name: run commands that require answering a prompt + dellos6_command: + commands: + - command: 'copy running-config startup-config' + prompt: '[confirm yes/no]: ?$' + answer: 'yes' """ RETURN = """ @@ -128,39 +139,26 @@ warnings: import time +from ansible.module_utils._text import to_text from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network.common.parsing import Conditional +from ansible.module_utils.network.common.utils import transform_commands, to_lines from ansible.module_utils.network.dellos6.dellos6 import run_commands from ansible.module_utils.network.dellos6.dellos6 import dellos6_argument_spec, check_args -from ansible.module_utils.network.common.utils import ComplexList -from ansible.module_utils.network.common.parsing import Conditional -from ansible.module_utils.six import string_types - - -def to_lines(stdout): - for item in stdout: - if isinstance(item, string_types): - item = str(item).split('\n') - yield item def parse_commands(module, warnings): - command = ComplexList(dict( - command=dict(key=True), - prompt=dict(), - answer=dict() - ), module) - commands = command(module.params['commands']) - for index, item in enumerate(commands): - if module.check_mode and not item['command'].startswith('show'): - warnings.append( - 'only show commands are supported when using check mode, not ' - 'executing `%s`' % item['command'] - ) - elif item['command'].startswith('conf'): - module.fail_json( - msg='dellos6_command does not support running config mode ' - 'commands. Please use dellos6_config instead' - ) + commands = transform_commands(module) + + if module.check_mode: + for item in list(commands): + if not item['command'].startswith('show'): + warnings.append( + 'Only show commands are supported when using check mode, not ' + 'executing %s' % item['command'] + ) + commands.remove(item) + return commands @@ -190,8 +188,11 @@ def main(): result['warnings'] = warnings wait_for = module.params['wait_for'] or list() - conditionals = [Conditional(c) for c in wait_for] + try: + conditionals = [Conditional(c) for c in wait_for] + except AttributeError as exc: + module.fail_json(msg=to_text(exc)) retries = module.params['retries'] interval = module.params['interval'] match = module.params['match'] @@ -218,7 +219,6 @@ def main(): module.fail_json(msg=msg, failed_conditions=failed_conditions) result.update({ - 'changed': False, 'stdout': responses, 'stdout_lines': list(to_lines(responses)) }) diff --git a/lib/ansible/modules/network/dellos9/dellos9_command.py b/lib/ansible/modules/network/dellos9/dellos9_command.py index bd8cea71915..37c1e7a4702 100644 --- a/lib/ansible/modules/network/dellos9/dellos9_command.py +++ b/lib/ansible/modules/network/dellos9/dellos9_command.py @@ -35,7 +35,11 @@ options: configured provider. The resulting output from the command is returned. If the I(wait_for) argument is provided, the module is not returned until the condition is satisfied or - the number of retries has expired. + the number of retries has expired. If a command sent to the + device requires answering a prompt, it is possible to pass + a dict containing I(command), I(answer) and I(prompt). + Common answers are 'yes' or "\\r" (carriage return, must be + double quotes). See examples. type: list required: true wait_for: @@ -43,7 +47,7 @@ options: - List of conditions to evaluate against the output of the command. The task will wait for each condition to be true before moving forward. If the conditional is not true - within the configured number of I(retries), the task fails. + within the configured number of retries, the task fails. See examples. type: list version_added: "2.2" @@ -57,7 +61,7 @@ options: satisfied. type: str default: all - choices: [ all, any ] + choices: [ 'all', 'any' ] version_added: "2.5" retries: description: @@ -111,6 +115,13 @@ tasks: wait_for: - result[0] contains OS9 - result[1] contains Loopback + + - name: run commands that require answering a prompt + dellos9_command: + commands: + - command: 'copy running-config startup-config' + prompt: '[confirm yes/no]: ?$' + answer: 'yes' """ RETURN = """ @@ -137,39 +148,26 @@ warnings: """ import time +from ansible.module_utils._text import to_text from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network.common.parsing import Conditional +from ansible.module_utils.network.common.utils import transform_commands, to_lines from ansible.module_utils.network.dellos9.dellos9 import run_commands from ansible.module_utils.network.dellos9.dellos9 import dellos9_argument_spec, check_args -from ansible.module_utils.network.common.utils import ComplexList -from ansible.module_utils.network.common.parsing import Conditional -from ansible.module_utils.six import string_types - - -def to_lines(stdout): - for item in stdout: - if isinstance(item, string_types): - item = str(item).split('\n') - yield item def parse_commands(module, warnings): - command = ComplexList(dict( - command=dict(key=True), - prompt=dict(), - answer=dict() - ), module) - commands = command(module.params['commands']) - for index, item in enumerate(commands): - if module.check_mode and not item['command'].startswith('show'): - warnings.append( - 'only show commands are supported when using check mode, not ' - 'executing `%s`' % item['command'] - ) - elif item['command'].startswith('conf'): - module.fail_json( - msg='dellos9_command does not support running config mode ' - 'commands. Please use dellos9_config instead' - ) + commands = transform_commands(module) + + if module.check_mode: + for item in list(commands): + if not item['command'].startswith('show'): + warnings.append( + 'Only show commands are supported when using check mode, not ' + 'executing %s' % item['command'] + ) + commands.remove(item) + return commands @@ -200,8 +198,11 @@ def main(): result['warnings'] = warnings wait_for = module.params['wait_for'] or list() - conditionals = [Conditional(c) for c in wait_for] + try: + conditionals = [Conditional(c) for c in wait_for] + except AttributeError as exc: + module.fail_json(msg=to_text(exc)) retries = module.params['retries'] interval = module.params['interval'] match = module.params['match'] @@ -228,7 +229,6 @@ def main(): module.fail_json(msg=msg, failed_conditions=failed_conditions) result.update({ - 'changed': False, 'stdout': responses, 'stdout_lines': list(to_lines(responses)) }) diff --git a/lib/ansible/plugins/cliconf/dellos10.py b/lib/ansible/plugins/cliconf/dellos10.py index e6b818cc383..40bee342f3e 100644 --- a/lib/ansible/plugins/cliconf/dellos10.py +++ b/lib/ansible/plugins/cliconf/dellos10.py @@ -36,7 +36,9 @@ import json from itertools import chain +from ansible.errors import AnsibleConnectionFailure from ansible.module_utils._text import to_bytes, to_text +from ansible.module_utils.common._collections_compat import Mapping from ansible.module_utils.network.common.utils import to_list from ansible.plugins.cliconf import CliconfBase, enable_mode @@ -87,3 +89,27 @@ class Cliconf(CliconfBase): def get_capabilities(self): result = super(Cliconf, self).get_capabilities() return json.dumps(result) + + def run_commands(self, commands=None, check_rc=True): + if commands is None: + raise ValueError("'commands' value is required") + + responses = list() + for cmd in to_list(commands): + if not isinstance(cmd, Mapping): + cmd = {'command': cmd} + + output = cmd.pop('output', None) + if output: + raise ValueError("'output' value %s is not supported for run_commands" % output) + + try: + out = self.send_command(**cmd) + except AnsibleConnectionFailure as e: + if check_rc: + raise + out = getattr(e, 'err', to_text(e)) + + responses.append(out) + + return responses diff --git a/lib/ansible/plugins/cliconf/dellos6.py b/lib/ansible/plugins/cliconf/dellos6.py index da0d8dcc5f0..bae7caeb78e 100644 --- a/lib/ansible/plugins/cliconf/dellos6.py +++ b/lib/ansible/plugins/cliconf/dellos6.py @@ -36,7 +36,9 @@ import json from itertools import chain +from ansible.errors import AnsibleConnectionFailure from ansible.module_utils._text import to_bytes, to_text +from ansible.module_utils.common._collections_compat import Mapping from ansible.module_utils.network.common.utils import to_list from ansible.plugins.cliconf import CliconfBase, enable_mode @@ -58,7 +60,7 @@ class Cliconf(CliconfBase): if match: device_info['network_os_model'] = match.group(1) - reply = self.get('show running-config | grep hostname') + reply = self.get('show running-config | include hostname') data = to_text(reply, errors='surrogate_or_strict').strip() match = re.search(r'^hostname (.+)', data, re.M) if match: @@ -87,3 +89,27 @@ class Cliconf(CliconfBase): def get_capabilities(self): result = super(Cliconf, self).get_capabilities() return json.dumps(result) + + def run_commands(self, commands=None, check_rc=True): + if commands is None: + raise ValueError("'commands' value is required") + + responses = list() + for cmd in to_list(commands): + if not isinstance(cmd, Mapping): + cmd = {'command': cmd} + + output = cmd.pop('output', None) + if output: + raise ValueError("'output' value %s is not supported for run_commands" % output) + + try: + out = self.send_command(**cmd) + except AnsibleConnectionFailure as e: + if check_rc: + raise + out = getattr(e, 'err', to_text(e)) + + responses.append(out) + + return responses diff --git a/lib/ansible/plugins/cliconf/dellos9.py b/lib/ansible/plugins/cliconf/dellos9.py index 20df6a03d7a..d0a48d0ef81 100644 --- a/lib/ansible/plugins/cliconf/dellos9.py +++ b/lib/ansible/plugins/cliconf/dellos9.py @@ -36,7 +36,9 @@ import json from itertools import chain +from ansible.errors import AnsibleConnectionFailure from ansible.module_utils._text import to_bytes, to_text +from ansible.module_utils.common._collections_compat import Mapping from ansible.module_utils.network.common.utils import to_list from ansible.plugins.cliconf import CliconfBase, enable_mode @@ -87,3 +89,27 @@ class Cliconf(CliconfBase): def get_capabilities(self): result = super(Cliconf, self).get_capabilities() return json.dumps(result) + + def run_commands(self, commands=None, check_rc=True): + if commands is None: + raise ValueError("'commands' value is required") + + responses = list() + for cmd in to_list(commands): + if not isinstance(cmd, Mapping): + cmd = {'command': cmd} + + output = cmd.pop('output', None) + if output: + raise ValueError("'output' value %s is not supported for run_commands" % output) + + try: + out = self.send_command(**cmd) + except AnsibleConnectionFailure as e: + if check_rc: + raise + out = getattr(e, 'err', to_text(e)) + + responses.append(out) + + return responses diff --git a/lib/ansible/plugins/terminal/dellos6.py b/lib/ansible/plugins/terminal/dellos6.py index 842b0c936f2..5cbd8f36423 100644 --- a/lib/ansible/plugins/terminal/dellos6.py +++ b/lib/ansible/plugins/terminal/dellos6.py @@ -55,6 +55,12 @@ class TerminalModule(TerminalBase): terminal_inital_prompt_newline = False + def on_open_shell(self): + try: + self._exec_cli_command(b'terminal length 0') + except AnsibleConnectionFailure: + raise AnsibleConnectionFailure('unable to set terminal parameters') + def on_become(self, passwd=None): if self._get_prompt().endswith(b'#'): return