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}}},