From c56a612f25cab30e9b3336bc6fc79687f9a57870 Mon Sep 17 00:00:00 2001 From: shawnh2 Date: Sat, 29 Jun 2024 21:33:33 +0800 Subject: [PATCH 1/3] auto fill missing clusterIP for service Signed-off-by: shawnh2 --- .../translate/in/no-service-cluster-ip.yaml | 55 ++++ .../translate/out/default-resources.all.yaml | 6 +- .../out/no-service-cluster-ip.all.yaml | 288 ++++++++++++++++++ internal/cmd/egctl/translate.go | 11 +- internal/cmd/egctl/translate_test.go | 6 + 5 files changed, 360 insertions(+), 6 deletions(-) create mode 100644 internal/cmd/egctl/testdata/translate/in/no-service-cluster-ip.yaml create mode 100644 internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml diff --git a/internal/cmd/egctl/testdata/translate/in/no-service-cluster-ip.yaml b/internal/cmd/egctl/testdata/translate/in/no-service-cluster-ip.yaml new file mode 100644 index 00000000000..312e12379ee --- /dev/null +++ b/internal/cmd/egctl/testdata/translate/in/no-service-cluster-ip.yaml @@ -0,0 +1,55 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: eg +spec: + controllerName: gateway.envoyproxy.io/gatewayclass-controller +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: eg +spec: + gatewayClassName: eg + listeners: + - name: http + protocol: HTTP + port: 80 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: backend +--- +apiVersion: v1 +kind: Service +metadata: + name: backend + labels: + app: backend1 + service: backend1 +spec: + ports: + - name: http + port: 8080 + targetPort: 8080 + selector: + app: backend +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: routes +spec: + parentRefs: + - name: eg + rules: + - backendRefs: + - group: "" + kind: Service + name: backend + port: 8080 + matches: + - path: + type: PathPrefix + value: /service diff --git a/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml b/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml index f1bc3b8eb15..5c04b7ad257 100644 --- a/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml +++ b/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml @@ -749,7 +749,7 @@ xds: - endpoint: address: socketAddress: - address: 127.0.0.1 + address: 1.2.3.4 portValue: 3000 loadBalancingWeight: 1 loadBalancingWeight: 1 @@ -763,7 +763,7 @@ xds: - endpoint: address: socketAddress: - address: 127.0.0.1 + address: 1.2.3.4 portValue: 3000 loadBalancingWeight: 1 loadBalancingWeight: 1 @@ -777,7 +777,7 @@ xds: - endpoint: address: socketAddress: - address: 127.0.0.1 + address: 1.2.3.4 portValue: 3000 loadBalancingWeight: 1 loadBalancingWeight: 1 diff --git a/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml b/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml new file mode 100644 index 00000000000..78917b18bc1 --- /dev/null +++ b/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml @@ -0,0 +1,288 @@ +xds: + envoy-gateway-system/eg: + configs: + - '@type': type.googleapis.com/envoy.admin.v3.BootstrapConfigDump + bootstrap: + admin: + accessLog: + - name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + path: /dev/null + address: + socketAddress: + address: 127.0.0.1 + portValue: 19000 + dynamicResources: + adsConfig: + apiType: DELTA_GRPC + grpcServices: + - envoyGrpc: + clusterName: xds_cluster + setNodeOnFirstMessageOnly: true + transportApiVersion: V3 + cdsConfig: + ads: {} + resourceApiVersion: V3 + ldsConfig: + ads: {} + resourceApiVersion: V3 + layeredRuntime: + layers: + - name: global_config + staticLayer: + envoy.restart_features.use_eds_cache_for_ads: true + re2.max_program_size.error_level: 4294967295 + re2.max_program_size.warn_level: 1000 + overloadManager: + refreshInterval: 0.250s + resourceMonitors: + - name: envoy.resource_monitors.global_downstream_max_connections + typedConfig: + '@type': type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig + maxActiveDownstreamConnections: "50000" + staticResources: + clusters: + - connectTimeout: 0.250s + loadAssignment: + clusterName: prometheus_stats + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 127.0.0.1 + portValue: 19000 + name: prometheus_stats + type: STATIC + - connectTimeout: 10s + loadAssignment: + clusterName: xds_cluster + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: envoy-gateway + portValue: 18000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + name: xds_cluster + transportSocket: + name: envoy.transport_sockets.tls + typedConfig: + '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + commonTlsContext: + tlsCertificateSdsSecretConfigs: + - name: xds_certificate + sdsConfig: + pathConfigSource: + path: /sds/xds-certificate.json + resourceApiVersion: V3 + tlsParams: + tlsMaximumProtocolVersion: TLSv1_3 + validationContextSdsSecretConfig: + name: xds_trusted_ca + sdsConfig: + pathConfigSource: + path: /sds/xds-trusted-ca.json + resourceApiVersion: V3 + type: STRICT_DNS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + connectionKeepalive: + interval: 30s + timeout: 5s + - connectTimeout: 10s + loadAssignment: + clusterName: wasm_cluster + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: envoy-gateway + portValue: 18002 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + name: wasm_cluster + transportSocket: + name: envoy.transport_sockets.tls + typedConfig: + '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + commonTlsContext: + tlsCertificateSdsSecretConfigs: + - name: xds_certificate + sdsConfig: + pathConfigSource: + path: /sds/xds-certificate.json + resourceApiVersion: V3 + tlsParams: + tlsMaximumProtocolVersion: TLSv1_3 + validationContextSdsSecretConfig: + name: xds_trusted_ca + sdsConfig: + pathConfigSource: + path: /sds/xds-trusted-ca.json + resourceApiVersion: V3 + type: STRICT_DNS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: {} + listeners: + - address: + socketAddress: + address: 0.0.0.0 + portValue: 19001 + filterChains: + - filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + httpFilters: + - name: envoy.filters.http.health_check + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck + headers: + - name: :path + stringMatch: + exact: /ready + passThroughMode: false + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + routeConfig: + name: local_route + virtualHosts: + - domains: + - '*' + name: prometheus_stats + routes: + - match: + prefix: /stats/prometheus + route: + cluster: prometheus_stats + statPrefix: eg-ready-http + name: envoy-gateway-proxy-ready-0.0.0.0-19001 + - '@type': type.googleapis.com/envoy.admin.v3.EndpointsConfigDump + dynamicEndpointConfigs: + - endpointConfig: + '@type': type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment + clusterName: httproute/envoy-gateway-system/routes/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/envoy-gateway-system/routes/rule/0/backend/0 + - '@type': type.googleapis.com/envoy.admin.v3.ClustersConfigDump + dynamicActiveClusters: + - cluster: + '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster + circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/envoy-gateway-system/routes/rule/0 + lbPolicy: LEAST_REQUEST + name: httproute/envoy-gateway-system/routes/rule/0 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + - '@type': type.googleapis.com/envoy.admin.v3.ListenersConfigDump + dynamicListeners: + - activeState: + listener: + '@type': type.googleapis.com/envoy.config.listener.v3.Listener + accessLog: + - filter: + responseFlagFilter: + flags: + - NR + name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} + path: /dev/stdout + address: + socketAddress: + address: 0.0.0.0 + portValue: 10080 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + accessLog: + - name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} + path: /dev/stdout + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: envoy-gateway-system/eg/http + serverHeaderTransformation: PASS_THROUGH + statPrefix: http + useRemoteAddress: true + name: envoy-gateway-system/eg/http + drainType: MODIFY_ONLY + name: envoy-gateway-system/eg/http + perConnectionBufferLimitBytes: 32768 + - '@type': type.googleapis.com/envoy.admin.v3.RoutesConfigDump + dynamicRouteConfigs: + - routeConfig: + '@type': type.googleapis.com/envoy.config.route.v3.RouteConfiguration + ignorePortInHostMatching: true + name: envoy-gateway-system/eg/http + virtualHosts: + - domains: + - '*' + name: envoy-gateway-system/eg/http/* + routes: + - match: + pathSeparatedPrefix: /service + name: httproute/envoy-gateway-system/routes/rule/0/match/0/* + route: + cluster: httproute/envoy-gateway-system/routes/rule/0 + upgradeConfigs: + - upgradeType: websocket diff --git a/internal/cmd/egctl/translate.go b/internal/cmd/egctl/translate.go index a9d16269be5..48045591dd0 100644 --- a/internal/cmd/egctl/translate.go +++ b/internal/cmd/egctl/translate.go @@ -46,6 +46,8 @@ const ( gatewayAPIType = "gateway-api" xdsType = "xds" irType = "ir" + + dummyClusterIP = "1.2.3.4" ) type TranslationResult struct { @@ -576,7 +578,7 @@ func addMissingServices(requiredServices map[string]*corev1.Service, obj interfa refs = append(refs, rule.BackendRefs...) } case *gwapiv1a2.UDPRoute: - protocol = corev1.Protocol(gatewayapi.UDPProtocol) + protocol = gatewayapi.UDPProtocol objNamespace = route.Namespace for _, rule := range route.Spec.Rules { refs = append(refs, rule.BackendRefs...) @@ -609,12 +611,11 @@ func addMissingServices(requiredServices map[string]*corev1.Service, obj interfa }, Spec: corev1.ServiceSpec{ // Just a dummy IP - ClusterIP: "127.0.0.1", + ClusterIP: dummyClusterIP, Ports: []corev1.ServicePort{servicePort}, }, } requiredServices[key] = service - } else { inserted := false for _, port := range service.Spec.Ports { @@ -792,6 +793,10 @@ func kubernetesYAMLToResources(str string, addMissingResources bool) (*gatewayap }, Spec: typedSpec.(corev1.ServiceSpec), } + // fill with dummy IP when service clusterIP is empty + if len(service.Spec.ClusterIP) == 0 { + service.Spec.ClusterIP = dummyClusterIP + } resources.Services = append(resources.Services, service) case egv1a1.KindEnvoyPatchPolicy: typedSpec := spec.Interface() diff --git a/internal/cmd/egctl/translate_test.go b/internal/cmd/egctl/translate_test.go index c7d51b0e83a..085fae27fa1 100644 --- a/internal/cmd/egctl/translate_test.go +++ b/internal/cmd/egctl/translate_test.go @@ -281,6 +281,12 @@ func TestTranslate(t *testing.T) { to: "gateway-api", expect: false, }, + { + name: "no-service-cluster-ip", + from: "gateway-api", + to: "xds", + expect: true, + }, } flag.Parse() From 7414b53931081ecf85c881e33040802e0e892ffd Mon Sep 17 00:00:00 2001 From: shawnh2 Date: Tue, 2 Jul 2024 10:51:27 +0800 Subject: [PATCH 2/3] add missing resources check Signed-off-by: shawnh2 --- internal/cmd/egctl/translate.go | 4 ++-- internal/cmd/egctl/translate_test.go | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/internal/cmd/egctl/translate.go b/internal/cmd/egctl/translate.go index 48045591dd0..2bf4cda177f 100644 --- a/internal/cmd/egctl/translate.go +++ b/internal/cmd/egctl/translate.go @@ -793,8 +793,8 @@ func kubernetesYAMLToResources(str string, addMissingResources bool) (*gatewayap }, Spec: typedSpec.(corev1.ServiceSpec), } - // fill with dummy IP when service clusterIP is empty - if len(service.Spec.ClusterIP) == 0 { + if addMissingResources && len(service.Spec.ClusterIP) == 0 { + // fill with dummy IP when service clusterIP is empty service.Spec.ClusterIP = dummyClusterIP } resources.Services = append(resources.Services, service) diff --git a/internal/cmd/egctl/translate_test.go b/internal/cmd/egctl/translate_test.go index 085fae27fa1..28d07afc977 100644 --- a/internal/cmd/egctl/translate_test.go +++ b/internal/cmd/egctl/translate_test.go @@ -282,10 +282,11 @@ func TestTranslate(t *testing.T) { expect: false, }, { - name: "no-service-cluster-ip", - from: "gateway-api", - to: "xds", - expect: true, + name: "no-service-cluster-ip", + from: "gateway-api", + to: "xds", + expect: true, + extraArgs: []string{"--add-missing-resources"}, }, } From ce67d89ae6496bdfb888235a1eb5e7ba210d3220 Mon Sep 17 00:00:00 2001 From: shawnh2 Date: Fri, 5 Jul 2024 16:46:19 +0800 Subject: [PATCH 3/3] fix gen-check Signed-off-by: shawnh2 --- .../translate/out/no-service-cluster-ip.all.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml b/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml index 78917b18bc1..73ea76b01e6 100644 --- a/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml +++ b/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml @@ -277,10 +277,25 @@ xds: virtualHosts: - domains: - '*' + metadata: + filterMetadata: + envoy-gateway: + resources: + - kind: "" + name: eg + namespace: envoy-gateway-system + sectionName: http name: envoy-gateway-system/eg/http/* routes: - match: pathSeparatedPrefix: /service + metadata: + filterMetadata: + envoy-gateway: + resources: + - kind: HTTPRoute + name: routes + namespace: envoy-gateway-system name: httproute/envoy-gateway-system/routes/rule/0/match/0/* route: cluster: httproute/envoy-gateway-system/routes/rule/0