mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 13:47:56 +00:00
sculpt: sanitize deployment, diagnostic feedback
This patch suppresses the start of components that cannot run because obvious runtime dependencies (used servers) are missing in the runtime. In this situation, the sculpt manager gives diagnostic feedback to the user in the runtime dialog.
This commit is contained in:
parent
bf1428be18
commit
a3999c93f4
@ -43,6 +43,16 @@ class Depot_deploy::Child : public List_model<Child>::Element
|
|||||||
Reconstructible<Buffered_xml> _start_xml; /* from config */
|
Reconstructible<Buffered_xml> _start_xml; /* from config */
|
||||||
Constructible<Buffered_xml> _pkg_xml { }; /* from blueprint */
|
Constructible<Buffered_xml> _pkg_xml { }; /* from blueprint */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* State of the condition check for generating the start node of
|
||||||
|
* the child. I.e., if the child is complete and configured but
|
||||||
|
* a used server component is missing, we need to suppress the start
|
||||||
|
* node until the condition is satisfied.
|
||||||
|
*/
|
||||||
|
enum Condition { UNCHECKED, SATISFIED, UNSATISFIED };
|
||||||
|
|
||||||
|
Condition _condition { UNCHECKED };
|
||||||
|
|
||||||
Name const _name;
|
Name const _name;
|
||||||
|
|
||||||
Archive::Path _config_pkg_path() const
|
Archive::Path _config_pkg_path() const
|
||||||
@ -158,6 +168,24 @@ class Depot_deploy::Child : public List_model<Child>::Element
|
|||||||
_pkg_xml.construct(_alloc, pkg);
|
_pkg_xml.construct(_alloc, pkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename COND_FN>
|
||||||
|
void apply_condition(COND_FN const &fn)
|
||||||
|
{
|
||||||
|
/* don't check the condition twice */
|
||||||
|
if (_condition == SATISFIED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_start_xml.constructed())
|
||||||
|
_condition = fn(_start_xml->xml()) ? SATISFIED : UNSATISFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FN>
|
||||||
|
void apply_if_unsatisfied(FN const &fn) const
|
||||||
|
{
|
||||||
|
if (_condition == UNSATISFIED && _start_xml.constructed())
|
||||||
|
fn(_start_xml->xml());
|
||||||
|
}
|
||||||
|
|
||||||
void mark_as_incomplete(Xml_node missing)
|
void mark_as_incomplete(Xml_node missing)
|
||||||
{
|
{
|
||||||
/* print error message only once */
|
/* print error message only once */
|
||||||
@ -225,7 +253,7 @@ class Depot_deploy::Child : public List_model<Child>::Element
|
|||||||
void Depot_deploy::Child::gen_start_node(Xml_generator &xml, Xml_node common,
|
void Depot_deploy::Child::gen_start_node(Xml_generator &xml, Xml_node common,
|
||||||
Depot_rom_server const &depot_rom) const
|
Depot_rom_server const &depot_rom) const
|
||||||
{
|
{
|
||||||
if (!_configured())
|
if (!_configured() || _condition == UNSATISFIED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_pkg_xml->xml().has_sub_node("runtime")) {
|
if (!_pkg_xml->xml().has_sub_node("runtime")) {
|
||||||
|
@ -78,6 +78,24 @@ class Depot_deploy::Children
|
|||||||
child.mark_as_incomplete(missing); }); });
|
child.mark_as_incomplete(missing); }); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename COND_FN>
|
||||||
|
void apply_condition(COND_FN const &fn)
|
||||||
|
{
|
||||||
|
_children.for_each([&] (Child &child) {
|
||||||
|
child.apply_condition(fn); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call 'fn' with start 'Xml_node' of each child that has an
|
||||||
|
* unsatisfied start condition.
|
||||||
|
*/
|
||||||
|
template <typename FN>
|
||||||
|
void for_each_unsatisfied_child(FN const &fn) const
|
||||||
|
{
|
||||||
|
_children.for_each([&] (Child const &child) {
|
||||||
|
child.apply_if_unsatisfied(fn); });
|
||||||
|
}
|
||||||
|
|
||||||
void reset_incomplete()
|
void reset_incomplete()
|
||||||
{
|
{
|
||||||
_children.for_each([&] (Child &child) {
|
_children.for_each([&] (Child &child) {
|
||||||
|
@ -15,6 +15,68 @@
|
|||||||
#include <deploy.h>
|
#include <deploy.h>
|
||||||
|
|
||||||
|
|
||||||
|
bool Sculpt::Deploy::update_child_conditions()
|
||||||
|
{
|
||||||
|
/* track whether any condition changed for the better */
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
_children.apply_condition([&] (Xml_node start) {
|
||||||
|
|
||||||
|
/* the child cannot be started as long as any dependency is missing */
|
||||||
|
bool condition = true;
|
||||||
|
_for_each_missing_server(start, [&] (Start_name const &) {
|
||||||
|
condition = false; });
|
||||||
|
|
||||||
|
result |= condition;
|
||||||
|
return condition;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Sculpt::Deploy::_gen_missing_dependencies(Xml_generator &xml,
|
||||||
|
Xml_node start, int &count) const
|
||||||
|
{
|
||||||
|
Start_name const child = start.attribute_value("name", Start_name());
|
||||||
|
_for_each_missing_server(start, [&] (Start_name const &server) {
|
||||||
|
gen_named_node(xml, "hbox", String<20>(count++), [&] () {
|
||||||
|
gen_named_node(xml, "float", "left", [&] () {
|
||||||
|
xml.attribute("west", "yes");
|
||||||
|
xml.node("label", [&] () {
|
||||||
|
xml.attribute("text", String<64>(child, " requires ", server));
|
||||||
|
xml.attribute("font", "annotation/regular");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Sculpt::Deploy::gen_child_diagnostics(Xml_generator &xml) const
|
||||||
|
{
|
||||||
|
bool all_children_ok = true;
|
||||||
|
_children.for_each_unsatisfied_child([&] (Xml_node) {
|
||||||
|
all_children_ok = false; });
|
||||||
|
|
||||||
|
if (all_children_ok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
gen_named_node(xml, "frame", "diagnostics", [&] () {
|
||||||
|
xml.node("vbox", [&] () {
|
||||||
|
|
||||||
|
xml.node("label", [&] () {
|
||||||
|
xml.attribute("text", "Diagnostics"); });
|
||||||
|
|
||||||
|
xml.node("float", [&] () {
|
||||||
|
xml.node("vbox", [&] () {
|
||||||
|
_children.for_each_unsatisfied_child([&] (Xml_node start) {
|
||||||
|
_gen_missing_dependencies(xml, start, count); }); }); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Sculpt::Deploy::handle_deploy()
|
void Sculpt::Deploy::handle_deploy()
|
||||||
{
|
{
|
||||||
Xml_node const manual_deploy = _manual_deploy_rom.xml();
|
Xml_node const manual_deploy = _manual_deploy_rom.xml();
|
||||||
@ -60,6 +122,10 @@ void Sculpt::Deploy::handle_deploy()
|
|||||||
xml.attribute("arch", _arch);
|
xml.attribute("arch", _arch);
|
||||||
_children.gen_installation_entries(xml); });
|
_children.gen_installation_entries(xml); });
|
||||||
|
|
||||||
|
/* apply runtime condition checks */
|
||||||
|
update_child_conditions();
|
||||||
|
|
||||||
|
_dialog_generator.generate_dialog();
|
||||||
_runtime_config_generator.generate_runtime_config();
|
_runtime_config_generator.generate_runtime_config();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <types.h>
|
#include <types.h>
|
||||||
#include <runtime.h>
|
#include <runtime.h>
|
||||||
#include <managed_config.h>
|
#include <managed_config.h>
|
||||||
|
#include <view/dialog.h>
|
||||||
|
|
||||||
namespace Sculpt { struct Deploy; }
|
namespace Sculpt { struct Deploy; }
|
||||||
|
|
||||||
@ -35,6 +36,10 @@ struct Sculpt::Deploy
|
|||||||
|
|
||||||
Allocator &_alloc;
|
Allocator &_alloc;
|
||||||
|
|
||||||
|
Runtime_info const &_runtime_info;
|
||||||
|
|
||||||
|
Dialog::Generator &_dialog_generator;
|
||||||
|
|
||||||
Runtime_config_generator &_runtime_config_generator;
|
Runtime_config_generator &_runtime_config_generator;
|
||||||
|
|
||||||
typedef String<16> Arch;
|
typedef String<16> Arch;
|
||||||
@ -85,6 +90,44 @@ struct Sculpt::Deploy
|
|||||||
handle_deploy();
|
handle_deploy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call 'fn' for each unsatisfied dependency of the child's 'start' node
|
||||||
|
*/
|
||||||
|
template <typename FN>
|
||||||
|
void _for_each_missing_server(Xml_node start, FN const &fn) const
|
||||||
|
{
|
||||||
|
start.for_each_sub_node("route", [&] (Xml_node route) {
|
||||||
|
route.for_each_sub_node("service", [&] (Xml_node service) {
|
||||||
|
service.for_each_sub_node("child", [&] (Xml_node child) {
|
||||||
|
Start_name const name = child.attribute_value("name", Start_name());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The dependency to the default-fs alias is always
|
||||||
|
* satisfied during the deploy phase. But it does not
|
||||||
|
* appear in the runtime-state report.
|
||||||
|
*/
|
||||||
|
if (name == "default_fs_rw")
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_runtime_info.present_in_runtime(name))
|
||||||
|
fn(name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-evaluate child dependencies
|
||||||
|
*
|
||||||
|
* \return true if any condition has changed and new children may have
|
||||||
|
* become able to start
|
||||||
|
*/
|
||||||
|
bool update_child_conditions();
|
||||||
|
|
||||||
|
void _gen_missing_dependencies(Xml_generator &, Xml_node, int &) const;
|
||||||
|
|
||||||
|
void gen_child_diagnostics(Xml_generator &xml) const;
|
||||||
|
|
||||||
void gen_runtime_start_nodes(Xml_generator &) const;
|
void gen_runtime_start_nodes(Xml_generator &) const;
|
||||||
|
|
||||||
Signal_handler<Deploy> _manual_deploy_handler {
|
Signal_handler<Deploy> _manual_deploy_handler {
|
||||||
@ -107,10 +150,12 @@ struct Sculpt::Deploy
|
|||||||
handle_deploy();
|
handle_deploy();
|
||||||
}
|
}
|
||||||
|
|
||||||
Deploy(Env &env, Allocator &alloc,
|
Deploy(Env &env, Allocator &alloc, Runtime_info const &runtime_info,
|
||||||
|
Dialog::Generator &dialog_generator,
|
||||||
Runtime_config_generator &runtime_config_generator)
|
Runtime_config_generator &runtime_config_generator)
|
||||||
:
|
:
|
||||||
_env(env), _alloc(alloc),
|
_env(env), _alloc(alloc), _runtime_info(runtime_info),
|
||||||
|
_dialog_generator(dialog_generator),
|
||||||
_runtime_config_generator(runtime_config_generator)
|
_runtime_config_generator(runtime_config_generator)
|
||||||
{
|
{
|
||||||
_manual_deploy_rom.sigh(_manual_deploy_handler);
|
_manual_deploy_rom.sigh(_manual_deploy_handler);
|
||||||
|
@ -158,7 +158,7 @@ struct Sculpt::Main : Input_event_handler,
|
|||||||
&& _network.ready()
|
&& _network.ready()
|
||||||
&& _deploy.update_needed(); };
|
&& _deploy.update_needed(); };
|
||||||
|
|
||||||
Deploy _deploy { _env, _heap, *this };
|
Deploy _deploy { _env, _heap, *this, *this, *this };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -214,6 +214,8 @@ struct Sculpt::Main : Input_event_handler,
|
|||||||
xml.attribute("font", "title/regular");
|
xml.attribute("font", "title/regular");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_deploy.gen_child_diagnostics(xml);
|
||||||
|
|
||||||
Xml_node const state = _update_state_rom.xml();
|
Xml_node const state = _update_state_rom.xml();
|
||||||
if (_update_running() && state.has_sub_node("archive"))
|
if (_update_running() && state.has_sub_node("archive"))
|
||||||
gen_download_status(xml, state);
|
gen_download_status(xml, state);
|
||||||
@ -618,6 +620,11 @@ void Sculpt::Main::_handle_runtime_state()
|
|||||||
*/
|
*/
|
||||||
_network.reattempt_nic_router_config();
|
_network.reattempt_nic_router_config();
|
||||||
|
|
||||||
|
if (_deploy.update_child_conditions()) {
|
||||||
|
reconfigure_runtime = true;
|
||||||
|
generate_dialog();
|
||||||
|
}
|
||||||
|
|
||||||
if (reconfigure_runtime)
|
if (reconfigure_runtime)
|
||||||
generate_runtime_config();
|
generate_runtime_config();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user