1
#include "source/common/upstream/cluster_factory_impl.h"
2

            
3
#include "envoy/config/cluster/v3/cluster.pb.h"
4
#include "envoy/server/options.h"
5

            
6
#include "source/common/http/utility.h"
7
#include "source/common/network/address_impl.h"
8
#include "source/common/network/dns_resolver/dns_factory_util.h"
9
#include "source/common/network/socket_option_factory.h"
10
#include "source/common/protobuf/protobuf.h"
11
#include "source/common/upstream/health_checker_impl.h"
12
#include "source/server/transport_socket_config_impl.h"
13

            
14
namespace Envoy {
15
namespace Upstream {
16

            
17
absl::StatusOr<std::pair<ClusterSharedPtr, ThreadAwareLoadBalancerPtr>>
18
ClusterFactoryImplBase::create(const envoy::config::cluster::v3::Cluster& cluster,
19
                               Server::Configuration::ServerFactoryContext& server_context,
20
                               LazyCreateDnsResolver dns_resolver_fn,
21
                               Outlier::EventLoggerSharedPtr outlier_event_logger,
22
17694
                               bool added_via_api) {
23
17694
  std::string cluster_name;
24
17694
  std::string cluster_config_type_name;
25

            
26
17694
  ClusterFactory* factory;
27
  // try to look up by typed_config
28
17694
  if (cluster.has_cluster_type() && cluster.cluster_type().has_typed_config() &&
29
17694
      (TypeUtil::typeUrlToDescriptorFullName(cluster.cluster_type().typed_config().type_url()) !=
30
180
       Protobuf::Struct::GetDescriptor()->full_name())) {
31
172
    cluster_config_type_name =
32
172
        TypeUtil::typeUrlToDescriptorFullName(cluster.cluster_type().typed_config().type_url());
33
172
    factory = Registry::FactoryRegistry<ClusterFactory>::getFactoryByType(cluster_config_type_name);
34
172
    if (factory == nullptr) {
35
1
      return absl::InvalidArgumentError(
36
1
          fmt::format("Didn't find a registered cluster factory implementation for type: '{}'",
37
1
                      cluster_config_type_name));
38
1
    }
39
17615
  } else {
40
17522
    if (!cluster.has_cluster_type()) {
41
17498
      switch (cluster.type()) {
42
        PANIC_ON_PROTO_ENUM_SENTINEL_VALUES;
43
16569
      case envoy::config::cluster::v3::Cluster::STATIC:
44
16569
        cluster_name = "envoy.cluster.static";
45
16569
        break;
46
242
      case envoy::config::cluster::v3::Cluster::STRICT_DNS:
47
242
        cluster_name = "envoy.cluster.strict_dns";
48
242
        break;
49
139
      case envoy::config::cluster::v3::Cluster::LOGICAL_DNS:
50
139
        cluster_name = "envoy.cluster.logical_dns";
51
139
        break;
52
17
      case envoy::config::cluster::v3::Cluster::ORIGINAL_DST:
53
17
        cluster_name = "envoy.cluster.original_dst";
54
17
        break;
55
531
      case envoy::config::cluster::v3::Cluster::EDS:
56
531
        cluster_name = "envoy.cluster.eds";
57
531
        break;
58
17498
      }
59
17502
    } else {
60
24
      cluster_name = cluster.cluster_type().name();
61
24
    }
62
17522
    factory = Registry::FactoryRegistry<ClusterFactory>::getFactory(cluster_name);
63
17522
    if (factory == nullptr) {
64
1
      return absl::InvalidArgumentError(fmt::format(
65
1
          "Didn't find a registered cluster factory implementation for name: '{}'", cluster_name));
66
1
    }
67
17522
  }
68

            
69
17692
  if (cluster.common_lb_config().has_consistent_hashing_lb_config() &&
70
17692
      cluster.common_lb_config().consistent_hashing_lb_config().use_hostname_for_hashing() &&
71
17692
      cluster.type() != envoy::config::cluster::v3::Cluster::STRICT_DNS) {
72
1
    return absl::InvalidArgumentError(fmt::format(
73
1
        "Cannot use hostname for consistent hashing loadbalancing for cluster of type: '{}'",
74
1
        cluster_name));
75
1
  }
76

            
77
17691
  ClusterFactoryContextImpl context(server_context, dns_resolver_fn,
78
17691
                                    std::move(outlier_event_logger), added_via_api);
79
17691
  return factory->create(cluster, context);
80
17692
}
81

            
82
absl::StatusOr<Network::DnsResolverSharedPtr>
83
ClusterFactoryImplBase::selectDnsResolver(const envoy::config::cluster::v3::Cluster& cluster,
84
393
                                          ClusterFactoryContext& context) {
85
  // We make this a shared pointer to deal with the distinct ownership
86
  // scenarios that can exist: in one case, we pass in the "default"
87
  // DNS resolver that is owned by the Server::Instance. In the case
88
  // where 'dns_resolvers' is specified, we have per-cluster DNS
89
  // resolvers that are created here but ownership resides with
90
  // StrictDnsClusterImpl/LogicalDnsCluster.
91
393
  if ((cluster.has_typed_dns_resolver_config() &&
92
393
       !(cluster.typed_dns_resolver_config().typed_config().type_url().empty())) ||
93
393
      (cluster.has_dns_resolution_config() &&
94
362
       !cluster.dns_resolution_config().resolvers().empty()) ||
95
393
      !cluster.dns_resolvers().empty()) {
96

            
97
54
    envoy::config::core::v3::TypedExtensionConfig typed_dns_resolver_config;
98
54
    Network::DnsResolverFactory& dns_resolver_factory =
99
54
        Network::createDnsResolverFactoryFromProto(cluster, typed_dns_resolver_config);
100
54
    auto& server_context = context.serverFactoryContext();
101
54
    return dns_resolver_factory.createDnsResolver(server_context.mainThreadDispatcher(),
102
54
                                                  server_context.api(), typed_dns_resolver_config);
103
54
  }
104

            
105
339
  return context.dnsResolver();
106
393
}
107

            
108
absl::StatusOr<Network::DnsResolverSharedPtr> ClusterFactoryImplBase::selectDnsResolver(
109
    const envoy::config::core::v3::TypedExtensionConfig& typed_dns_resolver_config,
110
140
    ClusterFactoryContext& context) {
111
140
  if (typed_dns_resolver_config.has_typed_config()) {
112
2
    Network::DnsResolverFactory& dns_resolver_factory =
113
2
        Network::createDnsResolverFactoryFromTypedConfig(typed_dns_resolver_config);
114
2
    auto& server_context = context.serverFactoryContext();
115
2
    return dns_resolver_factory.createDnsResolver(server_context.mainThreadDispatcher(),
116
2
                                                  server_context.api(), typed_dns_resolver_config);
117
2
  }
118
138
  return context.dnsResolver();
119
140
}
120

            
121
absl::StatusOr<std::pair<ClusterSharedPtr, ThreadAwareLoadBalancerPtr>>
122
ClusterFactoryImplBase::create(const envoy::config::cluster::v3::Cluster& cluster,
123
17896
                               ClusterFactoryContext& context) {
124

            
125
17896
  absl::StatusOr<std::pair<ClusterImplBaseSharedPtr, ThreadAwareLoadBalancerPtr>>
126
17896
      status_or_cluster = createClusterImpl(cluster, context);
127
17896
  RETURN_IF_NOT_OK_REF(status_or_cluster.status());
128
17823
  std::pair<ClusterImplBaseSharedPtr, ThreadAwareLoadBalancerPtr>& new_cluster_pair =
129
17823
      status_or_cluster.value();
130

            
131
17823
  auto& server_context = context.serverFactoryContext();
132

            
133
17823
  if (!cluster.health_checks().empty()) {
134
    // TODO(htuch): Need to support multiple health checks in v2.
135
94
    if (cluster.health_checks().size() != 1) {
136
1
      return absl::InvalidArgumentError("Multiple health checks not supported");
137
93
    } else {
138
93
      auto checker_or_error = HealthCheckerFactory::create(cluster.health_checks()[0],
139
93
                                                           *new_cluster_pair.first, server_context);
140
93
      RETURN_IF_NOT_OK_REF(checker_or_error.status());
141
93
      new_cluster_pair.first->setHealthChecker(checker_or_error.value());
142
93
    }
143
94
  }
144

            
145
17822
  auto detector_or_error = Outlier::DetectorImplFactory::createForCluster(
146
17822
      *new_cluster_pair.first, cluster, server_context.mainThreadDispatcher(),
147
17822
      server_context.runtime(), context.outlierEventLogger(),
148
17822
      server_context.api().randomGenerator());
149
17822
  RETURN_IF_NOT_OK_REF(detector_or_error.status());
150
17822
  new_cluster_pair.first->setOutlierDetector(detector_or_error.value());
151

            
152
17822
  return status_or_cluster;
153
17822
}
154

            
155
} // namespace Upstream
156
} // namespace Envoy