1
#pragma once
2

            
3
#include "envoy/config/cluster/v3/cluster.pb.h"
4
#include "envoy/config/endpoint/v3/endpoint_components.pb.h"
5
#include "envoy/extensions/clusters/dns/v3/dns_cluster.pb.h"
6
#include "envoy/extensions/clusters/dns/v3/dns_cluster.pb.validate.h"
7

            
8
#include "source/common/upstream/cluster_factory_impl.h"
9
#include "source/common/upstream/upstream_impl.h"
10

            
11
namespace Envoy {
12
namespace Upstream {
13

            
14
class LogicalDnsClusterTest;
15

            
16
/**
17
 * Factory for DnsClusterImpl
18
 */
19

            
20
class DnsClusterFactory : public Upstream::ConfigurableClusterFactoryBase<
21
                              envoy::extensions::clusters::dns::v3::DnsCluster> {
22
public:
23
194
  DnsClusterFactory() : ConfigurableClusterFactoryBase("envoy.cluster.dns") {}
24

            
25
private:
26
  friend class LogicalDnsClusterTest;
27
  absl::StatusOr<
28
      std::pair<Upstream::ClusterImplBaseSharedPtr, Upstream::ThreadAwareLoadBalancerPtr>>
29
  createClusterWithConfig(const envoy::config::cluster::v3::Cluster& cluster,
30
                          const envoy::extensions::clusters::dns::v3::DnsCluster& proto_config,
31
                          Upstream::ClusterFactoryContext& context) override;
32
};
33

            
34
class DnsClusterImpl : public BaseDynamicClusterImpl {
35
public:
36
  // Upstream::Cluster
37
  InitializePhase initializePhase() const override { return InitializePhase::Primary; }
38
  static absl::StatusOr<std::unique_ptr<DnsClusterImpl>>
39
  create(const envoy::config::cluster::v3::Cluster& cluster,
40
         const envoy::extensions::clusters::dns::v3::DnsCluster& dns_cluster,
41
         ClusterFactoryContext& context, Network::DnsResolverSharedPtr dns_resolver);
42

            
43
protected:
44
  DnsClusterImpl(const envoy::config::cluster::v3::Cluster& cluster,
45
                 const envoy::extensions::clusters::dns::v3::DnsCluster& dns_cluster,
46
                 ClusterFactoryContext& context, Network::DnsResolverSharedPtr dns_resolver,
47
                 absl::Status& creation_status);
48

            
49
private:
50
  struct ResolveTarget {
51
    ResolveTarget(DnsClusterImpl& parent, Event::Dispatcher& dispatcher,
52
                  const std::string& dns_address, const uint32_t dns_port,
53
                  const envoy::config::endpoint::v3::LocalityLbEndpoints& locality_lb_endpoint,
54
                  const envoy::config::endpoint::v3::LbEndpoint& lb_endpoint);
55
    ~ResolveTarget();
56
    void startResolve();
57
    bool isSuccessfulResponse(const std::list<Network::DnsResponse>& response,
58
                              const Network::DnsResolver::ResolutionStatus& status);
59

            
60
    struct ParsedHosts {
61
      HostVector hosts;
62
      std::chrono::seconds ttl_refresh_rate = std::chrono::seconds::max();
63
      absl::flat_hash_set<std::string> host_addresses;
64
    };
65
    absl::StatusOr<ParsedHosts>
66
    createLogicalDnsHosts(const std::list<Network::DnsResponse>& response);
67
    absl::StatusOr<ParsedHosts>
68
    createStrictDnsHosts(const std::list<Network::DnsResponse>& response);
69
    void updateLogicalDnsHosts(const std::list<Network::DnsResponse>& response,
70
                               const ParsedHosts& new_hosts);
71
    void updateStrictDnsHosts(const ParsedHosts& new_hosts);
72

            
73
    DnsClusterImpl& parent_;
74
    Network::ActiveDnsQuery* active_query_{};
75
    const envoy::config::endpoint::v3::LocalityLbEndpoints& locality_lb_endpoints_;
76
    const envoy::config::endpoint::v3::LbEndpoint& lb_endpoint_;
77
    const std::string dns_address_;
78
    const std::string hostname_;
79
    const uint32_t port_;
80
    const Event::TimerPtr resolve_timer_;
81
    HostVector hosts_;
82

            
83
    // Host map for current resolve target. When we have multiple resolve targets, multiple targets
84
    // may contain two different hosts with the same address. This has two effects:
85
    // 1) This host map cannot be replaced by the cross-priority global host map in the priority
86
    // set.
87
    // 2) Cross-priority global host map may not be able to search for the expected host based on
88
    // the address.
89
    HostMap all_hosts_;
90

            
91
    // These attributes are only used for logical DNS resolution. We use them to keep track of the
92
    // previous responses, so we can check and update the hosts only when the DNS response changes.
93
    // We cache those values here to avoid fetching them from the logical hosts, as that requires
94
    // synchronization mechanisms.
95
    Network::Address::InstanceConstSharedPtr logic_dns_cached_address_;
96
    std::vector<Network::Address::InstanceConstSharedPtr> logic_dns_cached_address_list_;
97
  };
98

            
99
  using ResolveTargetPtr = std::unique_ptr<ResolveTarget>;
100

            
101
  void updateAllHosts(const HostVector& hosts_added, const HostVector& hosts_removed,
102
                      uint32_t priority);
103

            
104
  // ClusterImplBase
105
  void startPreInit() override;
106

            
107
  static envoy::config::endpoint::v3::ClusterLoadAssignment
108
  extractAndProcessLoadAssignment(const envoy::config::cluster::v3::Cluster& cluster,
109
                                  bool all_addresses_in_single_endpoint);
110

            
111
  // Keep load assignment as a member to make sure its data referenced in
112
  // resolve_targets_ outlives them.
113
  const envoy::config::endpoint::v3::ClusterLoadAssignment load_assignment_;
114
  const LocalInfo::LocalInfo& local_info_;
115
  Network::DnsResolverSharedPtr dns_resolver_;
116
  std::list<ResolveTargetPtr> resolve_targets_;
117
  const std::chrono::milliseconds dns_refresh_rate_ms_;
118
  const std::chrono::milliseconds dns_jitter_ms_;
119
  BackOffStrategyPtr failure_backoff_strategy_;
120
  const bool respect_dns_ttl_;
121
  Network::DnsLookupFamily dns_lookup_family_;
122
  uint32_t overprovisioning_factor_;
123
  bool weighted_priority_health_;
124
  bool all_addresses_in_single_endpoint_;
125
};
126

            
127
DECLARE_FACTORY(DnsClusterFactory);
128

            
129
} // namespace Upstream
130
} // namespace Envoy