1
#pragma once
2

            
3
#include <memory>
4

            
5
#include "envoy/event/dispatcher.h"
6
#include "envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.pb.h"
7
#include "envoy/server/factory_context.h"
8
#include "envoy/upstream/load_balancer.h"
9

            
10
#include "source/common/common/logger.h"
11
#include "source/extensions/load_balancing_policies/client_side_weighted_round_robin/client_side_weighted_round_robin_lb.h"
12
#include "source/extensions/load_balancing_policies/common/factory_base.h"
13
#include "source/extensions/load_balancing_policies/wrr_locality/wrr_locality_lb.h"
14

            
15
namespace Envoy {
16
namespace Extensions {
17
namespace LoadBalancingPolicies {
18
namespace WrrLocality {
19

            
20
class Factory : public TypedLoadBalancerFactoryBase<WrrLocalityLbProto> {
21
public:
22
  Factory()
23
5
      : TypedLoadBalancerFactoryBase<WrrLocalityLbProto>(
24
5
            "envoy.load_balancing_policies.wrr_locality") {}
25

            
26
  Upstream::ThreadAwareLoadBalancerPtr create(OptRef<const Upstream::LoadBalancerConfig> lb_config,
27
                                              const Upstream::ClusterInfo& cluster_info,
28
                                              const Upstream::PrioritySet& priority_set,
29
                                              Runtime::Loader& runtime,
30
                                              Envoy::Random::RandomGenerator& random,
31
3
                                              TimeSource& time_source) override {
32
3
    return std::make_unique<WrrLocalityLoadBalancer>(lb_config, cluster_info, priority_set, runtime,
33
3
                                                     random, time_source);
34
3
  }
35

            
36
  absl::StatusOr<Upstream::LoadBalancerConfigPtr>
37
  loadConfig(Server::Configuration::ServerFactoryContext& context,
38
5
             const Protobuf::Message& config) override {
39
5
    const auto& lb_config = dynamic_cast<const WrrLocalityLbProto&>(config);
40
5
    Upstream::TypedLoadBalancerFactory* endpoint_picking_policy_factory = nullptr;
41
    // Iterate through the list of endpoint picking policies to find the first one that we know
42
    // about.
43
5
    for (const auto& endpoint_picking_policy : lb_config.endpoint_picking_policy().policies()) {
44
4
      endpoint_picking_policy_factory =
45
4
          Config::Utility::getAndCheckFactory<Upstream::TypedLoadBalancerFactory>(
46
4
              endpoint_picking_policy.typed_extension_config(),
47
4
              /*is_optional=*/true);
48

            
49
4
      if (endpoint_picking_policy_factory != nullptr) {
50
        // Ensure that the endpoint picking policy is a ClientSideWeightedRoundRobin.
51
4
        auto* client_side_weighted_round_robin_factory = dynamic_cast<
52
4
            ::Envoy::Extensions::LoadBalancingPolicies::ClientSideWeightedRoundRobin::Factory*>(
53
4
            endpoint_picking_policy_factory);
54
4
        if (client_side_weighted_round_robin_factory == nullptr) {
55
1
          return absl::InvalidArgumentError(
56
1
              "Currently WrrLocalityLoadBalancer only supports "
57
1
              "ClientSideWeightedRoundRobinLoadBalancer as its endpoint "
58
1
              "picking policy.");
59
1
        }
60
        // Load and validate the configuration.
61
3
        auto sub_lb_proto_message = endpoint_picking_policy_factory->createEmptyConfigProto();
62
3
        RETURN_IF_NOT_OK(Config::Utility::translateOpaqueConfig(
63
3
            endpoint_picking_policy.typed_extension_config().typed_config(),
64
3
            context.messageValidationVisitor(), *sub_lb_proto_message));
65

            
66
3
        auto lb_config_or_error =
67
3
            endpoint_picking_policy_factory->loadConfig(context, *sub_lb_proto_message);
68
3
        RETURN_IF_NOT_OK(lb_config_or_error.status());
69

            
70
3
        auto wrr_locality_lb_config = std::make_unique<WrrLocalityLbConfig>(
71
3
            *endpoint_picking_policy_factory, std::move(lb_config_or_error.value()));
72
3
        return Upstream::LoadBalancerConfigPtr{wrr_locality_lb_config.release()};
73
3
      }
74
4
    }
75

            
76
1
    return absl::InvalidArgumentError("No supported endpoint picking policy.");
77
5
  }
78
};
79

            
80
DECLARE_FACTORY(Factory);
81

            
82
} // namespace WrrLocality
83
} // namespace LoadBalancingPolicies
84
} // namespace Extensions
85
} // namespace Envoy