static result_type convert(const dynamic_t& from) { result_type component; const auto& logging = from.as_object(); for(auto it = logging.begin(); it != logging.end(); ++it) { using namespace blackhole::repository; auto object = it->second.as_object(); auto loggers = object.at("loggers", dynamic_t::empty_array); config_t::logging_t::logger_t log { logmask(object.at("verbosity", defaults::log_verbosity).as_string()), object.at("timestamp", defaults::log_timestamp).as_string(), config::parser_t<dynamic_t, blackhole::log_config_t>::parse(it->first, loggers) }; component.loggers[it->first] = log; } return component; }
node_t::node_t(context_t& context, asio::io_service& asio, const std::string& name, const dynamic_t& args): category_type(context, asio, name, args), dispatch<io::node_tag>(name), context(context), log(context.log(name)) { on<io::node::start_app>(std::bind(&node_t::start_app, this, ph::_1, ph::_2)); on<io::node::pause_app>(std::bind(&node_t::pause_app, this, ph::_1)); on<io::node::list> (std::bind(&node_t::list, this)); on<io::node::info> (std::bind(&node_t::info, this, ph::_1, ph::_2)); // Context signal/slot. signal = std::make_shared<dispatch<io::context_tag>>(name); signal->on<io::context::shutdown>(std::bind(&node_t::on_context_shutdown, this)); const auto runname = args.as_object().at("runlist", "").as_string(); if(runname.empty()) { context.listen(signal, asio); return; } COCAINE_LOG_INFO(log, "reading '%s' runlist", runname); typedef std::map<std::string, std::string> runlist_t; runlist_t runlist; const auto storage = api::storage(context, "core"); try { // TODO: Perform request to a special service, like "storage->runlist(runname)". runlist = storage->get<runlist_t>("runlists", runname); } catch(const std::system_error& err) { COCAINE_LOG_WARNING(log, "unable to read '%s' runlist: %s", runname, err.what()); } if(runlist.empty()) { context.listen(signal, asio); return; } COCAINE_LOG_INFO(log, "starting %d app(s)", runlist.size()); std::vector<std::string> errored; for(auto it = runlist.begin(); it != runlist.end(); ++it) { blackhole::scoped_attributes_t scope(*log, {{ "app", it->first }}); try { start_app(it->first, it->second); } catch(const std::exception& e) { COCAINE_LOG_WARNING(log, "unable to initialize app: %s", e.what()); errored.push_back(it->first); } } if(!errored.empty()) { std::ostringstream stream; std::ostream_iterator<char> builder(stream); boost::spirit::karma::generate(builder, boost::spirit::karma::string % ", ", errored); COCAINE_LOG_WARNING(log, "couldn't start %d app(s): %s", errored.size(), stream.str()); } context.listen(signal, asio); }
node_t::node_t(context_t& context, boost::asio::io_service& asio, const std::string& name, const dynamic_t& args): category_type(context, asio, name, args), dispatch<node_tag>(name), m_context(context), m_log(context.log(name)) { using namespace std::placeholders; on<node::start_app>(std::bind(&node_t::on_start_app, this, _1, _2)); on<node::pause_app>(std::bind(&node_t::on_pause_app, this, _1)); on<node::list>(std::bind(&node_t::on_list, this)); const auto runlist_id = args.as_object().at("runlist", "default").as_string(); const auto storage = api::storage(m_context, "core"); typedef std::map<std::string, std::string> runlist_t; runlist_t runlist; { blackhole::scoped_attributes_t attributes(*m_log, { blackhole::attribute::make("runlist", runlist_id) }); COCAINE_LOG_INFO(m_log, "reading runlist"); try { runlist = storage->get<runlist_t>("runlists", runlist_id); } catch(const storage_error_t& e) { COCAINE_LOG_WARNING(m_log, "unable to read runlist: %s", e.what()); } } if(runlist.empty()) { return; } COCAINE_LOG_INFO(m_log, "starting %d app(s)", runlist.size()); std::vector<std::string> errored; for(auto it = runlist.begin(); it != runlist.end(); ++it) { blackhole::scoped_attributes_t attributes(*m_log, { blackhole::attribute::make("app", it->first) }); try { on_start_app(it->first, it->second); } catch(const std::exception& e) { COCAINE_LOG_ERROR(m_log, "unable to initialize app: %s", e.what()); errored.push_back(it->first); } catch(...) { COCAINE_LOG_ERROR(m_log, "unable to initialize app"); errored.push_back(it->first); } } if(!errored.empty()) { std::ostringstream stream; std::ostream_iterator<char> builder(stream); boost::spirit::karma::generate(builder, boost::spirit::karma::stream % ", ", errored); COCAINE_LOG_ERROR(m_log, "couldn't start %d app(s): %s", errored.size(), stream.str()); } }
mongo_storage_t::mongo_storage_t(context_t& context, const std::string& name, const dynamic_t& args): category_type(context, name, args), m_log(context.log(name)), m_client(connect(args.as_object().at("uri", "<unspecified>").to<std::string>())) { }
control_service_t::control_service_t(context_t& context, io::reactor_t& reactor, const std::string& name, const dynamic_t& args): api::service_t(context, reactor, name, args), dispatch<io::raft_control_tag<msgpack::object, msgpack::object>>(name), m_context(context), m_log(context.log(name)) { using namespace std::placeholders; typedef io::raft_control<msgpack::object, msgpack::object> protocol; on<protocol::insert>(std::bind(&control_service_t::insert, this, _1, _2)); on<protocol::erase>(std::bind(&control_service_t::erase, this, _1, _2)); on<protocol::lock>(std::bind(&control_service_t::lock, this, _1)); on<protocol::reset>(std::bind(&control_service_t::reset, this, _1, _2)); on<protocol::dump>(std::bind(&control_service_t::dump, this)); on<protocol::status>(std::bind(&control_service_t::status, this, _1)); on<protocol::leader>(std::bind(&control_service_t::leader, this, _1)); options_t options; // The format of the name is "service/<name of service from the config>". // So here we drop "service/" part to determine the raft control service name. // TODO: Make the context to pass the names to services without "service/" part. options.control_service_name = name.substr(8, std::string::npos); options.node_service_name = "raft_node"; options.configuration_machine_name = "configuration"; options.some_nodes = args.as_object().at("some_nodes", dynamic_t::empty_array).to<std::set<node_id_t>>(); options.election_timeout = args.as_object().at("election_timeout", 500).to<unsigned int>(); options.heartbeat_timeout = args.as_object().at("heartbeat_timeout", options.election_timeout / 2).to<unsigned int>(); options.snapshot_threshold = args.as_object().at("snapshot_threshold", 100000).to<unsigned int>(); options.message_size = args.as_object().at("message_size", 1000).to<unsigned int>(); m_context.raft().set_options(options); m_context.raft().activate(); if(m_context.config.create_raft_cluster) { typedef log_entry<configuration_machine_t> entry_type; typedef configuration<configuration_machine_t> config_type; typedef log_traits<configuration_machine_t, config_type::cluster_type>::snapshot_type snapshot_type; config_type config(m_context, m_context.raft().options().configuration_machine_name, cluster_config_t {std::set<node_id_t>(), boost::none}); configuration_machine_t config_machine(m_context, *m_context.raft().m_reactor, *this); config.log().push(entry_type()); config.log().push(entry_type()); std::map<std::string, lockable_config_t> config_snapshot; config_snapshot[m_context.raft().options().configuration_machine_name] = lockable_config_t { false, cluster_config_t { std::set<node_id_t>({m_context.raft().id()}), boost::none } }; config_machine.consume(config_snapshot); config.log().set_snapshot(1, 1, snapshot_type(std::move(config_snapshot), config.cluster())); config.set_current_term(std::max<uint64_t>(1, config.current_term())); config.set_commit_index(1); config.set_last_applied(1); m_config_actor = m_context.raft().create_cluster( m_context.raft().options().configuration_machine_name, std::move(config_machine), std::move(config) ); } else { m_config_actor = m_context.raft().insert( m_context.raft().options().configuration_machine_name, configuration_machine_t(m_context, *m_context.raft().m_reactor, *this) ); } // Run Raft node service. auto node_service_reactor = std::make_shared<io::reactor_t>(); std::unique_ptr<api::service_t> node_service(std::make_unique<node_service_t>( m_context, *m_context.raft().m_reactor, std::string("service/") + m_context.raft().options().node_service_name )); std::unique_ptr<actor_t> node_service_actor( new actor_t(m_context, m_context.raft().m_reactor, std::move(node_service)) ); m_context.insert(m_context.raft().options().node_service_name, std::move(node_service_actor)); }
static result_type convert(const dynamic_t& source) { return ip::address::from_string(source.as_string()); }
config_t::config_t(const std::string& config_path) { path.config = config_path; const auto config_file_status = fs::status(path.config); if(!fs::exists(config_file_status) || !fs::is_regular_file(config_file_status)) { throw cocaine::error_t("the configuration file path is invalid"); } fs::ifstream stream(path.config); if(!stream) { throw cocaine::error_t("unable to read the configuration file"); } rapidjson::MemoryPoolAllocator<> json_allocator; rapidjson::Reader json_reader(&json_allocator); rapidjson_ifstream_t config_stream(&stream); dynamic_reader_t config_constructor; if(!json_reader.Parse<rapidjson::kParseDefaultFlags>(config_stream, config_constructor)) { if(json_reader.HasParseError()) { throw cocaine::error_t("the configuration file is corrupted - %s", json_reader.GetParseError()); } else { throw cocaine::error_t("the configuration file is corrupted"); } } const dynamic_t root(config_constructor.Result()); const auto &path_config = root.as_object().at("paths", dynamic_t::empty_object).as_object(); const auto &locator_config = root.as_object().at("locator", dynamic_t::empty_object).as_object(); const auto &network_config = root.as_object().at("network", dynamic_t::empty_object).as_object(); // Validation if(root.as_object().at("version", 0).to<unsigned int>() != 2) { throw cocaine::error_t("the configuration file version is invalid"); } // Paths path.plugins = path_config.at("plugins", defaults::plugins_path).as_string(); path.runtime = path_config.at("runtime", defaults::runtime_path).as_string(); const auto runtime_path_status = fs::status(path.runtime); if(!fs::exists(runtime_path_status)) { throw cocaine::error_t("the %s directory does not exist", path.runtime); } else if(!fs::is_directory(runtime_path_status)) { throw cocaine::error_t("the %s path is not a directory", path.runtime); } // Hostname configuration char hostname[256]; if(gethostname(hostname, 256) != 0) { throw std::system_error(errno, std::system_category(), "unable to determine the hostname"); } addrinfo hints, *result = nullptr; std::memset(&hints, 0, sizeof(addrinfo)); hints.ai_flags = AI_CANONNAME; const int rv = getaddrinfo(hostname, nullptr, &hints, &result); if(rv != 0) { throw std::system_error(rv, gai_category(), "unable to determine the hostname"); } network.hostname = locator_config.at("hostname", std::string(result->ai_canonname)).as_string(); network.uuid = unique_id_t().string(); freeaddrinfo(result); // Locator configuration network.endpoint = locator_config.at("endpoint", defaults::endpoint).as_string(); network.locator = locator_config.at("port", defaults::locator_port).to<uint16_t>(); // WARNING: Now only arrays of two items are allowed. auto ports = locator_config.find("port-range"); if(ports != locator_config.end()) { network.ports = ports->second.to<std::tuple<uint16_t, uint16_t>>(); } // Cluster configuration if(!network_config.empty()) { if(network_config.count("group") == 1) { network.group = network_config["group"].as_string(); } if(network_config.count("gateway") == 1) { network.gateway = { network_config["gateway"].as_object().at("type", "adhoc").as_string(), network_config["gateway"].as_object().at("args", dynamic_t::empty_object) }; } } #ifdef COCAINE_ALLOW_RAFT create_raft_cluster = false; #endif // Component configuration logging = root.as_object().at("logging" , dynamic_t::empty_object).to<config_t::logging_t>(); services = root.as_object().at("services", dynamic_t::empty_object).to<config_t::component_map_t>(); storages = root.as_object().at("storages", dynamic_t::empty_object).to<config_t::component_map_t>(); }
bool dynamic_t::operator!=(const dynamic_t& other) const { return !other.apply(equals_visitor(*this)); }
dynamic_t::dynamic_t(const dynamic_t& other) : m_value(null_t()) { other.apply(assign_visitor(*this)); }
uniresis_t::uniresis_t(context_t& context, asio::io_service& loop, const std::string& name, const dynamic_t& args) : api::service_t(context, loop, name, args), dispatch<io::uniresis_tag>(name), uuid(context.uuid()), resources(), updater(nullptr), log(context.log("uniresis")) { if (resources.cpu == 0) { throw std::system_error(uniresis::uniresis_errc::failed_calculate_cpu_count); } if (resources.mem == 0) { throw std::system_error(uniresis::uniresis_errc::failed_calculate_system_memory); } auto restrictions = args.as_object().at("restrictions", dynamic_t::empty_object).as_object(); auto cpu_restricted = std::min( resources.cpu, static_cast<uint>(restrictions.at("cpu", resources.cpu).as_uint()) ); if (resources.cpu != cpu_restricted) { resources.cpu = cpu_restricted; COCAINE_LOG_INFO(log, "restricted available CPU count to {}", resources.cpu); } auto mem_restricted = std::min( resources.mem, static_cast<std::uint64_t>(restrictions.at("mem", resources.mem).as_uint()) ); if (resources.mem != mem_restricted) { resources.mem = mem_restricted; COCAINE_LOG_INFO(log, "restricted available system memory to {}", resources.mem); } auto prefix = args.as_object().at("prefix", defaults::resources_path).as_string(); auto path = format("{}/{}", prefix, uuid); auto hostname = context.config().network().hostname(); auto endpoints = resolve(hostname); dynamic_t::object_t extra; if (auto locator = context.config().services().get("locator")) { extra = dynamic_converter<dynamic_t::object_t>::convert( locator->args().as_object().at("extra_param", dynamic_t::empty_object) ); } auto unicorn = api::unicorn(context, args.as_object().at("unicorn", defaults::unicorn_name).as_string()); updater = std::make_shared<updater_t>( std::move(path), std::move(hostname), std::move(endpoints), std::move(extra), resources, std::move(unicorn), log ); updater->notify(); on<io::uniresis::cpu_count>([&] { return resources.cpu; }); on<io::uniresis::memory_count>([&] { return resources.mem; }); on<io::uniresis::uuid>([&] { return uuid; }); }
files_t::files_t(context_t& context, const std::string& name, const dynamic_t& args): category_type(context, name, args), m_log(context.log(name)), m_parent_path(args.as_object().at("path").as_string()) { }