From f2dd0d3cc50fb1fdfc0dd9df8bb16c0d6429e5be Mon Sep 17 00:00:00 2001 From: Julia Kreger Date: Wed, 23 Jun 2021 07:56:24 -0700 Subject: [PATCH] Support use of dnsmasq as tftp service Switches to using the new ironic-dnsmasq-tftp-server service[1], which manages the dnsmasq process in order to facilitate standalone usage and testing of puppet-ironic outside with Centos-Stream 9 where package changes are anticipated. On Centos-Stream 9, users should effectively be forced over to using dnsmasq automatically. The higher level controls for defaults can also be changed for the purpose of backporting such that prior releases are not automatically switch to using dnsmasq unless they have to be run with dnsmasq based upon known package availability. Note that just setting tftp_use_xinetd=false in an existing deployment doesn't remove the xinetd service completely, because of limitation caused by current implementation of puppet-xinetd, and users are responsible to remove service, package and etc properly before switching to the new service. [1] https://review.rdoproject.org/r/c/openstack/ironic-distgit/+/34691 Change-Id: I5d388acfb96fa3e3a555a119ff72feabdd1cdf87 --- manifests/params.pp | 13 ++- manifests/pxe.pp | 105 +++++++++++++----- .../tftp_use_xinetd-710c4eb59d3b0501.yaml | 8 ++ spec/classes/ironic_pxe_spec.rb | 72 ++++++++++++ templates/dnsmasq_tftp_server.erb | 8 ++ 5 files changed, 177 insertions(+), 29 deletions(-) create mode 100644 releasenotes/notes/tftp_use_xinetd-710c4eb59d3b0501.yaml create mode 100644 templates/dnsmasq_tftp_server.erb 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 -%>