diff --git a/lib/ansible/modules/network/voss/voss_facts.py b/lib/ansible/modules/network/voss/voss_facts.py new file mode 100644 index 00000000000..e4266bc9cf8 --- /dev/null +++ b/lib/ansible/modules/network/voss/voss_facts.py @@ -0,0 +1,513 @@ +#!/usr/bin/python +# +# 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 . +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + + +DOCUMENTATION = """ +--- +module: voss_facts +version_added: "2.7" +author: "Lindsay Hill (@LindsayHill)" +short_description: Collect facts from remote devices running Extreme VOSS +description: + - Collects a base set of device facts from a remote device that + is running VOSS. This module prepends all of the base network fact + keys with C(ansible_net_). 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 VOSS 7.0.0 +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 = """ +# Collect all facts from the device +- voss_facts: + gather_subset: all + +# Collect only the config and default facts +- voss_facts: + gather_subset: + - config + +# Do not collect hardware facts +- voss_facts: + gather_subset: + - "!hardware" +""" + +RETURN = """ +ansible_net_gather_subset: + description: The list of fact subsets collected from the device + returned: always + type: list + +# default +ansible_net_model: + description: The model name returned from the device + returned: always + type: string +ansible_net_serialnum: + description: The serial number of the remote device + returned: always + type: string +ansible_net_version: + description: The operating system version running on the remote device + returned: always + type: string +ansible_net_hostname: + description: The configured hostname of 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 +ansible_net_memtotal_mb: + description: The total memory on the remote device in Mb + returned: when hardware is configured + type: int + +# config +ansible_net_config: + description: The current active config from the device + returned: when config is configured + type: string + +# 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 + 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.network.voss.voss import run_commands +from ansible.module_utils.network.voss.voss import check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import iteritems + + +class FactsBase(object): + + COMMANDS = list() + + def __init__(self, module): + self.module = module + self.facts = dict() + self.responses = None + + def populate(self): + self.responses = run_commands(self.module, commands=self.COMMANDS, check_rc=False) + + def run(self, cmd): + return run_commands(self.module, commands=cmd, check_rc=False) + + +class Default(FactsBase): + + COMMANDS = ['show sys-info'] + + def populate(self): + super(Default, self).populate() + data = self.responses[0] + 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['hostname'] = self.parse_hostname(data) + + def parse_version(self, data): + match = re.search(r'SysDescr\s+: \S+ \((\S+)\)', data) + if match: + return match.group(1) + return '' + + def parse_hostname(self, data): + match = re.search(r'SysName\s+: (\S+)', data, re.M) + if match: + return match.group(1) + return '' + + def parse_model(self, data): + match = re.search(r'Chassis\s+: (\S+)', data, re.M) + if match: + return match.group(1) + return '' + + def parse_serialnum(self, data): + match = re.search(r'Serial#\s+: (\S+)', data) + if match: + return match.group(1) + return '' + + +class Hardware(FactsBase): + + COMMANDS = [ + 'show khi performance memory' + ] + + def populate(self): + super(Hardware, self).populate() + data = self.responses[0] + + if data: + match = re.search(r'Free:\s+(\d+)\s+\(KB\)', data, re.M) + if match: + self.facts['memfree_mb'] = int(round(int(match.group(1)) / 1024, 0)) + match = re.search(r'Used:\s+(\d+)\s+\(KB\)', data, re.M) + if match: + memused_mb = int(round(int(match.group(1)) / 1024, 0)) + self.facts['memtotal_mb'] = self.facts.get('memfree_mb', 0) + memused_mb + + +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 interfaces gigabitEthernet interface', + 'show interfaces gigabitEthernet name', + 'show ip interface', + 'show ipv6 address interface', + 'show lldp neighbor | include Port|SysName' + ] + + def populate(self): + super(Interfaces, self).populate() + + self.facts['all_ipv4_addresses'] = list() + self.facts['all_ipv6_addresses'] = list() + + data = self.responses[0] + if data: + interfaces = self.parse_interfaces(data) + self.facts['interfaces'] = self.populate_interfaces_eth(interfaces) + + data = self.responses[1] + if data: + data = self.parse_interfaces(data) + self.populate_interfaces_eth_additional(data) + + data = self.responses[2] + if data: + data = self.parse_interfaces(data) + self.populate_ipv4_interfaces(data) + + data = self.responses[3] + if data: + self.populate_ipv6_interfaces(data) + + data = self.responses[4] + if data: + self.facts['neighbors'] = self.parse_neighbors(data) + + def populate_interfaces_eth(self, interfaces): + facts = dict() + for key, value in iteritems(interfaces): + intf = dict() + match = re.match(r'^\d+\s+(\S+)\s+\w+\s+\w+\s+(\d+)\s+([a-f\d:]+)\s+(\w+)\s+(\w+)$', value) + if match: + intf['mediatype'] = match.group(1) + intf['mtu'] = match.group(2) + intf['macaddress'] = match.group(3) + intf['adminstatus'] = match.group(4) + intf['operstatus'] = match.group(5) + intf['type'] = 'Ethernet' + facts[key] = intf + return facts + + def populate_interfaces_eth_additional(self, interfaces): + for key, value in iteritems(interfaces): + # This matches when no description is set + match = re.match(r'^\w+\s+\w+\s+(\w+)\s+(\d+)\s+\w+$', value) + if match: + self.facts['interfaces'][key]['description'] = '' + self.facts['interfaces'][key]['duplex'] = match.group(1) + self.facts['interfaces'][key]['bandwidth'] = match.group(2) + else: + # This matches when a description is set + match = re.match(r'^(.+)\s+\w+\s+\w+\s+(\w+)\s+(\d+)\s+\w+$', value) + if match: + self.facts['interfaces'][key]['description'] = match.group(1).strip() + self.facts['interfaces'][key]['duplex'] = match.group(2) + self.facts['interfaces'][key]['bandwidth'] = match.group(3) + + def populate_ipv4_interfaces(self, data): + for key, value in data.items(): + if key not in self.facts['interfaces']: + if re.match(r'Vlan\d+', key): + self.facts['interfaces'][key] = dict() + self.facts['interfaces'][key]['type'] = 'VLAN' + elif re.match(r'Clip\d+', key): + self.facts['interfaces'][key] = dict() + self.facts['interfaces'][key]['type'] = 'Loopback' + if re.match(r'Port(\d+/\d+)', key): + key = re.split('Port', key)[1] + self.facts['interfaces'][key]['ipv4'] = list() + match = re.match(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', value, re.M) + if match: + addr = match.group(1) + subnet = match.group(2) + ipv4 = dict(address=addr, subnet=subnet) + self.add_ip_address(addr, 'ipv4') + self.facts['interfaces'][key]['ipv4'].append(ipv4) + + def populate_ipv6_interfaces(self, data): + addresses = re.split(r'-{3,}', data)[1].lstrip() + for line in addresses.split('\n'): + if len(line) == 0: + break + + match = re.match(r'^([\da-f:]+)/(\d+)\s+([CV])-(\d+)\s+.+$', line) + if match: + address = match.group(1) + subnet = match.group(2) + interface_short_name = match.group(3) + interface_id = match.group(4) + if interface_short_name == 'C': + intf_type = 'Loopback' + interface_name = 'Clip' + interface_id + elif interface_short_name == 'V': + intf_type = 'VLAN' + interface_name = 'Vlan' + interface_id + else: + # Unknown interface type, better to gracefully ignore it for now + break + ipv6 = dict(address=address, subnet=subnet) + self.add_ip_address(address, 'ipv6') + try: + self.facts['interfaces'][interface_name].setdefault('ipv6', []).append(ipv6) + self.facts['interfaces'][interface_name]['type'] = intf_type + except KeyError: + self.facts['interfaces'][interface_name] = dict() + self.facts['interfaces'][interface_name]['type'] = intf_type + self.facts['interfaces'][interface_name].setdefault('ipv6', []).append(ipv6) + else: + break + + def add_ip_address(self, address, family): + if family == 'ipv4': + self.facts['all_ipv4_addresses'].append(address) + else: + self.facts['all_ipv6_addresses'].append(address) + + def parse_neighbors(self, neighbors): + facts = dict() + lines = neighbors.split('Port: ') + if len(lines) == 0: + return facts + for line in lines: + match = re.search(r'^(\w.*?)\s+Index.*IfName\s+(\w.*)$\s+SysName\s+:\s(\S+)', line, (re.M | re.S)) + if match: + intf = match.group(1) + if intf not in facts: + facts[intf] = list() + fact = dict() + fact['host'] = match.group(3) + fact['port'] = match.group(2) + facts[intf].append(fact) + return facts + + def parse_interfaces(self, data): + parsed = dict() + interfaces = re.split(r'-{3,}', data)[1].lstrip() + for line in interfaces.split('\n'): + if len(line) == 0: + break + else: + match = re.split(r'^(\S+)\s+', line) + key = match[1] + parsed[key] = match[2].strip() + return parsed + + def parse_description(self, data): + match = re.search(r'Description: (.+)$', data, re.M) + if match: + return match.group(1) + return '' + + def parse_macaddress(self, data): + match = re.search(r'Hardware is (?:.*), address is (\S+)', data) + if match: + return match.group(1) + return '' + + def parse_mtu(self, data): + match = re.search(r'MTU (\d+)', data) + if match: + return int(match.group(1)) + return '' + + def parse_bandwidth(self, data): + match = re.search(r'BW (\d+)', data) + if match: + return int(match.group(1)) + return '' + + def parse_duplex(self, data): + match = re.search(r'(\w+) Duplex', data, re.M) + if match: + return match.group(1) + return '' + + def parse_mediatype(self, data): + match = re.search(r'media type is (.+)$', data, re.M) + if match: + return match.group(1) + return '' + + def parse_type(self, data): + match = re.search(r'Hardware is (.+),', data, re.M) + if match: + return match.group(1) + return '' + + def parse_lineprotocol(self, data): + match = re.search(r'line protocol is (.+)$', data, re.M) + if match: + return match.group(1) + return '' + + def parse_operstatus(self, data): + match = re.search(r'^(?:.+) is (.+),', data, re.M) + if match: + return match.group(1) + return '' + + +FACT_SUBSETS = dict( + default=Default, + hardware=Hardware, + interfaces=Interfaces, + config=Config, +) + +VALID_SUBSETS = frozenset(FACT_SUBSETS.keys()) + +global warnings +warnings = list() + + +def main(): + """main entry point for module execution + """ + argument_spec = dict( + gather_subset=dict(default=['!config'], type='list') + ) + + 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 + + check_args(module, warnings) + + module.exit_json(ansible_facts=ansible_facts, warnings=warnings) + + +if __name__ == '__main__': + main() diff --git a/test/units/modules/network/voss/fixtures/voss_facts_show_interfaces_gigabitEthernet_interface b/test/units/modules/network/voss/fixtures/voss_facts_show_interfaces_gigabitEthernet_interface new file mode 100644 index 00000000000..cdebd4068b8 --- /dev/null +++ b/test/units/modules/network/voss/fixtures/voss_facts_show_interfaces_gigabitEthernet_interface @@ -0,0 +1,93 @@ + +========================================================================================== + Port Interface +========================================================================================== +PORT LINK PORT PHYSICAL STATUS +NUM INDEX DESCRIPTION TRAP LOCK MTU ADDRESS ADMIN OPERATE +------------------------------------------------------------------------------------------ +1/1 192 10GbNone true false 1950 00:51:00:16:40:00 down down +1/2 193 10GbNone true false 1950 00:51:00:16:40:01 down down +1/3 194 10GbNone true false 1950 00:51:00:16:40:02 down down +1/4 195 10GbNone true false 1950 00:51:00:16:40:03 down down +1/5 196 10GbNone true false 1950 00:51:00:16:40:04 down down +1/6 197 10GbNone true false 1950 00:51:00:16:40:05 down down +1/7 198 10GbNone true false 1950 00:51:00:16:40:06 down down +1/8 199 10GbNone true false 1950 00:51:00:16:40:07 down down +1/9 200 10GbNone true false 1950 00:51:00:16:40:08 down down +1/10 201 10GbNone true false 1950 00:51:00:16:40:09 down down +1/11 202 10GbNone true false 1950 00:51:00:16:40:0a down down +1/12 203 10GbNone true false 1950 00:51:00:16:40:0b down down +1/13 204 10GbNone true false 1950 00:51:00:16:40:0c down down +1/14 205 10GbNone true false 1950 00:51:00:16:40:0d down down +1/15 206 10GbNone true false 1950 00:51:00:16:40:0e down down +1/16 207 10GbNone true false 1950 00:51:00:16:40:0f down down +1/17 208 10GbNone true false 1950 00:51:00:16:40:10 down down +1/18 209 10GbNone true false 1950 00:51:00:16:40:11 down down +1/19 210 10GbNone true false 1950 00:51:00:16:40:12 down down +1/20 211 10GbNone true false 1950 00:51:00:16:40:13 down down +1/21 212 10GbNone true false 1950 00:51:00:16:40:14 down down +1/22 213 10GbNone true false 1950 00:51:00:16:40:15 down down +1/23 214 10GbNone true false 1950 00:51:00:16:40:16 down down +1/24 215 10GbNone true false 1950 00:51:00:16:40:17 down down +1/25 216 10GbNone true false 1950 00:51:00:16:40:18 down down +1/26 217 10GbNone true false 1950 00:51:00:16:40:19 down down +1/27 218 10GbNone true false 1950 00:51:00:16:40:1a down down +1/28 219 10GbNone true false 1950 00:51:00:16:40:1b down down +1/29 220 10GbNone true false 1950 00:51:00:16:40:1c down down +1/30 221 10GbNone true false 1950 00:51:00:16:40:1d down down +1/31 222 10GbNone true false 1950 00:51:00:16:40:1e down down +1/32 223 10GbNone true false 1950 00:51:00:16:40:1f down down +1/33 224 10GbNone true false 1950 00:51:00:16:40:20 down down +1/34 225 10GbNone true false 1950 00:51:00:16:40:21 down down +1/35 226 10GbNone true false 1950 00:51:00:16:40:22 down down +1/36 227 10GbNone true false 1950 00:51:00:16:40:23 down down +1/37 228 10GbNone true false 1950 00:51:00:16:40:24 down down +1/38 229 10GbNone true false 1950 00:51:00:16:40:25 down down +1/39 230 10GbNone true false 1950 00:51:00:16:40:26 down down +1/40 231 10GbNone true false 1950 00:51:00:16:40:27 down down +1/41 232 40GbNone true false 1950 00:51:00:16:40:28 down down +1/42 236 40GbNone true false 1950 00:51:00:16:40:2c down down +2/1 256 10GbNone true false 1950 00:51:00:16:40:40 down down +2/2 257 10GbNone true false 1950 00:51:00:16:40:41 down down +2/3 258 10GbNone true false 1950 00:51:00:16:40:42 down down +2/4 259 10GbNone true false 1950 00:51:00:16:40:43 down down +2/5 260 10GbNone true false 1950 00:51:00:16:40:44 down down +2/6 261 10GbNone true false 1950 00:51:00:16:40:45 down down +2/7 262 10GbNone true false 1950 00:51:00:16:40:46 down down +2/8 263 10GbNone true false 1950 00:51:00:16:40:47 down down +2/9 264 10GbNone true false 1950 00:51:00:16:40:48 down down +2/10 265 10GbNone true false 1950 00:51:00:16:40:49 down down +2/11 266 10GbNone true false 1950 00:51:00:16:40:4a down down +2/12 267 10GbNone true false 1950 00:51:00:16:40:4b down down +2/13 268 10GbNone true false 1950 00:51:00:16:40:4c down down +2/14 269 10GbNone true false 1950 00:51:00:16:40:4d down down +2/15 270 10GbNone true false 1950 00:51:00:16:40:4e down down +2/16 271 10GbNone true false 1950 00:51:00:16:40:4f down down +2/17 272 10GbNone true false 1950 00:51:00:16:40:50 down down +2/18 273 10GbNone true false 1950 00:51:00:16:40:51 down down +2/19 274 10GbNone true false 1950 00:51:00:16:40:52 down down +2/20 275 10GbNone true false 1950 00:51:00:16:40:53 down down +2/21 276 10GbNone true false 1950 00:51:00:16:40:54 down down +2/22 277 10GbNone true false 1950 00:51:00:16:40:55 down down +2/23 278 10GbNone true false 1950 00:51:00:16:40:56 down down +2/24 279 10GbNone true false 1950 00:51:00:16:40:57 down down +2/25 280 10GbNone true false 1950 00:51:00:16:40:58 down down +2/26 281 10GbNone true false 1950 00:51:00:16:40:59 down down +2/27 282 10GbNone true false 1950 00:51:00:16:40:5a down down +2/28 283 10GbNone true false 1950 00:51:00:16:40:5b down down +2/29 284 10GbNone true false 1950 00:51:00:16:40:5c down down +2/30 285 10GbNone true false 1950 00:51:00:16:40:5d down down +2/31 286 10GbNone true false 1950 00:51:00:16:40:5e down down +2/32 287 10GbNone true false 1950 00:51:00:16:40:5f down down +2/33 288 10GbNone true false 1950 00:51:00:16:40:60 down down +2/34 289 10GbNone true false 1950 00:51:00:16:40:61 down down +2/35 290 10GbNone true false 1950 00:51:00:16:40:62 down down +2/36 291 10GbNone true false 1950 00:51:00:16:40:63 down down +2/37 292 10GbNone true false 1950 00:51:00:16:40:64 down down +2/38 293 10GbNone true false 1950 00:51:00:16:40:65 down down +2/39 294 10GbNone true false 1950 00:51:00:16:40:66 down down +2/40 295 10GbNone true false 1950 00:51:00:16:40:67 down down +2/41 296 40GbNone true false 1950 00:51:00:16:40:68 down down +2/42 300 40GbNone true false 1950 00:51:00:16:40:6c down down + + diff --git a/test/units/modules/network/voss/fixtures/voss_facts_show_interfaces_gigabitEthernet_name b/test/units/modules/network/voss/fixtures/voss_facts_show_interfaces_gigabitEthernet_name new file mode 100644 index 00000000000..7efcfd07f37 --- /dev/null +++ b/test/units/modules/network/voss/fixtures/voss_facts_show_interfaces_gigabitEthernet_name @@ -0,0 +1,93 @@ + +========================================================================================== + Port Name +========================================================================================== +PORT OPERATE OPERATE OPERATE +NUM NAME DESCRIPTION STATUS DUPLX SPEED VLAN +---------------------------------------------------------------------------------------------------- +1/1 serverA 10GbNone down full 0 Access +1/2 10GbNone down full 0 Access +1/3 10GbNone down full 0 Access +1/4 10GbNone down full 0 Access +1/5 10GbNone down full 0 Access +1/6 10GbNone down full 0 Access +1/7 10GbNone down full 0 Access +1/8 10GbNone down full 0 Access +1/9 10GbNone down full 0 Access +1/10 10GbNone down full 0 Access +1/11 10GbNone down full 0 Access +1/12 10GbNone down full 0 Access +1/13 10GbNone down full 0 Access +1/14 10GbNone down full 0 Access +1/15 10GbNone down full 0 Access +1/16 10GbNone down full 0 Access +1/17 10GbNone down full 0 Access +1/18 10GbNone down full 0 Access +1/19 10GbNone down full 0 Access +1/20 10GbNone down full 0 Access +1/21 10GbNone down full 0 Access +1/22 10GbNone down full 0 Access +1/23 10GbNone down full 0 Access +1/24 10GbNone down full 0 Access +1/25 10GbNone down full 0 Access +1/26 10GbNone down full 0 Access +1/27 10GbNone down full 0 Access +1/28 10GbNone down full 0 Access +1/29 10GbNone down full 0 Access +1/30 10GbNone down full 0 Access +1/31 10GbNone down full 0 Access +1/32 10GbNone down full 0 Access +1/33 10GbNone down full 0 Access +1/34 10GbNone down full 0 Access +1/35 10GbNone down full 0 Access +1/36 10GbNone down full 0 Access +1/37 10GbNone down full 0 Access +1/38 10GbNone down full 0 Access +1/39 10GbNone down full 0 Access +1/40 10GbNone down full 0 Access +1/41 40GbNone down half 0 Access +1/42 40GbNone down half 0 Access +2/1 10GbNone down full 0 Access +2/2 10GbNone down full 0 Access +2/3 10GbNone down full 0 Access +2/4 10GbNone down full 0 Access +2/5 10GbNone down full 0 Access +2/6 10GbNone down full 0 Access +2/7 10GbNone down full 0 Access +2/8 10GbNone down full 0 Access +2/9 10GbNone down full 0 Access +2/10 10GbNone down full 0 Access +2/11 10GbNone down full 0 Access +2/12 10GbNone down full 0 Access +2/13 10GbNone down full 0 Access +2/14 10GbNone down full 0 Access +2/15 10GbNone down full 0 Access +2/16 10GbNone down full 0 Access +2/17 10GbNone down full 0 Access +2/18 10GbNone down full 0 Access +2/19 10GbNone down full 0 Access +2/20 10GbNone down full 0 Access +2/21 10GbNone down full 0 Access +2/22 10GbNone down full 0 Access +2/23 10GbNone down full 0 Access +2/24 10GbNone down full 0 Access +2/25 10GbNone down full 0 Access +2/26 10GbNone down full 0 Access +2/27 10GbNone down full 0 Access +2/28 10GbNone down full 0 Access +2/29 10GbNone down full 0 Access +2/30 10GbNone down full 0 Access +2/31 10GbNone down full 0 Access +2/32 10GbNone down full 0 Access +2/33 10GbNone down full 0 Access +2/34 10GbNone down full 0 Access +2/35 10GbNone down full 0 Access +2/36 10GbNone down full 0 Access +2/37 10GbNone down full 0 Access +2/38 10GbNone down full 0 Access +2/39 10GbNone down full 0 Access +2/40 10GbNone down full 0 Access +2/41 40GbNone down half 0 Access +2/42 40GbNone down half 0 Access + + diff --git a/test/units/modules/network/voss/fixtures/voss_facts_show_ip_interface b/test/units/modules/network/voss/fixtures/voss_facts_show_ip_interface new file mode 100644 index 00000000000..7283cef137f --- /dev/null +++ b/test/units/modules/network/voss/fixtures/voss_facts_show_ip_interface @@ -0,0 +1,12 @@ + +==================================================================================================== + IP Interface - GlobalRouter +==================================================================================================== +INTERFACE IP NET BCASTADDR REASM VLAN BROUTER IPSEC + ADDRESS MASK FORMAT MAXSIZE ID PORT STATE +---------------------------------------------------------------------------------------------------- +Clip1 1.1.1.1 255.255.255.255 ones 1500 -- false disable +Vlan1 10.10.10.10 255.255.255.0 ones 1500 1 false disable + + +All 2 out of 2 Total Num of IP interfaces displayed diff --git a/test/units/modules/network/voss/fixtures/voss_facts_show_ipv6_address_interface b/test/units/modules/network/voss/fixtures/voss_facts_show_ipv6_address_interface new file mode 100644 index 00000000000..51b1caed446 --- /dev/null +++ b/test/units/modules/network/voss/fixtures/voss_facts_show_ipv6_address_interface @@ -0,0 +1,12 @@ +======================================================================================================= + Address Information - GlobalRouter +======================================================================================================= +IPV6 ADDRESS/PREFIX LENGTH VID/BID/TID TYPE ORIGIN STATUS VALID PREF + LIFETIME LIFETIME +------------------------------------------------------------------------------------------------------- +2011:0:0:0:0:0:0:1/128 C-1 UNICAST MANUAL PREFERRED INF INF +2001:0:0:0:0:0:0:1/64 V-1 UNICAST MANUAL INACCESSIBLE INF INF +2002:0:0:0:0:0:0:1/64 V-1 UNICAST MANUAL INACCESSIBLE INF INF +fe80:0:0:0:251:ff:fe16:4100/64 V-1 UNICAST LINKLAYER INACCESSIBLE INF INF + +4 out of 4 Total Num of Address Entries displayed. diff --git a/test/units/modules/network/voss/fixtures/voss_facts_show_khi_performance_memory b/test/units/modules/network/voss/fixtures/voss_facts_show_khi_performance_memory new file mode 100644 index 00000000000..a9628f8a22d --- /dev/null +++ b/test/units/modules/network/voss/fixtures/voss_facts_show_khi_performance_memory @@ -0,0 +1,14 @@ + Slot:1 + Used: 386164 (KB) + Free: 639868 (KB) + Current utilization: 37 % + 5-minute average utilization: 37 % + 5-minute high water mark: 37 (%) + 10-minute average utilization: 37 % + 10-minute high water mark: 37 (%) + 1-Hour average utilization: 37 % + 1-Hour high water mark: 37 (%) + 1-Day average utilization: 36 % + 1-Month average utilization: 0 % + 1-Year average utilization: 0 % + diff --git a/test/units/modules/network/voss/fixtures/voss_facts_show_lldp_neighbor b/test/units/modules/network/voss/fixtures/voss_facts_show_lldp_neighbor new file mode 100644 index 00000000000..02e6b1600ac --- /dev/null +++ b/test/units/modules/network/voss/fixtures/voss_facts_show_lldp_neighbor @@ -0,0 +1,12 @@ +Port: 1/1 Index : 1 + PortId : IfName 5 + SysName : X690-48t-2q-4c + PortDescr: +Port: 1/2 Index : 2 + PortId : IfName 1/2 + SysName : VSP2 + PortDescr: Extreme Networks Virtual Services Platform 4450GSX-PWR+ - 1000BaseTX Port 1/2 +Port: 1/12 Index : 2 + PortId : IfName 1/12 + SysName : VSP2 + PortDescr: Extreme Networks Virtual Services Platform 4450GSX-PWR+ - 1000BaseTX Port 1/12 diff --git a/test/units/modules/network/voss/fixtures/voss_facts_show_running-config b/test/units/modules/network/voss/fixtures/voss_facts_show_running-config new file mode 100644 index 00000000000..a049a279656 --- /dev/null +++ b/test/units/modules/network/voss/fixtures/voss_facts_show_running-config @@ -0,0 +1,903 @@ +Preparing to Display Configuration... +# +# Wed Aug 15 05:20:06 2018 UTC +# box type : VSP-8284XSQ +# software version : 7.0.0.0_B015 +# cli mode : ECLI +# + +#Card Info : + +# Slot 1 : +# CardType : 8242XSQ +# CardDescription : 8242XSQ +# CardSerial# : +# CardPart# : +# CardAssemblyDate : +# CardHWRevision : +# CardHWConfig : +# AdminStatus : up +# OperStatus : up + +# Slot 2 : +# CardType : 8242XSQ +# CardDescription : 8242XSQ +# CardSerial# : +# CardPart# : +# CardAssemblyDate : +# CardHWRevision : +# CardHWConfig : +# AdminStatus : up +# OperStatus : up + +# +#!end +# +config terminal + +# +# BOOT CONFIGURATION +# + +boot config flags block-snmp +boot config flags sshd +# end boot flags + +# +# CLI CONFIGURATION +# + +cli timeout 3600 +password password-history 3 + +# +# SYSTEM CONFIGURATION +# + + +# +# LOG CONFIGURATION +# + + +# +# LINK-FLAP-DETECT CONFIGURATION +# + + +# +# IEEE VLAN AGING CONFIGURATION +# + + +# +# ACCESS-POLICY CONFIGURATION +# + +# +# SSH CONFIGURATION +# + +ssh keyboard-interactive-auth + + + +ssh secure + +# +# ASG CONFIGURATION +# + + +# +# MCAST SOFTWARE FORWARDING CONFIGURATION +# + + +# +# MCAST SMLT CONFIGURATION +# + + +# +# SNMP V3 GLOBAL CONFIGURATION +# + + +# +# SNMP V3 GROUP MEMBERSHIP CONFIGURATION +# + + +# +# SNMP V3 NOTIFY FILTER CONFIGURATION +# + + +# +# SNMP V3 MIB VIEW CONFIGURATION +# + + +# +# SNMP V3 GROUP CONFIGURATION +# + + +# +# SNMP V3 TARGET ADDRESS CONFIGURATION +# + + +# +# DDI CONFIGURATION +# + + +# +# SLOT CONFIGURATION +# + + +# +# MAC AGING CONFIGURATION +# + + +# +# SMTP CONFIGURATION +# + + +# +# WEB CONFIGURATION +# + +web-server enable + + +# +# GLOBAL FDB FILTER CONFIGURATION +# + + + + +# +# QOS CONFIGURATION - PHASE I +# + + +# +# LACP CONFIGURATION +# + + +# +# VRF CONFIGURATION +# + +ip vrf dmz vrfid 1 + +# +# MAINTENANCE-DOMAIN CONFIGURATION +# + + +# +# MAINTENANCE-ASSOCIATION CONFIGURATION +# + + +# +# MAINTENANCE-ENDPOINT CONFIGURATION +# + + +# +# PORT CHANNELIZE CONFIGURATION +# + + +# +# PORT CONFIGURATION - PHASE I +# + + +# +# ISIS SPBM CONFIGURATION +# + + +# +# SPB-PIM-GW CONFIGURATION +# + + +# +# MLT CONFIGURATION +# + + +# +# IP PREFIX LIST CONFIGURATION - GlobalRouter +# + + +# +# IP PREFIX LIST CONFIGURATION - VRF +# + + +# +# IPv6 PREFIX LIST CONFIGURATION - GlobalRouter +# + + +# +# RMON CONFIGURATION +# + + +# +# DVR CONFIGURATION +# + + +# +# VLAN CONFIGURATION +# + +interface Vlan 1 +ip address 10.10.10.10 255.255.255.0 0 +ipv6 interface mac-offset 0 +ipv6 interface address 2001:0:0:0:0:0:0:1/64 +ipv6 interface address 2002:0:0:0:0:0:0:1/64 + +exit +vlan create 3 type port-mstprstp 0 + +# +# MSTP CONFIGURATION +# + + +# +# NLS CONFIGURATION +# + + +# +# FHS CONFIGURATION +# + + +# +# MAC ACL CONFIGURATION +# + + +# +# IPv6 FHS ACL CONFIGURATION +# + + +# +# RA-GUARD CONFIGURATION +# + + +# +# DHCP-GUARD CONFIGURATION +# + + +# +# FHS SNOOPING CONFIGURATION +# + + +# +# SFLOW CONFIGURATION +# + + +# +# DHCP SNOOPING CONFIGURATION +# + + +# +# DHCP SNOOPING BINDING CONFIGURATION +# + + +# +# LINK-STATE TRACKING +# + + +# +# VIRTUAL IST CONFIGURATION +# + + +# +# MLT INTERFACE CONFIGURATION +# + + +# +# PORT CONFIGURATION - PHASE II +# + +interface mgmtEthernet mgmt +auto-negotiate +ip address 192.168.8.10 255.255.255.0 + +exit +interface GigabitEthernet 1/1 +name "serverA" +exit + +# +# IP CONFIGURATION +# + + +# +# IP AS LIST CONFIGURATION - GlobalRouter +# + + +# +# IP AS LIST CONFIGURATION - VRF +# + + +# +# IP COMMUNITY LIST CONFIGURATION - GlobalRouter +# + + +# +# IP COMMUNITY LIST CONFIGURATION - VRF +# + + +# +# IP EXTENDED COMMUNITY LIST CONFIGURATION - GlobalRouter +# + + +# +# IP EXTENDED COMMUNITY LIST CONFIGURATION - VRF +# + + +# +# IP ROUTE MAP CONFIGURATION - GlobalRouter +# + + +# +# IP ROUTE MAP CONFIGURATION - VRF +# + + +# +# IP CONFIGURATION - GlobalRouter +# + + +# +# IP CONFIGURATION - VRF +# + + +# +# CIRCUITLESS IP INTERFACE CONFIGURATION - GlobalRouter +# + +interface loopback 1 +ip address 1 1.1.1.1/255.255.255.255 +exit + +# +# CIRCUITLESS IP INTERFACE CONFIGURATION - VRF +# + +interface loopback 2 +ip address 2 4.4.4.4/255.255.255.255 vrf dmz +exit + +# +# TOPOLOGY-CLIP-IP +# + + +# +# MSDP CONFIGURATION - GlobalRouter +# + + + + +# +# CIRCUITLESS IPV6 INTERFACE CONFIGURATION - GlobalRouter +# + +interface loopback 1 +ipv6 interface address 2011:0:0:0:0:0:0:1/128 +exit + +# +# CIRCUITLESS IPV6 INTERFACE CONFIGURATION - VRF +# + + +# +# VRRP CONFIGURATION - GlobalRouter +# + + +# +# VRRP CONFIGURATION - VRF +# + + +# +# UDP FORWARDING CONFIGURATION - GlobalRouter +# + + +# +# UDP FORWARDING CONFIGURATION - VRF +# + + +# +# UDP FORWARDING VLAN CONFIGURATION +# + + +# +# DHCP CONFIGURATION - GlobalRouter +# + + +# +# DHCP CONFIGURATION - VRF +# + + +# +# RIP CONFIGURATION - GlobalRouter +# + + +# +# RIP CONFIGURATION - VRF +# + + +# +# RIP VLAN CONFIGURATION +# + + +# +# IGMP CONFIGURATION - GlobalRouter +# + + +# +# IGMP CONFIGURATION - VRF +# + + +# +# MROUTE CONFIGURATION +# + + +# +# MCAST RESOURCE USAGE CONFIGURATION - GlobalRouter +# + + +# +# MCAST RESOURCE USAGE CONFIGURATION - VRF +# + + +# +# TIMED PRUNE CONFIGURATION - GlobalRouter +# + + +# +# TIMED PRUNE CONFIGURATION - VRF +# + + +# +# RSMLT CONFIGURATION +# + + +# +# IPV6 CONFIGURATION - GlobalRouter +# + + +# +# IPV6 CONFIGURATION - VRF +# + + +# +# MLD CONFIGURATION - GlobalRouter +# + + +# +# MROUTE6 CONFIGURATION +# + + +# +# ISIS CONFIGURATION +# + + +# +# VTEP CONFIGURATION +# + + +# +# REMOTE VTEP CONFIGURATIONS +# + + +# +# VLAN NODAL MEP/MIP CONFIGURATION +# + + +# +# QOS CONFIGURATION - PHASE II +# + +qos queue-profile 1 member add 1/1-1/42,2/1-2/42 + +# +# CFM CONFIGURATION - PHASE II +# + + +# +# DIAG CONFIGURATION +# + + +# +# NTP CONFIGURATION +# + +no ntp + +# +# OSPF CONFIGURATION - GlobalRouter +# + +router ospf +exit + +# +# OSPF CONFIGURATION - VRF +# + + +# +# OSPF ACCEPT CONFIGURATION - GlobalRouter +# + + +# +# OSPF ACCEPT CONFIGURATION - VRF +# + + +# +# BGP CONFIGURATION - GlobalRouter +# + + +# +# BGP CONFIGURATION - VRF +# + + +# +# ISIS SPBM IPVPN CONFIGURATION +# + +# +# IP ISID LIST CONFIGURATION - GlobalRouter +# + + +# +# IP ISID LIST CONFIGURATION - VRF +# + + +# +# ISIS ACCEPT CONFIGURATION - GlobalRouter +# + + +# +# ISIS ACCEPT CONFIGURATION - VRF +# + + +# +# IP REDISTRIBUTION CONFIGURATION - GlobalRouter +# + + +# +# IP REDISTRIBUTION CONFIGURATION - VRF +# + + +# +# OSPF VLAN CONFIGURATION +# + + +# +# OSPF PORT CONFIGURATION +# + + +# +# OSPF LOOPBACK CONFIGURATION +# + + +# +# RIP PORT CONFIGURATION +# + + +# +# IPVPN CONFIGURATION +# + +# +# SLPP CONFIGURATION +# + + +# +# FILTER CONFIGURATION +# + + +# +# IPV6 TUNNEL CONFIGURATION +# + + +# +# IPV6 OSPFV3 CONFIGURATION +# + +router ospf + +exit + +# +# IPV6 RIPng CONFIGURATION +# + +router rip +exit + +# +# IPV6 STATIC ROUTE CONFIGURATION - GlobalRouter +# + + +# +# IPV6 STATIC ROUTE CONFIGURATION - VRF +# + +# +# IPV6 MGMT INTERFACE CONFIGURATION +# + + +# +# IPV6 OSPF VLAN CONFIGURATION +# + + +# +# IPV6 OSPF PORT CONFIGURATION +# + + +# +# IPV6 RIP VLAN CONFIGURATION +# + + +# +# IPV6 RIP PORT CONFIGURATION +# + + +# +# IPV6 VRRP VLAN CONFIGURATION +# + + +# +# IPV6 VRRP PORT CONFIGURATION +# + + +# +# IPV6 NEIGHBOR CONFIGURATION - GlobalRouter +# + + +# +# IPV6 NEIGHBOR CONFIGURATION - VRF +# + + +# +# IPV6 DHCP CONFIGURATION - GlobalRouter +# + + + +# +# IPV6 DHCP CONFIGURATION - VRF +# + + +# +# I-SID CONFIGURATION +# + + +# +# VNID CONFIGURATION +# + + + + +# +# RADIUS CONFIGURATION +# + + +# +# TACACS CONFIGURATION +# + + +# +# LLDP CONFIGURATION +# + + +# +# EAP CONFIGURATION +# + + +# +# MACSEC CONFIGURATION +# + + +# +# FABRIC ATTACH CONFIGURATION +# + + +# +# SPB-PIM-GW CONFIGURATION +# + + +# +# SOFTWARE CONFIGURATION +# + + +# +# APPLICATION CONFIGURATION +# + + +# +# OVSDB CONFIGURATION +# + + + + + + +# +# IPSEC CONFIGURATION +# + + +# +# IPSEC POLICY TABLE CONFIGURATION +# + + +# +# IPSEC SA TABLE CONFIGURATION +# + + +# +# IPSEC SA POLICY LINK TABLE CONFIGURATION +# + + +# +# IPV6 OSPFV3 IPSEC CONFIGURATION +# + + +# +# IPV6 IPSEC INTERFACE CONFIGURATION +# + + +# +# IP IPSEC INTERFACE CONFIGURATION +# + + + + + + +# +# IKE CONFIGURATION +# + + + + +# +# IP REDISTRIBUTE APPLY CONFIGURATIONS + +# +# + + +# +# IP ECMP APPLY CONFIGURATIONS + + + + +end + + diff --git a/test/units/modules/network/voss/fixtures/voss_facts_show_sys-info b/test/units/modules/network/voss/fixtures/voss_facts_show_sys-info new file mode 100644 index 00000000000..6e7099c2b6c --- /dev/null +++ b/test/units/modules/network/voss/fixtures/voss_facts_show_sys-info @@ -0,0 +1,107 @@ +General Info : + + SysDescr : VSP-4450GSX-PWR+ (7.0.0.0_B015) + SysName : VSP-4450GSX-PWR+ + SysUpTime : 5 day(s), 17:13:09 + SysContact : http://www.extremenetworks.com/contact/ + SysLocation : + +Chassis Info: + + Chassis : 4450GSX-PWR+ + ModelName : 4450GSX-PWR+ + BrandName : Extreme Networks. + Serial# : 14JP512E0001 + H/W Revision : 01 + H/W Config : none + Part Number : + NumSlots : 1 + NumPorts : 50 + BaseMacAddr : b4:47:5e:00:00:00 + MacAddrCapacity : 256 + System MTU : 1950 + +Card Info : + + Slot# CardType Serial# Part# Oper Admin Power + Status Status State + 1 4450GSX-PWR+ 14JP512E0001 -- up up on + +Temperature Info : + + Chassis Temperature + 30 + + +Power Supply Info : + + Ps#1 Status : UP + Ps#1 Type : AC + Ps#1 Description : AC-DC-54V-1000W + Ps#1 Serial Number: LBNNTMPL20180R + Ps#1 Version : -- + Ps#1 Part Number : 325220-A.01 + + Ps#2 Status : empty + + Total Power Available : 1000 watts + Total Power Usage : 127 watts + +Fan Info : + + Description OperStatus OperSpeed AirflowDir + Tray 1 Fan 1 up mediumSpeed left-right + Tray 1 Fan 2 up mediumSpeed left-right + Tray 1 Fan 3 up mediumSpeed left-right + +LED Info : + + LED#1 Label : PWR + LED#1 Status : GreenSteady + + LED#2 Label : Status + LED#2 Status : GreenSteady + + LED#3 Label : Rps + LED#3 Status : Off + + LED#4 Label : Up + LED#4 Status : UnSupported + + LED#5 Label : Down + LED#5 Status : UnSupported + + LED#6 Label : Base + LED#6 Status : UnSupported + +System Error Info : + + Send Login Success Trap : false + Send Authentication Trap : false + Error Code : 0 + Error Severity : 0 + +Port Lock Info : + + Status : off + LockedPorts : + +Message Control Info : + + Action : suppress-msg + Control-Interval : 5 + Max-msg-num : 5 + Status : disable + + +Configuration Operation Info Since Boot Up: + Last Change: 0 day(s), 08:31:10 (5 day(s), 08:41:59 ago) + Last Vlan Change: 0 day(s), 08:27:35 (5 day(s), 08:45:34 ago) +Last Statistic Reset: 5 day(s), 16:56:45 (0 day(s), 00:16:24 ago) + +Current Uboot Info : +---------------------------------------------------------------------------------------------------- + + VU-Boot 2012.04-00002-g6fb1c26 (Apr 26 2017 - 13:37:44) bld=17042617 + + diff --git a/test/units/modules/network/voss/test_voss_facts.py b/test/units/modules/network/voss/test_voss_facts.py new file mode 100644 index 00000000000..081ff7f296d --- /dev/null +++ b/test/units/modules/network/voss/test_voss_facts.py @@ -0,0 +1,86 @@ +# 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 . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.compat.tests.mock import patch +from ansible.modules.network.voss import voss_facts +from units.modules.utils import set_module_args +from .voss_module import TestVossModule, load_fixture + + +class TestVossFactsModule(TestVossModule): + + module = voss_facts + + def setUp(self): + super(TestVossFactsModule, self).setUp() + self.mock_run_commands = patch('ansible.modules.network.voss.voss_facts.run_commands') + self.run_commands = self.mock_run_commands.start() + + def tearDown(self): + super(TestVossFactsModule, self).tearDown() + self.mock_run_commands.stop() + + def load_fixtures(self, commands=None): + def load_from_file(*args, **kwargs): + module = args + commands = kwargs['commands'] + output = list() + + for command in commands: + filename = str(command).split(' | ')[0].replace(' ', '_') + output.append(load_fixture('voss_facts_%s' % filename)) + return output + + self.run_commands.side_effect = load_from_file + + def test_voss_facts_default(self): + set_module_args(dict(gather_subset='default')) + result = self.execute_module() + self.assertEqual( + result['ansible_facts']['ansible_net_model'], '4450GSX-PWR+' + ) + self.assertEqual( + result['ansible_facts']['ansible_net_serialnum'], '14JP512E0001' + ) + self.assertEqual( + result['ansible_facts']['ansible_net_version'], '7.0.0.0_B015' + ) + + def test_voss_facts_interfaces(self): + set_module_args(dict(gather_subset='interfaces')) + result = self.execute_module() + self.assertEqual( + result['ansible_facts']['ansible_net_interfaces']['1/1']['description'], 'serverA' + ) + self.assertEqual( + result['ansible_facts']['ansible_net_interfaces']['Clip1']['ipv4'][0]['address'], '1.1.1.1' + ) + self.assertEqual( + result['ansible_facts']['ansible_net_neighbors']['1/1'][0]['host'], 'X690-48t-2q-4c' + ) + + def test_voss_facts_hardware(self): + set_module_args(dict(gather_subset='hardware')) + result = self.execute_module() + self.assertEqual( + result['ansible_facts']['ansible_net_memfree_mb'], 625 + ) + self.assertEqual( + result['ansible_facts']['ansible_net_memtotal_mb'], 1002 + )