blob: 4be19583d3a1e7873b7c8ebe05446000bf93319c [file] [log] [blame]
#include <experimental/filesystem>
#include "activation.hpp"
#include "config.h"
#include "item_updater.hpp"
#include "serialize.hpp"
namespace openpower
{
namespace software
{
namespace updater
{
namespace fs = std::experimental::filesystem;
namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
void Activation::subscribeToSystemdSignals()
{
auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
SYSTEMD_OBJ_PATH,
SYSTEMD_INTERFACE,
"Subscribe");
this->bus.call_noreply(method);
return;
}
void Activation::createSymlinks()
{
if (!fs::is_directory(PNOR_ACTIVE_PATH))
{
fs::create_directories(PNOR_ACTIVE_PATH);
}
// If the RW or RO active links exist, remove them and create new
// ones pointing to the active version.
if (fs::is_symlink(PNOR_RO_ACTIVE_PATH))
{
fs::remove(PNOR_RO_ACTIVE_PATH);
}
fs::create_directory_symlink(PNOR_RO_PREFIX + versionId,
PNOR_RO_ACTIVE_PATH);
if (fs::is_symlink(PNOR_RW_ACTIVE_PATH))
{
fs::remove(PNOR_RW_ACTIVE_PATH);
}
fs::create_directory_symlink(PNOR_RW_PREFIX + versionId,
PNOR_RW_ACTIVE_PATH);
// There is only one preserved directory as it is not tied to a
// version, so just create the link if it doesn't exist already
if (!fs::is_symlink(PNOR_PRSV_ACTIVE_PATH))
{
fs::create_directory_symlink(PNOR_PRSV,
PNOR_PRSV_ACTIVE_PATH);
}
}
auto Activation::activation(Activations value) ->
Activations
{
if (value != softwareServer::Activation::Activations::Active)
{
redundancyPriority.reset(nullptr);
}
if (value == softwareServer::Activation::Activations::Activating)
{
softwareServer::Activation::activation(value);
if (squashfsLoaded == false && rwVolumesCreated == false)
{
// If the squashfs image has not yet been loaded to pnor and the
// RW volumes have not yet been created, we need to start the
// service files for each of those actions.
if (!activationProgress)
{
activationProgress = std::make_unique<ActivationProgress>(bus,
path);
}
if (!activationBlocksTransition)
{
activationBlocksTransition =
std::make_unique<ActivationBlocksTransition>(
bus,
path);
}
constexpr auto squashfsMountService =
"obmc-flash-bios-squashfsmount@";
auto squashfsMountServiceFile = std::string(squashfsMountService) +
versionId + ".service";
auto method = bus.new_method_call(
SYSTEMD_BUSNAME,
SYSTEMD_PATH,
SYSTEMD_INTERFACE,
"StartUnit");
method.append(squashfsMountServiceFile, "replace");
bus.call_noreply(method);
constexpr auto ubimountService = "obmc-flash-bios-ubimount@";
auto ubimountServiceFile = std::string(ubimountService) +
versionId +
".service";
method = bus.new_method_call(
SYSTEMD_BUSNAME,
SYSTEMD_PATH,
SYSTEMD_INTERFACE,
"StartUnit");
method.append(ubimountServiceFile, "replace");
bus.call_noreply(method);
activationProgress->progress(10);
return softwareServer::Activation::activation(value);
}
else if (squashfsLoaded == true && rwVolumesCreated == true)
{
// Only when the squashfs image is finished loading AND the RW
// volumes have been created do we proceed with activation.
// The ubimount service files attemps to create the RW and Preserved
// UBI volumes. If the service fails, the mount dirs PNOR_PRSV
// and PNOR_RW_PREFIX_<versionid> won't be present. Check for the
// existence of those directories to validate the service file was
// successful, also for the existence of the RO directory where the
// image is supposed to reside.
if ((fs::is_directory(PNOR_PRSV)) &&
(fs::is_directory(PNOR_RW_PREFIX + versionId)) &&
(fs::is_directory(PNOR_RO_PREFIX + versionId)))
{
activationProgress->progress(90);
createSymlinks();
// Set Redundancy Priority before setting to Active
if (!redundancyPriority)
{
redundancyPriority =
std::make_unique<RedundancyPriority>(
bus,
path,
*this,
0);
}
activationProgress->progress(100);
activationBlocksTransition.reset(nullptr);
activationProgress.reset(nullptr);
squashfsLoaded = false;
rwVolumesCreated = false;
//TODO: openbmc/openbmc#1843: Unsubscribe from systemd signals.
return softwareServer::Activation::activation(
softwareServer::Activation::Activations::Active);
}
else
{
activationBlocksTransition.reset(nullptr);
activationProgress.reset(nullptr);
return softwareServer::Activation::activation(
softwareServer::Activation::Activations::Failed);
}
}
else
{
// If either the squashfs image has not yet been loaded or the RW
// volumes have not yet been created, the activation process is
// ongoing, so we return "Activating" status.
return softwareServer::Activation::activation(value);
}
}
else
{
activationBlocksTransition.reset(nullptr);
activationProgress.reset(nullptr);
return softwareServer::Activation::activation(value);
}
}
auto Activation::requestedActivation(RequestedActivations value) ->
RequestedActivations
{
squashfsLoaded = false;
rwVolumesCreated = false;
if ((value == softwareServer::Activation::RequestedActivations::Active) &&
(softwareServer::Activation::requestedActivation() !=
softwareServer::Activation::RequestedActivations::Active))
{
if ((softwareServer::Activation::activation() ==
softwareServer::Activation::Activations::Ready) ||
(softwareServer::Activation::activation() ==
softwareServer::Activation::Activations::Failed))
{
Activation::activation(
softwareServer::Activation::Activations::Activating);
}
}
return softwareServer::Activation::requestedActivation(value);
}
uint8_t RedundancyPriority::priority(uint8_t value)
{
parent.parent.freePriority(value);
if(parent.parent.isLowestPriority(value))
{
// Need to update the symlinks to point to Software Version
// with lowest priority.
parent.createSymlinks();
}
storeToFile(parent.versionId, value);
return softwareServer::RedundancyPriority::priority(value);
}
void Activation::unitStateChange(sdbusplus::message::message& msg)
{
uint32_t newStateID {};
sdbusplus::message::object_path newStateObjPath;
std::string newStateUnit{};
std::string newStateResult{};
//Read the msg and populate each variable
msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
auto squashfsMountServiceFile =
"obmc-flash-bios-squashfsmount@" + versionId + ".service";
auto ubimountServiceFile =
"obmc-flash-bios-ubimount@" + versionId + ".service";
if(newStateUnit == squashfsMountServiceFile && newStateResult == "done")
{
squashfsLoaded = true;
activationProgress->progress(activationProgress->progress() + 20);
}
if(newStateUnit == ubimountServiceFile && newStateResult == "done")
{
rwVolumesCreated = true;
activationProgress->progress(activationProgress->progress() + 50);
}
if(squashfsLoaded && rwVolumesCreated)
{
Activation::activation(
softwareServer::Activation::Activations::Activating);
}
if((newStateUnit == squashfsMountServiceFile ||
newStateUnit == ubimountServiceFile) &&
(newStateResult == "failed" || newStateResult == "dependency"))
{
Activation::activation(softwareServer::Activation::Activations::Failed);
}
return;
}
void Activation::delete_()
{
parent.erase(versionId);
}
} // namespace updater
} // namespace software
} // namespace openpower