mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
New enos_facts, + module_utils/enos.py. modifying copyright year in rest all (#31696)
* Squashing all commits to one as suggested by John * Adding Unit test method for the module enos_facts.py * Pep8 and Ylint issues addressed * Trying again to remove blank line. Some scripts are required for this. * Bug Fixing for interfaces * Editing for over indenting issue * E203 whitespace before ',' * Update enos.py Added warnings argument as to check_args method * Update enos_facts.py Added warnings to check_args method
This commit is contained in:
parent
e5dbf63b65
commit
9d98452032
16 changed files with 1330 additions and 3 deletions
162
lib/ansible/module_utils/enos.py
Normal file
162
lib/ansible/module_utils/enos.py
Normal file
|
@ -0,0 +1,162 @@
|
|||
# This code is part of Ansible, but is an independent component.
|
||||
# This particular file snippet, and this file snippet only, is BSD licensed.
|
||||
# Modules you write using this snippet, which is embedded dynamically by
|
||||
# Ansible still belong to the author of the module, and may assign their own
|
||||
# license to the complete work.
|
||||
#
|
||||
# Copyright (C) 2017 Lenovo, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Contains utility methods
|
||||
# Lenovo Networking
|
||||
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.basic import env_fallback, return_values
|
||||
from ansible.module_utils.network_common import to_list, EntityCollection
|
||||
from ansible.module_utils.connection import Connection, exec_command
|
||||
|
||||
_DEVICE_CONFIGS = {}
|
||||
_CONNECTION = None
|
||||
|
||||
enos_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()
|
||||
}
|
||||
|
||||
enos_argument_spec = {
|
||||
'provider': dict(type='dict', options=enos_provider_spec),
|
||||
}
|
||||
|
||||
command_spec = {
|
||||
'command': dict(key=True),
|
||||
'prompt': dict(),
|
||||
'answer': dict()
|
||||
}
|
||||
|
||||
|
||||
def get_provider_argspec():
|
||||
return enos_provider_spec
|
||||
|
||||
|
||||
def check_args(module, warnings):
|
||||
pass
|
||||
|
||||
|
||||
def get_connection(module):
|
||||
global _CONNECTION
|
||||
if _CONNECTION:
|
||||
return _CONNECTION
|
||||
_CONNECTION = Connection(module)
|
||||
|
||||
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 = module.params['passwords']
|
||||
if passwords:
|
||||
cmd = 'more system:running-config'
|
||||
else:
|
||||
cmd = 'show 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):
|
||||
assert isinstance(commands, list), '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)
|
||||
|
||||
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):
|
||||
conn = get_connection(module)
|
||||
conn.edit_config(config)
|
||||
|
||||
|
||||
def get_defaults_flag(module):
|
||||
rc, out, err = exec_command(module, 'show 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'
|
488
lib/ansible/modules/network/enos/enos_facts.py
Normal file
488
lib/ansible/modules/network/enos/enos_facts.py
Normal file
|
@ -0,0 +1,488 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
# Module to Collect facts from Lenovo Switches running Lenovo ENOS commands
|
||||
# Lenovo Networking
|
||||
#
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: enos_facts
|
||||
version_added: "2.5"
|
||||
author: "Anil Kumar Muraleedharan (@amuraleedhar)"
|
||||
short_description: Collect facts from remote devices running Lenovo ENOS
|
||||
description:
|
||||
- Collects a base set of device facts from a remote Lenovo device
|
||||
running on ENOS. This module prepends all of the
|
||||
base network fact keys with C(ansible_net_<fact>). The facts
|
||||
module will always collect a base set of facts from the device
|
||||
and can enable or disable collection of additional facts.
|
||||
extends_documentation_fragment: enos
|
||||
notes:
|
||||
- Tested against ENOS 8.4.1.68
|
||||
options:
|
||||
gather_subset:
|
||||
description:
|
||||
- When supplied, this argument will restrict the facts collected
|
||||
to a given subset. Possible values for this argument include
|
||||
all, hardware, config, and interfaces. Can specify a list of
|
||||
values to include a larger subset. Values can also be used
|
||||
with an initial C(M(!)) to specify that a specific subset should
|
||||
not be collected.
|
||||
required: false
|
||||
default: '!config'
|
||||
'''
|
||||
EXAMPLES = '''
|
||||
Tasks: The following are examples of using the module enos_facts.
|
||||
---
|
||||
- name: Test Enos Facts
|
||||
enos_facts:
|
||||
provider={{ cli }}
|
||||
|
||||
vars:
|
||||
cli:
|
||||
host: "{{ inventory_hostname }}"
|
||||
port: 22
|
||||
username: admin
|
||||
password: admin
|
||||
transport: cli
|
||||
timeout: 30
|
||||
authorize: True
|
||||
auth_pass:
|
||||
|
||||
---
|
||||
# Collect all facts from the device
|
||||
- enos_facts:
|
||||
gather_subset: all
|
||||
provider: "{{ cli }}"
|
||||
|
||||
# Collect only the config and default facts
|
||||
- enos_facts:
|
||||
gather_subset:
|
||||
- config
|
||||
provider: "{{ cli }}"
|
||||
|
||||
# Do not collect hardware facts
|
||||
- enos_facts:
|
||||
gather_subset:
|
||||
- "!hardware"
|
||||
provider: "{{ cli }}"
|
||||
|
||||
'''
|
||||
RETURN = '''
|
||||
ansible_net_gather_subset:
|
||||
description: The list of fact subsets collected from the device
|
||||
returned: always
|
||||
type: list
|
||||
# default
|
||||
ansible_net_model:
|
||||
description: The model name returned from the Lenovo ENOS device
|
||||
returned: always
|
||||
type: str
|
||||
ansible_net_serialnum:
|
||||
description: The serial number of the Lenovo ENOS device
|
||||
returned: always
|
||||
type: str
|
||||
ansible_net_version:
|
||||
description: The ENOS 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 re
|
||||
|
||||
from ansible.module_utils.enos import run_commands, enos_argument_spec, check_args
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
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 = ['show version', 'show run']
|
||||
|
||||
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):
|
||||
match = re.search(r'^Software Version (.*?) ', data, re.M | re.I)
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
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):
|
||||
# match = re.search(r'^Cisco (.+) \(revision', data, re.M)
|
||||
match = re.search(r'^Lenovo RackSwitch (\S+)', data, re.M | re.I)
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
def parse_image(self, data):
|
||||
match = re.search(r'(.*) image1(.*)', data, re.M | re.I)
|
||||
if match:
|
||||
return "Image1"
|
||||
else:
|
||||
return "Image2"
|
||||
|
||||
def parse_serialnum(self, data):
|
||||
# match = re.search(r'board ID (\S+)', data)
|
||||
match = re.search(r'^Switch Serial No: (\S+)', data, re.M | re.I)
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
|
||||
class Hardware(FactsBase):
|
||||
|
||||
COMMANDS = [
|
||||
'show system memory'
|
||||
]
|
||||
|
||||
def populate(self):
|
||||
super(Hardware, self).populate()
|
||||
data = self.responses[0]
|
||||
if data:
|
||||
self.facts['memtotal_mb'] = self.parse_memtotal(data)
|
||||
self.facts['memfree_mb'] = self.parse_memfree(data)
|
||||
|
||||
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 = ['show running-config']
|
||||
|
||||
def populate(self):
|
||||
super(Config, self).populate()
|
||||
data = self.responses[0]
|
||||
if data:
|
||||
self.facts['config'] = data
|
||||
|
||||
|
||||
class Interfaces(FactsBase):
|
||||
|
||||
COMMANDS = ['show interface status']
|
||||
|
||||
def populate(self):
|
||||
super(Interfaces, self).populate()
|
||||
|
||||
self.facts['all_ipv4_addresses'] = list()
|
||||
self.facts['all_ipv6_addresses'] = list()
|
||||
|
||||
data1 = self.run(['show interface status'])
|
||||
data1 = to_text(data1, errors='surrogate_or_strict').strip()
|
||||
data1 = data1.replace(r"\n", "\n")
|
||||
data2 = self.run(['show lldp port'])
|
||||
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(['show lldp remote-device port'])
|
||||
data3 = to_text(data3, errors='surrogate_or_strict').strip()
|
||||
data3 = data3.replace(r"\n", "\n")
|
||||
|
||||
lines3 = None
|
||||
if data3:
|
||||
lines3 = self.parse_neighbors(data3)
|
||||
if lines3 is not None:
|
||||
self.facts['neighbors'] = self.populate_neighbors(lines3)
|
||||
|
||||
data4 = self.run(['show interface ip'])
|
||||
data4 = data4[0].split('\n')
|
||||
lines4 = None
|
||||
if data4:
|
||||
lines4 = self.parse_ipaddresses(data4)
|
||||
ipv4_interfaces = self.set_ipv4_interfaces(lines4)
|
||||
self.facts['all_ipv4_addresses'] = ipv4_interfaces
|
||||
ipv6_interfaces = self.set_ipv6_interfaces(lines4)
|
||||
self.facts['all_ipv6_addresses'] = ipv6_interfaces
|
||||
|
||||
def parse_ipaddresses(self, data4):
|
||||
parsed = list()
|
||||
for line in data4:
|
||||
if len(line) == 0:
|
||||
continue
|
||||
else:
|
||||
line = line.strip()
|
||||
if len(line) == 0:
|
||||
continue
|
||||
match = re.search(r'IP4', line, re.M | re.I)
|
||||
if match:
|
||||
key = match.group()
|
||||
parsed.append(line)
|
||||
match = re.search(r'IP6', line, re.M | re.I)
|
||||
if match:
|
||||
key = match.group()
|
||||
parsed.append(line)
|
||||
return parsed
|
||||
|
||||
def set_ipv4_interfaces(self, line4):
|
||||
ipv4_addresses = list()
|
||||
for line in line4:
|
||||
ipv4Split = line.split()
|
||||
if ipv4Split[1] == "IP4":
|
||||
ipv4_addresses.append(ipv4Split[2])
|
||||
return ipv4_addresses
|
||||
|
||||
def set_ipv6_interfaces(self, line4):
|
||||
ipv6_addresses = list()
|
||||
for line in line4:
|
||||
ipv6Split = line.split()
|
||||
if ipv6Split[1] == "IP6":
|
||||
ipv6_addresses.append(ipv6Split[2])
|
||||
return ipv6_addresses
|
||||
|
||||
def populate_neighbors(self, lines3):
|
||||
neighbors = dict()
|
||||
for line in lines3:
|
||||
neighborSplit = line.split("|")
|
||||
innerData = dict()
|
||||
innerData['Remote Chassis ID'] = neighborSplit[2].strip()
|
||||
innerData['Remote Port'] = neighborSplit[3].strip()
|
||||
sysName = neighborSplit[4].strip()
|
||||
if sysName is not None:
|
||||
innerData['Remote System Name'] = neighborSplit[4].strip()
|
||||
else:
|
||||
innerData['Remote System Name'] = "NA"
|
||||
neighbors[neighborSplit[0].strip()] = innerData
|
||||
return neighbors
|
||||
|
||||
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[6].strip()
|
||||
innerData['macaddress'] = intfSplit[8].strip()
|
||||
innerData['mtu'] = intfSplit[9].strip()
|
||||
innerData['speed'] = intfSplit[1].strip()
|
||||
innerData['duplex'] = intfSplit[2].strip()
|
||||
innerData['operstatus'] = intfSplit[5].strip()
|
||||
interfaces[intfSplit[0].strip()] = innerData
|
||||
return interfaces
|
||||
|
||||
def parse_neighbors(self, neighbors):
|
||||
parsed = list()
|
||||
for line in neighbors.split('\n'):
|
||||
if len(line) == 0:
|
||||
continue
|
||||
else:
|
||||
line = line.strip()
|
||||
match = re.match(r'^([0-9]+)', line)
|
||||
if match:
|
||||
key = match.group(1)
|
||||
parsed.append(line)
|
||||
match = re.match(r'^(MGT+)', line)
|
||||
if match:
|
||||
key = match.group(1)
|
||||
parsed.append(line)
|
||||
return parsed
|
||||
|
||||
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'^([0-9]+)', line)
|
||||
if match:
|
||||
key = match.group(1)
|
||||
parsed.append(line)
|
||||
match = re.match(r'^(MGT+)', line)
|
||||
if match:
|
||||
key = match.group(1)
|
||||
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():
|
||||
"""main entry point for module execution
|
||||
"""
|
||||
argument_spec = dict(
|
||||
gather_subset=dict(default=['!config'], type='list')
|
||||
)
|
||||
|
||||
argument_spec.update(enos_argument_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
gather_subset = module.params['gather_subset']
|
||||
|
||||
runable_subsets = set()
|
||||
exclude_subsets = set()
|
||||
|
||||
for subset in gather_subset:
|
||||
if subset == 'all':
|
||||
runable_subsets.update(VALID_SUBSETS)
|
||||
continue
|
||||
|
||||
if subset.startswith('!'):
|
||||
subset = subset[1:]
|
||||
if subset == 'all':
|
||||
exclude_subsets.update(VALID_SUBSETS)
|
||||
continue
|
||||
exclude = True
|
||||
else:
|
||||
exclude = False
|
||||
|
||||
if subset not in VALID_SUBSETS:
|
||||
module.fail_json(msg='Bad subset')
|
||||
|
||||
if exclude:
|
||||
exclude_subsets.add(subset)
|
||||
else:
|
||||
runable_subsets.add(subset)
|
||||
|
||||
if not runable_subsets:
|
||||
runable_subsets.update(VALID_SUBSETS)
|
||||
|
||||
runable_subsets.difference_update(exclude_subsets)
|
||||
runable_subsets.add('default')
|
||||
|
||||
facts = dict()
|
||||
facts['gather_subset'] = list(runable_subsets)
|
||||
|
||||
instances = list()
|
||||
for key in runable_subsets:
|
||||
instances.append(FACT_SUBSETS[key](module))
|
||||
|
||||
for inst in instances:
|
||||
inst.populate()
|
||||
facts.update(inst.facts)
|
||||
|
||||
ansible_facts = dict()
|
||||
for key, value in iteritems(facts):
|
||||
key = 'ansible_net_%s' % key
|
||||
ansible_facts[key] = value
|
||||
|
||||
warnings = list()
|
||||
check_args(module, warnings)
|
||||
|
||||
module.exit_json(ansible_facts=ansible_facts, warnings=warnings)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -4,7 +4,7 @@
|
|||
# Ansible still belong to the author of the module, and may assign their own
|
||||
# license to the complete work.
|
||||
#
|
||||
# Copyright (C) 2018 Lenovo, Inc.
|
||||
# Copyright (C) 2017 Lenovo, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# Ansible still belong to the author of the module, and may assign their own
|
||||
# license to the complete work.
|
||||
#
|
||||
# Copyright (C) 2018 Lenovo, Inc.
|
||||
# Copyright (C) 2017 Lenovo, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# Ansible still belong to the author of the module, and may assign their own
|
||||
# license to the complete work.
|
||||
#
|
||||
# Copyright (C) 2018 Lenovo, Inc.
|
||||
# Copyright (C) 2017 Lenovo, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
|
0
test/units/modules/network/enos/__init__.py
Normal file
0
test/units/modules/network/enos/__init__.py
Normal file
114
test/units/modules/network/enos/enos_module.py
Normal file
114
test/units/modules/network/enos/enos_module.py
Normal file
|
@ -0,0 +1,114 @@
|
|||
# (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 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 TestEnosModule(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
|
|
@ -0,0 +1,9 @@
|
|||
Interface information:
|
||||
1: IP4 192.168.49.50 255.255.255.0 192.168.49.255, vlan 1, up
|
||||
128: IP4 10.241.105.24 255.255.255.0 10.241.105.255, vlan 4095, up
|
||||
|
||||
Routed Port Interface Information:
|
||||
|
||||
Loopback interface information:
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
-----------------------------------------------------------------------
|
||||
Port Speed Duplex Flow Ctrl Link Description
|
||||
------- ------ -------- --TX-----RX-- ------ -------------
|
||||
1 1G/10G full no no down 1
|
||||
2 1G/10G full no no down 2
|
||||
3 1G/10G full no no down 3
|
||||
4 1G/10G full no no down 4
|
||||
5 1G/10G full no no down 5
|
||||
6 1G/10G full no no down 6
|
||||
7 1G/10G full no no down 7
|
||||
8 1G/10G full no no down 8
|
||||
9 1G/10G full no no down 9
|
||||
10 1G/10G full no no down 10
|
||||
11 1G/10G full no no down 11
|
||||
12 1G/10G full no no down 12
|
||||
13 1G/10G full no no down 13
|
||||
14 1G/10G full no no down 14
|
||||
15 1G/10G full no no down 15
|
||||
16 1G/10G full no no down 16
|
||||
17 1G/10G full no no down 17
|
||||
18 1G/10G full no no down 18
|
||||
19 1G/10G full no no down 19
|
||||
20 1G/10G full no no down 20
|
||||
21 1G/10G full no no down 21
|
||||
22 1G/10G full no no down 22
|
||||
23 1G/10G full no no down 23
|
||||
24 1G/10G full no no down 24
|
||||
25 1G/10G full no no down 25
|
||||
26 1G/10G full no no down 26
|
||||
27 1G/10G full no no down 27
|
||||
28 1G/10G full no no down 28
|
||||
29 1G/10G full no no down 29
|
||||
30 1G/10G full no no down 30
|
||||
31 1G/10G full no no down 31
|
||||
32 1G/10G full no no down 32
|
||||
33 1G/10G full no no down 33
|
||||
34 1G/10G full no no down 34
|
||||
35 1G/10G full no no down 35
|
||||
36 1G/10G full no no down 36
|
||||
37 1G/10G full no no down 37
|
||||
38 1000 full no no up 38
|
||||
39 1G/10G full no no down 39
|
||||
40 1G/10G full no no down 40
|
||||
41 1G/10G full no no down 41
|
||||
42 1G/10G full no no down 42
|
||||
43 1G/10G full no no down 43
|
||||
44 1G/10G full no no down 44
|
||||
45 1G/10G full no no down 45
|
||||
46 1G/10G full no no down 46
|
||||
47 1G/10G full no no down 47
|
||||
48 10000 full no no down 48
|
||||
49 40000 full no no down 49
|
||||
50 40000 full no no down 50
|
||||
51 40000 full no no down 51
|
||||
52 40000 full no no down 52
|
||||
53 40000 full no no down 53
|
||||
54 40000 full no no down 54
|
||||
MGT 1000 full yes yes up MGT
|
||||
|
60
test/units/modules/network/enos/fixtures/show_lldp_port
Normal file
60
test/units/modules/network/enos/fixtures/show_lldp_port
Normal file
|
@ -0,0 +1,60 @@
|
|||
LLDP Port Info
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Port MAC address MTU PortEnabled AdminStatus RxChange TrapNotify
|
||||
======= ================= ==== =========== =========== ======== ==========
|
||||
1 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
2 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
3 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
4 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
5 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
6 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
7 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
8 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
9 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
10 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
11 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
12 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
13 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
14 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
15 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
16 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
17 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
18 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
19 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
20 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
21 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
22 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
23 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
24 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
25 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
26 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
27 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
28 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
29 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
30 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
31 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
32 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
33 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
34 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
35 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
36 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
37 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
38 a8:97:dc:dd:e2:00 9216 enabled tx_rx no disabled
|
||||
39 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
40 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
41 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
42 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
43 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
44 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
45 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
46 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
47 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
48 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
49 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
50 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
51 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
52 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
53 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
54 a8:97:dc:dd:e2:00 9216 disabled tx_rx no disabled
|
||||
MGT a8:97:dc:dd:e2:fe 9216 enabled tx_rx no disabled
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
LLDP Remote Devices Information
|
||||
Legend(possible values in DMAC column) :
|
||||
NB - Nearest Bridge - 01-80-C2-00-00-0E
|
||||
NnTB - Nearest non-TPMR Bridge - 01-80-C2-00-00-03
|
||||
NCB - Nearest Customer Bridge - 01-80-C2-00-00-00
|
||||
Total number of current entries: 1
|
||||
|
||||
LocalPort | Index | Remote Chassis ID | Remote Port | Remote System Name | DMAC
|
||||
----------|-------|---------------------------|----------------------|-------------------------------|---------
|
||||
MGT | 1 | 74 26 ac 3d 3c c0 | Gi3/18 | INDIA-LAB-1-C4506E-A.labs.l...| NB
|
||||
|
||||
|
59
test/units/modules/network/enos/fixtures/show_run
Normal file
59
test/units/modules/network/enos/fixtures/show_run
Normal file
|
@ -0,0 +1,59 @@
|
|||
Current configuration:
|
||||
!
|
||||
version "8.4.3.12"
|
||||
switch-type "Lenovo RackSwitch G8272"
|
||||
iscli-new
|
||||
!
|
||||
!
|
||||
access https enable
|
||||
|
||||
snmp-server location "Location:,Room:,Rack:Rack 3,LRU:40"
|
||||
snmp-server read-community "public"
|
||||
snmp-server trap-source 128
|
||||
!
|
||||
!
|
||||
!
|
||||
no system dhcp
|
||||
no system default-ip mgt
|
||||
hostname "test1"
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!interface ip 1
|
||||
! addr <default>
|
||||
! enable
|
||||
!
|
||||
interface ip 128
|
||||
ip address 10.241.105.24 255.255.255.0
|
||||
enable
|
||||
exit
|
||||
!
|
||||
ip gateway 4 address 10.241.105.1
|
||||
ip gateway 4 enable
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
router bgp
|
||||
as 100
|
||||
!
|
||||
!
|
||||
end
|
||||
|
59
test/units/modules/network/enos/fixtures/show_running-config
Normal file
59
test/units/modules/network/enos/fixtures/show_running-config
Normal file
|
@ -0,0 +1,59 @@
|
|||
Current configuration:
|
||||
!
|
||||
version "8.4.3.12"
|
||||
switch-type "Lenovo RackSwitch G8272"
|
||||
iscli-new
|
||||
!
|
||||
!
|
||||
access https enable
|
||||
|
||||
snmp-server location "Location:,Room:,Rack:Rack 3,LRU:40"
|
||||
snmp-server read-community "public"
|
||||
snmp-server trap-source 128
|
||||
!
|
||||
!
|
||||
!
|
||||
no system dhcp
|
||||
no system default-ip mgt
|
||||
hostname "test1"
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!interface ip 1
|
||||
! addr <default>
|
||||
! enable
|
||||
!
|
||||
interface ip 128
|
||||
ip address 10.241.105.24 255.255.255.0
|
||||
enable
|
||||
exit
|
||||
!
|
||||
ip gateway 4 address 10.241.105.1
|
||||
ip gateway 4 enable
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
router bgp
|
||||
as 100
|
||||
!
|
||||
!
|
||||
end
|
||||
|
166
test/units/modules/network/enos/fixtures/show_system_memory
Normal file
166
test/units/modules/network/enos/fixtures/show_system_memory
Normal file
|
@ -0,0 +1,166 @@
|
|||
------------------------------------------------------------------
|
||||
|
||||
Memory utilization:
|
||||
MemTotal: 4088580 kB
|
||||
MemFree: 3464304 kB
|
||||
MemAvailable: 3586864 kB
|
||||
Buffers: 2016 kB
|
||||
Cached: 173236 kB
|
||||
SwapCached: 0 kB
|
||||
Active: 504316 kB
|
||||
Inactive: 38056 kB
|
||||
Active(anon): 376332 kB
|
||||
Inactive(anon): 27460 kB
|
||||
Active(file): 127984 kB
|
||||
Inactive(file): 10596 kB
|
||||
Unevictable: 0 kB
|
||||
Mlocked: 0 kB
|
||||
HighTotal: 3407860 kB
|
||||
HighFree: 2952904 kB
|
||||
LowTotal: 680720 kB
|
||||
LowFree: 511400 kB
|
||||
SwapTotal: 0 kB
|
||||
SwapFree: 0 kB
|
||||
Dirty: 0 kB
|
||||
Writeback: 0 kB
|
||||
AnonPages: 367120 kB
|
||||
Mapped: 20664 kB
|
||||
Shmem: 36672 kB
|
||||
Slab: 8240 kB
|
||||
SReclaimable: 3492 kB
|
||||
SUnreclaim: 4748 kB
|
||||
KernelStack: 760 kB
|
||||
PageTables: 1592 kB
|
||||
NFS_Unstable: 0 kB
|
||||
Bounce: 0 kB
|
||||
WritebackTmp: 0 kB
|
||||
CommitLimit: 2044288 kB
|
||||
Committed_AS: 1128364 kB
|
||||
VmallocTotal: 241652 kB
|
||||
VmallocUsed: 17116 kB
|
||||
VmallocChunk: 223920 kB
|
||||
HugePages_Total: 0
|
||||
HugePages_Free: 0
|
||||
HugePagesPercentage used 15
|
||||
|
||||
Memory tracing: enabled
|
||||
Extended Memory tracing: disabled
|
||||
High-water monitoring: enabled
|
||||
|
||||
Memory high-water: 20 percent (at 1818 seconds from boot)
|
||||
|
||||
Memory stats:
|
||||
allocs: 16484474
|
||||
frees: 16481108
|
||||
current: 3378
|
||||
alloc fails: 0
|
||||
|
||||
STEM thread memory stats:
|
||||
thid name allocs frees diff current * largest
|
||||
0 INIT 2655 933 1722 69381079 31982881
|
||||
1 STEM 0 0 0 0 0
|
||||
2 STP 13 6 7 41165721 16673868
|
||||
3 MFDB 1 0 1 6 6
|
||||
4 TND 41745 42134 -389 847441 336
|
||||
5 CONS 3867 3866 1 26622356 6291456
|
||||
6 TNET 3806775 3809157 -2382 1032303745 12582912
|
||||
7 TNET 126519 127060 -541 269598653 12582912
|
||||
8 TNET 1 0 1 6131 6131
|
||||
9 TNET 1 0 1 6131 6131
|
||||
10 TNET 1 0 1 6131 6131
|
||||
11 TNET 1 0 1 6131 6131
|
||||
12 LOG 441 441 0 61437 272
|
||||
13 TRAP 16911 16911 0 1416745 544
|
||||
14 NTP 0 0 0 0 0
|
||||
15 RMON 0 0 0 0 0
|
||||
18 IP 40 7 33 26152 4248
|
||||
19 RIP 0 0 0 0 0
|
||||
20 AGR 24643 23177 1466 8949189 6131
|
||||
21 EPI 0 0 0 0 0
|
||||
22 PORT 56 0 56 60032 16384
|
||||
23 BGP 0 10 -10 0 0
|
||||
27 MGMT 335 162 173 48883648 524436
|
||||
28 SCAN 0 0 0 0 0
|
||||
29 OSPF 0 20 -20 0 0
|
||||
30 VRRP 1 0 1 16 16
|
||||
31 SNMP 4670978 4670164 814 2315549793 12582912
|
||||
32 SNMP 1108 1068 40 208175203 12582912
|
||||
34 SSHD 800286 796910 3376 271976834 2017
|
||||
36 DT1X 0 0 0 0 0
|
||||
37 NCFD 1 0 1 6131 6131
|
||||
38 NCFD 1 0 1 6131 6131
|
||||
39 NCFD 1 0 1 6131 6131
|
||||
40 NCFD 1 0 1 6131 6131
|
||||
41 SWR 0 0 0 0 0
|
||||
42 SWRH 0 0 0 0 0
|
||||
43 OBS 0 0 0 0 0
|
||||
44 TEAM 0 0 0 0 0
|
||||
45 I2C 0 0 0 0 0
|
||||
46 LACP 72 0 72 1152 16
|
||||
47 SFP 0 0 0 0 0
|
||||
48 SWKY 0 0 0 0 0
|
||||
49 HLNK 0 0 0 0 0
|
||||
50 LLDP 5794454 5794373 81 598072737 14336
|
||||
51 IPV6 0 0 0 0 0
|
||||
52 RTM6 0 0 0 0 0
|
||||
53 PNG6 0 0 0 0 0
|
||||
55 OSP3 0 0 0 0 0
|
||||
56 VMAC 0 0 0 0 0
|
||||
57 MEMM 0 0 0 0 0
|
||||
58 UDLD 0 0 0 0 0
|
||||
59 FCOE 0 0 0 0 0
|
||||
60 SFLO 0 0 0 0 0
|
||||
61 PROX 0 0 0 0 0
|
||||
62 OAM 0 0 0 0 0
|
||||
63 PIM 0 0 0 0 0
|
||||
64 DCBX 1 1 0 126 126
|
||||
65 NBOO 1 0 1 6131 6131
|
||||
66 VLAG 0 0 0 0 0
|
||||
67 MLD6 0 0 0 0 0
|
||||
68 DHCP 0 0 0 0 0
|
||||
69 ETMR 0 0 0 0 0
|
||||
70 IKE2 0 0 0 0 0
|
||||
71 ACLG 1 0 1 5120 5120
|
||||
72 HWRT 0 0 0 0 0
|
||||
73 OFLO 17 0 17 32244 8048
|
||||
74 SFM 0 0 0 0 0
|
||||
75 UPTM 0 0 0 0 0
|
||||
76 VSDB 0 2 -2 0 0
|
||||
77 ECPT 3 0 3 168532 168000
|
||||
78 ECPR 0 0 0 0 0
|
||||
79 VDPT 5 0 5 5260 1460
|
||||
80 VFDB 0 1 -1 0 0
|
||||
81 PTP 0 0 0 0 0
|
||||
82 PBR 0 0 0 0 0
|
||||
83 HIST 0 0 0 0 0
|
||||
84 SLP 699757 701435 -1678 254297215 262140
|
||||
85 UFP 217 73 144 12908 132
|
||||
86 CDCP 0 0 0 0 0
|
||||
87 IGMP 0 0 0 0 0
|
||||
88 ICMP 0 0 0 0 0
|
||||
89 HCM 0 0 0 0 0
|
||||
90 CFCF 0 0 0 0 0
|
||||
91 FDF@ 0 0 0 0 0
|
||||
92 NAT 0 0 0 0 0
|
||||
93 OCM1 11 0 11 44 4
|
||||
94 OCM2 0 0 0 0 0
|
||||
95 OFDT 0 0 0 0 0
|
||||
96 OSFM 5 0 5 2636 1024
|
||||
97 OBSC 0 0 0 0 0
|
||||
98 STPM 0 0 0 0 0
|
||||
99 ARP 0 0 0 0 0
|
||||
100 VXLN 0 0 0 0 0
|
||||
101 OVSD 0 0 0 0 0
|
||||
102 OVSC 0 0 0 0 0
|
||||
103 VTEP 0 0 0 0 0
|
||||
104 BFD 18 0 18 440 44
|
||||
105 STPR 0 0 0 0 0
|
||||
106 VMFD 0 0 0 0 0
|
||||
107 NORM 0 0 0 0 0
|
||||
108 DONE 494136 493788 348 280129530 6291456
|
||||
Total 16485149 16481768 3381 1132837544
|
||||
|
||||
Non-STEM allocs 0
|
||||
Non-STEM frees 2
|
||||
Overhead 1780
|
||||
|
60
test/units/modules/network/enos/fixtures/show_version
Normal file
60
test/units/modules/network/enos/fixtures/show_version
Normal file
|
@ -0,0 +1,60 @@
|
|||
System Information at 11:37:06 Fri Oct 27, 2017
|
||||
Time zone: No timezone configured
|
||||
Daylight Savings Time Status: Disabled
|
||||
|
||||
Lenovo RackSwitch G8272
|
||||
|
||||
Switch has been up for 30 days, 10 hours, 43 minutes and 14 seconds.
|
||||
Last boot: 00:53:32 Wed Sep 27, 2017 (power cycle)
|
||||
|
||||
MAC address: a8:97:dc:dd:e2:00 IP (If 1) address: 192.168.49.50
|
||||
Management Port MAC Address: a8:97:dc:dd:e2:fe
|
||||
Management Port IP Address (if 128): 10.241.105.24
|
||||
Hardware Revision: 0
|
||||
Board Revision:
|
||||
Hardware Part No: 00CJ066
|
||||
Old Hardware Part No: 2MV4CR01W
|
||||
Switch Serial No: Y052MV4CR01W
|
||||
Manufacturing date: 14/51
|
||||
|
||||
MTM Value: 7159-HCV
|
||||
Old MTM Value:
|
||||
ESN: MM01086
|
||||
|
||||
|
||||
WARNING: This is UNRELEASED SOFTWARE for LAB TESTING ONLY.
|
||||
DO NOT USE IN A PRODUCTION NETWORK.
|
||||
|
||||
|
||||
Software Version 8.4.3.12 (FLASH image1), active configuration.
|
||||
Boot kernel version 8.4.3.12
|
||||
|
||||
USB Boot: disabled
|
||||
|
||||
|
||||
|
||||
Temperature CPU Local : 31 C
|
||||
Temperature Ambient : 32 C
|
||||
Temperature Hot Spot : 44 C
|
||||
Temperature Asic Max : 63 C
|
||||
|
||||
System Warning at 85 C / Shutdown at 95 C / Set Point is 70 C
|
||||
|
||||
Fan 1 Module 1: 4054rpm 60pwm(23%) Front-To-Back
|
||||
Fan 2 Module 1: 4404rpm 60pwm(23%) Front-To-Back
|
||||
Fan 3 Module 2: 4112rpm 60pwm(23%) Front-To-Back
|
||||
Fan 4 Module 2: 4372rpm 60pwm(23%) Front-To-Back
|
||||
Fan 5 Module 3: 4072rpm 60pwm(23%) Front-To-Back
|
||||
Fan 6 Module 3: 4306rpm 60pwm(23%) Front-To-Back
|
||||
Fan 7 Module 4: 4134rpm 60pwm(23%) Front-To-Back
|
||||
Fan 8 Module 4: 4326rpm 60pwm(23%) Front-To-Back
|
||||
|
||||
System Fan Airflow: Front-To-Back
|
||||
|
||||
Power Supply 1: Front-To-Back [DPS-460KB C]
|
||||
Power Supply 2: Front-To-Back [DPS-460KB C]
|
||||
|
||||
Power Faults: PS1-Pwr
|
||||
Fan Faults: None
|
||||
Service Faults: Too-Few-PS
|
||||
|
79
test/units/modules/network/enos/test_enos_facts.py
Normal file
79
test/units/modules/network/enos/test_enos_facts.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
# (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 .enos_module import TestEnosModule, load_fixture, set_module_args
|
||||
from ansible.modules.network.enos import enos_facts
|
||||
|
||||
|
||||
class TestEnosFacts(TestEnosModule):
|
||||
|
||||
module = enos_facts
|
||||
|
||||
def setUp(self):
|
||||
self.mock_run_commands = patch(
|
||||
'ansible.modules.network.enos.enos_facts.run_commands')
|
||||
self.run_commands = self.mock_run_commands.start()
|
||||
|
||||
def tearDown(self):
|
||||
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_enos_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('test1', ansible_facts['ansible_net_hostname'])
|
||||
self.assertIn('MGT', ansible_facts['ansible_net_interfaces'].keys())
|
||||
self.assertEquals(3992.75390625, ansible_facts['ansible_net_memtotal_mb'])
|
||||
self.assertEquals(3383.109375, ansible_facts['ansible_net_memfree_mb'])
|
||||
|
||||
def test_enos_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('test1', ansible_facts['ansible_net_hostname'])
|
||||
self.assertIn('ansible_net_config', ansible_facts)
|
Loading…
Reference in a new issue