From 0358830fa758847788e1b5aa0452cfb5725135ea Mon Sep 17 00:00:00 2001 From: John Trowbridge Date: Tue, 15 Sep 2015 11:13:38 -0400 Subject: [PATCH] Add ironic-inspector support Add the ability to configure the ironic-inspector service for doing introspection of bare metal nodes. Closes-Bug: 1486197 Change-Id: I9b2917a2c3f6afe75dc295c81d09f7a12856007f --- .../ironic_inspector_config/ini_setting.rb | 10 + lib/puppet/type/ironic_inspector_config.rb | 53 ++++ manifests/db/inspector_sync.pp | 21 ++ manifests/inspector.pp | 273 ++++++++++++++++++ manifests/params.pp | 36 ++- spec/acceptance/basic_ironic_spec.rb | 70 +++-- spec/classes/inspector_db_sync_spec.rb | 44 +++ spec/classes/ironic_inspector_spec.rb | 190 ++++++++++++ .../ini_setting_spec.rb | 71 +++++ .../unit/type/ironic_inspector_config_spec.rb | 19 ++ templates/inspector_dnsmasq_http.erb | 9 + templates/inspector_dnsmasq_tftp.erb | 7 + templates/inspector_ipxe.erb | 7 + templates/inspector_pxelinux_cfg.erb | 6 + 14 files changed, 780 insertions(+), 36 deletions(-) create mode 100644 lib/puppet/provider/ironic_inspector_config/ini_setting.rb create mode 100644 lib/puppet/type/ironic_inspector_config.rb create mode 100644 manifests/db/inspector_sync.pp create mode 100644 manifests/inspector.pp create mode 100644 spec/classes/inspector_db_sync_spec.rb create mode 100644 spec/classes/ironic_inspector_spec.rb create mode 100644 spec/unit/provider/ironic_inspector_config/ini_setting_spec.rb create mode 100644 spec/unit/type/ironic_inspector_config_spec.rb create mode 100644 templates/inspector_dnsmasq_http.erb create mode 100644 templates/inspector_dnsmasq_tftp.erb create mode 100644 templates/inspector_ipxe.erb create mode 100644 templates/inspector_pxelinux_cfg.erb diff --git a/lib/puppet/provider/ironic_inspector_config/ini_setting.rb b/lib/puppet/provider/ironic_inspector_config/ini_setting.rb new file mode 100644 index 00000000..fc448160 --- /dev/null +++ b/lib/puppet/provider/ironic_inspector_config/ini_setting.rb @@ -0,0 +1,10 @@ +Puppet::Type.type(:ironic_inspector_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:openstack_config).provider(:ini_setting) +) do + + def self.file_path + '/etc/ironic-inspector/inspector.conf' + end + +end diff --git a/lib/puppet/type/ironic_inspector_config.rb b/lib/puppet/type/ironic_inspector_config.rb new file mode 100644 index 00000000..fe7ff166 --- /dev/null +++ b/lib/puppet/type/ironic_inspector_config.rb @@ -0,0 +1,53 @@ +Puppet::Type.newtype(:ironic_inspector_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from inspector.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + newvalues(/^[\S ]*$/) + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + + newparam(:ensure_absent_val) do + desc 'A value that is specified as the value property will behave as if ensure => absent was specified' + defaultto('') + end + + autorequire(:package) do + 'ironic-inspector' + end + +end diff --git a/manifests/db/inspector_sync.pp b/manifests/db/inspector_sync.pp new file mode 100644 index 00000000..d09decf4 --- /dev/null +++ b/manifests/db/inspector_sync.pp @@ -0,0 +1,21 @@ +# +# Class to execute ironic-inspector dbsync +# +class ironic::db::inspector_sync { + + include ::ironic::params + + Package<| tag == 'ironic-inspector-package' |> ~> Exec['ironic-inspector-dbsync'] + Exec['ironic-inspector-dbsync'] ~> Service <| tag == 'ironic-inspector-service' |> + + Ironic_inspector_config<||> -> Exec['ironic-inspector-dbsync'] + Ironic_inspector_config<| title == 'database/connection' |> ~> Exec['ironic-inspector-dbsync'] + + exec { 'ironic-inspector-dbsync': + command => $::ironic::params::inspector_dbsync_command, + path => '/usr/bin', + user => 'ironic-inspector', + refreshonly => true, + logoutput => on_failure, + } +} diff --git a/manifests/inspector.pp b/manifests/inspector.pp new file mode 100644 index 00000000..773a79d6 --- /dev/null +++ b/manifests/inspector.pp @@ -0,0 +1,273 @@ +# +# Copyright (C) 2015 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# Configure the ironic-inspector auxiliary service to Ironic +# +# === Parameters +# +# [*package_ensure*] +# (optional) Control the ensure parameter for the package resource +# Defaults to 'present' +# +# [*enabled*] +# (optional) Define if the service must be enabled or not +# Defaults to true +# +# [*pxe_transfer_protocol*] +# (optional) Protocol to be used for transferring the ramdisk +# Defaults to 'tftp'. Valid values are 'tftp' or 'http'. +# +# [*debug*] +# (optional) Enable debug logging +# Defaults to false +# +# [*auth_uri*] +# (optional) Complete public Identity API endpoint +# Defaults to 'http://127.0.0.1:5000/v2.0' +# +# [*identity_uri*] +# (optional) Complete admin Identity API endpoint +# Defaults to 'http://127.0.0.1:35357' +# +# [*admin_user*] +# (optional) The name of the auth user +# Defaults to 'ironic' +# +# [*admin_password*] +# (optional) The password to use for authentication (keystone) +# Defaults to undef. Set a value unless you are using noauth +# +# [*admin_tenant_name*] +# (optional) The tenant of the auth user +# Defaults to 'services' +# +# [*dnsmasq_interface*] +# (optional) The interface for the ironic-inspector dnsmasq process +# to listen on +# Defaults to 'br-ctlplane' +# +# [*db_connection*] +# (optional) Location of the ironic-inspector node cache database +# Defaults to 'sqlite::////var/lib/ironic-inspector/inspector.sqlite' +# +# [*ramdisk_logs_dir*] +# (optional) Location to store logs retrieved from the ramdisk +# Defaults to '/var/log/ironic-inspector/ramdisk/' +# +# [*enable_setting_ipmi_credentials*] +# (optional) Enable setting of IPMI credentials +# Defaults to false +# +# [*keep_ports*] +# (optional) Which ports to keep after introspection +# Defaults to 'all' +# +# [*store_data*] +# (optional) Method for storing introspection data +# Defaults to 'none' +# +# [*ironic_username*] +# (optional) User name for accessing Ironic API +# Defaults to 'ironic' +# +# [*ironic_password*] +# (optional) Password for accessing Ironic API +# Defaults to undef. Set a value unless using noauth. +# +# [*ironic_tenant_name*] +# (optional) Tenant name for accessing Ironic API +# Defaults to 'services' +# +# [*ironic_auth_url*] +# (optional) Keystone authentication URL for Ironic +# Defautls to 'http://127.0.0.1:5000/v2.0' +# +# [*ironic_max_retries*] +# (optional) Maximum number of retries in case of conflict error +# Defaults to 30 +# +# [*ironic_retry_interval*] +# (optional) Interval between retries in case of conflict error +# Defaults to 2 +# +# [*swift_username*] +# (optional) User name for accessing Swift API +# Defaults to 'ironic' +# +# [*swift_password*] +# (optional) Password for accessing Swift API +# Defaults to undef. Set a value if using Swift. +# +# [*swift_tenant_name*] +# (optional) Tenant name for accessing Swift API +# Defaults to 'services' +# +# [*swift_auth_url*] +# (optional) Keystone authentication URL for Swift +# Defautls to 'http://127.0.0.1:5000/v2.0' +# +# [*dnsmasq_ip_range*] +# (optional) IP range to use for nodes being introspected +# Defaults to '192.168.0.100,192.168.0.120' +# +# [*dnsmasq_local_ip*] +# (optional) IP interface for the dnsmasq process +# Defaults to '192.168.0.1' +# +# [*sync_db*] +# Enable dbsync +# Defaults to true +# +class ironic::inspector ( + $package_ensure = 'present', + $enabled = true, + $pxe_transfer_protocol = 'tftp', + $debug = false, + $auth_uri = 'http://127.0.0.1:5000/v2.0', + $identity_uri = 'http://127.0.0.1:35357', + $admin_user = 'ironic', + $admin_password = undef, + $admin_tenant_name = 'services', + $dnsmasq_interface = 'br-ctlplane', + $db_connection = 'sqlite:////var/lib/ironic-inspector/inspector.sqlite', + $ramdisk_logs_dir = '/var/log/ironic-inspector/ramdisk/', + $enable_setting_ipmi_credentials = false, + $keep_ports = 'all', + $store_data = 'none', + $ironic_username = 'ironic', + $ironic_password = undef, + $ironic_tenant_name = 'services', + $ironic_auth_url = 'http://127.0.0.1:5000/v2.0', + $ironic_max_retries = 30, + $ironic_retry_interval = 2, + $swift_username = 'ironic', + $swift_password = undef, + $swift_tenant_name = 'services', + $swift_auth_url = 'http://127.0.0.1:5000/v2.0', + $dnsmasq_ip_range = '192.168.0.100,192.168.0.120', + $dnsmasq_local_ip = '192.168.0.1', + $sync_db = true, +) { + + include ::ironic::params + + Ironic_inspector_config<||> ~> Service['ironic-inspector'] + + file { '/etc/ironic-inspector/inspector.conf': + ensure => 'present', + require => Package['ironic-inspector'], + } + + if $pxe_transfer_protocol == 'tftp' { + file { '/etc/ironic-inspector/dnsmasq.conf': + ensure => 'present', + content => template('ironic/inspector_dnsmasq_tftp.erb'), + require => Package['ironic-inspector'], + } + file { '/tftpboot': + ensure => 'directory', + } + file { '/tftpboot/pxelinux.cfg': + ensure => 'directory', + } + file { '/tftpboot/pxelinux.cfg/default': + ensure => 'present', + content => template('ironic/inspector_pxelinux_cfg.erb'), + require => Package['ironic-inspector'], + } + } + + if $pxe_transfer_protocol == 'http' { + file { '/etc/ironic-inspector/dnsmasq.conf': + ensure => 'present', + content => template('ironic/inspector_dnsmasq_http.erb'), + require => Package['ironic-inspector'], + } + file { '/httpboot': + ensure => 'directory', + } + file { '/httpboot/inspector.ipxe': + ensure => 'present', + content => template('ironic/inspector_ipxe.erb'), + require => Package['ironic-inspector'], + } + } + + # Configure inspector.conf + ironic_inspector_config { + 'DEFAULT/debug': value => $debug; + 'keystone_authtoken/auth_uri': value => $auth_uri; + 'keystone_authtoken/identity_uri': value => $identity_uri; + 'keystone_authtoken/admin_user': value => $admin_user; + 'keystone_authtoken/admin_password': value => $admin_password, secret => true; + 'keystone_authtoken/admin_tenant_name': value => $admin_tenant_name; + 'firewall/dnsmasq_interface': value => $dnsmasq_interface; + 'database/connection': value => $db_connection; + 'processing/ramdisk_logs_dir': value => $ramdisk_logs_dir; + 'processing/enable_setting_ipmi_credentials': value => $enable_setting_ipmi_credentials; + 'processing/keep_ports': value => $keep_ports; + 'processing/store_data': value => $store_data; + 'ironic/os_username': value => $ironic_username; + 'ironic/os_password': value => $ironic_password, secret => true; + 'ironic/os_tenant_name': value => $ironic_tenant_name; + 'ironic/os_auth_url': value => $ironic_auth_url; + 'ironic/max_retries': value => $ironic_max_retries; + 'ironic/retry_interval': value => $ironic_retry_interval; + 'swift/username': value => $swift_username; + 'swift/password': value => $swift_password, secret => true; + 'swift/tenant_name': value => $swift_tenant_name; + 'swift/os_auth_url': value => $swift_auth_url; + } + + # Install package + if $::ironic::params::inspector_package { + Package['ironic-inspector'] -> Service['ironic-inspector'] + Package['ironic-inspector'] -> Service['ironic-inspector-dnsmasq'] + package { 'ironic-inspector': + ensure => $package_ensure, + name => $::ironic::params::inspector_package, + tag => ['openstack', 'ironic-inspector-package'], + } + } + + if $sync_db { + include ::ironic::db::inspector_sync + } + + if $enabled { + $ensure = 'running' + } else { + $ensure = 'stopped' + } + + # Manage services + service { 'ironic-inspector': + ensure => $ensure, + name => $::ironic::params::inspector_service, + enable => $enabled, + hasstatus => true, + tag => 'ironic-inspector-service', + } + + Service['ironic-inspector'] -> Service['ironic-inspector-dnsmasq'] + service { 'ironic-inspector-dnsmasq': + ensure => $ensure, + name => $::ironic::params::inspector_dnsmasq_service, + enable => $enabled, + hasstatus => true, + tag => 'ironic-inspector-dnsmasq-service', + } + +} diff --git a/manifests/params.pp b/manifests/params.pp index fba26f29..23ef8ebd 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -23,22 +23,34 @@ class ironic::params { $dbsync_command = 'ironic-dbsync --config-file /etc/ironic/ironic.conf' + $inspector_dbsync_command = + 'ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf upgrade' + case $::osfamily { 'RedHat': { - $common_package_name = 'openstack-ironic-common' - $api_package = 'openstack-ironic-api' - $api_service = 'openstack-ironic-api' - $conductor_package = 'openstack-ironic-conductor' - $conductor_service = 'openstack-ironic-conductor' - $client_package = 'python-ironicclient' + $common_package_name = 'openstack-ironic-common' + $api_package = 'openstack-ironic-api' + $api_service = 'openstack-ironic-api' + $conductor_package = 'openstack-ironic-conductor' + $conductor_service = 'openstack-ironic-conductor' + $client_package = 'python-ironicclient' + $inspector_package = 'openstack-ironic-inspector' + $inspector_service = 'openstack-ironic-inspector' + $inspector_dnsmasq_service = 'openstack-ironic-inspector-dnsmasq' } 'Debian': { - $common_package_name = 'ironic-common' - $api_service = 'ironic-api' - $api_package = 'ironic-api' - $conductor_service = 'ironic-conductor' - $conductor_package = 'ironic-conductor' - $client_package = 'python-ironicclient' + $common_package_name = 'ironic-common' + $api_service = 'ironic-api' + $api_package = 'ironic-api' + $conductor_service = 'ironic-conductor' + $conductor_package = 'ironic-conductor' + $client_package = 'python-ironicclient' + $inspector_package = 'ironic-inspector' + $inspector_service = 'ironic-inspector' + # it seems like there is not currently a builtin dnsmasq in the debian packaging + # https://packages.debian.org/source/experimental/ironic-inspector + # this should be changed to whatever debian will use for dnsmasq + $inspector_dnsmasq_service = 'ironic-inspector-dnsmasq' } default: { fail("Unsupported osfamily ${::osfamily}") diff --git a/spec/acceptance/basic_ironic_spec.rb b/spec/acceptance/basic_ironic_spec.rb index a0b26470..fef8faa3 100644 --- a/spec/acceptance/basic_ironic_spec.rb +++ b/spec/acceptance/basic_ironic_spec.rb @@ -96,32 +96,44 @@ describe 'basic ironic' do admin_url => "https://${::fqdn}:35357/", } + + # Ironic resources + class { '::ironic': + rabbit_userid => 'ironic', + rabbit_password => 'an_even_bigger_secret', + rabbit_host => '127.0.0.1', + database_connection => 'mysql://ironic:a_big_secret@127.0.0.1/ironic?charset=utf8', + debug => true, + verbose => true, + enabled_drivers => ['pxe_ssh'], + } + class { '::ironic::db::mysql': + password => 'a_big_secret', + } + class { '::ironic::keystone::auth': + password => 'a_big_secret', + } + class { '::ironic::client': } + class { '::ironic::conductor': } + class { '::ironic::api': + admin_password => 'a_big_secret', + } + class { '::ironic::drivers::ipmi': } + + # Ironic inspector resources case $::osfamily { 'Debian': { - # Ironic resources - class { '::ironic': - rabbit_userid => 'ironic', - rabbit_password => 'an_even_bigger_secret', - rabbit_host => '127.0.0.1', - database_connection => 'mysql://ironic:a_big_secret@127.0.0.1/ironic?charset=utf8', - debug => true, - verbose => true, - } - class { '::ironic::db::mysql': - password => 'a_big_secret', - } - class { '::ironic::keystone::auth': - password => 'a_big_secret', - } - class { '::ironic::client': } - class { '::ironic::conductor': } - class { '::ironic::api': - admin_password => 'a_big_secret', - } - class { '::ironic::drivers::ipmi': } + warning("Ironic inspector packaging is not ready on ${::osfamily}.") } 'RedHat': { - warning("Ironic packaging is not ready on ${::osfamily}.") + class { '::ironic::inspector': + auth_uri => "https://${::fqdn}:5000/v2.0", + identity_uri => "https://${::fqdn}:35357", + admin_password => 'a_big_secret', + ironic_password => 'a_big_secret', + ironic_auth_url => "https://${::fqdn}:5000/v2.0", + dnsmasq_interface => 'eth0', + } } } EOS @@ -129,10 +141,20 @@ describe 'basic ironic' do # Run it twice and test for idempotency apply_manifest(pp, :catch_failures => true) - apply_manifest(pp, :catch_changes => true) + apply_manifest(pp, :catch_changes => true) end - if os[:family] == 'Debian' + if os[:family].casecmp('RedHat') == 0 + # Ironic API port + describe port(6385) do + it { is_expected.to be_listening.with('tcp') } + end + # Inspector API port + describe port(5050) do + it { is_expected.to be_listening.with('tcp') } + end + else # Inspector is not packaged, so only test Ironic + # Ironic API port describe port(6385) do it { is_expected.to be_listening.with('tcp') } end diff --git a/spec/classes/inspector_db_sync_spec.rb b/spec/classes/inspector_db_sync_spec.rb new file mode 100644 index 00000000..cf71ccab --- /dev/null +++ b/spec/classes/inspector_db_sync_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe 'ironic::db::inspector_sync' do + + shared_examples_for 'inspector-dbsync' do + + it 'runs ironic-inspectror-db_sync' do + is_expected.to contain_exec('ironic-inspector-dbsync').with( + :command => 'ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf upgrade', + :path => '/usr/bin', + :user => 'ironic-inspector', + :refreshonly => 'true', + :logoutput => 'on_failure' + ) + end + + end + + context 'on a RedHat osfamily' do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '7.0', + :concat_basedir => '/var/lib/puppet/concat' + } + end + + it_configures 'inspector-dbsync' + end + + context 'on a Debian osfamily' do + let :facts do + { + :operatingsystemrelease => '7.8', + :operatingsystem => 'Debian', + :osfamily => 'Debian', + :concat_basedir => '/var/lib/puppet/concat' + } + end + + it_configures 'inspector-dbsync' + end + +end diff --git a/spec/classes/ironic_inspector_spec.rb b/spec/classes/ironic_inspector_spec.rb new file mode 100644 index 00000000..ea8cb4cb --- /dev/null +++ b/spec/classes/ironic_inspector_spec.rb @@ -0,0 +1,190 @@ +# +# Copyright (C) 2015 Red Hat, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for ironic::inspector class +# + +require 'spec_helper' + +describe 'ironic::inspector' do + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :pxe_transfer_protocol => 'tftp', + :debug => false, + :auth_uri => 'http://127.0.0.1:5000/v2.0', + :identity_uri => 'http://127.0.0.1:35357', + :admin_user => 'ironic', + :admin_tenant_name => 'services', + :dnsmasq_interface => 'br-ctlplane', + :db_connection => 'sqlite:////var/lib/ironic-inspector/inspector.sqlite', + :ramdisk_logs_dir => '/var/log/ironic-inspector/ramdisk/', + :enable_setting_ipmi_credentials => false, + :keep_ports => 'all', + :store_data => 'none', + :ironic_username => 'ironic', + :ironic_tenant_name => 'services', + :ironic_auth_url => 'http://127.0.0.1:5000/v2.0', + :ironic_max_retries => 30, + :ironic_retry_interval => 2, + :swift_username => 'ironic', + :swift_tenant_name => 'services', + :swift_auth_url => 'http://127.0.0.1:5000/v2.0', + :dnsmasq_ip_range => '192.168.0.100,192.168.0.120', + :dnsmasq_local_ip => '192.168.0.1', } + end + + let :params do + {} + end + + shared_examples_for 'ironic inspector' do + let :p do + default_params.merge(params) + end + + it { is_expected.to contain_class('ironic::params') } + + it 'installs ironic inspector package' do + if platform_params.has_key?(:inspector_package) + is_expected.to contain_package('ironic-inspector').with( + :name => platform_params[:inspector_package], + :ensure => p[:package_ensure], + :tag => ['openstack', 'ironic-inspector-package'], + ) + is_expected.to contain_package('ironic-inspector').with_before(/Service\[ironic-inspector\]/) + end + end + + it 'ensure ironic inspector service is running' do + is_expected.to contain_service('ironic-inspector').with( + 'hasstatus' => true, + 'tag' => 'ironic-inspector-service', + ) + end + + it 'ensure ironic inspector dnsmasq service is running' do + is_expected.to contain_service('ironic-inspector-dnsmasq').with( + 'hasstatus' => true, + 'tag' => 'ironic-inspector-dnsmasq-service', + ) + end + + it 'configures inspector.conf' do + is_expected.to contain_ironic_inspector_config('DEFAULT/debug').with_value(p[:debug]) + is_expected.to contain_ironic_inspector_config('keystone_authtoken/auth_uri').with_value(p[:auth_uri]) + is_expected.to contain_ironic_inspector_config('keystone_authtoken/identity_uri').with_value(p[:identity_uri]) + is_expected.to contain_ironic_inspector_config('keystone_authtoken/admin_user').with_value(p[:admin_user]) + is_expected.to contain_ironic_inspector_config('keystone_authtoken/admin_tenant_name').with_value(p[:admin_tenant_name]) + is_expected.to contain_ironic_inspector_config('firewall/dnsmasq_interface').with_value(p[:dnsmasq_interface]) + is_expected.to contain_ironic_inspector_config('database/connection').with_value(p[:db_connection]) + is_expected.to contain_ironic_inspector_config('processing/ramdisk_logs_dir').with_value(p[:ramdisk_logs_dir]) + is_expected.to contain_ironic_inspector_config('processing/enable_setting_ipmi_credentials').with_value(p[:enable_setting_ipmi_credentials]) + is_expected.to contain_ironic_inspector_config('processing/keep_ports').with_value(p[:keep_ports]) + is_expected.to contain_ironic_inspector_config('processing/store_data').with_value(p[:store_data]) + is_expected.to contain_ironic_inspector_config('ironic/os_username').with_value(p[:ironic_username]) + is_expected.to contain_ironic_inspector_config('ironic/os_tenant_name').with_value(p[:ironic_tenant_name]) + is_expected.to contain_ironic_inspector_config('ironic/os_auth_url').with_value(p[:ironic_auth_url]) + is_expected.to contain_ironic_inspector_config('ironic/max_retries').with_value(p[:ironic_max_retries]) + is_expected.to contain_ironic_inspector_config('ironic/retry_interval').with_value(p[:ironic_retry_interval]) + is_expected.to contain_ironic_inspector_config('swift/username').with_value(p[:swift_username]) + is_expected.to contain_ironic_inspector_config('swift/tenant_name').with_value(p[:swift_tenant_name]) + is_expected.to contain_ironic_inspector_config('swift/os_auth_url').with_value(p[:swift_auth_url]) + end + + it 'should contain file /etc/ironic-inspector/dnsmasq.conf' do + is_expected.to contain_file('/etc/ironic-inspector/dnsmasq.conf').with( + 'ensure' => 'present', + 'require' => 'Package[ironic-inspector]', + 'content' => /pxelinux/, + ) + end + it 'should contain file /tftpboot/pxelinux.cfg/default' do + is_expected.to contain_file('/tftpboot/pxelinux.cfg/default').with( + 'ensure' => 'present', + 'require' => 'Package[ironic-inspector]', + 'content' => /default/, + ) + end + + context 'when overriding parameters' do + before :each do + params.merge!( + :debug => true, + :auth_uri => 'http://192.168.0.1:5000/v2.0', + :identity_uri => 'http://192.168.0.1:35357', + :admin_password => 'password', + :ironic_password => 'password', + :ironic_auth_url => 'http://192.168.0.1:5000/v2.0', + :swift_password => 'password', + :swift_auth_url => 'http://192.168.0.1:5000/v2.0', + :pxe_transfer_protocol => 'http', + ) + end + it 'should replace default parameter with new value' do + is_expected.to contain_ironic_inspector_config('DEFAULT/debug').with_value(p[:debug]) + is_expected.to contain_ironic_inspector_config('keystone_authtoken/auth_uri').with_value(p[:auth_uri]) + is_expected.to contain_ironic_inspector_config('keystone_authtoken/identity_uri').with_value(p[:identity_uri]) + is_expected.to contain_ironic_inspector_config('keystone_authtoken/admin_password').with_value(p[:admin_password]) + is_expected.to contain_ironic_inspector_config('ironic/os_password').with_value(p[:ironic_password]) + is_expected.to contain_ironic_inspector_config('ironic/os_auth_url').with_value(p[:ironic_auth_url]) + is_expected.to contain_ironic_inspector_config('swift/password').with_value(p[:swift_password]) + is_expected.to contain_ironic_inspector_config('swift/os_auth_url').with_value(p[:swift_auth_url]) + end + + it 'should contain file /etc/ironic-inspector/dnsmasq.conf' do + is_expected.to contain_file('/etc/ironic-inspector/dnsmasq.conf').with( + 'ensure' => 'present', + 'require' => 'Package[ironic-inspector]', + 'content' => /ipxe/, + ) + end + it 'should contain file /httpboot/inspector.ipxe' do + is_expected.to contain_file('/httpboot/inspector.ipxe').with( + 'ensure' => 'present', + 'require' => 'Package[ironic-inspector]', + 'content' => /ipxe/, + ) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :inspector_package => 'ironic-inspector', + :inspector_service => 'ironic-inspector' } + end + + it_configures 'ironic inspector' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :inspector_service => 'ironic-inspector' } + end + + it_configures 'ironic inspector' + end + +end diff --git a/spec/unit/provider/ironic_inspector_config/ini_setting_spec.rb b/spec/unit/provider/ironic_inspector_config/ini_setting_spec.rb new file mode 100644 index 00000000..edf78060 --- /dev/null +++ b/spec/unit/provider/ironic_inspector_config/ini_setting_spec.rb @@ -0,0 +1,71 @@ +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + '..', + 'fixtures', + 'modules', + 'inifile', + 'lib') +) +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + '..', + 'fixtures', + 'modules', + 'openstacklib', + 'lib') +) + +require 'spec_helper' + +provider_class = Puppet::Type.type(:ironic_inspector_config).provider(:ini_setting) + +describe provider_class do + + it 'should default to the default setting when no other one is specified' do + resource = Puppet::Type::Ironic_inspector_config.new( + { + :name => 'DEFAULT/foo', + :value => 'bar' + } + ) + provider = provider_class.new(resource) + expect(provider.section).to eq('DEFAULT') + expect(provider.setting).to eq('foo') + end + + it 'should allow setting to be set explicitly' do + resource = Puppet::Type::Ironic_inspector_config.new( + { + :name => 'dude/foo', + :value => 'bar' + } + ) + provider = provider_class.new(resource) + expect(provider.section).to eq('dude') + expect(provider.setting).to eq('foo') + end + + it 'should ensure absent when is specified as a value' do + resource = Puppet::Type::Ironic_inspector_config.new( + {:name => 'dude/foo', :value => ''} + ) + provider = provider_class.new(resource) + provider.exists? + expect(resource[:ensure]).to eq :absent + end + + it 'should ensure absent when value matches ensure_absent_val' do + resource = Puppet::Type::Ironic_inspector_config.new( + {:name => 'dude/foo', :value => 'foo', :ensure_absent_val => 'foo' } + ) + provider = provider_class.new(resource) + provider.exists? + expect(resource[:ensure]).to eq :absent + end +end diff --git a/spec/unit/type/ironic_inspector_config_spec.rb b/spec/unit/type/ironic_inspector_config_spec.rb new file mode 100644 index 00000000..5d37e35f --- /dev/null +++ b/spec/unit/type/ironic_inspector_config_spec.rb @@ -0,0 +1,19 @@ +require 'puppet' +require 'puppet/type/ironic_inspector_config' + +describe 'Puppet::Type.type(:ironic_inspector_config)' do + before :each do + @ironic_inspector_config = Puppet::Type.type(:ironic_inspector_config).new(:name => 'DEFAULT/foo', :value => 'bar') + end + + it 'should autorequire the package that install the file' do + catalog = Puppet::Resource::Catalog.new + package = Puppet::Type.type(:package).new(:name => 'ironic-inspector') + catalog.add_resource package, @ironic_inspector_config + dependency = @ironic_inspector_config.autorequire + expect(dependency.size).to eq(1) + expect(dependency[0].target).to eq(@ironic_inspector_config) + expect(dependency[0].source).to eq(package) + end + +end diff --git a/templates/inspector_dnsmasq_http.erb b/templates/inspector_dnsmasq_http.erb new file mode 100644 index 00000000..6592475b --- /dev/null +++ b/templates/inspector_dnsmasq_http.erb @@ -0,0 +1,9 @@ +port=0 +interface=<%= @dnsmasq_interface %> +bind-interfaces +dhcp-range=<%= @dnsmasq_ip_range %>,29 +enable-tftp +tftp-root=/tftpboot +dhcp-match=ipxe,175 +dhcp-boot=tag:!ipxe,undionly.kpxe,localhost.localdomain,<%= @dnsmasq_local_ip %> +dhcp-boot=tag:ipxe,http://<%= @dnsmasq_local_ip %>:8088/inspector.ipxe diff --git a/templates/inspector_dnsmasq_tftp.erb b/templates/inspector_dnsmasq_tftp.erb new file mode 100644 index 00000000..890f273c --- /dev/null +++ b/templates/inspector_dnsmasq_tftp.erb @@ -0,0 +1,7 @@ +port=0 +interface=<%= @dnsmasq_interface %> +bind-interfaces +dhcp-range=<%= @dnsmasq_ip_range %>,29 +enable-tftp +tftp-root=/tftpboot +dhcp-boot=pxelinux.0,localhost.localdomain,<%= @dnsmasq_local_ip %> diff --git a/templates/inspector_ipxe.erb b/templates/inspector_ipxe.erb new file mode 100644 index 00000000..7362ca0b --- /dev/null +++ b/templates/inspector_ipxe.erb @@ -0,0 +1,7 @@ +#!ipxe + +dhcp + +kernel http://<%= @dnsmasq_local_ip %>:8088/agent.kernel ipa-inspection-callback-url=http://<%= @dnsmasq_local_ip %>:5050/v1/continue systemd.journald.forward_to_console=yes +initrd http://<%= @dnsmasq_local_ip %>:8088/agent.ramdisk +boot diff --git a/templates/inspector_pxelinux_cfg.erb b/templates/inspector_pxelinux_cfg.erb new file mode 100644 index 00000000..f25c4c7c --- /dev/null +++ b/templates/inspector_pxelinux_cfg.erb @@ -0,0 +1,6 @@ +default inspector + +label inspector +kernel agent.kernel +append initrd=agent.ramdisk ipa-inspection-callback-url=http://<%= @dnsmasq_local_ip %>:5050/v1/continue systemd.journald.forward_to_console=yes +ipappend 3