diff --git a/xCAT-server/lib/xcat/plugins/openbmc.pm b/xCAT-server/lib/xcat/plugins/openbmc.pm index ff192fbbf..618e96200 100644 --- a/xCAT-server/lib/xcat/plugins/openbmc.pm +++ b/xCAT-server/lib/xcat/plugins/openbmc.pm @@ -36,6 +36,7 @@ $::POWER_STATE_POWERING_OFF="powering-off"; $::POWER_STATE_POWERING_ON="powering-on"; $::POWER_STATE_QUIESCED="quiesced"; $::POWER_STATE_RESET="reset"; +$::UPLOAD_FILE=""; $::NO_ATTRIBUTES_RETURNED="No attributes returned from the BMC."; @@ -126,6 +127,13 @@ my %status_info = ( RFLASH_LIST_RESPONSE => { process => \&rflash_response, }, + RFLASH_FILE_UPLOAD_REQUEST => { + method => "PUT", + init_url => "$openbmc_project_url/upload/image/", + }, + RFLASH_FILE_UPLOAD_RESPONSE => { + process => \&rflash_response, + }, RINV_REQUEST => { method => "GET", @@ -217,6 +225,7 @@ my %status_info = ( $::RESPONSE_OK = "200 OK"; $::RESPONSE_SERVER_ERROR = "500 Internal Server Error"; $::RESPONSE_SERVICE_UNAVAILABLE = "503 Service Unavailable"; +$::RESPONSE_METHOD_NOT_ALLOWED = "405 Method Not Allowed"; #----------------------------- @@ -677,6 +686,7 @@ sub parse_command_status { if ($update_file =~ /.*\.tar$/) { # Filename ending on .tar was specified $filename = $update_file; + $::UPLOAD_FILE = $update_file; # Save filename to upload if ($check_version) { # Display firmware version of the specified .tar file my $firmware_version_in_file = `$grep_cmd $version_tag $filename`; @@ -710,8 +720,9 @@ sub parse_command_status { return 1; } if ($upload) { - xCAT::SvrUtils::sendmsg("Upload option is not yet supported.", $callback); - return 1; + # Upload specified update file to BMC + $next_status{LOGIN_RESPONSE} = "RFLASH_FILE_UPLOAD_REQUEST"; + $next_status{"RFLASH_FILE_UPLOAD_REQUEST"} = "RFLASH_FILE_UPLOAD_RESPONSE"; } } @@ -832,7 +843,13 @@ sub gen_send_request { if ($method eq "GET") { $debug_info = "$node: DEBUG $method $request_url"; } else { - $debug_info = "$node: DEBUG $method $request_url -d $content"; + if ($::UPLOAD_FILE) { + # Slightly different debug message when doing a file upload + $debug_info = "$node: DEBUG $method $request_url -T " . $::UPLOAD_FILE; + } + else { + $debug_info = "$node: DEBUG $method $request_url -d $content"; + } } print "$debug_info\n"; @@ -864,6 +881,15 @@ sub deal_with_response { my $error; if ($response->status_line eq $::RESPONSE_SERVICE_UNAVAILABLE) { $error = $::RESPONSE_SERVICE_UNAVAILABLE; + } elsif ($response->status_line eq $::RESPONSE_METHOD_NOT_ALLOWED) { + # Special processing for file upload. At this point we do not know how to + # form a proper file upload request. It always fails with "Method not allowed" error. + # If that happens, just assume it worked. + # TODO remove this block when proper request can be generated + $status_info{ $node_info{$node}{cur_status} }->{process}->($node, $response); + + return; + } else { my $response_info = decode_json $response->content; if ($response->status_line eq $::RESPONSE_SERVER_ERROR) { @@ -1420,6 +1446,45 @@ sub rflash_response { } xCAT::SvrUtils::sendmsg("", $callback, $node); #Separate output in case more than 1 endpoint } + if ($node_info{$node}{cur_status} eq "RFLASH_FILE_UPLOAD_RESPONSE") { + # Special processing for file upload. At this point we do not know how to + # form a proper file upload request. It always fails with "Method not allowed" error. + # If that happens, just call the curl commands for now. + # TODO remove this block when proper request can be generated + if ($::UPLOAD_FILE) { + my $request_url_login = "$http_protocol://" . $node_info{$node}{bmc} . "/login"; + my $request_url_logout = "$http_protocol://" . $node_info{$node}{bmc} . "/logout"; + my $request_url_upload = "$http_protocol://" . $node_info{$node}{bmc} . "/upload/image/"; + my $content_login = '{ "data": [ "' . $node_info{$node}{username} .'", "' . $node_info{$node}{password} . '" ] }'; + my $content_logout = '{ "data": [ ] }'; + + # curl commands + my $curl_login_cmd = "curl -c cjar -k -H 'Content-Type: application/json' -X POST $request_url_login -d '" . $content_login . "'"; + my $curl_logout_cmd = "curl -b cjar -k -H 'Content-Type: application/json' -X POST $request_url_logout -d '" . $content_logout . "'"; + my $curl_upload_cmd = "curl -b cjar -k -H 'Content-Type: application/octet-stream' -X PUT -T $::UPLOAD_FILE $request_url_upload"; + + # Try to login + my $curl_login_result = `$curl_login_cmd`; + my $h = from_json($curl_login_result); # convert command output to hash + if ($h->{message} eq $::RESPONSE_OK) { + # Login successfull, upload the file + my $curl_upload_result = `$curl_upload_cmd`; + $h = from_json($curl_upload_result); # convert command output to hash + if ($h->{message} eq $::RESPONSE_OK) { + # Upload successfull + xCAT::SvrUtils::sendmsg("Update file $::UPLOAD_FILE successfully uploaded", $callback, $node); + # Try to logoff, no need to check result, as there is nothing else to do if failure + my $curl_logout_result = `$curl_logout_cmd`; + } + else { + xCAT::SvrUtils::sendmsg("Failed to upload update file $::UPLOAD_FILE :" . $h->{message} . " - " . $h->{data}->{description}, $callback, $node); + } + } + else { + xCAT::SvrUtils::sendmsg("Unable to login :" . $h->{message} . " - " . $h->{data}->{description}, $callback, $node); + } + } + } if ($next_status{ $node_info{$node}{cur_status} }) { $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };