1
#include "source/extensions/clusters/static/static_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

            
7
#include "source/common/runtime/runtime_features.h"
8

            
9
namespace Envoy {
10
namespace Upstream {
11

            
12
StaticClusterImpl::StaticClusterImpl(const envoy::config::cluster::v3::Cluster& cluster,
13
                                     ClusterFactoryContext& context, absl::Status& creation_status)
14
16582
    : ClusterImplBase(cluster, context, creation_status) {
15
16582
  SET_AND_RETURN_IF_NOT_OK(creation_status, creation_status);
16
16575
  priority_state_manager_ = std::make_unique<PriorityStateManager>(
17
16575
      *this, context.serverFactoryContext().localInfo(), nullptr);
18
16575
  const envoy::config::endpoint::v3::ClusterLoadAssignment& cluster_load_assignment =
19
16575
      cluster.load_assignment();
20
16575
  overprovisioning_factor_ = PROTOBUF_GET_WRAPPED_OR_DEFAULT(
21
16575
      cluster_load_assignment.policy(), overprovisioning_factor, kDefaultOverProvisioningFactor);
22
16575
  weighted_priority_health_ = cluster_load_assignment.policy().weighted_priority_health();
23

            
24
16632
  for (const auto& locality_lb_endpoint : cluster_load_assignment.endpoints()) {
25
16433
    priority_state_manager_->initializePriorityFor(locality_lb_endpoint);
26
16867
    for (const auto& lb_endpoint : locality_lb_endpoint.lb_endpoints()) {
27
16866
      std::vector<Network::Address::InstanceConstSharedPtr> address_list;
28
16866
      if (!lb_endpoint.endpoint().additional_addresses().empty()) {
29
4
        address_list.emplace_back(
30
4
            THROW_OR_RETURN_VALUE(resolveProtoAddress(lb_endpoint.endpoint().address()),
31
4
                                  const Network::Address::InstanceConstSharedPtr));
32
4
        for (const auto& additional_address : lb_endpoint.endpoint().additional_addresses()) {
33
4
          Network::Address::InstanceConstSharedPtr address =
34
4
              returnOrThrow(resolveProtoAddress(additional_address.address()));
35
4
          address_list.emplace_back(address);
36
4
        }
37
4
        if (!Runtime::runtimeFeatureEnabled(
38
4
                "envoy.reloadable_features.happy_eyeballs_sort_non_ip_addresses")) {
39
2
          for (const Network::Address::InstanceConstSharedPtr& address : address_list) {
40
            // All addresses must by IP addresses.
41
2
            if (!address->ip()) {
42
1
              throwEnvoyExceptionOrPanic("additional_addresses must be IP addresses.");
43
1
            }
44
2
          }
45
1
        }
46
4
      }
47
16865
      priority_state_manager_->registerHostForPriority(
48
16865
          lb_endpoint.endpoint().hostname(),
49
16865
          THROW_OR_RETURN_VALUE(resolveProtoAddress(lb_endpoint.endpoint().address()),
50
16865
                                const Network::Address::InstanceConstSharedPtr),
51
16865
          address_list, locality_lb_endpoint, lb_endpoint);
52
16865
    }
53
16433
  }
54

            
55
16574
  THROW_IF_NOT_OK(validateEndpoints(cluster_load_assignment.endpoints(),
56
16574
                                    priority_state_manager_->priorityState()));
57
16574
}
58

            
59
16538
void StaticClusterImpl::startPreInit() {
60
  // At this point see if we have a health checker. If so, mark all the hosts unhealthy and
61
  // then fire update callbacks to start the health checking process.
62
16538
  const auto& health_checker_flag =
63
16538
      health_checker_ != nullptr
64
16538
          ? absl::optional<Upstream::Host::HealthFlag>(Host::HealthFlag::FAILED_ACTIVE_HC)
65
16538
          : absl::nullopt;
66

            
67
16538
  auto& priority_state = priority_state_manager_->priorityState();
68
32928
  for (size_t i = 0; i < priority_state.size(); ++i) {
69
16390
    if (priority_state[i].first == nullptr) {
70
1
      priority_state[i].first = std::make_unique<HostVector>();
71
1
    }
72
16390
    priority_state_manager_->updateClusterPrioritySet(
73
16390
        i, std::move(priority_state[i].first), absl::nullopt, absl::nullopt, health_checker_flag,
74
16390
        weighted_priority_health_, overprovisioning_factor_);
75
16390
  }
76
16538
  priority_state_manager_.reset();
77

            
78
16538
  onPreInitComplete();
79
16538
}
80

            
81
absl::StatusOr<std::pair<ClusterImplBaseSharedPtr, ThreadAwareLoadBalancerPtr>>
82
StaticClusterFactory::createClusterImpl(const envoy::config::cluster::v3::Cluster& cluster,
83
16583
                                        ClusterFactoryContext& context) {
84
16583
  const envoy::config::endpoint::v3::ClusterLoadAssignment& cluster_load_assignment =
85
16583
      cluster.load_assignment();
86
16640
  for (const auto& locality_lb_endpoint : cluster_load_assignment.endpoints()) {
87
    // TODO(adisuissa): Implement LEDS support for STATIC clusters.
88
16440
    if (locality_lb_endpoint.has_leds_cluster_locality_config()) {
89
1
      return absl::InvalidArgumentError(
90
1
          fmt::format("LEDS is only supported when EDS is used. Static cluster {} cannot use LEDS.",
91
1
                      cluster.name()));
92
1
    }
93
16440
  }
94
16582
  absl::Status creation_status = absl::OkStatus();
95
16582
  auto ret = std::make_pair(
96
16582
      std::shared_ptr<StaticClusterImpl>(new StaticClusterImpl(cluster, context, creation_status)),
97
16582
      nullptr);
98
16582
  RETURN_IF_NOT_OK(creation_status);
99
16575
  return ret;
100
16582
}
101

            
102
/**
103
 * Static registration for the static cluster factory. @see RegisterFactory.
104
 */
105
REGISTER_FACTORY(StaticClusterFactory, ClusterFactory);
106

            
107
} // namespace Upstream
108
} // namespace Envoy