Line data Source code
1 : #include "source/common/config/xds_context_params.h" 2 : 3 : #include "source/common/common/macros.h" 4 : #include "source/common/protobuf/utility.h" 5 : 6 : namespace Envoy { 7 : namespace Config { 8 : 9 : namespace { 10 : 11 : using RenderContextParamCb = std::function<std::string(const envoy::config::core::v3::Node& node)>; 12 : using NodeContextRenderers = absl::flat_hash_map<std::string, RenderContextParamCb>; 13 : 14 8 : RenderContextParamCb directStringFieldRenderer(const std::string& field) { 15 8 : return [field](const envoy::config::core::v3::Node& node) -> std::string { 16 0 : return MessageUtil::getStringField(node, field); 17 0 : }; 18 8 : } 19 : 20 6 : RenderContextParamCb localityStringFieldRenderer(const std::string& field) { 21 6 : return [field](const envoy::config::core::v3::Node& node) -> std::string { 22 0 : return MessageUtil::getStringField(node.locality(), field); 23 0 : }; 24 6 : } 25 : 26 0 : std::string buildSemanticVersionRenderer(const envoy::config::core::v3::Node& node) { 27 0 : const auto& semver = node.user_agent_build_version().version(); 28 0 : return fmt::format("{}.{}.{}", semver.major_number(), semver.minor_number(), semver.patch()); 29 0 : } 30 : 31 8 : const NodeContextRenderers& nodeParamCbs() { 32 8 : CONSTRUCT_ON_FIRST_USE(NodeContextRenderers, {"id", directStringFieldRenderer("id")}, 33 8 : {"cluster", directStringFieldRenderer("cluster")}, 34 8 : {"user_agent_name", directStringFieldRenderer("user_agent_name")}, 35 8 : {"user_agent_version", directStringFieldRenderer("user_agent_version")}, 36 8 : {"locality.region", localityStringFieldRenderer("region")}, 37 8 : {"locality.zone", localityStringFieldRenderer("zone")}, 38 8 : {"locality.sub_zone", localityStringFieldRenderer("sub_zone")}, 39 8 : {"user_agent_build_version.version", buildSemanticVersionRenderer}); 40 8 : } 41 : 42 : void mergeMetadataJson(Protobuf::Map<std::string, std::string>& params, 43 0 : const ProtobufWkt::Struct& metadata, const std::string& prefix) { 44 0 : #ifdef ENVOY_ENABLE_YAML 45 0 : for (const auto& it : metadata.fields()) { 46 0 : absl::StatusOr<std::string> json_or_error = MessageUtil::getJsonStringFromMessage(it.second); 47 0 : ENVOY_BUG(json_or_error.ok(), "Failed to parse json"); 48 0 : if (json_or_error.ok()) { 49 0 : params[prefix + it.first] = json_or_error.value(); 50 0 : } 51 0 : } 52 : #else 53 : UNREFERENCED_PARAMETER(params); 54 : UNREFERENCED_PARAMETER(metadata); 55 : UNREFERENCED_PARAMETER(prefix); 56 : IS_ENVOY_BUG("JSON/YAML support compiled out"); 57 : #endif 58 0 : } 59 : 60 : } // namespace 61 : 62 : xds::core::v3::ContextParams XdsContextParams::encodeResource( 63 : const xds::core::v3::ContextParams& node_context_params, 64 : const xds::core::v3::ContextParams& resource_context_params, 65 : const std::vector<std::string>& client_features, 66 0 : const absl::flat_hash_map<std::string, std::string>& extra_resource_params) { 67 0 : xds::core::v3::ContextParams context_params; 68 : // 1. Establish base layer of per-node context parameters. 69 0 : context_params.MergeFrom(node_context_params); 70 : 71 : // 2. Overlay with context parameters from resource name. 72 0 : auto& mutable_params = *context_params.mutable_params(); 73 0 : for (const auto& it : resource_context_params.params()) { 74 0 : mutable_params[it.first] = it.second; 75 0 : } 76 : 77 : // 3. Overlay with per-resource type context parameters. 78 0 : for (const std::string& cf : client_features) { 79 0 : mutable_params["xds.client_feature." + cf] = "true"; 80 0 : } 81 : 82 : // 4. Overlay with per-resource well-known attributes. 83 0 : for (const auto& it : extra_resource_params) { 84 0 : mutable_params["xds.resource." + it.first] = it.second; 85 0 : } 86 : 87 0 : return context_params; 88 0 : } 89 : 90 : xds::core::v3::ContextParams XdsContextParams::encodeNodeContext( 91 : const envoy::config::core::v3::Node& node, 92 248 : const Protobuf::RepeatedPtrField<std::string>& node_context_params) { 93 : // E.g. if we have a node instance with contents 94 : // 95 : // user_agent_build_version: 96 : // version: 97 : // major_number: 1 98 : // minor_number: 2 99 : // patch: 3 100 : // metadata: 101 : // foo: true 102 : // bar: "a" 103 : // baz: 42 104 : // 105 : // and node_context_params [user_agent_build_version.version, user_agent_build_version.metadata], 106 : // we end up with the map: 107 : // 108 : // xds.node.user_agent_build_version.metadata.bar: "\"a\"" 109 : // xds.node.user_agent_build_version.metadata.baz: "42" 110 : // xds.node.user_agent_build_version.metadata.foo: "true" 111 : // xds.node.user_agent_build_version.version: "1.2.3" 112 248 : xds::core::v3::ContextParams context_params; 113 248 : auto& mutable_params = *context_params.mutable_params(); 114 248 : for (const std::string& ncp : node_context_params) { 115 : // First attempt field accessors known ahead of time, if that fails we consider the cases of 116 : // metadata, either directly in the Node message, or nested in the user_agent_build_version. 117 4 : auto it = nodeParamCbs().find(ncp); 118 4 : if (it != nodeParamCbs().end()) { 119 0 : mutable_params["xds.node." + ncp] = (it->second)(node); 120 4 : } else if (ncp == "metadata") { 121 0 : mergeMetadataJson(mutable_params, node.metadata(), "xds.node.metadata."); 122 4 : } else if (ncp == "user_agent_build_version.metadata") { 123 0 : mergeMetadataJson(mutable_params, node.user_agent_build_version().metadata(), 124 0 : "xds.node.user_agent_build_version.metadata."); 125 0 : } 126 4 : } 127 248 : return context_params; 128 248 : } 129 : 130 : } // namespace Config 131 : } // namespace Envoy