diff --git a/lib/puppet/functions/ipv6_netmask_to_prefix.rb b/lib/puppet/functions/ipv6_netmask_to_prefix.rb deleted file mode 100644 index f0a93656..00000000 --- a/lib/puppet/functions/ipv6_netmask_to_prefix.rb +++ /dev/null @@ -1,25 +0,0 @@ -Puppet::Functions.create_function(:ipv6_netmask_to_prefix) do - def ipv6_netmask_to_prefix(args) - require 'ipaddr' - result = [] - args.each do |ip_subnet| - begin - if IPAddr.new(ip_subnet["netmask"]).ipv6? - # TODO(hjensas) Once we have ruby stdlib >= 2.5.x we can use - # IPAddr.new().prefix instead of counting 1's. - prefix = IPAddr.new(ip_subnet["netmask"]).to_i.to_s(2).count("1") - Puppet.debug("Netmask #{ip_subnet["netmask"]} changed to prefix #{prefix}") - ip_subnet_dup = ip_subnet.dup - ip_subnet_dup["netmask"] = prefix - result << ip_subnet_dup - else - result << ip_subnet - end - rescue IPAddr::AddressFamilyError, IPAddr::Error, IPAddr::InvalidAddressError, IPAddr::InvalidPrefixError => e - # Ignore it - result << ip_subnet - end - end - return result - end -end diff --git a/lib/puppet/functions/ipv6_normalize_dnsmasq_ip_subnets.rb b/lib/puppet/functions/ipv6_normalize_dnsmasq_ip_subnets.rb new file mode 100644 index 00000000..c3261757 --- /dev/null +++ b/lib/puppet/functions/ipv6_normalize_dnsmasq_ip_subnets.rb @@ -0,0 +1,37 @@ +Puppet::Functions.create_function(:ipv6_normalize_dnsmasq_ip_subnets) do + def ipv6_normalize_dnsmasq_ip_subnets(args) + require 'ipaddr' + result = [] + args.each do |ip_subnet| + ip_subnet_dup = ip_subnet.dup + begin + if ip_subnet["netmask"] + if IPAddr.new(ip_subnet["netmask"]).ipv6? + # TODO(hjensas) Once we have ruby stdlib >= 2.5.x we can use + # IPAddr.new().prefix instead of counting 1's. + prefix = IPAddr.new(ip_subnet["netmask"]).to_i.to_s(2).count("1") + Puppet.debug("Netmask #{ip_subnet["netmask"]} changed to prefix #{prefix}") + ip_subnet_dup["netmask"] = prefix + end + end + rescue IPAddr::AddressFamilyError, IPAddr::Error, IPAddr::InvalidAddressError, IPAddr::InvalidPrefixError => e + # Ignore it + end + begin + if ip_subnet["gateway"] + if IPAddr.new(ip_subnet["gateway"]).ipv6? + # draft-ietf-mif-dhcpv6-route-option-05 was never completed. + # https://datatracker.ietf.org/doc/draft-ietf-mif-dhcpv6-route-option/ + # Remove the gateway key:value so that the option:router entry is + # not created in dnsmasq.conf. + ip_subnet_dup.delete("gateway") + end + end + rescue IPAddr::AddressFamilyError, IPAddr::Error, IPAddr::InvalidAddressError, IPAddr::InvalidPrefixError => e + # Ignore it + end + result << ip_subnet_dup + end + return result + end +end diff --git a/manifests/inspector.pp b/manifests/inspector.pp index 4dc347c4..ea25d191 100644 --- a/manifests/inspector.pp +++ b/manifests/inspector.pp @@ -311,7 +311,8 @@ class ironic::inspector ( require => Anchor['ironic-inspector::config::begin'], } - $dnsmasq_ip_subnets_real = ipv6_netmask_to_prefix($dnsmasq_ip_subnets) + $dnsmasq_local_ip_real = normalize_ip_for_uri($dnsmasq_local_ip) + $dnsmasq_ip_subnets_real = ipv6_normalize_dnsmasq_ip_subnets($dnsmasq_ip_subnets) if $pxe_transfer_protocol == 'tftp' { file { '/etc/ironic-inspector/dnsmasq.conf': diff --git a/releasenotes/notes/fix-dnsmasq-conf-ipv6-33d320210be7b1ac.yaml b/releasenotes/notes/fix-dnsmasq-conf-ipv6-33d320210be7b1ac.yaml new file mode 100644 index 00000000..41453249 --- /dev/null +++ b/releasenotes/notes/fix-dnsmasq-conf-ipv6-33d320210be7b1ac.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + The dnsmasq configuration written for ironic-inspector did not work with + IPv6 addressing. Router addresses should be provided by router + advertisements, DHCPv6 does not support a router option. + `1844573 `_. + diff --git a/spec/classes/ironic_inspector_spec.rb b/spec/classes/ironic_inspector_spec.rb index bb5d824d..618e0385 100644 --- a/spec/classes/ironic_inspector_spec.rb +++ b/spec/classes/ironic_inspector_spec.rb @@ -179,7 +179,7 @@ describe 'ironic::inspector' do is_expected.to contain_file('/etc/ironic-inspector/dnsmasq.conf').with_content( /dhcp-range=set:subnet3,2001:4888:a03:313a:c0:fe0:0:c200,2001:4888:a03:313a:c0:fe0:0:c2ff,64,10m/ ) - is_expected.to contain_file('/etc/ironic-inspector/dnsmasq.conf').with_content( + is_expected.not_to contain_file('/etc/ironic-inspector/dnsmasq.conf').with_content( /dhcp-option=tag:subnet3,option:router,2001:4888:a03:313a:c0:fe0:0:c000/ ) end @@ -260,6 +260,12 @@ describe 'ironic::inspector' do is_expected.to contain_file('/etc/ironic-inspector/dnsmasq.conf').with_content( /log-queries/ ) + is_expected.to contain_file('/etc/ironic-inspector/dnsmasq.conf').with_content( + /dhcp-userclass=set:ipxe6,iPXE/ + ) + is_expected.to contain_file('/etc/ironic-inspector/dnsmasq.conf').with_content( + /dhcp-option=tag:ipxe6,option6:bootfile-url,http:\/\/.*:3816\/inspector.ipxe/ + ) end it 'should contain file /var/www/httpboot/inspector.ipxe' do is_expected.to contain_file('/var/www/httpboot/inspector.ipxe').with( diff --git a/spec/functions/ipv6_netmask_to_prefix_spec.rb b/spec/functions/ipv6_normalize_dnsmasq_ip_subnets_spec.rb similarity index 60% rename from spec/functions/ipv6_netmask_to_prefix_spec.rb rename to spec/functions/ipv6_normalize_dnsmasq_ip_subnets_spec.rb index cf85794f..528dd2cd 100644 --- a/spec/functions/ipv6_netmask_to_prefix_spec.rb +++ b/spec/functions/ipv6_normalize_dnsmasq_ip_subnets_spec.rb @@ -1,9 +1,12 @@ require 'spec_helper' -describe 'ipv6_netmask_to_prefix' do +describe 'ipv6_normalize_dnsmasq_ip_subnets' do it { should run.with_params([{'ip_range' => '192.168.0.100,192.168.0.120'}]).and_return([{'ip_range' => '192.168.0.100,192.168.0.120'}])} it { should run.with_params([{'netmask' => '255.255.255.0',}]).and_return([{'netmask' => '255.255.255.0'}])} it { should run.with_params([{'netmask' => 'ffff:ffff:ffff:ffff::'}]).and_return([{'netmask' => 64}])} it { should run.with_params([{'netmask' => '64'}]).and_return([{'netmask' => '64'}])} it { should run.with_params([{'netmask' => 64}]).and_return([{'netmask' => 64}])} + it { should run.with_params([{'gateway' => '192.168.0.1'}]).and_return([{'gateway' => '192.168.0.1'}])} + it { should run.with_params([{'gateway' => 'fd00::1'}]).and_return([{}])} + it { should run.with_params([{'netmask' => 'ffff:ffff:ffff:ffff::', 'gateway' => 'fd00::1'}]).and_return([{'netmask' => 64}])} end diff --git a/templates/inspector_dnsmasq_http.erb b/templates/inspector_dnsmasq_http.erb index de4ae311..8d1a12e7 100644 --- a/templates/inspector_dnsmasq_http.erb +++ b/templates/inspector_dnsmasq_http.erb @@ -43,8 +43,10 @@ dhcp-match=ipxe,175 dhcp-match=set:efi,option:client-arch,7 dhcp-match=set:efi,option:client-arch,9 dhcp-match=set:efi,option:client-arch,11 +dhcp-userclass=set:ipxe6,iPXE # Client is already running iPXE; move to next stage of chainloading -dhcp-boot=tag:ipxe,http://<%= @dnsmasq_local_ip %>:<%= @http_port_real %>/inspector.ipxe +dhcp-boot=tag:ipxe,http://<%= @dnsmasq_local_ip_real %>:<%= @http_port_real %>/inspector.ipxe +dhcp-option=tag:ipxe6,option6:bootfile-url,http://<%= @dnsmasq_local_ip_real %>:<%= @http_port_real %>/inspector.ipxe # Client is PXE booting over EFI without iPXE ROM; send EFI version of iPXE chainloader dhcp-boot=tag:efi,tag:!ipxe,ipxe.efi # Client is running PXE over BIOS; send BIOS version of iPXE chainloader