diff --git a/MANIFEST.in b/MANIFEST.in index 8954c0d..e5aac22 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,6 +9,7 @@ include examples/elasticsearch/servers.py.example include examples/elasticsearch/kibana-dashboard.json include examples/firmwareupdater/hpilo_firmware_update include examples/ca/hpilo_ca +recursive-include examples/puppet *.rb *.pp *.erb include ilo.conf.example include COPYING include CHANGES diff --git a/docs/index.rst b/docs/index.rst index edaedcc..6f75af2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -106,6 +106,7 @@ dependencies. ca elasticsearch autofirmware + puppet Development information ======================= diff --git a/docs/puppet.rst b/docs/puppet.rst new file mode 100644 index 0000000..589b659 --- /dev/null +++ b/docs/puppet.rst @@ -0,0 +1,287 @@ +Managing iLO's with puppet +========================== + +Instead of writing your own code to manage iLO interfaces with python-hpilo, +you can also use a puppet module. While it doesn't support all the +functionality of hpilo.py or hpilo_cli, it does support the more common +functions (and more can be added, just file a bug!) + +It uses the same network device management framework as the existing tools to +manage cisco devices or F5 loadbalancers, so you don't need to install anything +special on each server and no custom iLO code is required. + +To install the module, simply copy the `modules/ilo` directory into your puppet +tree and follow the instructions below to create recipes. + +Caching +------- +This module heavily caches iLO output, most for more than a day. The cache is +invalidated if settings etc. are changed by this module, but if you make +changes manually, you will need to remove the cached information yourself. The +cache lives in the per-device directories in `/var/lib/puppet/devices`. + +Because of this caching, applying the catalog takes only a few seconds instead +of several minutes if there are no changes. + +Configuring puppet +------------------ +Please configure `hpilo_cli` itself first, including username and password. The +puppet `ilo` module works by using this tool. Once it works for you, you can +configure puppet. + +To use `puppet device` to manage iLO's, the iLO devices must be added to +`/etc/puppet/device.conf` on the server you want to use for managing them. + +The ilo module can be used in two ways: to manage an iLO remotely via HTTP and +to manage an iLO locally via hpilo. With the former you can manage many iLOs +from a single server, with the latter you can manage iLOs that are not (yet) +reachable via the network. + +To manage the local iLO, you can put something this in `device.conf`:: + + [server-001.ilo.kaarsemaker.net] + type ilo + url ilo://server-001.ilo.kaarsemaker.net + +Note that the scheme is `ilo://`, this makes the ilo module use `hpilo_cli` in +local mode. You must still use the ilo's FQDN though, as each node needs a +unique name in puppet. + +I personally prefer the network method and configuring DHCP properly so all +iLOs are reachable via the network. For this, `device.conf` looks like the +following:: + + [server-001.ilo.kaarsemaker.net] + type ilo + url http://server-001.ilo.kaarsemaker.net + + [server-002.ilo.kaarsemaker.net] + type ilo + url http://server-002.ilo.kaarsemaker.net + + [server-003.ilo.kaarsemaker.net] + type ilo + url http://server-003.ilo.kaarsemaker.net + +In fact, it's generated by the iLO module. The management server has this +snippet in its recipe: + +.. code-block:: puppet + + class s_mgmt { + class{'ilo::proxy': + devices => [ + "http://server-001.ilo.kaarsemaker.net", + "http://server-002.ilo.kaarsemaker.net", + "http://server-003.ilo.kaarsemaker.net", + ] + } + } + +Of course you can generate this however you want. + +Facts +----- +Several facts are available for use in your recipes. + +* `$devicetype` is set to `ilo` +* `$users` contains a list of all users +* `$firmware_version`, `$firmware_date`, `$management_processor`, and + `$license_type` are set to what `get_fw_version` provides +* `$oa_encl`, `$oa_rack`, `$oa_ipaddress`, `$oa_location`, `$oa_macaddress`, + `$oa_uidstatus` and `$oa_system_health` are set to what `get_oa_info` + provides. These are only available on blade servers. + +Managing users +-------------- +You can use this module to create, modify and delete users. Unfortunately the +normal `user` type cannot be used, so there's a special `ilo_user` type. + +.. code-block:: puppet + + ilo_user { + "Administrator": + admin_priv => true; + "jack": + ensure => absent; + "dkaarsemaker": + ensure => present, + display_name => 'Dennis Kaarsemaker', + password_atcreate => 'P4ssw0rd', + reset_server_priv => false; + "linda": + ensure => present, + password => 'hunter2' + display_name => 'Linda', + admin_priv => false, + config_ilo_priv => false, + reset_server_priv => true; + } + +These example users show the features of this type: + +* You can create (`ensure => present`) or delete (`ensure => absent`) users. +* You can manage their permissions (`admin_priv`, `config_ilo_priv`, + `remote_cons_priv`, `reset_server_priv` and `virtual_media_priv`) +* You can manage display names and passwords. Note that for users you want this + module to create, these are mandatory attributes. + +Because user passwords cannot be queried, this module has to check the password +every time by doing an http request. This can take a while and goes against the +aggressive caching. To prevent these constant checks, you can use the +`password_atcreate` parameter instead of the `password` parameter. This is only +used when creating the user and is not checked subsequently. Should you want to +change the user's password you can temporarily also add a `password` parameter +until all devices have been updated. + +Managing iLO firmware +--------------------- +The `ilo_firmware` type can be used to manage firmware on your iLOs. + +.. code-block:: puppet + + ilo_firmware { $management_processor: + ensure => "latest", + http_proxy => "http://webproxy:3128" + } + +The name of the resource must be the same as the iLO type, you can use a fact +to make sure it is. `ensure` accepts any version number or the string `latest`, +which will always upgrade to the latest version. + +`http_proxy` is optional and can be used to specify a proxy via which to +download the firmware config and firmware. + +Managing settings +----------------- +This module also includes an `ilo_settings` type. This is a relatively thin +wrapper around functions like `mod_global_settings` to configure any of the +following settings: global (`mod_global_settings`), network +(`mod_network_settings`), snmp (`mod_snmp_im_settings`) and directory +authentication (`mod_dir_config`). As with the above types, an example should +make it clear. + +.. code-block:: puppet + + ilo_settings { + "global": + settings => { + "remote_console_port" => 23, + "enforce_aes" => true, + "f8_login_required" => true, + }; + "network": + settings => { + "prim_dns_server" => "10.42.1.31", + "sec_dns_server" => "10.42.1.32", + }; + } + +As you can see, the individual settings are not all parameters, instead there's +only one settings parameter. Any setting that is not managed by puppet is +completely left alone by this module, there are no defaults. + +Installing licenses +------------------- +The last functionality (for now) is the `ilo_license` type, which you can use +to install licenses. + +.. code-block:: puppet + + ilo_license { "iLO 3 Advanced": + key => "12345-67890-ABCDE-FGHIJ-KLMNO" + } + +Note that the spelling of the license name is important. If it's not exactly +the same as what `get_all_licenses` shows, puppet will try to activate the +license again and again. + +Complete example +---------------- +And here's a complete example to put all the above together. + +`/etc/puppet/device.conf`:: + + [server-001.ilo.kaarsemaker.net] + type ilo + url http://server-001.ilo.kaarsemaker.net + +`/etc/puppet/manifests/nodes.pp` + +.. code-block:: puppet + + node 'management-server.kaarsemaker.net' { + include s_mgmt + } + + node 'server-001.ilo.kaarsemaker.net' { + include s_ilo + } + + node 'server-002.ilo.kaarsemaker.net' { + include s_ilo + } + + node 'server-003.ilo.kaarsemaker.net' { + include s_ilo + } + +`/etc/puppet/modules/s_mgmt/manifests/init.pp` + +.. code-block:: puppet + + class s_mgmt { + class{'ilo::proxy': + devices => [ + "http://server-001.ilo.kaarsemaker.net", + "http://server-002.ilo.kaarsemaker.net", + "http://server-003.ilo.kaarsemaker.net", + ] + } + } + +`/etc/puppet/modules/s_ilo/manifests/init.pp` + +.. code-block:: puppet + + class s_ilo { + + # Always upgrade firmware + ilo_firmware { $management_processor: + ensure => "latest", + http_proxy => "http://webproxy:3128" + } + + # We only have iLO 3's in this setup, so one license will do + ilo_license { "iLO 3 Advanced": + key => "12345-67890-ABCDE-FGHIJ-KLMNO" + } + + ilo_settings { + "global": + settings => { + "remote_console_port" => 23, + "enforce_aes" => true, + "f8_login_required" => true, + }; + "network": + settings => { + "prim_dns_server" => "10.42.1.31", + "sec_dns_server" => "10.42.1.32", + }; + } + + ilo_user { + "Administrator": + # Temporary until changed everywhere + password => 'P4ssw0rd', + "dennis": + ensure => present, + display_name => 'Dennis Kaarsemaker', + password_atcreate => 'MyPass!', + reset_server_priv => false; + # Remove leavers + ["jack", "bob"]: + ensure => absent, + } + } diff --git a/examples/puppet/modules/ilo/lib/puppet/provider/ilo.rb b/examples/puppet/modules/ilo/lib/puppet/provider/ilo.rb new file mode 100644 index 0000000..6f47029 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/provider/ilo.rb @@ -0,0 +1,20 @@ +require 'puppet/util/network_device/ilo/device' +require 'puppet/provider/network_device' + +class Puppet::Provider::Ilo < Puppet::Provider::NetworkDevice + attr_writer :device + + def self.device(url) + @device = Puppet::Util::NetworkDevice::Ilo::Device.new(url) + @device + end + + def self.mkcommands + @commands ||= {} + commands :python => "python", :hpilo_cli => "hpilo_cli"; + end + + def mkcommands + self.class.mkcommands + end +end diff --git a/examples/puppet/modules/ilo/lib/puppet/provider/ilo_firmware/ilo_firmware.rb b/examples/puppet/modules/ilo/lib/puppet/provider/ilo_firmware/ilo_firmware.rb new file mode 100644 index 0000000..b62b8af --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/provider/ilo_firmware/ilo_firmware.rb @@ -0,0 +1,42 @@ +require 'puppet/provider/ilo' + +Puppet::Type.type(:ilo_firmware).provide(:ilo_firmware, :parent => Puppet::Provider::Ilo) do + @doc = "Manages iLO firmware" + + def firmware_version() @property_hash[:firmware_version] end + + def self.lookup(device, id) + version = device.transport.get('get_fw_version') + { + :name => version['management_processor'], + :management_processor => version['management_processor'], + :firmware_version => version['firmware_version'], + :firmware_date => version['firmware_date'] + } + end + + def fw_config + old_https_proxy = ENV['https_proxy'] + old_http_proxy = ENV['http_proxy'] + begin + ENV['http_proxy'] = ENV['https_proxy'] = resource[:http_proxy] + device.transport.fw_config + ensure + ENV['https_proxy'] = old_https_proxy + ENV['http_proxy'] = old_http_proxy + end + + end + + def install + Puppet::debug("Installing firmware version #{@resource[:ensure]}") + old_https_proxy = ENV['https_proxy'] + old_http_proxy = ENV['http_proxy'] + begin + device.transport.call('update_rib_firmware', "version=#{@resource[:ensure]}") + ensure + ENV['https_proxy'] = old_https_proxy + ENV['http_proxy'] = old_http_proxy + end + end +end diff --git a/examples/puppet/modules/ilo/lib/puppet/provider/ilo_license/ilo_license.rb b/examples/puppet/modules/ilo/lib/puppet/provider/ilo_license/ilo_license.rb new file mode 100644 index 0000000..9099759 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/provider/ilo_license/ilo_license.rb @@ -0,0 +1,24 @@ +require 'puppet/provider/ilo' + +Puppet::Type.type(:ilo_license).provide(:ilo_license, :parent => Puppet::Provider::Ilo) do + @doc = "Manages iLO settings" + + mk_resource_methods + + def self.lookup(device, id) + instance = nil + device.transport.get('get_all_licenses').each do |license| + if license['license_type'] == id + instance = { + :name => license['license_type'], + :key => license['license_key'], + } + end + end + instance + end + + def flush + device.transport.call('activate_license', "key=#{properties[:key]}") + end +end diff --git a/examples/puppet/modules/ilo/lib/puppet/provider/ilo_settings/ilo_settings.rb b/examples/puppet/modules/ilo/lib/puppet/provider/ilo_settings/ilo_settings.rb new file mode 100644 index 0000000..2ce5f96 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/provider/ilo_settings/ilo_settings.rb @@ -0,0 +1,38 @@ +require 'puppet/provider/ilo' + +Puppet::Type.type(:ilo_settings).provide(:ilo_settings, :parent => Puppet::Provider::Ilo) do + @doc = "Manages iLO settings" + + attr_reader :supported + @supported = { + 'network' => { + :reader => 'get_network_settings', + :writer => 'mod_network_settings', + }, + 'global' => { + :reader => 'get_global_settings', + :writer => 'mod_global_settings', + }, + 'dir' => { + :reader => 'get_dir_config', + :writer => 'mod_dir_config', + }, + 'snmp' => { + :reader => 'get_snmp_im_settings', + :writer => 'mod_snmp_im_settings', + }, + + } + + mk_resource_methods + + def self.lookup(device, id) + fail Puppet::Error, "Unknown settings type #{id}" unless @supported.include?(id); + settings = device.transport.get(@supported[id][:reader]) + {:name => id, :writer => @supported[id][:writer], :settings => settings} + end + + def flush + device.transport.call(properties[:writer], *properties[:settings].map{|k,v| "#{k}=#{v}"}) + end +end diff --git a/examples/puppet/modules/ilo/lib/puppet/provider/ilo_user/ilo_user.rb b/examples/puppet/modules/ilo/lib/puppet/provider/ilo_user/ilo_user.rb new file mode 100644 index 0000000..cc3222d --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/provider/ilo_user/ilo_user.rb @@ -0,0 +1,55 @@ +require 'puppet/provider/ilo' + +Puppet::Type.type(:ilo_user).provide(:ilo_user, :parent => Puppet::Provider::Ilo) do + @doc = "Manages iLO users" + + mk_resource_methods + + def self.lookup(device, id) + begin + user = device.transport.get('get_user', "user_login=#{id}") + rescue + return nil + end + { + :name => user['user_login'], + :password => :absent, + :display_name => user['user_name'], + :admin_priv => user['admin_priv'], + :config_ilo_priv => user['config_ilo_priv'], + :remote_cons_priv => user['remote_cons_priv'], + :reset_server_priv => user['reset_server_priv'], + :virtual_media_priv => user['virtual_media_priv'], + } + end + + def verify_password(password) + device.transport.check_password(name, password) + end + + def propmap(props, oldprops=nil) + props = props.map do |k,v| + next if [:name, :ensure].include?(k) + next if oldprops and props[k] == oldprops[k] + if k == :display_name + "user_name=#{v}" + else + "#{k}=#{v}" + end + end + props.insert(0,"user_login=#{name}") + props.reject do |p| p == nil end + end + + def flush + if properties[:ensure] == :absent + device.transport.call('delete_user', "user_login=#{name}") + elsif former_properties[:ensure] == :absent: + cproperties = properties + cproperties[:password] ||= resource[:password_atcreate] + device.transport.call('add_user', *propmap(cproperties)) + else + device.transport.call('mod_user', *propmap(properties, former_properties)) + end + end +end diff --git a/examples/puppet/modules/ilo/lib/puppet/type/ilo_firmware.rb b/examples/puppet/modules/ilo/lib/puppet/type/ilo_firmware.rb new file mode 100644 index 0000000..7f521d3 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/type/ilo_firmware.rb @@ -0,0 +1,63 @@ +Puppet::Type.newtype(:ilo_firmware) do + desc "Manage iLO firmware" + + apply_to_device + + ensurable do + attr_accessor :latest + + newvalue(:latest) do + begin + provider.install + rescue => detail + self.fail "Could not update: #{detail}" + end + end + + newvalue(/./) do + begin + provider.install + rescue => detail + self.fail "Could not update: #{detail}" + end + end + + def insync?(is) + @should.each do |should| + case + when is == should + return true + when should == :latest && is == provider.fw_config[@resource.name.downcase]['version'] + return true + end + end + false + end + + def retrieve + provider.firmware_version + end + + defaultto :latest + + end + + newparam(:name, :namevar=>true) do + desc "Ilo type" + + validate do |value| + unless value =~ /ilo[234]?/i + fail Puppet::Error, "Unknown iLO type, '#{value}'" + end + if value.downcase != Facter.value(:management_processor).downcase + fail Puppet::Error, "This server has an #{Facter.value(:management_processor)}, not an #{value}" + end + end + + end + + newparam(:http_proxy) do + desc "HTTP proxy for downloading firmware" + defaultto "" + end +end diff --git a/examples/puppet/modules/ilo/lib/puppet/type/ilo_license.rb b/examples/puppet/modules/ilo/lib/puppet/type/ilo_license.rb new file mode 100644 index 0000000..9c94b84 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/type/ilo_license.rb @@ -0,0 +1,14 @@ +Puppet::Type.newtype(:ilo_license) do + desc "Manage iLO licenses" + + apply_to_device + + newparam(:name, :namevar=>true) do + desc "License name" + end + + newproperty(:key) do + desc "License key" + end + +end diff --git a/examples/puppet/modules/ilo/lib/puppet/type/ilo_settings.rb b/examples/puppet/modules/ilo/lib/puppet/type/ilo_settings.rb new file mode 100644 index 0000000..e4abc47 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/type/ilo_settings.rb @@ -0,0 +1,31 @@ +Puppet::Type.newtype(:ilo_settings) do + desc "Manage iLO settings" + + apply_to_device + + newparam(:name, :namevar=>true) do + desc "Which settings" + end + + newproperty(:settings) do + desc "The settings" + + def retrieve + provider.settings + end + + def insync?(is) + @should.each do |should| + is.keys.each do |key| + should.include?(key) || is.delete(key) + end + should.keys.each do |key| + return false if should[key].to_s != is[key].to_s + end + end + true + end + + end + +end diff --git a/examples/puppet/modules/ilo/lib/puppet/type/ilo_user.rb b/examples/puppet/modules/ilo/lib/puppet/type/ilo_user.rb new file mode 100644 index 0000000..d96eab2 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/type/ilo_user.rb @@ -0,0 +1,81 @@ +Puppet::Type.newtype(:ilo_user) do + desc "Manage iLO users" + + apply_to_device + + ensurable + + newparam(:name, :namevar=>true) do + desc "User loginname" + end + + def munge_boolean(value) + case value + when true, "true", :true + true + when false, "false", :false + false + else + fail("munge_boolean only takes booleans") + end + end + + newproperty(:password) do + desc "Password" + def insync?(is) + if(is == :absent) + return provider.verify_password(@should[0]) + end + is == @should[0] + end + end + + newparam(:password_atcreate) do + desc "Password, only used when creating users" + end + + newproperty(:display_name) do + desc "User's display name" + end + + newproperty(:admin_priv, :boolean => true) do + desc "Admin privileges" + newvalues(:true, :false) + munge do |value| @resource.munge_boolean(value) end + end + + newproperty(:config_ilo_priv, :boolean => true) do + desc "iLO configuration privileges" + newvalues(:true, :false) + munge do |value| @resource.munge_boolean(value) end + end + + newproperty(:remote_cons_priv, :boolean => true) do + desc "Remote console privileges" + newvalues(:true, :false) + munge do |value| @resource.munge_boolean(value) end + end + + newproperty(:reset_server_priv, :boolean => true) do + desc "Server reset privileges" + newvalues(:true, :false) + munge do |value| @resource.munge_boolean(value) end + end + + newproperty(:virtual_media_priv, :boolean => true) do + desc "Virtual Media privileges" + newvalues(:true, :false) + munge do |value| @resource.munge_boolean(value) end + end + + validate do + if @parameters[:ensure].value != :absent && !Facter.value(:users).include?(@parameters[:name].value) + unless @parameters.include?(:display_name) + raise Puppet::Error, "A display_name is mandatory for #{@parameters[:name].value}" + end + unless (@parameters.include?(:password) or @parameters.include?(:password_atcreate)) + raise Puppet::Error, "A password is mandatory for #{@parameters[:name].value}" + end + end + end +end diff --git a/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo.rb b/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo.rb new file mode 100644 index 0000000..1fead07 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo.rb @@ -0,0 +1,4 @@ +require 'puppet/util/network_device' + +module Puppet::Util::NetworkDevice::Ilo +end diff --git a/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo/device.rb b/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo/device.rb new file mode 100644 index 0000000..3d363ab --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo/device.rb @@ -0,0 +1,28 @@ +require 'puppet/util/network_device/ilo/facts' +require 'puppet/util/network_device/ilo/transport' +require 'uri' + +class Puppet::Util::NetworkDevice::Ilo::Device + + attr_accessor :hostname, :transport, :local + + def initialize(uri, option = {}) + uri = URI.parse(uri) + @hostname = uri.host + @local = uri.scheme == 'ilo' + @option = option + + Puppet.debug("(iLO device) connecting to iLO #{@hostname} #{@option.inspect}.") + @transport = Puppet::Util::NetworkDevice::Ilo::Transport.new(@hostname, @local) + Puppet.debug("Transport created") + end + + def facts + @facts = Puppet::Util::NetworkDevice::Ilo::Facts.new(@transport) + facts = @facts.retrieve + Puppet.debug("(iLO device) Facts retrieved: #{facts.inspect}") + facts.each do |k,v| Facter.add(k) do setcode do v end end end + facts + end + +end diff --git a/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo/facts.rb b/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo/facts.rb new file mode 100644 index 0000000..31a8920 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo/facts.rb @@ -0,0 +1,23 @@ +require 'puppet/util/network_device/ilo' + +class Puppet::Util::NetworkDevice::Ilo::Facts + + attr_reader :transport + + def initialize(transport) + @transport = transport + end + + def retrieve + facts = { + 'devicetype' => 'ilo', + 'users' => @transport.get('get_all_users'), + } + facts.merge! @transport.get('get_fw_version') + begin + facts.merge! Hash[@transport.get('get_oa_info').map{ |k,v| [ 'oa_'+ k, v ] }] + rescue + end + Hash[facts.map{ |k,v| [ k.to_sym, v ] }] + end +end diff --git a/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo/transport.rb b/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo/transport.rb new file mode 100644 index 0000000..fb88676 --- /dev/null +++ b/examples/puppet/modules/ilo/lib/puppet/util/network_device/ilo/transport.rb @@ -0,0 +1,124 @@ +require 'json' +require 'puppet/provider/ilo' + +module Puppet::Util::NetworkDevice::Ilo + class Transport + + attr_reader :hostname + + def initialize(hostname, local) + @hostname = hostname + @local = local + @provider = Puppet::Provider::Ilo.new(hostname) + @provider.mkcommands + @cachedir = File.join(Puppet[:confdir], 'cache') + Dir.mkdir(@cachedir) unless File.exist?(@cachedir) + @cachable = { + 'get_fw_version' => { + :updaters => ['update_rib_firmware'], + :ttl => 86400 * 3, + }, + 'get_global_settings' => { + :updaters => ['mod_global_settings'], + :ttl => 86400 * 2, + }, + 'get_network_settings' => { + :updaters => ['mod_network_settings'], + :ttl => 86400, + }, + 'get_all_licenses' => { + :updaters => ['activate_license'], + :ttl => 86400 * 4, + }, + 'get_dir_config' => { + :updaters => ['mod_dir_config'], + :ttl => 86400, + }, + 'get_snmp_im_settings' => { + :updaters => ['mod_snmp_im_settings'], + :ttl => 86400, + }, + 'get_user' => { + :updaters => ['add_user', 'mod_user', 'delete_user'], + :ttl => 86400, + }, + 'get_all_users' => { + :updaters => ['add_user', 'delete_user'], + :ttl => 86400, + }, + 'get_oa_info' => { + :updaters => [], + :ttl => 86400 * 3, + }, + } + @cachable.each do |k, v| + v[:updaters].push('factory_defaults') + end + end + + def call(method, *args) + @cachable.each do |reader,opts| + if(opts[:updaters].include?(method)) + cachefile = File.join(@cachedir, reader) + if File.exists?(cachefile) + File.unlink(cachefile) + end + Dir.glob(cachefile + '_*') do |filename| + File.unlink(filename) + end + end + end + args = args.clone + args.insert(0, '--json', @hostname, method) + args.insert(0, '-Plocal') if @local + @provider.hpilo_cli(*args) + end + + def get(method, *args) + args = args.clone + args.insert(0, '--json', @hostname, method) + if(@cachable.include?(method)) + cachefile = File.join(@cachedir, method) + if(args.length > 3) + cachefile += '_' + args.slice(3,args.length).join() + end + cutoff = Time.new - @cachable[method][:ttl] + if(File.exist?(cachefile) && File.mtime(cachefile) > cutoff) + args.insert(0, '--read-response', cachefile) + else + if File.exist?(cachefile) + File.unlink(cachefile) + end + args.insert(0, '--save-response', cachefile) + end + end + args.insert(0, '-Plocal') if @local + json = @provider.hpilo_cli(*args) + JSON.parse(json) + end + + def check_password(login, password) + begin + @provider.hpilo_cli('-l', login, '-p', password, @hostname, 'get_fw_version') + true + rescue + false + end + end + + def fw_config() + cachefile = File.join(File.dirname(Puppet[:confdir]), 'firmware.conf.json') + cutoff = Time.new - 86400 + if(!File.exist?(cachefile) || File.mtime(cachefile) < cutoff) + json = @provider.python("-c", "import hpilo_fw, json; print(json.dumps(hpilo_fw.config()))") + f = File.new(cachefile, 'w') + f.write(json) + f.close() + end + f = File.new(cachefile) + json = f.read() + f.close() + JSON.parse(json) + end + end +end diff --git a/examples/puppet/modules/ilo/manifests/init.pp b/examples/puppet/modules/ilo/manifests/init.pp new file mode 100644 index 0000000..3b1c64e --- /dev/null +++ b/examples/puppet/modules/ilo/manifests/init.pp @@ -0,0 +1,20 @@ +class ilo::proxy($devices) { + package{['ruby-json', 'python-hpilo']: + ensure => latest, + } + concat{"/etc/puppet/device.conf": + ensure => present, + mode => 400, + owner => root, + group => root, + } + device{$devices:} + + define device() { + concat::fragment{"ilo-device-$name": + target => "/etc/puppet/device.conf", + content => template("ilo/ilo-device.erb") + } + } +} + diff --git a/examples/puppet/modules/ilo/templates/ilo-device.erb b/examples/puppet/modules/ilo/templates/ilo-device.erb new file mode 100644 index 0000000..0a12556 --- /dev/null +++ b/examples/puppet/modules/ilo/templates/ilo-device.erb @@ -0,0 +1,8 @@ +<% +require 'uri' +uri = URI.parse(name) +-%> +[<%= uri.host %>] +type ilo +url <%= uri.to_s %> +