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
16627
    : ClusterImplBase(cluster, context, creation_status) {
15
16627
  SET_AND_RETURN_IF_NOT_OK(creation_status, creation_status);
16
16620
  priority_state_manager_ = std::make_unique<PriorityStateManager>(
17
16620
      *this, context.serverFactoryContext().localInfo(), nullptr);
18
16620
  const envoy::config::endpoint::v3::ClusterLoadAssignment& cluster_load_assignment =
19
16620
      cluster.load_assignment();
20
16620
  overprovisioning_factor_ = PROTOBUF_GET_WRAPPED_OR_DEFAULT(
21
16620
      cluster_load_assignment.policy(), overprovisioning_factor, kDefaultOverProvisioningFactor);
22
16620
  weighted_priority_health_ = cluster_load_assignment.policy().weighted_priority_health();
23

            
24
16677
  for (const auto& locality_lb_endpoint : cluster_load_assignment.endpoints()) {
25
16474
    priority_state_manager_->initializePriorityFor(locality_lb_endpoint);
26
16908
    for (const auto& lb_endpoint : locality_lb_endpoint.lb_endpoints()) {
27
16907
      std::vector<Network::Address::InstanceConstSharedPtr> address_list;
28
16907
      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
16906
      priority_state_manager_->registerHostForPriority(
48
16906
          lb_endpoint.endpoint().hostname(),
49
16906
          THROW_OR_RETURN_VALUE(resolveProtoAddress(lb_endpoint.endpoint().address()),
50
16906
                                const Network::Address::InstanceConstSharedPtr),
51
16906
          address_list, locality_lb_endpoint, lb_endpoint);
52
16906
    }
53
16474
  }
54

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

            
59
16583
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
16583
  const auto& health_checker_flag =
63
16583
      health_checker_ != nullptr
64
16583
          ? absl::optional<Upstream::Host::HealthFlag>(Host::HealthFlag::FAILED_ACTIVE_HC)
65
16583
          : absl::nullopt;
66

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

            
78
16583
  onPreInitComplete();
79
16583
}
80

            
81
absl::StatusOr<std::pair<ClusterImplBaseSharedPtr, ThreadAwareLoadBalancerPtr>>
82
StaticClusterFactory::createClusterImpl(const envoy::config::cluster::v3::Cluster& cluster,
83
16628
                                        ClusterFactoryContext& context) {
84
16628
  const envoy::config::endpoint::v3::ClusterLoadAssignment& cluster_load_assignment =
85
16628
      cluster.load_assignment();
86
16685
  for (const auto& locality_lb_endpoint : cluster_load_assignment.endpoints()) {
87
    // TODO(adisuissa): Implement LEDS support for STATIC clusters.
88
16481
    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
16481
  }
94
16627
  absl::Status creation_status = absl::OkStatus();
95
16627
  auto ret = std::make_pair(
96
16627
      std::shared_ptr<StaticClusterImpl>(new StaticClusterImpl(cluster, context, creation_status)),
97
16627
      nullptr);
98
16627
  RETURN_IF_NOT_OK(creation_status);
99
16620
  return ret;
100
16627
}
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