homeblogpuppet network device management

Puppet Network Device Management

Looking for more device management? Read about it here: Managing F5 BIG-IP Network Devices with Puppet Puppet 2.7.0 was recently released. This version, like every new Puppet release, brings numerous new features (and not counting bug fixes), including one I'm very proud of: Network Device Management. This all started during the Puppet Camp Europe 2010 in Ghent. One of the open space session was about managing non-POSIX systems like remote devices, database systems or proprietary appliances on which we can't directly run Puppet. Returning from the Puppet Camp, I started to think about implementing a network device management stack in Puppet, and several months later the feature was added to Puppet. The Puppet Network Device system is a way to configure some network devices' (switches, routers) aspects. This is currently limited to a subset of Cisco IOS devices at that time, but the system could be extended with new device types. For the moment only two aspects of a network device can be managed:
  • interfaces
  • vlans

A Bird's-Eye View

The configuration system does roughly the following:
  • connect to the device, through ssh or telnet
  • authenticate as a user (possibly unprivileged in which case it can "enable")
  • check the current device state
  • apply the necessary changes as IOS commands to bring it to the correct state
To achieve this, Puppet 2.7.0 introduces a new Puppet application called 'puppet device'. This application will run on a Puppet node (multiple puppet device can run on different hosts) and will make sure a given list of network devices will be managed. This application acts as a smart proxy between the Puppet Master and the managed network device. To do this, puppet device will sequentially connects to the master on behalf of the managed network device and will ask for a catalog (a catalog containing only network device resources). It will then apply this catalog to the said device by translating the resources to orders the network device understands. Puppet device will then report back to the master for any changes and failures as a standard node.

Closer Look at Puppet Device

Puppet device is not yet a daemon, so the best way to run it is to schedule it with cron. Puppet device knows the devices it will manage by reading a simple configuration file: "/etc/puppet/device.conf". If the node on which puppet device runs is managed by Puppet, this file can be created by Puppet itself. This file contains the list of device to manage with this instance of puppet device. It has this format:
  [device1 certname]
  type cisco
  url ssh://puppet:letmein@device.domain.com/

  [device2 certname]
  type cisco
  url telnet://puppet:letmein@router.domain.com/?enable=enablepassword
You'll notice that the configuration file lists three things:
  • the device certname. This is the name your master will refer to this device.
  • the device type. currently only cisco is supported
  • the device URL
The device URL must mention:
  • the access method. For the moment only ssh:// and telnet:// are supported
  • the user and password to connect to the device
  • the network hostname of said device
  • any potential TCP port
  • an enable password for unprivileged users requiring one
I mentioned certname in the description above. Yes, that means every device will have its own certificate in the Puppet ecosystem. This guarantees the security of the infrastructure, and allows to revoke devices when needed. The downside is that you'll have to sign those certificate, like we do for every puppet node. Puppet device acts like the regular Puppet Agent in this area, it will wait for a certificate if one of the managed device is not yet signed.

Enough Talk—Let's Configure a Switch!

Let's suppose we're managing a small cisco 2950 switch (and that's good because I have one next to me), and that we want to manage some of its interfaces. This switch is a layer 2 only switch, so we won't configure any IP Address, just bare switch interfaces. Let's first add the node to our puppet manifests:
  node "c2950.domain.com" {

    Interface {
      duplex => auto,
      speed => auto

    interface {
      "FastEthernet 0/1":
        description => "--> to end-user workstation",
        mode => access,
        native_vlan => 1000

    interface {
      # abbreviated interface name are supported
        description => "--> to web server (channel 1)",
        mode => access,
        etherchannel => 1

    interface {
        description => "--> to web server (channel 1)",
        mode => access,
        etherchannel => 1

    interface {
        description => "--> to upstream router",
        mode => trunk,
        allowed_trunk_vlans => "99, 1000"
We configured 4 interfaces, one for a standard workstation, two parts of a bonding channel, and finally one trunk to a router. And when we run puppet device, the following happens:
  info: starting applying configuration to c2950.domain.com
  info: Caching catalog for c2950.domain.com
  info: Applying configuration version '1308408722'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[GigabitEthernet0/1]/description: defined 'description' as '--> to upstream router'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[GigabitEthernet0/1]/mode: mode changed 'access' to 'trunk'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[GigabitEthernet0/1]/allowed_trunk_vlans: defined 'allowed_trunk_vlans' as '99,1000'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[FastEthernet 0/1]/description: defined 'description' as '--> to end-user workstation'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[FastEthernet 0/1]/native_vlan: defined 'native_vlan' as '1000'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[FastEthernet 0/1]/mode: mode changed 'trunk' to 'access'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[FastEthernet0/18]/description: defined 'description' as '--> to web server (channel 1)'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[FastEthernet0/18]/etherchannel: defined 'etherchannel' as '1'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[Fa0/17]/description: defined 'description' as '--> to web server (channel 1)'
  notice: /Stage[main]//Node[c2950.domain.com]/Interface[Fa0/17]/etherchannel: defined 'etherchannel' as '1'
  notice: Finished catalog run in 28.24 seconds
We can see that the configuration was applied interface by interface and properties by properties. Let's connect to the switch to check the configuration changed:
  c2950#sh interfaces FastEthernet 0/1 status

  Port      Name               Status       Vlan       Duplex  Speed Type
  Fa0/1     --> to end-user wo connect      1000         auto   auto 10/100BaseTX

  c2950#sh etherchannel 1 summary 
  Number of channel-groups in use: 1
  Number of aggregators:           1

  Group  Port-channel  Protocol    Ports
  1      Po1(SD)         PAgP      Fa0/17(D)   Fa0/18(D)   

  c2950#sh running-config interface GigabitEthernet 0/1
  Building configuration...
  interface GigabitEthernet0/1
   description --> to upstream router
   switchport trunk allowed vlan 99,1000
   switchport mode trunk
We can also manage vlan with the puppet vlan type:
  node "c2950.domain.com" {
    vlan {
        description => "G&A_Dept"
This will make sure the vlan 103 exists and has the correct "G&A_Dept" name:
  info: starting applying configuration to c2950.domain.com
  info: Caching catalog for c2950.domain.com
  info: Applying configuration version '1308409100'
  notice: /Stage[main]//Node[c2950.domain.com]/Vlan[103]/ensure: created
  notice: Finished catalog run in 21.04 seconds
Let's check it worked:
  c2950#sh vlan         

  VLAN Name                             Status    Ports
  ---- -------------------------------- --------- -------------------------------
  103  G&A_Dept                         active    

And Routers?

This feature also allows to manage layer 3 interfaces. The only configurable aspect for router interface at this time is IP Addresses. Both IPv4 and IPv6 addresses are supported:
  node "c877.domain.com" {
    interface {
        ipaddress => [ "", "2001:2674:8C23::1/64" ]
And after running this manifest we can check it did setup the correct ip addresses:
  c877#sh running-config interface vlan 12
  interface Vlan12
   description Vlan12
   ip address
   ipv6 address 2001:2674:8C23::1/64


Another important part of puppet is the ability for the node to send to the master its "facts". The puppet network device system also supports a limited number of facts:
  • hostname: configured hostname
  • uptime, uptime_seconds and uptime_days
  • hardwaremodel, processor, hardwarerevision
  • memorysize
  • operatingsystem, operatingsystemrelease


The Puppet Network Device system is still very new. For instance, I found several bugs/regressions while I was writing this article (issues for which I sent patches for review). Bug reports and/or patches are more than welcome!

The Future

People might find strange this feature was added, in a world where networking becomes less and less prominent with more and more infrastructure being virtualized in the cloud. I believe managing network device will still happen (for instance in cloud provider networks). I also see this software brick as the base of new features to manage cloud specific resources (for instance ec2 load balancers or VPN clouds). Still, there are plenty of things we can add to this new system:
  • new device types, or device models
  • more configurable aspects (access lists, routes, vpns)
  • new puppet device features: ENC-like for device sources, daemonization, parallelism
We're ready for your contributions :)