diff --git a/BUILD b/BUILD index a9b4c193252..5f8015bf0a5 100644 --- a/BUILD +++ b/BUILD @@ -38,6 +38,7 @@ envoy_cc_binary( "//extensions/access_log_policy:access_log_policy_lib", "//extensions/metadata_exchange:metadata_exchange_lib", "//extensions/stackdriver:stackdriver_plugin", + "//source/extensions/common/workload_discovery:api_lib", # Experimental: WIP "//source/extensions/filters/http/alpn:config_lib", "//source/extensions/filters/http/authn:filter_lib", "//source/extensions/filters/http/connect_authority", # Experimental: ambient diff --git a/go.mod b/go.mod index 7c06cea0c8a..aa0a12df7d5 100644 --- a/go.mod +++ b/go.mod @@ -8,13 +8,13 @@ require ( cloud.google.com/go/trace v1.4.0 github.com/cncf/xds/go v0.0.0-20221128185840-c261a164b73d github.com/d4l3k/messagediff v1.2.2-0.20180726183240-b9e99b2f9263 - github.com/envoyproxy/go-control-plane v0.10.3-0.20221213161420-c99aac2a2f43 + github.com/envoyproxy/go-control-plane v0.11.0 github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.9 github.com/prometheus/client_model v0.3.0 github.com/prometheus/common v0.38.0 google.golang.org/genproto v0.0.0-20221207170731-23e4bf6bdc37 - google.golang.org/grpc v1.51.0 + google.golang.org/grpc v1.52.0 google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v2 v2.4.0 sigs.k8s.io/yaml v1.3.0 @@ -22,8 +22,8 @@ require ( require ( cloud.google.com/go/longrunning v0.3.0 // indirect - github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect - github.com/envoyproxy/protoc-gen-validate v0.6.7 // indirect + github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect + github.com/envoyproxy/protoc-gen-validate v0.9.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect github.com/stretchr/testify v1.8.1 // indirect golang.org/x/net v0.7.0 // indirect diff --git a/go.sum b/go.sum index d7be67404bb..80586ed3b9e 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,8 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -75,9 +77,13 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.3-0.20221213161420-c99aac2a2f43 h1:PtquDI1L8Ak/ALyHzCoyrJ9SI556KvFO/jfFX3Qh8M8= github.com/envoyproxy/go-control-plane v0.10.3-0.20221213161420-c99aac2a2f43/go.mod h1:ufpOdMVWU+v42FYQiIBUhSWglFcK3S1Ml8bbzLwkdcE= +github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o= +github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7 h1:qcZcULcd/abmQg6dwigimCNEyi4gg31M/xaciQlDml8= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -261,6 +267,10 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -308,6 +318,10 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -319,6 +333,10 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -442,6 +460,8 @@ google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk= +google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/source/extensions/common/workload_discovery/BUILD b/source/extensions/common/workload_discovery/BUILD new file mode 100644 index 00000000000..c7bdb8ea07c --- /dev/null +++ b/source/extensions/common/workload_discovery/BUILD @@ -0,0 +1,58 @@ +# Copyright Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ +# + +load( + "@envoy//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_test", + "envoy_extension_package", + "envoy_proto_library", +) + +envoy_extension_package() + +envoy_cc_extension( + name = "api_lib", + srcs = ["api.cc"], + hdrs = ["api.h"], + repository = "@envoy", + deps = [ + ":discovery_cc_proto", + "//extensions/common:metadata_object_lib", + "@envoy//envoy/registry", + "@envoy//envoy/server:bootstrap_extension_config_interface", + "@envoy//envoy/server:factory_context_interface", + "@envoy//envoy/singleton:manager_interface", + "@envoy//envoy/stats:stats_macros", + "@envoy//envoy/thread_local:thread_local_interface", + "@envoy//source/common/common:non_copyable", + "@envoy//source/common/config:subscription_base_interface", + "@envoy//source/common/grpc:common_lib", + "@envoy//source/common/init:target_lib", + ], +) + +envoy_proto_library( + name = "discovery", + srcs = [ + "discovery.proto", + "extension.proto", + ], + deps = [ + "@envoy_api//envoy/config/core/v3:pkg", + ], +) diff --git a/source/extensions/common/workload_discovery/api.cc b/source/extensions/common/workload_discovery/api.cc new file mode 100644 index 00000000000..c8c49bb22f5 --- /dev/null +++ b/source/extensions/common/workload_discovery/api.cc @@ -0,0 +1,238 @@ +// Copyright Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/extensions/common/workload_discovery/api.h" + +#include "envoy/registry/registry.h" +#include "envoy/server/bootstrap_extension_config.h" +#include "envoy/server/factory_context.h" +#include "envoy/singleton/manager.h" +#include "envoy/thread_local/thread_local.h" +#include "source/common/common/non_copyable.h" +#include "source/common/config/subscription_base.h" +#include "source/common/grpc/common.h" +#include "source/common/init/target_impl.h" +#include "source/extensions/common/workload_discovery/discovery.pb.h" +#include "source/extensions/common/workload_discovery/discovery.pb.validate.h" +#include "source/extensions/common/workload_discovery/extension.pb.h" +#include "source/extensions/common/workload_discovery/extension.pb.validate.h" + +namespace Envoy::Extensions::Common::WorkloadDiscovery { + +namespace { +Istio::Common::WorkloadMetadataObject convert(const istio::workload::Workload& workload) { + auto workload_type = Istio::Common::WorkloadType::Deployment; + switch (workload.workload_type()) { + case istio::workload::WorkloadType::CRONJOB: + workload_type = Istio::Common::WorkloadType::CronJob; + break; + case istio::workload::WorkloadType::JOB: + workload_type = Istio::Common::WorkloadType::Job; + break; + case istio::workload::WorkloadType::POD: + workload_type = Istio::Common::WorkloadType::Pod; + break; + default: + break; + } + return Istio::Common::WorkloadMetadataObject( + workload.name(), /* cluster_name */ "", workload.namespace_(), workload.workload_name(), + workload.canonical_name(), workload.canonical_revision(), /* app_name */ "", + /* app_version */ "", workload_type); +} +} // namespace + +class WorkloadMetadataProviderImpl : public WorkloadMetadataProvider, public Singleton::Instance { +public: + WorkloadMetadataProviderImpl(const envoy::config::core::v3::ConfigSource& config_source, + Server::Configuration::ServerFactoryContext& factory_context) + : config_source_(config_source), factory_context_(factory_context), + tls_(factory_context.threadLocal()), + scope_(factory_context.scope().createScope("workload_discovery")), + stats_(generateStats(*scope_)), subscription_(*this) { + tls_.set([](Event::Dispatcher&) { return std::make_shared(); }); + // This is safe because the ADS mux is started in the cluster manager constructor prior to this + // call. + subscription_.start(); + } + + std::optional + GetMetadata(const Network::Address::InstanceConstSharedPtr& address) override { + if (address && address->ip()) { + if (const auto ipv4 = address->ip()->ipv4(); ipv4) { + uint32_t value = ipv4->address(); + std::array output; + absl::little_endian::Store32(&output, value); + return tls_->get(std::string(output.begin(), output.end())); + } else if (const auto ipv6 = address->ip()->ipv6(); ipv6) { + const uint64_t high = absl::Uint128High64(ipv6->address()); + const uint64_t low = absl::Uint128Low64(ipv6->address()); + std::array output; + absl::little_endian::Store64(&output, high); + absl::little_endian::Store64(&output[8], low); + return tls_->get(std::string(output.begin(), output.end())); + } + } + return {}; + } + +private: + using AddressIndex = absl::flat_hash_map; + using AddressIndexSharedPtr = std::shared_ptr; + using AddressVector = std::vector; + using AddressVectorSharedPtr = std::shared_ptr; + + struct ThreadLocalProvider : public ThreadLocal::ThreadLocalObject { + void reset(const AddressIndexSharedPtr& index) { address_index_ = *index; } + void update(const AddressIndexSharedPtr& added, const AddressVectorSharedPtr& removed) { + for (const auto& [address, workload] : *added) { + address_index_.emplace(address, workload); + } + for (const auto& address : *removed) { + address_index_.erase(address); + } + } + size_t total() const { return address_index_.size(); } + // Returns by-value since the flat map does not provide pointer stability. + std::optional get(const std::string& address) { + const auto it = address_index_.find(address); + if (it != address_index_.end()) { + return it->second; + } + return {}; + } + AddressIndex address_index_; + }; + class WorkloadSubscription : Config::SubscriptionBase { + public: + WorkloadSubscription(WorkloadMetadataProviderImpl& parent) + : Config::SubscriptionBase( + parent.factory_context_.messageValidationVisitor(), "address"), + parent_(parent) { + subscription_ = parent.factory_context_.clusterManager() + .subscriptionFactory() + .subscriptionFromConfigSource( + parent.config_source_, Grpc::Common::typeUrl(getResourceName()), + *parent.scope_, *this, resource_decoder_, {}); + } + void start() { subscription_->start({}); } + + private: + // Config::SubscriptionCallbacks + void onConfigUpdate(const std::vector& resources, + const std::string&) override { + AddressIndexSharedPtr index = std::make_shared(); + for (const auto& resource : resources) { + const auto& workload = + dynamic_cast(resource.get().resource()); + index->emplace(workload.address(), convert(workload)); + } + parent_.reset(index); + } + void onConfigUpdate(const std::vector& added_resources, + const Protobuf::RepeatedPtrField& removed_resources, + const std::string&) override { + AddressIndexSharedPtr added = std::make_shared(); + for (const auto& resource : added_resources) { + const auto& workload = + dynamic_cast(resource.get().resource()); + added->emplace(workload.address(), convert(workload)); + } + AddressVectorSharedPtr removed = std::make_shared(); + removed->reserve(removed_resources.size()); + for (const auto& resource : removed_resources) { + removed->push_back(resource); + } + parent_.update(added, removed); + } + void onConfigUpdateFailed(Config::ConfigUpdateFailureReason, const EnvoyException*) override { + // Do nothing - feature is automatically disabled. + // TODO: Potential issue with the expiration of the metadata. + } + WorkloadMetadataProviderImpl& parent_; + Config::SubscriptionPtr subscription_; + }; + + void reset(AddressIndexSharedPtr index) { + tls_.runOnAllThreads([index](OptRef tls) { tls->reset(index); }); + stats_.total_.set(tls_->total()); + } + + void update(AddressIndexSharedPtr added, AddressVectorSharedPtr removed) { + tls_.runOnAllThreads( + [added, removed](OptRef tls) { tls->update(added, removed); }); + stats_.total_.set(tls_->total()); + } + + WorkloadDiscoveryStats generateStats(Stats::Scope& scope) { + return WorkloadDiscoveryStats{WORKLOAD_DISCOVERY_STATS(POOL_GAUGE(scope))}; + } + + const envoy::config::core::v3::ConfigSource config_source_; + Server::Configuration::ServerFactoryContext& factory_context_; + ThreadLocal::TypedSlot tls_; + Stats::ScopeSharedPtr scope_; + WorkloadDiscoveryStats stats_; + WorkloadSubscription subscription_; +}; + +SINGLETON_MANAGER_REGISTRATION(WorkloadMetadataProvider) + +class WorkloadDiscoveryExtension : public Server::BootstrapExtension { +public: + WorkloadDiscoveryExtension(Server::Configuration::ServerFactoryContext& factory_context, + const istio::workload::BootstrapExtension& config) + : factory_context_(factory_context), config_(config) {} + + // Server::Configuration::BootstrapExtension + void onServerInitialized() override { + provider_ = factory_context_.singletonManager().getTyped( + SINGLETON_MANAGER_REGISTERED_NAME(WorkloadMetadataProvider), [&] { + return std::make_shared(config_.config_source(), + factory_context_); + }); + } + +private: + Server::Configuration::ServerFactoryContext& factory_context_; + const istio::workload::BootstrapExtension config_; + WorkloadMetadataProviderSharedPtr provider_; +}; + +class WorkloadDiscoveryFactory : public Server::Configuration::BootstrapExtensionFactory { +public: + // Server::Configuration::BootstrapExtensionFactory + Server::BootstrapExtensionPtr + createBootstrapExtension(const Protobuf::Message& config, + Server::Configuration::ServerFactoryContext& context) override { + const auto& message = + MessageUtil::downcastAndValidate( + config, context.messageValidationVisitor()); + return std::make_unique(context, message); + } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + std::string name() const override { return "envoy.bootstrap.workload_discovery"; }; +}; + +REGISTER_FACTORY(WorkloadDiscoveryFactory, Server::Configuration::BootstrapExtensionFactory); + +WorkloadMetadataProviderSharedPtr +GetProvider(Server::Configuration::ServerFactoryContext& context) { + return context.singletonManager().getTyped( + SINGLETON_MANAGER_REGISTERED_NAME(WorkloadMetadataProvider)); +} + +} // namespace Envoy::Extensions::Common::WorkloadDiscovery diff --git a/source/extensions/common/workload_discovery/api.h b/source/extensions/common/workload_discovery/api.h new file mode 100644 index 00000000000..38ad400c658 --- /dev/null +++ b/source/extensions/common/workload_discovery/api.h @@ -0,0 +1,41 @@ +// Copyright Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "envoy/network/address.h" +#include "envoy/stats/stats_macros.h" +#include "envoy/server/factory_context.h" +#include "extensions/common/metadata_object.h" + +namespace Envoy::Extensions::Common::WorkloadDiscovery { + +#define WORKLOAD_DISCOVERY_STATS(GAUGE) GAUGE(total, NeverImport) + +struct WorkloadDiscoveryStats { + WORKLOAD_DISCOVERY_STATS(GENERATE_GAUGE_STRUCT) +}; + +class WorkloadMetadataProvider { +public: + virtual ~WorkloadMetadataProvider() = default; + virtual std::optional + GetMetadata(const Network::Address::InstanceConstSharedPtr& address) PURE; +}; + +using WorkloadMetadataProviderSharedPtr = std::shared_ptr; + +WorkloadMetadataProviderSharedPtr GetProvider(Server::Configuration::ServerFactoryContext& context); + +} // namespace Envoy::Extensions::Common::WorkloadDiscovery diff --git a/source/extensions/common/workload_discovery/discovery.proto b/source/extensions/common/workload_discovery/discovery.proto new file mode 100644 index 00000000000..a24d65eeb17 --- /dev/null +++ b/source/extensions/common/workload_discovery/discovery.proto @@ -0,0 +1,68 @@ +// Copyright Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package istio.workload; +option go_package = "test/envoye2e/workloadapi"; + +/** + * Warning: Derived from + * https://raw.githubusercontent.com/istio/istio/57f3b2bab3c07188d940fce94d3261f617ad0e10/pkg/workloadapi/workload.proto + * with the following changes: + * + * 1) delete unused fields; + * 2) change go_package; + * 3) append bootstrap extension stub; + */ + +message Workload { + // Name represents the name for the workload. + // For Kubernetes, this is the pod name. + // This is just for debugging and may be elided as an optimization. + string name = 1; + + // Namespace represents the namespace for the workload. + // This is just for debugging and may be elided as an optimization. + string namespace = 2; + + // IP address of the workload. + bytes address = 3; + + // The SPIFFE identity of the workload. The identity is joined to form spiffe:///ns//sa/. + // TrustDomain of the workload. May be elided if this is the mesh wide default (typically cluster.local) + string trust_domain = 6; + + // ServiceAccount of the workload. May be elided if this is "default" + string service_account = 7; + + // CanonicalName for the workload. Used for telemetry. + string canonical_name = 10; + + // CanonicalRevision for the workload. Used for telemetry. + string canonical_revision = 11; + + // WorkloadType represents the type of the workload. Used for telemetry. + WorkloadType workload_type = 12; + + // WorkloadName represents the name for the workload (of type WorkloadType). Used for telemetry. + string workload_name = 13; +} + +enum WorkloadType { + DEPLOYMENT = 0; + CRONJOB = 1; + POD = 2; + JOB = 3; +} diff --git a/source/extensions/common/workload_discovery/extension.proto b/source/extensions/common/workload_discovery/extension.proto new file mode 100644 index 00000000000..412f77f851e --- /dev/null +++ b/source/extensions/common/workload_discovery/extension.proto @@ -0,0 +1,24 @@ +// Copyright Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "envoy/config/core/v3/config_source.proto"; + +package istio.workload; +option go_package = "test/envoye2e/workloadapi"; + +message BootstrapExtension { + envoy.config.core.v3.ConfigSource config_source = 1; +} diff --git a/source/extensions/filters/http/istio_stats/BUILD b/source/extensions/filters/http/istio_stats/BUILD index 01605f77d82..d4b7cbc3f5a 100644 --- a/source/extensions/filters/http/istio_stats/BUILD +++ b/source/extensions/filters/http/istio_stats/BUILD @@ -33,6 +33,7 @@ envoy_cc_extension( ":config_cc_proto", "//extensions/common:metadata_object_lib", "//source/extensions/common:utils_lib", + "//source/extensions/common/workload_discovery:api_lib", "//source/extensions/filters/network/istio_authn:config_lib", "@com_google_cel_cpp//eval/public:builtin_func_registrar", "@com_google_cel_cpp//eval/public:cel_expr_builder_factory", @@ -42,6 +43,7 @@ envoy_cc_extension( "@envoy//envoy/stream_info:filter_state_interface", "@envoy//source/common/grpc:common_lib", "@envoy//source/common/http:header_map_lib", + "@envoy//source/common/network:utility_lib", "@envoy//source/common/stream_info:utility_lib", "@envoy//source/extensions/filters/common/expr:cel_state_lib", "@envoy//source/extensions/filters/common/expr:context_lib", diff --git a/source/extensions/filters/http/istio_stats/istio_stats.cc b/source/extensions/filters/http/istio_stats/istio_stats.cc index 03c7fa6fea2..f3115752903 100644 --- a/source/extensions/filters/http/istio_stats/istio_stats.cc +++ b/source/extensions/filters/http/istio_stats/istio_stats.cc @@ -24,8 +24,10 @@ #include "source/common/grpc/common.h" #include "source/common/http/header_map_impl.h" #include "source/common/http/header_utility.h" +#include "source/common/network/utility.h" #include "source/common/stream_info/utility.h" #include "source/extensions/common/utils.h" +#include "source/extensions/common/workload_discovery/api.h" #include "source/extensions/filters/common/expr/cel_state.h" #include "source/extensions/filters/common/expr/context.h" #include "source/extensions/filters/common/expr/evaluator.h" @@ -74,6 +76,27 @@ extractEndpointMetadata(const StreamInfo::StreamInfo& info) { return {}; } +const Network::Address::InstanceConstSharedPtr +extractEndpointAddress(const StreamInfo::StreamInfo& info) { + auto upstream_info = info.upstreamInfo(); + auto upstream_host = upstream_info ? upstream_info->upstreamHost() : nullptr; + if (upstream_host) { + if (upstream_host->metadata()) { + const auto& filter_metadata = upstream_host->metadata()->filter_metadata(); + const auto& it = filter_metadata.find("tunnel"); + if (it != filter_metadata.end()) { + const auto& destination_it = it->second.fields().find("destination"); + if (destination_it != it->second.fields().end()) { + return Network::Utility::parseInternetAddressAndPortNoThrow( + destination_it->second.string_value(), /*v6only=*/false); + } + } + } + return upstream_host->address(); + } + return nullptr; +} + enum class Reporter { // Regular outbound listener on a sidecar. ClientSidecar, @@ -439,7 +462,9 @@ struct Config : public Logger::Loggable { scope_(factory_context.scope()), disable_host_header_fallback_(proto_config.disable_host_header_fallback()), report_duration_( - PROTOBUF_GET_MS_OR_DEFAULT(proto_config, tcp_reporting_duration, /* 5s */ 5000)) { + PROTOBUF_GET_MS_OR_DEFAULT(proto_config, tcp_reporting_duration, /* 5s */ 5000)), + metadata_provider_(Extensions::Common::WorkloadDiscovery::GetProvider( + factory_context.getServerFactoryContext())) { reporter_ = Reporter::ClientSidecar; switch (proto_config.reporter()) { case stats::Reporter::UNSPECIFIED: @@ -677,6 +702,7 @@ struct Config : public Logger::Loggable { const bool disable_host_header_fallback_; const std::chrono::milliseconds report_duration_; + Extensions::Common::WorkloadDiscovery::WorkloadMetadataProviderSharedPtr metadata_provider_; std::unique_ptr metric_overrides_; }; @@ -975,7 +1001,10 @@ class IstioStatsFilter : public Http::PassThroughFilter, : context_.unknown_}); switch (config_->reporter()) { case Reporter::ServerGateway: { - auto endpoint_peer = extractEndpointMetadata(info); + std::optional endpoint_peer = + config_->metadata_provider_ + ? config_->metadata_provider_->GetMetadata(extractEndpointAddress(info)) + : std::nullopt; tags_.push_back( {context_.destination_workload_, endpoint_peer ? pool_.add(endpoint_peer->workload_name_) : context_.unknown_}); diff --git a/test/envoye2e/driver/xds.go b/test/envoye2e/driver/xds.go index 743ee261958..1ceacbb3ea8 100644 --- a/test/envoye2e/driver/xds.go +++ b/test/envoye2e/driver/xds.go @@ -19,6 +19,7 @@ import ( "fmt" "log" "net" + "net/netip" clusterv3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" @@ -31,6 +32,8 @@ import ( "github.com/envoyproxy/go-control-plane/pkg/cache/v3" "github.com/envoyproxy/go-control-plane/pkg/server/v3" "google.golang.org/grpc" + + "istio.io/proxy/test/envoye2e/workloadapi" ) // XDS creates an xDS server @@ -40,20 +43,46 @@ type XDS struct { // XDSServer is a struct holding xDS state. type XDSServer struct { + cache.MuxCache Extensions *ExtensionServer Cache cache.SnapshotCache + Workloads *cache.LinearCache } var _ Step = &XDS{} +const WorkloadTypeURL = "type.googleapis.com/istio.workload.Workload" + // Run starts up an Envoy XDS server. func (x *XDS) Run(p *Params) error { log.Printf("XDS server starting on %d\n", p.Ports.XDSPort) x.grpc = grpc.NewServer() p.Config.Extensions = NewExtensionServer(context.Background()) extensionservice.RegisterExtensionConfigDiscoveryServiceServer(x.grpc, p.Config.Extensions) + + // Register caches. p.Config.Cache = cache.NewSnapshotCache(false, cache.IDHash{}, x) - xdsServer := server.NewServer(context.Background(), p.Config.Cache, nil) + p.Config.Workloads = cache.NewLinearCache(WorkloadTypeURL, + cache.WithLogger(x)) + + p.Config.Caches = map[string]cache.Cache{ + "default": p.Config.Cache, + "workloads": p.Config.Workloads, + } + p.Config.Classify = func(r *cache.Request) string { + if r.TypeUrl == WorkloadTypeURL { + return "workloads" + } + return "default" + } + p.Config.ClassifyDelta = func(r *cache.DeltaRequest) string { + if r.TypeUrl == WorkloadTypeURL { + return "workloads" + } + return "default" + } + + xdsServer := server.NewServer(context.Background(), &p.Config, nil) discovery.RegisterAggregatedDiscoveryServiceServer(x.grpc, xdsServer) secret.RegisterSecretDiscoveryServiceServer(x.grpc, xdsServer) lis, err := net.Listen("tcp", fmt.Sprintf(":%d", p.Ports.XDSPort)) @@ -67,6 +96,16 @@ func (x *XDS) Run(p *Params) error { return nil } +type NamedWorkload struct { + workloadapi.Workload +} + +func (nw *NamedWorkload) GetName() string { + return string(nw.Address) +} + +var _ types.ResourceWithName = &NamedWorkload{} + // Cleanup stops the XDS server. func (x *XDS) Cleanup() { log.Println("stopping XDS server") @@ -164,3 +203,37 @@ func (u *UpdateExtensions) Run(p *Params) error { } func (u *UpdateExtensions) Cleanup() {} + +type WorkloadMetadata struct { + Address string + Metadata string +} + +type UpdateWorkloadMetadata struct { + Workloads []WorkloadMetadata +} + +var _ Step = &UpdateWorkloadMetadata{} + +func (u *UpdateWorkloadMetadata) Run(p *Params) error { + for _, wl := range u.Workloads { + out := &workloadapi.Workload{} + if err := p.FillYAML(wl.Metadata, out); err != nil { + return err + } + // Parse address as IP bytes + ip, err := netip.ParseAddr(wl.Address) + if err != nil { + return err + } + log.Printf("updating metadata for %q\n", wl.Address) + out.Address = ip.AsSlice() + err = p.Config.Workloads.UpdateResource(string(out.Address), out) + if err != nil { + return err + } + } + return nil +} + +func (u *UpdateWorkloadMetadata) Cleanup() {} diff --git a/test/envoye2e/stats_plugin/stats_test.go b/test/envoye2e/stats_plugin/stats_test.go index 36135c64294..842b8c43530 100644 --- a/test/envoye2e/stats_plugin/stats_test.go +++ b/test/envoye2e/stats_plugin/stats_test.go @@ -628,10 +628,18 @@ func TestStatsEndpointLabels(t *testing.T) { } } +const BackendMetadata = ` +namespace: default +workload_name: ratings-v1 +canonical_name: ratings +canonical_revision: version-1 +` + func TestStatsServerWaypointProxy(t *testing.T) { params := driver.NewTestParams(t, map[string]string{ "RequestCount": "10", - "EnableEndpointMetadata": "true", + "EnableDelta": "true", + "EnableMetadataDiscovery": "true", "StatsFilterServerConfig": driver.LoadTestJSON("testdata/stats/server_waypoint_proxy_config.yaml"), }, envoye2e.ProxyE2ETests) params.Vars["ClientMetadata"] = params.LoadTestData("testdata/client_node_metadata.json.tmpl") @@ -645,6 +653,10 @@ func TestStatsServerWaypointProxy(t *testing.T) { &driver.XDS{}, &driver.Update{Node: "client", Version: "0", Listeners: []string{params.LoadTestData("testdata/listener/client.yaml.tmpl")}}, &driver.Update{Node: "server", Version: "0", Listeners: []string{params.LoadTestData("testdata/listener/server.yaml.tmpl")}}, + &driver.UpdateWorkloadMetadata{Workloads: []driver.WorkloadMetadata{{ + Address: "127.0.0.1", + Metadata: BackendMetadata, + }}}, &driver.Envoy{Bootstrap: params.LoadTestData("testdata/bootstrap/client.yaml.tmpl")}, &driver.Envoy{Bootstrap: params.LoadTestData("testdata/bootstrap/server.yaml.tmpl")}, &driver.Sleep{Duration: 1 * time.Second}, @@ -670,7 +682,8 @@ func TestStatsServerWaypointProxy(t *testing.T) { func TestStatsServerWaypointProxyCONNECT(t *testing.T) { params := driver.NewTestParams(t, map[string]string{ "RequestCount": "10", - "EnableEndpointMetadata": "true", + "EnableDelta": "true", + "EnableMetadataDiscovery": "true", "StatsFilterServerConfig": driver.LoadTestJSON("testdata/stats/server_waypoint_proxy_config.yaml"), }, envoye2e.ProxyE2ETests) params.Vars["ServerClusterName"] = "internal_outbound" @@ -709,6 +722,10 @@ func TestStatsServerWaypointProxyCONNECT(t *testing.T) { driver.LoadTestData("testdata/secret/server.yaml.tmpl"), }, }, + &driver.UpdateWorkloadMetadata{Workloads: []driver.WorkloadMetadata{{ + Address: "127.0.0.1", + Metadata: BackendMetadata, + }}}, &driver.Envoy{Bootstrap: params.LoadTestData("testdata/bootstrap/client.yaml.tmpl")}, &driver.Envoy{Bootstrap: params.LoadTestData("testdata/bootstrap/server.yaml.tmpl")}, &driver.Sleep{Duration: 1 * time.Second}, diff --git a/test/envoye2e/workloadapi/discovery.pb.go b/test/envoye2e/workloadapi/discovery.pb.go new file mode 100644 index 00000000000..39ce0b12c8f --- /dev/null +++ b/test/envoye2e/workloadapi/discovery.pb.go @@ -0,0 +1,388 @@ +// Copyright Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.12 +// source: source/extensions/common/workload_discovery/discovery.proto + +package workloadapi + +import ( + v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type WorkloadType int32 + +const ( + WorkloadType_DEPLOYMENT WorkloadType = 0 + WorkloadType_CRONJOB WorkloadType = 1 + WorkloadType_POD WorkloadType = 2 + WorkloadType_JOB WorkloadType = 3 +) + +// Enum value maps for WorkloadType. +var ( + WorkloadType_name = map[int32]string{ + 0: "DEPLOYMENT", + 1: "CRONJOB", + 2: "POD", + 3: "JOB", + } + WorkloadType_value = map[string]int32{ + "DEPLOYMENT": 0, + "CRONJOB": 1, + "POD": 2, + "JOB": 3, + } +) + +func (x WorkloadType) Enum() *WorkloadType { + p := new(WorkloadType) + *p = x + return p +} + +func (x WorkloadType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (WorkloadType) Descriptor() protoreflect.EnumDescriptor { + return file_source_extensions_common_workload_discovery_discovery_proto_enumTypes[0].Descriptor() +} + +func (WorkloadType) Type() protoreflect.EnumType { + return &file_source_extensions_common_workload_discovery_discovery_proto_enumTypes[0] +} + +func (x WorkloadType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use WorkloadType.Descriptor instead. +func (WorkloadType) EnumDescriptor() ([]byte, []int) { + return file_source_extensions_common_workload_discovery_discovery_proto_rawDescGZIP(), []int{0} +} + +type Workload struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Name represents the name for the workload. + // For Kubernetes, this is the pod name. + // This is just for debugging and may be elided as an optimization. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Namespace represents the namespace for the workload. + // This is just for debugging and may be elided as an optimization. + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + // IP address of the workload. + Address []byte `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + // The SPIFFE identity of the workload. The identity is joined to form spiffe:///ns//sa/. + // TrustDomain of the workload. May be elided if this is the mesh wide default (typically cluster.local) + TrustDomain string `protobuf:"bytes,6,opt,name=trust_domain,json=trustDomain,proto3" json:"trust_domain,omitempty"` + // ServiceAccount of the workload. May be elided if this is "default" + ServiceAccount string `protobuf:"bytes,7,opt,name=service_account,json=serviceAccount,proto3" json:"service_account,omitempty"` + // CanonicalName for the workload. Used for telemetry. + CanonicalName string `protobuf:"bytes,10,opt,name=canonical_name,json=canonicalName,proto3" json:"canonical_name,omitempty"` + // CanonicalRevision for the workload. Used for telemetry. + CanonicalRevision string `protobuf:"bytes,11,opt,name=canonical_revision,json=canonicalRevision,proto3" json:"canonical_revision,omitempty"` + // WorkloadType represents the type of the workload. Used for telemetry. + WorkloadType WorkloadType `protobuf:"varint,12,opt,name=workload_type,json=workloadType,proto3,enum=istio.workload.WorkloadType" json:"workload_type,omitempty"` + // WorkloadName represents the name for the workload (of type WorkloadType). Used for telemetry. + WorkloadName string `protobuf:"bytes,13,opt,name=workload_name,json=workloadName,proto3" json:"workload_name,omitempty"` +} + +func (x *Workload) Reset() { + *x = Workload{} + if protoimpl.UnsafeEnabled { + mi := &file_source_extensions_common_workload_discovery_discovery_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Workload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Workload) ProtoMessage() {} + +func (x *Workload) ProtoReflect() protoreflect.Message { + mi := &file_source_extensions_common_workload_discovery_discovery_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Workload.ProtoReflect.Descriptor instead. +func (*Workload) Descriptor() ([]byte, []int) { + return file_source_extensions_common_workload_discovery_discovery_proto_rawDescGZIP(), []int{0} +} + +func (x *Workload) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Workload) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *Workload) GetAddress() []byte { + if x != nil { + return x.Address + } + return nil +} + +func (x *Workload) GetTrustDomain() string { + if x != nil { + return x.TrustDomain + } + return "" +} + +func (x *Workload) GetServiceAccount() string { + if x != nil { + return x.ServiceAccount + } + return "" +} + +func (x *Workload) GetCanonicalName() string { + if x != nil { + return x.CanonicalName + } + return "" +} + +func (x *Workload) GetCanonicalRevision() string { + if x != nil { + return x.CanonicalRevision + } + return "" +} + +func (x *Workload) GetWorkloadType() WorkloadType { + if x != nil { + return x.WorkloadType + } + return WorkloadType_DEPLOYMENT +} + +func (x *Workload) GetWorkloadName() string { + if x != nil { + return x.WorkloadName + } + return "" +} + +type BootstrapExtension struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConfigSource *v3.ConfigSource `protobuf:"bytes,1,opt,name=config_source,json=configSource,proto3" json:"config_source,omitempty"` +} + +func (x *BootstrapExtension) Reset() { + *x = BootstrapExtension{} + if protoimpl.UnsafeEnabled { + mi := &file_source_extensions_common_workload_discovery_discovery_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BootstrapExtension) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BootstrapExtension) ProtoMessage() {} + +func (x *BootstrapExtension) ProtoReflect() protoreflect.Message { + mi := &file_source_extensions_common_workload_discovery_discovery_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BootstrapExtension.ProtoReflect.Descriptor instead. +func (*BootstrapExtension) Descriptor() ([]byte, []int) { + return file_source_extensions_common_workload_discovery_discovery_proto_rawDescGZIP(), []int{1} +} + +func (x *BootstrapExtension) GetConfigSource() *v3.ConfigSource { + if x != nil { + return x.ConfigSource + } + return nil +} + +var File_source_extensions_common_workload_discovery_discovery_proto protoreflect.FileDescriptor + +var file_source_extensions_common_workload_discovery_discovery_proto_rawDesc = []byte{ + 0x0a, 0x3b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x6c, + 0x6f, 0x61, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x64, 0x69, + 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x69, + 0x73, 0x74, 0x69, 0x6f, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x1a, 0x28, 0x65, + 0x6e, 0x76, 0x6f, 0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x63, 0x6f, 0x72, 0x65, + 0x2f, 0x76, 0x33, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe0, 0x02, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x6b, + 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x72, 0x75, 0x73, 0x74, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, + 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, + 0x5f, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x11, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x69, 0x73, 0x74, 0x69, + 0x6f, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, + 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, + 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, + 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, + 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x5d, 0x0a, 0x12, 0x42, 0x6f, + 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x47, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x33, 0x2e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0c, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2a, 0x3d, 0x0a, 0x0c, 0x57, 0x6f, 0x72, + 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x45, 0x50, + 0x4c, 0x4f, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x52, 0x4f, + 0x4e, 0x4a, 0x4f, 0x42, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x4f, 0x44, 0x10, 0x02, 0x12, + 0x07, 0x0a, 0x03, 0x4a, 0x4f, 0x42, 0x10, 0x03, 0x42, 0x1b, 0x5a, 0x19, 0x74, 0x65, 0x73, 0x74, + 0x2f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x65, 0x32, 0x65, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, + 0x61, 0x64, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_source_extensions_common_workload_discovery_discovery_proto_rawDescOnce sync.Once + file_source_extensions_common_workload_discovery_discovery_proto_rawDescData = file_source_extensions_common_workload_discovery_discovery_proto_rawDesc +) + +func file_source_extensions_common_workload_discovery_discovery_proto_rawDescGZIP() []byte { + file_source_extensions_common_workload_discovery_discovery_proto_rawDescOnce.Do(func() { + file_source_extensions_common_workload_discovery_discovery_proto_rawDescData = protoimpl.X.CompressGZIP(file_source_extensions_common_workload_discovery_discovery_proto_rawDescData) + }) + return file_source_extensions_common_workload_discovery_discovery_proto_rawDescData +} + +var file_source_extensions_common_workload_discovery_discovery_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_source_extensions_common_workload_discovery_discovery_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_source_extensions_common_workload_discovery_discovery_proto_goTypes = []interface{}{ + (WorkloadType)(0), // 0: istio.workload.WorkloadType + (*Workload)(nil), // 1: istio.workload.Workload + (*BootstrapExtension)(nil), // 2: istio.workload.BootstrapExtension + (*v3.ConfigSource)(nil), // 3: envoy.config.core.v3.ConfigSource +} +var file_source_extensions_common_workload_discovery_discovery_proto_depIdxs = []int32{ + 0, // 0: istio.workload.Workload.workload_type:type_name -> istio.workload.WorkloadType + 3, // 1: istio.workload.BootstrapExtension.config_source:type_name -> envoy.config.core.v3.ConfigSource + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_source_extensions_common_workload_discovery_discovery_proto_init() } +func file_source_extensions_common_workload_discovery_discovery_proto_init() { + if File_source_extensions_common_workload_discovery_discovery_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_source_extensions_common_workload_discovery_discovery_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Workload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_source_extensions_common_workload_discovery_discovery_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BootstrapExtension); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_source_extensions_common_workload_discovery_discovery_proto_rawDesc, + NumEnums: 1, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_source_extensions_common_workload_discovery_discovery_proto_goTypes, + DependencyIndexes: file_source_extensions_common_workload_discovery_discovery_proto_depIdxs, + EnumInfos: file_source_extensions_common_workload_discovery_discovery_proto_enumTypes, + MessageInfos: file_source_extensions_common_workload_discovery_discovery_proto_msgTypes, + }.Build() + File_source_extensions_common_workload_discovery_discovery_proto = out.File + file_source_extensions_common_workload_discovery_discovery_proto_rawDesc = nil + file_source_extensions_common_workload_discovery_discovery_proto_goTypes = nil + file_source_extensions_common_workload_discovery_discovery_proto_depIdxs = nil +} diff --git a/testdata/bootstrap/server.yaml.tmpl b/testdata/bootstrap/server.yaml.tmpl index 02f616b92b2..d4cb31a4902 100644 --- a/testdata/bootstrap/server.yaml.tmpl +++ b/testdata/bootstrap/server.yaml.tmpl @@ -11,7 +11,11 @@ admin: {{ .Vars.StatsConfig }} dynamic_resources: ads_config: +{{- if eq .Vars.EnableDelta "true" }} + api_type: DELTA_GRPC +{{- else }} api_type: GRPC +{{- end}} transport_api_version: V3 grpc_services: - envoy_grpc: @@ -60,12 +64,6 @@ static_resources: socket_address: address: 127.0.0.1 port_value: {{ .Ports.BackendPort }} - {{- if eq .Vars.EnableEndpointMetadata "true" }} - metadata: - filter_metadata: - istio: - workload: ratings-v1;default;ratings;version-1;server-cluster - {{- end }} {{ .Vars.ServerStaticCluster | indent 2 }} {{- if ne .Vars.DisableDirectResponse "true" }} listeners: @@ -107,3 +105,12 @@ bootstrap_extensions: typed_config: "@type": type.googleapis.com/udpa.type.v1.TypedStruct type_url: type.googleapis.com/envoy.extensions.bootstrap.internal_listener.v3.InternalListener +{{- if eq .Vars.EnableMetadataDiscovery "true" }} +- name: metadata_discovery + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/istio.workload.BootstrapExtension + value: + config_source: + ads: {} +{{- end }}