LCOV - code coverage report
Current view: top level - source/extensions/clusters/strict_dns - strict_dns_cluster.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 128 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 9 0.0 %

          Line data    Source code
       1             : #include "source/extensions/clusters/strict_dns/strict_dns_cluster.h"
       2             : 
       3             : #include "envoy/common/exception.h"
       4             : #include "envoy/config/cluster/v3/cluster.pb.h"
       5             : #include "envoy/config/endpoint/v3/endpoint.pb.h"
       6             : #include "envoy/config/endpoint/v3/endpoint_components.pb.h"
       7             : 
       8             : namespace Envoy {
       9             : namespace Upstream {
      10             : 
      11             : StrictDnsClusterImpl::StrictDnsClusterImpl(const envoy::config::cluster::v3::Cluster& cluster,
      12             :                                            ClusterFactoryContext& context,
      13             :                                            Network::DnsResolverSharedPtr dns_resolver)
      14             :     : BaseDynamicClusterImpl(cluster, context), load_assignment_(cluster.load_assignment()),
      15             :       local_info_(context.serverFactoryContext().localInfo()), dns_resolver_(dns_resolver),
      16             :       dns_refresh_rate_ms_(
      17             :           std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(cluster, dns_refresh_rate, 5000))),
      18           0 :       respect_dns_ttl_(cluster.respect_dns_ttl()) {
      19           0 :   failure_backoff_strategy_ =
      20           0 :       Config::Utility::prepareDnsRefreshStrategy<envoy::config::cluster::v3::Cluster>(
      21           0 :           cluster, dns_refresh_rate_ms_.count(),
      22           0 :           context.serverFactoryContext().api().randomGenerator());
      23             : 
      24           0 :   std::list<ResolveTargetPtr> resolve_targets;
      25           0 :   const auto& locality_lb_endpoints = load_assignment_.endpoints();
      26           0 :   for (const auto& locality_lb_endpoint : locality_lb_endpoints) {
      27           0 :     validateEndpointsForZoneAwareRouting(locality_lb_endpoint);
      28             : 
      29           0 :     for (const auto& lb_endpoint : locality_lb_endpoint.lb_endpoints()) {
      30           0 :       const auto& socket_address = lb_endpoint.endpoint().address().socket_address();
      31           0 :       if (!socket_address.resolver_name().empty()) {
      32           0 :         throw EnvoyException("STRICT_DNS clusters must NOT have a custom resolver name set");
      33           0 :       }
      34             : 
      35           0 :       resolve_targets.emplace_back(new ResolveTarget(
      36           0 :           *this, context.serverFactoryContext().mainThreadDispatcher(), socket_address.address(),
      37           0 :           socket_address.port_value(), locality_lb_endpoint, lb_endpoint));
      38           0 :     }
      39           0 :   }
      40           0 :   resolve_targets_ = std::move(resolve_targets);
      41           0 :   dns_lookup_family_ = getDnsLookupFamilyFromCluster(cluster);
      42             : 
      43           0 :   overprovisioning_factor_ = PROTOBUF_GET_WRAPPED_OR_DEFAULT(
      44           0 :       load_assignment_.policy(), overprovisioning_factor, kDefaultOverProvisioningFactor);
      45           0 :   weighted_priority_health_ = load_assignment_.policy().weighted_priority_health();
      46           0 : }
      47             : 
      48           0 : void StrictDnsClusterImpl::startPreInit() {
      49           0 :   for (const ResolveTargetPtr& target : resolve_targets_) {
      50           0 :     target->startResolve();
      51           0 :   }
      52             :   // If the config provides no endpoints, the cluster is initialized immediately as if all hosts are
      53             :   // resolved in failure.
      54           0 :   if (resolve_targets_.empty() || !wait_for_warm_on_init_) {
      55           0 :     onPreInitComplete();
      56           0 :   }
      57           0 : }
      58             : 
      59             : void StrictDnsClusterImpl::updateAllHosts(const HostVector& hosts_added,
      60             :                                           const HostVector& hosts_removed,
      61           0 :                                           uint32_t current_priority) {
      62           0 :   PriorityStateManager priority_state_manager(*this, local_info_, nullptr);
      63             :   // At this point we know that we are different so make a new host list and notify.
      64             :   //
      65             :   // TODO(dio): The uniqueness of a host address resolved in STRICT_DNS cluster per priority is not
      66             :   // guaranteed. Need a clear agreement on the behavior here, whether it is allowable to have
      67             :   // duplicated hosts inside a priority. And if we want to enforce this behavior, it should be done
      68             :   // inside the priority state manager.
      69           0 :   for (const ResolveTargetPtr& target : resolve_targets_) {
      70           0 :     priority_state_manager.initializePriorityFor(target->locality_lb_endpoints_);
      71           0 :     for (const HostSharedPtr& host : target->hosts_) {
      72           0 :       if (target->locality_lb_endpoints_.priority() == current_priority) {
      73           0 :         priority_state_manager.registerHostForPriority(host, target->locality_lb_endpoints_);
      74           0 :       }
      75           0 :     }
      76           0 :   }
      77             : 
      78             :   // TODO(dio): Add assertion in here.
      79           0 :   priority_state_manager.updateClusterPrioritySet(
      80           0 :       current_priority, std::move(priority_state_manager.priorityState()[current_priority].first),
      81           0 :       hosts_added, hosts_removed, absl::nullopt, weighted_priority_health_,
      82           0 :       overprovisioning_factor_);
      83           0 : }
      84             : 
      85             : StrictDnsClusterImpl::ResolveTarget::ResolveTarget(
      86             :     StrictDnsClusterImpl& parent, Event::Dispatcher& dispatcher, const std::string& dns_address,
      87             :     const uint32_t dns_port,
      88             :     const envoy::config::endpoint::v3::LocalityLbEndpoints& locality_lb_endpoint,
      89             :     const envoy::config::endpoint::v3::LbEndpoint& lb_endpoint)
      90             :     : parent_(parent), locality_lb_endpoints_(locality_lb_endpoint), lb_endpoint_(lb_endpoint),
      91             :       dns_address_(dns_address),
      92             :       hostname_(lb_endpoint_.endpoint().hostname().empty() ? dns_address_
      93             :                                                            : lb_endpoint_.endpoint().hostname()),
      94             :       port_(dns_port),
      95           0 :       resolve_timer_(dispatcher.createTimer([this]() -> void { startResolve(); })) {}
      96             : 
      97           0 : StrictDnsClusterImpl::ResolveTarget::~ResolveTarget() {
      98           0 :   if (active_query_) {
      99           0 :     active_query_->cancel(Network::ActiveDnsQuery::CancelReason::QueryAbandoned);
     100           0 :   }
     101           0 : }
     102             : 
     103           0 : void StrictDnsClusterImpl::ResolveTarget::startResolve() {
     104           0 :   ENVOY_LOG(trace, "starting async DNS resolution for {}", dns_address_);
     105           0 :   parent_.info_->configUpdateStats().update_attempt_.inc();
     106             : 
     107           0 :   active_query_ = parent_.dns_resolver_->resolve(
     108           0 :       dns_address_, parent_.dns_lookup_family_,
     109           0 :       [this](Network::DnsResolver::ResolutionStatus status,
     110           0 :              std::list<Network::DnsResponse>&& response) -> void {
     111           0 :         active_query_ = nullptr;
     112           0 :         ENVOY_LOG(trace, "async DNS resolution complete for {}", dns_address_);
     113             : 
     114           0 :         std::chrono::milliseconds final_refresh_rate = parent_.dns_refresh_rate_ms_;
     115             : 
     116           0 :         if (status == Network::DnsResolver::ResolutionStatus::Success) {
     117           0 :           parent_.info_->configUpdateStats().update_success_.inc();
     118             : 
     119           0 :           HostVector new_hosts;
     120           0 :           std::chrono::seconds ttl_refresh_rate = std::chrono::seconds::max();
     121           0 :           absl::flat_hash_set<std::string> all_new_hosts;
     122           0 :           for (const auto& resp : response) {
     123           0 :             const auto& addrinfo = resp.addrInfo();
     124             :             // TODO(mattklein123): Currently the DNS interface does not consider port. We need to
     125             :             // make a new address that has port in it. We need to both support IPv6 as well as
     126             :             // potentially move port handling into the DNS interface itself, which would work better
     127             :             // for SRV.
     128           0 :             ASSERT(addrinfo.address_ != nullptr);
     129           0 :             auto address = Network::Utility::getAddressWithPort(*(addrinfo.address_), port_);
     130           0 :             if (all_new_hosts.count(address->asString()) > 0) {
     131           0 :               continue;
     132           0 :             }
     133             : 
     134           0 :             new_hosts.emplace_back(new HostImpl(
     135           0 :                 parent_.info_, hostname_, address,
     136             :                 // TODO(zyfjeff): Created through metadata shared pool
     137           0 :                 std::make_shared<const envoy::config::core::v3::Metadata>(lb_endpoint_.metadata()),
     138           0 :                 lb_endpoint_.load_balancing_weight().value(), locality_lb_endpoints_.locality(),
     139           0 :                 lb_endpoint_.endpoint().health_check_config(), locality_lb_endpoints_.priority(),
     140           0 :                 lb_endpoint_.health_status(), parent_.time_source_));
     141           0 :             all_new_hosts.emplace(address->asString());
     142           0 :             ttl_refresh_rate = min(ttl_refresh_rate, addrinfo.ttl_);
     143           0 :           }
     144             : 
     145           0 :           HostVector hosts_added;
     146           0 :           HostVector hosts_removed;
     147           0 :           if (parent_.updateDynamicHostList(new_hosts, hosts_, hosts_added, hosts_removed,
     148           0 :                                             all_hosts_, all_new_hosts)) {
     149           0 :             ENVOY_LOG(debug, "DNS hosts have changed for {}", dns_address_);
     150           0 :             ASSERT(std::all_of(hosts_.begin(), hosts_.end(), [&](const auto& host) {
     151           0 :               return host->priority() == locality_lb_endpoints_.priority();
     152           0 :             }));
     153             : 
     154             :             // Update host map for current resolve target.
     155           0 :             for (const auto& host : hosts_removed) {
     156           0 :               all_hosts_.erase(host->address()->asString());
     157           0 :             }
     158           0 :             for (const auto& host : hosts_added) {
     159           0 :               all_hosts_.insert({host->address()->asString(), host});
     160           0 :             }
     161             : 
     162           0 :             parent_.updateAllHosts(hosts_added, hosts_removed, locality_lb_endpoints_.priority());
     163           0 :           } else {
     164           0 :             parent_.info_->configUpdateStats().update_no_rebuild_.inc();
     165           0 :           }
     166             : 
     167             :           // reset failure backoff strategy because there was a success.
     168           0 :           parent_.failure_backoff_strategy_->reset();
     169             : 
     170           0 :           if (!response.empty() && parent_.respect_dns_ttl_ &&
     171           0 :               ttl_refresh_rate != std::chrono::seconds(0)) {
     172           0 :             final_refresh_rate = ttl_refresh_rate;
     173           0 :             ASSERT(ttl_refresh_rate != std::chrono::seconds::max() &&
     174           0 :                    final_refresh_rate.count() > 0);
     175           0 :           }
     176           0 :           ENVOY_LOG(debug, "DNS refresh rate reset for {}, refresh rate {} ms", dns_address_,
     177           0 :                     final_refresh_rate.count());
     178           0 :         } else {
     179           0 :           parent_.info_->configUpdateStats().update_failure_.inc();
     180             : 
     181           0 :           final_refresh_rate =
     182           0 :               std::chrono::milliseconds(parent_.failure_backoff_strategy_->nextBackOffMs());
     183           0 :           ENVOY_LOG(debug, "DNS refresh rate reset for {}, (failure) refresh rate {} ms",
     184           0 :                     dns_address_, final_refresh_rate.count());
     185           0 :         }
     186             : 
     187             :         // If there is an initialize callback, fire it now. Note that if the cluster refers to
     188             :         // multiple DNS names, this will return initialized after a single DNS resolution
     189             :         // completes. This is not perfect but is easier to code and unclear if the extra
     190             :         // complexity is needed so will start with this.
     191           0 :         parent_.onPreInitComplete();
     192           0 :         resolve_timer_->enableTimer(final_refresh_rate);
     193           0 :       });
     194           0 : }
     195             : 
     196             : absl::StatusOr<std::pair<ClusterImplBaseSharedPtr, ThreadAwareLoadBalancerPtr>>
     197             : StrictDnsClusterFactory::createClusterImpl(const envoy::config::cluster::v3::Cluster& cluster,
     198           0 :                                            ClusterFactoryContext& context) {
     199           0 :   auto selected_dns_resolver = selectDnsResolver(cluster, context);
     200             : 
     201           0 :   return std::make_pair(
     202           0 :       std::make_shared<StrictDnsClusterImpl>(cluster, context, selected_dns_resolver), nullptr);
     203           0 : }
     204             : 
     205             : /**
     206             :  * Static registration for the strict dns cluster factory. @see RegisterFactory.
     207             :  */
     208             : REGISTER_FACTORY(StrictDnsClusterFactory, ClusterFactory);
     209             : 
     210             : } // namespace Upstream
     211             : } // namespace Envoy

Generated by: LCOV version 1.15