Line data Source code
1 : #pragma once 2 : 3 : #include <memory> 4 : #include <string> 5 : 6 : #include "envoy/config/core/v3/base.pb.h" 7 : #include "envoy/config/typed_metadata.h" 8 : #include "envoy/event/dispatcher.h" 9 : #include "envoy/registry/registry.h" 10 : #include "envoy/singleton/manager.h" 11 : #include "envoy/type/metadata/v3/metadata.pb.h" 12 : 13 : #include "source/common/protobuf/protobuf.h" 14 : #include "source/common/shared_pool/shared_pool.h" 15 : 16 : #include "absl/container/node_hash_map.h" 17 : 18 : namespace Envoy { 19 : namespace Config { 20 : 21 : using ConstMetadataSharedPoolSharedPtr = 22 : std::shared_ptr<SharedPool::ObjectSharedPool<const envoy::config::core::v3::Metadata, 23 : MessageUtil, MessageUtil>>; 24 : 25 : /** 26 : * MetadataKey presents the key name and path to retrieve value from metadata. 27 : */ 28 : struct MetadataKey { 29 : std::string key_; 30 : std::vector<std::string> path_; 31 : 32 : MetadataKey(const envoy::type::metadata::v3::MetadataKey& metadata_key); 33 : }; 34 : 35 : /** 36 : * Config metadata helpers. 37 : */ 38 : class Metadata { 39 : public: 40 : /** 41 : * Lookup value of a key for a given filter in Metadata. 42 : * @param metadata reference. 43 : * @param filter name. 44 : * @param key for filter metadata. 45 : * @return const ProtobufWkt::Value& value if found, empty if not found. 46 : */ 47 : static const ProtobufWkt::Value& metadataValue(const envoy::config::core::v3::Metadata* metadata, 48 : const std::string& filter, const std::string& key); 49 : /** 50 : * Lookup value by a multi-key path for a given filter in Metadata. If path is empty 51 : * will return the empty struct. 52 : * @param metadata reference. 53 : * @param filter name. 54 : * @param path multi-key path. 55 : * @return const ProtobufWkt::Value& value if found, empty if not found. 56 : */ 57 : static const ProtobufWkt::Value& metadataValue(const envoy::config::core::v3::Metadata* metadata, 58 : const std::string& filter, 59 : const std::vector<std::string>& path); 60 : /** 61 : * Lookup the value by a metadata key from a Metadata. 62 : * @param metadata reference. 63 : * @param metadata_key with key name and path to retrieve the value. 64 : * @return const ProtobufWkt::Value& value if found, empty if not found. 65 : */ 66 : static const ProtobufWkt::Value& metadataValue(const envoy::config::core::v3::Metadata* metadata, 67 : const MetadataKey& metadata_key); 68 : 69 : /** 70 : * Obtain mutable reference to metadata value for a given filter and key. 71 : * @param metadata reference. 72 : * @param filter name. 73 : * @param key for filter metadata. 74 : * @return ProtobufWkt::Value&. A Value message is created if not found. 75 : */ 76 : static ProtobufWkt::Value& mutableMetadataValue(envoy::config::core::v3::Metadata& metadata, 77 : const std::string& filter, 78 : const std::string& key); 79 : 80 : using LabelSet = std::vector<std::pair<std::string, ProtobufWkt::Value>>; 81 : 82 : /** 83 : * Returns whether a set of the labels match a particular host's metadata. 84 : * @param label_set the target label key/value pair set. 85 : * @param host_metadata a given host's metadata. 86 : * @param filter_key identifies the entry in the metadata entry for the match. 87 : * @param list_as_any if the metadata value entry is a list, and any one of 88 : * the element equals to the input label_set, it's considered as match. 89 : */ 90 : static bool metadataLabelMatch(const LabelSet& label_set, 91 : const envoy::config::core::v3::Metadata* host_metadata, 92 : const std::string& filter_key, bool list_as_any); 93 : /** 94 : * Returns an ObjectSharedPool to store const Metadata 95 : * @param manager used to create singleton 96 : * @param dispatcher the dispatcher object reference to the thread that created the 97 : * ObjectSharedPool 98 : */ 99 : static ConstMetadataSharedPoolSharedPtr getConstMetadataSharedPool(Singleton::Manager& manager, 100 : Event::Dispatcher& dispatcher); 101 : }; 102 : 103 : template <typename factoryClass> class TypedMetadataImpl : public TypedMetadata { 104 : public: 105 : static_assert(std::is_base_of<Config::TypedMetadataFactory, factoryClass>::value, 106 : "Factory type must be inherited from Envoy::Config::TypedMetadataFactory."); 107 494 : TypedMetadataImpl(const envoy::config::core::v3::Metadata& metadata) { populateFrom(metadata); } 108 : 109 0 : const TypedMetadata::Object* getData(const std::string& key) const override { 110 0 : const auto& it = data_.find(key); 111 0 : return it == data_.end() ? nullptr : it->second.get(); 112 0 : } 113 : 114 : protected: 115 : /* Attempt to run each of the registered factories for TypedMetadata, to 116 : * populate the data_ map. 117 : */ 118 494 : void populateFrom(const envoy::config::core::v3::Metadata& metadata) { 119 494 : auto& data_by_key = metadata.filter_metadata(); 120 494 : auto& typed_data_by_key = metadata.typed_filter_metadata(); 121 494 : for (const auto& [factory_name, factory] : 122 494 : Registry::FactoryRegistry<factoryClass>::factories()) { 123 0 : const auto& typed_meta_iter = typed_data_by_key.find(factory_name); 124 : // If the key exists in Any metadata, and parse() does not return nullptr, 125 : // populate data_. 126 0 : if (typed_meta_iter != typed_data_by_key.end()) { 127 0 : auto result = factory->parse(typed_meta_iter->second); 128 0 : if (result != nullptr) { 129 0 : data_[factory->name()] = std::move(result); 130 0 : continue; 131 0 : } 132 0 : } 133 : // Fall back cases to parsing Struct metadata and populate data_. 134 0 : const auto& meta_iter = data_by_key.find(factory_name); 135 0 : if (meta_iter != data_by_key.end()) { 136 0 : data_[factory->name()] = factory->parse(meta_iter->second); 137 0 : } 138 0 : } 139 494 : } 140 : 141 : absl::node_hash_map<std::string, std::unique_ptr<const TypedMetadata::Object>> data_; 142 : }; 143 : 144 : // MetadataPack is struct that contains both the proto and typed metadata. 145 : template <class FactoryClass> struct MetadataPack { 146 : MetadataPack(const envoy::config::core::v3::Metadata& metadata) 147 192 : : proto_metadata_(metadata), typed_metadata_(proto_metadata_) {} 148 246 : MetadataPack() : proto_metadata_(), typed_metadata_(proto_metadata_) {} 149 : 150 : const envoy::config::core::v3::Metadata proto_metadata_; 151 : const TypedMetadataImpl<FactoryClass> typed_metadata_; 152 : }; 153 : 154 : template <class FactoryClass> using MetadataPackPtr = std::unique_ptr<MetadataPack<FactoryClass>>; 155 : template <class FactoryClass> 156 : using MetadataPackSharedPtr = std::shared_ptr<MetadataPack<FactoryClass>>; 157 : 158 : } // namespace Config 159 : } // namespace Envoy