diff --git a/manifests/params.pp b/manifests/params.pp index 6e206aa5..90b02515 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -41,6 +41,8 @@ class ironic::params { $api_service = 'openstack-ironic-api' $conductor_package = 'openstack-ironic-conductor' $conductor_service = 'openstack-ironic-conductor' + $dnsmasq_tftp_package = 'openstack-ironic-dnsmasq-tftp-server' + $dnsmasq_tftp_service = 'openstack-ironic-dnsmasq-tftp-server' $inspector_package = 'openstack-ironic-inspector' $inspector_dnsmasq_package = 'openstack-ironic-inspector-dnsmasq' $inspector_service = 'openstack-ironic-inspector' @@ -50,7 +52,13 @@ class ironic::params { $ipxe_rom_dir = '/usr/share/ipxe' $ironic_wsgi_script_path = '/var/www/cgi-bin/ironic' $ironic_wsgi_script_source = '/usr/bin/ironic-api-wsgi' - $tftpd_package = 'tftp-server' + if (Integer.new($::os['release']['major']) > 8) { + $xinetd_available = false + $tftpd_package = false + } else { + $xinetd_available = true + $tftpd_package = 'tftp-server' + } $ipxe_package = 'ipxe-bootimgs' $syslinux_package = 'syslinux-tftpboot' $syslinux_path = '/tftpboot' @@ -62,6 +70,8 @@ class ironic::params { $api_package = 'ironic-api' $conductor_service = 'ironic-conductor' $conductor_package = 'ironic-conductor' + $dnsmasq_tftp_package = false + $dnsmasq_tftp_service = false $inspector_package = 'ironic-inspector' $inspector_dnsmasq_package = false $inspector_service = 'ironic-inspector' @@ -75,6 +85,7 @@ class ironic::params { $ipxe_rom_dir = '/usr/lib/ipxe' $ironic_wsgi_script_path = '/usr/lib/cgi-bin/ironic' $ironic_wsgi_script_source = '/usr/bin/ironic-api-wsgi' + $xinetd_available = true $tftpd_package = 'tftpd' $ipxe_package = 'ipxe' $syslinux_package = 'syslinux-common' diff --git a/manifests/pxe.pp b/manifests/pxe.pp index e57b2b0a..9509af39 100644 --- a/manifests/pxe.pp +++ b/manifests/pxe.pp @@ -44,7 +44,7 @@ # Defaults to '$::ironic::params::syslinux_files' # # [*tftp_bind_host*] -# (optional) The IP address xinetd will listen on for TFTP. +# (optional) The IP address TFTP server will listen on for TFTP. # Defaults to undef (listen on all ip addresses). # # [*enable_ppc64le*] @@ -63,6 +63,11 @@ # driver. # Defaults to 'snponly.efi' # +# [*tftp_use_xinetd*] +# (optional) Override wheter to use xinetd instead of dnsmasq as the tftp +# service facilitator. +# Defaults to ironic::params::xinetd_available +# class ironic::pxe ( $package_ensure = 'present', $tftp_root = '/tftpboot', @@ -73,7 +78,8 @@ class ironic::pxe ( $tftp_bind_host = undef, $enable_ppc64le = false, $ipxe_name_base = 'ipxe-snponly', - $uefi_ipxe_bootfile_name = 'snponly.efi' + $uefi_ipxe_bootfile_name = 'snponly.efi', + $tftp_use_xinetd = $::ironic::params::xinetd_available ) inherits ironic::params { include ironic::deps @@ -99,9 +105,10 @@ class ironic::pxe ( } ensure_resource( 'package', 'ironic-common', { - ensure => $package_ensure, - name => $::ironic::params::common_package_name, - tag => ['openstack', 'ironic-package'],}) + ensure => $package_ensure, + name => $::ironic::params::common_package_name, + tag => ['openstack', 'ironic-package'], + }) file { "${tftp_root_real}/pxelinux.cfg": ensure => 'directory', @@ -132,32 +139,74 @@ class ironic::pxe ( before => Anchor['ironic::config::end'], } - ensure_resource( 'package', 'tftp-server', { - 'ensure' => $package_ensure, - 'name' => $::ironic::params::tftpd_package, - 'tag' => ['openstack', 'ironic-ipxe', 'ironic-support-package'], - }) + if $tftp_use_xinetd { + if ! $::ironic::params::xinetd_available { + fail('xinetd is not available in this distro. Please use tftp_use_xinetd=false') + } - $options = "--map-file ${tftp_root_real}/map-file" - include xinetd + ensure_resource( 'package', 'tftp-server', { + 'ensure' => $package_ensure, + 'name' => $::ironic::params::tftpd_package, + 'tag' => ['openstack', 'ironic-ipxe', 'ironic-support-package'], + }) - xinetd::service { 'tftp': - port => '69', - bind => $tftp_bind_host, - protocol => 'udp', - server_args => "${options} ${tftp_root_real}", - server => '/usr/sbin/in.tftpd', - socket_type => 'dgram', - cps => '100 2', - per_source => '11', - wait => 'yes', - subscribe => Anchor['ironic::install::end'], - } + $options = "--map-file ${tftp_root_real}/map-file" - file { "${tftp_root_real}/map-file": - ensure => 'present', - content => "r ^([^/]) ${tftp_root_real}/\\1", - tag => 'ironic-tftp-file', + include xinetd + + xinetd::service { 'tftp': + port => '69', + bind => $tftp_bind_host, + protocol => 'udp', + server_args => "${options} ${tftp_root_real}", + server => '/usr/sbin/in.tftpd', + socket_type => 'dgram', + cps => '100 2', + per_source => '11', + wait => 'yes', + subscribe => Anchor['ironic::install::end'], + } + + file { "${tftp_root_real}/map-file": + ensure => 'present', + content => "r ^([^/]) ${tftp_root_real}/\\1", + } + } else { + if ! $::ironic::params::dnsmasq_tftp_package { + fail('ironic-dnsmasq-tftp-server is not available in this distro. Please use tftp_use_xnetd=true') + } + + # NOTE(tkajinam): We can't use puppet-xinetd for cleanup because the xinetd + # class forcefully installs the xinetd package. + warning('Any prior xinetd based tftp server should be disabled and removed from the system.') + + file { "${tftp_root_real}/map-file": + ensure => 'absent', + } + + package { 'dnsmasq-tftp-server': + ensure => $package_ensure, + name => $::ironic::params::dnsmasq_tftp_package, + tag => ['openstack', 'ironic-ipxe', 'ironic-support-package'], + } + + file { '/etc/ironic/dnsmasq-tftp-server.conf': + ensure => 'present', + mode => '0644', + owner => 'root', + group => 'root', + content => template('ironic/dnsmasq_tftp_server.erb'), + } + + service { 'dnsmasq-tftp-server': + ensure => 'running', + name => $::ironic::params::dnsmasq_tftp_service, + enable => true, + hasstatus => true, + subscribe => File['/etc/ironic/dnsmasq-tftp-server.conf'], + } + + Package['dnsmasq-tftp-server'] ~> Service['dnsmasq-tftp-server'] } if $syslinux_path { diff --git a/releasenotes/notes/tftp_use_xinetd-710c4eb59d3b0501.yaml b/releasenotes/notes/tftp_use_xinetd-710c4eb59d3b0501.yaml new file mode 100644 index 00000000..e0c2c599 --- /dev/null +++ b/releasenotes/notes/tftp_use_xinetd-710c4eb59d3b0501.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + The new ``ironic::pxe::tftp_use_xinetd`` parameter has been added. When + this parameter is set to ``false``, the ironic-dnsmasq-tftp-server service, + which actually manages a dnsmasq process, is used instead of xinetd, to + implement TFTP server. Note that the dnsmasq service is currently available + only in RDO. diff --git a/spec/classes/ironic_pxe_spec.rb b/spec/classes/ironic_pxe_spec.rb index 8edc1a6c..35987738 100644 --- a/spec/classes/ironic_pxe_spec.rb +++ b/spec/classes/ironic_pxe_spec.rb @@ -120,12 +120,28 @@ describe 'ironic::pxe' do 'backup' => false, ) end + + it 'should setup tftp xinetd service' do + is_expected.to contain_class('xinetd') + is_expected.to contain_xinetd__service('tftp').with( + 'port' => '69', + 'protocol' => 'udp', + 'server_args' => '--map-file /var/lib/tftpboot/map-file /var/lib/tftpboot', + 'server' => '/usr/sbin/in.tftpd', + 'socket_type' => 'dgram', + 'cps' => '100 2', + 'per_source' => '11', + 'wait' => 'yes', + 'subscribe' => 'Anchor[ironic::install::end]', + ) + end it 'should setup tftp xinetd service' do is_expected.to contain_xinetd__service('tftp').with( 'bind' => '1.2.3.4', ) end end + context 'when excluding syslinux' do before :each do params.merge!( @@ -158,6 +174,47 @@ describe 'ironic::pxe' do end end + shared_examples_for 'ironic pxe in RedHat' do + let :p do + default_params.merge(params) + end + + context 'when xinetd is disabled' do + before :each do + params.merge!( + :tftp_use_xinetd => false, + ) + end + + it 'should configure dnsmasq-tftp-server' do + is_expected.to contain_file('/etc/ironic/dnsmasq-tftp-server.conf').with( + 'ensure' => 'present', + 'mode' => '0644', + 'owner' => 'root', + 'group' => 'root', + ) + is_expected.to contain_package('dnsmasq-tftp-server').with( + 'ensure' => 'present', + 'name' => platform_params[:dnsmasq_tftp_package], + 'tag' => ['openstack', 'ironic-ipxe', 'ironic-support-package'], + ) + is_expected.to contain_service('dnsmasq-tftp-server').with( + 'ensure' => 'running', + 'name' => platform_params[:dnsmasq_tftp_service], + 'enable' => true, + 'hasstatus' => true, + ) + end + + it 'should not enable xinetd' do + is_expected.to_not contain_package('tftp-server') + is_expected.to_not contain_class('xinetd') + is_expected.to_not contain_xinetd__service('tftp') + is_expected.to contain_file('/tftpboot/map-file').with_ensure('absent') + end + end + end + on_supported_os({ :supported_os => OSDefaults.get_supported_os }).each do |os,facts| @@ -166,8 +223,23 @@ describe 'ironic::pxe' do facts.merge!(OSDefaults.get_facts()) end + let(:platform_params) do + case facts[:osfamily] + when 'Debian' + {} + when 'RedHat' + { :dnsmasq_tftp_package => 'openstack-ironic-dnsmasq-tftp-server', + :dnsmasq_tftp_service => 'openstack-ironic-dnsmasq-tftp-server' } + end + end + + # TODO(tkajinam): This should be refactored before we add support for + # CentOS9, because xinetd is not available in CentOS9 it_behaves_like 'ironic pxe' + if facts[:osfamily] == 'RedHat' + it_behaves_like 'ironic pxe in RedHat' + end end end diff --git a/templates/dnsmasq_tftp_server.erb b/templates/dnsmasq_tftp_server.erb new file mode 100644 index 00000000..1cead8e5 --- /dev/null +++ b/templates/dnsmasq_tftp_server.erb @@ -0,0 +1,8 @@ +# Configuration for a dnsmasq based TFTP service +port=0 +bind-interfaces +enable-tftp +tftp-root=<%= @tftp_root_real %> +<% if @tftp_bind_host -%> +listen-address=<%= @tftp_bind_host %> +<% end -%>