Its been a year since my last post, and I’m thinking its time to make another.

Lately I’ve been trying to work through some network management solutions to try and define the problem more clearly. This is an interesting problem primary because I’m unable to rely on my previous tool sets to get this done. Namely, Puppet running on the host.

There are a couple interesting Python tools for this purpose that I’d given a spin, but the more I was working in them, the more I was wishing I was writing in Go. Most of my actively maintained code these days is Go, and working in two languages for personal infrastructure tooling means I can’t leverage the libraries of one tool in another.

Goals

Unify the following elements.

  • Multiple Junos network devices with different configuration requirements
  • Leverage LDAP for inventory
  • Fill in the gaps with YAML data
  • Complete project and migration in one weekend

Tooling

Inventory

The inventory bits were pretty straightforward here. The schema I came up with contained the following object attributes.

  • hostname
  • domain
  • role
  • platform
  • device type

Reading those attributes into a device struct was pleasant enough. Once I had an object I was able to move on to loading data from YAML.

YAML Data Loading

This was two fold, develop a method that worked a bit like Hiera, but just merged the data into struct I could work with easily.

The following config file allows the varios levels to contain template strings, from which I can render based on a given device. The fields are members on the host struct, making it simple to extend for template lookup also.

data_dir: "data"
hierarchy:
  - "global.yaml"
  - "role/{{ .Role }}.yaml"
  - "host/{{ .Name }}.yaml"

template_dir: "templates"
template_paths:
  - "platform/{{ .Platform }}"
  - "role/{{ .Role }}"

Since the templates will require the data to fully render, the data gets looked first. Each file encountered is read and merged into the previous struct. This has the result of a final object that has the most specific options merged in last to arrive at something I can pass into a template.

To discover the templates, I’m loading all templates found with the .tmpl file extension.

Final loop

From there, its just a matter of constructing some loop over the inventory and requesting that the configuration happen, optionally with a commit set. Defaulting to to a no-op seems good.

commit := false
for _, host := range hosts {
  z.ConfigureNetworkHost(&host, commit)
}

The full loop is pretty light. You can see it here in full to get an idea what’s taking place.

The 13th Hour

I spent about as much time as I had wanted. About 13 hours in total.

While I don’t expect tooling to be useful to anyone, maybe there are useful ideas from which to glean for your own environment. I don’t have too many network configuration requirements on my personal network, though I think this pattern would transition nicely to my professional network. Even if the complexity were to grow, I would expect this to scale for my needs indefinitely.