Adding slx_command module and supporting module_utils. (#38235)

* Adding slx_command module and supporting module_utils.

This commit adds the slx_command module and tests as well as the
required slxos module_utils.

* Update copyright in header

* Adding missing module init

* Cleaning up shebangs/licensing.

* Incorporating feedback

Removing reference to `waitfor` alias in `slxos_command` module.
Adding `Extreme Networks` to `short_description` of `slxos_command` module.

* Adding cliconf tests

* Fixing 3.X tests

* Adding docstrings to test methods for slxos cliconf tests

* Adding slxos terminal tests

* Adding slxos module_utils tests

* Adding Extreme Networks team members to BOTMETA.yml
This commit is contained in:
Matthew Stone 2018-04-11 06:59:34 -05:00 committed by John R Barker
parent 8f6ee2a5ca
commit 5b1a8ee1e8
20 changed files with 2375 additions and 0 deletions

11
.github/BOTMETA.yml vendored
View file

@ -486,6 +486,7 @@ files:
$modules/network/panos/panos_address.py: itdependsnetworks ivanbojer jtschichold $modules/network/panos/panos_address.py: itdependsnetworks ivanbojer jtschichold
$modules/network/protocol/: $team_networking $modules/network/protocol/: $team_networking
$modules/network/routing/: $team_networking $modules/network/routing/: $team_networking
$modules/network/slxos/: $team_extreme
$modules/network/sros/: privateip $modules/network/sros/: privateip
$modules/network/system/: $team_networking $modules/network/system/: $team_networking
$modules/network/vyos/: Qalthos samdoran $modules/network/vyos/: Qalthos samdoran
@ -850,6 +851,9 @@ files:
$module_utils/network/onyx: $module_utils/network/onyx:
maintainers: $team_onyx maintainers: $team_onyx
labels: networking labels: networking
$module_utils/network/slxos:
maintainers: $team_extreme
labels: networking
$module_utils/openstack.py: $module_utils/openstack.py:
maintainers: $team_openstack maintainers: $team_openstack
labels: labels:
@ -953,6 +957,9 @@ files:
lib/ansible/plugins/cliconf/onyx.py: lib/ansible/plugins/cliconf/onyx.py:
maintainers: $team_onyx maintainers: $team_onyx
labels: networking labels: networking
lib/ansible/plugins/cliconf/slxos.py:
maintainers: $team_extreme
labels: networking
lib/ansible/plugins/connection/lxd.py: lib/ansible/plugins/connection/lxd.py:
maintainers: mattclay maintainers: mattclay
lib/ansible/plugins/connection/netconf.py: lib/ansible/plugins/connection/netconf.py:
@ -1043,6 +1050,9 @@ files:
lib/ansible/plugins/terminal/onyx.py: lib/ansible/plugins/terminal/onyx.py:
maintainers: $team_onyx maintainers: $team_onyx
labels: networking labels: networking
lib/ansible/plugins/terminal/slxos.py:
maintainers: $team_extreme
labels: networking
lib/ansible/plugins/terminal/sros.py: lib/ansible/plugins/terminal/sros.py:
maintainers: $team_networking maintainers: $team_networking
labels: networking labels: networking
@ -1121,6 +1131,7 @@ macros:
team_cloudstack: resmo dpassante team_cloudstack: resmo dpassante
team_cumulus: isharacomix jrrivers privateip team_cumulus: isharacomix jrrivers privateip
team_cyberark_conjur: jvanderhoof ryanprior team_cyberark_conjur: jvanderhoof ryanprior
team_extreme: bigmstone LindsayHill
team_ipa: Nosmoht akasurde team_ipa: Nosmoht akasurde
team_manageiq: gtanzillo abellotti zgalor yaacov cben team_manageiq: gtanzillo abellotti zgalor yaacov cben
team_meraki: dagwieers kbreit team_meraki: dagwieers kbreit

View file

@ -0,0 +1,107 @@
#
# (c) 2018 Extreme Networks 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/>.
#
import json
from ansible.module_utils._text import to_text
from ansible.module_utils.network.common.utils import to_list, ComplexList
from ansible.module_utils.connection import Connection
def get_connection(module):
"""Get switch connection
Creates reusable SSH connection to the switch described in a given module.
Args:
module: A valid AnsibleModule instance.
Returns:
An instance of `ansible.module_utils.connection.Connection` with a
connection to the switch described in the provided module.
Raises:
AnsibleConnectionFailure: An error occurred connecting to the device
"""
if hasattr(module, 'slxos_connection'):
return module.slxos_connection
capabilities = get_capabilities(module)
network_api = capabilities.get('network_api')
if network_api == 'cliconf':
module.slxos_connection = Connection(module._socket_path)
else:
module.fail_json(msg='Invalid connection type %s' % network_api)
return module.slxos_connection
def get_capabilities(module):
"""Get switch capabilities
Collects and returns a python object with the switch capabilities.
Args:
module: A valid AnsibleModule instance.
Returns:
A dictionary containing the switch capabilities.
"""
if hasattr(module, 'slxos_capabilities'):
return module.slxos_capabilities
capabilities = Connection(module._socket_path).get_capabilities()
module.slxos_capabilities = json.loads(capabilities)
return module.slxos_capabilities
def run_commands(module, commands):
"""Run command list against connection.
Get new or previously used connection and send commands to it one at a time,
collecting response.
Args:
module: A valid AnsibleModule instance.
commands: Iterable of command strings.
Returns:
A list of output strings.
"""
responses = list()
connection = get_connection(module)
for cmd in to_list(commands):
if isinstance(cmd, dict):
command = cmd['command']
prompt = cmd['prompt']
answer = cmd['answer']
else:
command = cmd
prompt = None
answer = None
out = connection.get(command, prompt, answer)
try:
out = to_text(out, errors='surrogate_or_strict')
except UnicodeError:
module.fail_json(msg=u'Failed to decode output from %s: %s' % (cmd, to_text(out)))
responses.append(out)
return responses

View file

@ -0,0 +1,243 @@
#!/usr/bin/python
#
# (c) 2018 Extreme Networks 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)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = """
---
module: slxos_command
version_added: "2.6"
author: "Lindsay Hill (@LindsayHill)"
short_description: Run commands on remote devices running Extreme Networks SLX-OS
description:
- Sends arbitrary commands to an SLX node 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(slxos_config) to configure SLX-OS devices.
notes:
- Tested against SLX-OS 17s.1.02
- 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). See examples.
options:
commands:
description:
- List of commands to send to the remote SLX-OS 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.
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 retries, the task fails.
See examples.
default: null
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.
required: false
default: all
choices: ['any', 'all']
retries:
description:
- Specifies the number of retries a command should by tried
before it is considered failed. The command is run on the
target device every retry and evaluated against the
I(wait_for) conditions.
required: false
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.
required: false
default: 1
"""
EXAMPLES = """
tasks:
- name: run show version on remote devices
slxos_command:
commands: show version
- name: run show version and check to see if output contains SLX
slxos_command:
commands: show version
wait_for: result[0] contains SLX
- name: run multiple commands on remote nodes
slxos_command:
commands:
- show version
- show interfaces
- name: run multiple commands and evaluate the output
slxos_command:
commands:
- show version
- show interface status
wait_for:
- result[0] contains SLX
- result[1] contains Eth
- name: run command that requires answering a prompt
slxos_command:
commands:
- command: 'clear sessions'
prompt: 'This operation will logout all the user sessions. Do you want to continue (yes/no)?:'
answer: y
"""
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: ['...', '...']
"""
import re
import time
from ansible.module_utils.network.slxos.slxos import run_commands
from ansible.module_utils.basic import AnsibleModule
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
__metaclass__ = type
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 item in list(commands):
configure_type = re.match(r'conf(?:\w*)(?:\s+(\w+))?', item['command'])
if module.check_mode:
if configure_type and configure_type.group(1) not in ('confirm', 'replace', 'revert', 'network'):
module.fail_json(
msg='slxos_command does not support running config mode '
'commands. Please use slxos_config instead'
)
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
def main():
"""main entry point for module execution
"""
argument_spec = dict(
commands=dict(type='list', required=True),
wait_for=dict(type='list'),
match=dict(default='all', choices=['all', 'any']),
retries=dict(default=10, type='int'),
interval=dict(default=1, type='int')
)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
result = {'changed': False}
warnings = list()
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()

View file

@ -0,0 +1,98 @@
#
# (c) 2018 Extreme Networks 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 itertools import chain
from ansible.module_utils._text import to_bytes, to_text
from ansible.module_utils.network.common.utils import to_list
from ansible.plugins.cliconf import CliconfBase
class Cliconf(CliconfBase):
def get_device_info(self):
device_info = {}
device_info['network_os'] = 'slxos'
reply = self.get(b'show version')
data = to_text(reply, errors='surrogate_or_strict').strip()
match = re.search(r'SLX\-OS Operating System Version: (\S+)', data)
if match:
device_info['network_os_version'] = match.group(1)
reply = self.get(b'show chassis')
data = to_text(reply, errors='surrogate_or_strict').strip()
match = re.search(r'^Chassis Name:(\s+)(\S+)', data, re.M)
if match:
device_info['network_os_model'] = match.group(2)
reply = self.get(b'show running-config | inc "switch-attributes host-name')
data = to_text(reply, errors='surrogate_or_strict').strip()
match = re.search(r'switch-attributes host-name (\S+)', data, re.M)
if match:
device_info['network_os_hostname'] = match.group(1)
return device_info
def get_config(self, source='running', 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'
else:
cmd = 'show startup-config'
flags = [] if flags is None else flags
cmd += ' '.join(flags)
cmd = cmd.strip()
return self.send_command(cmd)
def edit_config(self, command):
for cmd in chain(['configure terminal'], to_list(command), ['end']):
if isinstance(cmd, dict):
command = cmd['command']
prompt = cmd['prompt']
answer = cmd['answer']
newline = cmd.get('newline', True)
else:
command = cmd
prompt = None
answer = None
newline = True
self.send_command(command, prompt, answer, False, newline)
def get(self, command, prompt=None, answer=None, sendonly=False):
return self.send_command(command, prompt=prompt, answer=answer, sendonly=sendonly)
def get_capabilities(self):
result = {}
result['rpc'] = self.get_base_rpc()
result['network_api'] = 'cliconf'
result['device_info'] = self.get_device_info()
return json.dumps(result)

View file

@ -0,0 +1,54 @@
#
# (c) 2018 Extreme Networks 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
from ansible.errors import AnsibleConnectionFailure
from ansible.plugins.terminal import TerminalBase
class TerminalModule(TerminalBase):
terminal_stdout_re = [
re.compile(br"([\r\n]|(\x1b\[\?7h))[\w\+\-\.:\/\[\]]+(?:\([^\)]+\)){0,3}(?:[>#]) ?$")
]
terminal_stderr_re = [
re.compile(br"% ?Error"),
# re.compile(br"^% \w+", re.M),
re.compile(br"% ?Bad secret"),
re.compile(br"[\r\n%] Bad passwords"),
re.compile(br"invalid input", re.I),
re.compile(br"(?:incomplete|ambiguous) command", re.I),
re.compile(br"connection timed out", re.I),
re.compile(br"[^\r\n]+ not found"),
re.compile(br"'[^']' +returned error code: ?\d+"),
re.compile(br"Bad mask", re.I),
re.compile(br"% ?(\S+) ?overlaps with ?(\S+)", re.I),
re.compile(br"[%\S] ?Informational: ?[\s]+", re.I),
re.compile(br"syntax error: unknown argument.", re.I)
]
def on_open_shell(self):
try:
self._exec_cli_command(u'terminal length 0')
except AnsibleConnectionFailure:
raise AnsibleConnectionFailure('unable to set terminal parameters')

View file

@ -0,0 +1,131 @@
#
# (c) 2018 Extreme Networks 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
from os import path
import json
from mock import MagicMock, patch, call
from ansible.compat.tests import unittest
from ansible.module_utils.network.slxos import slxos
class TestPluginCLIConfSLXOS(unittest.TestCase):
""" Test class for SLX-OS CLI Conf Methods
"""
def test_get_connection_established(self):
""" Test get_connection with established connection
"""
module = MagicMock()
connection = slxos.get_connection(module)
self.assertEqual(connection, module.slxos_connection)
@patch('ansible.module_utils.network.slxos.slxos.Connection')
def test_get_connection_new(self, connection):
""" Test get_connection with new connection
"""
socket_path = "little red riding hood"
module = MagicMock(spec=[
'fail_json',
])
module._socket_path = socket_path
connection().get_capabilities.return_value = '{"network_api": "cliconf"}'
returned_connection = slxos.get_connection(module)
connection.assert_called_with(socket_path)
self.assertEqual(returned_connection, module.slxos_connection)
@patch('ansible.module_utils.network.slxos.slxos.Connection')
def test_get_connection_incorrect_network_api(self, connection):
""" Test get_connection with incorrect network_api response
"""
socket_path = "little red riding hood"
module = MagicMock(spec=[
'fail_json',
])
module._socket_path = socket_path
module.fail_json.side_effect = TypeError
connection().get_capabilities.return_value = '{"network_api": "nope"}'
with self.assertRaises(TypeError):
slxos.get_connection(module)
@patch('ansible.module_utils.network.slxos.slxos.Connection')
def test_get_capabilities(self, connection):
""" Test get_capabilities
"""
socket_path = "little red riding hood"
module = MagicMock(spec=[
'fail_json',
])
module._socket_path = socket_path
module.fail_json.side_effect = TypeError
capabilities = {'network_api': 'cliconf'}
connection().get_capabilities.return_value = json.dumps(capabilities)
capabilities_returned = slxos.get_capabilities(module)
self.assertEqual(capabilities, capabilities_returned)
@patch('ansible.module_utils.network.slxos.slxos.Connection')
def test_run_commands(self, connection):
""" Test get_capabilities
"""
module = MagicMock()
commands = [
'hello',
'dolly',
'well hello',
'dolly',
'its so nice to have you back',
'where you belong',
]
responses = [
'Dolly, never go away again1',
'Dolly, never go away again2',
'Dolly, never go away again3',
'Dolly, never go away again4',
'Dolly, never go away again5',
'Dolly, never go away again6',
]
module.slxos_connection.get.side_effect = responses
run_command_responses = slxos.run_commands(module, commands)
calls = []
for command in commands:
calls.append(call(
command,
None,
None
))
module.slxos_connection.get.assert_has_calls(calls)
self.assertEqual(responses, run_command_responses)

View file

@ -0,0 +1,18 @@
SLX-OS Operating System Software
SLX-OS Operating System Version: 17s.1.02
Copyright (c) 1995-2018 Brocade Communications Systems, Inc.
Firmware name: 17s.1.02
Build Time: 00:06:59 Sep 28, 2017
Install Time: 15:58:29 Feb 9, 2018
Kernel: 2.6.34.6
Host Version: Ubuntu 14.04 LTS
Host Kernel: Linux 3.14.17
Control Processor: QEMU Virtual CPU version 2.0.0
System Uptime: 34days 4hrs 41mins 53secs
Slot Name Primary/Secondary Versions Status
---------------------------------------------------------------------------
SW/0 SLX-OS 17s.1.02 ACTIVE*
17s.1.02

View file

@ -0,0 +1,87 @@
# (c) 2018 Extreme Networks 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 os
import json
from units.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase
fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
fixture_data = {}
def load_fixture(name):
path = os.path.join(fixture_path, name)
if path in fixture_data:
return fixture_data[path]
with open(path) as file_desc:
data = file_desc.read()
try:
data = json.loads(data)
except:
pass
fixture_data[path] = data
return data
class TestSlxosModule(ModuleTestCase):
def execute_module(self, failed=False, changed=False, commands=None, sort=True, defaults=False):
self.load_fixtures(commands)
if failed:
result = self.failed()
self.assertTrue(result['failed'], result)
else:
result = self.changed(changed)
self.assertEqual(result['changed'], changed, result)
if commands is not None:
if sort:
self.assertEqual(sorted(commands), sorted(result['commands']), result['commands'])
else:
self.assertEqual(commands, result['commands'], result['commands'])
return result
def failed(self):
with self.assertRaises(AnsibleFailJson) as exc:
self.module.main()
result = exc.exception.args[0]
self.assertTrue(result['failed'], result)
return result
def changed(self, changed=False):
with self.assertRaises(AnsibleExitJson) as exc:
self.module.main()
result = exc.exception.args[0]
self.assertEqual(result['changed'], changed, result)
return result
def load_fixtures(self, commands=None):
pass

View file

@ -0,0 +1,121 @@
#
# (c) 2018 Extreme Networks 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 json
from ansible.compat.tests.mock import patch
from ansible.modules.network.slxos import slxos_command
from units.modules.utils import set_module_args
from .slxos_module import TestSlxosModule, load_fixture
class TestSlxosCommandModule(TestSlxosModule):
module = slxos_command
def setUp(self):
super(TestSlxosCommandModule, self).setUp()
self.mock_run_commands = patch('ansible.modules.network.slxos.slxos_command.run_commands')
self.run_commands = self.mock_run_commands.start()
def tearDown(self):
super(TestSlxosCommandModule, self).tearDown()
self.mock_run_commands.stop()
def load_fixtures(self, commands=None):
def load_from_file(*args, **kwargs):
module, commands = args
output = list()
for item in commands:
try:
obj = json.loads(item['command'])
command = obj['command']
except ValueError:
command = item['command']
filename = str(command).replace(' ', '_')
output.append(load_fixture(filename))
return output
self.run_commands.side_effect = load_from_file
def test_slxos_command_simple(self):
set_module_args(dict(commands=['show version']))
result = self.execute_module()
self.assertEqual(len(result['stdout']), 1)
self.assertTrue(result['stdout'][0].startswith('SLX-OS Operating System Software'))
def test_slxos_command_multiple(self):
set_module_args(dict(commands=['show version', 'show version']))
result = self.execute_module()
self.assertEqual(len(result['stdout']), 2)
self.assertTrue(result['stdout'][0].startswith('SLX-OS Operating System Software'))
def test_slxos_command_wait_for(self):
wait_for = 'result[0] contains "SLX-OS Operating System Software"'
set_module_args(dict(commands=['show version'], wait_for=wait_for))
self.execute_module()
def test_slxos_command_wait_for_fails(self):
wait_for = 'result[0] contains "test string"'
set_module_args(dict(commands=['show version'], wait_for=wait_for))
self.execute_module(failed=True)
self.assertEqual(self.run_commands.call_count, 10)
def test_slxos_command_retries(self):
wait_for = 'result[0] contains "test string"'
set_module_args(dict(commands=['show version'], wait_for=wait_for, retries=2))
self.execute_module(failed=True)
self.assertEqual(self.run_commands.call_count, 2)
def test_slxos_command_match_any(self):
wait_for = ['result[0] contains "SLX-OS"',
'result[0] contains "test string"']
set_module_args(dict(commands=['show version'], wait_for=wait_for, match='any'))
self.execute_module()
def test_slxos_command_match_all(self):
wait_for = ['result[0] contains "SLX-OS"',
'result[0] contains "SLX-OS Operating System Software"']
set_module_args(dict(commands=['show version'], wait_for=wait_for, match='all'))
self.execute_module()
def test_slxos_command_match_all_failure(self):
wait_for = ['result[0] contains "SLX-OS Operating System Software"',
'result[0] contains "test string"']
commands = ['show version', 'show version']
set_module_args(dict(commands=commands, wait_for=wait_for, match='all'))
self.execute_module(failed=True)
def test_slxos_command_configure_error(self):
commands = ['configure terminal']
set_module_args({
'commands': commands,
'_ansible_check_mode': True,
})
result = self.execute_module(failed=True)
self.assertEqual(
result['msg'],
'slxos_command does not support running config mode commands. '
'Please use slxos_config instead'
)

View file

View file

@ -0,0 +1,40 @@
Chassis Name: BR-SLX9140
switchType: 3001
FAN Unit: 1
Time Awake: 36 days
FAN Unit: 2
Time Awake: 36 days
FAN Unit: 3
Time Awake: 36 days
FAN Unit: 5
Time Awake: 36 days
FAN Unit: 6
Time Awake: 36 days
POWER SUPPLY Unit: 1
Factory Part Num: 11-1111111-11
Factory Serial Num: ASERIALNUMB
Time Awake: 36 days
POWER SUPPLY Unit: 2
Factory Part Num: 11-1111111-11
Factory Serial Num: ASERIALNUMB
Time Awake: 36 days
CHASSIS/WWN Unit: 1
Power Consume Factor: 0
Factory Part Num: 11-1111111-11
Factory Serial Num: ASERIALNUMB
Manufacture: Day: 12 Month: 1 Year: 2017
Update: Day: 5 Month: 4 Year: 2018
Time Alive: 277 days
Time Awake: 36 days
Airflow direction : Port side INTAKE

View file

@ -0,0 +1,624 @@
root enable
host-table aging-mode conversational
clock timezone Europe/Warsaw
hardware
profile tcam default
profile overlay-visibility default
profile route-table default maximum_paths 8
system-mode default
!
http server use-vrf default-vrf
http server use-vrf mgmt-vrf
node-id 1
!
ntp server 172.16.10.2 use-vrf mgmt-vrf
!
logging raslog console INFO
logging syslog-server 10.1.5.11 use-vrf mgmt-vrf
!
logging auditlog class SECURITY
logging auditlog class CONFIGURATION
logging auditlog class FIRMWARE
logging syslog-facility local LOG_LOCAL0
logging syslog-client localip CHASSIS_IP
switch-attributes chassis-name SLX9140-LEAF2
switch-attributes host-name DC2LEAF2
no support autoupload enable
support ffdc
resource-monitor cpu enable threshold 90 action raslog
resource-monitor memory enable threshold 100 action raslog
resource-monitor process memory enable alarm 1000 critical 1200
system-monitor fan threshold marginal-threshold 1 down-threshold 2
system-monitor fan alert state removed action raslog
system-monitor power threshold marginal-threshold 1 down-threshold 2
system-monitor power alert state removed action raslog
system-monitor temp threshold marginal-threshold 1 down-threshold 2
system-monitor cid-card threshold marginal-threshold 1 down-threshold 2
system-monitor cid-card alert state none action none
system-monitor compact-flash threshold marginal-threshold 1 down-threshold 0
system-monitor MM threshold marginal-threshold 1 down-threshold 0
system-monitor LineCard threshold marginal-threshold 1 down-threshold 2
system-monitor LineCard alert state none action none
system-monitor SFM threshold marginal-threshold 1 down-threshold 2
telemetry server use-vrf mgmt-vrf
transport tcp
port 50051
activate
!
telemetry profile system-utilization default_system_utilization_statistics
interval 60
add total-system-memory
add total-used-memory
add total-free-memory
add cached-memory
add buffers
add user-free-memory
add kernel-free-memory
add total-swap-memory
add total-free-swap-memory
add total-used-swap-memory
add user-process
add system-process
add niced-process
add iowait
add hw-interrupt
add sw-interrupt
add idle-state
add steal-time
add uptime
!
telemetry profile interface default_interface_statistics
interval 30
add out-pkts
add in-pkts
add out-unicast-pkts
add in-unicast-pkts
add out-broadcast-pkts
add in-broadcast-pkts
add out-multicast-pkts
add in-multicast-pkts
add out-pkts-per-second
add in-pkts-per-second
add out-bandwidth
add in-bandwidth
add out-octets
add in-octets
add out-errors
add in-errors
add out-crc-errors
add in-crc-errors
add out-discards
add in-discards
!
line vty
exec-timeout 10
!
threshold-monitor Buffer limit 70
vrf mgmt-vrf
address-family ipv4 unicast
ip route 0.0.0.0/0 172.168.192.1
!
address-family ipv6 unicast
!
!
ssh server key rsa 2048
ssh server key ecdsa 256
ssh server key dsa
ssh server use-vrf default-vrf
ssh server use-vrf mgmt-vrf
telnet server use-vrf default-vrf
telnet server use-vrf mgmt-vrf
role name admin desc Administrator
role name user desc User
aaa authentication login local
aaa accounting exec default start-stop none
aaa accounting commands default start-stop none
service password-encryption
username admin password "AINTNOPARTYLIKEAHOTELPARTYCAUSEAHOTELPARTYDONTSLEEPNOONEWOULDEVERACTUALLYTYPETHISWHYAREYOUHERE\n" encryption-level 7 role admin desc Administrator
cee-map default
precedence 1
priority-group-table 1 weight 40 pfc on
priority-group-table 15.0 pfc off
priority-group-table 15.1 pfc off
priority-group-table 15.2 pfc off
priority-group-table 15.3 pfc off
priority-group-table 15.4 pfc off
priority-group-table 15.5 pfc off
priority-group-table 15.6 pfc off
priority-group-table 15.7 pfc off
priority-group-table 2 weight 60 pfc off
priority-table 2 2 2 1 2 2 2 15.0
remap lossless-priority priority 0
!
mac access-list extended M1
seq 10 permit any any
!
vlan 1
ip igmp snooping startup-query-interval 100
ipv6 mld snooping startup-query-interval 100
!
vlan 100
!
vlan 200
!
vlan 1001
router-interface Ve 1001
description Thomas-Test-Cluster
!
qos map cos-mutation all-zero-map
map cos 0 to cos 0
map cos 1 to cos 0
map cos 2 to cos 0
map cos 3 to cos 0
map cos 4 to cos 0
map cos 5 to cos 0
map cos 6 to cos 0
map cos 7 to cos 0
!
qos map cos-mutation default
map cos 0 to cos 0
map cos 1 to cos 1
map cos 2 to cos 2
map cos 3 to cos 3
map cos 4 to cos 4
map cos 5 to cos 5
map cos 6 to cos 6
map cos 7 to cos 7
!
qos map cos-traffic-class all-zero-map
map cos 0 to traffic-class 0
map cos 1 to traffic-class 0
map cos 2 to traffic-class 0
map cos 3 to traffic-class 0
map cos 4 to traffic-class 0
map cos 5 to traffic-class 0
map cos 6 to traffic-class 0
map cos 7 to traffic-class 0
!
qos map cos-traffic-class default
map cos 0 to traffic-class 1
map cos 1 to traffic-class 0
map cos 2 to traffic-class 2
map cos 3 to traffic-class 3
map cos 4 to traffic-class 4
map cos 5 to traffic-class 5
map cos 6 to traffic-class 6
map cos 7 to traffic-class 7
!
qos map cos-dscp all-zero-map
map cos 0 to dscp 0
map cos 1 to dscp 0
map cos 2 to dscp 0
map cos 3 to dscp 0
map cos 4 to dscp 0
map cos 5 to dscp 0
map cos 6 to dscp 0
map cos 7 to dscp 0
!
qos map cos-dscp default
map cos 0 to dscp 0
map cos 1 to dscp 8
map cos 2 to dscp 16
map cos 3 to dscp 24
map cos 4 to dscp 32
map cos 5 to dscp 40
map cos 6 to dscp 48
map cos 7 to dscp 56
!
qos map traffic-class-cos all-zero-map
map traffic-class 0 to cos 0
map traffic-class 1 to cos 0
map traffic-class 2 to cos 0
map traffic-class 3 to cos 0
map traffic-class 4 to cos 0
map traffic-class 5 to cos 0
map traffic-class 6 to cos 0
map traffic-class 7 to cos 0
!
qos map traffic-class-cos default
map traffic-class 0 to cos 0
map traffic-class 1 to cos 1
map traffic-class 2 to cos 2
map traffic-class 3 to cos 3
map traffic-class 4 to cos 4
map traffic-class 5 to cos 5
map traffic-class 6 to cos 6
map traffic-class 7 to cos 7
!
qos map traffic-class-mutation all-zero-map
map traffic-class 0 to traffic-class 0
map traffic-class 1 to traffic-class 0
map traffic-class 2 to traffic-class 0
map traffic-class 3 to traffic-class 0
map traffic-class 4 to traffic-class 0
map traffic-class 5 to traffic-class 0
map traffic-class 6 to traffic-class 0
map traffic-class 7 to traffic-class 0
!
qos map traffic-class-mutation default
map traffic-class 0 to traffic-class 0
map traffic-class 1 to traffic-class 1
map traffic-class 2 to traffic-class 2
map traffic-class 3 to traffic-class 3
map traffic-class 4 to traffic-class 4
map traffic-class 5 to traffic-class 5
map traffic-class 6 to traffic-class 6
map traffic-class 7 to traffic-class 7
!
qos map traffic-class-dscp all-zero-map
map traffic-class 0 to dscp 0
map traffic-class 1 to dscp 0
map traffic-class 2 to dscp 0
map traffic-class 3 to dscp 0
map traffic-class 4 to dscp 0
map traffic-class 5 to dscp 0
map traffic-class 6 to dscp 0
map traffic-class 7 to dscp 0
!
qos map traffic-class-dscp default
map traffic-class 0 to dscp 0
map traffic-class 1 to dscp 8
map traffic-class 2 to dscp 16
map traffic-class 3 to dscp 24
map traffic-class 4 to dscp 32
map traffic-class 5 to dscp 40
map traffic-class 6 to dscp 48
map traffic-class 7 to dscp 56
!
qos map dscp-mutation all-zero-map
map dscp 0-63 to dscp 0
!
qos map dscp-mutation default
map dscp 0 to dscp 0
map dscp 1 to dscp 1
map dscp 10 to dscp 10
map dscp 11 to dscp 11
map dscp 12 to dscp 12
map dscp 13 to dscp 13
map dscp 14 to dscp 14
map dscp 15 to dscp 15
map dscp 16 to dscp 16
map dscp 17 to dscp 17
map dscp 18 to dscp 18
map dscp 19 to dscp 19
map dscp 2 to dscp 2
map dscp 20 to dscp 20
map dscp 21 to dscp 21
map dscp 22 to dscp 22
map dscp 23 to dscp 23
map dscp 24 to dscp 24
map dscp 25 to dscp 25
map dscp 26 to dscp 26
map dscp 27 to dscp 27
map dscp 28 to dscp 28
map dscp 29 to dscp 29
map dscp 3 to dscp 3
map dscp 30 to dscp 30
map dscp 31 to dscp 31
map dscp 32 to dscp 32
map dscp 33 to dscp 33
map dscp 34 to dscp 34
map dscp 35 to dscp 35
map dscp 36 to dscp 36
map dscp 37 to dscp 37
map dscp 38 to dscp 38
map dscp 39 to dscp 39
map dscp 4 to dscp 4
map dscp 40 to dscp 40
map dscp 41 to dscp 41
map dscp 42 to dscp 42
map dscp 43 to dscp 43
map dscp 44 to dscp 44
map dscp 45 to dscp 45
map dscp 46 to dscp 46
map dscp 47 to dscp 47
map dscp 48 to dscp 48
map dscp 49 to dscp 49
map dscp 5 to dscp 5
map dscp 50 to dscp 50
map dscp 51 to dscp 51
map dscp 52 to dscp 52
map dscp 53 to dscp 53
map dscp 54 to dscp 54
map dscp 55 to dscp 55
map dscp 56 to dscp 56
map dscp 57 to dscp 57
map dscp 58 to dscp 58
map dscp 59 to dscp 59
map dscp 6 to dscp 6
map dscp 60 to dscp 60
map dscp 61 to dscp 61
map dscp 62 to dscp 62
map dscp 63 to dscp 63
map dscp 7 to dscp 7
map dscp 8 to dscp 8
map dscp 9 to dscp 9
!
qos map dscp-traffic-class all-zero-map
map dscp 0-63 to traffic-class 0
!
qos map dscp-traffic-class default
map dscp 0-7 to traffic-class 0
map dscp 16-23 to traffic-class 2
map dscp 24-31 to traffic-class 3
map dscp 32-39 to traffic-class 4
map dscp 40-47 to traffic-class 5
map dscp 48-55 to traffic-class 6
map dscp 56-63 to traffic-class 7
map dscp 8-15 to traffic-class 1
!
qos map dscp-cos all-zero-map
map dscp 0-63 to cos 0
!
qos map dscp-cos default
map dscp 0-7 to cos 0
map dscp 16-23 to cos 2
map dscp 24-31 to cos 3
map dscp 32-39 to cos 4
map dscp 40-47 to cos 5
map dscp 48-55 to cos 6
map dscp 56-63 to cos 7
map dscp 8-15 to cos 1
!
protocol lldp
advertise optional-tlv management-address
system-description Brocade BR-SLX9140 Router
!
vlan dot1q tag native
police-remark-profile default
!
class-map BD-100
!
class-map C1
match access-group M1
!
class-map cee
!
class-map default
!
policy-map P1
class C1
police cir 1000000
!
!
policy-map P2
class default
police cir 12121212
!
!
no protocol vrrp
no protocol vrrp-extended
router bgp
local-as 65301
capability as4-enable
bfd interval 300 min-rx 300 multiplier 3
neighbor leaf_group peer-group
neighbor leaf_group remote-as 65500
neighbor leaf_group bfd
neighbor 10.220.4.3 remote-as 65500
neighbor 10.220.4.3 peer-group leaf_group
address-family ipv4 unicast
network 172.32.252.5/32
maximum-paths 8
!
address-family ipv6 unicast
!
address-family l2vpn evpn
!
!
interface Loopback 1
ip address 172.16.128.6/32
no shutdown
!
interface Loopback 2
ip address 172.16.129.5/32
no shutdown
!
interface Management 0
no tcp burstrate
no shutdown
vrf forwarding mgmt-vrf
ip address dhcp
!
interface Ethernet 0/1
speed 25000
fec mode disabled
switchport
switchport mode access
switchport access vlan 1
no shutdown
!
interface Ethernet 0/2
no shutdown
!
interface Ethernet 0/3
speed 25000
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/4
shutdown
!
interface Ethernet 0/5
service-policy in P1
no shutdown
!
interface Ethernet 0/6
mtu 1548
description L2 Interface
no shutdown
!
interface Ethernet 0/7
mtu 1548
description L2 Interface
no shutdown
!
interface Ethernet 0/8
switchport
switchport mode trunk
switchport trunk allowed vlan add 100,200
switchport trunk tag native-vlan
shutdown
!
interface Ethernet 0/9
shutdown
!
interface Ethernet 0/10
no shutdown
!
interface Ethernet 0/11
no shutdown
!
interface Ethernet 0/12
no shutdown
!
interface Ethernet 0/13
no shutdown
!
interface Ethernet 0/14
no shutdown
!
interface Ethernet 0/15
shutdown
!
interface Ethernet 0/16
shutdown
!
interface Ethernet 0/17
shutdown
!
interface Ethernet 0/18
shutdown
!
interface Ethernet 0/19
shutdown
!
interface Ethernet 0/20
shutdown
!
interface Ethernet 0/21
shutdown
!
interface Ethernet 0/22
shutdown
!
interface Ethernet 0/23
shutdown
!
interface Ethernet 0/24
shutdown
!
interface Ethernet 0/25
shutdown
!
interface Ethernet 0/26
shutdown
!
interface Ethernet 0/27
shutdown
!
interface Ethernet 0/28
shutdown
!
interface Ethernet 0/29
shutdown
!
interface Ethernet 0/30
shutdown
!
interface Ethernet 0/31
shutdown
!
interface Ethernet 0/32
shutdown
!
interface Ethernet 0/33
shutdown
!
interface Ethernet 0/34
shutdown
!
interface Ethernet 0/35
shutdown
!
interface Ethernet 0/36
shutdown
!
interface Ethernet 0/37
shutdown
!
interface Ethernet 0/38
shutdown
!
interface Ethernet 0/39
shutdown
!
interface Ethernet 0/40
shutdown
!
interface Ethernet 0/41
shutdown
!
interface Ethernet 0/42
shutdown
!
interface Ethernet 0/43
shutdown
!
interface Ethernet 0/44
shutdown
!
interface Ethernet 0/45
shutdown
!
interface Ethernet 0/46
shutdown
!
interface Ethernet 0/47
shutdown
!
interface Ethernet 0/48
shutdown
!
interface Ethernet 0/49
shutdown
!
interface Ethernet 0/50
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/51
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/52
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/53
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/54
fec mode disabled
no shutdown
!
interface Port-channel 200
switchport
switchport mode access
switchport access vlan 200
shutdown
!
interface Port-channel 1024
insight enable
no shutdown
!
monitor session 1
source ethernet 0/1 destination port-channel 1024 direction both
!
monitor session 2
!
bridge-domain 100 p2mp
!
cluster MCT1 1
!

View file

@ -0,0 +1,624 @@
root enable
host-table aging-mode conversational
clock timezone Europe/Warsaw
hardware
profile tcam default
profile overlay-visibility default
profile route-table default maximum_paths 8
system-mode default
!
http server use-vrf default-vrf
http server use-vrf mgmt-vrf
node-id 1
!
ntp server 172.16.10.2 use-vrf mgmt-vrf
!
logging raslog console INFO
logging syslog-server 10.1.5.11 use-vrf mgmt-vrf
!
logging auditlog class SECURITY
logging auditlog class CONFIGURATION
logging auditlog class FIRMWARE
logging syslog-facility local LOG_LOCAL0
logging syslog-client localip CHASSIS_IP
switch-attributes chassis-name SLX9140-LEAF2
switch-attributes host-name DC2LEAF2
no support autoupload enable
support ffdc
resource-monitor cpu enable threshold 90 action raslog
resource-monitor memory enable threshold 100 action raslog
resource-monitor process memory enable alarm 1000 critical 1200
system-monitor fan threshold marginal-threshold 1 down-threshold 2
system-monitor fan alert state removed action raslog
system-monitor power threshold marginal-threshold 1 down-threshold 2
system-monitor power alert state removed action raslog
system-monitor temp threshold marginal-threshold 1 down-threshold 2
system-monitor cid-card threshold marginal-threshold 1 down-threshold 2
system-monitor cid-card alert state none action none
system-monitor compact-flash threshold marginal-threshold 1 down-threshold 0
system-monitor MM threshold marginal-threshold 1 down-threshold 0
system-monitor LineCard threshold marginal-threshold 1 down-threshold 2
system-monitor LineCard alert state none action none
system-monitor SFM threshold marginal-threshold 1 down-threshold 2
telemetry server use-vrf mgmt-vrf
transport tcp
port 50051
activate
!
telemetry profile system-utilization default_system_utilization_statistics
interval 60
add total-system-memory
add total-used-memory
add total-free-memory
add cached-memory
add buffers
add user-free-memory
add kernel-free-memory
add total-swap-memory
add total-free-swap-memory
add total-used-swap-memory
add user-process
add system-process
add niced-process
add iowait
add hw-interrupt
add sw-interrupt
add idle-state
add steal-time
add uptime
!
telemetry profile interface default_interface_statistics
interval 30
add out-pkts
add in-pkts
add out-unicast-pkts
add in-unicast-pkts
add out-broadcast-pkts
add in-broadcast-pkts
add out-multicast-pkts
add in-multicast-pkts
add out-pkts-per-second
add in-pkts-per-second
add out-bandwidth
add in-bandwidth
add out-octets
add in-octets
add out-errors
add in-errors
add out-crc-errors
add in-crc-errors
add out-discards
add in-discards
!
line vty
exec-timeout 10
!
threshold-monitor Buffer limit 70
vrf mgmt-vrf
address-family ipv4 unicast
ip route 0.0.0.0/0 172.168.192.1
!
address-family ipv6 unicast
!
!
ssh server key rsa 2048
ssh server key ecdsa 256
ssh server key dsa
ssh server use-vrf default-vrf
ssh server use-vrf mgmt-vrf
telnet server use-vrf default-vrf
telnet server use-vrf mgmt-vrf
role name admin desc Administrator
role name user desc User
aaa authentication login local
aaa accounting exec default start-stop none
aaa accounting commands default start-stop none
service password-encryption
username admin password "AINTNOPARTYLIKEAHOTELPARTYCAUSEAHOTELPARTYDONTSLEEPNOONEWOULDEVERACTUALLYTYPETHISWHYAREYOUHERE\n" encryption-level 7 role admin desc Administrator
cee-map default
precedence 1
priority-group-table 1 weight 40 pfc on
priority-group-table 15.0 pfc off
priority-group-table 15.1 pfc off
priority-group-table 15.2 pfc off
priority-group-table 15.3 pfc off
priority-group-table 15.4 pfc off
priority-group-table 15.5 pfc off
priority-group-table 15.6 pfc off
priority-group-table 15.7 pfc off
priority-group-table 2 weight 60 pfc off
priority-table 2 2 2 1 2 2 2 15.0
remap lossless-priority priority 0
!
mac access-list extended M1
seq 10 permit any any
!
vlan 1
ip igmp snooping startup-query-interval 100
ipv6 mld snooping startup-query-interval 100
!
vlan 100
!
vlan 200
!
vlan 1001
router-interface Ve 1001
description Thomas-Test-Cluster
!
qos map cos-mutation all-zero-map
map cos 0 to cos 0
map cos 1 to cos 0
map cos 2 to cos 0
map cos 3 to cos 0
map cos 4 to cos 0
map cos 5 to cos 0
map cos 6 to cos 0
map cos 7 to cos 0
!
qos map cos-mutation default
map cos 0 to cos 0
map cos 1 to cos 1
map cos 2 to cos 2
map cos 3 to cos 3
map cos 4 to cos 4
map cos 5 to cos 5
map cos 6 to cos 6
map cos 7 to cos 7
!
qos map cos-traffic-class all-zero-map
map cos 0 to traffic-class 0
map cos 1 to traffic-class 0
map cos 2 to traffic-class 0
map cos 3 to traffic-class 0
map cos 4 to traffic-class 0
map cos 5 to traffic-class 0
map cos 6 to traffic-class 0
map cos 7 to traffic-class 0
!
qos map cos-traffic-class default
map cos 0 to traffic-class 1
map cos 1 to traffic-class 0
map cos 2 to traffic-class 2
map cos 3 to traffic-class 3
map cos 4 to traffic-class 4
map cos 5 to traffic-class 5
map cos 6 to traffic-class 6
map cos 7 to traffic-class 7
!
qos map cos-dscp all-zero-map
map cos 0 to dscp 0
map cos 1 to dscp 0
map cos 2 to dscp 0
map cos 3 to dscp 0
map cos 4 to dscp 0
map cos 5 to dscp 0
map cos 6 to dscp 0
map cos 7 to dscp 0
!
qos map cos-dscp default
map cos 0 to dscp 0
map cos 1 to dscp 8
map cos 2 to dscp 16
map cos 3 to dscp 24
map cos 4 to dscp 32
map cos 5 to dscp 40
map cos 6 to dscp 48
map cos 7 to dscp 56
!
qos map traffic-class-cos all-zero-map
map traffic-class 0 to cos 0
map traffic-class 1 to cos 0
map traffic-class 2 to cos 0
map traffic-class 3 to cos 0
map traffic-class 4 to cos 0
map traffic-class 5 to cos 0
map traffic-class 6 to cos 0
map traffic-class 7 to cos 0
!
qos map traffic-class-cos default
map traffic-class 0 to cos 0
map traffic-class 1 to cos 1
map traffic-class 2 to cos 2
map traffic-class 3 to cos 3
map traffic-class 4 to cos 4
map traffic-class 5 to cos 5
map traffic-class 6 to cos 6
map traffic-class 7 to cos 7
!
qos map traffic-class-mutation all-zero-map
map traffic-class 0 to traffic-class 0
map traffic-class 1 to traffic-class 0
map traffic-class 2 to traffic-class 0
map traffic-class 3 to traffic-class 0
map traffic-class 4 to traffic-class 0
map traffic-class 5 to traffic-class 0
map traffic-class 6 to traffic-class 0
map traffic-class 7 to traffic-class 0
!
qos map traffic-class-mutation default
map traffic-class 0 to traffic-class 0
map traffic-class 1 to traffic-class 1
map traffic-class 2 to traffic-class 2
map traffic-class 3 to traffic-class 3
map traffic-class 4 to traffic-class 4
map traffic-class 5 to traffic-class 5
map traffic-class 6 to traffic-class 6
map traffic-class 7 to traffic-class 7
!
qos map traffic-class-dscp all-zero-map
map traffic-class 0 to dscp 0
map traffic-class 1 to dscp 0
map traffic-class 2 to dscp 0
map traffic-class 3 to dscp 0
map traffic-class 4 to dscp 0
map traffic-class 5 to dscp 0
map traffic-class 6 to dscp 0
map traffic-class 7 to dscp 0
!
qos map traffic-class-dscp default
map traffic-class 0 to dscp 0
map traffic-class 1 to dscp 8
map traffic-class 2 to dscp 16
map traffic-class 3 to dscp 24
map traffic-class 4 to dscp 32
map traffic-class 5 to dscp 40
map traffic-class 6 to dscp 48
map traffic-class 7 to dscp 56
!
qos map dscp-mutation all-zero-map
map dscp 0-63 to dscp 0
!
qos map dscp-mutation default
map dscp 0 to dscp 0
map dscp 1 to dscp 1
map dscp 10 to dscp 10
map dscp 11 to dscp 11
map dscp 12 to dscp 12
map dscp 13 to dscp 13
map dscp 14 to dscp 14
map dscp 15 to dscp 15
map dscp 16 to dscp 16
map dscp 17 to dscp 17
map dscp 18 to dscp 18
map dscp 19 to dscp 19
map dscp 2 to dscp 2
map dscp 20 to dscp 20
map dscp 21 to dscp 21
map dscp 22 to dscp 22
map dscp 23 to dscp 23
map dscp 24 to dscp 24
map dscp 25 to dscp 25
map dscp 26 to dscp 26
map dscp 27 to dscp 27
map dscp 28 to dscp 28
map dscp 29 to dscp 29
map dscp 3 to dscp 3
map dscp 30 to dscp 30
map dscp 31 to dscp 31
map dscp 32 to dscp 32
map dscp 33 to dscp 33
map dscp 34 to dscp 34
map dscp 35 to dscp 35
map dscp 36 to dscp 36
map dscp 37 to dscp 37
map dscp 38 to dscp 38
map dscp 39 to dscp 39
map dscp 4 to dscp 4
map dscp 40 to dscp 40
map dscp 41 to dscp 41
map dscp 42 to dscp 42
map dscp 43 to dscp 43
map dscp 44 to dscp 44
map dscp 45 to dscp 45
map dscp 46 to dscp 46
map dscp 47 to dscp 47
map dscp 48 to dscp 48
map dscp 49 to dscp 49
map dscp 5 to dscp 5
map dscp 50 to dscp 50
map dscp 51 to dscp 51
map dscp 52 to dscp 52
map dscp 53 to dscp 53
map dscp 54 to dscp 54
map dscp 55 to dscp 55
map dscp 56 to dscp 56
map dscp 57 to dscp 57
map dscp 58 to dscp 58
map dscp 59 to dscp 59
map dscp 6 to dscp 6
map dscp 60 to dscp 60
map dscp 61 to dscp 61
map dscp 62 to dscp 62
map dscp 63 to dscp 63
map dscp 7 to dscp 7
map dscp 8 to dscp 8
map dscp 9 to dscp 9
!
qos map dscp-traffic-class all-zero-map
map dscp 0-63 to traffic-class 0
!
qos map dscp-traffic-class default
map dscp 0-7 to traffic-class 0
map dscp 16-23 to traffic-class 2
map dscp 24-31 to traffic-class 3
map dscp 32-39 to traffic-class 4
map dscp 40-47 to traffic-class 5
map dscp 48-55 to traffic-class 6
map dscp 56-63 to traffic-class 7
map dscp 8-15 to traffic-class 1
!
qos map dscp-cos all-zero-map
map dscp 0-63 to cos 0
!
qos map dscp-cos default
map dscp 0-7 to cos 0
map dscp 16-23 to cos 2
map dscp 24-31 to cos 3
map dscp 32-39 to cos 4
map dscp 40-47 to cos 5
map dscp 48-55 to cos 6
map dscp 56-63 to cos 7
map dscp 8-15 to cos 1
!
protocol lldp
advertise optional-tlv management-address
system-description Brocade BR-SLX9140 Router
!
vlan dot1q tag native
police-remark-profile default
!
class-map BD-100
!
class-map C1
match access-group M1
!
class-map cee
!
class-map default
!
policy-map P1
class C1
police cir 1000000
!
!
policy-map P2
class default
police cir 12121212
!
!
no protocol vrrp
no protocol vrrp-extended
router bgp
local-as 65301
capability as4-enable
bfd interval 300 min-rx 300 multiplier 3
neighbor leaf_group peer-group
neighbor leaf_group remote-as 65500
neighbor leaf_group bfd
neighbor 10.220.4.3 remote-as 65500
neighbor 10.220.4.3 peer-group leaf_group
address-family ipv4 unicast
network 172.32.252.5/32
maximum-paths 8
!
address-family ipv6 unicast
!
address-family l2vpn evpn
!
!
interface Loopback 1
ip address 172.16.128.6/32
no shutdown
!
interface Loopback 2
ip address 172.16.129.5/32
no shutdown
!
interface Management 0
no tcp burstrate
no shutdown
vrf forwarding mgmt-vrf
ip address dhcp
!
interface Ethernet 0/1
speed 25000
fec mode disabled
switchport
switchport mode access
switchport access vlan 1
no shutdown
!
interface Ethernet 0/2
no shutdown
!
interface Ethernet 0/3
speed 25000
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/4
shutdown
!
interface Ethernet 0/5
service-policy in P1
no shutdown
!
interface Ethernet 0/6
mtu 1548
description L2 Interface
no shutdown
!
interface Ethernet 0/7
mtu 1548
description L2 Interface
no shutdown
!
interface Ethernet 0/8
switchport
switchport mode trunk
switchport trunk allowed vlan add 100,200
switchport trunk tag native-vlan
shutdown
!
interface Ethernet 0/9
shutdown
!
interface Ethernet 0/10
no shutdown
!
interface Ethernet 0/11
no shutdown
!
interface Ethernet 0/12
no shutdown
!
interface Ethernet 0/13
no shutdown
!
interface Ethernet 0/14
no shutdown
!
interface Ethernet 0/15
shutdown
!
interface Ethernet 0/16
shutdown
!
interface Ethernet 0/17
shutdown
!
interface Ethernet 0/18
shutdown
!
interface Ethernet 0/19
shutdown
!
interface Ethernet 0/20
shutdown
!
interface Ethernet 0/21
shutdown
!
interface Ethernet 0/22
shutdown
!
interface Ethernet 0/23
shutdown
!
interface Ethernet 0/24
shutdown
!
interface Ethernet 0/25
shutdown
!
interface Ethernet 0/26
shutdown
!
interface Ethernet 0/27
shutdown
!
interface Ethernet 0/28
shutdown
!
interface Ethernet 0/29
shutdown
!
interface Ethernet 0/30
shutdown
!
interface Ethernet 0/31
shutdown
!
interface Ethernet 0/32
shutdown
!
interface Ethernet 0/33
shutdown
!
interface Ethernet 0/34
shutdown
!
interface Ethernet 0/35
shutdown
!
interface Ethernet 0/36
shutdown
!
interface Ethernet 0/37
shutdown
!
interface Ethernet 0/38
shutdown
!
interface Ethernet 0/39
shutdown
!
interface Ethernet 0/40
shutdown
!
interface Ethernet 0/41
shutdown
!
interface Ethernet 0/42
shutdown
!
interface Ethernet 0/43
shutdown
!
interface Ethernet 0/44
shutdown
!
interface Ethernet 0/45
shutdown
!
interface Ethernet 0/46
shutdown
!
interface Ethernet 0/47
shutdown
!
interface Ethernet 0/48
shutdown
!
interface Ethernet 0/49
shutdown
!
interface Ethernet 0/50
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/51
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/52
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/53
fec mode RS-FEC
no shutdown
!
interface Ethernet 0/54
fec mode disabled
no shutdown
!
interface Port-channel 200
switchport
switchport mode access
switchport access vlan 200
shutdown
!
interface Port-channel 1024
insight enable
no shutdown
!
monitor session 1
source ethernet 0/1 destination port-channel 1024 direction both
!
monitor session 2
!
bridge-domain 100 p2mp
!
cluster MCT1 1
!

View file

@ -0,0 +1,18 @@
SLX-OS Operating System Software
SLX-OS Operating System Version: 17s.1.02
Copyright (c) 1995-2018 Brocade Communications Systems, Inc.
Firmware name: 17s.1.02
Build Time: 00:06:59 Sep 28, 2017
Install Time: 15:58:29 Feb 9, 2018
Kernel: 2.6.34.6
Host Version: Ubuntu 14.04 LTS
Host Kernel: Linux 3.14.17
Control Processor: QEMU Virtual CPU version 2.0.0
System Uptime: 34days 4hrs 41mins 53secs
Slot Name Primary/Secondary Versions Status
---------------------------------------------------------------------------
SW/0 SLX-OS 17s.1.02 ACTIVE*
17s.1.02

View file

@ -0,0 +1,140 @@
#
# (c) 2018 Extreme Networks 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
from os import path
import json
from mock import MagicMock, call
from ansible.compat.tests import unittest
from ansible.plugins.cliconf import slxos
FIXTURE_DIR = b'%s/fixtures/slxos' % (
path.dirname(path.abspath(__file__)).encode('utf-8')
)
def _connection_side_effect(*args, **kwargs):
try:
if args:
value = args[0]
else:
value = kwargs.get('command')
fixture_path = path.abspath(
b'%s/%s' % (FIXTURE_DIR, b'_'.join(value.split(b' ')))
)
with open(fixture_path, 'rb') as file_desc:
return file_desc.read()
except (OSError, IOError):
if args:
value = args[0]
return value
elif kwargs.get('command'):
value = kwargs.get('command')
return value
return 'Nope'
class TestPluginCLIConfSLXOS(unittest.TestCase):
""" Test class for SLX-OS CLI Conf Methods
"""
def setUp(self):
self._mock_connection = MagicMock()
self._mock_connection.send.side_effect = _connection_side_effect
self._cliconf = slxos.Cliconf(self._mock_connection)
def tearDown(self):
pass
def test_get_device_info(self):
""" Test get_device_info
"""
device_info = self._cliconf.get_device_info()
mock_device_info = {
'network_os': 'slxos',
'network_os_model': 'BR-SLX9140',
'network_os_version': '17s.1.02',
}
self.assertEqual(device_info, mock_device_info)
def test_get_config(self):
""" Test get_config
"""
running_config = self._cliconf.get_config()
fixture_path = path.abspath(b'%s/show_running-config' % FIXTURE_DIR)
with open(fixture_path, 'rb') as file_desc:
mock_running_config = file_desc.read()
self.assertEqual(running_config, mock_running_config)
startup_config = self._cliconf.get_config()
fixture_path = path.abspath(b'%s/show_running-config' % FIXTURE_DIR)
with open(fixture_path, 'rb') as file_desc:
mock_startup_config = file_desc.read()
self.assertEqual(startup_config, mock_startup_config)
def test_edit_config(self):
""" Test edit_config
"""
test_config_command = b'this\nis\nthe\nsong\nthat\nnever\nends'
self._cliconf.edit_config(test_config_command)
send_calls = []
for command in [b'configure terminal', test_config_command, b'end']:
send_calls.append(call(
command=command,
prompt_retry_check=False,
sendonly=False,
newline=True
))
self._mock_connection.send.assert_has_calls(send_calls)
def test_get_capabilities(self):
""" Test get_capabilities
"""
capabilities = json.loads(self._cliconf.get_capabilities())
mock_capabilities = {
'network_api': 'cliconf',
'rpc': [
'get_config',
'edit_config',
'get_capabilities',
'get'
],
'device_info': {
'network_os_model': 'BR-SLX9140',
'network_os_version': '17s.1.02',
'network_os': 'slxos'
}
}
self.assertEqual(
mock_capabilities,
capabilities
)

View file

View file

@ -0,0 +1,59 @@
#
# (c) 2018 Extreme Networks 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
from os import path
import json
from mock import MagicMock
from ansible.compat.tests import unittest
from ansible.plugins.terminal import slxos
from ansible.errors import AnsibleConnectionFailure
class TestPluginTerminalSLXOS(unittest.TestCase):
""" Test class for SLX-OS Terminal Module
"""
def setUp(self):
self._mock_connection = MagicMock()
self._terminal = slxos.TerminalModule(self._mock_connection)
def tearDown(self):
pass
def test_on_open_shell(self):
""" Test on_open_shell
"""
self._mock_connection.exec_command.side_effect = [
b'Looking out my window I see a brick building, and people. Cool.',
]
self._terminal.on_open_shell()
self._mock_connection.exec_command.assert_called_with(u'terminal length 0')
def test_on_open_shell_error(self):
""" Test on_open_shell with error
"""
self._mock_connection.exec_command.side_effect = [
AnsibleConnectionFailure
]
with self.assertRaises(AnsibleConnectionFailure):
self._terminal.on_open_shell()