github.com/cilium/cilium@v1.16.2/operator/identitygc/gc_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package identitygc
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/cilium/hive/cell"
    13  	"github.com/cilium/hive/hivetest"
    14  	"go.uber.org/goleak"
    15  	corev1 "k8s.io/api/core/v1"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  
    18  	authIdentity "github.com/cilium/cilium/operator/auth/identity"
    19  	"github.com/cilium/cilium/operator/auth/spire"
    20  	"github.com/cilium/cilium/operator/k8s"
    21  	cmtypes "github.com/cilium/cilium/pkg/clustermesh/types"
    22  	"github.com/cilium/cilium/pkg/hive"
    23  	v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    24  	k8sClient "github.com/cilium/cilium/pkg/k8s/client"
    25  	"github.com/cilium/cilium/pkg/metrics"
    26  	"github.com/cilium/cilium/pkg/option"
    27  )
    28  
    29  func TestIdentitiesGC(t *testing.T) {
    30  	defer goleak.VerifyNone(
    31  		t,
    32  		// To ignore goroutine started from sigs.k8s.io/controller-runtime/pkg/log.go
    33  		// init function
    34  		goleak.IgnoreTopFunction("time.Sleep"),
    35  	)
    36  
    37  	var clientset k8sClient.Clientset
    38  	var authIdentityClient authIdentity.Provider
    39  
    40  	hive := hive.New(
    41  		cell.Config(cmtypes.DefaultClusterInfo),
    42  		metrics.Metric(NewMetrics),
    43  
    44  		// provide a fake clientset
    45  		k8sClient.FakeClientCell,
    46  		// provide a fake spire client
    47  		spire.FakeCellClient,
    48  		// provide resources
    49  		k8s.ResourcesCell,
    50  
    51  		// provide identities gc test configuration
    52  		cell.Provide(func() Config {
    53  			return Config{
    54  				Interval:         50 * time.Millisecond,
    55  				HeartbeatTimeout: 50 * time.Millisecond,
    56  
    57  				RateInterval: time.Minute,
    58  				RateLimit:    2500,
    59  			}
    60  		}),
    61  		cell.Provide(func() SharedConfig {
    62  			return SharedConfig{
    63  				IdentityAllocationMode: option.IdentityAllocationModeCRD,
    64  			}
    65  		}),
    66  
    67  		// initial setup for the test
    68  		cell.Invoke(func(c k8sClient.Clientset, authClient authIdentity.Provider) error {
    69  			clientset = c
    70  			authIdentityClient = authClient
    71  			if err := setupK8sNodes(clientset); err != nil {
    72  				return err
    73  			}
    74  			if err := setupCiliumIdentities(clientset); err != nil {
    75  				return err
    76  			}
    77  			if err := setupCiliumEndpoint(clientset); err != nil {
    78  				return err
    79  			}
    80  			if err := setupAuthIdentities(authIdentityClient); err != nil {
    81  				return err
    82  			}
    83  
    84  			return nil
    85  		}),
    86  
    87  		cell.Invoke(registerGC),
    88  	)
    89  
    90  	ctx, cancel := context.WithCancel(context.Background())
    91  	defer cancel()
    92  
    93  	tlog := hivetest.Logger(t)
    94  	if err := hive.Start(tlog, ctx); err != nil {
    95  		t.Fatalf("failed to start: %s", err)
    96  	}
    97  
    98  	var (
    99  		identities *v2.CiliumIdentityList
   100  		err        error
   101  	)
   102  	for retry := 0; retry < 10; retry++ {
   103  		identities, err = clientset.CiliumV2().CiliumIdentities().List(
   104  			ctx,
   105  			metav1.ListOptions{
   106  				LabelSelector: metav1.FormatLabelSelector(
   107  					&metav1.LabelSelector{
   108  						MatchLabels: map[string]string{
   109  							"test": "identities-gc",
   110  						},
   111  					},
   112  				),
   113  			},
   114  		)
   115  		if err == nil && len(identities.Items) == 1 {
   116  			break
   117  		}
   118  		time.Sleep(50 * time.Millisecond)
   119  	}
   120  	if err != nil {
   121  		t.Fatalf("unable to list Cilium identities: %s", err)
   122  	}
   123  	if len(identities.Items) != 1 {
   124  		t.Fatalf("expected 1 Cilium identity, got %d", len(identities.Items))
   125  	}
   126  	if identities.Items[0].Name != "99999" {
   127  		t.Fatalf("expected Cilium identity \"99999\", got %q", identities.Items[0].Name)
   128  	}
   129  
   130  	authIdentities, err := authIdentityClient.List(ctx)
   131  	if err != nil {
   132  		t.Fatalf("unable to list Cilium Auth identities: %s", err)
   133  	}
   134  
   135  	if len(authIdentities) != 1 {
   136  		t.Fatalf("expected 1 Cilium Auth identity, got %d", len(authIdentities))
   137  	}
   138  
   139  	if authIdentities[0] != "99999" {
   140  		t.Fatalf("expected Cilium Auth identity \"99999\", got %q", authIdentities[0])
   141  	}
   142  
   143  	if err := hive.Stop(tlog, ctx); err != nil {
   144  		t.Fatalf("failed to stop: %s", err)
   145  	}
   146  }
   147  
   148  func setupK8sNodes(clientset k8sClient.Clientset) error {
   149  	nodes := []*corev1.Node{
   150  		{
   151  			TypeMeta: metav1.TypeMeta{
   152  				APIVersion: "v1",
   153  				Kind:       "Node",
   154  			},
   155  			ObjectMeta: metav1.ObjectMeta{
   156  				Name:   "node-control-plane",
   157  				Labels: map[string]string{"kubernetes.io/hostname": "node-control-plane"},
   158  			},
   159  		},
   160  		{
   161  			TypeMeta: metav1.TypeMeta{
   162  				APIVersion: "v1",
   163  				Kind:       "Node",
   164  			},
   165  			ObjectMeta: metav1.ObjectMeta{
   166  				Name:   "node-worker",
   167  				Labels: map[string]string{"kubernetes.io/hostname": "node-worker"},
   168  			},
   169  		},
   170  	}
   171  	for _, node := range nodes {
   172  		if _, err := clientset.CoreV1().Nodes().
   173  			Create(context.Background(), node, metav1.CreateOptions{}); err != nil {
   174  			return fmt.Errorf("failed to create node %v: %w", node, err)
   175  		}
   176  	}
   177  	return nil
   178  }
   179  
   180  func setupCiliumIdentities(clientset k8sClient.Clientset) error {
   181  	identities := []*v2.CiliumIdentity{
   182  		{
   183  			TypeMeta: metav1.TypeMeta{
   184  				APIVersion: "cilium.io/v2",
   185  				Kind:       "CiliumIdentity",
   186  			},
   187  			ObjectMeta: metav1.ObjectMeta{
   188  				Name: "88888",
   189  				Labels: map[string]string{
   190  					"test": "identities-gc",
   191  				},
   192  			},
   193  		},
   194  		{
   195  			TypeMeta: metav1.TypeMeta{
   196  				APIVersion: "cilium.io/v2",
   197  				Kind:       "CiliumIdentity",
   198  			},
   199  			ObjectMeta: metav1.ObjectMeta{
   200  				Name: "99999",
   201  				Labels: map[string]string{
   202  					"test": "identities-gc",
   203  				},
   204  			},
   205  		},
   206  	}
   207  	for _, identity := range identities {
   208  		if _, err := clientset.CiliumV2().CiliumIdentities().
   209  			Create(context.Background(), identity, metav1.CreateOptions{}); err != nil {
   210  			return fmt.Errorf("failed to create identity %v: %w", identity, err)
   211  		}
   212  	}
   213  	return nil
   214  }
   215  
   216  func setupAuthIdentities(client authIdentity.Provider) error {
   217  	if err := client.Upsert(context.Background(), "88888"); err != nil {
   218  		return err
   219  	}
   220  	if err := client.Upsert(context.Background(), "99999"); err != nil {
   221  		return err
   222  	}
   223  	return nil
   224  }
   225  
   226  func setupCiliumEndpoint(clientset k8sClient.Clientset) error {
   227  	endpoint := &v2.CiliumEndpoint{
   228  		ObjectMeta: metav1.ObjectMeta{
   229  			Name: "test-endpoint",
   230  		},
   231  		Status: v2.EndpointStatus{
   232  			Identity: &v2.EndpointIdentity{
   233  				ID: 99999,
   234  			},
   235  		},
   236  	}
   237  	if _, err := clientset.CiliumV2().CiliumEndpoints("").
   238  		Create(context.Background(), endpoint, metav1.CreateOptions{}); err != nil {
   239  		return fmt.Errorf("failed to create endpoint %v: %w", endpoint, err)
   240  	}
   241  	return nil
   242  }