/* * \brief Sculpt deploy management * \author Norman Feske * \date 2018-04-30 */ /* * Copyright (C) 2018 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. */ #ifndef _DEPLOY_H_ #define _DEPLOY_H_ /* Genode includes */ #include #include /* included from depot_deploy tool */ #include /* local includes */ #include #include #include #include #include #include #include namespace Sculpt { struct Deploy; } struct Sculpt::Deploy { Env &_env; Allocator &_alloc; Registry &_child_states; Runtime_info const &_runtime_info; Dialog::Generator &_dialog_generator; Runtime_config_generator &_runtime_config_generator; Depot_query &_depot_query; Attached_rom_dataspace const &_launcher_listing_rom; Attached_rom_dataspace const &_blueprint_rom; Download_queue const &_download_queue; typedef String<16> Arch; Arch _arch { }; Child_state cached_depot_rom_state { _child_states, "depot_rom", Ram_quota{24*1024*1024}, Cap_quota{200} }; Child_state uncached_depot_rom_state { _child_states, "dynamic_depot_rom", Ram_quota{8*1024*1024}, Cap_quota{200} }; /* * Report written to '/config/managed/deploy' * * This report takes the manually maintained '/config/deploy' and the * interactive state as input. */ Expanding_reporter _managed_deploy_config { _env, "config", "deploy_config" }; /* config obtained from '/config/managed/deploy' */ Attached_rom_dataspace _managed_deploy_rom { _env, "config -> managed/deploy" }; void update_managed_deploy_config(Xml_node deploy) { /* * Ignore intermediate states that may occur when manually updating * the config/deploy configuration. Depending on the tool used, * the original file may be unlinked before the new version is * created. The temporary empty configuration must not be applied. */ if (deploy.type() == "empty") return; _managed_deploy_config.generate([&] (Xml_generator &xml) { Arch const arch = deploy.attribute_value("arch", Arch()); if (arch.valid()) xml.attribute("arch", arch); auto append_xml_node = [&] (Xml_node node) { xml.append("\t"); node.with_raw_node([&] (char const *start, size_t length) { xml.append(start, length); }); xml.append("\n"); }; /* copy from manual deploy config */ deploy.for_each_sub_node("common_routes", [&] (Xml_node node) { append_xml_node(node); }); /* * Copy the node from manual deploy config, unless the * component was interactively killed by the user. */ deploy.for_each_sub_node("start", [&] (Xml_node node) { Start_name const name = node.attribute_value("name", Start_name()); if (!_runtime_info.abandoned_by_user(name)) append_xml_node(node); }); /* * Add start nodes for interactively launched components. */ _runtime_info.gen_launched_deploy_start_nodes(xml); }); } bool _manual_installation_scheduled = false; Managed_config _installation { _env, "installation", "installation", *this, &Deploy::_handle_installation }; void _handle_installation(Xml_node manual_config) { _manual_installation_scheduled = manual_config.has_sub_node("archive"); handle_deploy(); } Depot_deploy::Children _children { _alloc }; bool update_needed() const { return _manual_installation_scheduled || _children.any_incomplete() || _download_queue.any_active_download(); } void handle_deploy(); void _handle_managed_deploy() { _managed_deploy_rom.update(); handle_deploy(); _depot_query.trigger_depot_query(); } /** * Call 'fn' for each unsatisfied dependency of the child's 'start' node */ template 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(); bool any_unsatisfied_child() const { bool all_satisfied = true; _children.for_each_unsatisfied_child([&] (Xml_node, Xml_node, Start_name const &) { all_satisfied = false; }); return !all_satisfied; } void gen_child_diagnostics(Xml_generator &xml) const; void gen_runtime_start_nodes(Xml_generator &) const; Signal_handler _managed_deploy_handler { _env.ep(), *this, &Deploy::_handle_managed_deploy }; void restart() { /* ignore stale query results */ _depot_query.trigger_depot_query(); _children.apply_config(Xml_node("")); } void reattempt_after_installation() { _children.reset_incomplete(); handle_deploy(); } void gen_depot_query(Xml_generator &xml) const { _children.gen_queries(xml); } void update_installation() { /* feed missing packages to installation queue */ if (_installation.try_generate_manually_managed()) return; _installation.generate([&] (Xml_generator &xml) { xml.attribute("arch", _arch); _children.gen_installation_entries(xml); _download_queue.gen_installation_entries(xml); }); } Deploy(Env &env, Allocator &alloc, Registry &child_states, Runtime_info const &runtime_info, Dialog::Generator &dialog_generator, Runtime_config_generator &runtime_config_generator, Depot_query &depot_query, Attached_rom_dataspace const &launcher_listing_rom, Attached_rom_dataspace const &blueprint_rom, Download_queue const &download_queue) : _env(env), _alloc(alloc), _child_states(child_states), _runtime_info(runtime_info), _dialog_generator(dialog_generator), _runtime_config_generator(runtime_config_generator), _depot_query(depot_query), _launcher_listing_rom(launcher_listing_rom), _blueprint_rom(blueprint_rom), _download_queue(download_queue) { _managed_deploy_rom.sigh(_managed_deploy_handler); } }; #endif /* _DEPLOY_H_ */