Your network inventory

  • by Patrick Ogenstad
  • April 25, 2018

I dare to say that most organizations know less about their network than they want to. Especially when there’s a need to describe the network or use the information in any way. In theory, there might be a lot of things that are known about the network. However, often it’s hidden away in someone’s head, or some wiki page, old Visio diagrams or just lost to the ages.

A lot of companies, even large ones still don’t have their network devices in DNS. While DNS isn’t by any means a requirement the lack of it is usually an indication that the organization doesn’t have a good data source which contains information about their network. DNS is of course not enough. When talking about zero-touch provisioning you need some data source which you can query in order to get a complete picture of what the configuration should look like.

In some environments, it could be that most of the configuration should look identical for all devices. It is much, much easier to automate such an environment. Though even in that kind of environment each device will have different IP addresses and you need some place to keep track of these.

Choosing an inventory system

You will have to find a system which suits your needs and I won’t cover that in this tutorial. There are a lot of commercial and open source inventory, CMDB or IPAM solutions to choose from. You also might end up creating your own one if you can’t find any other tool that provides what you need.

The important part is that you have a single source of truth which can be queried by a program, i.e. it can’t be written down in a Wiki or a post-it note. If you don’t know where to start Netbox could be an option. Regardless of which tool you use you will probably start with doing a brownfield discovery of your network.

If you don’t have an inventory at all you won’t have a zero-touch provisioning system, you will only have a system with a delayed first touch.

The inventory in this tutorial

To keep things simple in this guide I won’t be using an external system and instead relying on a Yaml file. There are four devices in the inventory:

  • og-sw-01 - My existing switch
  • og-sw-02 - The first new switch, connected to og-sw-01 and lab-sw-01
  • lab-sw-01 - A switch connected to og-sw-01 and lab-rtr-01
  • lab-rtr-01 - A router, connected lab-sw-01

I’ve created the file /opt/ztp/devices.yaml

---
og-sw-01:
  management_ip: 172.29.50.3
  ip_interfaces:
    - name: Vlan20
      ip: 172.29.50.3
      mask: 255.255.255.224
  links:
    - interface: "FastEthernet0/7"
      interface_brief: fa0_7
      neighbor: og-sw-02
      neighbor_if: GigabitEthernet0/1
  location: desk
  platform: c2960
  model: WS-C2960-8TC-L
  gateway: 172.29.50.1
  vlans:
    - id: 20
      name: TRANSIT

og-sw-02:
  management_ip: 172.29.50.14
  ip_interfaces:
    - name: Vlan20
      ip: 172.29.50.14
      mask: 255.255.255.224
  links:
    - interface: "GigabitEthernet0/1"
      interface_brief: ge0_1
      neighbor: og-sw-01
      neighbor_if: FastEthernet0/7
      access_vlan: 20
      snooping_trust: True
    - interface: FastEthernet0/2
      interface_brief: fa0_2
      neighbor: lab-sw-01
      neighbor_if: FastEthernet0/1
      access_vlan: 20
  location: desk
  platform: c2960
  model: WS-C2960-8TC-S
  gateway: 172.29.50.1
  vlans:
    - id: 20
      name: TRANSIT

lab-sw-01:
  management_ip: 172.29.50.15
  ip_interfaces:
    - name: Vlan20
      ip: 172.29.50.15
      mask: 255.255.255.224
  links:
    - interface: "FastEthernet0/1"
      interface_brief: Fa0_1
      neighbor: og-sw-02
      neighbor_if: FastEthernet0/2
      access_vlan: 20
      snooping_trust: True
    - interface: FastEthernet0/4
      interface_brief: Fa0_4
      neighbor_if: FastEthernet4
      neighbor: lab-rtr-01
      access_vlan: 20
  location: closet
  platform: c2960
  model: WS-C2960C-8TC-L
  gateway: 172.29.50.1
  vlans:
    - id: 20
      name: TRANSIT


lab-rtr-01:
  management_ip: 172.29.50.16
  ip_interfaces:
    - name: FastEthernet4
      ip: 172.29.50.16
      mask: 255.255.255.224
    - name: Vlan100
      ip: 192.168.10.1
      mask: 255.255.255.0
      ip_helper: 172.29.58.10
    - name: Vlan200
      ip: 192.168.12.1
      mask: 255.255.255.0
      ip_helper: 172.29.58.10
  links:
    - interface: "FastEthernet4"
      snooping_trust: True
      interface_brief: fa4
      neighbor: lab-sw-01
      neighbor_if: FastEthernet0/4
    - interface: "FastEthernet0"
      interface_brief: fa0
      neighbor: lab-sw-01
      neighbor_if: FastEthernet0/1
      trunk:
        vlans:
          - 100
          - 200
        native: 100
  location: closet
  platform: c880
  model: 881
  gateway: 172.29.50.1
  vlans:
    - id: 100
      name: MANAGEMENT
    - id: 200
      name: USERS

Some of you might gasp at the mention of FastEthernet, while others are horrified about the duplication of data. I am more in the camp of the second group, of course, we don’t want to define the same data twice. If you are wondering what I’m talking about each link gets entered twice, one time for each host where it is connected. The management IP addresses could have been handled differently too. I do it here to highlight the issue though, it’s fine to have this format if the data is autogenerated from another source. One other thing to keep in mind is that it’s really easy to make errors in Yaml files, for instance, we could have accidentally entered the same IP address for og-sw-01 and og-sw-02. It’s always a good idea to validate and test input like this by an automated system. Another reason is to simplify the code needed to use this inventory, while Python is needed to complete the tutorial this isn’t a tutorial about learning Python.

We will need to read this file from our application so install a Yaml parser.

pip install ruamel.yaml

To end this part we add a small snippet of code in /opt/ztp/app/inventory.py to load the device data.

import ruamel.yaml

inventory_file = '/opt/ztp/devices.yaml'


with open(inventory_file, "r") as f:
    yml = ruamel.yaml.YAML(typ="rt", pure=True)
    devices = yml.load(f)