1 /* 2 * Copyright 2019 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "helper.hpp" 18 19 #include "status.hpp" 20 #include "tool_errors.hpp" 21 22 #include <ipmiblob/blob_errors.hpp> 23 24 #include <chrono> 25 #include <thread> 26 27 namespace host_tool 28 { 29 30 /* Poll an open verification session. Handling closing the session is not yet 31 * owned by this method. 32 */ 33 bool pollStatus(std::uint16_t session, ipmiblob::BlobInterface* blob) 34 { 35 using namespace std::chrono_literals; 36 37 static constexpr auto verificationSleep = 5s; 38 ipmi_flash::ActionStatus result = ipmi_flash::ActionStatus::unknown; 39 40 try 41 { 42 /* sleep for 5 seconds and check 360 times, for a timeout of: 1800 43 * seconds (30 minutes). 44 * TODO: make this command line configurable and provide smaller 45 * default value. 46 */ 47 static constexpr int commandAttempts = 360; 48 int attempts = 0; 49 bool exitLoop = false; 50 51 /* Reach back the current status from the verification service output. 52 */ 53 while (attempts++ < commandAttempts) 54 { 55 ipmiblob::StatResponse resp = blob->getStat(session); 56 57 if (resp.metadata.size() != sizeof(std::uint8_t)) 58 { 59 /* TODO: How do we want to handle the verification failures, 60 * because closing the session to the verify blob has a special 61 * as-of-yet not fully defined behavior. 62 */ 63 std::fprintf(stderr, "Received invalid metadata response!!!\n"); 64 } 65 66 result = static_cast<ipmi_flash::ActionStatus>(resp.metadata[0]); 67 68 switch (result) 69 { 70 case ipmi_flash::ActionStatus::failed: 71 std::fprintf(stderr, "failed\n"); 72 exitLoop = true; 73 break; 74 case ipmi_flash::ActionStatus::unknown: 75 std::fprintf(stderr, "other\n"); 76 break; 77 case ipmi_flash::ActionStatus::running: 78 std::fprintf(stderr, "running\n"); 79 break; 80 case ipmi_flash::ActionStatus::success: 81 std::fprintf(stderr, "success\n"); 82 exitLoop = true; 83 break; 84 default: 85 std::fprintf(stderr, "wat\n"); 86 } 87 88 if (exitLoop) 89 { 90 break; 91 } 92 std::this_thread::sleep_for(verificationSleep); 93 } 94 } 95 catch (const ipmiblob::BlobException& b) 96 { 97 throw ToolException("blob exception received: " + 98 std::string(b.what())); 99 } 100 101 /* TODO: If this is reached and it's not success, it may be worth just 102 * throwing a ToolException with a timeout message specifying the final 103 * read's value. 104 * 105 * TODO: Given that excepting from certain points leaves the BMC update 106 * state machine in an inconsistent state, we need to carefully evaluate 107 * which exceptions from the lower layers allow one to try and delete the 108 * blobs to rollback the state and progress. 109 */ 110 return (result == ipmi_flash::ActionStatus::success); 111 } 112 113 } // namespace host_tool 114