Repository: envoyproxy/gateway
Pull request #5569 (2025-03-21 06:00:45)

infra: delete resource if exists when using customized name
fixes: https://github.com/envoyproxy/gateway/issues/4380

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/envoyproxy/gateway/pull/5569?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) Report
Attention: Patch coverage is `9.09091%` with `30 lines` in your changes missing coverage. Please review.
> Project coverage is 65.17%. Comparing base [(`5cf6950`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/5cf695036c06c641d3827e0a786eb3daf7296816?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) to head [(`77ee41a`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/77ee41a55d2001de0fb96e580fa75acdb0078772?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).
> Report is 1 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/envoyproxy/gateway/pull/5569?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) | Patch % | Lines |
|---|---|---|
| [...ternal/infrastructure/kubernetes/infra\_resource.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/5569?src=pr&el=tree&filepath=internal%2Finfrastructure%2Fkubernetes%2Finfra_resource.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvaW5mcmFzdHJ1Y3R1cmUva3ViZXJuZXRlcy9pbmZyYV9yZXNvdXJjZS5nbw==) | 11.11% | [21 Missing and 3 partials :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/5569?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/infrastructure/kubernetes/infra\_client.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/5569?src=pr&el=tree&filepath=internal%2Finfrastructure%2Fkubernetes%2Finfra_client.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvaW5mcmFzdHJ1Y3R1cmUva3ViZXJuZXRlcy9pbmZyYV9jbGllbnQuZ28=) | 0.00% | [6 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/5569?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |

:x: Your patch check has failed because the patch coverage (9.09%) is below the target coverage (60.00%). You can increase the patch coverage or adjust the [target](https://docs.codecov.com/docs/commit-status#target) coverage.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #5569      +/-   ##
==========================================
- Coverage   65.19%   65.17%   -0.02%     
==========================================
  Files         213      213              
  Lines       34111    33987     -124     
==========================================
- Hits        22238    22152      -86     
+ Misses      10545    10506      -39     
- Partials     1328     1329       +1     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/envoyproxy/gateway/pull/5569?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
zirain: @arkodg should we highlight that EG does not guarantee with zero downtime when using customized name?

Patch:
diff --git a/internal/gatewayapi/resource/load.go b/internal/gatewayapi/resource/load.go
index 23f64c96a..4cbec0765 100644
--- a/internal/gatewayapi/resource/load.go
+++ b/internal/gatewayapi/resource/load.go
@@ -315,6 +315,8 @@ func loadKubernetesYAMLToResources(input []byte, addMissingResources bool) (*Res
 		case KindSecret:
 			typedData := data.Interface()
 			typedStringData := stringData.Interface()
+			typedSecretType := kobjVal.FieldByName("Type").Interface()
+
 			secret := &corev1.Secret{
 				TypeMeta: metav1.TypeMeta{
 					Kind: KindSecret,
@@ -323,6 +325,7 @@ func loadKubernetesYAMLToResources(input []byte, addMissingResources bool) (*Res
 					Name:      name,
 					Namespace: namespace,
 				},
+				Type:       typedSecretType.(corev1.SecretType),
 				Data:       typedData.(map[string][]byte),
 				StringData: typedStringData.(map[string]string),
 			}
diff --git a/internal/infrastructure/kubernetes/infra.go b/internal/infrastructure/kubernetes/infra.go
index a0615a4e8..82d51d066 100644
--- a/internal/infrastructure/kubernetes/infra.go
+++ b/internal/infrastructure/kubernetes/infra.go
@@ -20,6 +20,7 @@ import (
 	"github.com/envoyproxy/gateway/internal/envoygateway/config"
 	"github.com/envoyproxy/gateway/internal/infrastructure/kubernetes/proxy"
 	"github.com/envoyproxy/gateway/internal/infrastructure/kubernetes/ratelimit"
+	"github.com/envoyproxy/gateway/internal/logging"
 )
 
 var _ ResourceRender = &proxy.ResourceRender{}
@@ -58,6 +59,8 @@ type Infra struct {
 
 	// Client wrap k8s client.
 	Client *InfraClient
+
+	logger logging.Logger
 }
 
 // NewInfra returns a new Infra.
@@ -67,6 +70,7 @@ func NewInfra(cli client.Client, cfg *config.Server) *Infra {
 		DNSDomain:    cfg.DNSDomain,
 		EnvoyGateway: cfg.EnvoyGateway,
 		Client:       New(cli),
+		logger:       cfg.Logger.WithName(string(egv1a1.LogComponentInfrastructureRunner)),
 	}
 }
 
diff --git a/internal/infrastructure/kubernetes/infra_client.go b/internal/infrastructure/kubernetes/infra_client.go
index 0d3a01e5d..2cee23604 100644
--- a/internal/infrastructure/kubernetes/infra_client.go
+++ b/internal/infrastructure/kubernetes/infra_client.go
@@ -8,6 +8,7 @@ package kubernetes
 import (
 	"context"
 	"fmt"
+	"reflect"
 
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/types"
@@ -33,6 +34,41 @@ func (cli *InfraClient) ServerSideApply(ctx context.Context, obj client.Object)
 	return nil
 }
 
+// DeleteAllExcept delete all resources filter by ListOption except the one specified by key.
+func (cli *InfraClient) DeleteAllExcept(ctx context.Context, objList client.ObjectList, key client.ObjectKey, listOpts ...client.ListOption) error {
+	if err := cli.List(ctx, objList, listOpts...); err != nil {
+		if kerrors.IsNotFound(err) {
+			return nil
+		}
+		return err
+	}
+
+	v := reflect.ValueOf(objList).Elem()
+	items := v.FieldByName("Items")
+
+	// If there is only one item, we don't need to delete it,
+	// because it normally means custom resource name is not enabled.
+	if items.Len() <= 1 {
+		return nil
+	}
+
+	for i := range items.Len() {
+		item := items.Index(i)
+		name := item.FieldByName("Name")
+		namespace := item.FieldByName("Namespace")
+
+		if name.String() == key.Name && namespace.String() == key.Namespace {
+			continue
+		}
+
+		if err := cli.Delete(ctx, item.Addr().Interface().(client.Object)); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 func (cli *InfraClient) Delete(ctx context.Context, object client.Object) error {
 	if err := cli.Client.Delete(ctx, object); err != nil {
 		if kerrors.IsNotFound(err) {
diff --git a/internal/infrastructure/kubernetes/infra_resource.go b/internal/infrastructure/kubernetes/infra_resource.go
index 1bec17c09..6c2cacc2b 100644
--- a/internal/infrastructure/kubernetes/infra_resource.go
+++ b/internal/infrastructure/kubernetes/infra_resource.go
@@ -119,6 +119,17 @@ func (i *Infra) createOrUpdateDeployment(ctx context.Context, r ResourceRender)
 	}
 
 	defer func() {
+		deleteErr := i.Client.DeleteAllExcept(ctx, &appsv1.DeploymentList{}, client.ObjectKey{
+			Namespace: deployment.Namespace,
+			Name:      deployment.Name,
+		}, &client.ListOptions{
+			Namespace:     deployment.Namespace,
+			LabelSelector: r.LabelSelector(),
+		})
+		if deleteErr != nil {
+			i.logger.Error(deleteErr, "failed to delete all except deployment", "name", r.Name())
+		}
+
 		if err == nil {
 			resourceApplyDurationSeconds.With(labels...).Record(time.Since(startTime).Seconds())
 			resourceApplyTotal.WithSuccess(labels...).Increment()
@@ -192,7 +203,7 @@ func (i *Infra) createOrUpdateDaemonSet(ctx context.Context, r ResourceRender) (
 		return err
 	}
 
-	// delete the daemonset and return early
+	// delete the DaemonSet and return early
 	// this handles the case where a deployment has been
 	// configured.
 	if daemonSet == nil {
@@ -200,6 +211,17 @@ func (i *Infra) createOrUpdateDaemonSet(ctx context.Context, r ResourceRender) (
 	}
 
 	defer func() {
+		deleteErr := i.Client.DeleteAllExcept(ctx, &appsv1.DaemonSetList{}, client.ObjectKey{
+			Namespace: daemonSet.Namespace,
+			Name:      daemonSet.Name,
+		}, &client.ListOptions{
+			Namespace:     daemonSet.Namespace,
+			LabelSelector: r.LabelSelector(),
+		})
+		if deleteErr != nil {
+			i.logger.Error(deleteErr, "failed to delete all except deployment", "name", r.Name())
+		}
+
 		if err == nil {
 			resourceApplyDurationSeconds.With(labels...).Record(time.Since(startTime).Seconds())
 			resourceApplyTotal.WithSuccess(labels...).Increment()
@@ -358,6 +380,17 @@ func (i *Infra) createOrUpdateService(ctx context.Context, r ResourceRender) (er
 	}
 
 	defer func() {
+		deleteErr := i.Client.DeleteAllExcept(ctx, &corev1.ServiceList{}, client.ObjectKey{
+			Namespace: svc.Namespace,
+			Name:      svc.Name,
+		}, &client.ListOptions{
+			Namespace:     svc.Namespace,
+			LabelSelector: r.LabelSelector(),
+		})
+		if deleteErr != nil {
+			i.logger.Error(deleteErr, "failed to delete all except deployment", "name", r.Name())
+		}
+
 		if err == nil {
 			resourceApplyDurationSeconds.With(labels...).Record(time.Since(startTime).Seconds())
 			resourceApplyTotal.WithSuccess(labels...).Increment()
diff --git a/release-notes/current.yaml b/release-notes/current.yaml
index 7f2b62ad4..1d7679956 100644
--- a/release-notes/current.yaml
+++ b/release-notes/current.yaml
@@ -38,6 +38,7 @@ bug fixes: |
   Fix not logging an error and returning it in the K8s Reconcile method when a GatewayClass is not accepted.
   Fix allowing empty text field for opentelemetry sink when using JSON format.
   Fix an issue that SamplingFraction was not working.
+  Fix kubernetes resources not being deleted when the customized name used.
 
 # Enhancements that improve performance.
 performance improvements: |


Test patch:
diff --git a/internal/gatewayapi/resource/testdata/all-resources.in.yaml b/internal/gatewayapi/resource/testdata/all-resources.in.yaml
index 6bb599437..f5cba5ff6 100644
--- a/internal/gatewayapi/resource/testdata/all-resources.in.yaml
+++ b/internal/gatewayapi/resource/testdata/all-resources.in.yaml
@@ -257,6 +257,15 @@ stringData:
   secret: "literal value"
 ---
 apiVersion: v1
+kind: Secret
+metadata:
+  name: secret-with-type
+  namespace: default
+type: "type value"
+data:
+  .secret-file: dmFsdWUtMg0KDQo=
+---
+apiVersion: v1
 kind: ConfigMap
 metadata:
   name: configmap
diff --git a/internal/gatewayapi/resource/testdata/all-resources.out.yaml b/internal/gatewayapi/resource/testdata/all-resources.out.yaml
index b9cd72b99..55e2fadb4 100644
--- a/internal/gatewayapi/resource/testdata/all-resources.out.yaml
+++ b/internal/gatewayapi/resource/testdata/all-resources.out.yaml
@@ -270,6 +270,14 @@ secrets:
     namespace: default
   stringData:
     secret: literal value
+- data:
+    .secret-file: dmFsdWUtMg0KDQo=
+  kind: Secret
+  metadata:
+    creationTimestamp: null
+    name: secret-with-type
+    namespace: default
+  type: type value
 securityPolicies:
 - kind: SecurityPolicy
   metadata:
diff --git a/test/e2e/testdata/envoyproxy-custom-name.yaml b/test/e2e/testdata/envoyproxy-custom-name.yaml
new file mode 100644
index 000000000..a1061025e
--- /dev/null
+++ b/test/e2e/testdata/envoyproxy-custom-name.yaml
@@ -0,0 +1,120 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: deploy-custom-name
+  namespace: gateway-conformance-infra
+spec:
+  gatewayClassName: "{GATEWAY_CLASS_NAME}"
+  listeners:
+    - name: http
+      port: 80
+      protocol: HTTP
+      allowedRoutes:
+        namespaces:
+          from: All
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: EnvoyProxy
+metadata:
+  name: deploy-custom-name
+  namespace: gateway-conformance-infra
+spec:
+  ipFamily: IPv4
+  provider:
+    type: Kubernetes
+    kubernetes:
+      envoyDeployment:
+        name: deploy-custom-name
+      envoyService:
+        name: deploy-custom-name
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: deploy-route
+  namespace: gateway-conformance-infra
+spec:
+  parentRefs:
+    - name: deploy-custom-name
+  rules:
+    - backendRefs:
+        - name: infra-backend-v1
+          port: 8080
+      matches:
+        - path:
+            type: PathPrefix
+            value: /deploy
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: ds-custom-name
+  namespace: gateway-conformance-infra
+spec:
+  gatewayClassName: "{GATEWAY_CLASS_NAME}"
+  listeners:
+    - name: http
+      port: 80
+      protocol: HTTP
+      allowedRoutes:
+        namespaces:
+          from: All
+  infrastructure:
+    parametersRef:
+      group: gateway.envoyproxy.io
+      kind: EnvoyProxy
+      name: eg-daemonset
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: EnvoyProxy
+metadata:
+  name: eg-daemonset
+  namespace: gateway-conformance-infra
+spec:
+  ipFamily: IPv4
+  provider:
+    type: Kubernetes
+    kubernetes:
+      envoyDaemonSet:
+        patch:
+          type: StrategicMerge
+          value:
+            spec:
+              template:
+                spec:
+                  containers:
+                    - name: envoy
+                      readinessProbe:
+                        initialDelaySeconds: 5
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: EnvoyProxy
+metadata:
+  name: ds-custom-name
+  namespace: gateway-conformance-infra
+spec:
+  ipFamily: IPv4
+  provider:
+    type: Kubernetes
+    kubernetes:
+      envoyDaemonSet:
+        name: ds-custom-name
+      envoyService:
+        name: ds-custom-name
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: ds-route
+  namespace: gateway-conformance-infra
+spec:
+  parentRefs:
+    - name: ds-custom-name
+  rules:
+    - backendRefs:
+        - name: infra-backend-v1
+          port: 8080
+      matches:
+        - path:
+            type: PathPrefix
+            value: /daemonset
diff --git a/test/e2e/tests/envoyproxy.go b/test/e2e/tests/envoyproxy.go
new file mode 100644
index 000000000..b8980bd09
--- /dev/null
+++ b/test/e2e/tests/envoyproxy.go
@@ -0,0 +1,315 @@
+// Copyright Envoy Gateway Authors
+// SPDX-License-Identifier: Apache-2.0
+// The full text of the Apache license is available in the LICENSE file at
+// the root of the repo.
+
+//go:build e2e
+
+package tests
+
+import (
+	"context"
+	"fmt"
+	"strings"
+	"testing"
+	"time"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/apimachinery/pkg/util/wait"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
+	"sigs.k8s.io/gateway-api/conformance/utils/http"
+	"sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
+	"sigs.k8s.io/gateway-api/conformance/utils/suite"
+	"sigs.k8s.io/gateway-api/conformance/utils/tlog"
+)
+
+func init() {
+	ConformanceTests = append(ConformanceTests, EnvoyProxyCustomNameTest)
+}
+
+var EnvoyProxyCustomNameTest = suite.ConformanceTest{
+	ShortName:   "EnvoyProxyCustomName",
+	Description: "Test running Envoy with custom name",
+	Manifests:   []string{"testdata/envoyproxy-custom-name.yaml"},
+	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
+		t.Run("Deployment", func(t *testing.T) {
+			ns := "gateway-conformance-infra"
+			routeNN := types.NamespacedName{Name: "deploy-route", Namespace: ns}
+			gwNN := types.NamespacedName{Name: "deploy-custom-name", Namespace: ns}
+			OkResp := http.ExpectedResponse{
+				Request: http.Request{
+					Path: "/deploy",
+				},
+				Response: http.Response{
+					StatusCode: 200,
+				},
+				Namespace: ns,
+			}
+
+			// Make sure there's deployment for the gateway
+			err := checkEnvoyProxyDeployment(t, suite, gwNN, fmt.Sprintf("envoy-%s-%s", gwNN.Namespace, gwNN.Name))
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy deployment: %v", err)
+			}
+			err = checkEnvoyProxyService(t, suite, gwNN, fmt.Sprintf("envoy-%s-%s", gwNN.Namespace, gwNN.Name))
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy service: %v", err)
+			}
+			gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
+			// Send a request to a valid path and expect a successful response
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, OkResp)
+
+			// Update the Gateway to use a custom name
+			gw := &gwapiv1.Gateway{}
+			err = suite.Client.Get(context.Background(), gwNN, gw)
+			if err != nil {
+				t.Fatalf("Failed to get Gateway: %v", err)
+			}
+			gw.Spec.Infrastructure = &gwapiv1.GatewayInfrastructure{
+				ParametersRef: &gwapiv1.LocalParametersReference{
+					Name:  "deploy-custom-name",
+					Kind:  "EnvoyProxy",
+					Group: "gateway.envoyproxy.io",
+				},
+			}
+			err = suite.Client.Update(context.Background(), gw)
+			if err != nil {
+				t.Fatalf("Failed to update Gateway: %v", err)
+			}
+
+			err = checkEnvoyProxyDeployment(t, suite, gwNN, "deploy-custom-name")
+			if err != nil {
+				t.Fatalf("Failed to delete Gateway: %v", err)
+			}
+			err = checkEnvoyProxyService(t, suite, gwNN, "deploy-custom-name")
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy service: %v", err)
+			}
+			gwAddr = kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
+			// Send a request to a valid path and expect a successful response
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, OkResp)
+
+			// Rollback the Gateway to without custom name
+			gw = &gwapiv1.Gateway{}
+			err = suite.Client.Get(context.Background(), gwNN, gw)
+			if err != nil {
+				t.Fatalf("Failed to get Gateway: %v", err)
+			}
+			gw.Spec.Infrastructure = &gwapiv1.GatewayInfrastructure{}
+			err = suite.Client.Update(context.Background(), gw)
+			if err != nil {
+				t.Fatalf("Failed to update Gateway: %v", err)
+			}
+
+			// Make sure there's deployment for the gateway
+			err = checkEnvoyProxyDeployment(t, suite, gwNN, fmt.Sprintf("envoy-%s-%s", gwNN.Namespace, gwNN.Name))
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy deployment: %v", err)
+			}
+			err = checkEnvoyProxyService(t, suite, gwNN, fmt.Sprintf("envoy-%s-%s", gwNN.Namespace, gwNN.Name))
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy service: %v", err)
+			}
+			gwAddr = kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
+			// Send a request to a valid path and expect a successful response
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, OkResp)
+		})
+
+		t.Run("DaemonSet", func(t *testing.T) {
+			ns := "gateway-conformance-infra"
+			routeNN := types.NamespacedName{Name: "ds-route", Namespace: ns}
+			gwNN := types.NamespacedName{Name: "ds-custom-name", Namespace: ns}
+			OkResp := http.ExpectedResponse{
+				Request: http.Request{
+					Path: "/daemonset",
+				},
+				Response: http.Response{
+					StatusCode: 200,
+				},
+				Namespace: ns,
+			}
+
+			// Make sure there's DaemonSet for the gateway
+			err := checkEnvoyProxyDaemonSet(t, suite, gwNN, fmt.Sprintf("envoy-%s-%s", gwNN.Namespace, gwNN.Name))
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy deployment: %v", err)
+			}
+			err = checkEnvoyProxyService(t, suite, gwNN, fmt.Sprintf("envoy-%s-%s", gwNN.Namespace, gwNN.Name))
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy service: %v", err)
+			}
+			gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
+			// Send a request to a valid path and expect a successful response
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, OkResp)
+
+			// Update the Gateway to use a custom name
+			gw := &gwapiv1.Gateway{}
+			err = suite.Client.Get(context.Background(), gwNN, gw)
+			if err != nil {
+				t.Fatalf("Failed to get Gateway: %v", err)
+			}
+			gw.Spec.Infrastructure = &gwapiv1.GatewayInfrastructure{
+				ParametersRef: &gwapiv1.LocalParametersReference{
+					Name:  "ds-custom-name",
+					Kind:  "EnvoyProxy",
+					Group: "gateway.envoyproxy.io",
+				},
+			}
+			err = suite.Client.Update(context.Background(), gw)
+			if err != nil {
+				t.Fatalf("Failed to update Gateway: %v", err)
+			}
+
+			err = checkEnvoyProxyDaemonSet(t, suite, gwNN, "ds-custom-name")
+			if err != nil {
+				t.Fatalf("Failed to delete Gateway: %v", err)
+			}
+			err = checkEnvoyProxyService(t, suite, gwNN, "ds-custom-name")
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy service: %v", err)
+			}
+			gwAddr = kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
+			// Send a request to a valid path and expect a successful response
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, OkResp)
+
+			// Rollback the Gateway to without custom name
+			gw = &gwapiv1.Gateway{}
+			err = suite.Client.Get(context.Background(), gwNN, gw)
+			if err != nil {
+				t.Fatalf("Failed to get Gateway: %v", err)
+			}
+			gw.Spec.Infrastructure = &gwapiv1.GatewayInfrastructure{
+				ParametersRef: &gwapiv1.LocalParametersReference{
+					Name:  "eg-daemonset",
+					Kind:  "EnvoyProxy",
+					Group: "gateway.envoyproxy.io",
+				},
+			}
+			err = suite.Client.Update(context.Background(), gw)
+			if err != nil {
+				t.Fatalf("Failed to update Gateway: %v", err)
+			}
+
+			// Make sure there's DaemonSet for the gateway
+			err = checkEnvoyProxyDaemonSet(t, suite, gwNN, fmt.Sprintf("envoy-%s-%s", gwNN.Namespace, gwNN.Name))
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy deployment: %v", err)
+			}
+			err = checkEnvoyProxyService(t, suite, gwNN, fmt.Sprintf("envoy-%s-%s", gwNN.Namespace, gwNN.Name))
+			if err != nil {
+				t.Fatalf("Failed to check EnvoyProxy service: %v", err)
+			}
+			gwAddr = kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
+			// Send a request to a valid path and expect a successful response
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, OkResp)
+		})
+	},
+}
+
+func checkEnvoyProxyDeployment(t *testing.T, suite *suite.ConformanceTestSuite, gwNN types.NamespacedName, exceptName string) error {
+	// Make sure there's deployment for the gateway
+	return wait.PollUntilContextTimeout(context.TODO(), time.Second, suite.TimeoutConfig.CreateTimeout, true, func(ctx context.Context) (bool, error) {
+		deploys := &appsv1.DeploymentList{}
+		err := suite.Client.List(ctx, deploys, &client.ListOptions{
+			Namespace: "envoy-gateway-system",
+			LabelSelector: labels.SelectorFromSet(map[string]string{
+				"app.kubernetes.io/managed-by":                   "envoy-gateway",
+				"app.kubernetes.io/name":                         "envoy",
+				"gateway.envoyproxy.io/owning-gateway-name":      gwNN.Name,
+				"gateway.envoyproxy.io/owning-gateway-namespace": gwNN.Namespace,
+			}),
+		})
+		if err != nil {
+			return false, err
+		}
+		if len(deploys.Items) != 1 {
+			tlog.Logf(t, "Expected 1 Deployment for the Gateway, got %d", len(deploys.Items))
+			return false, nil
+		}
+
+		dp := deploys.Items[0]
+		if !strings.HasPrefix(dp.Name, exceptName) {
+			tlog.Logf(t, "Expected Deployment name has prefix '%s', got %s", exceptName, dp.Name)
+			return false, nil
+		}
+
+		if dp.Status.ReadyReplicas <= 0 {
+			tlog.Logf(t, "Expected Deployment %s ready", dp.Name)
+		}
+
+		tlog.Logf(t, "Check Envoy proxy deployment pass, name: %s", dp.Name)
+		return true, nil
+	})
+}
+
+func checkEnvoyProxyService(t *testing.T, suite *suite.ConformanceTestSuite, gwNN types.NamespacedName, exceptName string) error {
+	// Make sure there's deployment for the gateway
+	return wait.PollUntilContextTimeout(context.TODO(), time.Second, suite.TimeoutConfig.CreateTimeout, true, func(ctx context.Context) (bool, error) {
+		svcList := &corev1.ServiceList{}
+		err := suite.Client.List(ctx, svcList, &client.ListOptions{
+			Namespace: "envoy-gateway-system",
+			LabelSelector: labels.SelectorFromSet(map[string]string{
+				"app.kubernetes.io/managed-by":                   "envoy-gateway",
+				"app.kubernetes.io/name":                         "envoy",
+				"gateway.envoyproxy.io/owning-gateway-name":      gwNN.Name,
+				"gateway.envoyproxy.io/owning-gateway-namespace": gwNN.Namespace,
+			}),
+		})
+		if err != nil {
+			return false, err
+		}
+		if len(svcList.Items) != 1 {
+			tlog.Logf(t, "Expected 1 Service for the Gateway, got %d", len(svcList.Items))
+			return false, nil
+		}
+
+		svc := svcList.Items[0]
+		if !strings.HasPrefix(svc.Name, exceptName) {
+			tlog.Logf(t, "Expected Service name has prefix '%s', got %s", exceptName, svc.Name)
+			return false, nil
+		}
+
+		tlog.Logf(t, "Check envoy proxy service pass, name: %s", svc.Name)
+		return true, nil
+	})
+}
+
+func checkEnvoyProxyDaemonSet(t *testing.T, suite *suite.ConformanceTestSuite, gwNN types.NamespacedName, exceptName string) error {
+	// Make sure there's deployment for the gateway
+	return wait.PollUntilContextTimeout(context.TODO(), time.Second, suite.TimeoutConfig.CreateTimeout, true, func(ctx context.Context) (bool, error) {
+		dsList := &appsv1.DaemonSetList{}
+		err := suite.Client.List(ctx, dsList, &client.ListOptions{
+			Namespace: "envoy-gateway-system",
+			LabelSelector: labels.SelectorFromSet(map[string]string{
+				"app.kubernetes.io/managed-by":                   "envoy-gateway",
+				"app.kubernetes.io/name":                         "envoy",
+				"gateway.envoyproxy.io/owning-gateway-name":      gwNN.Name,
+				"gateway.envoyproxy.io/owning-gateway-namespace": gwNN.Namespace,
+			}),
+		})
+		if err != nil {
+			return false, err
+		}
+		if len(dsList.Items) != 1 {
+			tlog.Logf(t, "Expected 1 DaemonSet for the Gateway, got %d", len(dsList.Items))
+			return false, nil
+		}
+
+		ds := dsList.Items[0]
+		if !strings.HasPrefix(ds.Name, exceptName) {
+			tlog.Logf(t, "Expected DaemonSet name has prefix '%s', got %s", exceptName, ds.Name)
+			return false, nil
+		}
+
+		if ds.Status.NumberReady <= 0 {
+			tlog.Logf(t, "Expected DaemonSet %s ready", ds.Name)
+		}
+
+		tlog.Logf(t, "Check envoy proxy DaemonSet pass, name: %s", ds.Name)
+		return true, nil
+	})
+}