Skip to content

Launch Manager loads the new configuration file#248

Open
paulquiring wants to merge 9 commits into
eclipse-score:mainfrom
etas-contrib:feature/lm-use-new-configuration
Open

Launch Manager loads the new configuration file#248
paulquiring wants to merge 9 commits into
eclipse-score:mainfrom
etas-contrib:feature/lm-use-new-configuration

Conversation

@paulquiring

@paulquiring paulquiring commented Jun 15, 2026

Copy link
Copy Markdown
Contributor
  • Map user-facing json config to the new flatbuffer config
  • Load new launch manager config
  • Introduce adapters to make the rest of the code work with the new configuration content
  • Remove the legacy configuration files

Closes: #209

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

License Check Results

🚀 The license check job ran with the Bazel command:

bazel run --lockfile_mode=error //:license-check

Status: ⚠️ Needs Review

Click to expand output
[License Check Output]
Extracting Bazel installation...
Starting local Bazel server (8.4.2) and connecting to it...
INFO: Invocation ID: 87349e67-6baf-4dc4-8451-12ef92285d38
Computing main repo mapping: 
Computing main repo mapping: 
Loading: 
Loading: 0 packages loaded
Loading: 0 packages loaded
Loading: 0 packages loaded
    currently loading: 
Loading: 0 packages loaded
    currently loading: 
Loading: 0 packages loaded
    currently loading: 
Analyzing: target //:license-check (1 packages loaded, 0 targets configured)
Analyzing: target //:license-check (1 packages loaded, 0 targets configured)

Analyzing: target //:license-check (30 packages loaded, 10 targets configured)

Analyzing: target //:license-check (82 packages loaded, 10 targets configured)

Analyzing: target //:license-check (86 packages loaded, 10 targets configured)

Analyzing: target //:license-check (138 packages loaded, 2721 targets configured)

Analyzing: target //:license-check (150 packages loaded, 5404 targets configured)

Analyzing: target //:license-check (155 packages loaded, 5453 targets configured)

Analyzing: target //:license-check (155 packages loaded, 5453 targets configured)

Analyzing: target //:license-check (155 packages loaded, 5453 targets configured)

Analyzing: target //:license-check (158 packages loaded, 7340 targets configured)

Analyzing: target //:license-check (160 packages loaded, 9062 targets configured)

Analyzing: target //:license-check (162 packages loaded, 10142 targets configured)

Analyzing: target //:license-check (162 packages loaded, 10142 targets configured)

Analyzing: target //:license-check (162 packages loaded, 10142 targets configured)

Analyzing: target //:license-check (162 packages loaded, 10142 targets configured)

Analyzing: target //:license-check (162 packages loaded, 10142 targets configured)

INFO: Analyzed target //:license-check (163 packages loaded, 10268 targets configured).
[13 / 16] JavaToolchainCompileClasses external/rules_java+/toolchains/platformclasspath_classes; 0s disk-cache, processwrapper-sandbox
[14 / 16] JavaToolchainCompileBootClasspath external/rules_java+/toolchains/platformclasspath.jar; 0s disk-cache, processwrapper-sandbox
INFO: Found 1 target...
Target //:license.check.license_check up-to-date:
  bazel-bin/license.check.license_check
  bazel-bin/license.check.license_check.jar
INFO: Elapsed time: 31.286s, Critical Path: 2.50s
INFO: 16 processes: 12 internal, 3 processwrapper-sandbox, 1 worker.
INFO: Build completed successfully, 16 total actions
INFO: Running command line: bazel-bin/license.check.license_check ./formatted.txt <args omitted>
usage: org.eclipse.dash.licenses.cli.Main [-batch <int>] [-cd <url>]
       [-confidence <int>] [-ef <url>] [-excludeSources <sources>] [-help] [-lic
       <url>] [-project <shortname>] [-repo <url>] [-review] [-summary <file>]
       [-timeout <seconds>] [-token <token>]

Comment thread scripts/config_mapping/lifecycle_config.py
@paulquiring paulquiring marked this pull request as ready for review June 16, 2026 08:02
Comment thread score/launch_manager/daemon/src/configuration/configuration_adapter.cpp Outdated
Comment thread score/launch_manager/daemon/src/configuration/configuration_adapter.hpp Outdated
Comment thread score/launch_manager/daemon/src/main.cpp Outdated
@S-MOHAMD

Copy link
Copy Markdown
Contributor

Please lnk corresponding issue/bug.
see: https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue

@paulquiring paulquiring force-pushed the feature/lm-use-new-configuration branch from f13cffe to eb807a1 Compare June 18, 2026 08:28
@github-actions

Copy link
Copy Markdown

The created documentation from the pull request is available at: docu-html

@NicolasFussberger NicolasFussberger moved this from Backlog to In Progress in LCM - Lifecycle & Health FT Jun 18, 2026
<< std::string_view{f_exception_r.what()};
const auto* comp = supervised_components_[idx];
const std::string checkpointCfgName = comp->name + "_checkpoint";
const uint32_t checkpointId = 1U;

@NicolasFussberger NicolasFussberger Jun 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is worth it, but the checkpointId has to match this

static constexpr std::uint32_t kDefaultCheckpointId{1U};

I wonder if we should make this a static constant in score/launch_manager/src/daemon/src/alive_monitor/details/factory/StaticConfig.hpp which is then used in both places.

The background is, when this code was still supporting Deadline and Logical supervisions, then different kinds of checkpoints were required.
But now only Alive supervision support is left, which only needs sending "Alive notificiations" - for which he just use checkpointId 1.

@paulquiring paulquiring Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would need to reorganize the code a bit
Looking at:

score/launch_manager/src/daemon/src/alive_monitor/details/factory/StaticConfig.hpp
score/launch_manager/src/alive/src/alive.cpp

we might want to move StaticConfig.hpp into score/launch_manager/src/common or a similar location. We might want to create a ticket out if this comment to work in it later?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ticket for removal of this id already exists #251

void logConfiguration() noexcept(true);

/// @brief Configured watchdog devices
/// By default, no watchdog device is configured

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should bring back some of this doxygen, thats seems rather useful

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread score/launch_manager/daemon/src/configuration/configuration_adapter.cpp Outdated
Comment thread score/launch_manager/daemon/src/configuration/configuration_adapter.hpp Outdated
Comment thread score/launch_manager/daemon/src/configuration/configuration_adapter.cpp Outdated
Comment thread score/launch_manager/daemon/src/main.cpp Outdated
Comment thread score/launch_manager/daemon/src/configuration/configuration_adapter.cpp Outdated
Comment thread score/launch_manager/daemon/src/configuration/configuration_adapter.cpp Outdated
Comment thread score/launch_manager/daemon/src/alive_monitor/details/factory/FlatCfgFactory.cpp Outdated
// strdup() returns nullptr on OOM. On this embedded target, OOM during daemon
// startup is unrecoverable — the OS will terminate the process.
size_t arg_index = 0U;
startup.argv_[arg_index++] = strdup(startup.executable_path_.c_str());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use comp.deployment_config.executable_path.c_str(), but this would create a mixed ownership between the configuration object in main and the adapter. The Adapter copies the configuration so that it owns it. Yes this costs a bit of resources but is the simplest and clearest way currently to bridge the old to new configuration.

const auto& wd = *wd_opt;
watchdog::DeviceConfig wdConfig{};
wdConfig.fileName = wd.device_file_path;
assert(wd.max_timeout_ms <= std::numeric_limits<std::uint16_t>::max());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this a validation in score/launch_manager/src/daemon/src/configuration/details/flatbuffer_type_converters.cpp ?

}
dep.target_process_id_ = IdentifierHash{dep_name};
os_process.dependencies_.push_back(dep);
}

@NicolasFussberger NicolasFussberger Jun 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here is a bug. We need to lookup the ReadyCondition process_state for the referenced component.

Image

I think it would be good to extend the UTs with these different state combinations to catch this

for (const auto& comp_name : fallback.depends_on) {
auto it = component_to_process_index.find(comp_name);
if (it != component_to_process_index.end()) {
fallback_state.process_indexes_.push_back(it->second);

@NicolasFussberger NicolasFussberger Jun 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here we also need to resolve the dependencies recursively.

E.g. fallback_run_target depends_on [CompA]
and CompA depends_on [CompB] then

fallback_run_target = [CompA, CompB]

I think it would be good to extend the UT with this case

true)
{
return score::lcm::IdentifierHash{f_processPath_r}.data();
std::optional<common::ProcessId> FlatCfgFactory::getProcessId(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::optional no longer required, hashing cannot fail

pg.off_state_ = IdentifierHash{"MainPG/Off"};

IdentifierHash recovery_state{"Recovery"};
for (const auto& rt : config.runTargets()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be changed to just
IdentifierHash recovery_state = IdentifierHash{std::string("MainPG/") + "fallback_run_target"};

without the for loop

component_by_name[comp.name] = &comp;
}

std::map<std::string, uint32_t> component_to_process_index;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need a separate map just for the index or can we get the index from component_by_name?

size_t arg_index = 0U;
startup.argv_[arg_index++] = strdup(startup.executable_path_.c_str());
size_t max_args = std::min(props.process_arguments.size(),
static_cast<size_t>(score::lcm::internal::kMaxArg));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we assert that we have enough space for all configured process_arguments and env variables?
kMaxArg with 20 is rather small, can we bump this to 100?

bool is_sup = (props.application_profile.application_type == ApplicationType::ReportingAndSupervised ||
props.application_profile.application_type == ApplicationType::StateManager);
if (is_sup && env_index < static_cast<size_t>(score::lcm::internal::kMaxEnv)) {
std::string iface_path = "LCM_ALIVE_INTERFACE_PATH=" + score::lcm::internal::aliveInterfacePath(comp.name);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could also add a constant for the env name

? score::lcm::ProcessState::kRunning
: score::lcm::ProcessState::kTerminated;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is a possible error case. In case the configured dependency does not actually exist

pgm.number_of_restart_attempts = deploy.ready_recovery_action->number_of_attempts;
}

for (const auto& dep_name : props.depends_on) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

depends_on might also contain a run_target and not only a component.
Special Case: This may be also the fallback_run_target

}
}
auto rt_it = run_target_by_name.find(dep_name);
if (rt_it != run_target_by_name.end()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think depends_on might also refer to fallback_run_target which is currently not in the run_target_by_name map

run_target_by_name[rt.name] = &rt;
}

std::map<std::string, const ComponentConfig*> component_by_name;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

component_by_name exists twice in this class

std::set<std::string>& visited) {
if (!visited.insert(dep_name).second) return;
auto comp_it = component_to_process_index.find(dep_name);
if (comp_it != component_to_process_index.end()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be some possible error cases when component/runTarget names are not found because they have not been configured

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we keep the current validation in the python script and just put asserts in the code for these error cases

component_by_name[comp.name] = &comp;
}

std::function<void(const std::string&, std::vector<uint32_t>&, std::set<std::string>&)> resolve_depends;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it could make sense to have a dedicated Visitor class for this

}

void ConfigurationAdapter::resolveDependencyIndexes(std::vector<OsProcess>& processes) {
for (auto& proc : processes) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed?

component_by_name[comp.name] = &comp;
}

std::map<std::string, uint32_t> component_to_process_index;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we build these maps once during initialize and store them as private member?

if (pg) {
if (index < pg->processes_.size()) {
return pg;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does not make sense to validate the index here


static const uint32_t kDefaultProcessExecutionError;
static uint32_t kDefaultProcessorAffinityMask();
static const int32_t kDefaultSchedulingPolicy;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These defaults seem obsolete now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate Launch Manager from the reading the old configuration file format to the new format

4 participants