@@ -7,6 +7,7 @@ package kubernetes
77
88import (
99 "context"
10+ "encoding/json"
1011 "errors"
1112 "fmt"
1213 "os"
@@ -282,6 +283,90 @@ func TestDeleteProxyInfra(t *testing.T) {
282283 }
283284}
284285
286+ func TestCreateProxyInfraDeletesTrackedServiceAccountsWhenListIsStale (t * testing.T ) {
287+ listStaleInterceptor := interceptor.Funcs {
288+ Patch : interceptorFunc .Patch ,
289+ List : func (ctx context.Context , clnt client.WithWatch , list client.ObjectList , opts ... client.ListOption ) error {
290+ if err := clnt .List (ctx , list , opts ... ); err != nil {
291+ return err
292+ }
293+ saList , ok := list .(* corev1.ServiceAccountList )
294+ if ok && len (saList .Items ) > 1 {
295+ saList .Items = saList .Items [:1 ]
296+ }
297+ return nil
298+ },
299+ }
300+
301+ cli := fakeclient .NewClientBuilder ().
302+ WithScheme (envoygateway .GetScheme ()).
303+ WithInterceptorFuncs (listStaleInterceptor ).
304+ Build ()
305+ kube := newTestInfraWithClient (t , cli )
306+ kube .EnvoyGateway .Provider = & egv1a1.EnvoyGatewayProvider {
307+ Type : egv1a1 .ProviderTypeKubernetes ,
308+ Kubernetes : & egv1a1.EnvoyGatewayKubernetesProvider {
309+ Deploy : & egv1a1.KubernetesDeployMode {
310+ Type : new (egv1a1.KubernetesDeployModeTypeGatewayNamespace ),
311+ },
312+ },
313+ }
314+
315+ ctx := context .Background ()
316+ require .NoError (t , setupOwnerReferenceResources (ctx , kube .Client ))
317+
318+ gwNN := types.NamespacedName {Namespace : "ns1" , Name : "gateway-1" }
319+
320+ defaultInfra := newProxyInfraForGateway (gwNN , "" )
321+ require .NoError (t , kube .CreateOrUpdateProxyInfra (ctx , defaultInfra ))
322+ assertTrackingConfigMap (t , ctx , kube , defaultInfra , []proxy.ManagedProxyResourceRef {
323+ {Kind : "ServiceAccount" , Namespace : gwNN .Namespace , Name : gwNN .Name },
324+ {Kind : "Service" , Namespace : gwNN .Namespace , Name : gwNN .Name },
325+ {Kind : "Deployment" , Namespace : gwNN .Namespace , Name : gwNN .Name },
326+ })
327+
328+ customAInfra := newProxyInfraForGateway (gwNN , "custom-a-sa" )
329+ require .NoError (t , kube .CreateOrUpdateProxyInfra (ctx , customAInfra ))
330+ assertTrackingConfigMap (t , ctx , kube , customAInfra , []proxy.ManagedProxyResourceRef {
331+ {Kind : "ServiceAccount" , Namespace : gwNN .Namespace , Name : "custom-a-sa" },
332+ {Kind : "Service" , Namespace : gwNN .Namespace , Name : gwNN .Name },
333+ {Kind : "Deployment" , Namespace : gwNN .Namespace , Name : gwNN .Name },
334+ })
335+ require .NoError (t , kube .Client .Get (ctx , client.ObjectKey {Namespace : gwNN .Namespace , Name : "custom-a-sa" }, & corev1.ServiceAccount {}))
336+ require .True (t , kerrors .IsNotFound (kube .Client .Get (ctx , gwNN , & corev1.ServiceAccount {})))
337+
338+ customBInfra := newProxyInfraForGateway (gwNN , "custom-b-sa" )
339+ require .NoError (t , kube .CreateOrUpdateProxyInfra (ctx , customBInfra ))
340+ assertTrackingConfigMap (t , ctx , kube , customBInfra , []proxy.ManagedProxyResourceRef {
341+ {Kind : "ServiceAccount" , Namespace : gwNN .Namespace , Name : "custom-b-sa" },
342+ {Kind : "Service" , Namespace : gwNN .Namespace , Name : gwNN .Name },
343+ {Kind : "Deployment" , Namespace : gwNN .Namespace , Name : gwNN .Name },
344+ })
345+ require .NoError (t , kube .Client .Get (ctx , client.ObjectKey {Namespace : gwNN .Namespace , Name : "custom-b-sa" }, & corev1.ServiceAccount {}))
346+ require .True (t , kerrors .IsNotFound (kube .Client .Get (ctx , client.ObjectKey {Namespace : gwNN .Namespace , Name : "custom-a-sa" }, & corev1.ServiceAccount {})))
347+ }
348+
349+ func TestCreateProxyInfraTracksRefsInControllerNamespaceConfigMapForMergedGateways (t * testing.T ) {
350+ kube := newTestInfra (t )
351+ ctx := context .Background ()
352+ require .NoError (t , setupOwnerReferenceResources (ctx , kube .Client ))
353+
354+ infra := ir .NewInfra ()
355+ infra .Proxy .Metadata .Labels = proxy .EnvoyAppLabel ()
356+ infra .Proxy .Metadata .Labels [gatewayapi .OwningGatewayClassLabel ] = testGatewayClass
357+ infra .Proxy .Metadata .OwnerReference = & ir.ResourceMetadata {
358+ Kind : resource .KindGatewayClass ,
359+ Name : testGatewayClass ,
360+ }
361+
362+ require .NoError (t , kube .CreateOrUpdateProxyInfra (ctx , infra ))
363+ assertTrackingConfigMap (t , ctx , kube , infra , []proxy.ManagedProxyResourceRef {
364+ {Kind : "ServiceAccount" , Namespace : kube .ControllerNamespace , Name : expectedName (infra .Proxy , false )},
365+ {Kind : "Service" , Namespace : kube .ControllerNamespace , Name : expectedName (infra .Proxy , false )},
366+ {Kind : "Deployment" , Namespace : kube .ControllerNamespace , Name : expectedName (infra .Proxy , false )},
367+ })
368+ }
369+
285370// This function uses setup creating Resources for OwnerReference.
286371// When the default case, ProxyInfra Get OwnerReference from GatewayClass.
287372// When enable GatewayNamespace mode, ProxyInfra Get OwnerReference from Gateway.
@@ -304,3 +389,47 @@ func setupOwnerReferenceResources(ctx context.Context, client *InfraClient) erro
304389 }
305390 return client .Create (ctx , gw )
306391}
392+
393+ func newProxyInfraForGateway (gwNN types.NamespacedName , serviceAccountName string ) * ir.Infra {
394+ infra := ir .NewInfra ()
395+ infra .Proxy .Name = gwNN .Name
396+ infra .Proxy .Namespace = gwNN .Namespace
397+ infra .Proxy .Metadata .Labels = proxy .EnvoyAppLabel ()
398+ infra .Proxy .Metadata .Labels [gatewayapi .OwningGatewayNamespaceLabel ] = gwNN .Namespace
399+ infra .Proxy .Metadata .Labels [gatewayapi .OwningGatewayNameLabel ] = gwNN .Name
400+ infra .Proxy .Metadata .OwnerReference = & ir.ResourceMetadata {
401+ Kind : resource .KindGateway ,
402+ Name : gwNN .Name ,
403+ }
404+ infra .Proxy .Config = & egv1a1.EnvoyProxy {
405+ Spec : egv1a1.EnvoyProxySpec {
406+ Provider : & egv1a1.EnvoyProxyProvider {
407+ Type : egv1a1 .EnvoyProxyProviderTypeKubernetes ,
408+ Kubernetes : egv1a1 .DefaultEnvoyProxyKubeProvider (),
409+ },
410+ },
411+ }
412+ if serviceAccountName != "" {
413+ infra .Proxy .Config .Spec .Provider .Kubernetes .EnvoyServiceAccount = & egv1a1.KubernetesServiceAccountSpec {
414+ Name : & serviceAccountName ,
415+ }
416+ }
417+ return infra
418+ }
419+
420+ func assertTrackingConfigMap (t * testing.T , ctx context.Context , kube * Infra , infra * ir.Infra , expected []proxy.ManagedProxyResourceRef ) {
421+ t .Helper ()
422+
423+ render , err := proxy .NewResourceRender (ctx , kube , infra )
424+ require .NoError (t , err )
425+
426+ cm := & corev1.ConfigMap {}
427+ require .NoError (t , kube .APIReader .Get (ctx , client.ObjectKey {
428+ Namespace : kube .ControllerNamespace ,
429+ Name : render .TrackingConfigMapName (),
430+ }, cm ))
431+
432+ var actual []proxy.ManagedProxyResourceRef
433+ require .NoError (t , json .Unmarshal ([]byte (cm .Data [trackedProxyRefsDataKey ]), & actual ))
434+ require .Equal (t , expected , actual )
435+ }
0 commit comments