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 }