1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Modifying cnos-facts, cnos_command and cnos-config in line with the design followed in Ansible. Adding unit test cases for these modules. Added plugins to support them. (#39955)

* Modifying cnos-facts, cnos_command and cnos-config in line with the design followed in Ansible. Adding unit test cases for these modules. Added plugins to support them.

* Removing doc fragment conflicts with other modules

* Replacing show with display
This commit is contained in:
Anil Kumar Muraleedharan 2018-05-17 19:36:24 +05:30 committed by Nathaniel Case
parent 30f992f260
commit 1cb4619c9a
27 changed files with 3395 additions and 216 deletions

View file

@ -41,6 +41,149 @@ try:
except: except:
HAS_LIB = False HAS_LIB = False
from distutils.cmd import Command from distutils.cmd import Command
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import env_fallback, return_values
from ansible.module_utils.network.common.utils import to_list, EntityCollection
from ansible.module_utils.connection import Connection, exec_command
from ansible.module_utils.connection import ConnectionError
_DEVICE_CONFIGS = {}
_CONNECTION = None
cnos_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'),
'context': dict(),
'passwords': dict()
}
cnos_argument_spec = {
'provider': dict(type='dict', options=cnos_provider_spec),
}
command_spec = {
'command': dict(key=True),
'prompt': dict(),
'answer': dict()
}
def get_provider_argspec():
return cnos_provider_spec
def check_args(module, warnings):
pass
def get_connection(module):
global _CONNECTION
if _CONNECTION:
return _CONNECTION
_CONNECTION = Connection(module._socket_path)
context = None
try:
context = module.params['context']
except KeyError:
context = None
if context:
if context == 'system':
command = 'changeto system'
else:
command = 'changeto context %s' % context
_CONNECTION.get(command)
return _CONNECTION
def get_config(module, flags=None):
flags = [] if flags is None else flags
passwords = None
try:
passwords = module.params['passwords']
except KeyError:
passwords = None
if passwords:
cmd = 'more system:running-config'
else:
cmd = 'display running-config '
cmd += ' '.join(flags)
cmd = cmd.strip()
try:
return _DEVICE_CONFIGS[cmd]
except KeyError:
conn = get_connection(module)
out = conn.get(cmd)
cfg = to_text(out, errors='surrogate_then_replace').strip()
_DEVICE_CONFIGS[cmd] = cfg
return cfg
def to_commands(module, commands):
if not isinstance(commands, list):
raise AssertionError('argument must be of type <list>')
transform = EntityCollection(module, command_spec)
commands = transform(commands)
for index, item in enumerate(commands):
if module.check_mode and not item['command'].startswith('show'):
module.warn('only show commands are supported when using check '
'mode, not executing `%s`' % item['command'])
return commands
def run_commands(module, commands, check_rc=True):
connection = get_connection(module)
connection.get('enable')
commands = to_commands(module, to_list(commands))
responses = list()
for cmd in commands:
out = connection.get(**cmd)
responses.append(to_text(out, errors='surrogate_then_replace'))
return responses
def load_config(module, config):
try:
conn = get_connection(module)
conn.get('enable')
conn.edit_config(config)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc))
def get_defaults_flag(module):
rc, out, err = exec_command(module, 'display running-config ?')
out = to_text(out, errors='surrogate_then_replace')
commands = set()
for line in out.splitlines():
if line:
commands.add(line.strip().split()[0])
if 'all' in commands:
return 'all'
else:
return 'full'
def interfaceConfig( def interfaceConfig(

View file

@ -1,166 +1,271 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
# #
# Copyright (C) 2017 Lenovo, Inc. # (C) 2017 Red Hat Inc.
# Copyright (C) 2017 Lenovo.
# #
# This file is part of Ansible # GNU General Public License v3.0+
# #
# Ansible is free software: you can redistribute it and/or modify # This program is distributed in the hope that it will be useful,
# 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 # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# #
# Module to send CLI commands to Lenovo Switches # Module to execute CNOS Commands on Lenovo Switches.
# Lenovo Networking # Lenovo Networking
# #
# from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
'supported_by': 'community'} 'supported_by': 'community'}
DOCUMENTATION = ''' DOCUMENTATION = """
--- ---
module: cnos_command module: cnos_command
author: "Dave Kasberg (@dkasberg)" version_added: "2.6"
short_description: Execute a single command on devices running Lenovo CNOS author: "Anil Kumar Muraleedharan (@amuraleedhar)"
short_description: Run arbitrary commands on Lenovo CNOS devices
description: description:
- This module allows you to modify the switch running configuration. It provides a way to - Sends arbitrary commands to an CNOS node and returns the results
execute a single CNOS command on a switch by evaluating the current running configuration read from the device. The C(cnos_command) module includes an
and executing the command only if the specific setting has not been already configured. argument that will cause the module to wait for a specific condition
The CNOS command is passed as an argument of the method. before returning or timing out if the condition is not met.
This module uses SSH to manage network device configuration.
The results of the operation will be placed in a directory named 'results'
that must be created by the user in their local directory to where the playbook is run.
For more information about this module from Lenovo and customizing it usage for your
use cases, please visit U(http://systemx.lenovofiles.com/help/index.jsp?topic=%2Fcom.lenovo.switchmgt.ansible.doc%2Fcnos_command.html)
version_added: "2.3"
extends_documentation_fragment: cnos
options: options:
clicommand: provider:
version_added: "2.6"
description:
- A dict object containing connection details.
suboptions:
host:
description: description:
- This specifies the CLI command as an attribute to this method. The command is - Specifies the DNS host name or address for connecting to the remote
passed using double quotes. The variables can be placed directly on to the CLI device over the specified transport. The value of host is used as
commands or can be invoked from the vars directory. the destination address for the transport.
required: true required: true
default: Null port:
''' description:
EXAMPLES = ''' - Specifies the port to use when building the connection to the remote device.
Tasks : The following are examples of using the module cnos_command. These are written in the main.yml file of the tasks directory. default: 22
username:
description:
- Configures the username to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_USERNAME) will be used instead.
password:
description:
- Specifies the password to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_PASSWORD) will be used instead.
timeout:
description:
- Specifies the timeout in seconds for communicating with the network device
for either connecting or sending commands. If the timeout is
exceeded before the operation is completed, the module will error.
default: 10
ssh_keyfile:
description:
- Specifies the SSH key to use to authenticate the connection to
the remote device. This value is the path to the
key used to authenticate the SSH session. If the value is not specified
in the task, the value of environment variable C(ANSIBLE_NET_SSH_KEYFILE)
will be used instead.
commands:
version_added: "2.6"
description:
- List of commands to send to the remote 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 retires as expired.
required: true
wait_for:
version_added: "2.6"
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.
match:
version_added: "2.6"
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.
default: all
choices: ['any', 'all']
retries:
version_added: "2.6"
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.
default: 10
interval:
version_added: "2.6"
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.
default: 1
"""
EXAMPLES = """
# Note: examples below use the following provider dict to handle
# transport and authentication to the node.
--- ---
- name: Test Command vars:
cli:
host: "{{ inventory_hostname }}"
port: 22
username: admin
password: admin
timeout: 30
---
- name: test contains operator
cnos_command: cnos_command:
host: "{{ inventory_hostname }}" commands:
username: "{{ hostvars[inventory_hostname]['username'] }}" - show version
password: "{{ hostvars[inventory_hostname]['password'] }}" - show system memory
enablePassword: "{{ hostvars[inventory_hostname]['enablePassword'] }}" wait_for:
deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}" - "result[0] contains 'Lenovo'"
outputfile: "./results/test_command_{{ inventory_hostname }}_output.txt" - "result[1] contains 'MemFree'"
clicommand: "display users" provider: "{{ cli }}"
register: result
''' - assert:
RETURN = ''' that:
msg: - "result.changed == false"
description: Success or failure message - "result.stdout is defined"
- name: get output for single command
cnos_command:
commands: ['show version']
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- name: get output for multiple commands
cnos_command:
commands:
- show version
- show interface information
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout | length == 2"
"""
RETURN = """
stdout:
description: the set of responses from the commands
returned: always returned: always
type: string type: list
sample: "Command Applied" sample: ['...', '...']
''' stdout_lines:
description: The value of stdout split into a list
returned: always
type: list
sample: [['...', '...'], ['...'], ['...']]
failed_conditions:
description: the conditionals that failed
returned: failed
type: list
sample: ['...', '...']
"""
import sys
try:
import paramiko
HAS_PARAMIKO = True
except ImportError:
HAS_PARAMIKO = False
import time import time
import socket
import array
import json
import time
import re
try:
from ansible.module_utils.network.cnos import cnos
HAS_LIB = True
except:
HAS_LIB = False
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from collections import defaultdict from ansible.module_utils.network.cnos.cnos import run_commands, check_args
from ansible.module_utils.network.cnos.cnos import cnos_argument_spec
from ansible.module_utils.network.common.parsing import Conditional
from ansible.module_utils.six import string_types
def to_lines(stdout):
for item in stdout:
if isinstance(item, string_types):
item = str(item).split('\n')
yield item
def main(): def main():
module = AnsibleModule( spec = dict(
argument_spec=dict( # { command: <str>, prompt: <str>, response: <str> }
clicommand=dict(required=True), commands=dict(type='list', required=True),
outputfile=dict(required=True),
host=dict(required=True),
deviceType=dict(required=True),
username=dict(required=True),
password=dict(required=True, no_log=True),
enablePassword=dict(required=False, no_log=True),),
supports_check_mode=False)
username = module.params['username'] wait_for=dict(type='list'),
password = module.params['password'] match=dict(default='all', choices=['all', 'any']),
enablePassword = module.params['enablePassword']
cliCommand = module.params['clicommand']
deviceType = module.params['deviceType']
outputfile = module.params['outputfile']
hostIP = module.params['host']
output = ""
if not HAS_PARAMIKO:
module.fail_json(msg='paramiko is required for this module')
# Create instance of SSHClient object retries=dict(default=10, type='int'),
remote_conn_pre = paramiko.SSHClient() interval=dict(default=1, type='int')
)
# Automatically add untrusted hosts (make sure okay for security policy in your environment) spec.update(cnos_argument_spec)
remote_conn_pre.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# initiate SSH connection with the switch module = AnsibleModule(argument_spec=spec, supports_check_mode=True)
remote_conn_pre.connect(hostIP, username=username, password=password) result = {'changed': False}
time.sleep(2)
# Use invoke_shell to establish an 'interactive session' wait_for = module.params['wait_for'] or list()
remote_conn = remote_conn_pre.invoke_shell() conditionals = [Conditional(c) for c in wait_for]
time.sleep(2)
# Enable and enter configure terminal then send command commands = module.params['commands']
output = output + cnos.waitForDeviceResponse("\n", ">", 2, remote_conn) retries = module.params['retries']
interval = module.params['interval']
match = module.params['match']
output = output + cnos.enterEnableModeForDevice(enablePassword, 3, remote_conn) while retries > 0:
responses = run_commands(module, commands)
# Make terminal length = 0 for item in list(conditionals):
output = output + cnos.waitForDeviceResponse("terminal length 0\n", "#", 2, remote_conn) if item(responses):
if match == 'any':
conditionals = list()
break
conditionals.remove(item)
# Go to config mode if not conditionals:
output = output + cnos.waitForDeviceResponse("configure d\n", "(config)#", 2, remote_conn) break
# Send the CLi command time.sleep(interval)
output = output + cnos.waitForDeviceResponse(cliCommand + "\n", "(config)#", 2, remote_conn) retries -= 1
# Save it into the file if conditionals:
file = open(outputfile, "a") failed_conditions = [item.raw for item in conditionals]
file.write(output) msg = 'One or more conditional statements have not been satisfied'
file.close() 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)
# Logic to check when changes occur or not
errorMsg = cnos.checkOutputForError(output)
if(errorMsg is None):
module.exit_json(changed=True, msg="CLI command executed and results saved in file ")
else:
module.fail_json(msg=errorMsg)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -0,0 +1,317 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# (C) 2017 Red Hat Inc.
# Copyright (C) 2017 Lenovo.
#
# GNU General Public License v3.0+
#
# This program 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.
#
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# Module to configure Lenovo Switches.
# Lenovo Networking
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = """
---
module: cnos_config
version_added: "2.6"
author: "Anil Kumar Muraleedharan (@amuraleedhar)"
short_description: Manage Lenovo CNOS configuration sections
description:
- Lenovo CNOS configurations use a simple block indent file syntax
for segmenting configuration into sections. This module provides
an implementation for working with CNOS configuration sections in
a deterministic way.
notes:
- Tested against CNOS 10.8.0.42
options:
provider:
version_added: "2.6"
description:
- A dict object containing connection details.
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.
required: true
port:
description:
- Specifies the port to use when building the connection to the remote device.
default: 22
username:
description:
- Configures the username to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_USERNAME) will be used instead.
password:
description:
- Specifies the password to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_PASSWORD) will be used instead.
timeout:
description:
- Specifies the timeout in seconds for communicating with the network device
for either connecting or sending commands. If the timeout is
exceeded before the operation is completed, the module will error.
default: 10
ssh_keyfile:
description:
- Specifies the SSH key to use to authenticate the connection to
the remote device. This value is the path to the
key used to authenticate the SSH session. If the value is not specified
in the task, the value of environment variable C(ANSIBLE_NET_SSH_KEYFILE)
will be used instead.
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.
aliases: ['commands']
parents:
description:
- The ordered set of parents that uniquely identify the section
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.
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), I(parents).
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.
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.
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.
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.
default: line
choices: ['line', 'block', 'config']
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.
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. 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'
comment:
description:
- Allows a commit description to be specified to be included
when the configuration is committed. If the configuration is
not changed or committed, this argument is ignored.
default: 'configured by cnos_config'
admin:
description:
- Enters into administration configuration mode for making config
changes to the device.
type: bool
default: 'no'
"""
EXAMPLES = """
Tasks: The following are examples of using the module cnos_config.
---
- name: configure top level configuration
cnos_config:
"lines: hostname {{ inventory_hostname }}"
- name: configure interface settings
cnos_config:
lines:
- enable
- ip ospf enable
parents: interface ip 13
- name: load a config from disk and replace the current config
cnos_config:
src: config.cfg
backup: yes
"""
RETURN = """
updates:
description: The set of commands that will be pushed to the remote device
returned: Only when lines is specified.
type: list
sample: ['...', '...']
backup_path:
description: The full path to the backup file
returned: when backup is yes
type: string
sample: /playbooks/ansible/backup/cnos01.2016-07-16@22:28:34
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.cnos.cnos import load_config, get_config
from ansible.module_utils.network.cnos.cnos import cnos_argument_spec
from ansible.module_utils.network.cnos.cnos import check_args
from ansible.module_utils.network.common.config import NetworkConfig, dumps
DEFAULT_COMMIT_COMMENT = 'configured by cnos_config'
def get_running_config(module):
contents = module.params['config']
if not contents:
contents = get_config(module)
return NetworkConfig(indent=1, contents=contents)
def get_candidate(module):
candidate = NetworkConfig(indent=1)
if module.params['src']:
candidate.load(module.params['src'])
elif module.params['lines']:
parents = module.params['parents'] or list()
candidate.add(module.params['lines'], parents=parents)
return candidate
def run(module, result):
match = module.params['match']
replace = module.params['replace']
replace_config = replace == 'config'
path = module.params['parents']
comment = module.params['comment']
admin = module.params['admin']
check_mode = module.check_mode
candidate = get_candidate(module)
if match != 'none' and replace != 'config':
contents = get_running_config(module)
configobj = NetworkConfig(contents=contents, indent=1)
commands = candidate.difference(configobj, path=path, match=match,
replace=replace)
else:
commands = candidate.items
if commands:
commands = dumps(commands, 'commands').split('\n')
if any((module.params['lines'], module.params['src'])):
if module.params['before']:
commands[:0] = module.params['before']
if module.params['after']:
commands.extend(module.params['after'])
result['commands'] = commands
diff = load_config(module, commands)
if diff:
result['diff'] = dict(prepared=diff)
result['changed'] = True
def main():
"""main entry point for module execution
"""
argument_spec = dict(
src=dict(type='path'),
lines=dict(aliases=['commands'], type='list'),
parents=dict(type='list'),
before=dict(type='list'),
after=dict(type='list'),
match=dict(default='line', choices=['line', 'strict',
'exact', 'none']),
replace=dict(default='line', choices=['line', 'block', 'config']),
config=dict(),
backup=dict(type='bool', default=False),
comment=dict(default=DEFAULT_COMMIT_COMMENT),
admin=dict(type='bool', default=False)
)
argument_spec.update(cnos_argument_spec)
mutually_exclusive = [('lines', 'src'),
('parents', 'src')]
required_if = [('match', 'strict', ['lines']),
('match', 'exact', ['lines']),
('replace', 'block', ['lines']),
('replace', 'config', ['src'])]
module = AnsibleModule(argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive,
required_if=required_if,
supports_check_mode=True)
warnings = list()
check_args(module, warnings)
result = dict(changed=False, warnings=warnings)
if module.params['backup']:
result['__backup__'] = get_config(module)
run(module, result)
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -1,146 +1,594 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
# #
# Copyright (C) 2017 Lenovo, Inc. # (C) 2017 Red Hat Inc.
# Copyright (C) 2017 Lenovo.
# #
# This file is part of Ansible # GNU General Public License v3.0+
# #
# Ansible is free software: you can redistribute it and/or modify # This program is distributed in the hope that it will be useful,
# 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 # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # Module to Collect facts from Lenovo Switches running Lenovo CNOS commands
#
# Module to show sys info of Lenovo Switches
# Lenovo Networking # Lenovo Networking
# #
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
'supported_by': 'community'} 'supported_by': 'community'}
DOCUMENTATION = ''' DOCUMENTATION = '''
--- ---
module: cnos_facts module: cnos_facts
author: "Dave Kasberg (@dkasberg)"
short_description: Collect facts on devices running Lenovo CNOS
description:
- This module allows you to view the switch information. It executes the show sysinfo CLI command on a switch
and returns a file containing all the system information of the target network device. This module uses SSH to
manage network device configuration. The results of the operation can be viewed in results directory.
For more information about this module from Lenovo and customizing it usage for your
use cases, please visit U(http://systemx.lenovofiles.com/help/index.jsp?topic=%2Fcom.lenovo.switchmgt.ansible.doc%2Fcnos_facts.html)
version_added: "2.3" version_added: "2.3"
extends_documentation_fragment: cnos author: "Anil Kumar Muraleedharan (@amuraleedhar)"
options: {} short_description: Collect facts from remote devices running Lenovo CNOS
description:
- Collects a base set of device facts from a remote Lenovo device
running on CNOS. 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.
notes:
- Tested against CNOS 10.8.0.42
options:
authorize:
version_added: "2.6"
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
default: 'no'
auth_pass:
version_added: "2.6"
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.
provider:
version_added: "2.6"
description:
- A dict object containing connection details.
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.
required: true
port:
description:
- Specifies the port to use when building the connection to the remote device.
default: 22
username:
description:
- Configures the username to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_USERNAME) will be used instead.
password:
description:
- Specifies the password to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_PASSWORD) will be used instead.
timeout:
description:
- Specifies the timeout in seconds for communicating with the network device
for either connecting or sending commands. If the timeout is
exceeded before the operation is completed, the module will error.
default: 10
ssh_keyfile:
description:
- Specifies the SSH key to use to authenticate the connection to
the remote device. This value is the path to the
key used to authenticate the SSH session. If the value is not specified
in the task, the value of environment variable C(ANSIBLE_NET_SSH_KEYFILE)
will be used instead.
gather_subset:
version_added: "2.6"
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.
required: false
default: '!config'
''' '''
EXAMPLES = ''' EXAMPLES = '''
Tasks : The following are examples of using the module cnos_facts. These are written in the main.yml file of the tasks directory. Tasks: The following are examples of using the module cnos_facts.
--- ---
- name: Test Sys Info - name: Test cnos Facts
cnos_facts: cnos_facts:
provider={{ cli }}
vars:
cli:
host: "{{ inventory_hostname }}" host: "{{ inventory_hostname }}"
username: "{{ hostvars[inventory_hostname]['username'] }}" port: 22
password: "{{ hostvars[inventory_hostname]['password'] }}" username: admin
deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}" password: admin
enablePassword: "{{ hostvars[inventory_hostname]['enablePassword'] }}" transport: cli
outputfile: "./results/cnos_facts_{{ inventory_hostname }}_output.txt" timeout: 30
authorize: True
auth_pass:
---
# Collect all facts from the device
- cnos_facts:
gather_subset: all
provider: "{{ cli }}"
# Collect only the config and default facts
- cnos_facts:
gather_subset:
- config
provider: "{{ cli }}"
# Do not collect hardware facts
- cnos_facts:
gather_subset:
- "!hardware"
provider: "{{ cli }}"
''' '''
RETURN = ''' RETURN = '''
msg: ansible_net_gather_subset:
description: Success or failure message description: The list of fact subsets collected from the device
returned: always returned: always
type: string type: list
sample: "Device Sys Info is saved to file" # default
ansible_net_model:
description: The model name returned from the Lenovo CNOS device
returned: always
type: str
ansible_net_serialnum:
description: The serial number of the Lenovo CNOS device
returned: always
type: str
ansible_net_version:
description: The CNOS 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: string
ansible_net_image:
description: Indicates the active image for the device
returned: always
type: string
# hardware
ansible_net_memfree_mb:
description: The available free 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_all_ipv4_addresses:
description: All IPv4 addresses configured on the device
returned: when interfaces is configured
type: list
ansible_net_all_ipv6_addresses:
description: All IPv6 addresses configured on the device
returned: when interfaces is configured
type: list
ansible_net_interfaces:
description: A hash of all interfaces running on the system.
This gives information on description, mac address, mtu, speed,
duplex and operstatus
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 sys
try:
import paramiko
HAS_PARAMIKO = True
except ImportError:
HAS_PARAMIKO = False
import time
import socket
import array
import json
import time
import re import re
try:
from ansible.module_utils.network.cnos import cnos from ansible.module_utils.network.cnos.cnos import run_commands
HAS_LIB = True from ansible.module_utils.network.cnos.cnos import cnos_argument_spec
except: from ansible.module_utils.network.cnos.cnos import check_args
HAS_LIB = False from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from collections import defaultdict from ansible.module_utils.six import iteritems
from ansible.module_utils.six.moves import zip
class FactsBase(object):
COMMANDS = list()
def __init__(self, module):
self.module = module
self.facts = dict()
self.responses = None
self.PERSISTENT_COMMAND_TIMEOUT = 60
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 = ['display sys-info', 'display running-config']
def populate(self):
super(Default, self).populate()
data = self.responses[0]
data_run = self.responses[1]
if data:
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)
if data_run:
self.facts['hostname'] = self.parse_hostname(data_run)
def parse_version(self, data):
for line in data.split('\n'):
line = line.strip()
match = re.match(r'System Software Revision (.*?)',
line, re.M | re.I)
if match:
vers = line.split(':')
ver = vers[1].strip()
return ver
return "NA"
def parse_hostname(self, data_run):
for line in data_run.split('\n'):
line = line.strip()
match = re.match(r'hostname (.*?)', line, re.M | re.I)
if match:
hosts = line.split()
hostname = hosts[1].strip('\"')
return hostname
return "NA"
def parse_model(self, data):
for line in data.split('\n'):
line = line.strip()
match = re.match(r'System Model (.*?)', line, re.M | re.I)
if match:
mdls = line.split(':')
mdl = mdls[1].strip()
return mdl
return "NA"
def parse_image(self, data):
match = re.search(r'(.*) image1(.*)', data, re.M | re.I)
if match:
return "Image1"
else:
return "Image1"
def parse_serialnum(self, data):
for line in data.split('\n'):
line = line.strip()
match = re.match(r'System Serial Number (.*?)', line, re.M | re.I)
if match:
serNums = line.split(':')
ser = serNums[1].strip()
return ser
return "NA"
class Hardware(FactsBase):
COMMANDS = [
'display running-config'
]
def populate(self):
super(Hardware, self).populate()
data = self.run(['display process memory'])
data = to_text(data, errors='surrogate_or_strict').strip()
data = data.replace(r"\n", "\n")
if data:
for line in data.split('\n'):
line = line.strip()
match = re.match(r'Mem: (.*?)', line, re.M | re.I)
if match:
memline = line.split(':')
mems = memline[1].strip().split()
self.facts['memtotal_mb'] = int(mems[0]) / 1024
self.facts['memused_mb'] = int(mems[1]) / 1024
self.facts['memfree_mb'] = int(mems[2]) / 1024
self.facts['memshared_mb'] = int(mems[3]) / 1024
self.facts['memavailable_mb'] = int(mems[5]) / 1024
def parse_memtotal(self, data):
match = re.search(r'^MemTotal:\s*(.*) kB', data, re.M | re.I)
if match:
return int(match.group(1)) / 1024
def parse_memfree(self, data):
match = re.search(r'^MemFree:\s*(.*) kB', data, re.M | re.I)
if match:
return int(match.group(1)) / 1024
class Config(FactsBase):
COMMANDS = ['display running-config']
def populate(self):
super(Config, self).populate()
data = self.responses[0]
if data:
self.facts['config'] = data
class Interfaces(FactsBase):
COMMANDS = ['display interface brief']
def populate(self):
super(Interfaces, self).populate()
self.facts['all_ipv4_addresses'] = list()
self.facts['all_ipv6_addresses'] = list()
data1 = self.run(['display interface status'])
data1 = to_text(data1, errors='surrogate_or_strict').strip()
data1 = data1.replace(r"\n", "\n")
data2 = self.run(['display interface mac-address'])
data2 = to_text(data2, errors='surrogate_or_strict').strip()
data2 = data2.replace(r"\n", "\n")
lines1 = None
lines2 = None
if data1:
lines1 = self.parse_interfaces(data1)
if data2:
lines2 = self.parse_interfaces(data2)
if lines1 is not None and lines2 is not None:
self.facts['interfaces'] = self.populate_interfaces(lines1, lines2)
data3 = self.run(['display lldp neighbors'])
data3 = to_text(data3, errors='surrogate_or_strict').strip()
data3 = data3.replace(r"\n", "\n")
if data3:
lines3 = self.parse_neighbors(data3)
if lines3 is not None:
self.facts['neighbors'] = self.populate_neighbors(lines3)
data4 = self.run(['display ip interface brief vrf all'])
data5 = self.run(['display ipv6 interface brief vrf all'])
data4 = to_text(data4, errors='surrogate_or_stdisplay').strip()
data4 = data4.replace(r"\n", "\n")
data5 = to_text(data5, errors='surrogate_or_strict').strip()
data5 = data5.replace(r"\n", "\n")
lines4 = None
lines5 = None
if data4:
lines4 = self.parse_ipaddresses(data4)
ipv4_interfaces = self.set_ip_interfaces(lines4)
self.facts['all_ipv4_addresses'] = ipv4_interfaces
if data5:
lines5 = self.parse_ipaddresses(data5)
ipv6_interfaces = self.set_ipv6_interfaces(lines5)
self.facts['all_ipv6_addresses'] = ipv6_interfaces
def parse_ipaddresses(self, data):
parsed = list()
for line in data.split('\n'):
if len(line) == 0:
continue
else:
line = line.strip()
match = re.match(r'^(Ethernet+)', line)
if match:
key = match.group(1)
parsed.append(line)
match = re.match(r'^(po+)', line)
if match:
key = match.group(1)
parsed.append(line)
match = re.match(r'^(mgmt+)', line)
if match:
key = match.group(1)
parsed.append(line)
match = re.match(r'^(loopback+)', line)
if match:
key = match.group(1)
parsed.append(line)
return parsed
def populate_interfaces(self, lines1, lines2):
interfaces = dict()
for line1, line2 in zip(lines1, lines2):
line = line1 + " " + line2
intfSplit = line.split()
innerData = dict()
innerData['description'] = intfSplit[1].strip()
innerData['macaddress'] = intfSplit[8].strip()
innerData['type'] = intfSplit[6].strip()
innerData['speed'] = intfSplit[5].strip()
innerData['duplex'] = intfSplit[4].strip()
innerData['operstatus'] = intfSplit[2].strip()
interfaces[intfSplit[0].strip()] = innerData
return interfaces
def parse_interfaces(self, data):
parsed = list()
for line in data.split('\n'):
if len(line) == 0:
continue
else:
line = line.strip()
match = re.match(r'^(Ethernet+)', line)
if match:
key = match.group(1)
parsed.append(line)
match = re.match(r'^(po+)', line)
if match:
key = match.group(1)
parsed.append(line)
match = re.match(r'^(mgmt+)', line)
if match:
key = match.group(1)
parsed.append(line)
# match = re.match(r'^(loopback+)', line)
# if match:
# key = match.group(1)
# parsed.append(line)
return parsed
def set_ip_interfaces(self, line4):
ipv4_addresses = list()
for line in line4:
ipv4Split = line.split()
if 'Ethernet' in ipv4Split[0]:
ipv4_addresses.append(ipv4Split[1])
if 'mgmt' in ipv4Split[0]:
ipv4_addresses.append(ipv4Split[1])
if 'po' in ipv4Split[0]:
ipv4_addresses.append(ipv4Split[1])
if 'loopback' in ipv4Split[0]:
ipv4_addresses.append(ipv4Split[1])
return ipv4_addresses
def set_ipv6_interfaces(self, line4):
ipv6_addresses = list()
for line in line4:
ipv6Split = line.split()
if 'Ethernet' in ipv6Split[0]:
ipv6_addresses.append(ipv6Split[1])
if 'mgmt' in ipv6Split[0]:
ipv6_addresses.append(ipv6Split[1])
if 'po' in ipv6Split[0]:
ipv6_addresses.append(ipv6Split[1])
if 'loopback' in ipv6Split[0]:
ipv6_addresses.append(ipv6Split[1])
return ipv6_addresses
def populate_neighbors(self, lines3):
neighbors = dict()
for line in lines3:
neighborSplit = line.split()
innerData = dict()
innerData['Local Interface'] = neighborSplit[1].strip()
innerData['Hold Time'] = neighborSplit[2].strip()
innerData['Capability'] = neighborSplit[3].strip()
innerData['Remote Port'] = neighborSplit[4].strip()
neighbors[neighborSplit[0].strip()] = innerData
return neighbors
def parse_neighbors(self, neighbors):
parsed = list()
for line in neighbors.split('\n'):
if len(line) == 0:
continue
else:
line = line.strip()
if 'Ethernet' in line:
parsed.append(line)
if 'mgmt' in line:
parsed.append(line)
if 'po' in line:
parsed.append(line)
if 'loopback' in line:
parsed.append(line)
return parsed
FACT_SUBSETS = dict(
default=Default,
hardware=Hardware,
interfaces=Interfaces,
config=Config,
)
VALID_SUBSETS = frozenset(FACT_SUBSETS.keys())
PERSISTENT_COMMAND_TIMEOUT = 60
def main(): def main():
module = AnsibleModule( """main entry point for module execution
argument_spec=dict( """
outputfile=dict(required=True), argument_spec = dict(
host=dict(required=True), gather_subset=dict(default=['!config'], type='list')
username=dict(required=True), )
password=dict(required=True, no_log=True),
enablePassword=dict(required=False, no_log=True),),
supports_check_mode=False)
username = module.params['username'] argument_spec.update(cnos_argument_spec)
password = module.params['password']
enablePassword = module.params['enablePassword']
cliCommand = "display sys-info"
outputfile = module.params['outputfile']
hostIP = module.params['host']
output = ""
if not HAS_PARAMIKO:
module.fail_json(msg='paramiko is required for this module')
# Create instance of SSHClient object module = AnsibleModule(argument_spec=argument_spec,
remote_conn_pre = paramiko.SSHClient() supports_check_mode=True)
# Automatically add untrusted hosts (make sure okay for security policy in your environment) gather_subset = module.params['gather_subset']
remote_conn_pre.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# initiate SSH connection with the switch runable_subsets = set()
remote_conn_pre.connect(hostIP, username=username, password=password) exclude_subsets = set()
time.sleep(2)
# Use invoke_shell to establish an 'interactive session' for subset in gather_subset:
remote_conn = remote_conn_pre.invoke_shell() if subset == 'all':
time.sleep(2) runable_subsets.update(VALID_SUBSETS)
continue
# Enable and enter configure terminal then send command if subset.startswith('!'):
output = output + cnos.waitForDeviceResponse("\n", ">", 2, remote_conn) subset = subset[1:]
if subset == 'all':
exclude_subsets.update(VALID_SUBSETS)
continue
exclude = True
else:
exclude = False
output = output + cnos.enterEnableModeForDevice(enablePassword, 3, remote_conn) if subset not in VALID_SUBSETS:
module.fail_json(msg='Bad subset')
# Make terminal length = 0 if exclude:
output = output + cnos.waitForDeviceResponse("terminal length 0\n", "#", 2, remote_conn) exclude_subsets.add(subset)
else:
runable_subsets.add(subset)
# Send the CLi command if not runable_subsets:
output = output + cnos.waitForDeviceResponse(cliCommand + "\n", "#", 2, remote_conn) runable_subsets.update(VALID_SUBSETS)
# Save it into the file runable_subsets.difference_update(exclude_subsets)
file = open(outputfile, "a") runable_subsets.add('default')
file.write(output)
file.close() 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)
errorMsg = cnos.checkOutputForError(output)
if(errorMsg is None):
module.exit_json(changed=True, msg="Device Sys Info is saved to file ")
else:
module.fail_json(msg=errorMsg)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -0,0 +1,84 @@
# (C) 2017 Red Hat Inc.
# Copyright (C) 2017 Lenovo.
#
# GNU General Public License v3.0+
#
# This program 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.
#
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# Contains Action Plugin methods for ENOS Config Module
# Lenovo Networking
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import sys
import copy
from ansible import constants as C
from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.network.cnos.cnos import cnos_provider_spec
from ansible.module_utils.network.common.utils import load_provider
from ansible.module_utils.connection import Connection
from ansible.module_utils._text import to_text
try:
from __main__ import display
except ImportError:
from ansible.utils.display import Display
display = Display()
class ActionModule(_ActionModule):
def run(self, tmp=None, task_vars=None):
del tmp # tmp no longer has any effect
socket_path = None
if self._play_context.connection == 'local':
provider = load_provider(cnos_provider_spec, self._task.args)
pc = copy.deepcopy(self._play_context)
pc.connection = 'network_cli'
pc.network_os = 'cnos'
pc.remote_addr = provider['host'] or self._play_context.remote_addr
pc.port = 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
pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT)
pc.become = provider['authorize'] or True
pc.become_pass = provider['auth_pass']
pc.become_method = 'enable'
display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr)
connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin)
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 or exec mode
if socket_path is None:
socket_path = self._connection.socket_path
conn = Connection(socket_path)
out = conn.get_prompt()
if to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('In Config mode, sending exit to device', self._play_context.remote_addr)
conn.send_command('exit')
else:
conn.send_command('enable')
result = super(ActionModule, self).run(task_vars=task_vars)
return result

View file

@ -0,0 +1,110 @@
# (C) 2017 Red Hat Inc.
# Copyright (C) 2017 Lenovo.
#
# GNU General Public License v3.0+
#
# This program 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.
#
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# Contains Action Plugin methods for ENOS Config Module
# Lenovo Networking
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import re
import time
import glob
from ansible.plugins.action.cnos import ActionModule as _ActionModule
from ansible.module_utils._text import to_text
from ansible.module_utils.six.moves.urllib.parse import urlsplit
from ansible.utils.vars import merge_hash
PRIVATE_KEYS_RE = re.compile('__.+__')
class ActionModule(_ActionModule):
def run(self, tmp=None, task_vars=None):
if self._task.args.get('src'):
try:
self._handle_template()
except ValueError as exc:
return dict(failed=True, msg=to_text(exc))
result = super(ActionModule, self).run(tmp, task_vars)
del tmp # tmp no longer has any effect
if self._task.args.get('backup') and result.get('__backup__'):
# User requested backup and no error occurred in module.
# NOTE: If there is a parameter error, _backup key may not be in results.
filepath = self._write_backup(task_vars['inventory_hostname'],
result['__backup__'])
result['backup_path'] = filepath
# strip out any keys that have two leading and two trailing
# underscore characters
for key in list(result.keys()):
if PRIVATE_KEYS_RE.match(key):
del result[key]
return result
def _get_working_path(self):
cwd = self._loader.get_basedir()
if self._task._role is not None:
cwd = self._task._role._role_path
return cwd
def _write_backup(self, host, contents):
backup_path = self._get_working_path() + '/backup'
if not os.path.exists(backup_path):
os.mkdir(backup_path)
for fn in glob.glob('%s/%s*' % (backup_path, host)):
os.remove(fn)
tstamp = time.strftime("%Y-%m-%d@%H:%M:%S", time.localtime(time.time()))
filename = '%s/%s_config.%s' % (backup_path, host, tstamp)
open(filename, 'w').write(contents)
return filename
def _handle_template(self):
src = self._task.args.get('src')
working_path = self._get_working_path()
if os.path.isabs(src) or urlsplit('src').scheme:
source = src
else:
source = self._loader.path_dwim_relative(working_path, 'templates', src)
if not source:
source = self._loader.path_dwim_relative(working_path, src)
if not os.path.exists(source):
raise ValueError('path specified in src not found')
try:
with open(source, 'r') as f:
template_data = to_text(f.read())
except IOError:
return dict(failed=True, msg='unable to load src file')
# Create a template search path in the following order:
# [working_path, self_role_path, dependent_role_paths, dirname(source)]
searchpath = [working_path]
if self._task._role is not None:
searchpath.append(self._task._role._role_path)
if hasattr(self._task, "_block:"):
dep_chain = self._task._block.get_dep_chain()
if dep_chain is not None:
for role in dep_chain:
searchpath.append(role._role_path)
searchpath.append(os.path.dirname(source))
self._templar.environment.loader.searchpath = searchpath
self._task.args['src'] = self._templar.template(template_data)

View file

@ -0,0 +1,78 @@
# (C) 2017 Red Hat Inc.
# Copyright (C) 2017 Lenovo.
#
# GNU General Public License v3.0+
#
# This program 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.
#
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# Contains CLIConf Plugin methods for ENOS Modules
# Lenovo Networking
#
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, enable_mode
class Cliconf(CliconfBase):
def get_device_info(self):
device_info = {}
device_info['network_os'] = 'cnos'
reply = self.get(b'display version')
data = to_text(reply, errors='surrogate_or_strict').strip()
match = re.search(r'^System version: (.*?) ', data, re.M | re.I)
if match:
device_info['network_os_version'] = match.group(1)
match = re.search(r'^Lenovo RackSwitch (\S+)', data, re.M | re.I)
if match:
device_info['network_os_model'] = match.group(1)
match = re.search(r'^Device name: (.*?) ', data, re.M | re.I)
if match:
device_info['network_os_hostname'] = match.group(1)
else:
device_info['network_os_hostname'] = "NA"
return device_info
@enable_mode
def get_config(self, source='running', format='text'):
if source not in ('running', 'startup'):
msg = "fetching configuration from %s is not supported"
return self.invalid_params(msg % source)
if source == 'running':
cmd = b'display running-config'
else:
cmd = b'display startup-config'
return self.send_command(cmd)
@enable_mode
def edit_config(self, command):
for cmd in chain([b'configure device'], to_list(command), [b'end']):
self.send_command(cmd)
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,83 @@
# (C) 2017 Red Hat Inc.
# Copyright (C) 2017 Lenovo.
#
# GNU General Public License v3.0+
#
# This program 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.
#
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# Contains terminal Plugin methods for ENOS Config Module
# Lenovo Networking
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
import re
from ansible.errors import AnsibleConnectionFailure
from ansible.module_utils._text import to_text, to_bytes
from ansible.plugins.terminal import TerminalBase
class TerminalModule(TerminalBase):
terminal_stdout_re = [
re.compile(br"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"),
re.compile(br"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$"),
re.compile(br">[\r\n]?")
]
terminal_stderr_re = [
re.compile(br"% ?Error"),
re.compile(br"% ?Bad secret"),
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+"),
]
def on_open_shell(self):
try:
for cmd in (b'\n', b'terminal length 0\n'):
self._exec_cli_command(cmd)
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:
# Note: python-3.5 cannot combine u"" and r"" together. Thus make
# an r string and use to_text to ensure it's text
# on both py2 and py3.
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:
msg = 'unable to elevate privilege to enable mode'
raise AnsibleConnectionFailure(msg)
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 b'(config' in prompt:
self._exec_cli_command(b'end')
self._exec_cli_command(b'disable')
elif prompt.endswith(b'#'):
self._exec_cli_command(b'disable')

View file

@ -880,7 +880,6 @@ lib/ansible/modules/network/cnos/cnos_backup.py E322
lib/ansible/modules/network/cnos/cnos_backup.py E323 lib/ansible/modules/network/cnos/cnos_backup.py E323
lib/ansible/modules/network/cnos/cnos_backup.py E326 lib/ansible/modules/network/cnos/cnos_backup.py E326
lib/ansible/modules/network/cnos/cnos_bgp.py E326 lib/ansible/modules/network/cnos/cnos_bgp.py E326
lib/ansible/modules/network/cnos/cnos_command.py E326
lib/ansible/modules/network/cnos/cnos_conditional_command.py E326 lib/ansible/modules/network/cnos/cnos_conditional_command.py E326
lib/ansible/modules/network/cnos/cnos_conditional_template.py E326 lib/ansible/modules/network/cnos/cnos_conditional_template.py E326
lib/ansible/modules/network/cnos/cnos_factory.py E326 lib/ansible/modules/network/cnos/cnos_factory.py E326

View file

@ -0,0 +1,117 @@
# Copyright (C) 2017 Lenovo, 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/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import patch
from ansible.module_utils import basic
from ansible.module_utils._text import to_bytes
def set_module_args(args):
args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
basic._ANSIBLE_ARGS = to_bytes(args)
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 f:
data = f.read()
try:
data = json.loads(data)
except:
pass
fixture_data[path] = data
return data
class AnsibleExitJson(Exception):
pass
class AnsibleFailJson(Exception):
pass
class TestCnosModule(unittest.TestCase):
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):
def fail_json(*args, **kwargs):
kwargs['failed'] = True
raise AnsibleFailJson(kwargs)
with patch.object(basic.AnsibleModule, 'fail_json', fail_json):
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):
def exit_json(*args, **kwargs):
if 'changed' not in kwargs:
kwargs['changed'] = False
raise AnsibleExitJson(kwargs)
with patch.object(basic.AnsibleModule, 'exit_json', exit_json):
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,334 @@
!
version "10.8.0.42"
!
hostname ip10-241-107-39
!
banner motd NMS India CNOS
banner motd NMS India CNOS G8272
!
clock timezone EDT 0 0
!
logging console 7
vrf context management
ip route 0.0.0.0/0 10.241.107.1
!
!
port-channel load-balance ethernet destination-mac
port-channel load-balance ethernet source-interface
feature telnet
ip domain-name labs.lenovo.com vrf management
ip domain-list labs.lenovo.com vrf management
ip name-server 10.241.104.120 vrf management
ip name-server 10.240.0.10 vrf management
ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf management
ip host ip10-241-107-39 10.241.107.39 vrf management
ip domain-name labs.lenovo.com vrf default
ip domain-list labs.lenovo.com vrf default
ip name-server 10.240.0.10 vrf default
ip name-server 10.241.104.120 vrf default
ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf default
ip host ip10-241-107-39 10.241.107.39 vrf default
ntp server 173.230.154.254 prefer
ntp server 97.127.86.33 prefer
ntp server 129.250.35.250 prefer
ntp server 174.136.103.130 prefer
ntp server 69.10.161.7 prefer
ntp server 96.226.123.196 prefer
ntp server 104.238.179.130 prefer
ntp server 108.61.73.244 prefer
ntp server 208.75.89.4 prefer
snmp-server community public group network-operator
snmp-server community private group network-admin
snmp-server contact Ralph
username admin role network-admin password encrypted $6$bJoWyEu/$9pzSgFPAKGRm1stpTCEl3I39htbjxiFCfhqiHag1NQiKHv/IiLQ2lYW0V3p7p72SgSmVHp38em9P9R/EdePpk/
logging server 10.241.107.231
logging server 10.241.107.222
feature restApi
ovsdb pki ovsdb_mgmt vrf management
ovsdb pki ovsdb_default vrf default
lacp system-priority 32769
vlag tier-id 313
vlag priority 1313
vlag isl port-channel 100
vlag hlthchk keepalive-attempts 5
vlag hlthchk peer-ip 1.2.3.4
vlag auto-recovery 266
vlag startup-delay 323
vlag enable
vlag instance 1 port-channel 1003
vlag instance 1 enable
vlag instance 2 port-channel 20
vlag instance 2 enable
vlag instance 12 port-channel 23
vlag instance 33 port-channel 333
vlag instance 33 enable
spanning-tree mode mst
telemetry heartbeat enabled interval 15
!
policy-map type control-plane copp-system-policy
class type control-plane copp-s-pvst-bpdu
police pps 500
class type control-plane copp-s-ecp
police pps 3000
class type control-plane copp-s-igmp
police pps 3000
!
vlan 1-2
no flood ipv4
!
vlan 3
!
vlan 5
!
vlan 12
!
vlan 13
name dave
!
vlan dot1q tag native egress-only
!
interface Ethernet1/1
description Link 1 to LP21
load-interval counter 2 33
switchport access vlan 33
storm-control broadcast level 12.50
mtu 66
channel-group 33 mode on
!
interface Ethernet1/2
description Link 2 to LP21
channel-group 1001 mode active
!
interface Ethernet1/3
description Link 1 to LP22
switchport mode trunk
channel-group 1003 mode active
!
interface Ethernet1/4
description Link 2 to LP22
switchport mode trunk
channel-group 1004 mode active
!
interface Ethernet1/5
description Link 1 to LP23
no switchport
ip address 20.131.1.1/30
!
interface Ethernet1/6
description Link 2 to LP23
no switchport
ip address 20.131.2.1/30
!
interface Ethernet1/7
description Link 1 to LP24
no switchport
ip address 20.141.1.1/30
!
interface Ethernet1/8
description Link 2 to LP24
no switchport
ip address 20.141.2.1/30
!
interface Ethernet1/9
!
interface Ethernet1/10
!
interface Ethernet1/11
no switchport
mtu 1402
ip address 1.1.1.2/8
!
!
interface Ethernet1/12
ip address 100.10.10.10/24
mtu 1402
no switchport
!
interface Ethernet1/13
description test string
no switchport
ip address 10.241.107.54/24
vrrp 254
address 10.241.107.55
priority 254
no shutdown
ip arp timeout 1500
!
interface Ethernet1/14
!
interface Ethernet1/15
!
interface Ethernet1/16
!
interface Ethernet1/17
!
interface Ethernet1/18
!
interface Ethernet1/19
!
interface Ethernet1/20
!
interface Ethernet1/21
!
interface Ethernet1/22
!
interface Ethernet1/23
channel-group 11 mode active
lacp port-priority 32769
!
interface Ethernet1/24
!
interface Ethernet1/25
!
interface Ethernet1/26
!
interface Ethernet1/27
!
interface Ethernet1/28
!
interface Ethernet1/29
!
interface Ethernet1/30
!
interface Ethernet1/31
!
interface Ethernet1/32
!
interface Ethernet1/33
description Hentammoo
load-interval counter 2 33
switchport access vlan 33
storm-control broadcast level 12.50
mtu 66
microburst-detection enable threshold 25
lldp tlv-select max-frame-size
lacp port-priority 33
spanning-tree mst 33-35 cost 33
spanning-tree bpduguard enable
!
interface Ethernet1/34
!
interface Ethernet1/35
!
interface Ethernet1/36
!
interface Ethernet1/37
!
interface Ethernet1/38
!
interface Ethernet1/39
!
interface Ethernet1/40
!
interface Ethernet1/41
!
interface Ethernet1/42
!
interface Ethernet1/43
!
interface Ethernet1/44
!
interface Ethernet1/45
!
interface Ethernet1/46
!
interface Ethernet1/47
!
interface Ethernet1/48
!
interface Ethernet1/49
!
interface Ethernet1/50
!
interface Ethernet1/51
!
interface Ethernet1/52
!
interface Ethernet1/53
!
interface Ethernet1/54
!
interface loopback0
no switchport
!
interface mgmt0
no switchport
vrf member management
no ip address dhcp
ip address 10.241.107.39/24
no ipv6 address dhcp
!
interface Vlan1
no switchport
!
interface port-channel1
!
interface port-channel2
!
interface port-channel11
lacp min-links 2
!
interface port-channel13
switchport mode trunk
!
interface port-channel17
switchport mode trunk
!
interface port-channel20
!
interface port-channel33
description Hentammoo
load-interval counter 2 33
switchport access vlan 33
storm-control broadcast level 12.50
mtu 66
spanning-tree mst 33-35 cost 33
spanning-tree bpduguard enable
!
interface port-channel100
switchport mode trunk
!
interface port-channel1001
!
interface port-channel1002
!
interface port-channel1003
switchport mode trunk
!
interface port-channel1004
switchport mode trunk
!
router bgp 33
router-id 1.2.3.4
bestpath always-compare-med
cluster-id 1.2.3.4
confederation identifier 333
enforce-first-as
bgp as-local-count 33
bestpath compare-confed-aspath
maxas-limit 333
graceful-restart-helper
graceful-restart stalepath-time 333
timers bgp 333 3333
address-family ipv4 unicast
synchronization
network 0.0.0.0 backdoor
dampening 13 233 333 15 33
neighbor 10.241.107.40 remote-as 13
bfd
address-family ipv4 unicast
next-hop-self
!
route-map anil permit 10
!
ip arp timeout 1000
!
line con 0
line vty 0
exec-timeout 90 0
line vty 1 39
!
!
!
end

View file

@ -0,0 +1,6 @@
!
hostname foo
!
interface ethernet 1/13
speed 10000
!

View file

@ -0,0 +1,92 @@
--------------------------------------------------------------------------------
Ethernet PVID Type Mode Status Reason Speed Port
Interface NVLAN Ch#
--------------------------------------------------------------------------------
Ethernet1/1 33 eth access down Link not connected 10000 33
Ethernet1/2 1 eth access down Link not connected 10000 1001
Ethernet1/3 1 eth trunk down Link not connected 10000 1003
Ethernet1/4 1 eth trunk down Link not connected 10000 1004
Ethernet1/5 -- eth routed down Link not connected 10000 --
Ethernet1/6 -- eth routed down Link not connected 10000 --
Ethernet1/7 -- eth routed down Link not connected 10000 --
Ethernet1/8 -- eth routed down Link not connected 10000 --
Ethernet1/9 1 eth access down Link not connected 10000 --
Ethernet1/10 1 eth access down Link not connected 10000 --
Ethernet1/11 -- eth routed down Link not connected 10000 --
Ethernet1/12 -- eth routed down Link not connected 10000 --
Ethernet1/13 -- eth routed down Link not connected 10000 --
Ethernet1/14 1 eth access down Link not connected 10000 --
Ethernet1/15 1 eth access down Link not connected 10000 --
Ethernet1/16 1 eth access down Link not connected 10000 --
Ethernet1/17 1 eth access down Link not connected 10000 --
Ethernet1/18 1 eth access down Link not connected 10000 --
Ethernet1/19 1 eth access down Link not connected 10000 --
Ethernet1/20 1 eth access down Link not connected 10000 --
Ethernet1/21 1 eth access down Link not connected 10000 --
Ethernet1/22 1 eth access down Link not connected 10000 --
Ethernet1/23 1 eth access down Link not connected 10000 11
Ethernet1/24 1 eth access down Link not connected 10000 --
Ethernet1/25 1 eth access down Link not connected 10000 --
Ethernet1/26 1 eth access down Link not connected 10000 --
Ethernet1/27 1 eth access down Link not connected 10000 --
Ethernet1/28 1 eth access down Link not connected 10000 --
Ethernet1/29 1 eth access down Link not connected 10000 --
Ethernet1/30 1 eth access down Link not connected 10000 --
Ethernet1/31 1 eth access down Link not connected 10000 --
Ethernet1/32 1 eth access down Link not connected 10000 --
Ethernet1/33 33 eth access down Link not connected 10000 --
Ethernet1/34 1 eth access down Link not connected 10000 --
Ethernet1/35 1 eth access down Link not connected 10000 --
Ethernet1/36 1 eth access down Link not connected 10000 --
Ethernet1/37 1 eth access down Link not connected 10000 --
Ethernet1/38 1 eth access down Link not connected 10000 --
Ethernet1/39 1 eth access down Link not connected 10000 --
Ethernet1/40 1 eth access down Link not connected 10000 --
Ethernet1/41 1 eth access down Link not connected 10000 --
Ethernet1/42 1 eth access down Link not connected 10000 --
Ethernet1/43 1 eth access down Link not connected 10000 --
Ethernet1/44 1 eth access down Link not connected 10000 --
Ethernet1/45 1 eth access down Link not connected 10000 --
Ethernet1/46 1 eth access down Link not connected 10000 --
Ethernet1/47 1 eth access down Link not connected 10000 --
Ethernet1/48 1 eth access down Link not connected 10000 --
Ethernet1/49 1 eth access down Link not connected 40000 --
Ethernet1/50 1 eth access down Link not connected 40000 --
Ethernet1/51 1 eth access down Link not connected 40000 --
Ethernet1/52 1 eth access down Link not connected 40000 --
Ethernet1/53 1 eth access down Link not connected 40000 --
Ethernet1/54 1 eth access down Link not connected 40000 --
--------------------------------------------------------------------------------
Port-channel PVID Type Mode Status Reason Speed Protocol
Interface NVLAN
--------------------------------------------------------------------------------
po1 1 eth access down No link up members NA none
po2 1 eth access down No link up members NA none
po11 1 eth access down No link up members NA lacp
po13 1 eth trunk down No link up members NA none
po17 1 eth trunk down No link up members NA none
po20 1 eth access down No link up members NA none
po33 33 eth access down No link up members NA none
po100 1 eth trunk down No link up members NA none
po1001 1 eth access down No link up members NA lacp
po1002 1 eth access down No link up members NA none
po1003 1 eth trunk down No link up members NA lacp
po1004 1 eth trunk down No link up members NA lacp
--------------------------------------------------------------------------------
Port VRF Status IP Address Speed MTU
--------------------------------------------------------------------------------
mgmt0 management up 10.241.107.39 1000 1500
-------------------------------------------------------------------------------
Interface Secondary VLAN(Type) Status Reason
-------------------------------------------------------------------------------
Vlan1 -- down VLAN is down
--------------------------------------------------------------------------------
Interface Status Description
--------------------------------------------------------------------------------
loopback0 up --
loopback3 up --

View file

@ -0,0 +1,72 @@
--------------------------------------------------------------------------------
Interface Mac-Address Burn-in Mac-Address
--------------------------------------------------------------------------------
Ethernet1/1 a48c.db33.bc02 a48c.db33.bc02
Ethernet1/2 a48c.db33.bc03 a48c.db33.bc03
Ethernet1/3 a48c.db33.bc04 a48c.db33.bc04
Ethernet1/4 a48c.db33.bc05 a48c.db33.bc05
Ethernet1/5 a48c.db33.bc01 a48c.db33.bc06
Ethernet1/6 a48c.db33.bc01 a48c.db33.bc07
Ethernet1/7 a48c.db33.bc01 a48c.db33.bc08
Ethernet1/8 a48c.db33.bc01 a48c.db33.bc09
Ethernet1/9 a48c.db33.bc0a a48c.db33.bc0a
Ethernet1/10 a48c.db33.bc0b a48c.db33.bc0b
Ethernet1/11 a48c.db33.bc01 a48c.db33.bc0c
Ethernet1/12 a48c.db33.bc01 a48c.db33.bc0d
Ethernet1/13 a48c.db33.bc01 a48c.db33.bc0e
Ethernet1/14 a48c.db33.bc0f a48c.db33.bc0f
Ethernet1/15 a48c.db33.bc10 a48c.db33.bc10
Ethernet1/16 a48c.db33.bc11 a48c.db33.bc11
Ethernet1/17 a48c.db33.bc12 a48c.db33.bc12
Ethernet1/18 a48c.db33.bc13 a48c.db33.bc13
Ethernet1/19 a48c.db33.bc14 a48c.db33.bc14
Ethernet1/20 a48c.db33.bc15 a48c.db33.bc15
Ethernet1/21 a48c.db33.bc16 a48c.db33.bc16
Ethernet1/22 a48c.db33.bc17 a48c.db33.bc17
Ethernet1/23 a48c.db33.bc18 a48c.db33.bc18
Ethernet1/24 a48c.db33.bc19 a48c.db33.bc19
Ethernet1/25 a48c.db33.bc1a a48c.db33.bc1a
Ethernet1/26 a48c.db33.bc1b a48c.db33.bc1b
Ethernet1/27 a48c.db33.bc1c a48c.db33.bc1c
Ethernet1/28 a48c.db33.bc1d a48c.db33.bc1d
Ethernet1/29 a48c.db33.bc1e a48c.db33.bc1e
Ethernet1/30 a48c.db33.bc1f a48c.db33.bc1f
Ethernet1/31 a48c.db33.bc20 a48c.db33.bc20
Ethernet1/32 a48c.db33.bc21 a48c.db33.bc21
Ethernet1/33 a48c.db33.bc22 a48c.db33.bc22
Ethernet1/34 a48c.db33.bc23 a48c.db33.bc23
Ethernet1/35 a48c.db33.bc24 a48c.db33.bc24
Ethernet1/36 a48c.db33.bc25 a48c.db33.bc25
Ethernet1/37 a48c.db33.bc26 a48c.db33.bc26
Ethernet1/38 a48c.db33.bc27 a48c.db33.bc27
Ethernet1/39 a48c.db33.bc28 a48c.db33.bc28
Ethernet1/40 a48c.db33.bc29 a48c.db33.bc29
Ethernet1/41 a48c.db33.bc2a a48c.db33.bc2a
Ethernet1/42 a48c.db33.bc2b a48c.db33.bc2b
Ethernet1/43 a48c.db33.bc2c a48c.db33.bc2c
Ethernet1/44 a48c.db33.bc2d a48c.db33.bc2d
Ethernet1/45 a48c.db33.bc2e a48c.db33.bc2e
Ethernet1/46 a48c.db33.bc2f a48c.db33.bc2f
Ethernet1/47 a48c.db33.bc30 a48c.db33.bc30
Ethernet1/48 a48c.db33.bc31 a48c.db33.bc31
Ethernet1/49 a48c.db33.bc32 a48c.db33.bc32
Ethernet1/50 a48c.db33.bc33 a48c.db33.bc33
Ethernet1/51 a48c.db33.bc34 a48c.db33.bc34
Ethernet1/52 a48c.db33.bc35 a48c.db33.bc35
Ethernet1/53 a48c.db33.bc36 a48c.db33.bc36
Ethernet1/54 a48c.db33.bc37 a48c.db33.bc37
mgmt0 a48c.db33.bc00 a48c.db33.bc00
po1 0e00.0000.0001 (not set)
po2 0e00.0000.0002 (not set)
po11 a48c.db33.bc18 (not set)
po13 0e00.0000.0003 (not set)
po17 0e00.0000.0004 (not set)
po20 0e00.0000.0005 (not set)
po33 a48c.db33.bc02 (not set)
po100 0e00.0000.0006 (not set)
po1001 a48c.db33.bc03 (not set)
po1002 0e00.0000.0007 (not set)
po1003 a48c.db33.bc04 (not set)
po1004 a48c.db33.bc05 (not set)
Vlan1 a48c.db33.bc01 (not set)

View file

@ -0,0 +1,74 @@
--------------------------------------------------------------------------------
Port Name Status Vlan Duplex Speed Type
--------------------------------------------------------------------------------
Ethernet1/1 Link 1 to LP21 notconnec 33 full 10000 eth
Ethernet1/2 Link 2 to LP21 notconnec 1 full 10000 eth
Ethernet1/3 Link 1 to LP22 notconnec trunk full 10000 eth
Ethernet1/4 Link 2 to LP22 notconnec trunk full 10000 eth
Ethernet1/5 Link 1 to LP23 notconnec routed full 10000 eth
Ethernet1/6 Link 2 to LP23 notconnec routed full 10000 eth
Ethernet1/7 Link 1 to LP24 notconnec routed full 10000 eth
Ethernet1/8 Link 2 to LP24 notconnec routed full 10000 eth
Ethernet1/9 -- notconnec 1 full 10000 eth
Ethernet1/10 -- notconnec 1 full 10000 eth
Ethernet1/11 -- notconnec routed full 10000 eth
Ethernet1/12 -- notconnec routed full 10000 eth
Ethernet1/13 -- notconnec routed full 10000 eth
Ethernet1/14 -- notconnec 1 full 10000 eth
Ethernet1/15 -- notconnec 1 full 10000 eth
Ethernet1/16 -- notconnec 1 full 10000 eth
Ethernet1/17 -- notconnec 1 full 10000 eth
Ethernet1/18 -- notconnec 1 full 10000 eth
Ethernet1/19 -- notconnec 1 full 10000 eth
Ethernet1/20 -- notconnec 1 full 10000 eth
Ethernet1/21 -- notconnec 1 full 10000 eth
Ethernet1/22 -- notconnec 1 full 10000 eth
Ethernet1/23 -- notconnec 1 full 10000 eth
Ethernet1/24 -- notconnec 1 full 10000 eth
Ethernet1/25 -- notconnec 1 full 10000 eth
Ethernet1/26 -- notconnec 1 full 10000 eth
Ethernet1/27 -- notconnec 1 full 10000 eth
Ethernet1/28 -- notconnec 1 full 10000 eth
Ethernet1/29 -- notconnec 1 full 10000 eth
Ethernet1/30 -- notconnec 1 full 10000 eth
Ethernet1/31 -- notconnec 1 full 10000 eth
Ethernet1/32 -- notconnec 1 full 10000 eth
Ethernet1/33 Hentammoo notconnec 33 full 10000 eth
Ethernet1/34 -- notconnec 1 full 10000 eth
Ethernet1/35 -- notconnec 1 full 10000 eth
Ethernet1/36 -- notconnec 1 full 10000 eth
Ethernet1/37 -- notconnec 1 full 10000 eth
Ethernet1/38 -- notconnec 1 full 10000 eth
Ethernet1/39 -- notconnec 1 full 10000 eth
Ethernet1/40 -- notconnec 1 full 10000 eth
Ethernet1/41 -- notconnec 1 full 10000 eth
Ethernet1/42 -- notconnec 1 full 10000 eth
Ethernet1/43 -- notconnec 1 full 10000 eth
Ethernet1/44 -- notconnec 1 full 10000 eth
Ethernet1/45 -- notconnec 1 full 10000 eth
Ethernet1/46 -- notconnec 1 full 10000 eth
Ethernet1/47 -- notconnec 1 full 10000 eth
Ethernet1/48 -- notconnec 1 full 10000 eth
Ethernet1/49 -- notconnec 1 full 40000 eth
Ethernet1/50 -- notconnec 1 full 40000 eth
Ethernet1/51 -- notconnec 1 full 40000 eth
Ethernet1/52 -- notconnec 1 full 40000 eth
Ethernet1/53 -- notconnec 1 full 40000 eth
Ethernet1/54 -- notconnec 1 full 40000 eth
po1 -- notconnec 1 full NA eth
po2 -- notconnec 1 full NA eth
po11 -- notconnec 1 full NA eth
po13 -- notconnec trunk full NA eth
po17 -- notconnec trunk full NA eth
po20 -- notconnec 1 full NA eth
po33 Hentammoo notconnec 33 full NA eth
po100 -- notconnec trunk full NA eth
po1001 -- notconnec 1 full NA eth
po1002 -- notconnec 1 full NA eth
po1003 -- notconnec trunk full NA eth
po1004 -- notconnec trunk full NA eth
mgmt0 -- connected routed full 1000 eth
loopback0 -- connected routed half NA eth
loopback3 -- connected routed half NA eth
Vlan1 -- notconnec routed auto NA --

View file

@ -0,0 +1,10 @@
Interface IP-Address Admin-Status Link-Status VRF
Ethernet1/5 20.131.1.1 up down default
Ethernet1/6 20.131.2.1 up down default
Ethernet1/7 20.141.1.1 up down default
Ethernet1/8 20.141.2.1 up down default
Ethernet1/11 1.1.1.2 up down default
Ethernet1/12 100.10.10.10 up down default
Ethernet1/13 10.241.107.54 up down default
mgmt0 10.241.107.39 up up management

View file

@ -0,0 +1,5 @@
Interface IPv6 Address/Link-local Address Admin-Status Link-Status VRF
loopback0 fe80::200:ff:fe00:0 up up default
loopback3 fe80::200:ff:fe00:0 up up default
mgmt0 fe80::a68c:dbff:fe33:bc00 up up management

View file

@ -0,0 +1,8 @@
Capability codes:
(R) Router, (B) Bridge, (T) Telephone, (C) DOCSIS Cable Device
(W) WLAN Access Point, (P) Repeater, (S) Station, (O) Other
Device ID Local Intf Hold-time Capability Port ID
INDIA-LAB-1-C3750X.l... mgmt0 120 BR Gi1/0/30
Total entries displayed: 1

View file

@ -0,0 +1,38 @@
PID MemAlloc StkSize RSSMem LibMem StackBase/Ptr Process
----- -------- ---------- ------- ------- ------------------ ----------
1 6204 8388608 12312 5380 bff01bc0/bff01590 nsm
4 2608 8388608 5264 5312 bfa92080/bfa91ab0 ospfd
7 14152 8388608 5924 5284 bfaa7250/bfaa6c20 hostpd
10 2092 8388608 4652 5312 bfafcbf0/bfafc620 mribd
11 2024 8388608 3108 5284 bfb7c650/bfb7c080 pimd
14 2016 8388608 4896 5312 bff0ff10/bff0f940 lacpd
17 48608 8388608 36200 5312 bfc10e30/bfc10830 mstpd
24 2520 8388608 5340 5312 bf90ad00/bf90a730 onmd
26 228628 8388608 77312 5376 bfb34e10/bfb34830 hsl
28 2020 8388608 4784 5312 bff3c410/bff3be10 oam
39 21396 8388608 8184 5312 bf9b1a50/bf9b1460 vrrpd
40 2480 8388608 4064 5336 bfe5f020/bfe5ea20 ndd
42 2860 8388608 5672 5364 bfe83aa0/bfe83470 ribd
44 3528 8388608 7140 5328 bf90b720/bf90b110 bgpd
45 1772 8388608 4404 5312 bf9fc250/bf9fbc80 hostmibd
46 39564 8388608 25632 5428 bfe30db0/bfe30780 l2mribd
62 1876 8388608 3920 5312 bf81c210/bf81bc40 sysmgr
63 94380 8388608 13804 5292 bfcb67d0/bfcb61d0 nwvd
64 1920 8388608 5664 5676 bfc28470/bfc27ea0 ovsdbd
65 96548 8388608 55168 5292 bfdbcf80/bfdbc980 vlagd
66 1756 8388608 3808 5284 bfa15ab0/bfa154e0 slpd
71 2116 8388608 5880 10076 bfe8abd0/bfe8a600 npad
72 2220 8388608 5452 7936 bf9e6da0/bf9e67d0 hscd
73 1920 8388608 2760 5284 bfbc6cd0/bfbc6700 dhcpsnpd
74 58620 8388608 16168 9956 bfe1af70/bfe1a970 telemetryd
75 1756 8388608 3456 5284 bfb21da0/bfb217d0 securityd
76 2152 8388608 4216 5284 bfc36900/bfc36330 l2fd
77 1920 8388608 3876 5284 bf91e480/bf91dec0 sflowd
78 1888 8388608 3772 5284 bffd10c0/bffd0af0 qosd
69 70520 8388608 5584 5260 bfca0980/bfca0490 platform_mgr
70 26828 8388608 2116 2040 bfce09c0/bfce0440 service_mgr
total used free shared buff/cache available
Mem: 4081464 442136 3144092 153168 495236 3452732
Swap: 0 0 0

View file

@ -0,0 +1,331 @@
!
version "10.8.0.42"
!
hostname ip10-241-107-39
!
banner motd NMS India CNOS
banner motd NMS India CNOS G8272
!
clock timezone EDT 0 0
!
logging console 7
vrf context management
ip route 0.0.0.0/0 10.241.107.1
!
!
port-channel load-balance ethernet destination-mac
port-channel load-balance ethernet source-interface
feature telnet
ip domain-name labs.lenovo.com vrf management
ip domain-list labs.lenovo.com vrf management
ip name-server 10.241.104.120 vrf management
ip name-server 10.240.0.10 vrf management
ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf management
ip host ip10-241-107-39 10.241.107.39 vrf management
ip domain-name labs.lenovo.com vrf default
ip domain-list labs.lenovo.com vrf default
ip name-server 10.240.0.10 vrf default
ip name-server 10.241.104.120 vrf default
ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf default
ip host ip10-241-107-39 10.241.107.39 vrf default
ntp server 173.230.154.254 prefer
ntp server 97.127.86.33 prefer
ntp server 129.250.35.250 prefer
ntp server 174.136.103.130 prefer
ntp server 69.10.161.7 prefer
ntp server 96.226.123.196 prefer
ntp server 104.238.179.130 prefer
ntp server 108.61.73.244 prefer
ntp server 208.75.89.4 prefer
snmp-server community public group network-operator
snmp-server community private group network-admin
snmp-server contact Ralph
username admin role network-admin password encrypted $6$bJoWyEu/$9pzSgFPAKGRm1stpTCEl3I39htbjxiFCfhqiHag1NQiKHv/IiLQ2lYW0V3p7p72SgSmVHp38em9P9R/EdePpk/
logging server 10.241.107.231
logging server 10.241.107.222
feature restApi
ovsdb pki ovsdb_mgmt vrf management
ovsdb pki ovsdb_default vrf default
lacp system-priority 32769
vlag tier-id 313
vlag priority 1313
vlag isl port-channel 100
vlag hlthchk keepalive-attempts 5
vlag hlthchk peer-ip 1.2.3.4
vlag auto-recovery 266
vlag startup-delay 323
vlag enable
vlag instance 1 port-channel 1003
vlag instance 1 enable
vlag instance 2 port-channel 20
vlag instance 2 enable
vlag instance 12 port-channel 23
vlag instance 33 port-channel 333
vlag instance 33 enable
spanning-tree mode mst
telemetry heartbeat enabled interval 15
!
policy-map type control-plane copp-system-policy
class type control-plane copp-s-pvst-bpdu
police pps 500
class type control-plane copp-s-ecp
police pps 3000
class type control-plane copp-s-igmp
police pps 3000
!
vlan 1-2
no flood ipv4
!
vlan 3
!
vlan 5
!
vlan 12
!
vlan 13
name dave
!
vlan dot1q tag native egress-only
!
interface Ethernet1/1
description Link 1 to LP21
load-interval counter 2 33
switchport access vlan 33
storm-control broadcast level 12.50
mtu 66
channel-group 33 mode on
!
interface Ethernet1/2
description Link 2 to LP21
channel-group 1001 mode active
!
interface Ethernet1/3
description Link 1 to LP22
switchport mode trunk
channel-group 1003 mode active
!
interface Ethernet1/4
description Link 2 to LP22
switchport mode trunk
channel-group 1004 mode active
!
interface Ethernet1/5
description Link 1 to LP23
no switchport
ip address 20.131.1.1/30
!
interface Ethernet1/6
description Link 2 to LP23
no switchport
ip address 20.131.2.1/30
!
interface Ethernet1/7
description Link 1 to LP24
no switchport
ip address 20.141.1.1/30
!
interface Ethernet1/8
description Link 2 to LP24
no switchport
ip address 20.141.2.1/30
!
interface Ethernet1/9
!
interface Ethernet1/10
!
interface Ethernet1/11
no switchport
mtu 1402
ip address 1.1.1.2/8
!
interface Ethernet1/12
no switchport
ip address 100.10.10.10/24
!
interface Ethernet1/13
no switchport
ip address 10.241.107.54/24
vrrp 254
address 10.241.107.55
priority 254
no shutdown
ip arp timeout 1500
!
interface Ethernet1/14
!
interface Ethernet1/15
!
interface Ethernet1/16
!
interface Ethernet1/17
!
interface Ethernet1/18
!
interface Ethernet1/19
!
interface Ethernet1/20
!
interface Ethernet1/21
!
interface Ethernet1/22
!
interface Ethernet1/23
channel-group 11 mode active
lacp port-priority 32769
!
interface Ethernet1/24
!
interface Ethernet1/25
!
interface Ethernet1/26
!
interface Ethernet1/27
!
interface Ethernet1/28
!
interface Ethernet1/29
!
interface Ethernet1/30
!
interface Ethernet1/31
!
interface Ethernet1/32
!
interface Ethernet1/33
description Hentammoo
load-interval counter 2 33
switchport access vlan 33
storm-control broadcast level 12.50
mtu 66
microburst-detection enable threshold 25
lldp tlv-select max-frame-size
lacp port-priority 33
spanning-tree mst 33-35 cost 33
spanning-tree bpduguard enable
!
interface Ethernet1/34
!
interface Ethernet1/35
!
interface Ethernet1/36
!
interface Ethernet1/37
!
interface Ethernet1/38
!
interface Ethernet1/39
!
interface Ethernet1/40
!
interface Ethernet1/41
!
interface Ethernet1/42
!
interface Ethernet1/43
!
interface Ethernet1/44
!
interface Ethernet1/45
!
interface Ethernet1/46
!
interface Ethernet1/47
!
interface Ethernet1/48
!
interface Ethernet1/49
!
interface Ethernet1/50
!
interface Ethernet1/51
!
interface Ethernet1/52
!
interface Ethernet1/53
!
interface Ethernet1/54
!
interface loopback0
no switchport
!
interface mgmt0
no switchport
vrf member management
no ip address dhcp
ip address 10.241.107.39/24
no ipv6 address dhcp
!
interface Vlan1
no switchport
!
interface port-channel1
!
interface port-channel2
!
interface port-channel11
lacp min-links 2
!
interface port-channel13
switchport mode trunk
!
interface port-channel17
switchport mode trunk
!
interface port-channel20
!
interface port-channel33
description Hentammoo
load-interval counter 2 33
switchport access vlan 33
storm-control broadcast level 12.50
mtu 66
spanning-tree mst 33-35 cost 33
spanning-tree bpduguard enable
!
interface port-channel100
switchport mode trunk
!
interface port-channel1001
!
interface port-channel1002
!
interface port-channel1003
switchport mode trunk
!
interface port-channel1004
switchport mode trunk
!
router bgp 33
router-id 1.2.3.4
bestpath always-compare-med
cluster-id 1.2.3.4
confederation identifier 333
enforce-first-as
bgp as-local-count 33
bestpath compare-confed-aspath
maxas-limit 333
graceful-restart-helper
graceful-restart stalepath-time 333
timers bgp 333 3333
address-family ipv4 unicast
synchronization
network 0.0.0.0 backdoor
dampening 13 233 333 15 33
neighbor 10.241.107.40 remote-as 13
bfd
address-family ipv4 unicast
next-hop-self
!
route-map anil permit 10
!
ip arp timeout 1000
!
line con 0
line vty 0
exec-timeout 90 0
line vty 1 39
!
!
!
end

View file

@ -0,0 +1,331 @@
!
version "10.8.0.42"
!
hostname ip10-241-107-39
!
banner motd NMS India CNOS
banner motd NMS India CNOS G8272
!
clock timezone EDT 0 0
!
logging console 7
vrf context management
ip route 0.0.0.0/0 10.241.107.1
!
!
port-channel load-balance ethernet destination-mac
port-channel load-balance ethernet source-interface
feature telnet
ip domain-name labs.lenovo.com vrf management
ip domain-list labs.lenovo.com vrf management
ip name-server 10.241.104.120 vrf management
ip name-server 10.240.0.10 vrf management
ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf management
ip host ip10-241-107-39 10.241.107.39 vrf management
ip domain-name labs.lenovo.com vrf default
ip domain-list labs.lenovo.com vrf default
ip name-server 10.240.0.10 vrf default
ip name-server 10.241.104.120 vrf default
ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf default
ip host ip10-241-107-39 10.241.107.39 vrf default
ntp server 173.230.154.254 prefer
ntp server 97.127.86.33 prefer
ntp server 129.250.35.250 prefer
ntp server 174.136.103.130 prefer
ntp server 69.10.161.7 prefer
ntp server 96.226.123.196 prefer
ntp server 104.238.179.130 prefer
ntp server 108.61.73.244 prefer
ntp server 208.75.89.4 prefer
snmp-server community public group network-operator
snmp-server community private group network-admin
snmp-server contact Ralph
username admin role network-admin password encrypted $6$bJoWyEu/$9pzSgFPAKGRm1stpTCEl3I39htbjxiFCfhqiHag1NQiKHv/IiLQ2lYW0V3p7p72SgSmVHp38em9P9R/EdePpk/
logging server 10.241.107.231
logging server 10.241.107.222
feature restApi
ovsdb pki ovsdb_mgmt vrf management
ovsdb pki ovsdb_default vrf default
lacp system-priority 32769
vlag tier-id 313
vlag priority 1313
vlag isl port-channel 100
vlag hlthchk keepalive-attempts 5
vlag hlthchk peer-ip 1.2.3.4
vlag auto-recovery 266
vlag startup-delay 323
vlag enable
vlag instance 1 port-channel 1003
vlag instance 1 enable
vlag instance 2 port-channel 20
vlag instance 2 enable
vlag instance 12 port-channel 23
vlag instance 33 port-channel 333
vlag instance 33 enable
spanning-tree mode mst
telemetry heartbeat enabled interval 15
!
policy-map type control-plane copp-system-policy
class type control-plane copp-s-pvst-bpdu
police pps 500
class type control-plane copp-s-ecp
police pps 3000
class type control-plane copp-s-igmp
police pps 3000
!
vlan 1-2
no flood ipv4
!
vlan 3
!
vlan 5
!
vlan 12
!
vlan 13
name dave
!
vlan dot1q tag native egress-only
!
interface Ethernet1/1
description Link 1 to LP21
load-interval counter 2 33
switchport access vlan 33
storm-control broadcast level 12.50
mtu 66
channel-group 33 mode on
!
interface Ethernet1/2
description Link 2 to LP21
channel-group 1001 mode active
!
interface Ethernet1/3
description Link 1 to LP22
switchport mode trunk
channel-group 1003 mode active
!
interface Ethernet1/4
description Link 2 to LP22
switchport mode trunk
channel-group 1004 mode active
!
interface Ethernet1/5
description Link 1 to LP23
no switchport
ip address 20.131.1.1/30
!
interface Ethernet1/6
description Link 2 to LP23
no switchport
ip address 20.131.2.1/30
!
interface Ethernet1/7
description Link 1 to LP24
no switchport
ip address 20.141.1.1/30
!
interface Ethernet1/8
description Link 2 to LP24
no switchport
ip address 20.141.2.1/30
!
interface Ethernet1/9
!
interface Ethernet1/10
!
interface Ethernet1/11
no switchport
mtu 1402
ip address 1.1.1.2/8
!
interface Ethernet1/12
no switchport
ip address 100.10.10.10/24
!
interface Ethernet1/13
no switchport
ip address 10.241.107.54/24
vrrp 254
address 10.241.107.55
priority 254
no shutdown
ip arp timeout 1500
!
interface Ethernet1/14
!
interface Ethernet1/15
!
interface Ethernet1/16
!
interface Ethernet1/17
!
interface Ethernet1/18
!
interface Ethernet1/19
!
interface Ethernet1/20
!
interface Ethernet1/21
!
interface Ethernet1/22
!
interface Ethernet1/23
channel-group 11 mode active
lacp port-priority 32769
!
interface Ethernet1/24
!
interface Ethernet1/25
!
interface Ethernet1/26
!
interface Ethernet1/27
!
interface Ethernet1/28
!
interface Ethernet1/29
!
interface Ethernet1/30
!
interface Ethernet1/31
!
interface Ethernet1/32
!
interface Ethernet1/33
description Hentammoo
load-interval counter 2 33
switchport access vlan 33
storm-control broadcast level 12.50
mtu 66
microburst-detection enable threshold 25
lldp tlv-select max-frame-size
lacp port-priority 33
spanning-tree mst 33-35 cost 33
spanning-tree bpduguard enable
!
interface Ethernet1/34
!
interface Ethernet1/35
!
interface Ethernet1/36
!
interface Ethernet1/37
!
interface Ethernet1/38
!
interface Ethernet1/39
!
interface Ethernet1/40
!
interface Ethernet1/41
!
interface Ethernet1/42
!
interface Ethernet1/43
!
interface Ethernet1/44
!
interface Ethernet1/45
!
interface Ethernet1/46
!
interface Ethernet1/47
!
interface Ethernet1/48
!
interface Ethernet1/49
!
interface Ethernet1/50
!
interface Ethernet1/51
!
interface Ethernet1/52
!
interface Ethernet1/53
!
interface Ethernet1/54
!
interface loopback0
no switchport
!
interface mgmt0
no switchport
vrf member management
no ip address dhcp
ip address 10.241.107.39/24
no ipv6 address dhcp
!
interface Vlan1
no switchport
!
interface port-channel1
!
interface port-channel2
!
interface port-channel11
lacp min-links 2
!
interface port-channel13
switchport mode trunk
!
interface port-channel17
switchport mode trunk
!
interface port-channel20
!
interface port-channel33
description Hentammoo
load-interval counter 2 33
switchport access vlan 33
storm-control broadcast level 12.50
mtu 66
spanning-tree mst 33-35 cost 33
spanning-tree bpduguard enable
!
interface port-channel100
switchport mode trunk
!
interface port-channel1001
!
interface port-channel1002
!
interface port-channel1003
switchport mode trunk
!
interface port-channel1004
switchport mode trunk
!
router bgp 33
router-id 1.2.3.4
bestpath always-compare-med
cluster-id 1.2.3.4
confederation identifier 333
enforce-first-as
bgp as-local-count 33
bestpath compare-confed-aspath
maxas-limit 333
graceful-restart-helper
graceful-restart stalepath-time 333
timers bgp 333 3333
address-family ipv4 unicast
synchronization
network 0.0.0.0 backdoor
dampening 13 233 333 15 33
neighbor 10.241.107.40 remote-as 13
bfd
address-family ipv4 unicast
next-hop-self
!
route-map anil permit 10
!
ip arp timeout 1000
!
line con 0
line vty 0
exec-timeout 90 0
line vty 1 39
!
!
!
end

View file

@ -0,0 +1,62 @@
*** show boot ***
Current ZTP State: Enable
Current FLASH software:
active image: version 10.8.0.42, downloaded 09:40:15 EDT Mon May 7 2018
standby image: version 10.7.0.6, downloaded 11:02:12 EDT Thu Mar 29 2018
Uboot: version 10.7.0.6, downloaded 11:02:14 EDT Thu Mar 29 2018
ONIE: empty
Currently set to boot software active image
Current port mode: default mode
Next boot port mode: default mode
Currently scheduled reboot time: none
*** show env fan detail ***
Total Fan: 8
+--------+-----+-----------------+---------------+-------+--------+
| Module | Fan | Name | Air-Flow | Speed | Speed |
| Number | ID | | Direction | (%) | (RPM) |
+--------+-----+-----------------+---------------+-------+--------+
01 01 Fan1 Front-to-Back 23 4023
01 02 Fan2 Front-to-Back 23 4285
02 03 Fan3 Front-to-Back 23 4032
02 04 Fan4 Front-to-Back 23 4147
03 05 Fan5 Front-to-Back 23 4192
03 06 Fan6 Front-to-Back 23 4397
04 07 Fan7 Front-to-Back 23 4153
04 08 Fan8 Front-to-Back 23 4451
*** show env power ***
Total Power Supplies: 2
+----+-----------------+----------------+-----------------+------------------+
| ID | Name | Manufacturer | Model | State |
+----+-----------------+----------------+-----------------+------------------+
01 Power Supply 1 DELTA XXXXXXXXXX Normal ON
02 Power Supply 2 DELTA XXXXXXXXXX 12V Output Fault
*** show env temperature ***
+----+------------------+----------+--------+
| ID | Name | Temp | State |
| | | (Celsius)| |
+----+------------------+----------+--------+
01 CPU Local 32 OK
02 Ambient 31 OK
03 Hot Spot 47 OK
System Name : G8272
System Description : G8272 ("48x10GE + 6x40GE")
System Model : Lenovo RackSwitch G8272
System VPD Version : 3
System Manufacture Date : 1542 (YYWW)
System Part Number : 00CJ066
System Serial Number : Y052MV59Y052
System FRU Number : 00FM430
System Machine Type Model : 7159-HCV
System Machine Serial Number : MM11945
System Hardware Revision : 1
System Management MAC : A4:8C:DB:33:BC:00
System Software Revision : 10.8.0.42

View file

@ -0,0 +1,19 @@
Lenovo Networking Operating System (NOS) Software
Technical Assistance Center: http://www.lenovo.com
Copyright (C) Lenovo, 2016. All rights reserved.
Software:
Bootloader version: 10.7.0.6
System version: 10.8.0.42
System compile time: May 03 11:06:25 PDT 2018
Hardware:
G8272 ("48x10GE + 6x40GE")
NXP P2020 CPU with 4096 MB of memory
Device name: ip10-241-107-39
Boot Flash: 16 MB
Kernel uptime is 2 day(s), 21 hour(s), 26 minute(s), 14 second(s)
Last Reset Reason: Reset by CLI reload command

View file

@ -0,0 +1,106 @@
# Copyright (C) 2017 Lenovo, 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/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
from ansible.compat.tests.mock import patch
from ansible.modules.network.cnos import cnos_command
from units.modules.utils import set_module_args
from .cnos_module import TestCnosModule, load_fixture
class TestCnosCommandModule(TestCnosModule):
module = cnos_command
def setUp(self):
super(TestCnosCommandModule, self).setUp()
self.mock_run_commands = patch('ansible.modules.network.cnos.cnos_command.run_commands')
self.run_commands = self.mock_run_commands.start()
def tearDown(self):
super(TestCnosCommandModule, 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:
command = item
except ValueError:
command = 'display version'
filename = str(command).replace(' ', '_')
output.append(load_fixture(filename))
return output
self.run_commands.side_effect = load_from_file
def test_cnos_command_simple(self):
set_module_args(dict(commands=['display version']))
result = self.execute_module()
self.assertEqual(len(result['stdout']), 1)
self.assertTrue(result['stdout'][0].startswith('Lenovo Networking Operating System (NOS) Software'))
def test_cnos_command_multiple(self):
set_module_args(dict(commands=['display version', 'display running-config']))
result = self.execute_module()
self.assertEqual(len(result['stdout']), 2)
self.assertTrue(result['stdout'][0].startswith('Lenovo Networking Operating System (NOS) Software'))
def test_cnos_command_wait_for(self):
wait_for = 'result[0] contains "Lenovo Networking Operating System (NOS) Software"'
set_module_args(dict(commands=['display version'], wait_for=wait_for))
self.execute_module()
def test_cnos_command_wait_for_fails(self):
wait_for = 'result[0] contains "test string"'
set_module_args(dict(commands=['display version'], wait_for=wait_for))
self.execute_module(failed=True)
self.assertEqual(self.run_commands.call_count, 10)
def test_cnos_command_retries(self):
wait_for = 'result[0] contains "test string"'
set_module_args(dict(commands=['display version'], wait_for=wait_for, retries=2))
self.execute_module(failed=True)
self.assertEqual(self.run_commands.call_count, 2)
def test_cnos_command_match_any(self):
wait_for = ['result[0] contains "Lenovo Networking Operating System (NOS) Software"',
'result[0] contains "test string"']
set_module_args(dict(commands=['display version'], wait_for=wait_for, match='any'))
self.execute_module()
def test_cnos_command_match_all(self):
wait_for = ['result[0] contains "Lenovo Networking Operating System (NOS) Software"',
'result[0] contains "Lenovo"']
set_module_args(dict(commands=['display version'], wait_for=wait_for, match='all'))
self.execute_module()
def test_cnos_command_match_all_failure(self):
wait_for = ['result[0] contains "Lenovo ENOS"',
'result[0] contains "test string"']
commands = ['display version', 'display run']
set_module_args(dict(commands=commands, wait_for=wait_for, match='all'))
self.execute_module(failed=True)

View file

@ -0,0 +1,125 @@
#
# (c) 2016 Red Hat 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/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
from ansible.compat.tests.mock import patch
from ansible.modules.network.cnos import cnos_config
from .cnos_module import TestCnosModule, load_fixture, set_module_args
class TestCnosConfigModule(TestCnosModule):
module = cnos_config
def setUp(self):
self.patcher_get_config = patch('ansible.modules.network.cnos.cnos_config.get_config')
self.mock_get_config = self.patcher_get_config.start()
self.patcher_exec_command = patch('ansible.modules.network.cnos.cnos_config.load_config')
self.mock_exec_command = self.patcher_exec_command.start()
def tearDown(self):
self.patcher_get_config.stop()
self.patcher_exec_command.stop()
def load_fixtures(self, commands=None):
config_file = 'cnos_config_config.cfg'
self.mock_get_config.return_value = load_fixture(config_file)
self.mock_exec_command.return_value = 'dummy diff'
def test_cnos_config_unchanged(self):
src = load_fixture('cnos_config_config.cfg')
set_module_args(dict(src=src))
self.execute_module()
def test_cnos_config_src(self):
src = load_fixture('cnos_config_src.cfg')
set_module_args(dict(src=src))
commands = ['hostname foo', 'interface ethernet 1/13',
'speed 10000']
self.execute_module(changed=True, commands=commands)
def test_cnos_config_backup(self):
set_module_args(dict(backup=True))
result = self.execute_module()
self.assertIn('__backup__', result)
def test_cnos_config_lines_wo_parents(self):
set_module_args(dict(lines=['hostname foo']))
commands = ['hostname foo']
self.execute_module(changed=True, commands=commands)
def test_cnos_config_lines_w_parents(self):
set_module_args(dict(lines=['shutdown'], parents=['interface ethernet 1/13']))
commands = ['interface ethernet 1/13', 'shutdown']
self.execute_module(changed=True, commands=commands)
def test_cnos_config_before(self):
set_module_args(dict(lines=['hostname foo'], before=['test1', 'test2']))
commands = ['test1', 'test2', 'hostname foo']
self.execute_module(changed=True, commands=commands, sort=False)
def test_cnos_config_after(self):
set_module_args(dict(lines=['hostname foo'], after=['test1', 'test2']))
commands = ['hostname foo', 'test1', 'test2']
self.execute_module(changed=True, commands=commands, sort=False)
def test_cnos_config_before_after_no_change(self):
set_module_args(dict(lines=['hostname ip10-241-107-39'],
before=['test1', 'test2'],
after=['test2', 'test3']))
self.execute_module()
def test_cnos_config_config(self):
config = 'hostname localhost'
set_module_args(dict(lines=['hostname ip10-241-107-39'], config=config))
commands = ['hostname ip10-241-107-39']
self.execute_module(changed=True, commands=commands)
def test_cnos_config_replace_block(self):
lines = ['description test string', 'test string']
parents = ['interface ethernet 1/13']
set_module_args(dict(lines=lines, replace='block', parents=parents))
commands = parents + lines
self.execute_module(changed=True, commands=commands)
def test_cnos_config_match_none(self):
lines = ['ip address 1.2.3.4 255.255.255.0', 'description test string']
parents = ['interface ethernet 1/13']
set_module_args(dict(lines=lines, parents=parents, match='none'))
commands = parents + lines
self.execute_module(changed=True, commands=commands, sort=False)
def test_cnos_config_match_strict(self):
lines = ['ip address 100.10.10.10/24', 'no switchport']
parents = ['interface Ethernet1/12']
set_module_args(dict(lines=lines, parents=parents, match='strict'))
commands = parents + ['no switchport']
self.execute_module(changed=True, commands=commands, sort=False)
def test_cnos_config_match_exact(self):
lines = ['ip address 1.2.3.4 255.255.255.0', 'description test string',
'no shutdown']
parents = ['interface ethernet 1/13']
set_module_args(dict(lines=lines, parents=parents, match='exact'))
commands = parents + lines
self.execute_module(changed=True, commands=commands, sort=False)

View file

@ -0,0 +1,82 @@
# (c) 2016 Red Hat 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/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
from ansible.compat.tests.mock import patch
from .cnos_module import TestCnosModule, load_fixture
from ansible.modules.network.cnos import cnos_facts
from units.modules.utils import set_module_args
class TestCnosFacts(TestCnosModule):
module = cnos_facts
def setUp(self):
super(TestCnosFacts, self).setUp()
self.mock_run_commands = patch(
'ansible.modules.network.cnos.cnos_facts.run_commands')
self.run_commands = self.mock_run_commands.start()
def tearDown(self):
super(TestCnosFacts, 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 = obj['command']
except ValueError:
command = item
filename = str(command).replace(' ', '_')
filename = filename.replace('/', '7')
output.append(load_fixture(filename))
return output
self.run_commands.side_effect = load_from_file
def test_cnos_facts_gather_subset_default(self):
set_module_args(dict())
result = self.execute_module()
ansible_facts = result['ansible_facts']
self.assertIn('hardware', ansible_facts['ansible_net_gather_subset'])
self.assertIn('default', ansible_facts['ansible_net_gather_subset'])
self.assertIn('interfaces', ansible_facts['ansible_net_gather_subset'])
self.assertEquals('ip10-241-107-39', ansible_facts['ansible_net_hostname'])
self.assertIn('Ethernet1/1', ansible_facts['ansible_net_interfaces'].keys())
self.assertEquals(3985.8046875, ansible_facts['ansible_net_memtotal_mb'])
self.assertEquals(3070.40234375, ansible_facts['ansible_net_memfree_mb'])
def test_cnos_facts_gather_subset_config(self):
set_module_args({'gather_subset': 'config'})
result = self.execute_module()
ansible_facts = result['ansible_facts']
self.assertIn('default', ansible_facts['ansible_net_gather_subset'])
self.assertIn('config', ansible_facts['ansible_net_gather_subset'])
self.assertEquals('ip10-241-107-39', ansible_facts['ansible_net_hostname'])
self.assertIn('ansible_net_config', ansible_facts)