From 4a79112e5ce27f4d763c05f64f8a829b67fe80cb Mon Sep 17 00:00:00 2001 From: Nathaniel Case Date: Tue, 30 Jan 2018 11:17:14 -0500 Subject: [PATCH] Fix ios_facts return values (#35239) * Revert model and serialnum to older version * Add stacked versions of model and serialnum as separate facts * Add unit test to check stacked output * Alter model regex to address #34768 --- lib/ansible/modules/network/ios/ios_facts.py | 50 +++++++------- .../ios/fixtures/ios_facts_show_version | 68 +++++++++++++++++++ .../modules/network/ios/test_ios_facts.py | 66 ++++++++++++++++++ 3 files changed, 157 insertions(+), 27 deletions(-) create mode 100644 test/units/modules/network/ios/fixtures/ios_facts_show_version create mode 100644 test/units/modules/network/ios/test_ios_facts.py diff --git a/lib/ansible/modules/network/ios/ios_facts.py b/lib/ansible/modules/network/ios/ios_facts.py index f3c5d5e9fa..a0c60a13a9 100644 --- a/lib/ansible/modules/network/ios/ios_facts.py +++ b/lib/ansible/modules/network/ios/ios_facts.py @@ -49,33 +49,19 @@ options: """ EXAMPLES = """ -# Note: examples below use the following provider dict to handle -# transport and authentication to the node. ---- -vars: - cli: - host: "{{ inventory_hostname }}" - username: cisco - password: cisco - transport: cli - ---- # Collect all facts from the device - ios_facts: gather_subset: all - provider: "{{ cli }}" # Collect only the config and default facts - ios_facts: gather_subset: - config - provider: "{{ cli }}" # Do not collect hardware facts - ios_facts: gather_subset: - "!hardware" - provider: "{{ cli }}" """ RETURN = """ @@ -105,6 +91,14 @@ ansible_net_image: description: The image file the device is running returned: always type: string +ansible_net_stacked_models: + description: The model names of each device in the stack + returned: when multiple devices are configured in a stack + type: list +ansible_net_stacked_serialnums: + description: The serial numbers of each device in the stack + returned: when multiple devices are configured in a stack + type: list # hardware ansible_net_filesystems: @@ -163,10 +157,10 @@ class FactsBase(object): self.responses = None def populate(self): - self.responses = run_commands(self.module, self.COMMANDS, check_rc=False) + self.responses = run_commands(self.module, commands=self.COMMANDS, check_rc=False) def run(self, cmd): - return run_commands(self.module, cmd, check_rc=False) + return run_commands(self.module, commands=cmd, check_rc=False) class Default(FactsBase): @@ -182,6 +176,7 @@ class Default(FactsBase): self.facts['model'] = self.parse_model(data) self.facts['image'] = self.parse_image(data) self.facts['hostname'] = self.parse_hostname(data) + self.parse_stacks(data) def parse_version(self, data): match = re.search(r'Version (\S+?)(?:,\s|\s)', data) @@ -194,13 +189,9 @@ class Default(FactsBase): return match.group(1) def parse_model(self, data): - match = re.findall(r'^Model number\s+: (\S+)', data, re.M) + match = re.search(r'^[Cc]isco (\S+).+bytes of .*memory', data, re.M) if match: - return match - else: - match = re.search(r'^[Cc]isco (\S+).+bytes of memory', data, re.M) - if match: - return [match.group(1)] + return match.group(1) def parse_image(self, data): match = re.search(r'image file is "(.+)"', data) @@ -208,13 +199,18 @@ class Default(FactsBase): return match.group(1) def parse_serialnum(self, data): + match = re.search(r'board ID (\S+)', data) + if match: + return match.group(1) + + def parse_stacks(self, data): + match = re.findall(r'^Model number\s+: (\S+)', data, re.M) + if match: + self.facts['stacked_models'] = match + match = re.findall(r'^System serial number\s+: (\S+)', data, re.M) if match: - return match - else: - match = re.search(r'board ID (\S+)', data) - if match: - return [match.group(1)] + self.facts['stacked_serialnums'] = match class Hardware(FactsBase): diff --git a/test/units/modules/network/ios/fixtures/ios_facts_show_version b/test/units/modules/network/ios/fixtures/ios_facts_show_version new file mode 100644 index 0000000000..58322c80b4 --- /dev/null +++ b/test/units/modules/network/ios/fixtures/ios_facts_show_version @@ -0,0 +1,68 @@ +Cisco Internetwork Operating System Software +IOS (tm) C3750 Software (C3750-I5-M), Version 12.1(14)EA1, RELEASE SOFTWARE (fc1) +Copyright (c) 1986-2003 by cisco Systems, Inc. +Compiled Tue 22-Jul-03 13:17 by antonino +Image text-base: 0x00003000, data-base: 0x008F0CF8 + +ROM: Bootstrap program is C3750 boot loader +BOOTLDR: C3750 Boot Loader (C3750-HBOOT-M) Version 12.1(11r)AX, RELEASE SOFTWARE (fc1) + +3750RJ uptime is 1 hour, 29 minutes +System returned to ROM by power-on +System image file is "flash:c3750-i5-mz.121.14-EA1/c3750-i5-mz.121.14-EA1.bin" + +cisco WS-C3750-24TS (PowerPC405) processor (revision A0) with 120822K/10240K bytes of memory. +Processor board ID CAT0726R0ZU +Last reset from power-on +Bridging software. +2 Virtual Ethernet/IEEE 802.3 interface(s) +48 FastEthernet/IEEE 802.3 interface(s) +16 Gigabit Ethernet/IEEE 802.3 interface(s) +The password-recovery mechanism is enabled. + +512K bytes of flash-simulated non-volatile configuration memory. +Base ethernet MAC Address : 00:0D:29:B4:18:00 +Motherboard assembly number : 73-7055-06 +Power supply part number : 341-0034-01 +Motherboard serial number : CAT0726043V +Power supply serial number : PHI0708009K +Model revision number : A0 +Motherboard revision number : A0 +Model number : WS-C3750-24TS-E +System serial number : CAT0726R0ZU + +Switch Ports Model SW Version SW Image +------ ----- ----- ---------- ---------- +* 1 26 WS-C3750-24TS 12.1(14)EA1 C3750-I5-M +2 26 WS-C3750-24TS 12.1(14)EA1 C3750-I5-M +3 12 WS-C3750G-12S 12.1(14)EA1 C3750-I5-M + +Switch 02 +--------- +Switch Uptime : 1 hour, 29 minutes +Base ethernet MAC Address : 00:0D:29:B4:3F:00 +Motherboard assembly number : 73-7055-06 +Power supply part number : 341-0034-01 +Motherboard serial number : CAT07260438 +Power supply serial number : PHI0708008X +Model revision number : A0 +Motherboard revision number : A0 +Model number : WS-C3750-24TS-E +System serial number : CAT0726R10A + +Switch 03 +--------- +Switch Uptime : 1 hour, 29 minutes +Base ethernet MAC Address : 00:0D:BD:6A:3E:00 +Motherboard assembly number : 73-8307-06 +Power supply part number : 341-0048-01 +Motherboard serial number : CAT073205S2 +Power supply serial number : DTH0731055Z +Model revision number : A0 +Motherboard revision number : A0 +Model number : WS-C3750G-12S-E +System serial number : CAT0732R0M4 +Top assembly part number : 800-23419-01 +Top assembly revision number : A0 + +Configuration register is 0xF diff --git a/test/units/modules/network/ios/test_ios_facts.py b/test/units/modules/network/ios/test_ios_facts.py new file mode 100644 index 0000000000..c6bd8ca220 --- /dev/null +++ b/test/units/modules/network/ios/test_ios_facts.py @@ -0,0 +1,66 @@ +# 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.ios import ios_facts +from units.modules.utils import set_module_args +from .ios_module import TestIosModule, load_fixture + + +class TestIosFactsModule(TestIosModule): + + module = ios_facts + + def setUp(self): + super(TestIosFactsModule, self).setUp() + self.mock_run_commands = patch('ansible.modules.network.ios.ios_facts.run_commands') + self.run_commands = self.mock_run_commands.start() + + def tearDown(self): + super(TestIosFactsModule, 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('ios_facts_%s' % filename)) + return output + + self.run_commands.side_effect = load_from_file + + def test_ios_facts_stacked(self): + set_module_args(dict(gather_subset='default')) + result = self.execute_module() + self.assertEqual( + result['ansible_facts']['ansible_net_model'], 'WS-C3750-24TS' + ) + self.assertEqual( + result['ansible_facts']['ansible_net_serialnum'], 'CAT0726R0ZU' + ) + self.assertEqual( + result['ansible_facts']['ansible_net_stacked_models'], ['WS-C3750-24TS-E', 'WS-C3750-24TS-E', 'WS-C3750G-12S-E'] + ) + self.assertEqual( + result['ansible_facts']['ansible_net_stacked_serialnums'], ['CAT0726R0ZU', 'CAT0726R10A', 'CAT0732R0M4'] + )