diff --git a/xCAT-server/lib/xcat/plugins/dhcp.pm b/xCAT-server/lib/xcat/plugins/dhcp.pm index 095ca03a9..1a0e5ba42 100644 --- a/xCAT-server/lib/xcat/plugins/dhcp.pm +++ b/xCAT-server/lib/xcat/plugins/dhcp.pm @@ -2476,6 +2476,11 @@ sub kea_process_request $client_classes_changed = kea_remove_xnba_client_classes($loaded4, $nodes); } else { $reservations4 = kea_build_node_reservations($backend, $loaded4, $nodes); + if (ref($reservations4) eq 'HASH' && $reservations4->{error}) { + $callback->({ error => [ $reservations4->{error} ], errorcode => [1] }); + flock($dhcplockfd, LOCK_UN); + return; + } $backend->upsert_reservations($loaded4, $reservations4); $client_classes_changed = kea_sync_xnba_client_classes($loaded4, $nodes); if ($loaded6) { @@ -3092,7 +3097,9 @@ sub kea_build_node_reservations my @reservations; foreach my $node (@$nodes) { - push @reservations, @{ kea_node_reservations($backend, $config, $node) }; + my $node_reservations = kea_node_reservations($backend, $config, $node); + return $node_reservations if ref($node_reservations) eq 'HASH' && $node_reservations->{error}; + push @reservations, @$node_reservations; } return \@reservations; @@ -3148,7 +3155,7 @@ sub kea_node_reservations $mac = $normalized_mac; my $ip = getipaddr($hname, OnlyV4 => 1); - next unless $ip; + return { error => "Unable to resolve $hname for the Kea DHCP reservation for $node." } unless $ip; if (ipIsDynamic($ip)) { $callback->({ error => ["Node $node has IP $ip which is inside the DHCP dynamic range. Move the node IP outside the dynamic range or adjust the range in the networks table."], errorcode => [1] }); diff --git a/xCAT-test/unit/dhcp_kea_plugin_intent.t b/xCAT-test/unit/dhcp_kea_plugin_intent.t index ce3a38ba5..afb6d739b 100644 --- a/xCAT-test/unit/dhcp_kea_plugin_intent.t +++ b/xCAT-test/unit/dhcp_kea_plugin_intent.t @@ -494,6 +494,88 @@ foreach my $case (@invalid_mac_cases) { ); } +{ + my %unresolved_tables = ( + noderes => DHCPKeaResTable->new( { unresolved01 => {} } ), + chain => DHCPKeaResTable->new( { unresolved01 => {} } ), + nodetype => DHCPKeaResTable->new( { unresolved01 => {} } ), + iscsi => DHCPKeaResTable->new( {} ), + mac => DHCPKeaResTable->new( { unresolved01 => { mac => '00:11:22:33:44:55' } } ), + ); + + no warnings 'redefine'; + local *xCAT::Table::new = sub { + my ( $class, $name ) = @_; + return $unresolved_tables{$name}; + }; + local *xCAT_plugin::dhcp::getipaddr = sub { return; }; + local *xCAT_plugin::dhcp::kea_next_server_for_node = sub { return ( '192.0.2.1', '192.0.2.1' ); }; + + my $backend = bless {}, 'DHCPKeaResBackend'; + my $result = xCAT_plugin::dhcp::kea_build_node_reservations( $backend, {}, ['unresolved01'] ); + + is( ref($result), 'HASH', 'unresolved Kea reservation returns an error result' ); + is( + $result->{error}, + 'Unable to resolve unresolved01 for the Kea DHCP reservation for unresolved01.', + 'unresolved Kea reservation identifies the requested node' + ); +} + +{ + package DHCPKeaWriteGuardBackend; + sub load_dhcp4_config { + return { Dhcp4 => { subnet4 => [ { id => 1, subnet => '192.0.2.0/24' } ] } }; + } + sub upsert_reservations { $_[0]->{writes}++; return; } + sub write_dhcp4_json { $_[0]->{writes}++; return {}; } + + package main; + + no warnings 'redefine'; + local *xCAT_plugin::dhcp::kea_build_dhcp4_intent = sub { return { subnets => [] }; }; + local *xCAT_plugin::dhcp::kea_build_dhcp6_intent = sub { return { subnets => [] }; }; + local *xCAT_plugin::dhcp::kea_build_ddns_intent = sub { return; }; + local *xCAT_plugin::dhcp::kea_expand_request_nodes = sub { return ['unresolved01']; }; + local *xCAT_plugin::dhcp::kea_build_node_reservations = sub { + return { error => 'Unable to resolve unresolved01 for the Kea DHCP reservation for unresolved01.' }; + }; + local *xCAT::MsgUtils::message = sub { return; }; + local *xCAT::MsgUtils::trace = sub { return; }; + + my @errors; + my $capture_error = sub { + my $response = shift; + push @errors, @{ $response->{error} || [] }; + }; + my $saved_umask = umask; + my $saved_ignorecase = $Getopt::Long::ignorecase; + { + local @ARGV; + xCAT_plugin::dhcp::process_request( + { + _xcatpreprocessed => [0], + arg => [ '-q', '-a' ], + }, + $capture_error + ); + } + umask $saved_umask; + $Getopt::Long::ignorecase = $saved_ignorecase; + Getopt::Long::Configure('pass_through'); + @errors = (); + + my $backend = bless { writes => 0 }, 'DHCPKeaWriteGuardBackend'; + xCAT_plugin::dhcp::kea_process_request( $backend, { node => ['unresolved01'] }, {}, {}, 0 ); + + is_deeply( + \@errors, + ['Unable to resolve unresolved01 for the Kea DHCP reservation for unresolved01.'], + 'unresolved Kea reservation is reported to the caller' + ); + is( $backend->{writes}, 0, 'unresolved Kea reservation leaves the configuration unchanged' ); +} + { my %xnba_tables = ( noderes => DHCPKeaResTable->new( { xnba01 => { netboot => 'xnba' } } ),