Yesterday I attended a short presentation held by David Barroso introducing the NAPALM-„Validation“-Module.
Configuring the Network fully automated is just half the way to go.
Checking the Network-State the other half.
Python-Script
Had to try it out the easy-way using just python (without ansible) first:
import napalm #just to get the DICT returned by the "compliance_report"-Method in a readable manner on the screen import pprint pp = pprint.PrettyPrinter() iosdriver = napalm.get_network_driver('ios') DEVICE="192.168.2.139" USER="rmond" PASS="rmondpassword" router = iosdriver(hostname=DEVICE, username=USER, password=PASS, optional_args={'port': 22, 'dest_file_system': 'bootflash:'}) router.open() report = router.compliance_report("validate.yaml") router.close() pp.pprint(report)
Static YAML-File
Validating against the following static „validate.yaml“-File:
- get_facts: hostname: CSR-1-DC os_version: CSR1000V Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 15.4(2)S3, RELEASE SOFTWARE (fc2) interface_list: list: - GigabitEthernet1 - GigabitEthernet2 - GigabitEthernet3 - GigabitEthernet4 - VirtualPortGroup0 - get_interfaces_ip: GigabitEthernet1: ipv4: 192.168.2.139: prefix_length: 25
leads to the following result
{u'complies': False, 'get_facts': {u'complies': True, u'extra': [], u'missing': [], u'present': {'hostname': {u'complies': True, u'nested': False}, 'interface_list': {u'complies': True, u'nested': True}, 'os_version': {u'complies': True, u'nested': False}}}, 'get_interfaces_ip': {u'complies': False, u'extra': [], u'missing': [], u'present': {'GigabitEthernet1': {u'complies': False, u'diff': {u'complies': False, u'extra': [], u'missing': [], u'present': {'ipv4': {u'complies': False, u'diff': {u'complies': False, u'extra': [], u'missing': [], u'present': {'192.168.2.139': {u'complies': False, u'diff': {u'complies': False, u'extra': [], u'missing': [], u'present': {'prefix_length': {u'actual_value': 24, u'complies': False, u'expected_value': 25, u'nested': False}}}, u'nested': True}}}, u'nested': True}}}, u'nested': True}}}, u'skipped': []}
Whats wrong with the Router?
„nested = True“ means – the issue is downward in the datastructure.
In the example, the first Object with „nested = False“ is „prefix_length“
The Prefix-Length („Subnet-Mask“) is wrong:
- wanted: /25-Bit
- configured: /24-Bit.
Validate the output of commands which use additional parameters
Example: Ping to the Default-Gateway
First: Get familiar with the datastructure returned by the command:
>>> pp.pprint(router.ping("192.168.2.1")) {u'success': {u'packet_loss': 0, u'probes_sent': 5, u'results': [{u'ip_address': u'192.168.2.1', u'rtt': 0.0}, {u'ip_address': u'192.168.2.1', u'rtt': 0.0}, {u'ip_address': u'192.168.2.1', u'rtt': 0.0}, {u'ip_address': u'192.168.2.1', u'rtt': 0.0}, {u'ip_address': u'192.168.2.1', u'rtt': 0.0}], u'rtt_avg': 1.0, u'rtt_max': 2.0, u'rtt_min': 1.0, u'rtt_stddev': 0.0}}
add the following portion to the YAML-File:
- ping: _name: Default-Gateway _kwargs: destination: "192.168.2.1" success: packet_loss: 0
Result (Success)
>>> pp.pprint(router.compliance_report("validate.yaml")) {'Default-Gateway': {u'complies': True, u'extra': [], u'missing': [], u'present': {'success': {u'complies': True, u'nested': True}}},
Result (failure)
>>> pp.pprint(router.compliance_report("validate.yaml")) {'Default-Gateway': {u'complies': False, u'extra': [], u'missing': [], u'present': {'success': {u'complies': False, u'diff': {u'complies': False, u'extra': [], u'missing': [], u'present': {'packet_loss': {u'actual_value': -1, u'complies': False, u'expected_value': 0, u'nested': False}}}, u'nested': True}}},