From 016164594f7a7fa80b42ae40e932b71a9f41b233 Mon Sep 17 00:00:00 2001 From: Mark Gurevich Date: Thu, 15 Mar 2018 13:49:29 -0400 Subject: [PATCH 1/3] Do not allow firmware delete if active --- xCAT-server/lib/xcat/plugins/openbmc.pm | 125 +++++++++++++++--- .../testcase/UT_openbmc/rflash_cases0 | 2 +- 2 files changed, 108 insertions(+), 19 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/openbmc.pm b/xCAT-server/lib/xcat/plugins/openbmc.pm index 5bbc34877..2571857f2 100644 --- a/xCAT-server/lib/xcat/plugins/openbmc.pm +++ b/xCAT-server/lib/xcat/plugins/openbmc.pm @@ -276,6 +276,10 @@ my %status_info = ( process => \&rflash_response, }, + RFLASH_DELETE_CHECK_STATE_RESPONSE => { + process => \&rflash_response, + }, + RINV_REQUEST => { method => "GET", init_url => "$openbmc_project_url/inventory/enumerate", @@ -2034,9 +2038,10 @@ sub parse_command_status { $next_status{RFLASH_LIST_REQUEST} = "RFLASH_LIST_RESPONSE"; } if ($delete) { - # Delete uploaded image from BMC - $next_status{LOGIN_RESPONSE} = "RFLASH_DELETE_IMAGE_REQUEST"; - $next_status{RFLASH_DELETE_IMAGE_REQUEST} = "RFLASH_DELETE_IMAGE_RESPONSE"; + # Request to delete uploaded image from BMC or Host + # Firsh check if image is allowed to be deleted + $next_status{LOGIN_RESPONSE} = "RFLASH_LIST_REQUEST"; + $next_status{RFLASH_LIST_REQUEST} = "RFLASH_DELETE_CHECK_STATE_RESPONSE"; } if ($upload) { # Upload specified update file to BMC @@ -2632,32 +2637,42 @@ sub rpower_response { my $bmc_short_state = (split(/\./, $bmc_state))[-1]; if (defined($bmc_state) and $bmc_state !~ /State.BMC.BMCState.Ready$/) { if ($node_info{$node}{bmcstate_check_times} > 0) { - $node_info{$node}{bmcstate_check_times}--; - if ($node_info{$node}{wait_start}) { - $node_info{$node}{wait_end} = time(); + $node_info{$node}{bmcstate_check_times}--; + if ($node_info{$node}{wait_start}) { + $node_info{$node}{wait_end} = time(); + } else { + $node_info{$node}{wait_start} = time(); + } + retry_after($node, "RPOWER_BMC_STATUS_REQUEST", $::BMC_CHECK_INTERVAL); + return; } else { - $node_info{$node}{wait_start} = time(); + my $wait_time_X = $node_info{$node}{wait_end} - $node_info{$node}{wait_start}; + xCAT::SvrUtils::sendmsg([1, "Error: Sent bmcreboot but state did not change to BMC Ready after waiting $wait_time_X seconds. (State=BMC $bmc_short_state)."], $callback, $node); + $node_info{$node}{cur_status} = ""; + $wait_node_num--; + return; } - retry_after($node, "RPOWER_BMC_STATUS_REQUEST", $::BMC_CHECK_INTERVAL); - return; - } else { - my $wait_time_X = $node_info{$node}{wait_end} - $node_info{$node}{wait_start}; - xCAT::SvrUtils::sendmsg([1, "Error: Sent bmcreboot but state did not change to BMC Ready after waiting $wait_time_X seconds. (State=BMC $bmc_short_state)."], $callback, $node); - $node_info{$node}{cur_status} = ""; - $wait_node_num--; - return; - } } xCAT::SvrUtils::sendmsg("BMC $bmc_short_state", $callback, $node); - }else { + } else { if ($chassis_state =~ /Off$/) { # Chassis state is Off, but check if we can detect transition states if ((defined($::OPENBMC_PWR) and ($::OPENBMC_PWR eq "YES")) and $host_state =~ /Off$/ and $host_transition_state =~ /On$/) { xCAT::SvrUtils::sendmsg("$::POWER_STATE_POWERING_ON", $callback, $node); } else { - xCAT::SvrUtils::sendmsg("$::POWER_STATE_OFF", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} }); + if (defined $status_info{RPOWER_STATUS_RESPONSE}{argv} and $status_info{RPOWER_STATUS_RESPONSE}{argv} =~ /fw_delete$/) { + # We are here just to check the state of the Host to determine if ok to remove active FW + # The state is Off so FW can be removed + $next_status{"RPOWER_STATUS_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; + $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; + $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} }; + gen_send_request($node); + return; + } else { + xCAT::SvrUtils::sendmsg("$::POWER_STATE_OFF", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} }); + } } $all_status = $::POWER_STATE_OFF; } elsif ($chassis_state =~ /On$/) { @@ -2673,6 +2688,11 @@ sub rpower_response { $host_transition_state =~ /Off$/ and $chassis_state =~ /On$/) { xCAT::SvrUtils::sendmsg("$::POWER_STATE_POWERING_OFF", $callback, $node); } else { + if (defined $status_info{RPOWER_STATUS_RESPONSE}{argv} and $status_info{RPOWER_STATUS_RESPONSE}{argv} =~ /fw_delete$/) { + xCAT::SvrUtils::sendmsg([1, "Deleting currently active firmware on powered on host is not supported"], $callback, $node); + $wait_node_num--; + return; + } xCAT::SvrUtils::sendmsg("$::POWER_STATE_ON", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} }); } $all_status = $::POWER_STATE_ON; @@ -4227,6 +4247,75 @@ sub rflash_response { } xCAT::SvrUtils::sendmsg("", $callback, $node); #Separate output in case more than 1 endpoint } + if ($node_info{$node}{cur_status} eq "RFLASH_DELETE_CHECK_STATE_RESPONSE") { + # Verify selected FW ID is not active. If active display error message, + # If not active, proceed to delete + my $to_delete_id = (split ('/', $status_info{RFLASH_DELETE_IMAGE_REQUEST}{init_url}))[4]; + # Get the functional IDs to accurately mark the active running FW + my $functional = get_functional_software_ids($response_info); + foreach my $key_url (keys %{$response_info->{data}}) { + $update_id = (split(/\//, $key_url))[ -1 ]; + if ($update_id ne $to_delete_id) { + # Not a match on the id, try next one + next; + } + # Initialize values to Unknown for each loop, incase they are not defined in the BMC + $update_activation = "Unknown"; + $update_purpose = "Unknown"; + $update_version = "Unknown"; + + my %content = %{ ${ $response_info->{data} }{$key_url} }; + + if (defined($content{Version}) and $content{Version}) { + $update_version = $content{Version}; + } + else { + # Entry has no Version attribute, skip listing it + next; + } + if (defined($content{Purpose}) and $content{Purpose}) { + $update_purpose = (split(/\./, $content{Purpose}))[ -1 ]; + } + my $update_priority = -1; + # Just check defined, because priority=0 is a valid value + if (defined($content{Priority})) { + $update_priority = (split(/\./, $content{Priority}))[ -1 ]; + } + + # Check if this is active firmware + if (exists($functional->{$update_id}) ) { + if ($update_purpose eq "BMC") { + # Active BMC firmware can not be deleted + xCAT::SvrUtils::sendmsg([1, "Deleting currently active BMC firmware is not supported"], $callback, $node); + $wait_node_num--; + return; + } elsif ($update_purpose eq "Host") { + # Active Host firmware can NOT be deleted if host is ON + # Active Host firmware can be deleted if host is OFF + + # Send the request to check Host state + $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RPOWER_STATUS_REQUEST"; + $next_status{"RPOWER_STATUS_REQUEST"} = "RPOWER_STATUS_RESPONSE"; + # Set special argv to deleter_fw if Host is off + $status_info{RPOWER_STATUS_RESPONSE}{argv} = "fw_delete"; + last; + } else { + xCAT::SvrUtils::sendmsg([1, "Unable to determine the purpose of the firmware to delete"], $callback, $node); + # Can not figure out if Host or BMC, attempt to delete anyway. + # Worst case, BMC will not allow FW deletion if we are wrong + $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; + $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; + last; + } + } + else { + # FW is not active, it can be deleted. Send the request to do the deletion + $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; + $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; + last; + } + } + } if ($node_info{$node}{cur_status} eq "RFLASH_FILE_UPLOAD_REQUEST") { # # Special processing for file upload diff --git a/xCAT-test/autotest/testcase/UT_openbmc/rflash_cases0 b/xCAT-test/autotest/testcase/UT_openbmc/rflash_cases0 index f191d85c8..63911d67b 100644 --- a/xCAT-test/autotest/testcase/UT_openbmc/rflash_cases0 +++ b/xCAT-test/autotest/testcase/UT_openbmc/rflash_cases0 @@ -77,5 +77,5 @@ os:Linux hcp:openbmc cmd: rflash $$CN -l | grep \* | grep BMC | awk '{print $2}' | xargs -i{} rflash $$CN --delete {} check:rc==1 -check:output=~$$CN: Error: Deleting currently active firmware is not supported +check:output=~$$CN: Error: Deleting currently active BMC firmware is not supported end From cdaf8df706454055880e0a9cfc07f801072ae27f Mon Sep 17 00:00:00 2001 From: Mark Gurevich Date: Mon, 19 Mar 2018 13:30:30 -0400 Subject: [PATCH 2/3] Fix for review comments --- xCAT-server/lib/xcat/plugins/openbmc.pm | 116 +++++++++++++----------- 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/openbmc.pm b/xCAT-server/lib/xcat/plugins/openbmc.pm index 2571857f2..1a85ba9e8 100644 --- a/xCAT-server/lib/xcat/plugins/openbmc.pm +++ b/xCAT-server/lib/xcat/plugins/openbmc.pm @@ -4248,72 +4248,78 @@ sub rflash_response { xCAT::SvrUtils::sendmsg("", $callback, $node); #Separate output in case more than 1 endpoint } if ($node_info{$node}{cur_status} eq "RFLASH_DELETE_CHECK_STATE_RESPONSE") { - # Verify selected FW ID is not active. If active display error message, + # Verify selected FW ID is not active. If active, display error message, # If not active, proceed to delete my $to_delete_id = (split ('/', $status_info{RFLASH_DELETE_IMAGE_REQUEST}{init_url}))[4]; - # Get the functional IDs to accurately mark the active running FW + # Get the functional IDs to determint if active running FW can be deleted my $functional = get_functional_software_ids($response_info); - foreach my $key_url (keys %{$response_info->{data}}) { - $update_id = (split(/\//, $key_url))[ -1 ]; - if ($update_id ne $to_delete_id) { - # Not a match on the id, try next one - next; - } - # Initialize values to Unknown for each loop, incase they are not defined in the BMC - $update_activation = "Unknown"; - $update_purpose = "Unknown"; - $update_version = "Unknown"; + if (!%{$functional}) { + # Can not figure out if FW functional, attempt to delete anyway. + # Worst case, BMC will not allow FW deletion if we are wrong + $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; + $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; + } else { + foreach my $key_url (keys %{$response_info->{data}}) { + $update_id = (split(/\//, $key_url))[ -1 ]; + if ($update_id ne $to_delete_id) { + # Not a match on the id, try next one + next; + } + # Initialize values to Unknown for each loop, incase they are not defined in the BMC + $update_activation = "Unknown"; + $update_purpose = "Unknown"; + $update_version = "Unknown"; - my %content = %{ ${ $response_info->{data} }{$key_url} }; + my %content = %{ ${ $response_info->{data} }{$key_url} }; - if (defined($content{Version}) and $content{Version}) { - $update_version = $content{Version}; - } - else { - # Entry has no Version attribute, skip listing it - next; - } - if (defined($content{Purpose}) and $content{Purpose}) { - $update_purpose = (split(/\./, $content{Purpose}))[ -1 ]; - } - my $update_priority = -1; - # Just check defined, because priority=0 is a valid value - if (defined($content{Priority})) { - $update_priority = (split(/\./, $content{Priority}))[ -1 ]; - } - - # Check if this is active firmware - if (exists($functional->{$update_id}) ) { - if ($update_purpose eq "BMC") { - # Active BMC firmware can not be deleted - xCAT::SvrUtils::sendmsg([1, "Deleting currently active BMC firmware is not supported"], $callback, $node); - $wait_node_num--; - return; - } elsif ($update_purpose eq "Host") { - # Active Host firmware can NOT be deleted if host is ON - # Active Host firmware can be deleted if host is OFF - - # Send the request to check Host state - $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RPOWER_STATUS_REQUEST"; - $next_status{"RPOWER_STATUS_REQUEST"} = "RPOWER_STATUS_RESPONSE"; - # Set special argv to deleter_fw if Host is off - $status_info{RPOWER_STATUS_RESPONSE}{argv} = "fw_delete"; - last; + if (defined($content{Version}) and $content{Version}) { + $update_version = $content{Version}; } else { - xCAT::SvrUtils::sendmsg([1, "Unable to determine the purpose of the firmware to delete"], $callback, $node); - # Can not figure out if Host or BMC, attempt to delete anyway. - # Worst case, BMC will not allow FW deletion if we are wrong + # Entry has no Version attribute, skip listing it + next; + } + if (defined($content{Purpose}) and $content{Purpose}) { + $update_purpose = (split(/\./, $content{Purpose}))[ -1 ]; + } + my $update_priority = -1; + # Just check defined, because priority=0 is a valid value + if (defined($content{Priority})) { + $update_priority = (split(/\./, $content{Priority}))[ -1 ]; + } + + # Check if this is active firmware + if (exists($functional->{$update_id}) ) { + if ($update_purpose eq "BMC") { + # Active BMC firmware can not be deleted + xCAT::SvrUtils::sendmsg([1, "Deleting currently active BMC firmware is not supported"], $callback, $node); + $wait_node_num--; + return; + } elsif ($update_purpose eq "Host") { + # Active Host firmware can NOT be deleted if host is ON + # Active Host firmware can be deleted if host is OFF + + # Send the request to check Host state + $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RPOWER_STATUS_REQUEST"; + $next_status{"RPOWER_STATUS_REQUEST"} = "RPOWER_STATUS_RESPONSE"; + # Set special argv to fw_delete if Host is off + $status_info{RPOWER_STATUS_RESPONSE}{argv} = "fw_delete"; + last; + } else { + xCAT::SvrUtils::sendmsg([1, "Unable to determine the purpose of the firmware to delete"], $callback, $node); + # Can not figure out if Host or BMC, attempt to delete anyway. + # Worst case, BMC will not allow FW deletion if we are wrong + $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; + $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; + last; + } + } + else { + # FW is not active, it can be deleted. Send the request to do the deletion $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; last; } } - else { - # FW is not active, it can be deleted. Send the request to do the deletion - $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; - $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; - last; - } } } if ($node_info{$node}{cur_status} eq "RFLASH_FILE_UPLOAD_REQUEST") { From 1c69da5b4e90f0dd390fbfd08a0b06cc030c5ea9 Mon Sep 17 00:00:00 2001 From: Mark Gurevich Date: Wed, 21 Mar 2018 16:59:24 -0400 Subject: [PATCH 3/3] Another improvement after review --- xCAT-server/lib/xcat/plugins/openbmc.pm | 50 +++++++++++-------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/openbmc.pm b/xCAT-server/lib/xcat/plugins/openbmc.pm index 1a85ba9e8..5c54eacc7 100644 --- a/xCAT-server/lib/xcat/plugins/openbmc.pm +++ b/xCAT-server/lib/xcat/plugins/openbmc.pm @@ -4253,9 +4253,12 @@ sub rflash_response { my $to_delete_id = (split ('/', $status_info{RFLASH_DELETE_IMAGE_REQUEST}{init_url}))[4]; # Get the functional IDs to determint if active running FW can be deleted my $functional = get_functional_software_ids($response_info); - if (!%{$functional}) { + if ((!%{$functional}) || + (!exists($functional->{$to_delete_id}))) { # Can not figure out if FW functional, attempt to delete anyway. # Worst case, BMC will not allow FW deletion if we are wrong + # OR + # FW is not active, it can be deleted. Send the request to do the deletion $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; } else { @@ -4287,34 +4290,25 @@ sub rflash_response { $update_priority = (split(/\./, $content{Priority}))[ -1 ]; } - # Check if this is active firmware - if (exists($functional->{$update_id}) ) { - if ($update_purpose eq "BMC") { - # Active BMC firmware can not be deleted - xCAT::SvrUtils::sendmsg([1, "Deleting currently active BMC firmware is not supported"], $callback, $node); - $wait_node_num--; - return; - } elsif ($update_purpose eq "Host") { - # Active Host firmware can NOT be deleted if host is ON - # Active Host firmware can be deleted if host is OFF + if ($update_purpose eq "BMC") { + # Active BMC firmware can not be deleted + xCAT::SvrUtils::sendmsg([1, "Deleting currently active BMC firmware is not supported"], $callback, $node); + $wait_node_num--; + return; + } elsif ($update_purpose eq "Host") { + # Active Host firmware can NOT be deleted if host is ON + # Active Host firmware can be deleted if host is OFF - # Send the request to check Host state - $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RPOWER_STATUS_REQUEST"; - $next_status{"RPOWER_STATUS_REQUEST"} = "RPOWER_STATUS_RESPONSE"; - # Set special argv to fw_delete if Host is off - $status_info{RPOWER_STATUS_RESPONSE}{argv} = "fw_delete"; - last; - } else { - xCAT::SvrUtils::sendmsg([1, "Unable to determine the purpose of the firmware to delete"], $callback, $node); - # Can not figure out if Host or BMC, attempt to delete anyway. - # Worst case, BMC will not allow FW deletion if we are wrong - $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; - $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; - last; - } - } - else { - # FW is not active, it can be deleted. Send the request to do the deletion + # Send the request to check Host state + $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RPOWER_STATUS_REQUEST"; + $next_status{"RPOWER_STATUS_REQUEST"} = "RPOWER_STATUS_RESPONSE"; + # Set special argv to fw_delete if Host is off + $status_info{RPOWER_STATUS_RESPONSE}{argv} = "fw_delete"; + last; + } else { + xCAT::SvrUtils::sendmsg([1, "Unable to determine the purpose of the firmware to delete"], $callback, $node); + # Can not figure out if Host or BMC, attempt to delete anyway. + # Worst case, BMC will not allow FW deletion if we are wrong $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST"; $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE"; last;