github.com/cilium/cilium@v1.16.2/pkg/k8s/resource_ctors.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package k8s 5 6 import ( 7 "fmt" 8 "sync" 9 10 "github.com/cilium/cilium/pkg/allocator" 11 "github.com/cilium/cilium/pkg/identity/key" 12 13 "github.com/cilium/hive/cell" 14 "github.com/spf13/pflag" 15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 k8sRuntime "k8s.io/apimachinery/pkg/runtime" 17 "k8s.io/apimachinery/pkg/watch" 18 "k8s.io/client-go/tools/cache" 19 20 cilium_api_v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 21 cilium_api_v2alpha1 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2alpha1" 22 "github.com/cilium/cilium/pkg/k8s/client" 23 "github.com/cilium/cilium/pkg/k8s/resource" 24 slim_corev1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1" 25 slim_discoveryv1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/discovery/v1" 26 slim_discoveryv1beta1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/discovery/v1beta1" 27 slim_networkingv1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/networking/v1" 28 "github.com/cilium/cilium/pkg/k8s/synced" 29 "github.com/cilium/cilium/pkg/k8s/types" 30 "github.com/cilium/cilium/pkg/k8s/utils" 31 "github.com/cilium/cilium/pkg/k8s/version" 32 "github.com/cilium/cilium/pkg/node" 33 "github.com/cilium/cilium/pkg/promise" 34 ) 35 36 // Config defines the configuration options for k8s resources. 37 type Config struct { 38 EnableK8sEndpointSlice bool 39 40 // K8sServiceProxyName is the value of service.kubernetes.io/service-proxy-name label, 41 // that identifies the service objects Cilium should handle. 42 // If the provided value is an empty string, Cilium will manage service objects when 43 // the label is not present. For more details - 44 // https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/2447-Make-kube-proxy-service-abstraction-optional 45 K8sServiceProxyName string 46 } 47 48 // DefaultConfig represents the default k8s resources config values. 49 var DefaultConfig = Config{ 50 EnableK8sEndpointSlice: true, 51 } 52 53 const ( 54 NamespaceIndex = "namespace" 55 ByKeyIndex = "by-key-index" 56 ) 57 58 // Flags implements the cell.Flagger interface. 59 func (def Config) Flags(flags *pflag.FlagSet) { 60 flags.Bool("enable-k8s-endpoint-slice", def.EnableK8sEndpointSlice, "Enables k8s EndpointSlice feature in Cilium if the k8s cluster supports it") 61 flags.String("k8s-service-proxy-name", def.K8sServiceProxyName, "Value of K8s service-proxy-name label for which Cilium handles the services (empty = all services without service.kubernetes.io/service-proxy-name label)") 62 } 63 64 // namespaceIndexFunc is an IndexFunc that indexes Namespace of Kubernetes 65 // types by their namespace. 66 func namespaceIndexFunc(obj any) ([]string, error) { 67 object, ok := obj.(utils.NamespaceNameGetter) 68 if !ok { 69 return nil, fmt.Errorf("unexpected object type: %T", obj) 70 } 71 return []string{object.GetNamespace()}, nil 72 } 73 74 func GetIdentitiesByKeyFunc(keyFunc func(map[string]string) allocator.AllocatorKey) func(obj interface{}) ([]string, error) { 75 return func(obj interface{}) ([]string, error) { 76 if identity, ok := obj.(*cilium_api_v2.CiliumIdentity); ok { 77 return []string{keyFunc(identity.SecurityLabels).GetKey()}, nil 78 } 79 return []string{}, fmt.Errorf("object other than CiliumIdentity was pushed to the store") 80 } 81 } 82 83 // Dependencies for Cilium resources that may be used by Cilium Agent. 84 // When CRDSyncPromise is provided, watchers of resources using this 85 // will block until all CRDs used by the agent have been registered. 86 // Agent will fail to start if Cilium Operator does not register all 87 // the CRDs in time. 88 type CiliumResourceParams struct { 89 cell.In 90 91 Lifecycle cell.Lifecycle 92 ClientSet client.Clientset 93 CRDSyncPromise promise.Promise[synced.CRDSync] `optional:"true"` 94 } 95 96 // ServiceResource builds the Resource[Service] object. 97 func ServiceResource(lc cell.Lifecycle, cfg Config, cs client.Clientset, opts ...func(*metav1.ListOptions)) (resource.Resource[*slim_corev1.Service], error) { 98 if !cs.IsEnabled() { 99 return nil, nil 100 } 101 optsModifier, err := utils.GetServiceAndEndpointListOptionsModifier(cfg.K8sServiceProxyName) 102 if err != nil { 103 return nil, err 104 } 105 indexers := cache.Indexers{ 106 NamespaceIndex: namespaceIndexFunc, 107 } 108 lw := utils.ListerWatcherWithModifiers( 109 utils.ListerWatcherFromTyped[*slim_corev1.ServiceList](cs.Slim().CoreV1().Services("")), 110 append(opts, optsModifier)..., 111 ) 112 return resource.New[*slim_corev1.Service]( 113 lc, lw, 114 resource.WithMetric("Service"), 115 resource.WithIndexers(indexers), 116 ), nil 117 } 118 119 func NodeResource(lc cell.Lifecycle, cs client.Clientset, opts ...func(*metav1.ListOptions)) (resource.Resource[*slim_corev1.Node], error) { 120 if !cs.IsEnabled() { 121 return nil, nil 122 } 123 lw := utils.ListerWatcherWithModifiers( 124 utils.ListerWatcherFromTyped[*slim_corev1.NodeList](cs.Slim().CoreV1().Nodes()), 125 opts..., 126 ) 127 return resource.New[*slim_corev1.Node](lc, lw, resource.WithMetric("Node")), nil 128 } 129 130 func CiliumNodeResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2.CiliumNode], error) { 131 if !params.ClientSet.IsEnabled() { 132 return nil, nil 133 } 134 lw := utils.ListerWatcherWithModifiers( 135 utils.ListerWatcherFromTyped[*cilium_api_v2.CiliumNodeList](params.ClientSet.CiliumV2().CiliumNodes()), 136 opts..., 137 ) 138 return resource.New[*cilium_api_v2.CiliumNode](params.Lifecycle, lw, 139 resource.WithMetric("CiliumNode"), 140 resource.WithStoppableInformer(), 141 resource.WithCRDSync(params.CRDSyncPromise), // optional, can be nil 142 ), nil 143 } 144 145 func PodResource(lc cell.Lifecycle, cs client.Clientset, opts ...func(*metav1.ListOptions)) (resource.Resource[*slim_corev1.Pod], error) { 146 if !cs.IsEnabled() { 147 return nil, nil 148 } 149 lw := utils.ListerWatcherWithModifiers( 150 utils.ListerWatcherFromTyped[*slim_corev1.PodList](cs.Slim().CoreV1().Pods("")), 151 opts..., 152 ) 153 return resource.New[*slim_corev1.Pod](lc, lw, resource.WithMetric("Pod")), nil 154 } 155 156 func NamespaceResource(lc cell.Lifecycle, cs client.Clientset, opts ...func(*metav1.ListOptions)) (resource.Resource[*slim_corev1.Namespace], error) { 157 if !cs.IsEnabled() { 158 return nil, nil 159 } 160 lw := utils.ListerWatcherWithModifiers( 161 utils.ListerWatcherFromTyped[*slim_corev1.NamespaceList](cs.Slim().CoreV1().Namespaces()), 162 opts..., 163 ) 164 return resource.New[*slim_corev1.Namespace](lc, lw, resource.WithMetric("Namespace")), nil 165 } 166 167 func LBIPPoolsResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2alpha1.CiliumLoadBalancerIPPool], error) { 168 if !params.ClientSet.IsEnabled() { 169 return nil, nil 170 } 171 lw := utils.ListerWatcherWithModifiers( 172 utils.ListerWatcherFromTyped[*cilium_api_v2alpha1.CiliumLoadBalancerIPPoolList](params.ClientSet.CiliumV2alpha1().CiliumLoadBalancerIPPools()), 173 opts..., 174 ) 175 return resource.New[*cilium_api_v2alpha1.CiliumLoadBalancerIPPool](params.Lifecycle, lw, resource.WithMetric("CiliumLoadBalancerIPPool"), resource.WithCRDSync(params.CRDSyncPromise)), nil 176 } 177 178 func CiliumIdentityResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2.CiliumIdentity], error) { 179 if !params.ClientSet.IsEnabled() { 180 return nil, nil 181 } 182 lw := utils.ListerWatcherWithModifiers( 183 utils.ListerWatcherFromTyped[*cilium_api_v2.CiliumIdentityList](params.ClientSet.CiliumV2().CiliumIdentities()), 184 opts..., 185 ) 186 187 indexers := cache.Indexers{ 188 ByKeyIndex: GetIdentitiesByKeyFunc((&key.GlobalIdentity{}).PutKeyFromMap), 189 } 190 191 return resource.New[*cilium_api_v2.CiliumIdentity](params.Lifecycle, lw, resource.WithMetric("CiliumIdentityList"), resource.WithIndexers(indexers), resource.WithCRDSync(params.CRDSyncPromise)), nil 192 } 193 194 func NetworkPolicyResource(lc cell.Lifecycle, cs client.Clientset, opts ...func(*metav1.ListOptions)) (resource.Resource[*slim_networkingv1.NetworkPolicy], error) { 195 if !cs.IsEnabled() { 196 return nil, nil 197 } 198 lw := utils.ListerWatcherWithModifiers( 199 utils.ListerWatcherFromTyped[*slim_networkingv1.NetworkPolicyList](cs.Slim().NetworkingV1().NetworkPolicies("")), 200 opts..., 201 ) 202 return resource.New[*slim_networkingv1.NetworkPolicy](lc, lw, resource.WithMetric("NetworkPolicy")), nil 203 } 204 205 func CiliumNetworkPolicyResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2.CiliumNetworkPolicy], error) { 206 if !params.ClientSet.IsEnabled() { 207 return nil, nil 208 } 209 lw := utils.ListerWatcherWithModifiers( 210 utils.ListerWatcherFromTyped[*cilium_api_v2.CiliumNetworkPolicyList](params.ClientSet.CiliumV2().CiliumNetworkPolicies("")), 211 opts..., 212 ) 213 return resource.New[*cilium_api_v2.CiliumNetworkPolicy](params.Lifecycle, lw, resource.WithMetric("CiliumNetworkPolicy"), resource.WithCRDSync(params.CRDSyncPromise)), nil 214 } 215 216 func CiliumClusterwideNetworkPolicyResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2.CiliumClusterwideNetworkPolicy], error) { 217 if !params.ClientSet.IsEnabled() { 218 return nil, nil 219 } 220 lw := utils.ListerWatcherWithModifiers( 221 utils.ListerWatcherFromTyped[*cilium_api_v2.CiliumClusterwideNetworkPolicyList](params.ClientSet.CiliumV2().CiliumClusterwideNetworkPolicies()), 222 opts..., 223 ) 224 return resource.New[*cilium_api_v2.CiliumClusterwideNetworkPolicy](params.Lifecycle, lw, resource.WithMetric("CiliumClusterwideNetworkPolicy"), resource.WithCRDSync(params.CRDSyncPromise)), nil 225 } 226 227 func CiliumCIDRGroupResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2alpha1.CiliumCIDRGroup], error) { 228 if !params.ClientSet.IsEnabled() { 229 return nil, nil 230 } 231 lw := utils.ListerWatcherWithModifiers( 232 utils.ListerWatcherFromTyped[*cilium_api_v2alpha1.CiliumCIDRGroupList](params.ClientSet.CiliumV2alpha1().CiliumCIDRGroups()), 233 opts..., 234 ) 235 return resource.New[*cilium_api_v2alpha1.CiliumCIDRGroup](params.Lifecycle, lw, resource.WithMetric("CiliumCIDRGroup"), resource.WithCRDSync(params.CRDSyncPromise)), nil 236 } 237 238 func CiliumPodIPPoolResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2alpha1.CiliumPodIPPool], error) { 239 if !params.ClientSet.IsEnabled() { 240 return nil, nil 241 } 242 lw := utils.ListerWatcherWithModifiers( 243 utils.ListerWatcherFromTyped[*cilium_api_v2alpha1.CiliumPodIPPoolList](params.ClientSet.CiliumV2alpha1().CiliumPodIPPools()), 244 opts..., 245 ) 246 return resource.New[*cilium_api_v2alpha1.CiliumPodIPPool](params.Lifecycle, lw, resource.WithMetric("CiliumPodIPPool"), resource.WithCRDSync(params.CRDSyncPromise)), nil 247 } 248 249 func CiliumBGPPeeringPolicyResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2alpha1.CiliumBGPPeeringPolicy], error) { 250 if !params.ClientSet.IsEnabled() { 251 return nil, nil 252 } 253 254 lw := utils.ListerWatcherWithModifiers( 255 utils.ListerWatcherFromTyped[*cilium_api_v2alpha1.CiliumBGPPeeringPolicyList](params.ClientSet.CiliumV2alpha1().CiliumBGPPeeringPolicies()), 256 opts..., 257 ) 258 return resource.New[*cilium_api_v2alpha1.CiliumBGPPeeringPolicy](params.Lifecycle, lw, resource.WithMetric("CiliumBGPPeeringPolicies"), resource.WithCRDSync(params.CRDSyncPromise)), nil 259 } 260 261 func CiliumBGPNodeConfigResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2alpha1.CiliumBGPNodeConfig], error) { 262 if !params.ClientSet.IsEnabled() { 263 return nil, nil 264 } 265 266 lw := utils.ListerWatcherWithModifiers( 267 utils.ListerWatcherFromTyped[*cilium_api_v2alpha1.CiliumBGPNodeConfigList](params.ClientSet.CiliumV2alpha1().CiliumBGPNodeConfigs()), 268 opts..., 269 ) 270 return resource.New[*cilium_api_v2alpha1.CiliumBGPNodeConfig](params.Lifecycle, lw, resource.WithMetric("CiliumBGPNodeConfig"), resource.WithCRDSync(params.CRDSyncPromise)), nil 271 } 272 273 func CiliumBGPAdvertisementResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2alpha1.CiliumBGPAdvertisement], error) { 274 if !params.ClientSet.IsEnabled() { 275 return nil, nil 276 } 277 278 lw := utils.ListerWatcherWithModifiers( 279 utils.ListerWatcherFromTyped[*cilium_api_v2alpha1.CiliumBGPAdvertisementList](params.ClientSet.CiliumV2alpha1().CiliumBGPAdvertisements()), 280 opts..., 281 ) 282 return resource.New[*cilium_api_v2alpha1.CiliumBGPAdvertisement](params.Lifecycle, lw, resource.WithMetric("CiliumBGPAdvertisement"), resource.WithCRDSync(params.CRDSyncPromise)), nil 283 } 284 285 func CiliumBGPPeerConfigResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2alpha1.CiliumBGPPeerConfig], error) { 286 if !params.ClientSet.IsEnabled() { 287 return nil, nil 288 } 289 290 lw := utils.ListerWatcherWithModifiers( 291 utils.ListerWatcherFromTyped[*cilium_api_v2alpha1.CiliumBGPPeerConfigList](params.ClientSet.CiliumV2alpha1().CiliumBGPPeerConfigs()), 292 opts..., 293 ) 294 return resource.New[*cilium_api_v2alpha1.CiliumBGPPeerConfig](params.Lifecycle, lw, resource.WithMetric("CiliumBGPPeerConfig"), resource.WithCRDSync(params.CRDSyncPromise)), nil 295 } 296 297 func EndpointsResource(lc cell.Lifecycle, cfg Config, cs client.Clientset, opts ...func(*metav1.ListOptions)) (resource.Resource[*Endpoints], error) { 298 if !cs.IsEnabled() { 299 return nil, nil 300 } 301 endpointsOptsModifier, err := utils.GetServiceAndEndpointListOptionsModifier(cfg.K8sServiceProxyName) 302 if err != nil { 303 return nil, err 304 } 305 306 endpointSliceOptsModifier, err := utils.GetEndpointSliceListOptionsModifier() 307 if err != nil { 308 return nil, err 309 } 310 311 lw := &endpointsListerWatcher{ 312 cs: cs, 313 enableK8sEndpointSlice: cfg.EnableK8sEndpointSlice, 314 endpointsOptsModifiers: append(opts, endpointsOptsModifier), 315 endpointSlicesOptsModifiers: append(opts, endpointSliceOptsModifier), 316 } 317 return resource.New[*Endpoints]( 318 lc, 319 lw, 320 resource.WithLazyTransform(lw.getSourceObj, transformEndpoint), 321 resource.WithMetric("Endpoint"), 322 resource.WithName("endpoints"), 323 ), nil 324 } 325 326 // endpointsListerWatcher implements List and Watch for endpoints/endpointslices. It 327 // performs the capability check on first call to List/Watch. This allows constructing 328 // the resource before the client has been started and capabilities have been probed. 329 type endpointsListerWatcher struct { 330 cs client.Clientset 331 enableK8sEndpointSlice bool 332 endpointsOptsModifiers []func(*metav1.ListOptions) 333 endpointSlicesOptsModifiers []func(*metav1.ListOptions) 334 sourceObj k8sRuntime.Object 335 336 once sync.Once 337 cachedListerWatcher cache.ListerWatcher 338 } 339 340 func (lw *endpointsListerWatcher) getSourceObj() k8sRuntime.Object { 341 lw.getListerWatcher() // force the construction 342 return lw.sourceObj 343 } 344 345 func (lw *endpointsListerWatcher) getListerWatcher() cache.ListerWatcher { 346 lw.once.Do(func() { 347 if lw.enableK8sEndpointSlice && version.Capabilities().EndpointSlice { 348 if version.Capabilities().EndpointSliceV1 { 349 log.Info("Using discoveryv1.EndpointSlice") 350 lw.cachedListerWatcher = utils.ListerWatcherFromTyped[*slim_discoveryv1.EndpointSliceList]( 351 lw.cs.Slim().DiscoveryV1().EndpointSlices(""), 352 ) 353 lw.sourceObj = &slim_discoveryv1.EndpointSlice{} 354 } else { 355 log.Info("Using discoveryv1beta1.EndpointSlice") 356 lw.cachedListerWatcher = utils.ListerWatcherFromTyped[*slim_discoveryv1beta1.EndpointSliceList]( 357 lw.cs.Slim().DiscoveryV1beta1().EndpointSlices(""), 358 ) 359 lw.sourceObj = &slim_discoveryv1beta1.EndpointSlice{} 360 } 361 lw.cachedListerWatcher = utils.ListerWatcherWithModifiers(lw.cachedListerWatcher, lw.endpointSlicesOptsModifiers...) 362 } else { 363 log.Info("Using v1.Endpoints") 364 lw.cachedListerWatcher = utils.ListerWatcherFromTyped[*slim_corev1.EndpointsList]( 365 lw.cs.Slim().CoreV1().Endpoints(""), 366 ) 367 lw.sourceObj = &slim_corev1.Endpoints{} 368 lw.cachedListerWatcher = utils.ListerWatcherWithModifiers(lw.cachedListerWatcher, lw.endpointsOptsModifiers...) 369 } 370 }) 371 return lw.cachedListerWatcher 372 } 373 374 func (lw *endpointsListerWatcher) List(opts metav1.ListOptions) (k8sRuntime.Object, error) { 375 return lw.getListerWatcher().List(opts) 376 } 377 378 func (lw *endpointsListerWatcher) Watch(opts metav1.ListOptions) (watch.Interface, error) { 379 return lw.getListerWatcher().Watch(opts) 380 } 381 382 func transformEndpoint(obj any) (any, error) { 383 switch obj := obj.(type) { 384 case *slim_corev1.Endpoints: 385 return ParseEndpoints(obj), nil 386 case *slim_discoveryv1.EndpointSlice: 387 return ParseEndpointSliceV1(obj), nil 388 case *slim_discoveryv1beta1.EndpointSlice: 389 return ParseEndpointSliceV1Beta1(obj), nil 390 default: 391 return nil, fmt.Errorf("%T not a known endpoint or endpoint slice object", obj) 392 } 393 } 394 395 // CiliumSlimEndpointResource uses the "localNode" IndexFunc to build the resource indexer. 396 // The IndexFunc accesses the local node info to get its IP, so it depends on the local node store 397 // to initialize it before the first access. 398 // To reflect this, the node.LocalNodeStore dependency is explicitly requested in the function 399 // signature. 400 func CiliumSlimEndpointResource(params CiliumResourceParams, _ *node.LocalNodeStore, opts ...func(*metav1.ListOptions)) (resource.Resource[*types.CiliumEndpoint], error) { 401 if !params.ClientSet.IsEnabled() { 402 return nil, nil 403 } 404 lw := utils.ListerWatcherWithModifiers( 405 utils.ListerWatcherFromTyped[*cilium_api_v2.CiliumEndpointList](params.ClientSet.CiliumV2().CiliumEndpoints(slim_corev1.NamespaceAll)), 406 opts..., 407 ) 408 indexers := cache.Indexers{ 409 "localNode": ciliumEndpointLocalPodIndexFunc, 410 } 411 return resource.New[*types.CiliumEndpoint](params.Lifecycle, lw, 412 resource.WithLazyTransform(func() k8sRuntime.Object { 413 return &cilium_api_v2.CiliumEndpoint{} 414 }, TransformToCiliumEndpoint), 415 resource.WithMetric("CiliumEndpoint"), 416 resource.WithIndexers(indexers), 417 resource.WithStoppableInformer(), 418 resource.WithCRDSync(params.CRDSyncPromise), 419 ), nil 420 } 421 422 // ciliumEndpointLocalPodIndexFunc is an IndexFunc that indexes only local 423 // CiliumEndpoints, by their local Node IP. 424 func ciliumEndpointLocalPodIndexFunc(obj any) ([]string, error) { 425 cep, ok := obj.(*types.CiliumEndpoint) 426 if !ok { 427 return nil, fmt.Errorf("unexpected object type: %T", obj) 428 } 429 indices := []string{} 430 if cep.Networking == nil { 431 log.WithField("ciliumendpoint", cep.GetNamespace()+"/"+cep.GetName()). 432 Debug("cannot index CiliumEndpoint by node without network status") 433 return nil, nil 434 } 435 if cep.Networking.NodeIP == node.GetCiliumEndpointNodeIP() { 436 indices = append(indices, cep.Networking.NodeIP) 437 } 438 return indices, nil 439 } 440 441 // CiliumEndpointSliceResource uses the "localNode" IndexFunc to build the resource indexer. 442 // The IndexFunc accesses the local node info to get its IP, so it depends on the local node store 443 // to initialize it before the first access. 444 // To reflect this, the node.LocalNodeStore dependency is explicitly requested in the function 445 // signature. 446 func CiliumEndpointSliceResource(params CiliumResourceParams, _ *node.LocalNodeStore, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2alpha1.CiliumEndpointSlice], error) { 447 if !params.ClientSet.IsEnabled() { 448 return nil, nil 449 } 450 lw := utils.ListerWatcherWithModifiers( 451 utils.ListerWatcherFromTyped[*cilium_api_v2alpha1.CiliumEndpointSliceList](params.ClientSet.CiliumV2alpha1().CiliumEndpointSlices()), 452 opts..., 453 ) 454 indexers := cache.Indexers{ 455 "localNode": ciliumEndpointSliceLocalPodIndexFunc, 456 } 457 return resource.New[*cilium_api_v2alpha1.CiliumEndpointSlice](params.Lifecycle, lw, 458 resource.WithMetric("CiliumEndpointSlice"), 459 resource.WithIndexers(indexers), 460 resource.WithStoppableInformer(), 461 resource.WithCRDSync(params.CRDSyncPromise), 462 ), nil 463 } 464 465 // ciliumEndpointSliceLocalPodIndexFunc is an IndexFunc that indexes CiliumEndpointSlices 466 // by their corresponding Pod, which are running locally on this Node. 467 func ciliumEndpointSliceLocalPodIndexFunc(obj any) ([]string, error) { 468 ces, ok := obj.(*cilium_api_v2alpha1.CiliumEndpointSlice) 469 if !ok { 470 return nil, fmt.Errorf("unexpected object type: %T", obj) 471 } 472 indices := []string{} 473 for _, ep := range ces.Endpoints { 474 if ep.Networking.NodeIP == node.GetCiliumEndpointNodeIP() { 475 indices = append(indices, ep.Networking.NodeIP) 476 break 477 } 478 } 479 return indices, nil 480 } 481 482 func CiliumExternalWorkloads(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2.CiliumExternalWorkload], error) { 483 if !params.ClientSet.IsEnabled() { 484 return nil, nil 485 } 486 lw := utils.ListerWatcherWithModifiers( 487 utils.ListerWatcherFromTyped[*cilium_api_v2.CiliumExternalWorkloadList](params.ClientSet.CiliumV2().CiliumExternalWorkloads()), 488 opts..., 489 ) 490 return resource.New[*cilium_api_v2.CiliumExternalWorkload](params.Lifecycle, lw, resource.WithMetric("CiliumExternalWorkloads"), resource.WithCRDSync(params.CRDSyncPromise)), nil 491 } 492 493 func CiliumEnvoyConfigResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2.CiliumEnvoyConfig], error) { 494 if !params.ClientSet.IsEnabled() { 495 return nil, nil 496 } 497 lw := utils.ListerWatcherWithModifiers( 498 utils.ListerWatcherFromTyped[*cilium_api_v2.CiliumEnvoyConfigList](params.ClientSet.CiliumV2().CiliumEnvoyConfigs("")), 499 opts..., 500 ) 501 return resource.New[*cilium_api_v2.CiliumEnvoyConfig](params.Lifecycle, lw, resource.WithMetric("CiliumEnvoyConfig"), resource.WithCRDSync(params.CRDSyncPromise)), nil 502 } 503 504 func CiliumClusterwideEnvoyConfigResource(params CiliumResourceParams, opts ...func(*metav1.ListOptions)) (resource.Resource[*cilium_api_v2.CiliumClusterwideEnvoyConfig], error) { 505 if !params.ClientSet.IsEnabled() { 506 return nil, nil 507 } 508 lw := utils.ListerWatcherWithModifiers( 509 utils.ListerWatcherFromTyped[*cilium_api_v2.CiliumClusterwideEnvoyConfigList](params.ClientSet.CiliumV2().CiliumClusterwideEnvoyConfigs()), 510 opts..., 511 ) 512 return resource.New[*cilium_api_v2.CiliumClusterwideEnvoyConfig](params.Lifecycle, lw, resource.WithMetric("CiliumClusterwideEnvoyConfig"), resource.WithCRDSync(params.CRDSyncPromise)), nil 513 }