diff --git a/api/v1alpha1/envoygateway_helpers.go b/api/v1alpha1/envoygateway_helpers.go index 5f36282f5b5..0b1faf7e66a 100644 --- a/api/v1alpha1/envoygateway_helpers.go +++ b/api/v1alpha1/envoygateway_helpers.go @@ -234,6 +234,9 @@ func (r *EnvoyGatewayProvider) GetEnvoyGatewayKubeProvider() *EnvoyGatewayKubern r.Kubernetes.RateLimitDeployment.defaultKubernetesDeploymentSpec(DefaultRateLimitImage) + if r.Kubernetes.ShutdownManager == nil { + r.Kubernetes.ShutdownManager = &ShutdownManager{Image: ptr.To(DefaultShutdownManagerImage)} + } return r.Kubernetes } diff --git a/api/v1alpha1/envoygateway_types.go b/api/v1alpha1/envoygateway_types.go index ade9e056b1e..ffc871b517c 100644 --- a/api/v1alpha1/envoygateway_types.go +++ b/api/v1alpha1/envoygateway_types.go @@ -213,6 +213,10 @@ type EnvoyGatewayKubernetesProvider struct { // If it's not set up, leader election will be active by default, using Kubernetes' standard settings. // +optional LeaderElection *LeaderElection `json:"leaderElection,omitempty"` + + // ShutdownManager defines the configuration for the shutdown manager. + // +optional + ShutdownManager *ShutdownManager `json:"shutdownManager,omitempty"` } const ( @@ -536,6 +540,12 @@ type EnvoyGatewayAdminAddress struct { Host string `json:"host,omitempty"` } +// ShutdownManager defines the configuration for the shutdown manager. +type ShutdownManager struct { + // Image specifies the ShutdownManager container image to be used, instead of the default image. + Image *string `json:"image,omitempty"` +} + func init() { SchemeBuilder.Register(&EnvoyGateway{}) } diff --git a/internal/infrastructure/kubernetes/proxy/resource.go b/internal/infrastructure/kubernetes/proxy/resource.go index 323d2593d6e..47050998405 100644 --- a/internal/infrastructure/kubernetes/proxy/resource.go +++ b/internal/infrastructure/kubernetes/proxy/resource.go @@ -102,7 +102,8 @@ func enablePrometheus(infra *ir.ProxyInfra) bool { // expectedProxyContainers returns expected proxy containers. func expectedProxyContainers(infra *ir.ProxyInfra, containerSpec *egv1a1.KubernetesContainerSpec, - shutdownConfig *egv1a1.ShutdownConfig) ([]corev1.Container, error) { + shutdownConfig *egv1a1.ShutdownConfig, + shutdownManager *egv1a1.ShutdownManager) ([]corev1.Container, error) { // Define slice to hold container ports var ports []corev1.ContainerPort @@ -229,7 +230,7 @@ func expectedProxyContainers(infra *ir.ProxyInfra, }, { Name: "shutdown-manager", - Image: expectedShutdownManagerImage(), + Image: expectedShutdownManagerImage(shutdownManager), ImagePullPolicy: corev1.PullIfNotPresent, Command: []string{"envoy-gateway"}, Args: expectedShutdownManagerArgs(shutdownConfig), @@ -276,7 +277,10 @@ func expectedProxyContainers(infra *ir.ProxyInfra, return containers, nil } -func expectedShutdownManagerImage() string { +func expectedShutdownManagerImage(shutdownManager *egv1a1.ShutdownManager) string { + if shutdownManager != nil && shutdownManager.Image != nil { + return *shutdownManager.Image + } if v := version.Get().ShutdownManagerVersion; v != "" { return fmt.Sprintf("%s:%s", strings.Split(egv1a1.DefaultShutdownManagerImage, ":")[0], v) } diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider.go b/internal/infrastructure/kubernetes/proxy/resource_provider.go index 607aa117e7b..502620c1cd0 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider.go @@ -29,12 +29,15 @@ type ResourceRender struct { // Namespace is the Namespace used for managed infra. Namespace string + + ShutdownManager *egv1a1.ShutdownManager } -func NewResourceRender(ns string, infra *ir.ProxyInfra) *ResourceRender { +func NewResourceRender(ns string, infra *ir.ProxyInfra, gateway *egv1a1.EnvoyGateway) *ResourceRender { return &ResourceRender{ - Namespace: ns, - infra: infra, + Namespace: ns, + infra: infra, + ShutdownManager: gateway.GetEnvoyGatewayProvider().GetEnvoyGatewayKubeProvider().ShutdownManager, } } @@ -199,7 +202,7 @@ func (r *ResourceRender) Deployment() (*appsv1.Deployment, error) { } // Get expected bootstrap configurations rendered ProxyContainers - containers, err := expectedProxyContainers(r.infra, deploymentConfig.Container, proxyConfig.Spec.Shutdown) + containers, err := expectedProxyContainers(r.infra, deploymentConfig.Container, proxyConfig.Spec.Shutdown, r.ShutdownManager) if err != nil { return nil, err } @@ -288,7 +291,7 @@ func (r *ResourceRender) DaemonSet() (*appsv1.DaemonSet, error) { } // Get expected bootstrap configurations rendered ProxyContainers - containers, err := expectedProxyContainers(r.infra, daemonSetConfig.Container, proxyConfig.Spec.Shutdown) + containers, err := expectedProxyContainers(r.infra, daemonSetConfig.Container, proxyConfig.Spec.Shutdown, r.ShutdownManager) if err != nil { return nil, err } diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider_test.go b/internal/infrastructure/kubernetes/proxy/resource_provider_test.go index 6a9548817a9..4d11d534984 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider_test.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider_test.go @@ -90,15 +90,16 @@ func TestDeployment(t *testing.T) { require.NoError(t, err) cases := []struct { - caseName string - infra *ir.Infra - deploy *egv1a1.KubernetesDeploymentSpec - shutdown *egv1a1.ShutdownConfig - proxyLogging map[egv1a1.ProxyLogComponent]egv1a1.LogLevel - bootstrap string - telemetry *egv1a1.ProxyTelemetry - concurrency *int32 - extraArgs []string + caseName string + infra *ir.Infra + deploy *egv1a1.KubernetesDeploymentSpec + shutdown *egv1a1.ShutdownConfig + shutdownManager *egv1a1.ShutdownManager + proxyLogging map[egv1a1.ProxyLogComponent]egv1a1.LogLevel + bootstrap string + telemetry *egv1a1.ProxyTelemetry + concurrency *int32 + extraArgs []string }{ { caseName: "default", @@ -173,8 +174,7 @@ func TestDeployment(t *testing.T) { "env":[ {"name":"env_a","value":"env_a_value"}, {"name":"env_b","value":"env_b_value"} - ], - "image":"envoyproxy/gateway-dev:v1.2.3" + ] }] } } @@ -191,6 +191,9 @@ func TestDeployment(t *testing.T) { Duration: 15 * time.Second, }, }, + shutdownManager: &egv1a1.ShutdownManager{ + Image: ptr.To("privatereop/envoyproxy/gateway-dev:v1.2.3"), + }, }, { caseName: "bootstrap", @@ -544,11 +547,15 @@ func TestDeployment(t *testing.T) { tc.infra.Proxy.Config.Spec.Shutdown = tc.shutdown } + if tc.shutdownManager != nil { + cfg.EnvoyGateway.Provider.Kubernetes.ShutdownManager = tc.shutdownManager + } + if len(tc.extraArgs) > 0 { tc.infra.Proxy.Config.Spec.ExtraArgs = tc.extraArgs } - r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra()) + r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra(), cfg.EnvoyGateway) dp, err := r.Deployment() require.NoError(t, err) @@ -969,7 +976,7 @@ func TestDaemonSet(t *testing.T) { tc.infra.Proxy.Config.Spec.ExtraArgs = tc.extraArgs } - r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra()) + r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra(), cfg.EnvoyGateway) ds, err := r.DaemonSet() require.NoError(t, err) @@ -1084,7 +1091,7 @@ func TestService(t *testing.T) { provider.EnvoyService = tc.service } - r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra()) + r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra(), cfg.EnvoyGateway) svc, err := r.Service() require.NoError(t, err) @@ -1127,7 +1134,7 @@ func TestConfigMap(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra()) + r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra(), cfg.EnvoyGateway) cm, err := r.ConfigMap() require.NoError(t, err) @@ -1171,7 +1178,7 @@ func TestServiceAccount(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra()) + r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra(), cfg.EnvoyGateway) sa, err := r.ServiceAccount() require.NoError(t, err) @@ -1252,7 +1259,7 @@ func TestHorizontalPodAutoscaler(t *testing.T) { provider.GetEnvoyProxyKubeProvider() - r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra()) + r := NewResourceRender(cfg.Namespace, tc.infra.GetProxyInfra(), cfg.EnvoyGateway) hpa, err := r.HorizontalPodAutoscaler() require.NoError(t, err) diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/shutdown-manager.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/shutdown-manager.yaml index 7bcb064cdee..ba12fe74dfe 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/shutdown-manager.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/shutdown-manager.yaml @@ -249,7 +249,7 @@ spec: fieldRef: apiVersion: v1 fieldPath: metadata.name - image: envoyproxy/gateway-dev:v1.2.3 + image: privatereop/envoyproxy/gateway-dev:v1.2.3 imagePullPolicy: IfNotPresent lifecycle: preStop: diff --git a/internal/infrastructure/kubernetes/proxy_configmap_test.go b/internal/infrastructure/kubernetes/proxy_configmap_test.go index 4df19b223f2..b16a0f61bbf 100644 --- a/internal/infrastructure/kubernetes/proxy_configmap_test.go +++ b/internal/infrastructure/kubernetes/proxy_configmap_test.go @@ -111,7 +111,7 @@ func TestCreateOrUpdateProxyConfigMap(t *testing.T) { Build() } kube := NewInfra(cli, cfg) - r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra()) + r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra(), kube.EnvoyGateway) err := kube.createOrUpdateConfigMap(context.Background(), r) require.NoError(t, err) actual := &corev1.ConfigMap{ @@ -170,7 +170,7 @@ func TestDeleteConfigProxyMap(t *testing.T) { infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNamespaceLabel] = "default" infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNameLabel] = infra.Proxy.Name - r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra()) + r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra(), kube.EnvoyGateway) cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: kube.Namespace, diff --git a/internal/infrastructure/kubernetes/proxy_deployment_test.go b/internal/infrastructure/kubernetes/proxy_deployment_test.go index 1958dffd559..a1d595b750d 100644 --- a/internal/infrastructure/kubernetes/proxy_deployment_test.go +++ b/internal/infrastructure/kubernetes/proxy_deployment_test.go @@ -47,7 +47,7 @@ func TestCreateOrUpdateProxyDeployment(t *testing.T) { infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNamespaceLabel] = "default" infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNameLabel] = infra.Proxy.Name - r := proxy.NewResourceRender(cfg.Namespace, infra.GetProxyInfra()) + r := proxy.NewResourceRender(cfg.Namespace, infra.GetProxyInfra(), cfg.EnvoyGateway) deploy, err := r.Deployment() require.NoError(t, err) @@ -119,7 +119,7 @@ func TestCreateOrUpdateProxyDeployment(t *testing.T) { } kube := NewInfra(cli, cfg) - r := proxy.NewResourceRender(kube.Namespace, tc.in.GetProxyInfra()) + r := proxy.NewResourceRender(kube.Namespace, tc.in.GetProxyInfra(), cfg.EnvoyGateway) err := kube.createOrUpdateDeployment(context.Background(), r) require.NoError(t, err) @@ -162,7 +162,7 @@ func TestDeleteProxyDeployment(t *testing.T) { infra := ir.NewInfra() infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNamespaceLabel] = "default" infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNameLabel] = infra.Proxy.Name - r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra()) + r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra(), kube.EnvoyGateway) err := kube.createOrUpdateDeployment(context.Background(), r) require.NoError(t, err) diff --git a/internal/infrastructure/kubernetes/proxy_infra.go b/internal/infrastructure/kubernetes/proxy_infra.go index 203c3fa4ef6..e0b1fc5f9cc 100644 --- a/internal/infrastructure/kubernetes/proxy_infra.go +++ b/internal/infrastructure/kubernetes/proxy_infra.go @@ -23,7 +23,7 @@ func (i *Infra) CreateOrUpdateProxyInfra(ctx context.Context, infra *ir.Infra) e return errors.New("infra proxy ir is nil") } - r := proxy.NewResourceRender(i.Namespace, infra.GetProxyInfra()) + r := proxy.NewResourceRender(i.Namespace, infra.GetProxyInfra(), i.EnvoyGateway) return i.createOrUpdate(ctx, r) } @@ -33,6 +33,6 @@ func (i *Infra) DeleteProxyInfra(ctx context.Context, infra *ir.Infra) error { return errors.New("infra ir is nil") } - r := proxy.NewResourceRender(i.Namespace, infra.GetProxyInfra()) + r := proxy.NewResourceRender(i.Namespace, infra.GetProxyInfra(), i.EnvoyGateway) return i.delete(ctx, r) } diff --git a/internal/infrastructure/kubernetes/proxy_service_test.go b/internal/infrastructure/kubernetes/proxy_service_test.go index 6aa221a4113..0c1c0cc6b89 100644 --- a/internal/infrastructure/kubernetes/proxy_service_test.go +++ b/internal/infrastructure/kubernetes/proxy_service_test.go @@ -33,7 +33,7 @@ func TestDeleteProxyService(t *testing.T) { infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNamespaceLabel] = "default" infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNameLabel] = infra.Proxy.Name - r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra()) + r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra(), kube.EnvoyGateway) err := kube.createOrUpdateService(context.Background(), r) require.NoError(t, err) diff --git a/internal/infrastructure/kubernetes/proxy_serviceaccount_test.go b/internal/infrastructure/kubernetes/proxy_serviceaccount_test.go index abed92cbccb..2b92fc53417 100644 --- a/internal/infrastructure/kubernetes/proxy_serviceaccount_test.go +++ b/internal/infrastructure/kubernetes/proxy_serviceaccount_test.go @@ -188,7 +188,7 @@ func TestCreateOrUpdateProxyServiceAccount(t *testing.T) { kube := NewInfra(cli, cfg) - r := proxy.NewResourceRender(kube.Namespace, tc.in.GetProxyInfra()) + r := proxy.NewResourceRender(kube.Namespace, tc.in.GetProxyInfra(), cfg.EnvoyGateway) err = kube.createOrUpdateServiceAccount(context.Background(), r) require.NoError(t, err) @@ -221,7 +221,7 @@ func TestDeleteProxyServiceAccount(t *testing.T) { infra := ir.NewInfra() infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNamespaceLabel] = "default" infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNameLabel] = infra.Proxy.Name - r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra()) + r := proxy.NewResourceRender(kube.Namespace, infra.GetProxyInfra(), kube.EnvoyGateway) err := kube.createOrUpdateServiceAccount(context.Background(), r) require.NoError(t, err)