diff options
| author | Patrick Venture <venture@google.com> | 2019-05-16 10:06:26 -0700 |
|---|---|---|
| committer | Patrick Venture <venture@google.com> | 2019-05-16 11:30:59 -0700 |
| commit | 55646dec5f09c4f5704ed11ef6da5f8fd8bd4427 (patch) | |
| tree | 29c11cce95d8a96f1c1b0561fccbe495136b9569 /tools | |
| parent | 12233c5d55785ceaab0f5ad0e6edddd0020246a3 (diff) | |
| download | phosphor-ipmi-flash-55646dec5f09c4f5704ed11ef6da5f8fd8bd4427.tar.gz phosphor-ipmi-flash-55646dec5f09c4f5704ed11ef6da5f8fd8bd4427.zip | |
tools: add update handler
Add an UpdateHandler to handle each step of the update process.
This code was already in place but is now handled via an UpdateHandler
object.
Tested: Not yet tested.
Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I36cd1b94d8e2c0788d09805d935738d86e6e33de
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/main.cpp | 4 | ||||
| -rw-r--r-- | tools/updater.cpp | 235 | ||||
| -rw-r--r-- | tools/updater.hpp | 50 |
3 files changed, 170 insertions, 119 deletions
diff --git a/tools/main.cpp b/tools/main.cpp index 5868d11..536cde1 100644 --- a/tools/main.cpp +++ b/tools/main.cpp @@ -175,8 +175,8 @@ int main(int argc, char* argv[]) /* The parameters are all filled out. */ try { - host_tool::updaterMain(&blob, handler.get(), imagePath, - signaturePath); + host_tool::UpdateHandler updater(&blob, handler.get()); + host_tool::updaterMain(&updater, imagePath, signaturePath); } catch (const host_tool::ToolException& e) { diff --git a/tools/updater.cpp b/tools/updater.cpp index 975ee0f..92afe5d 100644 --- a/tools/updater.cpp +++ b/tools/updater.cpp @@ -26,10 +26,84 @@ #include <memory> #include <string> #include <thread> +#include <vector> namespace host_tool { +bool UpdateHandler::checkAvailable(const std::string& goalFirmware) +{ + std::vector<std::string> blobs = blob->getBlobList(); + + auto blobInst = std::find_if( + blobs.begin(), blobs.end(), [&goalFirmware](const std::string& iter) { + /* Running into weird scenarios where the string comparison doesn't + * work. TODO: revisit. + */ + return (0 == std::memcmp(goalFirmware.c_str(), iter.c_str(), + goalFirmware.length())); + // return (goalFirmware.compare(iter)); + }); + if (blobInst == blobs.end()) + { + std::fprintf(stderr, "%s not found\n", goalFirmware.c_str()); + return false; + } + + /* Call stat on /flash/image (or /flash/tarball) and check if data interface + * is supported. + */ + ipmiblob::StatResponse stat; + + try + { + stat = blob->getStat(goalFirmware); + } + catch (const ipmiblob::BlobException& b) + { + std::fprintf(stderr, "Received exception '%s' on getStat\n", b.what()); + return false; + } + + auto supported = handler->supportedType(); + if ((stat.blob_state & supported) == 0) + { + std::fprintf(stderr, "data interface selected not supported.\n"); + return false; + } + + return true; +} + +void UpdateHandler::sendFile(const std::string& target, const std::string& path) +{ + std::uint16_t session; + auto supported = handler->supportedType(); + + try + { + session = blob->openBlob( + target, static_cast<std::uint16_t>(supported) | + static_cast<std::uint16_t>(blobs::OpenFlags::write)); + } + catch (const ipmiblob::BlobException& b) + { + throw ToolException("blob exception received: " + + std::string(b.what())); + } + + if (!handler->sendContents(path, session)) + { + /* Need to close the session on failure, or it's stuck open (until the + * blob handler timeout is implemented, and even then, why make it wait. + */ + blob->closeBlob(session); + throw ToolException("Failed to send contents of " + path); + } + + blob->closeBlob(session); +} + /* Poll an open verification session. Handling closing the session is not yet * owned by this method. */ bool pollVerificationStatus(std::uint16_t session, @@ -111,120 +185,15 @@ bool pollVerificationStatus(std::uint16_t session, blobs::FirmwareBlobHandler::VerifyCheckResponses::success); } -void updaterMain(ipmiblob::BlobInterface* blob, DataInterface* handler, - const std::string& imagePath, const std::string& signaturePath) +bool UpdateHandler::verifyFile(const std::string& target) { - /* TODO(venture): Add optional parameter to specify the flash type, default - * to legacy for now. - * - * TODO(venture): Move the strings from the FirmwareHandler object to a - * boring utils object so it will be more happly linked cleanly to both the - * BMC and host-side. - */ - std::string goalFirmware = "/flash/image"; - std::string hashFilename = "/flash/hash"; - std::string verifyFilename = "/flash/verify"; - - /* Get list of blob_ids, check for /flash/image, or /flash/tarball. - * TODO(venture) the mechanism doesn't care, but the caller of burn_my_bmc - * will have in mind which they're sending and we need to verify it's - * available and use it. - */ - std::vector<std::string> blobs = blob->getBlobList(); - auto blobInst = std::find_if( - blobs.begin(), blobs.end(), [&goalFirmware](const std::string& iter) { - /* Running into weird scenarios where the string comparison doesn't - * work. TODO: revisit. - */ - return (0 == std::memcmp(goalFirmware.c_str(), iter.c_str(), - goalFirmware.length())); - // return (goalFirmware.compare(iter)); - }); - if (blobInst == blobs.end()) - { - throw ToolException(goalFirmware + " not found"); - } - - /* Call stat on /flash/image (or /flash/tarball) and check if data interface - * is supported. - */ - ipmiblob::StatResponse stat; - try - { - stat = blob->getStat(goalFirmware); - } - catch (const ipmiblob::BlobException& b) - { - throw ToolException("blob exception received: " + - std::string(b.what())); - } - - auto supported = handler->supportedType(); - if ((stat.blob_state & supported) == 0) - { - throw ToolException("data interface selected not supported."); - } - - /* Yay, our data handler is supported. */ - - /* Send over the firmware image. */ - std::fprintf(stderr, "Sending over the firmware image.\n"); std::uint16_t session; - try - { - session = blob->openBlob( - goalFirmware, - static_cast<std::uint16_t>(supported) | - static_cast<std::uint16_t>(blobs::OpenFlags::write)); - } - catch (const ipmiblob::BlobException& b) - { - throw ToolException("blob exception received: " + - std::string(b.what())); - } - - if (!handler->sendContents(imagePath, session)) - { - /* Need to close the session on failure, or it's stuck open (until the - * blob handler timeout is implemented, and even then, why make it wait. - */ - blob->closeBlob(session); - throw ToolException("Failed to send contents of " + imagePath); - } - - blob->closeBlob(session); - - /* Send over the hash contents. */ - std::fprintf(stderr, "Sending over the hash file.\n"); - try - { - session = blob->openBlob( - hashFilename, - static_cast<std::uint16_t>(supported) | - static_cast<std::uint16_t>(blobs::OpenFlags::write)); - } - catch (const ipmiblob::BlobException& b) - { - throw ToolException("blob exception received: " + - std::string(b.what())); - } - - if (!handler->sendContents(signaturePath, session)) - { - blob->closeBlob(session); - throw ToolException("Failed to send contents of " + signaturePath); - } - - blob->closeBlob(session); + bool success = false; - /* Trigger the verification by opening the verify file. */ - std::fprintf(stderr, "Opening the verification file\n"); try { session = blob->openBlob( - verifyFilename, - static_cast<std::uint16_t>(supported) | - static_cast<std::uint16_t>(blobs::OpenFlags::write)); + target, static_cast<std::uint16_t>(blobs::OpenFlags::write)); } catch (const ipmiblob::BlobException& b) { @@ -235,6 +204,7 @@ void updaterMain(ipmiblob::BlobInterface* blob, DataInterface* handler, std::fprintf( stderr, "Committing to verification file to trigger verification service\n"); + try { blob->commit(session, {}); @@ -251,6 +221,7 @@ void updaterMain(ipmiblob::BlobInterface* blob, DataInterface* handler, if (pollVerificationStatus(session, blob)) { std::fprintf(stderr, "Verification returned success\n"); + success = true; } else { @@ -258,12 +229,50 @@ void updaterMain(ipmiblob::BlobInterface* blob, DataInterface* handler, "be running (unlikely))\n"); } - /* DO NOT CLOSE the verification session until it's done. - * TODO: Evaluate what closing verification should do? If the process is - * complete, nothing bad, maybe reset the entire state machine? This will - * benefit from a diagram. - */ blob->closeBlob(session); + return (success == true); +} + +void updaterMain(UpdateHandler* updater, const std::string& imagePath, + const std::string& signaturePath) +{ + /* TODO(venture): Add optional parameter to specify the flash type, default + * to legacy for now. + * + * TODO(venture): Move the strings from the FirmwareHandler object to a + * boring utils object so it will be more happly linked cleanly to both the + * BMC and host-side. + */ + std::string goalFirmware = "/flash/image"; + std::string hashFilename = "/flash/hash"; + std::string verifyFilename = "/flash/verify"; + + bool goalSupported = updater->checkAvailable(goalFirmware); + if (!goalSupported) + { + throw ToolException("Goal firmware or interface not supported"); + } + + /* Yay, our data handler is supported. */ + + /* Send over the firmware image. */ + std::fprintf(stderr, "Sending over the firmware image.\n"); + updater->sendFile(goalFirmware, imagePath); + + /* Send over the hash contents. */ + std::fprintf(stderr, "Sending over the hash file.\n"); + updater->sendFile(hashFilename, signaturePath); + + /* Trigger the verification by opening the verify file. */ + std::fprintf(stderr, "Opening the verification file\n"); + if (updater->verifyFile(verifyFilename)) + { + std::fprintf(stderr, "succeeded\n"); + } + else + { + std::fprintf(stderr, "failed\n"); + } } } // namespace host_tool diff --git a/tools/updater.hpp b/tools/updater.hpp index 062f704..4674e91 100644 --- a/tools/updater.hpp +++ b/tools/updater.hpp @@ -8,6 +8,50 @@ namespace host_tool { +/** Object that actually handles the update itself. */ +class UpdateHandler +{ + public: + UpdateHandler(ipmiblob::BlobInterface* blob, DataInterface* handler) : + blob(blob), handler(handler) + { + } + + virtual ~UpdateHandler() = default; + + /** + * Check if the goal firmware is listed in the blob_list and that the + * handler's supported data type is available. + * + * @param[in] goalFirmware - the firmware to check /flash/image + * /flash/tarball, etc. + */ + virtual bool checkAvailable(const std::string& goalFirmware); + + /** + * Send the file contents at path to the blob id, target. + * + * @param[in] target - the blob id + * @param[in] path - the source file path + * @throw ToolException on failure. + */ + virtual void sendFile(const std::string& target, const std::string& path); + + /** + * Trigger verification. + * + * @param[in] target - the verification blob id (may support multiple in the + * future. + * @return true if verified, false if verification errors. + * @throw ToolException on failure (TODO: throw on timeout.) + */ + virtual bool verifyFile(const std::string& target); + + private: + ipmiblob::BlobInterface* blob; + DataInterface* handler; +}; + /** * Poll an open verification session. * @@ -21,14 +65,12 @@ bool pollVerificationStatus(std::uint16_t session, /** * Attempt to update the BMC's firmware using the interface provided. * - * @param[in] blob - pointer to blob interface implementation object. - * @param[in] handler - pointer to the data interface implementation object. + * @param[in] updater - update handler object. * @param[in] imagePath - the path to the image file. * @param[in] signaturePath - the path to the signature file. * @throws ToolException on failures. */ -void updaterMain(ipmiblob::BlobInterface* blob, DataInterface* handler, - const std::string& imagePath, +void updaterMain(UpdateHandler* updater, const std::string& imagePath, const std::string& signaturePath); } // namespace host_tool |

