diff options
Diffstat (limited to 'ansible_collections/dellemc/os6/plugins')
14 files changed, 0 insertions, 1742 deletions
diff --git a/ansible_collections/dellemc/os6/plugins/action/__init__.py b/ansible_collections/dellemc/os6/plugins/action/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/ansible_collections/dellemc/os6/plugins/action/__init__.py +++ /dev/null diff --git a/ansible_collections/dellemc/os6/plugins/action/os6.py b/ansible_collections/dellemc/os6/plugins/action/os6.py deleted file mode 100644 index a7f16df37..000000000 --- a/ansible_collections/dellemc/os6/plugins/action/os6.py +++ /dev/null @@ -1,95 +0,0 @@ -# -# (c) 2020 Red Hat Inc. -# -# (c) 2020 Dell Inc. -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import sys -import copy - -from ansible import constants as C -from ansible.module_utils._text import to_text -from ansible.module_utils.connection import Connection -from ansible_collections.dellemc.os6.plugins.module_utils.network.os6 import os6_provider_spec -from ansible_collections.ansible.netcommon.plugins.action.network import ActionModule as ActionNetworkModule -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider -from ansible.utils.display import Display - -display = Display() - - -class ActionModule(ActionNetworkModule): - - def run(self, tmp=None, task_vars=None): - del tmp # tmp no longer has any effect - - module_name = self._task.action.split('.')[-1] - self._config_module = True if module_name == 'os6_config' else False - socket_path = None - persistent_connection = self._play_context.connection.split('.')[-1] - - if persistent_connection == 'network_cli': - provider = self._task.args.get('provider', {}) - if any(provider.values()): - display.warning('provider is unnecessary when using network_cli and will be ignored') - del self._task.args['provider'] - elif self._play_context.connection == 'local': - provider = load_provider(os6_provider_spec, self._task.args) - pc = copy.deepcopy(self._play_context) - pc.connection = 'network_cli' - pc.network_os = 'dellemc.os6.os6' - pc.remote_addr = provider['host'] or self._play_context.remote_addr - pc.port = int(provider['port'] or self._play_context.port or 22) - pc.remote_user = provider['username'] or self._play_context.connection_user - pc.password = provider['password'] or self._play_context.password - pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file - command_timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) - pc.become = provider['authorize'] or False - if pc.become: - pc.become_method = 'enable' - pc.become_pass = provider['auth_pass'] - - display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) - connection.set_options(direct={'persistent_command_timeout': command_timeout}) - - socket_path = connection.run() - display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) - if not socket_path: - return {'failed': True, - 'msg': 'unable to open shell. Please see: ' + - 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} - - task_vars['ansible_socket'] = socket_path - - # make sure we are in the right cli context which should be - # enable mode and not config module - if socket_path is None: - socket_path = self._connection.socket_path - - conn = Connection(socket_path) - out = conn.get_prompt() - while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'): - display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) - conn.send_command('exit') - out = conn.get_prompt() - - result = super(ActionModule, self).run(task_vars=task_vars) - return result diff --git a/ansible_collections/dellemc/os6/plugins/cliconf/__init__.py b/ansible_collections/dellemc/os6/plugins/cliconf/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/ansible_collections/dellemc/os6/plugins/cliconf/__init__.py +++ /dev/null diff --git a/ansible_collections/dellemc/os6/plugins/cliconf/os6.py b/ansible_collections/dellemc/os6/plugins/cliconf/os6.py deleted file mode 100644 index 9c9290da7..000000000 --- a/ansible_collections/dellemc/os6/plugins/cliconf/os6.py +++ /dev/null @@ -1,88 +0,0 @@ -# -# (c) 2020 Red Hat Inc. -# -# (c) 2020 Dell Inc. -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = """ ---- -cliconf: os6 -short_description: Use os6 cliconf to run command on Dell OS6 platform -description: - - This os6 plugin provides low level abstraction apis for - sending and receiving CLI commands from Dell OS6 network devices. -""" - -import re -import json - -from itertools import chain - -from ansible.module_utils._text import to_bytes, to_text -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list -from ansible.plugins.cliconf import CliconfBase, enable_mode - - -class Cliconf(CliconfBase): - - def get_device_info(self): - device_info = {} - - device_info['network_os'] = 'dellemc.os6.os6' - reply = self.get('show version') - data = to_text(reply, errors='surrogate_or_strict').strip() - - match = re.search(r'Software Version (\S+)', data) - if match: - device_info['network_os_version'] = match.group(1) - - match = re.search(r'System Type (\S+)', data, re.M) - if match: - device_info['network_os_model'] = match.group(1) - - reply = self.get('show running-config | grep hostname') - data = to_text(reply, errors='surrogate_or_strict').strip() - match = re.search(r'^hostname (.+)', data, re.M) - if match: - device_info['network_os_hostname'] = match.group(1) - - return device_info - - @enable_mode - def get_config(self, source='running', format='text', flags=None): - if source not in ('running', 'startup'): - return self.invalid_params("fetching configuration from %s is not supported" % source) -# if source == 'running': -# cmd = 'show running-config all' - else: - cmd = 'show startup-config' - return self.send_command(cmd) - - @enable_mode - def edit_config(self, command): - for cmd in chain(['configure terminal'], to_list(command), ['end']): - self.send_command(cmd) - - def get(self, command, prompt=None, answer=None, sendonly=False, newline=True, check_all=False): - return self.send_command(command=command, prompt=prompt, answer=answer, sendonly=sendonly, newline=newline, check_all=check_all) - - def get_capabilities(self): - result = super(Cliconf, self).get_capabilities() - return json.dumps(result) diff --git a/ansible_collections/dellemc/os6/plugins/doc_fragments/__init__.py b/ansible_collections/dellemc/os6/plugins/doc_fragments/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/ansible_collections/dellemc/os6/plugins/doc_fragments/__init__.py +++ /dev/null diff --git a/ansible_collections/dellemc/os6/plugins/doc_fragments/os6.py b/ansible_collections/dellemc/os6/plugins/doc_fragments/os6.py deleted file mode 100644 index 32daca592..000000000 --- a/ansible_collections/dellemc/os6/plugins/doc_fragments/os6.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright: (c) 2020, Peter Sprygada <psprygada@ansible.com> -# Copyright: (c) 2020, Dell Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class ModuleDocFragment(object): - - # Standard files documentation fragment - DOCUMENTATION = r''' -options: - provider: - description: - - A dict object containing connection details. - type: dict - suboptions: - host: - description: - - Specifies the DNS host name or address for connecting to the remote - device over the specified transport. The value of host is used as - the destination address for the transport. - type: str - port: - description: - - Specifies the port to use when building the connection to the remote - device. - type: int - username: - description: - - User to authenticate the SSH session to the remote device. If the - value is not specified in the task, the value of environment variable - C(ANSIBLE_NET_USERNAME) will be used instead. - type: str - password: - description: - - Password to authenticate the SSH session to the remote device. If the - value is not specified in the task, the value of environment variable - C(ANSIBLE_NET_PASSWORD) will be used instead. - type: str - ssh_keyfile: - description: - - Path to an ssh key used to authenticate the SSH session to the remote - device. If the value is not specified in the task, the value of - environment variable C(ANSIBLE_NET_SSH_KEYFILE) will be used instead. - type: path - timeout: - description: - - Specifies idle timeout (in seconds) for the connection. Useful if the - console freezes before continuing. For example when saving - configurations. - type: int - authorize: - description: - - Instructs the module to enter privileged mode on the remote device before - sending any commands. If not specified, the device will attempt to execute - all commands in non-privileged mode. If the value is not specified in the - task, the value of environment variable C(ANSIBLE_NET_AUTHORIZE) will be - used instead. - type: bool - auth_pass: - 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. - If the value is not specified in the task, the value of environment variable - C(ANSIBLE_NET_AUTH_PASS) will be used instead. - type: str -notes: - - For more information on using Ansible to manage Dell EMC Network devices see U(https://www.ansible.com/ansible-dell-networking). -''' diff --git a/ansible_collections/dellemc/os6/plugins/module_utils/network/__init__.py b/ansible_collections/dellemc/os6/plugins/module_utils/network/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/ansible_collections/dellemc/os6/plugins/module_utils/network/__init__.py +++ /dev/null diff --git a/ansible_collections/dellemc/os6/plugins/module_utils/network/os6.py b/ansible_collections/dellemc/os6/plugins/module_utils/network/os6.py deleted file mode 100644 index aeea2cfc0..000000000 --- a/ansible_collections/dellemc/os6/plugins/module_utils/network/os6.py +++ /dev/null @@ -1,278 +0,0 @@ -# -# (c) 2020 Peter Sprygada, <psprygada@ansible.com> -# (c) 2020 Red Hat, Inc -# -# Copyright (c) 2020 Dell Inc. -# -# This code is part of Ansible, but is an independent component. -# This particular file snippet, and this file snippet only, is BSD licensed. -# Modules you write using this snippet, which is embedded dynamically by Ansible -# still belong to the author of the module, and may assign their own license -# to the complete work. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# 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. -# -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -import re -import json -from ansible.module_utils._text import to_text -from ansible.module_utils.basic import env_fallback -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list, ComplexList -from ansible.module_utils.connection import exec_command -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig, ConfigLine, ignore_line -from ansible.module_utils._text import to_bytes -from ansible.module_utils.connection import Connection, ConnectionError - -_DEVICE_CONFIGS = {} - -WARNING_PROMPTS_RE = [ - r"[\r\n]?\[confirm yes/no\]:\s?$", - r"[\r\n]?\[y/n\]:\s?$", - r"[\r\n]?\[yes/no\]:\s?$" -] - -os6_provider_spec = { - 'host': dict(), - 'port': dict(type='int'), - 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), - 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), - 'ssh_keyfile': dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'), - 'authorize': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'), - 'auth_pass': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS']), no_log=True), - 'timeout': dict(type='int'), -} -os6_argument_spec = { - 'provider': dict(type='dict', options=os6_provider_spec), -} - - -def check_args(module, warnings): - pass - - -def get_connection(module): - if hasattr(module, "_os6_connection"): - return module._os6_connection - - capabilities = get_capabilities(module) - network_api = capabilities.get("network_api") - if network_api in ["cliconf"]: - module._os6_connection = Connection(module._socket_path) - else: - module.fail_json(msg="Invalid connection type %s" % network_api) - - return module._os6_connection - - -def get_capabilities(module): - if hasattr(module, "_os6_capabilities"): - return module._os6_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._os6_capabilities = json.loads(capabilities) - return module._os6_capabilities - - -def get_config(module, flags=None): - flags = [] if flags is None else flags - - cmd = 'show running-config' - cmd += ' '.join(flags) - cmd = cmd.strip() - - try: - return _DEVICE_CONFIGS[cmd] - except KeyError: - rc, out, err = exec_command(module, cmd) - if rc != 0: - module.fail_json(msg='unable to retrieve current config', stderr=to_text(err, errors='surrogate_or_strict')) - cfg = to_text(out, errors='surrogate_or_strict').strip() - _DEVICE_CONFIGS[cmd] = cfg - return cfg - - -def to_commands(module, commands): - spec = { - 'command': dict(key=True), - 'prompt': dict(), - 'answer': dict(), - 'sendonly': dict(), - 'newline': 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 - - -def load_config(module, commands): - rc, out, err = exec_command(module, 'configure terminal') - if rc != 0: - module.fail_json(msg='unable to enter configuration mode', err=to_text(err, errors='surrogate_or_strict')) - - for command in to_list(commands): - if command == 'end': - continue - rc, out, err = exec_command(module, command) - if rc != 0: - module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), command=command, rc=rc) - exec_command(module, 'end') - - -def get_sublevel_config(running_config, module): - contents = list() - current_config_contents = list() - sublevel_config = NetworkConfig(indent=0) - obj = running_config.get_object(module.params['parents']) - if obj: - contents = obj._children - for c in contents: - if isinstance(c, ConfigLine): - current_config_contents.append(c.raw) - sublevel_config.add(current_config_contents, module.params['parents']) - return sublevel_config - - -def os6_parse(lines, indent=None, comment_tokens=None): - sublevel_cmds = [ - re.compile(r'^vlan\s[\d,-]+.*$'), - re.compile(r'^stack.*$'), - re.compile(r'^interface.*$'), - re.compile(r'datacenter-bridging.*$'), - re.compile(r'line (console|telnet|ssh).*$'), - re.compile(r'ip ssh !(server).*$'), - 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\s.*$'), - re.compile(r'route-map.*$'), - re.compile(r'policy-map.*$'), - re.compile(r'class-map match-all.*$'), - re.compile(r'captive-portal.*$'), - re.compile(r'admin-profile.*$'), - re.compile(r'link-dependency group.*$'), - re.compile(r'openflow.*$'), - re.compile(r'support-assist.*$'), - re.compile(r'template.*$'), - 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 (?!.*(attribute|dead-criteria|deadtime|timeout|key|load-balance|retransmit|source-interface|source-ip|vsa)).*$'), - re.compile(r'(tacacs-server) host.*$')] - - childline = re.compile(r'^exit\s*$') - config = list() - parent = list() - children = [] - parent_match = False - for line in str(lines).split('\n'): - line = str(line).strip() - text = str(re.sub(r'([{};])', '', line)).strip() - cfg = ConfigLine(text) - cfg.raw = line - if not text or ignore_line(text, comment_tokens): - parent = list() - children = [] - continue - - parent_match = False - # handle sublevel parent - for pr in sublevel_cmds: - if pr.match(line): - if len(parent) != 0: - cfg._parents.extend(parent) - parent.append(cfg) - config.append(cfg) - if children: - children.insert(len(parent) - 1, []) - children[len(parent) - 2].append(cfg) - if not children and len(parent) > 1: - configlist = [cfg] - children.append(configlist) - children.insert(len(parent) - 1, []) - parent_match = True - continue - # handle exit - if childline.match(line): - if children: - parent[len(children) - 1]._children.extend(children[len(children) - 1]) - if len(children) > 1: - parent[len(children) - 2]._children.extend(parent[len(children) - 1]._children) - cfg._parents.extend(parent) - children.pop() - parent.pop() - if not children: - children = list() - if parent: - cfg._parents.extend(parent) - parent = list() - config.append(cfg) - # handle sublevel children - elif parent_match is False and len(parent) > 0: - if not children: - cfglist = [cfg] - children.append(cfglist) - else: - children[len(parent) - 1].append(cfg) - cfg._parents.extend(parent) - config.append(cfg) - # handle global commands - elif not parent: - config.append(cfg) - return config - - -class NetworkConfig(NetworkConfig): - - def load(self, contents): - self._items = os6_parse(contents, self._indent) - - def _diff_line(self, other, path=None): - diff = list() - for item in self.items: - if str(item) == "exit": - for diff_item in diff: - if diff_item._parents: - if item._parents == diff_item._parents: - diff.append(item) - break - elif [e for e in item._parents if e == diff_item]: - diff.append(item) - break - elif item not in other: - diff.append(item) - return diff diff --git a/ansible_collections/dellemc/os6/plugins/modules/__init__.py b/ansible_collections/dellemc/os6/plugins/modules/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/ansible_collections/dellemc/os6/plugins/modules/__init__.py +++ /dev/null diff --git a/ansible_collections/dellemc/os6/plugins/modules/os6_command.py b/ansible_collections/dellemc/os6/plugins/modules/os6_command.py deleted file mode 100644 index 99df00144..000000000 --- a/ansible_collections/dellemc/os6/plugins/modules/os6_command.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2020, Peter Sprygada <psprygada@ansible.com> -# Copyright: (c) 2020, Dell Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = """ ---- -module: os6_command -author: "Abirami N (@abirami-n)" -short_description: Run commands on devices running Dell EMC OS6 -description: - - Sends arbitrary commands to a OS6 device and returns the results - read from the device. This module includes an - argument that will cause the module to wait for a specific condition - before returning or timing out if the condition is not met. - - This module does not support running commands in configuration mode. - Please use M(dellemc_os6_os6_config) to configure OS6 devices. -extends_documentation_fragment: dellemc.os6.os6 -options: - commands: - description: - - List of commands to send to the remote os6 device over the - 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. - type: list - required: true - wait_for: - description: - - 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. - See examples. - type: list - elements: str - match: - description: - - The I(match) argument is used in conjunction with the - I(wait_for) argument to specify the match policy. Valid - values are C(all) or C(any). If the value is set to C(all) - then all conditionals in the wait_for must be satisfied. If - the value is set to C(any) then only one of the values must be - satisfied. - type: str - default: all - choices: [ all, any ] - retries: - description: - - Specifies the number of retries a command should be tried - before it is considered failed. The command is run on the - target device every retry and evaluated against the - I(wait_for) conditions. - type: int - default: 10 - interval: - description: - - Configures the interval in seconds to wait between retries - of the command. If the command does not pass the specified - conditions, the interval indicates how long to wait before - trying the command again. - type: int - default: 1 -""" - -EXAMPLES = """ -tasks: - - name: run show version on remote devices - os6_command: - commands: show version - - name: run show version and check to see if output contains Dell - os6_command: - commands: show version - wait_for: result[0] contains Dell - - name: run multiple commands on remote nodes - os6_command: - commands: - - show version - - show interfaces - - name: run multiple commands and evaluate the output - os6_command: - commands: - - show version - - show interfaces - wait_for: - - result[0] contains Dell - - result[1] contains Access -""" - -RETURN = """ -stdout: - description: The set of responses from the commands - returned: always apart from low level errors (such as action plugin) - type: list - sample: ['...', '...'] -stdout_lines: - description: The value of stdout split into a list - returned: always apart from low level errors (such as action plugin) - type: list - sample: [['...', '...'], ['...'], ['...']] -failed_conditions: - description: The list of conditionals that have failed - returned: failed - type: list - sample: ['...', '...'] -warnings: - description: The list of warnings (if any) generated by module based on arguments - returned: always - type: list - sample: ['...', '...'] -""" - -import time - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.dellemc.os6.plugins.module_utils.network.os6 import run_commands -from ansible_collections.dellemc.os6.plugins.module_utils.network.os6 import os6_argument_spec, check_args -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ComplexList -from ansible_collections.ansible.netcommon.plugins.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='os6_command does not support running config mode ' - 'commands. Please use os6_config instead' - ) - return commands - - -def main(): - """main entry point for module execution - """ - argument_spec = dict( - # { command: <str>, prompt: <str>, response: <str> } - commands=dict(type='list', required=True), - - wait_for=dict(type='list', elements='str'), - match=dict(default='all', choices=['all', 'any']), - - retries=dict(default=10, type='int'), - interval=dict(default=1, type='int') - ) - - argument_spec.update(os6_argument_spec) - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - result = {'changed': False} - - warnings = list() - check_args(module, warnings) - commands = parse_commands(module, warnings) - result['warnings'] = warnings - - wait_for = module.params['wait_for'] or list() - conditionals = [Conditional(c) for c in wait_for] - - retries = module.params['retries'] - interval = module.params['interval'] - match = module.params['match'] - - while retries > 0: - responses = run_commands(module, commands) - - for item in list(conditionals): - if item(responses): - if match == 'any': - conditionals = list() - break - conditionals.remove(item) - - if not conditionals: - break - - time.sleep(interval) - retries -= 1 - - if conditionals: - failed_conditions = [item.raw for item in conditionals] - msg = 'One or more conditional statements have not been satisfied' - module.fail_json(msg=msg, failed_conditions=failed_conditions) - - result.update({ - 'changed': False, - 'stdout': responses, - 'stdout_lines': list(to_lines(responses)) - }) - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/dellemc/os6/plugins/modules/os6_config.py b/ansible_collections/dellemc/os6/plugins/modules/os6_config.py deleted file mode 100644 index b4321e9fd..000000000 --- a/ansible_collections/dellemc/os6/plugins/modules/os6_config.py +++ /dev/null @@ -1,410 +0,0 @@ -#!/usr/bin/python -# -# (c) 2020 Peter Sprygada, <psprygada@ansible.com> -# Copyright (c) 2020 Dell Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = """ ---- -module: os6_config -author: "Abirami N (@abirami-n)" -short_description: Manage Dell EMC OS6 configuration sections -description: - - OS6 configurations use a simple block indent file syntax - for segmenting configuration into sections. This module provides - an implementation for working with OS6 configuration sections in - a deterministic way. -extends_documentation_fragment: dellemc.os6.os6 -options: - lines: - description: - - The ordered set of commands that should be configured in the - section. The commands must be the exact same commands as found - in the device running-config. Be sure to note the configuration - command syntax as some commands are automatically modified by the - device config parser. This argument is mutually exclusive with I(src). - type: list - aliases: ['commands'] - parents: - description: - - The ordered set of parents that uniquely identify the section or hierarchy - the commands should be checked against. If the parents argument - is omitted, the commands are checked against the set of top - level or global commands. - type: list - src: - description: - - Specifies the source path to the file that contains the configuration - or configuration template to load. The path to the source file can - either be the full path on the Ansible control host or a relative - path from the playbook or role root directory. This argument is - mutually exclusive with I(lines). - type: path - before: - description: - - The ordered set of commands to push on to the command stack if - a change needs to be made. This allows the playbook designer - the opportunity to perform configuration commands prior to pushing - any changes without affecting how the set of commands are matched - against the system. - type: list - after: - description: - - The ordered set of commands to append to the end of the command - stack if a change needs to be made. Just like with I(before) this - allows the playbook designer to append a set of commands to be - executed after the command set. - type: list - match: - description: - - Instructs the module on the way to perform the matching of - the set of commands against the current device config. If - match is set to I(line), commands are matched line by line. If - match is set to I(strict), command lines are matched with respect - to position. If match is set to I(exact), command lines - must be an equal match. Finally, if match is set to I(none), the - module will not attempt to compare the source configuration with - the running configuration on the remote device. - type: str - default: line - choices: ['line', 'strict', 'exact', 'none'] - replace: - description: - - Instructs the module on the way to perform the configuration - on the device. If the replace argument is set to I(line) then - the modified lines are pushed to the device in configuration - mode. If the replace argument is set to I(block) then the entire - command block is pushed to the device in configuration mode if any - line is not correct. - type: str - default: line - choices: ['line', 'block'] - update: - description: - - The I(update) argument controls how the configuration statements - are processed on the remote device. Valid choices for the I(update) - argument are I(merge) and I(check). When you set this argument to - I(merge), the configuration changes merge with the current - device running configuration. When you set this argument to I(check) - the configuration updates are determined but not actually configured - on the remote device. - type: str - default: merge - choices: ['merge', 'check'] - save: - description: - - The C(save) argument instructs the module to save the running- - config to the startup-config at the conclusion of the module - running. If check mode is specified, this argument is ignored. - type: bool - default: 'no' - config: - description: - - The module, by default, will connect to the remote device and - retrieve the current running-config to use as a base for comparing - against the contents of source. There are times when it is not - desirable to have the task get the current running-config for - every task in a playbook. The I(config) argument allows the - implementer to pass in the configuration to use as the base - config for comparison. - type: str - backup: - description: - - This argument will cause the module to create a full backup of - the current C(running-config) from the remote device before any - changes are made. If the C(backup_options) value is not given, - the backup file is written to the C(backup) folder in the playbook - root directory. If the directory does not exist, it is created. - type: bool - default: 'no' - backup_options: - description: - - This is a dict object containing configurable options related to backup file path. - The value of this option is read only when C(backup) is set to I(yes), if C(backup) is set - to I(no) this option will be silently ignored. - suboptions: - filename: - description: - - The filename to be used to store the backup configuration. If the the filename - is not given it will be generated based on the hostname, current time and date - in format defined by <hostname>_config.<current-date>@<current-time> - type: str - dir_path: - description: - - This option provides the path ending with directory name in which the backup - configuration file will be stored. If the directory does not exist it will be first - created and the filename is either the value of C(filename) or default filename - as described in C(filename) options description. If the path value is not given - in that case a I(backup) directory will be created in the current working directory - and backup configuration will be copied in C(filename) within I(backup) directory. - type: path - type: dict -""" - -EXAMPLES = """ -- os6_config: - lines: ['hostname {{ inventory_hostname }}'] -- os6_config: - lines: - - 10 permit ip 1.1.1.1 any log - - 20 permit ip 2.2.2.2 any log - - 30 permit ip 3.3.3.3 any log - - 40 permit ip 4.4.4.4 any log - - 50 permit ip 5.5.5.5 any log - parents: ['ip access-list test'] - before: ['no ip access-list test'] - match: exact -- os6_config: - lines: - - 10 permit ip 1.1.1.1 any log - - 20 permit ip 2.2.2.2 any log - - 30 permit ip 3.3.3.3 any log - - 40 permit ip 4.4.4.4 any log - parents: ['ip access-list test'] - before: ['no ip access-list test'] - replace: block -- os6_config: - lines: ['hostname {{ inventory_hostname }}'] - backup: yes - backup_options: - filename: backup.cfg - dir_path: /home/user -""" - -RETURN = """ -updates: - description: The set of commands that will be pushed to the remote device. - returned: always - type: list - sample: ['interface Te1/0/1', 'no shutdown', 'exit'] -commands: - description: The set of commands that will be pushed to the remote device - returned: always - type: list - sample: ['interface Te1/0/1', 'no shutdown', 'exit'] -saved: - description: Returns whether the configuration is saved to the startup - configuration or not. - returned: When not check_mode. - type: bool - sample: True -backup_path: - description: The full path to the backup file - returned: when backup is yes - type: str - sample: /playbooks/ansible/backup/os6_config.2017-07-16@22:28:34 -""" -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.dellemc.os6.plugins.module_utils.network.os6 import get_config, get_sublevel_config, NetworkConfig -from ansible_collections.dellemc.os6.plugins.module_utils.network.os6 import os6_argument_spec, check_args -from ansible_collections.dellemc.os6.plugins.module_utils.network.os6 import load_config, run_commands -from ansible_collections.dellemc.os6.plugins.module_utils.network.os6 import WARNING_PROMPTS_RE -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import dumps -import re -from ansible.module_utils.six import iteritems -from ansible.module_utils.connection import exec_command -from ansible.module_utils._text import to_bytes - - -def get_candidate(module): - candidate = NetworkConfig(indent=0) - banners = {} - if module.params['src']: - src, banners = extract_banners(module.params['src']) - candidate.load(src) - elif module.params['lines']: - parents = module.params['parents'] or list() - commands = module.params['lines'][0] - if (isinstance(commands, dict)) and (isinstance(commands['command'], list)): - candidate.add(commands['command'], parents=parents) - elif (isinstance(commands, dict)) and (isinstance(commands['command'], str)): - candidate.add([commands['command']], parents=parents) - else: - lines, banners = extract_banners(module.params['lines']) - candidate.add(lines, parents=parents) - return candidate, banners - - -def extract_banners(config): - flag = False - if isinstance(config, list): - str1 = "\n" - config = str1.join(config) - flag = True - banners = {} - banner_cmds = re.findall(r'^banner (\w+)', config, re.M) - for cmd in banner_cmds: - regex = r'banner %s \"(.+?)\".*' % cmd - match = re.search(regex, config, re.S) - if match: - key = 'banner %s' % cmd - banners[key] = match.group(1).strip() - - for cmd in banner_cmds: - regex = r'banner %s \"(.+?)\".*' % cmd - match = re.search(regex, config, re.S) - if match: - config = config.replace(str(match.group(1)), '') - config = re.sub(r'banner \w+ \"\"', '', config) - if flag: - config = config.split("\n") - return (config, banners) - - -def diff_banners(want, have): - candidate = {} - for key, value in iteritems(want): - if value != have.get(key): - candidate[key] = value - return candidate - - -def get_running_config(module): - contents = module.params['config'] - if not contents: - contents = get_config(module) - contents, banners = extract_banners(contents) - return contents, banners - - -def load_banners(module, banners): - result_banners = [] - exec_command(module, 'configure terminal') - for each in banners: - delimiter = '"' - cmdline = "" - for key, value in each.items(): - cmdline = key + " " + delimiter + value + delimiter - for cmd in cmdline.split("\n"): - rc, out, err = exec_command(module, module.jsonify({'command': cmd, 'sendonly': True})) - result_banners.append(cmdline) - exec_command(module, 'end') - return result_banners - - -def main(): - backup_spec = dict( - filename=dict(), - dir_path=dict(type='path') - ) - argument_spec = dict( - lines=dict(aliases=['commands'], type='list'), - parents=dict(type='list'), - - src=dict(type='path'), - - before=dict(type='list'), - after=dict(type='list'), - - match=dict(default='line', - choices=['line', 'strict', 'exact', 'none']), - replace=dict(default='line', choices=['line', 'block']), - - update=dict(choices=['merge', 'check'], default='merge'), - save=dict(type='bool', default=False), - config=dict(), - backup=dict(type='bool', default=False), - backup_options=dict(type='dict', options=backup_spec) - ) - - argument_spec.update(os6_argument_spec) - mutually_exclusive = [('lines', 'src'), - ('parents', 'src')] - - module = AnsibleModule(argument_spec=argument_spec, - mutually_exclusive=mutually_exclusive, - supports_check_mode=True) - - parents = module.params['parents'] or list() - - match = module.params['match'] - replace = module.params['replace'] - - warnings = list() - check_args(module, warnings) - result = dict(changed=False, saved=False, warnings=warnings) - - candidate, want_banners = get_candidate(module) - if module.params['backup']: - if not module.check_mode: - result['__backup__'] = get_config(module) - - commands = list() - if any((module.params['lines'], module.params['src'])): - if match != 'none': - config, have_banners = get_running_config(module) - config = NetworkConfig(contents=config, indent=0) - if parents: - config = get_sublevel_config(config, module) - configobjs = candidate.difference(config, match=match, replace=replace) - else: - configobjs = candidate.items - have_banners = {} - diffbanners = diff_banners(want_banners, have_banners) - banners = list() - if diffbanners: - banners.append(diffbanners) - if configobjs or banners: - commands = dumps(configobjs, 'commands') - if ((isinstance(module.params['lines'], list)) and - (isinstance(module.params['lines'][0], dict)) and - set(['prompt', 'answer']).issubset(module.params['lines'][0])): - cmd = {'command': commands, - 'prompt': module.params['lines'][0]['prompt'], - 'answer': module.params['lines'][0]['answer']} - commands = [module.jsonify(cmd)] - else: - if commands: - commands = commands.split('\n') - - if module.params['before']: - commands[:0], before_banners = extract_banners(module.params['before']) - if before_banners: - banners.insert(0, before_banners) - - if module.params['after']: - commands_after, after_banners = extract_banners(module.params['after']) - commands.extend(commands_after) - if after_banners: - banners.insert(len(banners), after_banners) - - if not module.check_mode and module.params['update'] == 'merge': - if commands: - load_config(module, commands) - if banners: - result_banners = load_banners(module, banners) - else: - result_banners = [] - - result['changed'] = True - result['commands'] = commands - result['updates'] = commands if commands else [] - result['banners'] = result_banners - if result['banners']: - result['updates'].extend(result_banners) - - if module.params['save']: - result['changed'] = True - if not module.check_mode: - cmd = {'command': 'copy running-config startup-config', - 'prompt': r'\(y/n\)\s?$', 'answer': 'y'} - run_commands(module, [cmd]) - result['saved'] = True - else: - module.warn('Skipping command `copy running-config startup-config`' - 'due to check_mode. Configuration not copied to ' - 'non-volatile storage') - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/dellemc/os6/plugins/modules/os6_facts.py b/ansible_collections/dellemc/os6/plugins/modules/os6_facts.py deleted file mode 100644 index ce439ad40..000000000 --- a/ansible_collections/dellemc/os6/plugins/modules/os6_facts.py +++ /dev/null @@ -1,478 +0,0 @@ -#!/usr/bin/python -# -# (c) 2020 Peter Sprygada, <psprygada@ansible.com> -# Copyright (c) 2020 Dell Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = """ ---- -module: os6_facts -author: "Abirami N (@abirami-n)" -short_description: Collect facts from devices running Dell EMC OS6 -description: - - Collects a base set of device facts from a remote device that - is running OS6. This module prepends all of the - base network fact keys with C(ansible_net_<fact>). The facts - module will always collect a base set of facts from the device - and can enable or disable collection of additional facts. -extends_documentation_fragment: dellemc.os6.os6 -options: - gather_subset: - description: - - When supplied, this argument will restrict the facts collected - to a given subset. Possible values for this argument include - all, hardware, config, and interfaces. Can specify a list of - values to include a larger subset. Values can also be used - with an initial C(M(!)) to specify that a specific subset should - not be collected. - type: list - default: [ '!config' ] -""" - -EXAMPLES = """ -# Collect all facts from the device -- os6_facts: - gather_subset: all -# Collect only the config and default facts -- os6_facts: - gather_subset: - - config -# Do not collect hardware facts -- os6_facts: - gather_subset: - - "!interfaces" -""" - -RETURN = """ -ansible_net_gather_subset: - description: The list of fact subsets collected from the device. - returned: always. - type: list -# default -ansible_net_model: - description: The model name returned from the device. - returned: always. - type: str -ansible_net_serialnum: - description: The serial number of the remote device. - returned: always. - type: str -ansible_net_version: - description: The operating system version running on the remote device. - returned: always. - type: str -ansible_net_hostname: - description: The configured hostname of the device. - returned: always. - type: str -ansible_net_image: - description: The image file that the device is running. - returned: always - type: str -# hardware -ansible_net_memfree_mb: - description: The available free memory on the remote device in MB. - returned: When hardware is configured. - type: int -ansible_net_memtotal_mb: - description: The total memory on the remote device in MB. - returned: When hardware is configured. - type: int -# config -ansible_net_config: - description: The current active config from the device. - returned: When config is configured. - type: str -# interfaces -ansible_net_interfaces: - description: A hash of all interfaces running on the system. - returned: When interfaces is configured. - type: dict -ansible_net_neighbors: - description: The list of LLDP neighbors from the remote device. - returned: When interfaces is configured. - type: dict -""" -import re - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.dellemc.os6.plugins.module_utils.network.os6 import run_commands -from ansible_collections.dellemc.os6.plugins.module_utils.network.os6 import os6_argument_spec, check_args -from ansible.module_utils.six import iteritems - - -class FactsBase(object): - - COMMANDS = list() - - def __init__(self, module): - self.module = module - self.facts = dict() - self.responses = None - - 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): - - COMMANDS = [ - 'show version', - 'show running-config | include hostname' - ] - - def populate(self): - super(Default, self).populate() - data = self.responses[0] - self.facts['version'] = self.parse_version(data) - self.facts['serialnum'] = self.parse_serialnum(data) - self.facts['model'] = self.parse_model(data) - self.facts['image'] = self.parse_image(data) - hdata = self.responses[1] - self.facts['hostname'] = self.parse_hostname(hdata) - - def parse_version(self, data): - facts = dict() - match = re.search(r'HW Version(.+)\s(\d+)', data) - temp, temp_next = data.split('---- ----------- ----------- -------------- --------------') - for en in temp_next.splitlines(): - if en == '': - continue - match_image = re.search(r'^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)', en) - version = match_image.group(4) - facts["Version"] = list() - fact = dict() - fact['HW Version'] = match.group(2) - fact['SW Version'] = match_image.group(4) - facts["Version"].append(fact) - return facts - - def parse_hostname(self, data): - match = re.search(r'\S+\s(\S+)', data, re.M) - if match: - return match.group(1) - - def parse_model(self, data): - match = re.search(r'System Model ID(.+)\s([-A-Z0-9]*)\n', data, re.M) - if match: - return match.group(2) - - def parse_image(self, data): - match = re.search(r'Image File(.+)\s([A-Z0-9a-z_.]*)\n', data) - if match: - return match.group(2) - - def parse_serialnum(self, data): - match = re.search(r'Serial Number(.+)\s([A-Z0-9]*)\n', data) - if match: - return match.group(2) - - -class Hardware(FactsBase): - - COMMANDS = [ - 'show memory cpu' - ] - - def populate(self): - super(Hardware, self).populate() - data = self.responses[0] - match = re.findall(r'\s(\d+)\s', data) - if match: - self.facts['memtotal_mb'] = int(match[0]) // 1024 - self.facts['memfree_mb'] = int(match[1]) // 1024 - - -class Config(FactsBase): - - COMMANDS = ['show running-config'] - - def populate(self): - super(Config, self).populate() - self.facts['config'] = self.responses[0] - - -class Interfaces(FactsBase): - COMMANDS = [ - 'show interfaces', - 'show interfaces status', - 'show interfaces transceiver properties', - 'show ip int', - 'show lldp', - 'show lldp remote-device all', - 'show version' - ] - - def populate(self): - vlan_info = dict() - super(Interfaces, self).populate() - data = self.responses[0] - interfaces = self.parse_interfaces(data) - desc = self.responses[1] - properties = self.responses[2] - vlan = self.responses[3] - version_info = self.responses[6] - vlan_info = self.parse_vlan(vlan, version_info) - self.facts['interfaces'] = self.populate_interfaces(interfaces, desc, properties) - self.facts['interfaces'].update(vlan_info) - if 'LLDP is not enabled' not in self.responses[4]: - neighbors = self.responses[5] - self.facts['neighbors'] = self.parse_neighbors(neighbors) - - def parse_vlan(self, vlan, version_info): - facts = dict() - if "N11" in version_info: - match = re.search(r'IP Address(.+)\s([0-9.]*)\n', vlan) - mask = re.search(r'Subnet Mask(.+)\s([0-9.]*)\n', vlan) - vlan_id_match = re.search(r'Management VLAN ID(.+)\s(\d+)', vlan) - vlan_id = "Vl" + vlan_id_match.group(2) - if vlan_id not in facts: - facts[vlan_id] = list() - fact = dict() - fact['address'] = match.group(2) - fact['masklen'] = mask.group(2) - facts[vlan_id].append(fact) - else: - vlan_info, vlan_info_next = vlan.split('---------- ----- --------------- --------------- -------') - for en in vlan_info_next.splitlines(): - if en == '': - continue - match = re.search(r'^(\S+)\s+(\S+)\s+(\S+)', en) - intf = match.group(1) - if intf not in facts: - facts[intf] = list() - fact = dict() - matc = re.search(r'^([\w+\s\d]*)\s+(\S+)\s+(\S+)', en) - fact['address'] = matc.group(2) - fact['masklen'] = matc.group(3) - facts[intf].append(fact) - return facts - - def populate_interfaces(self, interfaces, desc, properties): - facts = dict() - for key, value in interfaces.items(): - intf = dict() - intf['description'] = self.parse_description(key, desc) - intf['macaddress'] = self.parse_macaddress(value) - intf['mtu'] = self.parse_mtu(value) - intf['bandwidth'] = self.parse_bandwidth(value) - intf['mediatype'] = self.parse_mediatype(key, properties) - intf['duplex'] = self.parse_duplex(value) - intf['lineprotocol'] = self.parse_lineprotocol(value) - intf['operstatus'] = self.parse_operstatus(value) - intf['type'] = self.parse_type(key, properties) - facts[key] = intf - return facts - - def parse_neighbors(self, neighbors): - facts = dict() - neighbor, neighbor_next = neighbors.split('--------- ------- ------------------- ----------------- -----------------') - for en in neighbor_next.splitlines(): - if en == '': - continue - intf = self.parse_lldp_intf(en.split()[0]) - if intf not in facts: - facts[intf] = list() - fact = dict() - if len(en.split()) > 2: - fact['port'] = self.parse_lldp_port(en.split()[3]) - if (len(en.split()) > 4): - fact['host'] = self.parse_lldp_host(en.split()[4]) - else: - fact['host'] = "Null" - facts[intf].append(fact) - return facts - - def parse_interfaces(self, data): - parsed = dict() - for line in data.split('\n'): - if len(line) == 0: - continue - match = re.match(r'Interface Name(.+)\s([A-Za-z0-9/]*)', line, re.IGNORECASE) - if match: - key = match.group(2) - parsed[key] = line - else: - parsed[key] += '\n%s' % line - return parsed - - def parse_description(self, key, desc): - desc_val, desc_info = "", "" - desc = re.split(r'[-+\s](?:-+\s)[-+\s].*', desc) - for desc_val in desc: - if desc_val: - for en in desc_val.splitlines(): - if key in en: - match = re.search(r'^(\S+)\s+(\S+)', en) - if match.group(2) in ['Full', 'N/A']: - return "Null" - else: - return match.group(2) - - def parse_macaddress(self, data): - match = re.search(r'Burned In MAC Address(.+)\s([A-Z0-9.]*)\n', data) - if match: - return match.group(2) - - def parse_mtu(self, data): - match = re.search(r'MTU Size(.+)\s(\d+)\n', data) - if match: - return int(match.group(2)) - - def parse_bandwidth(self, data): - match = re.search(r'Port Speed\s*[:\s\.]+\s(\d+)\n', data) - if match: - return int(match.group(1)) - - def parse_duplex(self, data): - match = re.search(r'Port Mode\s([A-Za-z]*)(.+)\s([A-Za-z/]*)\n', data) - if match: - return match.group(3) - - def parse_mediatype(self, key, properties): - mediatype, mediatype_next = properties.split('--------- ------- --------------------- --------------------- --------------') - flag = 1 - for en in mediatype_next.splitlines(): - if key in en: - flag = 0 - match = re.search(r'^(\S+)\s+(\S+)\s+(\S+)', en) - if match: - strval = match.group(3) - return strval - if flag == 1: - return "null" - - def parse_type(self, key, properties): - type_val, type_val_next = properties.split('--------- ------- --------------------- --------------------- --------------') - flag = 1 - for en in type_val_next.splitlines(): - if key in en: - flag = 0 - match = re.search(r'^(\S+)\s+(\S+)\s+(\S+)', en) - if match: - strval = match.group(2) - return strval - if flag == 1: - return "null" - - def parse_lineprotocol(self, data): - data = data.splitlines() - for d in data: - match = re.search(r'^Link Status\s*[:\s\.]+\s(\S+)', d) - if match: - return match.group(1) - - def parse_operstatus(self, data): - data = data.splitlines() - for d in data: - match = re.search(r'^Link Status\s*[:\s\.]+\s(\S+)', d) - if match: - return match.group(1) - - def parse_lldp_intf(self, data): - match = re.search(r'^([A-Za-z0-9/]*)', data) - if match: - return match.group(1) - - def parse_lldp_host(self, data): - match = re.search(r'^([A-Za-z0-9-]*)', data) - if match: - return match.group(1) - - def parse_lldp_port(self, data): - match = re.search(r'^([A-Za-z0-9/]*)', data) - if match: - return match.group(1) - - -FACT_SUBSETS = dict( - default=Default, - hardware=Hardware, - interfaces=Interfaces, - config=Config, -) - -VALID_SUBSETS = frozenset(FACT_SUBSETS.keys()) - - -def main(): - """main entry point for module execution - """ - argument_spec = dict( - gather_subset=dict(default=['!config'], type='list') - ) - - argument_spec.update(os6_argument_spec) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - gather_subset = module.params['gather_subset'] - - runable_subsets = set() - exclude_subsets = set() - - for subset in gather_subset: - if subset == 'all': - runable_subsets.update(VALID_SUBSETS) - continue - - if subset.startswith('!'): - subset = subset[1:] - if subset == 'all': - exclude_subsets.update(VALID_SUBSETS) - continue - exclude = True - else: - exclude = False - - if subset not in VALID_SUBSETS: - module.fail_json(msg='Bad subset') - - if exclude: - exclude_subsets.add(subset) - else: - runable_subsets.add(subset) - - if not runable_subsets: - runable_subsets.update(VALID_SUBSETS) - - runable_subsets.difference_update(exclude_subsets) - runable_subsets.add('default') - - facts = dict() - facts['gather_subset'] = list(runable_subsets) - - instances = list() - for key in runable_subsets: - instances.append(FACT_SUBSETS[key](module)) - - for inst in instances: - inst.populate() - facts.update(inst.facts) - - ansible_facts = dict() - for key, value in iteritems(facts): - key = 'ansible_net_%s' % key - ansible_facts[key] = value - - warnings = list() - check_args(module, warnings) - - module.exit_json(ansible_facts=ansible_facts, warnings=warnings) - - -if __name__ == '__main__': - main() diff --git a/ansible_collections/dellemc/os6/plugins/terminal/__init__.py b/ansible_collections/dellemc/os6/plugins/terminal/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/ansible_collections/dellemc/os6/plugins/terminal/__init__.py +++ /dev/null diff --git a/ansible_collections/dellemc/os6/plugins/terminal/os6.py b/ansible_collections/dellemc/os6/plugins/terminal/os6.py deleted file mode 100644 index b11995524..000000000 --- a/ansible_collections/dellemc/os6/plugins/terminal/os6.py +++ /dev/null @@ -1,95 +0,0 @@ -# -# (c) 2020 Red Hat Inc. -# -# (c) 2020 Dell Inc. -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import re -import json - -from ansible.module_utils._text import to_text, to_bytes -from ansible.plugins.terminal import TerminalBase -from ansible.errors import AnsibleConnectionFailure - - -class TerminalModule(TerminalBase): - - terminal_stdout_re = [ - re.compile(br"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), - re.compile(br"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$") - ] - - terminal_stderr_re = [ - re.compile(br"% ?Bad secret"), - re.compile(br"(\bInterface is part of a port-channel\b)"), - re.compile(br"(\bThe maximum number of users have already been created\b)|(\bUse '-' for range\b)"), - re.compile(br"(?:incomplete|ambiguous) command", re.I), - re.compile(br"connection timed out", re.I), - re.compile(br"\bParameter length should be exactly 32 characters\b"), - re.compile(br"'[^']' +returned error code: ?\d+"), - re.compile(br"Invalid|invalid.*$", re.I), - re.compile(br"((\bout of range\b)|(\bnot found\b)|(\bCould not\b)|(\bUnable to\b)|(\bCannot\b)|(\bError\b)).*", re.I), - re.compile(br"((\balready exists\b)|(\bnot exist\b)|(\bnot active\b)|(\bFailed\b)|(\bIncorrect\b)|(\bnot enabled\b)|(\bDeactivate\b)).*", re.I), - - ] - - terminal_initial_prompt = br"\(y/n\)" - - terminal_initial_answer = b"y" - - terminal_inital_prompt_newline = False - - def on_open_shell(self): - try: - if self._get_prompt().endswith(b'#'): - 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 - - cmd = {u'command': u'enable'} - if passwd: - cmd[u'prompt'] = to_text(r"[\r\n]?password:$", errors='surrogate_or_strict') - cmd[u'answer'] = passwd - try: - self._exec_cli_command(to_bytes(json.dumps(cmd), errors='surrogate_or_strict')) - except AnsibleConnectionFailure: - raise AnsibleConnectionFailure('unable to elevate privilege to enable mode') - # in os6 the terminal settings are accepted after the privilege mode - try: - self._exec_cli_command(b'terminal length 0') - except AnsibleConnectionFailure: - raise AnsibleConnectionFailure('unable to set terminal parameters') - - def on_unbecome(self): - prompt = self._get_prompt() - if prompt is None: - # if prompt is None most likely the terminal is hung up at a prompt - return - - if prompt.strip().endswith(b')#'): - self._exec_cli_command(b'end') - self._exec_cli_command(b'disable') - - elif prompt.endswith(b'#'): - self._exec_cli_command(b'disable') |