text: #pragma once
  
  #include <chrono>
  #include <cstdint>
  #include <functional>
  #include <list>
  #include <memory>
  #include <string>
  #include <vector>
  
  #include "envoy/api/v2/core/base.pb.h"
  #include "envoy/common/callback.h"
  #include "envoy/config/typed_metadata.h"
  #include "envoy/http/codec.h"
  #include "envoy/network/connection.h"
  #include "envoy/network/transport_socket.h"
  #include "envoy/ssl/context.h"
  #include "envoy/stats/scope.h"
  #include "envoy/stats/stats.h"
  #include "envoy/upstream/health_check_host_monitor.h"
  #include "envoy/upstream/load_balancer_type.h"
  #include "envoy/upstream/locality.h"
  #include "envoy/upstream/outlier_detection.h"
  #include "envoy/upstream/resource_manager.h"
  
  #include "absl/types/optional.h"
  
  namespace Envoy {
  namespace Upstream {
  
  /**
   * An upstream host.
   */
  class Host : virtual public HostDescription {
  public:
    struct CreateConnectionData {
      Network::ClientConnectionPtr connection_;
      HostDescriptionConstSharedPtr host_description_;
    };
  
    enum class HealthFlag {
      // The host is currently failing active health checks.
      FAILED_ACTIVE_HC = 0x1,
      // The host is currently considered an outlier and has been ejected.
      FAILED_OUTLIER_CHECK = 0x02,
      // The host is currently marked as unhealthy by EDS.
      FAILED_EDS_HEALTH = 0x04,
    };
  
    enum class ActiveHealthFailureType {
      // The failure type is unknown, all hosts' failure types are initialized as UNKNOWN
      UNKNOWN,
      // The host is actively responding it's unhealthy
      UNHEALTHY,
      // The host is timing out
      TIMEOUT,
    };
  
    /**
     * @return host specific counters.
     */
    virtual std::vector<Stats::CounterSharedPtr> counters() const PURE;
  
    /**
     * Create a connection for this host.
     * @param dispatcher supplies the owning dispatcher.
     * @param options supplies the socket options that will be set on the new connection.
     * @return the connection data which includes the raw network connection as well as the *real*
     *         host that backs it. The reason why a 2nd host is returned is that some hosts are
     *         logical and wrap multiple real network destinations. In this case, a different host
     *         will be returned along with the connection vs. the host the method was called on.
     *         If it matters, callers should not assume that the returned host will be the same.
     */
    virtual CreateConnectionData
    createConnection(Event::Dispatcher& dispatcher,
                     const Network::ConnectionSocket::OptionsSharedPtr& options,
                     Network::TransportSocketOptionsSharedPtr transport_socket_options) const PURE;
  
    /**
     * Create a health check connection for this host.
     * @param dispatcher supplies the owning dispatcher.
     * @return the connection data.
     */
    virtual CreateConnectionData
    createHealthCheckConnection(Event::Dispatcher& dispatcher) const PURE;
  
    /**
     * @return host specific gauges.
     */
    virtual std::vector<Stats::GaugeSharedPtr> gauges() const PURE;
  
    /**
     * Atomically clear a health flag for a host. Flags are specified in HealthFlags.
     */
    virtual void healthFlagClear(HealthFlag flag) PURE;
  
    /**
     * Atomically get whether a health flag is set for a host. Flags are specified in HealthFlags.
     */
    virtual bool healthFlagGet(HealthFlag flag) const PURE;
  
    /**
     * Atomically set a health flag for a host. Flags are specified in HealthFlags.
     */
    virtual void healthFlagSet(HealthFlag flag) PURE;
  
    /**
     * @return whether in aggregate a host is healthy and routable. Multiple health flags and other
     *         information may be considered.
     */
    virtual bool healthy() const PURE;
  
    /**
     * Returns the host's ActiveHealthFailureType. Types are specified in ActiveHealthFailureType.
     */
    virtual ActiveHealthFailureType getActiveHealthFailureType() const PURE;
  
    /**
     * Set the most recent health failure type for a host. Types are specified in
     * ActiveHealthFailureType.
     */
    virtual void setActiveHealthFailureType(ActiveHealthFailureType flag) PURE;
  
    /**
     * Set the host's health checker monitor. Monitors are assumed to be thread safe, however
     * a new monitor must be installed before the host is used across threads. Thus,
     * this routine should only be called on the main thread before the host is used across threads.
     */
    virtual void setHealthChecker(HealthCheckHostMonitorPtr&& health_checker) PURE;
  
    /**
     * Set the host's outlier detector monitor. Outlier detector monitors are assumed to be thread
     * safe, however a new outlier detector monitor must be installed before the host is used across
     * threads. Thus, this routine should only be called on the main thread before the host is used
     * across threads.
     */
    virtual void setOutlierDetector(Outlier::DetectorHostMonitorPtr&& outlier_detector) PURE;
  
    /**
     * @return the current load balancing weight of the host, in the range 1-100.
     */
    virtual uint32_t weight() const PURE;
  
    /**
     * Set the current load balancing weight of the host, in the range 1-100.
     */
    virtual void weight(uint32_t new_weight) PURE;
  
    /**
     * @return the current boolean value of host being in use.
     */
    virtual bool used() const PURE;
  
    /**
     * @param new_used supplies the new value of host being in use to be stored.
     */
    virtual void used(bool new_used) PURE;
  };
  
  typedef std::shared_ptr<const Host> HostConstSharedPtr;
  
  typedef std::vector<HostSharedPtr> HostVector;
  typedef std::unordered_map<std::string, Upstream::HostSharedPtr> HostMap;
  typedef std::shared_ptr<HostVector> HostVectorSharedPtr;
  typedef std::shared_ptr<const HostVector> HostVectorConstSharedPtr;
  
  typedef std::unique_ptr<HostVector> HostListPtr;
  typedef std::unordered_map<envoy::api::v2::core::Locality, uint32_t, LocalityHash, LocalityEqualTo>
      LocalityWeightsMap;
  typedef std::vector<std::pair<HostListPtr, LocalityWeightsMap>> PriorityState;
  
  /**
   * Bucket hosts by locality.
   */
  class HostsPerLocality {
  public:
    virtual ~HostsPerLocality() {}
  
    /**
     * @return bool is local locality one of the locality buckets? If so, the
     *         local locality will be the first in the get() vector.
     */
    virtual bool hasLocalLocality() const PURE;
  
    /**
     * @return const std::vector<HostVector>& list of hosts organized per
     *         locality. The local locality is the first entry if
     *         hasLocalLocality() is true.
     */
    virtual const std::vector<HostVector>& get() const PURE;
  
    /**
     * Clone object with a filter predicate.
     * @param predicate on Host entries.
     * @return HostsPerLocalityConstSharedPtr clone of the HostsPerLocality with only
     *         hosts according to predicate.
     */
    virtual std::shared_ptr<const HostsPerLocality>
    filter(std::function<bool(const Host&)> predicate) const PURE;
  
    /**
     * Clone object.
     * @return HostsPerLocalityConstSharedPtr clone of the HostsPerLocality.
     */
    std::shared_ptr<const HostsPerLocality> clone() const {
      return filter([](const Host&) { return true; });
    }
  };
  
  typedef std::shared_ptr<HostsPerLocality> HostsPerLocalitySharedPtr;
  typedef std::shared_ptr<const HostsPerLocality> HostsPerLocalityConstSharedPtr;
  
  // Weight for each locality index in HostsPerLocality.
  typedef std::vector<uint32_t> LocalityWeights;
  typedef std::shared_ptr<LocalityWeights> LocalityWeightsSharedPtr;
  typedef std::shared_ptr<const LocalityWeights> LocalityWeightsConstSharedPtr;
  
  /**
   * Base host set interface. This contains all of the endpoints for a given LocalityLbEndpoints
   * priority level.
   */
  class HostSet {
  public:
    virtual ~HostSet() {}
  
    /**
     * @return all hosts that make up the set at the current time.
     */
    virtual const HostVector& hosts() const PURE;
  
    /**
     * @return all healthy hosts contained in the set at the current time. NOTE: This set is
     *         eventually consistent. There is a time window where a host in this set may become
     *         unhealthy and calling healthy() on it will return false. Code should be written to
     *         deal with this case if it matters.
     */
    virtual const HostVector& healthyHosts() const PURE;
  
    /**
     * @return hosts per locality.
     */
    virtual const HostsPerLocality& hostsPerLocality() const PURE;
  
    /**
     * @return same as hostsPerLocality but only contains healthy hosts.
     */
    virtual const HostsPerLocality& healthyHostsPerLocality() const PURE;
  
    /**
     * @return weights for each locality in the host set.
     */
    virtual LocalityWeightsConstSharedPtr localityWeights() const PURE;
  
    /**
     * @return next locality index to route to if performing locality weighted balancing.
     */
    virtual absl::optional<uint32_t> chooseLocality() PURE;
  
    /**
     * Updates the hosts in a given host set.
     *
     * @param hosts supplies the (usually new) list of hosts in the host set.
     * @param healthy hosts supplies the subset of hosts which are healthy.
     * @param hosts_per_locality supplies the hosts subdivided by locality.
     * @param hosts_per_locality supplies the healthy hosts subdivided by locality.
     * @param locality_weights supplies a map from locality to associated weight.
     * @param hosts_added supplies the hosts added since the last update.
     * @param hosts_removed supplies the hosts removed since the last update.
     * @param overprovisioning_factor if presents, overwrites the current overprovisioning_factor.
     */
    virtual void updateHosts(HostVectorConstSharedPtr hosts, HostVectorConstSharedPtr healthy_hosts,
                             HostsPerLocalityConstSharedPtr hosts_per_locality,
                             HostsPerLocalityConstSharedPtr healthy_hosts_per_locality,
                             LocalityWeightsConstSharedPtr locality_weights,
                             const HostVector& hosts_added, const HostVector& hosts_removed,
                             absl::optional<uint32_t> overprovisioning_factor) PURE;
  
    /**
     * @return uint32_t the priority of this host set.
     */
    virtual uint32_t priority() const PURE;
  
    /**
     * @return uint32_t the overprovisioning factor of this host set.
     */
    virtual uint32_t overprovisioning_factor() const PURE;
  };
  
  typedef std::unique_ptr<HostSet> HostSetPtr;
  
  /**
   * This class contains all of the HostSets for a given cluster grouped by priority, for
   * ease of load balancing.
   */
  class PrioritySet {
  public:
    typedef std::function<void(uint32_t priority, const HostVector& hosts_added,
                               const HostVector& hosts_removed)>
        MemberUpdateCb;
  
    virtual ~PrioritySet() {}
  
    /**
     * Install a callback that will be invoked when any of the HostSets in the PrioritySet changes.
     * This includes when a new HostSet is created.
     *
     * @param callback supplies the callback to invoke.
     * @return Common::CallbackHandle* a handle which can be used to unregister the callback.
     */
    virtual Common::CallbackHandle* addMemberUpdateCb(MemberUpdateCb callback) const PURE;
  
    /**
     * Returns the host sets for this priority set, ordered by priority.
     * The first element in the vector is the host set for priority 0, and so on.
     *
     * @return std::vector<HostSetPtr>& the host sets for this priority set.
     */
    virtual std::vector<HostSetPtr>& hostSetsPerPriority() PURE;
  
    /**
     * @return const std::vector<HostSetPtr>& the host sets, ordered by priority.
     */
    virtual const std::vector<HostSetPtr>& hostSetsPerPriority() const PURE;
  };
  
  /**
   * All cluster stats. @see stats_macros.h
   */
  // clang-format off
  #define ALL_CLUSTER_STATS(COUNTER, GAUGE, HISTOGRAM)                                               \
    COUNTER  (lb_healthy_panic)                                                                      \
    COUNTER  (lb_local_cluster_not_ok)                                                               \
    COUNTER  (lb_recalculate_zone_structures)                                                        \
    COUNTER  (lb_zone_cluster_too_small)                                                             \
    COUNTER  (lb_zone_no_capacity_left)                                                              \
    COUNTER  (lb_zone_number_differs)                                                                \
    COUNTER  (lb_zone_routing_all_directly)                                                          \
    COUNTER  (lb_zone_routing_sampled)                                                               \
    COUNTER  (lb_zone_routing_cross_zone)                                                            \
    GAUGE    (lb_subsets_active)                                                                     \
    COUNTER  (lb_subsets_created)                                                                    \
    COUNTER  (lb_subsets_removed)                                                                    \
    COUNTER  (lb_subsets_selected)                                                                   \
    COUNTER  (lb_subsets_fallback)                                                                   \
    COUNTER  (original_dst_host_invalid)                                                             \
    COUNTER  (upstream_cx_total)                                                                     \
    GAUGE    (upstream_cx_active)                                                                    \
    COUNTER  (upstream_cx_http1_total)                                                               \
    COUNTER  (upstream_cx_http2_total)                                                               \
    COUNTER  (upstream_cx_connect_fail)                                                              \
    COUNTER  (upstream_cx_connect_timeout)                                                           \
    COUNTER  (upstream_cx_idle_timeout)                                                              \
    COUNTER  (upstream_cx_connect_attempts_exceeded)                                                 \
    COUNTER  (upstream_cx_overflow)                                                                  \
    HISTOGRAM(upstream_cx_connect_ms)                                                                \
    HISTOGRAM(upstream_cx_length_ms)                                                                 \
    COUNTER  (upstream_cx_destroy)                                                                   \
    COUNTER  (upstream_cx_destroy_local)                                                             \
    COUNTER  (upstream_cx_destroy_remote)                                                            \
    COUNTER  (upstream_cx_destroy_with_active_rq)                                                    \
    COUNTER  (upstream_cx_destroy_local_with_active_rq)                                              \
    COUNTER  (upstream_cx_destroy_remote_with_active_rq)                                             \
    COUNTER  (upstream_cx_close_notify)                                                              \
    COUNTER  (upstream_cx_rx_bytes_total)                                                            \
    GAUGE    (upstream_cx_rx_bytes_buffered)                                                         \
    COUNTER  (upstream_cx_tx_bytes_total)                                                            \
    GAUGE    (upstream_cx_tx_bytes_buffered)                                                         \
    COUNTER  (upstream_cx_protocol_error)                                                            \
    COUNTER  (upstream_cx_max_requests)                                                              \
    COUNTER  (upstream_cx_none_healthy)                                                              \
    COUNTER  (upstream_rq_total)                                                                     \
    GAUGE    (upstream_rq_active)                                                                    \
    COUNTER  (upstream_rq_completed)                                                                 \
    COUNTER  (upstream_rq_pending_total)                                                             \
    COUNTER  (upstream_rq_pending_overflow)                                                          \
    COUNTER  (upstream_rq_pending_failure_eject)                                                     \
    GAUGE    (upstream_rq_pending_active)                                                            \
    COUNTER  (upstream_rq_cancelled)                                                                 \
    COUNTER  (upstream_rq_maintenance_mode)                                                          \
    COUNTER  (upstream_rq_timeout)                                                                   \
    COUNTER  (upstream_rq_per_try_timeout)                                                           \
    COUNTER  (upstream_rq_rx_reset)                                                                  \
    COUNTER  (upstream_rq_tx_reset)                                                                  \
    COUNTER  (upstream_rq_retry)                                                                     \
    COUNTER  (upstream_rq_retry_success)                                                             \
    COUNTER  (upstream_rq_retry_overflow)                                                            \
    COUNTER  (upstream_flow_control_paused_reading_total)                                            \
    COUNTER  (upstream_flow_control_resumed_reading_total)                                           \
    COUNTER  (upstream_flow_control_backed_up_total)                                                 \
    COUNTER  (upstream_flow_control_drained_total)                                                   \
    COUNTER  (bind_errors)                                                                           \
    GAUGE    (max_host_weight)                                                                       \
    COUNTER  (membership_change)                                                                     \
    GAUGE    (membership_healthy)                                                                    \
    GAUGE    (membership_total)                                                                      \
    COUNTER  (retry_or_shadow_abandoned)                                                             \
    COUNTER  (update_attempt)                                                                        \
    COUNTER  (update_success)                                                                        \
    COUNTER  (update_failure)                                                                        \
    COUNTER  (update_empty)                                                                          \
    COUNTER  (update_no_rebuild)                                                                     \
    GAUGE    (version)
  // clang-format on
  
  /**
   * All cluster load report stats. These are only use for EDS load reporting and not sent to the
   * stats sink. See envoy.api.v2.endpoint.ClusterStats for the definition of upstream_rq_dropped.
   * These are latched by LoadStatsReporter, independent of the normal stats sink flushing.
   */
  // clang-format off
  #define ALL_CLUSTER_LOAD_REPORT_STATS(COUNTER)                                                     \
    COUNTER (upstream_rq_dropped)
  // clang-format on
  
  /**
   * Cluster circuit breakers stats.
   */
  // clang-format off
  #define ALL_CLUSTER_CIRCUIT_BREAKERS_STATS(GAUGE)                                                  \
    GAUGE (cx_open)                                                                                  \
    GAUGE (rq_pending_open)                                                                          \
    GAUGE (rq_open)                                                                                  \
    GAUGE (rq_retry_open)
  // clang-format on
  
  /**
   * Struct definition for all cluster stats. @see stats_macros.h
   */
  struct ClusterStats {
    ALL_CLUSTER_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT, GENERATE_HISTOGRAM_STRUCT)
  };
  
  /**
   * Struct definition for all cluster load report stats. @see stats_macros.h
   */
  struct ClusterLoadReportStats {
    ALL_CLUSTER_LOAD_REPORT_STATS(GENERATE_COUNTER_STRUCT)
  };
  
  /**
   * Struct definition for cluster circuit breakers stats. @see stats_macros.h
   */
  struct ClusterCircuitBreakersStats {
    ALL_CLUSTER_CIRCUIT_BREAKERS_STATS(GENERATE_GAUGE_STRUCT)
  };
  
  /**
   * All extension protocol specific options returned by the method at
   *   NamedNetworkFilterConfigFactory::createProtocolOptions
   * must be derived from this class.
   */
  class ProtocolOptionsConfig {
  public:
    virtual ~ProtocolOptionsConfig() {}
  };
  typedef std::shared_ptr<const ProtocolOptionsConfig> ProtocolOptionsConfigConstSharedPtr;
  
  /**
   *  Base class for all cluster typed metadata factory.
   */
  class ClusterTypedMetadataFactory : public Envoy::Config::TypedMetadataFactory {};
  
  /**
   * Information about a given upstream cluster.
   */
  class ClusterInfo {
  public:
    struct Features {
      // Whether the upstream supports HTTP2. This is used when creating connection pools.
      static const uint64_t HTTP2 = 0x1;
      // Use the downstream protocol (HTTP1.1, HTTP2) for upstream connections as well, if available.
      // This is used when creating connection pools.
      static const uint64_t USE_DOWNSTREAM_PROTOCOL = 0x2;
      // Whether connections should be immediately closed upon health failure.
      static const uint64_t CLOSE_CONNECTIONS_ON_HOST_HEALTH_FAILURE = 0x4;
    };
  
    virtual ~ClusterInfo() {}
  
    /**
     * @return bool whether the cluster was added via API (if false the cluster was present in the
     *         initial configuration and cannot be removed or updated).
     */
    virtual bool addedViaApi() const PURE;
  
    /**
     * @return the connect timeout for upstream hosts that belong to this cluster.
     */
    virtual std::chrono::milliseconds connectTimeout() const PURE;
  
    /**
     * @return the idle timeout for upstream connection pool connections.
     */
    virtual const absl::optional<std::chrono::milliseconds> idleTimeout() const PURE;
  
    /**
     * @return soft limit on size of the cluster's connections read and write buffers.
     */
    virtual uint32_t perConnectionBufferLimitBytes() const PURE;
  
    /**
     * @return uint64_t features supported by the cluster. @see Features.
     */
    virtual uint64_t features() const PURE;
  
    /**
     * @return const Http::Http2Settings& for HTTP/2 connections created on behalf of this cluster.
     *         @see Http::Http2Settings.
     */
    virtual const Http::Http2Settings& http2Settings() const PURE;
  
    /**
     * @param name std::string containing the well-known name of the extension for which protocol
     *        options are desired
     * @return std::shared_ptr<const Derived> where Derived is a subclass of ProtocolOptionsConfig
     *         and contains extension-specific protocol options for upstream connections.
     */
    template <class Derived>
    const std::shared_ptr<const Derived>
    extensionProtocolOptionsTyped(const std::string& name) const {
      return std::dynamic_pointer_cast<const Derived>(extensionProtocolOptions(name));
    }
  
    /**
     * @return const envoy::api::v2::Cluster::CommonLbConfig& the common configuration for all
     *         load balancers for this cluster.
     */
    virtual const envoy::api::v2::Cluster::CommonLbConfig& lbConfig() const PURE;
  
    /**
     * @return the type of load balancing that the cluster should use.
     */
    virtual LoadBalancerType lbType() const PURE;
  
    /**
     * @return the service discovery type to use for resolving the cluster.
     */
    virtual envoy::api::v2::Cluster::DiscoveryType type() const PURE;
  
    /**
     * @return configuration for least request load balancing, only used if LB type is least request.
     */
    virtual const absl::optional<envoy::api::v2::Cluster::LeastRequestLbConfig>&
    lbLeastRequestConfig() const PURE;
  
    /**
     * @return configuration for ring hash load balancing, only used if type is set to ring_hash_lb.
     */
    virtual const absl::optional<envoy::api::v2::Cluster::RingHashLbConfig>&
    lbRingHashConfig() const PURE;
  
    /**
     * @return const absl::optional<envoy::api::v2::Cluster::OriginalDstLbConfig>& the configuration
     *         for the Original Destination load balancing policy, only used if type is set to
     *         ORIGINAL_DST_LB.
     */
    virtual const absl::optional<envoy::api::v2::Cluster::OriginalDstLbConfig>&
    lbOriginalDstConfig() const PURE;
  
    /**
     * @return Whether the cluster is currently in maintenance mode and should not be routed to.
     *         Different filters may handle this situation in different ways. The implementation
     *         of this routine is typically based on randomness and may not return the same answer
     *         on each call.
     */
    virtual bool maintenanceMode() const PURE;
  
    /**
     * @return uint64_t the maximum number of outbound requests that a connection pool will make on
     *         each upstream connection. This can be used to increase spread if the backends cannot
     *         tolerate imbalance. 0 indicates no maximum.
     */
    virtual uint64_t maxRequestsPerConnection() const PURE;
  
    /**
     * @return the human readable name of the cluster.
     */
    virtual const std::string& name() const PURE;
  
    /**
     * @return ResourceManager& the resource manager to use by proxy agents for this cluster (at
     *         a particular priority).
     */
    virtual ResourceManager& resourceManager(ResourcePriority priority) const PURE;
  
    /**
     * @return Network::TransportSocketFactory& the factory of transport socket to use when
     *         communicating with the cluster.
     */
    virtual Network::TransportSocketFactory& transportSocketFactory() const PURE;
  
    /**
     * @return ClusterStats& strongly named stats for this cluster.
     */
    virtual ClusterStats& stats() const PURE;
  
    /**
     * @return the stats scope that contains all cluster stats. This can be used to produce dynamic
     *         stats that will be freed when the cluster is removed.
     */
    virtual Stats::Scope& statsScope() const PURE;
  
    /**
     * @return ClusterLoadReportStats& strongly named load report stats for this cluster.
     */
    virtual ClusterLoadReportStats& loadReportStats() const PURE;
  
    /**
     * Returns an optional source address for upstream connections to bind to.
     *
     * @return a source address to bind to or nullptr if no bind need occur.
     */
    virtual const Network::Address::InstanceConstSharedPtr& sourceAddress() const PURE;
  
    /**
     * @return the configuration for load balancer subsets.
     */
    virtual const LoadBalancerSubsetInfo& lbSubsetInfo() const PURE;
  
    /**
     * @return const envoy::api::v2::core::Metadata& the configuration metadata for this cluster.
     */
    virtual const envoy::api::v2::core::Metadata& metadata() const PURE;
  
    /**
     * @return const Envoy::Config::TypedMetadata&& the typed metadata for this cluster.
     */
    virtual const Envoy::Config::TypedMetadata& typedMetadata() const PURE;
  
    /**
     *
     * @return const Network::ConnectionSocket::OptionsSharedPtr& socket options for all
     *         connections for this cluster.
     */
    virtual const Network::ConnectionSocket::OptionsSharedPtr& clusterSocketOptions() const PURE;
  
    /**
     * @return whether to skip waiting for health checking before draining connections
     *         after a host is removed from service discovery.
     */
    virtual bool drainConnectionsOnHostRemoval() const PURE;
  
  protected:
    /**
     * Invoked by extensionProtocolOptionsTyped.
     * @param name std::string containing the well-known name of the extension for which protocol
     *        options are desired
     * @return ProtocolOptionsConfigConstSharedPtr with extension-specific protocol options for
     *         upstream connections.
     */
    virtual ProtocolOptionsConfigConstSharedPtr
    extensionProtocolOptions(const std::string& name) const PURE;
  };
  
  typedef std::shared_ptr<const ClusterInfo> ClusterInfoConstSharedPtr;
  
  class HealthChecker;
  
  /**
   * An upstream cluster (group of hosts). This class is the "primary" singleton cluster used amongst
   * all forwarding threads/workers. Individual HostSets are used on the workers themselves.
   */
  class Cluster {
  public:
    virtual ~Cluster() {}
  
    enum class InitializePhase { Primary, Secondary };
  
    /**
     * @return a pointer to the cluster's health checker. If a health checker has not been installed,
     *         returns nullptr.
     */
    virtual HealthChecker* healthChecker() PURE;
  
    /**
     * @return the information about this upstream cluster.
     */
    virtual ClusterInfoConstSharedPtr info() const PURE;
  
    /**
     * @return a pointer to the cluster's outlier detector. If an outlier detector has not been
     *         installed, returns nullptr.
     */
    virtual Outlier::Detector* outlierDetector() PURE;
    virtual const Outlier::Detector* outlierDetector() const PURE;
  
    /**
     * Initialize the cluster. This will be called either immediately at creation or after all primary
     * clusters have been initialized (determined via initializePhase()).
     * @param callback supplies a callback that will be invoked after the cluster has undergone first
     *        time initialization. E.g., for a dynamic DNS cluster the initialize callback will be
     *        called when initial DNS resolution is complete.
     */
    virtual void initialize(std::function<void()> callback) PURE;
  
    /**
     * @return the phase in which the cluster is initialized at boot. This mechanism is used such that
     *         clusters that depend on other clusters can correctly initialize. (E.g., an EDS cluster
     *         that depends on resolution of the EDS server itself).
     */
    virtual InitializePhase initializePhase() const PURE;
  
    /**
     * @return the PrioritySet for the cluster.
     */
    virtual PrioritySet& prioritySet() PURE;
  
    /**
     * @return the const PrioritySet for the cluster.
     */
    virtual const PrioritySet& prioritySet() const PURE;
  };
  
  typedef std::shared_ptr<Cluster> ClusterSharedPtr;
  
  } // namespace Upstream
  } // namespace Envoy
  