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

          Line data    Source code
       1             : #include "source/extensions/clusters/logical_dns/logical_dns_cluster.h"
       2             : 
       3             : #include <chrono>
       4             : #include <list>
       5             : #include <memory>
       6             : #include <string>
       7             : #include <vector>
       8             : 
       9             : #include "envoy/common/exception.h"
      10             : #include "envoy/config/cluster/v3/cluster.pb.h"
      11             : #include "envoy/config/core/v3/address.pb.h"
      12             : #include "envoy/config/endpoint/v3/endpoint.pb.h"
      13             : #include "envoy/stats/scope.h"
      14             : 
      15             : #include "source/common/common/dns_utils.h"
      16             : #include "source/common/common/fmt.h"
      17             : #include "source/common/config/utility.h"
      18             : #include "source/common/network/address_impl.h"
      19             : #include "source/common/network/utility.h"
      20             : #include "source/common/protobuf/protobuf.h"
      21             : #include "source/common/protobuf/utility.h"
      22             : 
      23             : namespace Envoy {
      24             : namespace Upstream {
      25             : 
      26             : namespace {
      27             : envoy::config::endpoint::v3::ClusterLoadAssignment
      28           0 : convertPriority(const envoy::config::endpoint::v3::ClusterLoadAssignment& load_assignment) {
      29           0 :   envoy::config::endpoint::v3::ClusterLoadAssignment converted;
      30           0 :   converted.MergeFrom(load_assignment);
      31             : 
      32             :   // We convert the priority set by the configuration back to zero. This helps
      33             :   // ensure that we don't blow up later on when using zone aware routing due
      34             :   // to a check that all priorities are zero.
      35             :   //
      36             :   // Since LOGICAL_DNS is limited to exactly one host declared per load_assignment
      37             :   // (checked in the ctor in this file), we can safely just rewrite the priority
      38             :   // to zero.
      39           0 :   for (auto& endpoint : *converted.mutable_endpoints()) {
      40           0 :     endpoint.set_priority(0);
      41           0 :   }
      42             : 
      43           0 :   return converted;
      44           0 : }
      45             : } // namespace
      46             : 
      47             : LogicalDnsCluster::LogicalDnsCluster(const envoy::config::cluster::v3::Cluster& cluster,
      48             :                                      ClusterFactoryContext& context,
      49             :                                      Network::DnsResolverSharedPtr dns_resolver)
      50             :     : ClusterImplBase(cluster, context), dns_resolver_(dns_resolver),
      51             :       dns_refresh_rate_ms_(
      52             :           std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(cluster, dns_refresh_rate, 5000))),
      53             :       respect_dns_ttl_(cluster.respect_dns_ttl()),
      54             :       resolve_timer_(context.serverFactoryContext().mainThreadDispatcher().createTimer(
      55           0 :           [this]() -> void { startResolve(); })),
      56             :       local_info_(context.serverFactoryContext().localInfo()),
      57           0 :       load_assignment_(convertPriority(cluster.load_assignment())) {
      58           0 :   failure_backoff_strategy_ =
      59           0 :       Config::Utility::prepareDnsRefreshStrategy<envoy::config::cluster::v3::Cluster>(
      60           0 :           cluster, dns_refresh_rate_ms_.count(),
      61           0 :           context.serverFactoryContext().api().randomGenerator());
      62             : 
      63           0 :   const envoy::config::core::v3::SocketAddress& socket_address =
      64           0 :       lbEndpoint().endpoint().address().socket_address();
      65             : 
      66             :   // Checked by factory;
      67           0 :   ASSERT(socket_address.resolver_name().empty());
      68           0 :   dns_address_ = socket_address.address();
      69           0 :   dns_port_ = socket_address.port_value();
      70             : 
      71           0 :   if (lbEndpoint().endpoint().hostname().empty()) {
      72           0 :     hostname_ = dns_address_;
      73           0 :   } else {
      74           0 :     hostname_ = lbEndpoint().endpoint().hostname();
      75           0 :   }
      76           0 :   dns_lookup_family_ = getDnsLookupFamilyFromCluster(cluster);
      77           0 : }
      78             : 
      79           0 : void LogicalDnsCluster::startPreInit() {
      80           0 :   startResolve();
      81           0 :   if (!wait_for_warm_on_init_) {
      82           0 :     onPreInitComplete();
      83           0 :   }
      84           0 : }
      85             : 
      86           0 : LogicalDnsCluster::~LogicalDnsCluster() {
      87           0 :   if (active_dns_query_) {
      88           0 :     active_dns_query_->cancel(Network::ActiveDnsQuery::CancelReason::QueryAbandoned);
      89           0 :   }
      90           0 : }
      91             : 
      92           0 : void LogicalDnsCluster::startResolve() {
      93           0 :   ENVOY_LOG(trace, "starting async DNS resolution for {}", dns_address_);
      94           0 :   info_->configUpdateStats().update_attempt_.inc();
      95             : 
      96           0 :   active_dns_query_ = dns_resolver_->resolve(
      97           0 :       dns_address_, dns_lookup_family_,
      98           0 :       [this](Network::DnsResolver::ResolutionStatus status,
      99           0 :              std::list<Network::DnsResponse>&& response) -> void {
     100           0 :         active_dns_query_ = nullptr;
     101           0 :         ENVOY_LOG(trace, "async DNS resolution complete for {}", dns_address_);
     102             : 
     103           0 :         std::chrono::milliseconds final_refresh_rate = dns_refresh_rate_ms_;
     104             : 
     105             :         // If the DNS resolver successfully resolved with an empty response list, the logical DNS
     106             :         // cluster does not update. This ensures that a potentially previously resolved address does
     107             :         // not stabilize back to 0 hosts.
     108           0 :         if (status == Network::DnsResolver::ResolutionStatus::Success && !response.empty()) {
     109           0 :           info_->configUpdateStats().update_success_.inc();
     110           0 :           const auto addrinfo = response.front().addrInfo();
     111             :           // TODO(mattklein123): Move port handling into the DNS interface.
     112           0 :           ASSERT(addrinfo.address_ != nullptr);
     113           0 :           Network::Address::InstanceConstSharedPtr new_address =
     114           0 :               Network::Utility::getAddressWithPort(*(response.front().addrInfo().address_),
     115           0 :                                                    dns_port_);
     116           0 :           auto address_list = DnsUtils::generateAddressList(response, dns_port_);
     117             : 
     118           0 :           if (!logical_host_) {
     119           0 :             logical_host_ = std::make_shared<LogicalHost>(info_, hostname_, new_address,
     120           0 :                                                           address_list, localityLbEndpoint(),
     121           0 :                                                           lbEndpoint(), nullptr, time_source_);
     122             : 
     123           0 :             const auto& locality_lb_endpoint = localityLbEndpoint();
     124           0 :             PriorityStateManager priority_state_manager(*this, local_info_, nullptr);
     125           0 :             priority_state_manager.initializePriorityFor(locality_lb_endpoint);
     126           0 :             priority_state_manager.registerHostForPriority(logical_host_, locality_lb_endpoint);
     127             : 
     128           0 :             const uint32_t priority = locality_lb_endpoint.priority();
     129           0 :             priority_state_manager.updateClusterPrioritySet(
     130           0 :                 priority, std::move(priority_state_manager.priorityState()[priority].first),
     131           0 :                 absl::nullopt, absl::nullopt, absl::nullopt, absl::nullopt, absl::nullopt);
     132           0 :           }
     133             : 
     134           0 :           if (!current_resolved_address_ ||
     135           0 :               (*new_address != *current_resolved_address_ ||
     136           0 :                DnsUtils::listChanged(address_list, current_resolved_address_list_))) {
     137           0 :             current_resolved_address_ = new_address;
     138           0 :             current_resolved_address_list_ = address_list;
     139             : 
     140             :             // Make sure that we have an updated address for admin display, health
     141             :             // checking, and creating real host connections.
     142           0 :             logical_host_->setNewAddresses(new_address, address_list, lbEndpoint());
     143           0 :           }
     144             : 
     145             :           // reset failure backoff strategy because there was a success.
     146           0 :           failure_backoff_strategy_->reset();
     147             : 
     148           0 :           if (respect_dns_ttl_ && addrinfo.ttl_ != std::chrono::seconds(0)) {
     149           0 :             final_refresh_rate = addrinfo.ttl_;
     150           0 :           }
     151           0 :           ENVOY_LOG(debug, "DNS refresh rate reset for {}, refresh rate {} ms", dns_address_,
     152           0 :                     final_refresh_rate.count());
     153           0 :         } else {
     154           0 :           info_->configUpdateStats().update_failure_.inc();
     155           0 :           final_refresh_rate =
     156           0 :               std::chrono::milliseconds(failure_backoff_strategy_->nextBackOffMs());
     157           0 :           ENVOY_LOG(debug, "DNS refresh rate reset for {}, (failure) refresh rate {} ms",
     158           0 :                     dns_address_, final_refresh_rate.count());
     159           0 :         }
     160             : 
     161           0 :         onPreInitComplete();
     162           0 :         resolve_timer_->enableTimer(final_refresh_rate);
     163           0 :       });
     164           0 : }
     165             : 
     166             : absl::StatusOr<std::pair<ClusterImplBaseSharedPtr, ThreadAwareLoadBalancerPtr>>
     167             : LogicalDnsClusterFactory::createClusterImpl(const envoy::config::cluster::v3::Cluster& cluster,
     168           0 :                                             ClusterFactoryContext& context) {
     169           0 :   auto selected_dns_resolver = selectDnsResolver(cluster, context);
     170             : 
     171           0 :   const auto& load_assignment = cluster.load_assignment();
     172           0 :   const auto& locality_lb_endpoints = load_assignment.endpoints();
     173           0 :   if (locality_lb_endpoints.size() != 1 || locality_lb_endpoints[0].lb_endpoints().size() != 1) {
     174           0 :     if (cluster.has_load_assignment()) {
     175           0 :       return absl::InvalidArgumentError(
     176           0 :           "LOGICAL_DNS clusters must have a single locality_lb_endpoint and a single lb_endpoint");
     177           0 :     } else {
     178           0 :       return absl::InvalidArgumentError("LOGICAL_DNS clusters must have a single host");
     179           0 :     }
     180           0 :   }
     181             : 
     182           0 :   const envoy::config::core::v3::SocketAddress& socket_address =
     183           0 :       locality_lb_endpoints[0].lb_endpoints()[0].endpoint().address().socket_address();
     184           0 :   if (!socket_address.resolver_name().empty()) {
     185           0 :     return absl::InvalidArgumentError(
     186           0 :         "LOGICAL_DNS clusters must NOT have a custom resolver name set");
     187           0 :   }
     188             : 
     189           0 :   return std::make_pair(std::shared_ptr<LogicalDnsCluster>(
     190           0 :                             new LogicalDnsCluster(cluster, context, selected_dns_resolver)),
     191           0 :                         nullptr);
     192           0 : }
     193             : 
     194             : /**
     195             :  * Static registration for the strict dns cluster factory. @see RegisterFactory.
     196             :  */
     197             : REGISTER_FACTORY(LogicalDnsClusterFactory, ClusterFactory);
     198             : 
     199             : } // namespace Upstream
     200             : } // namespace Envoy

Generated by: LCOV version 1.15