Line data Source code
1 : #include "source/server/admin/runtime_handler.h" 2 : 3 : #include <string> 4 : #include <vector> 5 : 6 : #include "source/common/common/empty_string.h" 7 : #include "source/common/http/headers.h" 8 : #include "source/common/http/utility.h" 9 : #include "source/server/admin/utils.h" 10 : 11 : #include "absl/container/node_hash_map.h" 12 : 13 : namespace Envoy { 14 : namespace Server { 15 : 16 134 : RuntimeHandler::RuntimeHandler(Server::Instance& server) : HandlerContextBase(server) {} 17 : 18 : Http::Code RuntimeHandler::handlerRuntime(Http::ResponseHeaderMap& response_headers, 19 0 : Buffer::Instance& response, AdminStream& admin_stream) { 20 0 : const Http::Utility::QueryParamsMulti params = admin_stream.queryParams(); 21 0 : response_headers.setReferenceContentType(Http::Headers::get().ContentTypeValues.Json); 22 : 23 : // TODO(jsedgwick): Use proto to structure this output instead of arbitrary JSON. 24 0 : const auto& layers = server_.runtime().snapshot().getLayers(); 25 : 26 0 : std::vector<ProtobufWkt::Value> layer_names; 27 0 : layer_names.reserve(layers.size()); 28 0 : std::map<std::string, std::vector<std::string>> entries; 29 0 : for (const auto& layer : layers) { 30 0 : layer_names.push_back(ValueUtil::stringValue(layer->name())); 31 0 : for (const auto& value : layer->values()) { 32 0 : const auto found = entries.find(value.first); 33 0 : if (found == entries.end()) { 34 0 : entries.emplace(value.first, std::vector<std::string>{}); 35 0 : } 36 0 : } 37 0 : } 38 : 39 0 : for (const auto& layer : layers) { 40 0 : for (auto& entry : entries) { 41 0 : const auto found = layer->values().find(entry.first); 42 0 : const auto& entry_value = 43 0 : found == layer->values().end() ? EMPTY_STRING : found->second.raw_string_value_; 44 0 : entry.second.push_back(entry_value); 45 0 : } 46 0 : } 47 : 48 0 : ProtobufWkt::Struct layer_entries; 49 0 : auto* layer_entry_fields = layer_entries.mutable_fields(); 50 0 : for (const auto& entry : entries) { 51 0 : std::vector<ProtobufWkt::Value> layer_entry_values; 52 0 : layer_entry_values.reserve(entry.second.size()); 53 0 : std::string final_value; 54 0 : for (const auto& value : entry.second) { 55 0 : if (!value.empty()) { 56 0 : final_value = value; 57 0 : } 58 0 : layer_entry_values.push_back(ValueUtil::stringValue(value)); 59 0 : } 60 : 61 0 : ProtobufWkt::Struct layer_entry_value; 62 0 : auto* layer_entry_value_fields = layer_entry_value.mutable_fields(); 63 : 64 0 : (*layer_entry_value_fields)["final_value"] = ValueUtil::stringValue(final_value); 65 0 : (*layer_entry_value_fields)["layer_values"] = ValueUtil::listValue(layer_entry_values); 66 0 : (*layer_entry_fields)[entry.first] = ValueUtil::structValue(layer_entry_value); 67 0 : } 68 : 69 0 : ProtobufWkt::Struct runtime; 70 0 : auto* fields = runtime.mutable_fields(); 71 : 72 0 : (*fields)["layers"] = ValueUtil::listValue(layer_names); 73 0 : (*fields)["entries"] = ValueUtil::structValue(layer_entries); 74 : 75 0 : response.add(MessageUtil::getJsonStringFromMessageOrError(runtime, true, true)); 76 0 : return Http::Code::OK; 77 0 : } 78 : 79 : Http::Code RuntimeHandler::handlerRuntimeModify(Http::ResponseHeaderMap&, 80 : Buffer::Instance& response, 81 0 : AdminStream& admin_stream) { 82 0 : Http::Utility::QueryParamsMulti params = admin_stream.queryParams(); 83 0 : if (params.data().empty()) { 84 0 : response.add("usage: /runtime_modify?key1=value1&key2=value2&keyN=valueN\n"); 85 0 : response.add(" or send the parameters as form values\n"); 86 0 : response.add("use an empty value to remove a previously added override"); 87 0 : return Http::Code::BadRequest; 88 0 : } 89 0 : absl::node_hash_map<std::string, std::string> overrides; 90 0 : for (const auto& it : params.data()) { 91 0 : overrides.insert({it.first, it.second[0]}); 92 0 : } 93 0 : TRY_ASSERT_MAIN_THREAD { server_.runtime().mergeValues(overrides); } 94 0 : END_TRY 95 0 : catch (const EnvoyException& e) { 96 0 : ENVOY_LOG_MISC(error, "{}", e.what()); 97 0 : response.add(e.what()); 98 0 : return Http::Code::ServiceUnavailable; 99 0 : } 100 0 : response.add("OK\n"); 101 0 : return Http::Code::OK; 102 0 : } 103 : 104 : } // namespace Server 105 : } // namespace Envoy