Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ cc_library(
visibility = ["//score/launch_manager/src/daemon/src/process_group_manager:__subpackages__"],
deps = [
":icomponent",
"//score/launch_manager/src/daemon/src/alive_monitor:ialive_supervision_handle",
"//score/launch_manager/src/daemon/src/alive_monitor:isupervision_factory",
"//score/launch_manager/src/daemon/src/common:log",
"//score/launch_manager/src/daemon/src/configuration:component_config",
"//score/launch_manager/src/daemon/src/process_group_manager/details/force_stop_action:iforce_stop_action",
"//score/launch_manager/src/daemon/src/process_group_manager/details/ready_condition:iready_condition",
"//score/launch_manager/src/daemon/src/process_group_manager/details/start_action:istart_action",
Expand All @@ -37,6 +41,9 @@ lm_cc_test(
deps = [
":component",
":mock_component",
"//score/launch_manager:error",
"//score/launch_manager/src/daemon/src/alive_monitor:mock_alive_supervision_handle",
"//score/launch_manager/src/daemon/src/alive_monitor:mock_supervision_factory",
"//score/launch_manager/src/daemon/src/process_group_manager/details/force_stop_action:mock_force_stop_action",
"//score/launch_manager/src/daemon/src/process_group_manager/details/ready_condition:mock_ready_condition",
"//score/launch_manager/src/daemon/src/process_group_manager/details/start_action:mock_start_action",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,73 @@
********************************************************************************/

#include "score/mw/launch_manager/process_group_manager/details/component.hpp"
#include "score/mw/launch_manager/common/log.hpp"

namespace score::mw::lifecycle::internal
{

namespace
{

using score::mw::lifecycle::internal::configuration::ApplicationType;

bool isSupervised(const ApplicationType& application_type) noexcept
{
switch (application_type)
{
case ApplicationType::Native:
case ApplicationType::Reporting:
return false;
case ApplicationType::ReportingAndSupervised:
case ApplicationType::StateManager:
return true;
}

SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("All possible cases are covered");
}

std::unique_ptr<IAliveSupervisionHandle> constructSupervision(
configuration::ComponentConfig& config,
ISupervisionFactory& supervision_factory)
{
if (!isSupervised(config.component_properties.application_profile.application_type))
{
return nullptr;
}

SCORE_LANGUAGE_FUTURECPP_ASSERT_DBG_MESSAGE(
app_profile.alive_supervision.has_value(), "Supervised component did not have alive supervision config");

LM_LOG_DEBUG() << "Setting up alive supervision for" << config.name;
std::unique_ptr<IAliveSupervisionHandle> handle = supervision_factory.constructSupervision(
IdentifierHash{config.name},
config.deployment_config.sandbox.uid,
config.component_properties.application_profile.alive_supervision.value());
if (!handle)
{
LM_LOG_ERROR() << "Failed to set up alive supervision for" << config.name;
Comment thread
danth marked this conversation as resolved.
return nullptr;
}

config.deployment_config.environmental_variables.add("LCM_ALIVE_INTERFACE_PATH", handle->getConnectionId());
return handle;
}

} // namespace

Component::Component(
const IStartAction& start_action,
const IStopAction& stop_action,
const IForceStopAction& force_stop_action,
const IReadyCondition& ready_condition,
bool self_terminating,
IdentifierHash identifier)
ISupervisionFactory& supervision_factory,
configuration::ComponentConfig& config)
: start_action_(start_action),
stop_action_(stop_action),
force_stop_action_(force_stop_action),
ready_condition_(ready_condition),
self_terminating_(self_terminating),
identifier_(identifier),
config_(config),
supervision_handle_(constructSupervision(config, supervision_factory)),
state_(TerminatedState{})
{
}
Expand All @@ -40,6 +90,13 @@ IComponent::RequestResult Component::activate(cpp::stop_token stop_token)
SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE(
std::holds_alternative<TerminatedState>(state_), "Cannot activate component in a running state");

if (isSupervised(config_.component_properties.application_profile.application_type) && !supervision_handle_)
{
LM_LOG_ERROR() << config_.name << ": alive supervision is not set up";
state_ = FaultState{};
return RequestResult::kFailure;
}

const Result<Handle> start_result = start_action_.start(stop_token);
if (!start_result.has_value())
{
Expand Down Expand Up @@ -75,8 +132,16 @@ IComponent::RequestResult Component::activate(cpp::stop_token stop_token)
// The state could change while the lock was released, so we have to check.
if (const StartingState* const starting = std::get_if<StartingState>(&state_))
{
state_ = ReadyState{starting->handle_};
return RequestResult::kSuccess;
if (activateSupervision())
{
state_ = ReadyState{starting->handle_};
return RequestResult::kSuccess;
}
else
{
state_ = FaultState{starting->handle_};
return RequestResult::kFailure;
}
}

SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("If stop was not requested, then state must still be StartingState");
Expand All @@ -92,6 +157,12 @@ IComponent::RequestResult Component::deactivate(cpp::stop_token stop_token)
(starting != nullptr) || (ready != nullptr), "Cannot deactivate component in a non-running state");
const Handle& handle = (starting != nullptr) ? starting->handle_ : ready->handle_;

if (!deactivateSupervision())
{
state_ = FaultState{handle};
return RequestResult::kFailure;
}

// If the component is still waiting for ready conditions, cancel that.
if (starting != nullptr)
{
Expand Down Expand Up @@ -131,14 +202,19 @@ IComponent::TerminationResult Component::tryHandleTermination(int32_t status)
// Invalidate the resource to prevent acting on something which is already gone.
invalidate(handle);

if (ready != nullptr && !deactivateSupervision())
{
state_ = FaultState{handle};
return TerminationResult::kFailure;
}

// Certain ready conditions can accept terminations.
if (starting != nullptr && ready_condition_.tryHandleTermination(handle, status))
{
return TerminationResult::kIgnore;
}

// Self-terminating components can accept terminations.
if (self_terminating_ && status == 0)
if (config_.component_properties.application_profile.is_self_terminating && status == 0)
{
return TerminationResult::kIgnore;
}
Expand All @@ -156,7 +232,7 @@ IComponent::TerminationResult Component::tryHandleTermination(int32_t status)

IdentifierHash Component::getIdentifier() const
{
return identifier_;
return IdentifierHash{config_.name};
}

bool Component::active() const
Expand All @@ -165,4 +241,52 @@ bool Component::active() const
return std::holds_alternative<ReadyState>(state_);
}

bool Component::activateSupervision() const
{
if (!supervision_handle_)
{
return true;
}

timespec timestamp{};

if (clock_gettime(CLOCK_MONOTONIC, &timestamp) != 0)
{
LM_LOG_ERROR() << config_.name << ": failed to get timestamp to activate supervision:" << strerror(errno);
return false;
}

if (!supervision_handle_->activateSupervision(timestamp))
{
LM_LOG_ERROR() << config_.name << ": failed to activate supervision";
return false;
}

return true;
}

bool Component::deactivateSupervision() const
{
if (!supervision_handle_)
{
return true;
}

timespec timestamp{};

if (clock_gettime(CLOCK_MONOTONIC, &timestamp) != 0)
{
LM_LOG_ERROR() << config_.name << ": failed to get timestamp to deactivate supervision: " << strerror(errno);
return false;
}

if (!supervision_handle_->deactivateSupervision(timestamp))
{
LM_LOG_ERROR() << config_.name << ": failed to deactivate supervision";
return false;
}

return true;
}

} // namespace score::mw::lifecycle::internal
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#ifndef SCORE_LCM_COMPONENT_HPP_INCLUDED
#define SCORE_LCM_COMPONENT_HPP_INCLUDED

#include "score/mw/launch_manager/alive_monitor/ialive_supervision_handle.hpp"
#include "score/mw/launch_manager/alive_monitor/isupervision_factory.hpp"
#include "score/mw/launch_manager/configuration/component_config.hpp"
#include "score/mw/launch_manager/process_group_manager/details/force_stop_action/iforce_stop_action.hpp"
#include "score/mw/launch_manager/process_group_manager/details/icomponent.hpp"
#include "score/mw/launch_manager/process_group_manager/details/ready_condition/iready_condition.hpp"
Expand All @@ -29,20 +32,20 @@ namespace score::mw::lifecycle::internal
class Component final : public IComponent
{
public:
/// @brief Creates a new component from the given actions.
/// @brief Creates a new component from its configuration and the given actions.
/// @param start_action How to start the resource.
/// @param stop_action How to gracefully stop the resource.
/// @param force_stop_action How to forcefully stop the resource.
/// @param ready_condition How to decide when the resource has finished its startup.
/// @param self_terminating Whether the resource is allowed to terminate on its own.
/// @param identifier Name of the component.
/// @param supervision_factory Factory used to construct alive supervision.
/// @param config Configuration of the component.
Component(
const IStartAction& start_action,
Comment thread
NicolasFussberger marked this conversation as resolved.
const IStopAction& stop_action,
const IForceStopAction& force_stop_action,
const IReadyCondition& ready_condition,
bool self_terminating = false,
IdentifierHash identifier = IdentifierHash{});
ISupervisionFactory& supervision_factory,
configuration::ComponentConfig& config);

/// @brief Start the resource and set the component to active.
/// @param stop_token Token which can be used to interrupt the activation.
Expand Down Expand Up @@ -80,11 +83,11 @@ class Component final : public IComponent
/// @brief How to decide when the resource has finished its startup.
const IReadyCondition& ready_condition_;

/// @brief Whether the resource is allowed to terminate on its own.
const bool self_terminating_;
/// @brief Configuration of the component.
const configuration::ComponentConfig& config_;

/// @brief Name of the component.
const IdentifierHash identifier_;
/// @brief Alive supervision of the resource, or nullptr if it is not supervised.
const std::unique_ptr<IAliveSupervisionHandle> supervision_handle_;

struct TerminatedState final
{
Expand Down Expand Up @@ -118,6 +121,12 @@ class Component final : public IComponent

/// @brief The current state of the component.
State state_;

/// @brief Start alive supervision now, if the component is supervised.
[[nodiscard]] bool activateSupervision() const;

/// @brief Stop alive supervision now, if the component is supervised.
[[nodiscard]] bool deactivateSupervision() const;
};

} // namespace score::mw::lifecycle::internal
Expand Down
Loading
Loading