genode/repos/gems/src/app/depot_autopilot/main.cc

250 lines
7.9 KiB
C++

/*
* \brief Tool for turning a subsystem blueprint into an init configuration
* \author Norman Feske
* \date 2017-07-07
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <util/retry.h>
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <base/heap.h>
#include <os/reporter.h>
#include <root/component.h>
/* local includes */
#include "children.h"
namespace Depot_deploy {
class Log_session_component;
class Log_root;
struct Main;
}
class Depot_deploy::Log_session_component : public Rpc_object<Log_session>
{
private:
Session_label const _child_label;
Child &_child;
public:
Log_session_component(Session_label const &child_label,
Child &child)
:
_child_label(child_label),
_child(child)
{ }
size_t write(String const &line) override
{
if (_child.finished()) {
return 0; }
Log_event::Line line_labeled{ "[", _child_label.string(), "] ", line.string() };
_child.log_session_write(line_labeled);
return strlen(line.string());
}
};
class Depot_deploy::Log_root : public Root_component<Log_session_component>
{
public:
Children &_children;
Session_label const &_children_label_prefix;
Log_root(Entrypoint &ep,
Allocator &md_alloc,
Children &children,
Session_label const &children_label_prefix)
:
Root_component { ep, md_alloc },
_children { children },
_children_label_prefix { children_label_prefix }
{ }
Log_session_component *_create_session(const char *args, Affinity const &) override
{
using Name_delimiter = String<5>;
Session_label const label { label_from_args(args) };
size_t const label_prefix_len { strlen(_children_label_prefix.string()) };
Session_label const label_prefix { Cstring(label.string(), label_prefix_len) };
if (label_prefix != _children_label_prefix) {
warning("LOG session label does not have children label-prefix");
throw Service_denied();
}
char const *const name_base { label.string() + label_prefix_len };
Name_delimiter const name_delim { " -> " };
size_t name_len { 0 };
for (char const *str = name_base; str[name_len] &&
name_delim != Name_delimiter(str + name_len); name_len++);
Child::Name name { Cstring(name_base, name_len) };
char const *const label_base { name_base + name_len };
try {
return new (md_alloc())
Log_session_component(Session_label("init", label_base),
_children.find_by_name(name));
}
catch (Children::No_match) {
warning("Cannot find child by LOG session label");
throw Service_denied();
}
}
};
struct Depot_deploy::Main
{
struct Repeatable
{
Env &_env;
Heap &_heap;
Signal_transmitter _repeat_handler;
Attached_rom_dataspace _config { _env, "config" };
Attached_rom_dataspace _blueprint { _env, "blueprint" };
Expanding_reporter _query_reporter { _env, "query" , "query"};
Expanding_reporter _init_config_reporter { _env, "config", "init.config"};
Reconstructible<Session_label> _children_label_prefix { };
Timer::Connection _timer { _env };
Signal_handler<Repeatable> _config_handler { _env.ep(), *this, &Repeatable::_handle_config };
Children _children { _heap, _timer, _config_handler };
void _handle_config()
{
_config.update();
_blueprint.update();
Xml_node const config = _config.xml();
_children_label_prefix.construct(config.attribute_value("children_label_prefix", String<160>()));
_children.apply_config(config);
_children.apply_blueprint(_blueprint.xml());
/* determine CPU architecture of deployment */
typedef String<16> Arch;
Arch const arch = config.attribute_value("arch", Arch());
if (!arch.valid())
warning("config lacks 'arch' attribute");
/* generate init config containing all configured start nodes */
bool finished;
_init_config_reporter.generate([&] (Xml_generator &xml) {
Xml_node static_config = config.sub_node("static");
static_config.with_raw_content([&] (char const *start, size_t length) {
xml.append(start, length); });
Child::Depot_rom_server const parent { };
finished = _children.gen_start_nodes(xml, config.sub_node("common_routes"),
parent, parent);
});
if (finished) {
Result result;
Genode::uint64_t previous_time_sec { 0 };
if (config.has_sub_node("previous-results")) {
Xml_node const previous_results = config.sub_node("previous-results");
previous_time_sec += previous_results.attribute_value("time_sec", (Genode::uint64_t)0);
result.succeeded += previous_results.attribute_value("succeeded", 0UL);
result.failed += previous_results.attribute_value("failed", 0UL);
result.skipped += previous_results.attribute_value("skipped", 0UL);
}
Genode::uint64_t const time_us { _timer.curr_time().trunc_to_plain_us().value };
Genode::uint64_t time_ms { time_us / 1000 };
Genode::uint64_t const time_sec { time_ms / 1000 };
time_ms = time_ms - time_sec * 1000;
_children.conclusion(result);
int exit_code = result.failed ? -1 : 0;
typedef String<12> Repeat;
Repeat repeat = config.attribute_value("repeat", Repeat("false"));
if (repeat == Repeat("until_forever") ||
(repeat == Repeat("until_failed") && exit_code == 0)) {
char const *empty_config_str = "<config/>";
Xml_node const empty_config(empty_config_str, 10);
_children.apply_config(empty_config);
_query_reporter.generate([&] (Xml_generator &xml) { xml.attribute("arch", arch); });
_init_config_reporter.generate([&] (Xml_generator &) { });
_repeat_handler.submit();
return;
} else {
log("\n--- Finished after ", time_sec + previous_time_sec, ".", time_ms < 10 ? "00" : time_ms < 100 ? "0" : "", time_ms, " sec ---\n");
if (config.has_sub_node("previous-results")) {
Xml_node const previous_results = config.sub_node("previous-results");
previous_results.with_raw_content([&] (char const *start, size_t length) {
if (length)
log(Cstring(start, length)); });
}
_children.print_conclusion();
log("");
log(result);
log("");
_env.parent().exit(exit_code);
}
}
/* update query for blueprints of all unconfigured start nodes */
if (arch.valid()) {
_query_reporter.generate([&] (Xml_generator &xml) {
xml.attribute("arch", arch);
_children.gen_queries(xml);
});
}
}
Repeatable(Env &env,
Signal_context_capability const &repeat_handler,
Heap &heap)
:
_env(env),
_heap(heap),
_repeat_handler(repeat_handler)
{
_config .sigh(_config_handler);
_blueprint.sigh(_config_handler);
_handle_config();
}
};
Env &_env;
Signal_handler<Main> _repeat_handler { _env.ep(), *this, &Main::_handle_repeat };
Heap _heap { _env.ram(), _env.rm() };
Reconstructible<Repeatable> _repeatable { _env, _repeat_handler, _heap };
Log_root _log_root { _env.ep(), _heap, _repeatable->_children, *_repeatable->_children_label_prefix };
void _handle_repeat()
{
_repeatable.construct(_env, _repeat_handler, _heap);
}
Main(Env &env) : _env(env)
{
_env.parent().announce(_env.ep().manage(_log_root));
}
};
void Component::construct(Genode::Env &env) { static Depot_deploy::Main main(env); }