diff options
| author | Pieter van de Bruggen <pieter@puppetlabs.com> | 2011-04-18 13:40:31 -0700 |
|---|---|---|
| committer | Pieter van de Bruggen <pieter@puppetlabs.com> | 2011-04-18 14:08:32 -0700 |
| commit | 07b677c5f6af8def03c5c30393fd83bc3986239a (patch) | |
| tree | b28d3376b4ea835a2348ebfea898d674cb593e34 /lib/puppet | |
| parent | b142973a94ced6c0ff43da882189abe806c18c68 (diff) | |
| download | puppet-07b677c5f6af8def03c5c30393fd83bc3986239a.tar.gz puppet-07b677c5f6af8def03c5c30393fd83bc3986239a.tar.xz puppet-07b677c5f6af8def03c5c30393fd83bc3986239a.zip | |
Merge remote-tracking branch 'community/feature/puppet-device' into 2.7.x
Reviewed-By: Mike Stahnke
Diffstat (limited to 'lib/puppet')
| -rw-r--r-- | lib/puppet/application/device.rb | 255 | ||||
| -rw-r--r-- | lib/puppet/defaults.rb | 5 | ||||
| -rw-r--r-- | lib/puppet/indirector/facts/network_device.rb | 25 | ||||
| -rw-r--r-- | lib/puppet/provider/cisco.rb | 9 | ||||
| -rw-r--r-- | lib/puppet/provider/interface/cisco.rb | 18 | ||||
| -rw-r--r-- | lib/puppet/provider/network_device.rb | 21 | ||||
| -rw-r--r-- | lib/puppet/provider/vlan/cisco.rb | 14 | ||||
| -rw-r--r-- | lib/puppet/resource/catalog.rb | 1 | ||||
| -rw-r--r-- | lib/puppet/transaction.rb | 4 | ||||
| -rw-r--r-- | lib/puppet/type.rb | 28 | ||||
| -rw-r--r-- | lib/puppet/type/interface.rb | 2 | ||||
| -rwxr-xr-x | lib/puppet/type/schedule.rb | 2 | ||||
| -rw-r--r-- | lib/puppet/type/vlan.rb | 2 | ||||
| -rw-r--r-- | lib/puppet/util/command_line.rb | 3 | ||||
| -rw-r--r-- | lib/puppet/util/network_device.rb | 12 | ||||
| -rw-r--r-- | lib/puppet/util/network_device/base.rb | 32 | ||||
| -rw-r--r-- | lib/puppet/util/network_device/cisco/device.rb | 10 | ||||
| -rw-r--r-- | lib/puppet/util/network_device/cisco/facts.rb | 72 | ||||
| -rw-r--r-- | lib/puppet/util/network_device/config.rb | 93 | ||||
| -rw-r--r-- | lib/puppet/util/network_device/transport.rb | 4 | ||||
| -rw-r--r-- | lib/puppet/util/network_device/transport/ssh.rb | 4 |
21 files changed, 565 insertions, 51 deletions
diff --git a/lib/puppet/application/device.rb b/lib/puppet/application/device.rb new file mode 100644 index 000000000..df5bac26a --- /dev/null +++ b/lib/puppet/application/device.rb @@ -0,0 +1,255 @@ +require 'puppet/application' +require 'puppet/util/network_device' + + +class Puppet::Application::Device < Puppet::Application + + should_parse_config + run_mode :agent + + attr_accessor :args, :agent, :host + + def preinit + # Do an initial trap, so that cancels don't get a stack trace. + trap(:INT) do + $stderr.puts "Cancelling startup" + exit(0) + end + + { + :waitforcert => nil, + :detailed_exitcodes => false, + :verbose => false, + :debug => false, + :centrallogs => false, + :setdest => false, + }.each do |opt,val| + options[opt] = val + end + + @args = {} + end + + option("--centrallogging") + option("--debug","-d") + option("--verbose","-v") + + option("--detailed-exitcodes") do |arg| + options[:detailed_exitcodes] = true + end + + option("--logdest DEST", "-l DEST") do |arg| + begin + Puppet::Util::Log.newdestination(arg) + options[:setdest] = true + rescue => detail + puts detail.backtrace if Puppet[:debug] + $stderr.puts detail.to_s + end + end + + option("--waitforcert WAITFORCERT", "-w") do |arg| + options[:waitforcert] = arg.to_i + end + + option("--port PORT","-p") do |arg| + @args[:Port] = arg + end + + def help + <<-HELP + +puppet-device(8) -- Manage remote network devices +======== + +SYNOPSIS +-------- +Retrieves all configurations from the puppet master and apply +them to the remote devices configured in /etc/puppet/device.conf. + +Currently must be run out periodically, using cron or something similar. + +USAGE +----- + puppet device [-d|--debug] [--detailed-exitcodes] [-V|--version] + [-h|--help] [-l|--logdest syslog|<file>|console] + [-v|--verbose] [-w|--waitforcert <seconds>] + + +DESCRIPTION +----------- +Once the client has a signed certificate for a given remote device, it will +retrieve its configuration and apply it. + +USAGE NOTES +----------- +One need a /etc/puppet/device.conf file with the following content: + +[remote.device.fqdn] +type <type> +url <url> + +where: + * type: the current device type (the only value at this time is cisco) + * url: an url allowing to connect to the device + +Supported url must conforms to: + scheme://user:password@hostname/?query + + with: + * scheme: either ssh or telnet + * user: username, can be omitted depending on the switch/router configuration + * password: the connection password + * query: this is device specific. Cisco devices supports an enable parameter whose + value would be the enable password. + +OPTIONS +------- +Note that any configuration parameter that's valid in the configuration file +is also a valid long argument. For example, 'server' is a valid configuration +parameter, so you can specify '--server <servername>' as an argument. + +* --debug: + Enable full debugging. + +* --detailed-exitcodes: + Provide transaction information via exit codes. If this is enabled, an + exit code of '2' means there were changes, and an exit code of '4' means + that there were failures during the transaction. This option only makes + sense in conjunction with --onetime. + +* --help: + Print this help message + +* --logdest: + Where to send messages. Choose between syslog, the console, and a log file. + Defaults to sending messages to syslog, or the console if debugging or + verbosity is enabled. + +* --verbose: + Turn on verbose reporting. + +* --waitforcert: + This option only matters for daemons that do not yet have certificates + and it is enabled by default, with a value of 120 (seconds). This causes + +puppet agent+ to connect to the server every 2 minutes and ask it to sign a + certificate request. This is useful for the initial setup of a puppet + client. You can turn off waiting for certificates by specifying a time + of 0. + +EXAMPLE +------- + $ puppet device --server puppet.domain.com + +AUTHOR +------ +Brice Figureau + + +COPYRIGHT +--------- +Copyright (c) 2011 Puppet Labs, LLC +Licensed under the Apache 2.0 License + HELP + end + + + def main + vardir = Puppet[:vardir] + confdir = Puppet[:confdir] + certname = Puppet[:certname] + + # find device list + require 'puppet/util/network_device/config' + devices = Puppet::Util::NetworkDevice::Config.devices + if devices.empty? + Puppet.err "No device found in #{Puppet[:deviceconfig]}" + exit(1) + end + devices.each_value do |device| + begin + Puppet.info "starting applying configuration to #{device.name} at #{device.url}" + + # override local $vardir and $certname + Puppet.settings.set_value(:confdir, File.join(Puppet[:devicedir], device.name), :cli) + Puppet.settings.set_value(:vardir, File.join(Puppet[:devicedir], device.name), :cli) + Puppet.settings.set_value(:certname, device.name, :cli) + + # this will reload and recompute default settings and create the devices sub vardir, or we hope so :-) + Puppet.settings.use :main, :agent, :ssl + + # this init the device singleton, so that the facts terminus + # and the various network_device provider can use it + Puppet::Util::NetworkDevice.init(device) + + # ask for a ssl cert if needed, but at least + # setup the ssl system for this device. + setup_host + + require 'puppet/configurer' + configurer = Puppet::Configurer.new + report = configurer.run(:network_device => true) + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err detail.to_s + ensure + Puppet.settings.set_value(:vardir, vardir, :cli) + Puppet.settings.set_value(:confdir, confdir, :cli) + Puppet.settings.set_value(:certname, certname, :cli) + end + end + end + + # Handle the logging settings. + def setup_logs + if options[:debug] or options[:verbose] + Puppet::Util::Log.newdestination(:console) + if options[:debug] + Puppet::Util::Log.level = :debug + else + Puppet::Util::Log.level = :info + end + end + + Puppet::Util::Log.newdestination(:syslog) unless options[:setdest] + end + + def setup_host + @host = Puppet::SSL::Host.new + waitforcert = options[:waitforcert] || (Puppet[:onetime] ? 0 : 120) + cert = @host.wait_for_cert(waitforcert) + end + + def setup + setup_logs + + args[:Server] = Puppet[:server] + if options[:centrallogs] + logdest = args[:Server] + + logdest += ":" + args[:Port] if args.include?(:Port) + Puppet::Util::Log.newdestination(logdest) + end + + Puppet.settings.use :main, :agent, :device, :ssl + + # Always ignoreimport for agent. It really shouldn't even try to import, + # but this is just a temporary band-aid. + Puppet[:ignoreimport] = true + + # We need to specify a ca location for all of the SSL-related i + # indirected classes to work; in fingerprint mode we just need + # access to the local files and we don't need a ca. + Puppet::SSL::Host.ca_location = :remote + + Puppet::Transaction::Report.indirection.terminus_class = :rest + + # Override the default; puppetd needs this, usually. + # You can still override this on the command-line with, e.g., :compiler. + Puppet[:catalog_terminus] = :rest + + Puppet[:facts_terminus] = :network_device + + Puppet::Resource::Catalog.indirection.cache_class = :yaml + end +end diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 680762b94..dbd5a9437 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -487,6 +487,11 @@ module Puppet This should match how often the hosts report back to the server."] ) + setdefaults(:device, + :devicedir => {:default => "$vardir/devices", :mode => "750", :desc => "The root directory of devices' $vardir"}, + :deviceconfig => ["$confdir/device.conf","Path to the device config file for puppet device"] + ) + setdefaults(:agent, :localconfig => { :default => "$statedir/localconfig", :owner => "root", diff --git a/lib/puppet/indirector/facts/network_device.rb b/lib/puppet/indirector/facts/network_device.rb new file mode 100644 index 000000000..c9bac803e --- /dev/null +++ b/lib/puppet/indirector/facts/network_device.rb @@ -0,0 +1,25 @@ +require 'puppet/node/facts' +require 'puppet/indirector/code' + +class Puppet::Node::Facts::NetworkDevice < Puppet::Indirector::Code + desc "Retrieve facts from a network device." + + # Look a device's facts up through the current device. + def find(request) + result = Puppet::Node::Facts.new(request.key, Puppet::Util::NetworkDevice.current.facts) + + result.add_local_facts + result.stringify + result.downcase_if_necessary + + result + end + + def destroy(facts) + raise Puppet::DevError, "You cannot destroy facts in the code store; it is only used for getting facts from a remote device" + end + + def save(facts) + raise Puppet::DevError, "You cannot save facts to the code store; it is only used for getting facts from a remote device" + end +end
\ No newline at end of file diff --git a/lib/puppet/provider/cisco.rb b/lib/puppet/provider/cisco.rb new file mode 100644 index 000000000..918982f59 --- /dev/null +++ b/lib/puppet/provider/cisco.rb @@ -0,0 +1,9 @@ +require 'puppet/util/network_device/cisco/device' +require 'puppet/provider/network_device' + +# This is the base class of all prefetched cisco device providers +class Puppet::Provider::Cisco < Puppet::Provider::NetworkDevice + def self.device(url) + Puppet::Util::NetworkDevice::Cisco::Device.new(url) + end +end diff --git a/lib/puppet/provider/interface/cisco.rb b/lib/puppet/provider/interface/cisco.rb index f3bd202e9..795a7f1ac 100644 --- a/lib/puppet/provider/interface/cisco.rb +++ b/lib/puppet/provider/interface/cisco.rb @@ -1,22 +1,20 @@ -require 'puppet/util/network_device/cisco/device' -require 'puppet/provider/network_device' +require 'puppet/provider/cisco' -Puppet::Type.type(:interface).provide :cisco, :parent => Puppet::Provider::NetworkDevice do +Puppet::Type.type(:interface).provide :cisco, :parent => Puppet::Provider::Cisco do desc "Cisco switch/router provider for interface." mk_resource_methods - def self.lookup(url, name) + def self.lookup(device, name) interface = nil - network_gear = Puppet::Util::NetworkDevice::Cisco::Device.new(url) - network_gear.command do |ng| - interface = network_gear.interface(name) + device.command do |ng| + interface = device.interface(name) end interface end - def initialize(*args) + def initialize(device, *args) super end @@ -26,8 +24,4 @@ Puppet::Type.type(:interface).provide :cisco, :parent => Puppet::Provider::Netwo end super end - - def device - @device ||= Puppet::Util::NetworkDevice::Cisco::Device.new(resource[:device_url]) - end end diff --git a/lib/puppet/provider/network_device.rb b/lib/puppet/provider/network_device.rb index 58865fddc..b178df977 100644 --- a/lib/puppet/provider/network_device.rb +++ b/lib/puppet/provider/network_device.rb @@ -2,17 +2,22 @@ # This is the base class of all prefetched network device provider class Puppet::Provider::NetworkDevice < Puppet::Provider - def self.lookup(url, name) + def self.device(url) + raise "This provider doesn't implement the necessary device method" + end + + def self.lookup(device, name) raise "This provider doesn't implement the necessary lookup method" end def self.prefetch(resources) resources.each do |name, resource| - if result = lookup(resource[:device_url], name) + device = Puppet::Util::NetworkDevice.current || device(resource[:device_url]) + if result = lookup(device, name) result[:ensure] = :present - resource.provider = new(result) + resource.provider = new(device, result) else - resource.provider = new(:ensure => :absent) + resource.provider = new(device, :ensure => :absent) end end end @@ -21,8 +26,12 @@ class Puppet::Provider::NetworkDevice < Puppet::Provider @property_hash[:ensure] != :absent end - def initialize(*args) - super + attr_accessor :device + + def initialize(device, *args) + super(*args) + + @device = device # Make a duplicate, so that we have a copy for comparison # at the end. diff --git a/lib/puppet/provider/vlan/cisco.rb b/lib/puppet/provider/vlan/cisco.rb index 46e172c73..3421d35b0 100644 --- a/lib/puppet/provider/vlan/cisco.rb +++ b/lib/puppet/provider/vlan/cisco.rb @@ -1,22 +1,20 @@ -require 'puppet/util/network_device/cisco/device' -require 'puppet/provider/network_device' +require 'puppet/provider/cisco' -Puppet::Type.type(:vlan).provide :cisco, :parent => Puppet::Provider::NetworkDevice do +Puppet::Type.type(:vlan).provide :cisco, :parent => Puppet::Provider::Cisco do desc "Cisco switch/router provider for vlans." mk_resource_methods - def self.lookup(url, id) + def self.lookup(device, id) vlans = {} - device = Puppet::Util::NetworkDevice::Cisco::Device.new(url) device.command do |d| vlans = d.parse_vlans || {} end vlans[id] end - def initialize(*args) + def initialize(device, *args) super end @@ -27,8 +25,4 @@ Puppet::Type.type(:vlan).provide :cisco, :parent => Puppet::Provider::NetworkDev end super end - - def device - @device ||= Puppet::Util::NetworkDevice::Cisco::Device.new(resource[:device_url]) - end end diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb index 98c29657e..a6cff9bdc 100644 --- a/lib/puppet/resource/catalog.rb +++ b/lib/puppet/resource/catalog.rb @@ -133,6 +133,7 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph transaction.report = options[:report] if options[:report] transaction.tags = options[:tags] if options[:tags] transaction.ignoreschedules = true if options[:ignoreschedules] + transaction.for_network_device = options[:network_device] transaction.add_times :config_retrieval => self.retrieval_duration || 0 diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index d7845fbc9..3728a2fff 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -12,7 +12,7 @@ class Puppet::Transaction require 'puppet/transaction/resource_harness' require 'puppet/resource/status' - attr_accessor :component, :catalog, :ignoreschedules + attr_accessor :component, :catalog, :ignoreschedules, :for_network_device attr_accessor :configurator # The report, once generated. @@ -339,6 +339,8 @@ class Puppet::Transaction resource.warning "Skipping because of failed dependencies" elsif resource.virtual? resource.debug "Skipping because virtual" + elsif resource.appliable_to_device? ^ for_network_device + resource.debug "Skipping #{resource.appliable_to_device? ? 'device' : 'host'} resources because running on a #{for_network_device ? 'device' : 'host'}" else return false end diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index c0e5d390b..656b8f264 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -116,6 +116,26 @@ class Type ens end + def self.apply_to_device + @apply_to = :device + end + + def self.apply_to_host + @apply_to = :host + end + + def self.apply_to_all + @apply_to = :both + end + + def self.apply_to + @apply_to ||= :host + end + + def self.can_apply_to(target) + [ target == :device ? :device : :host, :both ].include?(apply_to) + end + # Deal with any options passed into parameters. def self.handle_param_options(name, options) # If it's a boolean parameter, create a method to test the value easily @@ -1895,6 +1915,14 @@ class Type def virtual?; !!@virtual; end def exported?; !!@exported; end + + def appliable_to_device? + self.class.can_apply_to(:device) + end + + def appliable_to_host? + self.class.can_apply_to(:host) + end end end diff --git a/lib/puppet/type/interface.rb b/lib/puppet/type/interface.rb index 7560a0552..d3b5cb06f 100644 --- a/lib/puppet/type/interface.rb +++ b/lib/puppet/type/interface.rb @@ -10,6 +10,8 @@ Puppet::Type.newtype(:interface) do interface mode (access or trunking, native vlan and encapsulation), switchport characteristics (speed, duplex)." + apply_to_device + ensurable do defaultvalues diff --git a/lib/puppet/type/schedule.rb b/lib/puppet/type/schedule.rb index 5fb008f6f..f60f96fd2 100755 --- a/lib/puppet/type/schedule.rb +++ b/lib/puppet/type/schedule.rb @@ -43,6 +43,8 @@ module Puppet This will cause resources to be applied every 30 minutes by default. " + apply_to_all + newparam(:name) do desc "The name of the schedule. This name is used to retrieve the schedule when assigning it to an object: diff --git a/lib/puppet/type/vlan.rb b/lib/puppet/type/vlan.rb index 6708ea4f5..e39daf994 100644 --- a/lib/puppet/type/vlan.rb +++ b/lib/puppet/type/vlan.rb @@ -5,6 +5,8 @@ Puppet::Type.newtype(:vlan) do @doc = "This represents a router or switch vlan." + apply_to_device + ensurable newparam(:name) do diff --git a/lib/puppet/util/command_line.rb b/lib/puppet/util/command_line.rb index a884b8658..714d03f74 100644 --- a/lib/puppet/util/command_line.rb +++ b/lib/puppet/util/command_line.rb @@ -14,7 +14,8 @@ module Puppet 'queue' => 'puppetqd', 'resource' => 'ralsh', 'kick' => 'puppetrun', - 'master' => 'puppetmasterd' + 'master' => 'puppetmasterd', + 'device' => 'puppetdevice' ) def initialize(zero = $0, argv = ARGV, stdin = STDIN) diff --git a/lib/puppet/util/network_device.rb b/lib/puppet/util/network_device.rb index bca66016b..d9c1aa34d 100644 --- a/lib/puppet/util/network_device.rb +++ b/lib/puppet/util/network_device.rb @@ -1,2 +1,12 @@ -module Puppet::Util::NetworkDevice +class Puppet::Util::NetworkDevice + class << self + attr_reader :current + end + + def self.init(device) + require "puppet/util/network_device/#{device.provider}/device" + @current = Puppet::Util::NetworkDevice.const_get(device.provider.capitalize).const_get(:Device).new(device.url) + rescue => detail + raise "Can't load #{device.provider} for #{device.name}: #{detail}" + end end
\ No newline at end of file diff --git a/lib/puppet/util/network_device/base.rb b/lib/puppet/util/network_device/base.rb index ff96c8693..7d6c3fc44 100644 --- a/lib/puppet/util/network_device/base.rb +++ b/lib/puppet/util/network_device/base.rb @@ -3,27 +3,25 @@ require 'uri' require 'puppet/util/network_device/transport' require 'puppet/util/network_device/transport/base' -module Puppet::Util::NetworkDevice - class Base +class Puppet::Util::NetworkDevice::Base - attr_accessor :url, :transport + attr_accessor :url, :transport - def initialize(url) - @url = URI.parse(url) + def initialize(url) + @url = URI.parse(url) - @autoloader = Puppet::Util::Autoload.new( - self, - "puppet/util/network_device/transport", - :wrap => false - ) + @autoloader = Puppet::Util::Autoload.new( + self, + "puppet/util/network_device/transport", + :wrap => false + ) - if @autoloader.load(@url.scheme) - @transport = Puppet::Util::NetworkDevice::Transport.const_get(@url.scheme.capitalize).new - @transport.host = @url.host - @transport.port = @url.port || case @url.scheme ; when "ssh" ; 22 ; when "telnet" ; 23 ; end - @transport.user = @url.user - @transport.password = @url.password - end + if @autoloader.load(@url.scheme) + @transport = Puppet::Util::NetworkDevice::Transport.const_get(@url.scheme.capitalize).new + @transport.host = @url.host + @transport.port = @url.port || case @url.scheme ; when "ssh" ; 22 ; when "telnet" ; 23 ; end + @transport.user = @url.user + @transport.password = @url.password end end end
\ No newline at end of file diff --git a/lib/puppet/util/network_device/cisco/device.rb b/lib/puppet/util/network_device/cisco/device.rb index 1f350991a..005470e13 100644 --- a/lib/puppet/util/network_device/cisco/device.rb +++ b/lib/puppet/util/network_device/cisco/device.rb @@ -3,6 +3,7 @@ require 'puppet/util' require 'puppet/util/network_device/base' require 'puppet/util/network_device/ipcalc' require 'puppet/util/network_device/cisco/interface' +require 'puppet/util/network_device/cisco/facts' require 'ipaddr' class Puppet::Util::NetworkDevice::Cisco::Device < Puppet::Util::NetworkDevice::Base @@ -91,6 +92,15 @@ class Puppet::Util::NetworkDevice::Cisco::Device < Puppet::Util::NetworkDevice:: interface end + def facts + @facts ||= Puppet::Util::NetworkDevice::Cisco::Facts.new(transport) + facts = {} + command do |ng| + facts = @facts.retrieve + end + facts + end + def interface(name) ifname = canonalize_ifname(name) interface = parse_interface(ifname) diff --git a/lib/puppet/util/network_device/cisco/facts.rb b/lib/puppet/util/network_device/cisco/facts.rb new file mode 100644 index 000000000..40e2b37c2 --- /dev/null +++ b/lib/puppet/util/network_device/cisco/facts.rb @@ -0,0 +1,72 @@ + +require 'puppet/util/network_device/cisco' +require 'puppet/util/network_device/ipcalc' + +# this retrieves facts from a cisco device +class Puppet::Util::NetworkDevice::Cisco::Facts + + attr_reader :transport + + def initialize(transport) + @transport = transport + end + + def retrieve + facts = {} + facts.merge(parse_show_ver) + end + + def parse_show_ver + facts = {} + out = @transport.command("sh ver") + lines = out.split("\n") + lines.shift; lines.pop + lines.each do |l| + case l + # cisco WS-C2924C-XL (PowerPC403GA) processor (revision 0x11) with 8192K/1024K bytes of memory. + # Cisco 1841 (revision 5.0) with 355328K/37888K bytes of memory. + # Cisco 877 (MPC8272) processor (revision 0x200) with 118784K/12288K bytes of memory. + # cisco WS-C2960G-48TC-L (PowerPC405) processor (revision C0) with 61440K/4088K bytes of memory. + # cisco WS-C2950T-24 (RC32300) processor (revision R0) with 19959K bytes of memory. + when /[cC]isco ([\w-]+) (?:\(([\w-]+)\) processor )?\(revision (.+)\) with (\d+[KMG])(?:\/(\d+[KMG]))? bytes of memory\./ + facts[:hardwaremodel] = $1 + facts[:processor] = $2 if $2 + facts[:hardwarerevision] = $3 + facts[:memorysize] = $4 + # uptime + # Switch uptime is 1 year, 12 weeks, 6 days, 22 hours, 32 minutes + # c2950 uptime is 3 weeks, 1 day, 23 hours, 36 minutes + # c2960 uptime is 2 years, 27 weeks, 5 days, 21 hours, 30 minutes + # router uptime is 5 weeks, 1 day, 3 hours, 30 minutes + when /^\s*([\w-]+)\s+uptime is (.*?)$/ + facts[:hostname] = $1 + facts[:uptime] = $2 + facts[:uptime_seconds] = uptime_to_seconds($2) + facts[:uptime_days] = facts[:uptime_seconds] / 86400 + # "IOS (tm) C2900XL Software (C2900XL-C3H2S-M), Version 12.0(5)WC10, RELEASE SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease => "12.0(5)WC10", :operatingsystemmajrelease => "12.0", :operatingsystemfeature => "C3H2S"}, + # "IOS (tm) C2950 Software (C2950-I6K2L2Q4-M), Version 12.1(22)EA8a, RELEASE SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease => "12.1(22)EA8a", :operatingsystemmajrelease => "12.1", :operatingsystemfeature => "I6K2L2Q4"}, + # "Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 12.2(44)SE, RELEASE SOFTWARE (fc1)"=>{ :operatingsystem => "IOS", :operatingsystemrelease => "12.2(44)SE", :operatingsystemmajrelease => "12.2", :operatingsystemfeature => "LANBASEK9"}, + # "Cisco IOS Software, C870 Software (C870-ADVIPSERVICESK9-M), Version 12.4(11)XJ4, RELEASE SOFTWARE (fc2)"=>{ :operatingsystem => "IOS", :operatingsystemrelease => "12.4(11)XJ40", :operatingsystemmajrelease => "12.4XJ", :operatingsystemfeature => "ADVIPSERVICESK9"}, + # "Cisco IOS Software, 1841 Software (C1841-ADVSECURITYK9-M), Version 12.4(24)T4, RELEASE SOFTWARE (fc2)" =>{ :operatingsystem => "IOS", :operatingsystemrelease => "12.4(24)T4", :operatingsystemmajrelease => "12.4T", :operatingsystemfeature => "ADVSECURITYK9"}, + when /(?:Cisco )?(IOS)\s*(?:\(tm\) |Software, )?(?:\w+)\s+Software\s+\(\w+-(\w+)-\w+\), Version ([0-9.()A-Za-z]+),/ + facts[:operatingsystem] = $1 + facts[:operatingsystemrelease] = $3 + facts[:operatingsystemmajrelease] = ios_major_version(facts[:operatingsystemrelease]) + facts[:operatingsystemfeature] = $2 + end + end + facts + end + + def ios_major_version(version) + version.gsub(/^(\d+)\.(\d+)\(.+\)([A-Z]+)([\da-z]+)?/, '\1.\2\3') + end + + def uptime_to_seconds(uptime) + captures = (uptime.match /^(?:(?:(?:(?:(\d+) years?,)?\s*(\d+) weeks?,)?\s*(\d+) days?,)?\s*(\d+) hours?,)?\s*(\d+) minutes?$/).captures + seconds = captures.zip([31536000, 604800, 86400, 3600, 60]).inject(0) do |total, (x,y)| + total + (x.nil? ? 0 : x.to_i * y) + end + end + +end
\ No newline at end of file diff --git a/lib/puppet/util/network_device/config.rb b/lib/puppet/util/network_device/config.rb new file mode 100644 index 000000000..17f4e254c --- /dev/null +++ b/lib/puppet/util/network_device/config.rb @@ -0,0 +1,93 @@ +require 'ostruct' +require 'puppet/util/loadedfile' + +class Puppet::Util::NetworkDevice::Config < Puppet::Util::LoadedFile + + def self.main + @main ||= self.new + end + + def self.devices + main.devices || [] + end + + attr_reader :devices + + def exists? + FileTest.exists?(@file) + end + + def initialize() + @file = Puppet[:deviceconfig] + + raise Puppet::DevError, "No device config file defined" unless @file + return unless self.exists? + super(@file) + @devices = {} + + read(true) # force reading at start + end + + # Read the configuration file. + def read(force = false) + return unless FileTest.exists?(@file) + + parse if force or changed? + end + + private + + def parse + begin + devices = {} + device = nil + File.open(@file) { |f| + count = 1 + f.each { |line| + case line + when /^\s*#/ # skip comments + count += 1 + next + when /^\s*$/ # skip blank lines + count += 1 + next + when /^\[([\w.]+)\]\s*$/ # [device.fqdn] + name = $1 + name.chomp! + raise ConfigurationError, "Duplicate device found at line #{count}, already found at #{device.line}" if devices.include?(name) + device = OpenStruct.new + device.name = name + device.line = count + Puppet.debug "found device: #{device.name} at #{device.line}" + devices[name] = device + when /^\s*(type|url)\s+(.+)$/ + parse_directive(device, $1, $2, count) + else + raise ConfigurationError, "Invalid line #{count}: #{line}" + end + count += 1 + } + } + rescue Errno::EACCES => detail + Puppet.err "Configuration error: Cannot read #{@file}; cannot serve" + #raise Puppet::Error, "Cannot read #{@config}" + rescue Errno::ENOENT => detail + Puppet.err "Configuration error: '#{@file}' does not exit; cannot serve" + end + + @devices = devices + end + + def parse_directive(device, var, value, count) + case var + when "type" + device.provider = value + when "url" + device.url = value + else + raise ConfigurationError, + "Invalid argument '#{var}' at line #{count}" + end + end + +end
\ No newline at end of file diff --git a/lib/puppet/util/network_device/transport.rb b/lib/puppet/util/network_device/transport.rb index e64fe9b69..cef8f3859 100644 --- a/lib/puppet/util/network_device/transport.rb +++ b/lib/puppet/util/network_device/transport.rb @@ -1,5 +1,3 @@ # stub -module Puppet::Util::NetworkDevice - module Transport - end +module Puppet::Util::NetworkDevice::Transport end
\ No newline at end of file diff --git a/lib/puppet/util/network_device/transport/ssh.rb b/lib/puppet/util/network_device/transport/ssh.rb index b3cf51b8a..bf0e7193c 100644 --- a/lib/puppet/util/network_device/transport/ssh.rb +++ b/lib/puppet/util/network_device/transport/ssh.rb @@ -31,6 +31,10 @@ class Puppet::Util::NetworkDevice::Transport::Ssh < Puppet::Util::NetworkDevice: @ssh = Net::SSH.start(host, user, :port => port, :password => password, :timeout => timeout) rescue TimeoutError raise TimeoutError, "timed out while opening an ssh connection to the host" + rescue Net::SSH::AuthenticationFailed + raise Puppet::Error, "SSH authentication failure connecting to #{host} as #{user}" + rescue Net::SSH::Exception => detail + raise Puppet::Error, "SSH connection failure to #{host}" end @buf = "" |
