/* * Copyright 2015-present ScyllaDB */ /* * SPDX-License-Identifier: AGPL-3.0-or-later */ #include "api.hh" #include #include #include #include "storage_service.hh" #include "commitlog.hh" #include "gossiper.hh" #include "failure_detector.hh" #include "column_family.hh" #include "lsa.hh" #include "messaging_service.hh" #include "storage_proxy.hh" #include "cache_service.hh" #include "collectd.hh" #include "endpoint_snitch.hh" #include "compaction_manager.hh" #include "hinted_handoff.hh" #include "error_injection.hh" #include "authorization_cache.hh" #include #include "stream_manager.hh" #include "system.hh" #include "api/config.hh" #include "task_manager.hh" #include "task_manager_test.hh" logging::logger apilog("api"); namespace api { static std::unique_ptr exception_reply(std::exception_ptr eptr) { try { std::rethrow_exception(eptr); } catch (const replica::no_such_keyspace& ex) { throw bad_param_exception(ex.what()); } // We never going to get here throw std::runtime_error("exception_reply"); } future<> set_server_init(http_context& ctx) { auto rb = std::make_shared < api_registry_builder > (ctx.api_doc); auto rb02 = std::make_shared < api_registry_builder20 > (ctx.api_doc, "/v2"); return ctx.http_server.set_routes([rb, &ctx, rb02](routes& r) { r.register_exeption_handler(exception_reply); r.put(GET, "/ui", new httpd::file_handler(ctx.api_dir + "/index.html", new content_replace("html"))); r.add(GET, url("/ui").remainder("path"), new httpd::directory_handler(ctx.api_dir, new content_replace("html"))); rb->set_api_doc(r); rb02->set_api_doc(r); rb02->register_api_file(r, "swagger20_header"); rb->register_function(r, "system", "The system related API"); set_system(ctx, r); }); } future<> set_server_config(http_context& ctx, const db::config& cfg) { auto rb02 = std::make_shared < api_registry_builder20 > (ctx.api_doc, "/v2"); return ctx.http_server.set_routes([&ctx, &cfg, rb02](routes& r) { set_config(rb02, ctx, r, cfg); }); } static future<> register_api(http_context& ctx, const sstring& api_name, const sstring api_desc, std::function f) { auto rb = std::make_shared < api_registry_builder > (ctx.api_doc); return ctx.http_server.set_routes([rb, &ctx, api_name, api_desc, f](routes& r) { rb->register_function(r, api_name, api_desc); f(ctx,r); }); } future<> set_transport_controller(http_context& ctx, cql_transport::controller& ctl) { return ctx.http_server.set_routes([&ctx, &ctl] (routes& r) { set_transport_controller(ctx, r, ctl); }); } future<> unset_transport_controller(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_transport_controller(ctx, r); }); } future<> set_rpc_controller(http_context& ctx, thrift_controller& ctl) { return ctx.http_server.set_routes([&ctx, &ctl] (routes& r) { set_rpc_controller(ctx, r, ctl); }); } future<> unset_rpc_controller(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_rpc_controller(ctx, r); }); } future<> set_server_storage_service(http_context& ctx, sharded& ss, sharded& g, sharded& cdc_gs, sharded& sys_ks) { return register_api(ctx, "storage_service", "The storage service API", [&ss, &g, &cdc_gs, &sys_ks] (http_context& ctx, routes& r) { set_storage_service(ctx, r, ss, g.local(), cdc_gs, sys_ks); }); } future<> set_server_sstables_loader(http_context& ctx, sharded& sst_loader) { return ctx.http_server.set_routes([&ctx, &sst_loader] (routes& r) { set_sstables_loader(ctx, r, sst_loader); }); } future<> unset_server_sstables_loader(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_sstables_loader(ctx, r); }); } future<> set_server_view_builder(http_context& ctx, sharded& vb) { return ctx.http_server.set_routes([&ctx, &vb] (routes& r) { set_view_builder(ctx, r, vb); }); } future<> unset_server_view_builder(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_view_builder(ctx, r); }); } future<> set_server_repair(http_context& ctx, sharded& repair) { return ctx.http_server.set_routes([&ctx, &repair] (routes& r) { set_repair(ctx, r, repair); }); } future<> unset_server_repair(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_repair(ctx, r); }); } future<> set_server_authorization_cache(http_context &ctx, sharded &auth_service) { return register_api(ctx, "authorization_cache", "The authorization cache API", [&auth_service] (http_context &ctx, routes &r) { set_authorization_cache(ctx, r, auth_service); }); } future<> unset_server_authorization_cache(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_authorization_cache(ctx, r); }); } future<> set_server_snapshot(http_context& ctx, sharded& snap_ctl) { return ctx.http_server.set_routes([&ctx, &snap_ctl] (routes& r) { set_snapshot(ctx, r, snap_ctl); }); } future<> unset_server_snapshot(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_snapshot(ctx, r); }); } future<> set_server_snitch(http_context& ctx, sharded& snitch) { return register_api(ctx, "endpoint_snitch_info", "The endpoint snitch info API", [&snitch] (http_context& ctx, routes& r) { set_endpoint_snitch(ctx, r, snitch); }); } future<> unset_server_snitch(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_endpoint_snitch(ctx, r); }); } future<> set_server_gossip(http_context& ctx, sharded& g) { return register_api(ctx, "gossiper", "The gossiper API", [&g] (http_context& ctx, routes& r) { set_gossiper(ctx, r, g.local()); }); } future<> set_server_load_sstable(http_context& ctx) { return register_api(ctx, "column_family", "The column family API", set_column_family); } future<> set_server_messaging_service(http_context& ctx, sharded& ms) { return register_api(ctx, "messaging_service", "The messaging service API", [&ms] (http_context& ctx, routes& r) { set_messaging_service(ctx, r, ms); }); } future<> unset_server_messaging_service(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_messaging_service(ctx, r); }); } future<> set_server_storage_proxy(http_context& ctx, sharded& ss) { return register_api(ctx, "storage_proxy", "The storage proxy API", [&ss] (http_context& ctx, routes& r) { set_storage_proxy(ctx, r, ss); }); } future<> set_server_stream_manager(http_context& ctx, sharded& sm) { return register_api(ctx, "stream_manager", "The stream manager API", [&sm] (http_context& ctx, routes& r) { set_stream_manager(ctx, r, sm); }); } future<> unset_server_stream_manager(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_stream_manager(ctx, r); }); } future<> set_server_cache(http_context& ctx) { return register_api(ctx, "cache_service", "The cache service API", set_cache_service); } future<> set_hinted_handoff(http_context& ctx, sharded& g) { return register_api(ctx, "hinted_handoff", "The hinted handoff API", [&g] (http_context& ctx, routes& r) { set_hinted_handoff(ctx, r, g.local()); }); } future<> unset_hinted_handoff(http_context& ctx) { return ctx.http_server.set_routes([&ctx] (routes& r) { unset_hinted_handoff(ctx, r); }); } future<> set_server_gossip_settle(http_context& ctx, sharded& g) { auto rb = std::make_shared < api_registry_builder > (ctx.api_doc); return ctx.http_server.set_routes([rb, &ctx, &g](routes& r) { rb->register_function(r, "failure_detector", "The failure detector API"); set_failure_detector(ctx, r, g.local()); }); } future<> set_server_compaction_manager(http_context& ctx) { auto rb = std::make_shared < api_registry_builder > (ctx.api_doc); return ctx.http_server.set_routes([rb, &ctx](routes& r) { rb->register_function(r, "compaction_manager", "The Compaction manager API"); set_compaction_manager(ctx, r); }); } future<> set_server_done(http_context& ctx) { auto rb = std::make_shared < api_registry_builder > (ctx.api_doc); return ctx.http_server.set_routes([rb, &ctx](routes& r) { rb->register_function(r, "lsa", "Log-structured allocator API"); set_lsa(ctx, r); rb->register_function(r, "commitlog", "The commit log API"); set_commitlog(ctx,r); rb->register_function(r, "collectd", "The collectd API"); set_collectd(ctx, r); rb->register_function(r, "error_injection", "The error injection API"); set_error_injection(ctx, r); }); } future<> set_server_task_manager(http_context& ctx) { auto rb = std::make_shared < api_registry_builder > (ctx.api_doc); return ctx.http_server.set_routes([rb, &ctx](routes& r) { rb->register_function(r, "task_manager", "The task manager API"); set_task_manager(ctx, r); }); } #ifndef SCYLLA_BUILD_MODE_RELEASE future<> set_server_task_manager_test(http_context& ctx, lw_shared_ptr cfg) { auto rb = std::make_shared < api_registry_builder > (ctx.api_doc); return ctx.http_server.set_routes([rb, &ctx, &cfg = *cfg](routes& r) mutable { rb->register_function(r, "task_manager_test", "The task manager test API"); set_task_manager_test(ctx, r, cfg); }); } #endif void req_params::process(const request& req) { // Process mandatory parameters for (auto& [name, ent] : params) { if (!ent.is_mandatory) { continue; } try { ent.value = req.param[name]; } catch (std::out_of_range&) { throw httpd::bad_param_exception(fmt::format("Mandatory parameter '{}' was not provided", name)); } } // Process optional parameters for (auto& [name, value] : req.query_parameters) { try { auto& ent = params.at(name); if (ent.is_mandatory) { throw httpd::bad_param_exception(fmt::format("Parameter '{}' is expected to be provided as part of the request url", name)); } ent.value = value; } catch (std::out_of_range&) { throw httpd::bad_param_exception(fmt::format("Unsupported optional parameter '{}'", name)); } } } }