github.com/cilium/cilium@v1.16.2/operator/pkg/model/translation/envoy_cluster.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package translation
     5  
     6  import (
     7  	envoy_config_cluster_v3 "github.com/cilium/proxy/go/envoy/config/cluster/v3"
     8  	envoy_config_core_v3 "github.com/cilium/proxy/go/envoy/config/core/v3"
     9  	envoy_upstreams_http_v3 "github.com/cilium/proxy/go/envoy/extensions/upstreams/http/v3"
    10  	"google.golang.org/protobuf/proto"
    11  	"google.golang.org/protobuf/types/known/anypb"
    12  	"google.golang.org/protobuf/types/known/durationpb"
    13  
    14  	"github.com/cilium/cilium/pkg/envoy"
    15  	ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    16  )
    17  
    18  const (
    19  	httpProtocolOptionsType = "envoy.extensions.upstreams.http.v3.HttpProtocolOptions"
    20  )
    21  
    22  type HTTPVersionType int
    23  
    24  const (
    25  	HTTPVersionDownstream HTTPVersionType = -1
    26  	HTTPVersionAuto       HTTPVersionType = 0
    27  	HTTPVersion1          HTTPVersionType = 1
    28  	HTTPVersion2          HTTPVersionType = 2
    29  	HTTPVersion3          HTTPVersionType = 3
    30  )
    31  
    32  type ClusterMutator func(*envoy_config_cluster_v3.Cluster) *envoy_config_cluster_v3.Cluster
    33  
    34  // WithClusterLbPolicy sets the cluster's load balancing policy.
    35  // https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/load_balancers
    36  func WithClusterLbPolicy(lbPolicy int32) ClusterMutator {
    37  	return func(cluster *envoy_config_cluster_v3.Cluster) *envoy_config_cluster_v3.Cluster {
    38  		if cluster == nil {
    39  			return cluster
    40  		}
    41  		cluster.LbPolicy = envoy_config_cluster_v3.Cluster_LbPolicy(lbPolicy)
    42  		return cluster
    43  	}
    44  }
    45  
    46  // WithOutlierDetection enables outlier detection on the cluster.
    47  func WithOutlierDetection(splitExternalLocalOriginErrors bool) ClusterMutator {
    48  	return func(cluster *envoy_config_cluster_v3.Cluster) *envoy_config_cluster_v3.Cluster {
    49  		if cluster == nil {
    50  			return cluster
    51  		}
    52  		cluster.OutlierDetection = &envoy_config_cluster_v3.OutlierDetection{
    53  			SplitExternalLocalOriginErrors: splitExternalLocalOriginErrors,
    54  		}
    55  		return cluster
    56  	}
    57  }
    58  
    59  // WithConnectionTimeout sets the cluster's connection timeout.
    60  func WithConnectionTimeout(seconds int) ClusterMutator {
    61  	return func(cluster *envoy_config_cluster_v3.Cluster) *envoy_config_cluster_v3.Cluster {
    62  		if cluster == nil {
    63  			return cluster
    64  		}
    65  		cluster.ConnectTimeout = &durationpb.Duration{Seconds: int64(seconds)}
    66  		return cluster
    67  	}
    68  }
    69  
    70  // WithIdleTimeout sets the cluster's connection idle timeout.
    71  func WithIdleTimeout(seconds int) ClusterMutator {
    72  	return func(cluster *envoy_config_cluster_v3.Cluster) *envoy_config_cluster_v3.Cluster {
    73  		if cluster == nil {
    74  			return cluster
    75  		}
    76  		a := cluster.TypedExtensionProtocolOptions[httpProtocolOptionsType]
    77  		opts := &envoy_upstreams_http_v3.HttpProtocolOptions{}
    78  		if err := a.UnmarshalTo(opts); err != nil {
    79  			return cluster
    80  		}
    81  		opts.CommonHttpProtocolOptions = &envoy_config_core_v3.HttpProtocolOptions{
    82  			IdleTimeout: &durationpb.Duration{Seconds: int64(seconds)},
    83  		}
    84  		cluster.TypedExtensionProtocolOptions[httpProtocolOptionsType] = toAny(opts)
    85  		return cluster
    86  	}
    87  }
    88  
    89  func WithProtocol(protocolVersion HTTPVersionType) ClusterMutator {
    90  	return func(cluster *envoy_config_cluster_v3.Cluster) *envoy_config_cluster_v3.Cluster {
    91  		a := cluster.TypedExtensionProtocolOptions[httpProtocolOptionsType]
    92  		options := &envoy_upstreams_http_v3.HttpProtocolOptions{}
    93  		if err := a.UnmarshalTo(options); err != nil {
    94  			return cluster
    95  		}
    96  		switch protocolVersion {
    97  		// Default protocol version in Envoy is HTTP1.1.
    98  		case HTTPVersion1, HTTPVersionAuto:
    99  			options.UpstreamProtocolOptions = &envoy_upstreams_http_v3.HttpProtocolOptions_ExplicitHttpConfig_{
   100  				ExplicitHttpConfig: &envoy_upstreams_http_v3.HttpProtocolOptions_ExplicitHttpConfig{
   101  					ProtocolConfig: &envoy_upstreams_http_v3.HttpProtocolOptions_ExplicitHttpConfig_HttpProtocolOptions{},
   102  				},
   103  			}
   104  		case HTTPVersion2:
   105  			options.UpstreamProtocolOptions = &envoy_upstreams_http_v3.HttpProtocolOptions_ExplicitHttpConfig_{
   106  				ExplicitHttpConfig: &envoy_upstreams_http_v3.HttpProtocolOptions_ExplicitHttpConfig{
   107  					ProtocolConfig: &envoy_upstreams_http_v3.HttpProtocolOptions_ExplicitHttpConfig_Http2ProtocolOptions{},
   108  				},
   109  			}
   110  		case HTTPVersion3:
   111  			options.UpstreamProtocolOptions = &envoy_upstreams_http_v3.HttpProtocolOptions_ExplicitHttpConfig_{
   112  				ExplicitHttpConfig: &envoy_upstreams_http_v3.HttpProtocolOptions_ExplicitHttpConfig{
   113  					ProtocolConfig: &envoy_upstreams_http_v3.HttpProtocolOptions_ExplicitHttpConfig_Http3ProtocolOptions{},
   114  				},
   115  			}
   116  		}
   117  
   118  		cluster.TypedExtensionProtocolOptions = map[string]*anypb.Any{
   119  			httpProtocolOptionsType: toAny(options),
   120  		}
   121  		return cluster
   122  	}
   123  }
   124  
   125  // NewHTTPCluster creates a new Envoy cluster.
   126  func NewHTTPCluster(clusterName string, clusterServiceName string, mutationFunc ...ClusterMutator) (ciliumv2.XDSResource, error) {
   127  	cluster := &envoy_config_cluster_v3.Cluster{
   128  		Name: clusterName,
   129  		TypedExtensionProtocolOptions: map[string]*anypb.Any{
   130  			httpProtocolOptionsType: toAny(&envoy_upstreams_http_v3.HttpProtocolOptions{
   131  				UpstreamProtocolOptions: &envoy_upstreams_http_v3.HttpProtocolOptions_UseDownstreamProtocolConfig{
   132  					UseDownstreamProtocolConfig: &envoy_upstreams_http_v3.HttpProtocolOptions_UseDownstreamHttpConfig{
   133  						Http2ProtocolOptions: &envoy_config_core_v3.Http2ProtocolOptions{},
   134  					},
   135  				},
   136  			}),
   137  		},
   138  		ClusterDiscoveryType: &envoy_config_cluster_v3.Cluster_Type{
   139  			Type: envoy_config_cluster_v3.Cluster_EDS,
   140  		},
   141  		EdsClusterConfig: &envoy_config_cluster_v3.Cluster_EdsClusterConfig{
   142  			ServiceName: clusterServiceName,
   143  		},
   144  	}
   145  
   146  	// Apply mutation functions for customizing the cluster.
   147  	for _, fn := range mutationFunc {
   148  		cluster = fn(cluster)
   149  	}
   150  
   151  	clusterBytes, err := proto.Marshal(cluster)
   152  	if err != nil {
   153  		return ciliumv2.XDSResource{}, err
   154  	}
   155  
   156  	return ciliumv2.XDSResource{
   157  		Any: &anypb.Any{
   158  			TypeUrl: envoy.ClusterTypeURL,
   159  			Value:   clusterBytes,
   160  		},
   161  	}, nil
   162  }
   163  
   164  // NewTCPClusterWithDefaults same as NewTCPCluster but has default mutation functions applied.
   165  // currently this is only used for TLSRoutes to create a passthrough proxy
   166  func NewTCPClusterWithDefaults(clusterName string, clusterServiceName string, mutationFunc ...ClusterMutator) (ciliumv2.XDSResource, error) {
   167  	fns := append(mutationFunc,
   168  		WithConnectionTimeout(5),
   169  		WithClusterLbPolicy(int32(envoy_config_cluster_v3.Cluster_ROUND_ROBIN)),
   170  		WithOutlierDetection(true),
   171  	)
   172  	return NewTCPCluster(clusterName, clusterServiceName, fns...)
   173  }
   174  
   175  // NewTCPCluster creates a new Envoy cluster.
   176  func NewTCPCluster(clusterName string, clusterServiceName string, mutationFunc ...ClusterMutator) (ciliumv2.XDSResource, error) {
   177  	cluster := &envoy_config_cluster_v3.Cluster{
   178  		Name: clusterName,
   179  		ClusterDiscoveryType: &envoy_config_cluster_v3.Cluster_Type{
   180  			Type: envoy_config_cluster_v3.Cluster_EDS,
   181  		},
   182  		EdsClusterConfig: &envoy_config_cluster_v3.Cluster_EdsClusterConfig{
   183  			ServiceName: clusterServiceName,
   184  		},
   185  	}
   186  
   187  	// Apply mutation functions for customizing the cluster.
   188  	for _, fn := range mutationFunc {
   189  		cluster = fn(cluster)
   190  	}
   191  
   192  	clusterBytes, err := proto.Marshal(cluster)
   193  	if err != nil {
   194  		return ciliumv2.XDSResource{}, err
   195  	}
   196  
   197  	return ciliumv2.XDSResource{
   198  		Any: &anypb.Any{
   199  			TypeUrl: envoy.ClusterTypeURL,
   200  			Value:   clusterBytes,
   201  		},
   202  	}, nil
   203  }
   204  
   205  func toAny(message proto.Message) *anypb.Any {
   206  	a, err := anypb.New(message)
   207  	if err != nil {
   208  		return nil
   209  	}
   210  	return a
   211  }