github.com/cilium/cilium@v1.16.2/pkg/ipam/metadata/manager_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package metadata
     5  
     6  import (
     7  	"errors"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/require"
    11  	"k8s.io/client-go/tools/cache"
    12  
    13  	"github.com/cilium/cilium/pkg/annotation"
    14  	"github.com/cilium/cilium/pkg/ipam"
    15  	"github.com/cilium/cilium/pkg/k8s/resource"
    16  	slim_core_v1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1"
    17  	slim_meta_v1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1"
    18  )
    19  
    20  type mockStore[T comparable] map[resource.Key]T
    21  
    22  func (m mockStore[T]) GetByKey(key resource.Key) (item T, exists bool, err error) {
    23  	item, exists = m[key]
    24  	return item, exists, nil
    25  }
    26  
    27  func (m mockStore[T]) Get(obj T) (item T, exists bool, err error) {
    28  	panic("not implemented")
    29  }
    30  
    31  func (m mockStore[T]) List() []T {
    32  	panic("not implemented")
    33  }
    34  
    35  func (m mockStore[T]) IterKeys() resource.KeyIter {
    36  	panic("not implemented")
    37  }
    38  
    39  func (m mockStore[T]) IndexKeys(indexName, indexedValue string) ([]string, error) {
    40  	panic("not implemented")
    41  }
    42  
    43  func (m mockStore[T]) ByIndex(indexName, indexedValue string) ([]T, error) {
    44  	panic("not implemented")
    45  }
    46  
    47  func (m mockStore[T]) CacheStore() cache.Store {
    48  	panic("not implemented")
    49  }
    50  
    51  func (m mockStore[T]) Release() {
    52  	panic("not implemented")
    53  }
    54  
    55  func podKey(ns, name string) resource.Key {
    56  	return resource.Key{
    57  		Namespace: ns,
    58  		Name:      name,
    59  	}
    60  }
    61  
    62  func namespaceKey(name string) resource.Key {
    63  	return resource.Key{
    64  		Name: name,
    65  	}
    66  }
    67  
    68  func TestManager_GetIPPoolForPod(t *testing.T) {
    69  	m := &manager{
    70  		namespaceStore: mockStore[*slim_core_v1.Namespace]{
    71  			namespaceKey("default"): &slim_core_v1.Namespace{},
    72  			namespaceKey("special"): &slim_core_v1.Namespace{
    73  				ObjectMeta: slim_meta_v1.ObjectMeta{
    74  					Annotations: map[string]string{
    75  						annotation.IPAMPoolKey: "namespace-pool",
    76  					},
    77  				},
    78  			},
    79  		},
    80  		podStore: mockStore[*slim_core_v1.Pod]{
    81  			podKey("default", "client"): &slim_core_v1.Pod{},
    82  			podKey("default", "custom-workload"): &slim_core_v1.Pod{
    83  				ObjectMeta: slim_meta_v1.ObjectMeta{
    84  					Annotations: map[string]string{
    85  						annotation.IPAMPoolKey: "custom-pool",
    86  					},
    87  				},
    88  			},
    89  			podKey("default", "custom-workload2"): &slim_core_v1.Pod{
    90  				ObjectMeta: slim_meta_v1.ObjectMeta{
    91  					Annotations: map[string]string{
    92  						annotation.IPAMIPv4PoolKey: "ipv4-pool",
    93  					},
    94  				},
    95  			},
    96  			podKey("default", "custom-workload3"): &slim_core_v1.Pod{
    97  				ObjectMeta: slim_meta_v1.ObjectMeta{
    98  					Annotations: map[string]string{
    99  						annotation.IPAMIPv4PoolKey: "ipv4-pool",
   100  						annotation.IPAMPoolKey:     "custom-pool",
   101  					},
   102  				},
   103  			},
   104  			podKey("default", "custom-workload4"): &slim_core_v1.Pod{
   105  				ObjectMeta: slim_meta_v1.ObjectMeta{
   106  					Annotations: map[string]string{
   107  						annotation.IPAMIPv4PoolKey: "ipv4-pool",
   108  						annotation.IPAMIPv6PoolKey: "ipv6-pool",
   109  					},
   110  				},
   111  			},
   112  			podKey("default", "custom-workload5"): &slim_core_v1.Pod{
   113  				ObjectMeta: slim_meta_v1.ObjectMeta{
   114  					Annotations: map[string]string{
   115  						annotation.IPAMIPv4PoolKey: "ipv4-pool",
   116  						annotation.IPAMIPv6PoolKey: "ipv6-pool",
   117  						annotation.IPAMPoolKey:     "custom-pool",
   118  					},
   119  				},
   120  			},
   121  
   122  			podKey("special", "server"): &slim_core_v1.Pod{},
   123  			podKey("special", "server2"): &slim_core_v1.Pod{
   124  				ObjectMeta: slim_meta_v1.ObjectMeta{
   125  					Annotations: map[string]string{
   126  						annotation.IPAMPoolKey: "pod-pool",
   127  					},
   128  				},
   129  			},
   130  
   131  			podKey("missing-ns", "pod"): &slim_core_v1.Pod{},
   132  		},
   133  	}
   134  
   135  	tests := []struct {
   136  		name     string
   137  		owner    string
   138  		ipfamily ipam.Family
   139  		wantPool string
   140  		wantErr  error
   141  	}{
   142  		{
   143  			name:     "no annotations",
   144  			owner:    "default/client",
   145  			ipfamily: ipam.IPv4,
   146  			wantPool: ipam.PoolDefault().String(),
   147  		},
   148  		{
   149  			name:     "not a pod name",
   150  			owner:    "router",
   151  			ipfamily: ipam.IPv4,
   152  			wantPool: ipam.PoolDefault().String(),
   153  		},
   154  		{
   155  			name:     "also not a pod name (due to underline)",
   156  			owner:    "default/xwing_net2",
   157  			ipfamily: ipam.IPv4,
   158  			wantPool: ipam.PoolDefault().String(),
   159  		},
   160  		{
   161  			name:     "pod annotation",
   162  			owner:    "default/custom-workload",
   163  			ipfamily: ipam.IPv4,
   164  			wantPool: "custom-pool",
   165  		},
   166  		{
   167  			name:     "pod annotation only ipv4 pool request ipv4",
   168  			owner:    "default/custom-workload2",
   169  			ipfamily: ipam.IPv4,
   170  			wantPool: "ipv4-pool",
   171  		},
   172  		{
   173  			name:     "pod annotation only ipv4 pool request ipv6",
   174  			owner:    "default/custom-workload2",
   175  			ipfamily: ipam.IPv6,
   176  			wantPool: ipam.PoolDefault().String(),
   177  		},
   178  		{
   179  			name:     "pod annotation ipv4 and custom pool request ipv4",
   180  			owner:    "default/custom-workload3",
   181  			ipfamily: ipam.IPv4,
   182  			wantPool: "ipv4-pool",
   183  		},
   184  		{
   185  			name:     "pod annotation ipv4 and custom pool request ipv6",
   186  			owner:    "default/custom-workload3",
   187  			ipfamily: ipam.IPv6,
   188  			wantPool: "custom-pool",
   189  		},
   190  		{
   191  			name:     "pod annotation ipv4 and ipv6 pool request ipv4",
   192  			owner:    "default/custom-workload4",
   193  			ipfamily: ipam.IPv4,
   194  			wantPool: "ipv4-pool",
   195  		},
   196  		{
   197  			name:     "pod annotation ipv4 and ipv6 pool request ipv6",
   198  			owner:    "default/custom-workload4",
   199  			ipfamily: ipam.IPv6,
   200  			wantPool: "ipv6-pool",
   201  		},
   202  		{
   203  			name:     "pod annotation ipv4, ipv6 and custom pool request ipv4",
   204  			owner:    "default/custom-workload3",
   205  			ipfamily: ipam.IPv4,
   206  			wantPool: "ipv4-pool",
   207  		},
   208  		{
   209  			name:     "pod annotation ipv4, ipv6 and custom pool request ipv6",
   210  			owner:    "default/custom-workload5",
   211  			ipfamily: ipam.IPv6,
   212  			wantPool: "ipv6-pool",
   213  		},
   214  		{
   215  			name:     "missing pod",
   216  			owner:    "does-not/exist",
   217  			ipfamily: ipam.IPv4,
   218  			wantErr:  &ResourceNotFound{Resource: "Pod"},
   219  		},
   220  		{
   221  			name:     "missing namespace",
   222  			owner:    "missing-ns/pod",
   223  			ipfamily: ipam.IPv4,
   224  			wantErr:  &ResourceNotFound{Resource: "Namespace"},
   225  		},
   226  	}
   227  
   228  	for _, tt := range tests {
   229  		t.Run(tt.name, func(t *testing.T) {
   230  			gotPool, err := m.GetIPPoolForPod(tt.owner, tt.ipfamily)
   231  			if !errors.Is(err, tt.wantErr) {
   232  				t.Errorf("GetIPPoolForPod() error = %v, wantErr %v", err, tt.wantErr)
   233  				return
   234  			}
   235  			if gotPool != tt.wantPool {
   236  				t.Errorf("GetIPPoolForPod() gotPool = %v, want %v", gotPool, tt.wantPool)
   237  			}
   238  		})
   239  	}
   240  }
   241  
   242  func TestDefaultManager_DefaultPool(t *testing.T) {
   243  	defaultPoolManager := defaultIPPoolManager{}
   244  
   245  	ipv4Pool, err := defaultPoolManager.GetIPPoolForPod("", ipam.IPv4)
   246  	require.Nil(t, err)
   247  	require.Equal(t, ipam.PoolDefault(), ipam.Pool(ipv4Pool))
   248  
   249  	ipv6Pool, err := defaultPoolManager.GetIPPoolForPod("", ipam.IPv6)
   250  	require.Nil(t, err)
   251  	require.Equal(t, ipam.PoolDefault(), ipam.Pool(ipv6Pool))
   252  }