Using exec with puppet device management?

305 views
Skip to first unread message

red 888

unread,
Dec 18, 2015, 6:10:23 PM12/18/15
to Puppet Users

I'm trying to use puppet's network device management feature to configure Cisco routers.

I know its just running ios commands so how can I extend it by having it run my own ios commands? I want to use this to create my own facts and do other stuff.

On a windows endpoint I can use exec to run shell commands:

exec { 'test':
      command => 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -executionpolicy remotesigned -file C:\test.ps1',
    }

How can I do something like this with puppet device?

When I tried running an ios command it gave me an error:

exec { 'test':
   command => 'show ip int bri'
}

Info: Caching catalog for 123.123.123.123
Error: Failed to apply catalog: Validation of Exec[test] failed: 'show ip int bri' is not qualified and no path was specified. Please qualify the command or specify a path. at /etc/puppet/environments/production/modules/ciscorouterconfig/manifests/init.pp:82
shell returned 1

jcbollinger

unread,
Dec 21, 2015, 10:40:05 AM12/21/15
to Puppet Users


On Friday, December 18, 2015 at 5:10:23 PM UTC-6, red 888 wrote:

I'm trying to use puppet's network device management feature to configure Cisco routers.

I know its just running ios commands so how can I extend it by having it run my own ios commands? I want to use this to create my own facts and do other stuff.


Note in particular this important remark from the 'puppet device' manual page: "Retrieves all configurations from the puppet master and apply them to the remote devices configured in /etc/puppetlabs/puppet/device.conf."  It perhaps takes a bit of reading between the lines to understand that 'puppet device' runs on an ordinary node on your network that can access your router(s) remotely to configure it.  You include the appropriate Puppet resources in the catalog for that node, and when you run 'puppet device' on that node it retrieves the node's catalog, extracts the pertinent resources (as chosen based in part on the contents of the node's device.conf file), and applies them to the device(s).  There is a puppet agent that runs directly on some Cisco devices, but that's an altogether different thing.

 

On a windows endpoint I can use exec to run shell commands:

exec { 'test':
      command => 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -executionpolicy remotesigned -file C:\test.ps1',
    }

How can I do something like this with puppet device?

When I tried running an ios command it gave me an error:

exec { 'test':
   command => 'show ip int bri'
}

Info: Caching catalog for 123.123.123.123
Error: Failed to apply catalog: Validation of Exec[test] failed: 'show ip int bri' is not qualified and no path was specified. Please qualify the command or specify a path. at /etc/puppet/environments/production/modules/ciscorouterconfig/manifests/init.pp:82
shell returned 1



Some of Puppet's diagnostics are not very good, but I don't see how this particular one could be improved: "'show ip int bri' is not qualified and no path was specified. Please qualify the command or specify a path."  If that's not quite enough, then it seems the next logical thing to do would be to consult the documentation for the Exec resource type.  The bottom line is that either the path to the command binary must be either specified explicitly or among those given via the Exec's 'path' parameter.  The former would look something like

exec { 'demo':
 
# for example only
  command
=> '/usr/bin/show ip int bri'
}

.  Note, however, that Exec runs commands on the node to which the catalog is applied, so the command must be one available on that machine.  If you are using 'puppet device' then you cannot run IOS commands via an Exec because the node to which the catalog is being applied is not the router itself, and therefore it is unlikely to be running IOS.  Even if it were running IOS, it's unclear whether that's the router on which you actually want the command to run.  You could, however, use an Exec to open a telnet or ssh connection to the router with which to execute a remote command; that is akin to how the built-in device management types work, but those do not themselves use an Exec.

I am a bit uncertain what you mean by "facts".  Of course, Puppet relies integrally on node facts provided via Facter, but it's unclear how those would be relevant to your objective of managing network devices via 'puppet device', since with that subsystem the node involved is not the device being managed.  The Cisco implementation ('provider') of the device-management types (i.e. interface and vlan) has an internal sense of device facts, but these appear not to be related to Facter and not to be customizable.  Similarly, I see no mechanism there for executing arbitrary IOS commands, but there is a pretty wide range of device properties that you can configure that way (see the referenced docs).

If the facilities already available do not adequately address your needs then you should consider filing a feature-request ticket.  Because such a feature request will take some time to be fulfilled if it is accepted at all, if you want to do something that is not presently supported then you could consider writing an Exec that connects remotely and runs a command of your choice, as described above.


John

red 888

unread,
Dec 21, 2015, 1:30:16 PM12/21/15
to Puppet Users
Thanks for replying!

I'm aware of how puppet device works and I know there is no actual agent software running on the Cisco device (I'm not talking about the newer OnePK thing).

My question was how can I use this to send my own commands in a integrated way- meaning the same way Puppet Device does it.

"You could, however, use an Exec to open a telnet or ssh connection to the router with which to execute a remote command; that is akin to how the built-in device management types work"

Opening my own instance of telent/ssh defeats the purpose- I want to do it "how the built-in device management" feature does it. Meaning I have already defined the IPs and authentication info for my routers in device.conf and I don't want to have to hard code that info into the module. 

Puppet device already has that telnet/ssh connection info so how can I send the devices my own arbitrary commands from my module?

Is there a way I can refer to the telnet session/connection in my module and just enter my own commands?

jcbollinger

unread,
Dec 22, 2015, 10:02:59 AM12/22/15
to Puppet Users


On Monday, December 21, 2015 at 12:30:16 PM UTC-6, red 888 wrote:
Thanks for replying!

I'm aware of how puppet device works and I know there is no actual agent software running on the Cisco device (I'm not talking about the newer OnePK thing).

My question was how can I use this to send my own commands in a integrated way- meaning the same way Puppet Device does it.


There is nothing particularly magical about 'puppet device'.  It relies on the same Puppet infrastructure as the agent, and in fact, it seems mostly to be just a specialization of the agent.  The "integrated way" in which 'puppet device' delivers commands to network devices is not directly accessible at the DSL level.  It is an aspect of the Ruby implementations of the providers for the resource types managed by that mechanism.

 

"You could, however, use an Exec to open a telnet or ssh connection to the router with which to execute a remote command; that is akin to how the built-in device management types work"

Opening my own instance of telent/ssh defeats the purpose- I want to do it "how the built-in device management" feature does it. Meaning I have already defined the IPs and authentication info for my routers in device.conf and I don't want to have to hard code that info into the module.


I don't see where hard-coding data into your module comes in.  Pretty much no one wants to do that; instead they externalize and centralize their data.  You could, too.

But if you are serious about using the same infrastructure that the providers for the existing resource types use, then you are talking about writing a custom type and provider -- a remote analog of Exec.  That is a significant undertaking, especially considering that the goal is something that must fit even more poorly into the Puppet model than does Exec itself.  If you want to pursue this course anyway, then the Puppet Developers group would be a more appropriate place to discuss the details.  Most of those folks participate here, too, but they're more likely to notice your question.  Before you go there, however, you should read the Custom Type documentation and study, say, the current implementation of the Interface resource type and its provider to get oriented to the task.

You should also consider whether you really need Puppet to issue arbitrary commands to your routers.  Puppet is fundamentally a state-management service, and it works best when used that way.  If you can characterize the objective of the IOS commands you want to run in terms of managing some aspect of the state of the device, especially an aspect whose value can be not only twiddled but examined, then it would probably be both easier and better to achieve that objective by adding a property to one of the existing resource types used by 'puppet device'.  Of course, I would suggest doing that in the context of a feature request.

 

Puppet device already has that telnet/ssh connection info so how can I send the devices my own arbitrary commands from my module?



Well no, it's not 'puppet device' itself that has that (I don't think), it's the providers for the custom types involved.  There are no hooks for it in the DSL, but as I said, you could write your own custom type, with a provider that uses the same Ruby support base.

 
Is there a way I can refer to the telnet session/connection in my module and just enter my own commands?



Not without first writing a pile of Ruby code to make it possible, no.

It is perhaps appropos to observe at this point, as I have at times in the past, that Puppet is not a script engine.  Puppet DSL has some script-like characteristics, but its role is solely to describe how to build catalogs; the agent never sees DSL.  For their part, Puppet catalogs are not scripts, nor script analogues: they are data.  The Puppet agent -- or its special-purpose analog, 'puppet device' -- uses catalog data and its own configuration to determine what actions to perform.  Therefore, if you want one of those Puppet services to manage a particular piece of state for you then you must convey that request by causing appropriate resources to be included in the target node's catalog.  If there is no existing resource type by which you can describe what you want, then you need to create one.


John

red 888

unread,
Dec 22, 2015, 10:50:37 AM12/22/15
to Puppet Users
Thanks for taking the time to answer my questions. 

It seems like Puppet isn't the right tool for what I want to accomplish or I will have to wait for native full featured Cisco support.

I think my confusion came from the notion that extending puppet in this way was a simple end usery task.

I thought, for example, if I wanted to push out an EIGRP message digest configuration (currently puppet device can't do this out of the box) I could plug in my own code/ios commands somewhere and refer to it in my module the same way I do other "resources'" like this (sloppy pseudo code):

keychain {
  name => chainName
  keynumber => 5
  key-string => zzzzzzzz
}

interface {
  'GigabitEthernet 0/1':
    description => $interface_description_lan
  eigrp keychain {
    as => 123
    name => chainName
  }
}

But, if I understand what you are saying, that would require a great deal of coding.  Being that I am not a ruby dev this would probably be a waste of my time.

jcbollinger

unread,
Dec 22, 2015, 3:00:45 PM12/22/15
to Puppet Users


On Tuesday, December 22, 2015 at 9:50:37 AM UTC-6, red 888 wrote:
Thanks for taking the time to answer my questions. 

It seems like Puppet isn't the right tool for what I want to accomplish or I will have to wait for native full featured Cisco support.

I think my confusion came from the notion that extending puppet in this way was a simple end usery task.


Puppet's end users are generally sysadmins, so what is simple and end-usery for them is not necessarily very simple in an absolute sense.  Even so, I'm not sure how you got the notion you describe.  I've always found Puppet DSL to be fairly easy to use, but writing extensions is developing for Puppet, not using it, and Puppet's native language is Ruby.  Perhaps you fell victim to precisely the misconception that I just denounced: that Puppet's language is some oddball form of scripting language.  As I said, it isn't.

 

I thought, for example, if I wanted to push out an EIGRP message digest configuration (currently puppet device can't do this out of the box) I could plug in my own code/ios commands somewhere and refer to it in my module the same way I do other "resources'" like this (sloppy pseudo code):

keychain {
  name => chainName
  keynumber => 5
  key-string => zzzzzzzz
}

interface {
  'GigabitEthernet 0/1':
    description => $interface_description_lan
  eigrp keychain {
    as => 123
    name => chainName
  }
}



No.  Each resource type has a specific set of attributes that it supports, each with specific semantics.  In this sense (and in most others) Puppet resource types are much closer analogs to Java or C++ classes than Puppet classes are.

 
But, if I understand what you are saying, that would require a great deal of coding.  Being that I am not a ruby dev this would probably be a waste of my time.



I don't know exactly how much "a great deal" of coding would be to you, but the amount involved is certainly a lot more than zero, and in addition to Ruby issues, there would be the learning curve specific to Puppet development.  I imagine the end result would have at least a few hundred lines of Ruby code (but having done that once and gotten it working, you could reuse it widely).  If you were looking for something you could do in a Monday morning, then no, I don't think this is it.

On the other hand, if configuring EIGRP digest parameters is something you imagine others might want to do too, then you should consider filing a feature request ticket.

BTW, do you plan to delete your SO question on this topic?  It would be a waste for me to write an answer there if you're just going to delete the question.


John

Reply all
Reply to author
Forward
0 new messages