Skip to content

Launch Manager loads the new configuration file#248

Open
paulquiring wants to merge 10 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 10 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.6.0) and connecting to it...
INFO: Invocation ID: 0dbf930a-e926-44a6-a6f4-41e237c11e88
Computing main repo mapping: 
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 (29 packages loaded, 10 targets configured)

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

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

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

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

Analyzing: target //:license-check (146 packages loaded, 3490 targets configured)

Analyzing: target //:license-check (147 packages loaded, 4203 targets configured)

Analyzing: target //:license-check (147 packages loaded, 8066 targets configured)

Analyzing: target //:license-check (151 packages loaded, 8093 targets configured)

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

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

Analyzing: target //:license-check (161 packages loaded, 10033 targets configured)

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

INFO: Analyzed target //:license-check (163 packages loaded, 10283 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.256s, Critical Path: 2.56s
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
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