diff --git a/cmd/glbc/main.go b/cmd/glbc/main.go index 9e9a3f889a..6664a418a0 100644 --- a/cmd/glbc/main.go +++ b/cmd/glbc/main.go @@ -20,11 +20,12 @@ import ( "context" "encoding/json" "fmt" - networkclient "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned" "math/rand" "os" "time" + networkclient "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned" + flag "github.com/spf13/pflag" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/ingress-gce/pkg/frontendconfig" @@ -349,6 +350,8 @@ func runControllers(ctx *ingctx.ControllerContext) { ctx.NodeInformer, ctx.EndpointSliceInformer, ctx.SvcNegInformer, + ctx.NetworkInformer, + ctx.GKENetworkParamsInformer, ctx.HasSynced, ctx.ControllerMetrics, ctx.L4Namer, diff --git a/pkg/multinetwork/multinetwork.go b/pkg/multinetwork/multinetwork.go new file mode 100644 index 0000000000..d5195d1943 --- /dev/null +++ b/pkg/multinetwork/multinetwork.go @@ -0,0 +1,127 @@ +package multinetwork + +import ( + "fmt" + "strings" + + "github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud" + "github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta" + apiv1 "k8s.io/api/core/v1" + "k8s.io/client-go/tools/cache" + networkv1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1" + gkenetworkparamsetv1alpha1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1" +) + +const ( + networkingGKEGroup = "networking.gke.io" + gkeNetworkParamSetKind = "gkenetworkparamset" + networkSelector = "networking.gke.io/network" +) + +func ServiceNetwork(service *apiv1.Service, networkLister, gkeNetworkParamSetLister cache.Indexer, cloudProvider cloudNetworkProvider) (*NetworkInfo, error) { + if networkLister == nil || gkeNetworkParamSetLister == nil { + return nil, nil + } + networkName, ok := service.Spec.Selector[networkSelector] + if !ok || networkName == "" { + return nil, nil + } + obj, exists, err := networkLister.GetByKey(networkName) + if err != nil { + return nil, err + } + if !exists { + return nil, fmt.Errorf("network %s does not exist, networks available [%s]", networkName, strings.Join(networkLister.ListKeys(), ", ")) + } + network := obj.(*networkv1.Network) + if network == nil { + return nil, fmt.Errorf("cannot convert to Network (%T)", obj) + } + + parametersRef := network.Spec.ParametersRef + if !refersGKENetworkParamSet(parametersRef) { + return nil, fmt.Errorf("network.Spec.ParametersRef does not refer a GKENetworkParamSet resource") + } + if parametersRef.Namespace != nil { + return nil, fmt.Errorf("network.Spec.ParametersRef.namespace must not be set for GKENetworkParamSet reference as it is a cluster scope resource") + } + gkeParamsObj, exists, err := gkeNetworkParamSetLister.GetByKey(parametersRef.Name) + if err != nil { + return nil, err + } + if !exists { + return nil, fmt.Errorf("GKENetworkParamSet %s was not found", parametersRef.Name) + } + gkeNetworkParamSet := gkeParamsObj.(*gkenetworkparamsetv1alpha1.GKENetworkParamSet) + if network == nil { + return nil, fmt.Errorf("cannot convert to GKENetworkParamSet (%T)", gkeParamsObj) + } + return &NetworkInfo{ + K8sNetwork: networkName, + VPC: gkeNetworkParamSet.Spec.VPC, + Subnetwork: gkeNetworkParamSet.Spec.VPCSubnet, + NetworkURL: networkURL(cloudProvider, gkeNetworkParamSet.Spec.VPC), + SubnetworkURL: subnetworkURL(cloudProvider, gkeNetworkParamSet.Spec.VPCSubnet), + }, nil +} + +func refersGKENetworkParamSet(parametersRef *networkv1.NetworkParametersReference) bool { + return parametersRef != nil && + parametersRef.Group == networkingGKEGroup && + strings.ToLower(parametersRef.Kind) == gkeNetworkParamSetKind && + parametersRef.Name != "" +} + +type NetworkInfo struct { + IsDefault bool + // VPC is the VPC as specified in GKENetworkParamSet resource. + VPC string + // VPC is the VPCSubnet as specified in GKENetworkParamSet resource. + Subnetwork string + // K8sNetwork is the network name of the Network resource in the cluster. + K8sNetwork string + // NetworkURL is the GCE VPC URL (to be used in GCE LB resources). + NetworkURL string + // SubnetworkURL is the GCE subnetwork URL (to be used in GCE LB resources). + SubnetworkURL string +} + +func networkURL(cloudProvider cloudNetworkProvider, vpc string) string { + key := meta.GlobalKey(vpc) + return cloud.SelfLink(meta.VersionGA, cloudProvider.NetworkProjectID(), "networks", key) +} + +func subnetworkURL(cloudProvider cloudNetworkProvider, subnetwork string) string { + key := meta.RegionalKey(subnetwork, cloudProvider.Region()) + return cloud.SelfLink(meta.VersionGA, cloudProvider.NetworkProjectID(), "subnetworks", key) +} + +// IsConnectedToNetwork checks if the node is connected to the given network. +// It's based on the data from the 'networking.gke.io/north-interfaces' annotation. +func IsConnectedToNetwork(node *apiv1.Node, network string) bool { + return NodeIPForNetwork(node, network) != "" +} + +// NodeIPForNetwork retrieves the IP of the interface of the node connected to the network. +// The addresses come from the 'networking.gke.io/north-interfaces' annotation. +func NodeIPForNetwork(node *apiv1.Node, network string) string { + northInterfacesAnnotation, ok := node.Annotations[networkv1.NorthInterfacesAnnotationKey] + if !ok || northInterfacesAnnotation == "" { + return "" + } + northInterfaces, err := networkv1.ParseNorthInterfacesAnnotation(northInterfacesAnnotation) + if err != nil { + return "" + } + for _, northInterface := range northInterfaces { + if northInterface.Network == network { + return northInterface.IpAddress + } + } + return "" +} + +type cloudNetworkProvider interface { + NetworkProjectID() string + Region() string +} diff --git a/pkg/multinetwork/multinetwork_test.go b/pkg/multinetwork/multinetwork_test.go new file mode 100644 index 0000000000..8008f3d062 --- /dev/null +++ b/pkg/multinetwork/multinetwork_test.go @@ -0,0 +1,418 @@ +package multinetwork + +import ( + "strings" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + + apiv1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + networkv1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1" + gkenetworkparamsetv1alpha1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1" + netfake "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake" + informernetwork "k8s.io/cloud-provider-gcp/crd/client/network/informers/externalversions/network/v1" + informergkenetworkparamset "k8s.io/cloud-provider-gcp/crd/client/network/informers/externalversions/network/v1alpha1" + "k8s.io/ingress-gce/pkg/utils" +) + +func TestServiceNetwork(t *testing.T) { + + namespace := "test" + + testService := &apiv1.Service{ + ObjectMeta: metav1.ObjectMeta{Name: "testService"}, + Spec: apiv1.ServiceSpec{ + Selector: map[string]string{ + networkSelector: "secondary-network", + }, + }, + } + cases := []struct { + desc string + network *networkv1.Network + gkeNetworkParamSet *gkenetworkparamsetv1alpha1.GKENetworkParamSet + service *apiv1.Service + want *NetworkInfo + wantErr string + }{ + { + desc: "valid setup", + network: testNetwork("secondary-network", "secondary-network-params"), + gkeNetworkParamSet: testGKENetworkParamSet("secondary-network-params", "secondary-vpc", "secondary-subnet"), + service: testService, + want: &NetworkInfo{ + K8sNetwork: "secondary-network", + VPC: "secondary-vpc", + Subnetwork: "secondary-subnet", + NetworkURL: "https://www.googleapis.com/compute/v1/projects/test-project/global/networks/secondary-vpc", + SubnetworkURL: "https://www.googleapis.com/compute/v1/projects/test-project/regions/test-region/subnetworks/secondary-subnet", + }, + }, + { + desc: "service without network selector", + service: &apiv1.Service{ + ObjectMeta: metav1.ObjectMeta{Name: "testService"}, + Spec: apiv1.ServiceSpec{ + Selector: map[string]string{ + "app": "someapp", + }, + }, + }, + want: nil, + }, + { + desc: "service with empty network selector", + service: &apiv1.Service{ + ObjectMeta: metav1.ObjectMeta{Name: "testService"}, + Spec: apiv1.ServiceSpec{ + Selector: map[string]string{ + networkSelector: "", + }, + }, + }, + want: nil, + }, + { + desc: "network not defined", + service: testService, + wantErr: "network secondary-network does not exist", + }, + { + desc: "network paramsRef for non GKENetworkParamSet", + network: &networkv1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Name: "secondary-network", + }, + Spec: networkv1.NetworkSpec{ + Type: "L3", + ParametersRef: &networkv1.NetworkParametersReference{ + Group: networkingGKEGroup, + Kind: "UnsupportedNetworkParams", + Name: "secondary-network-params", + }, + }, + }, + gkeNetworkParamSet: testGKENetworkParamSet("secondary-network-params", "secondary-vpc", "secondary-subnet"), + service: testService, + wantErr: "network.Spec.ParametersRef does not refer a GKENetworkParamSet resource", + }, + { + desc: "network paramsRef for GKENetworkParamSet with namespace", + network: &networkv1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Name: "secondary-network", + }, + Spec: networkv1.NetworkSpec{ + Type: "L3", + ParametersRef: &networkv1.NetworkParametersReference{ + Group: networkingGKEGroup, + Kind: "GKENetworkParamSet", + Name: "secondary-network-params", + Namespace: &namespace, + }, + }, + }, + gkeNetworkParamSet: testGKENetworkParamSet("secondary-network-params", "secondary-vpc", "secondary-subnet"), + service: testService, + wantErr: "network.Spec.ParametersRef.namespace must not be set for GKENetworkParamSet reference as it is a cluster scope resource", + }, + { + desc: "missing GKENetworkParamSet", + network: testNetwork("secondary-network", "secondary-network-params"), + gkeNetworkParamSet: nil, + service: testService, + wantErr: "GKENetworkParamSet secondary-network-params was not found", + }, + } + + for _, tc := range cases { + + t.Run(tc.desc, func(t *testing.T) { + networkClient := netfake.NewSimpleClientset() + + networkInformer := informernetwork.NewNetworkInformer(networkClient, time.Minute*10, utils.NewNamespaceIndexer()) + gkeNetworkParamSetInformer := informergkenetworkparamset.NewGKENetworkParamSetInformer(networkClient, time.Minute*10, utils.NewNamespaceIndexer()) + + networkIndexer := networkInformer.GetIndexer() + gkeNetworkParamSetIndexer := gkeNetworkParamSetInformer.GetIndexer() + + if tc.network != nil { + networkIndexer.Add(tc.network) + } + if tc.gkeNetworkParamSet != nil { + gkeNetworkParamSetIndexer.Add(tc.gkeNetworkParamSet) + } + + network, err := ServiceNetwork(tc.service, networkIndexer, gkeNetworkParamSetIndexer, fakeCloud{}) + if err != nil { + if tc.wantErr == "" { + t.Fatalf("determining network info returned an error, err=%v", err) + } + if !strings.Contains(err.Error(), tc.wantErr) { + t.Fatalf("expected error containing message %q but got error %v", tc.wantErr, err) + } + } + if err == nil && tc.wantErr != "" { + t.Fatalf("expected error containing message %q but got no error", tc.wantErr) + } + diff := cmp.Diff(tc.want, network) + if diff != "" { + t.Errorf("Expected NetworkInfo ranges: %v, got ranges %v, diff: %s", tc.want, network, diff) + } + }) + } +} + +type fakeCloud struct { +} + +func (f fakeCloud) NetworkProjectID() string { + return "test-project" +} + +func (f fakeCloud) Region() string { + return "test-region" +} + +func (f fakeCloud) NetworkURL() string { + return "https://www.googleapis.com/compute/v1/projects/test-project/global/networks/default" +} + +func (f fakeCloud) SubnetworkURL() string { + return "https://www.googleapis.com/compute/v1/projects/test-region/regions/test-region/subnetworks/secondary-subnet" +} +func testNetwork(name, gkeNetworkParamSetName string) *networkv1.Network { + return &networkv1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: networkv1.NetworkSpec{ + Type: "L3", + ParametersRef: &networkv1.NetworkParametersReference{ + Group: networkingGKEGroup, + Kind: "GKENetworkParamSet", + Name: gkeNetworkParamSetName, + }, + }, + } +} + +func testGKENetworkParamSet(name, vpc, subnet string) *gkenetworkparamsetv1alpha1.GKENetworkParamSet { + return &gkenetworkparamsetv1alpha1.GKENetworkParamSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: gkenetworkparamsetv1alpha1.GKENetworkParamSetSpec{ + VPC: vpc, + VPCSubnet: subnet, + }, + } +} + +func TestRefersGKENetworkParamSet(t *testing.T) { + cases := []struct { + desc string + ref *networkv1.NetworkParametersReference + want bool + }{ + { + desc: "valid", + ref: &networkv1.NetworkParametersReference{ + Group: networkingGKEGroup, + Kind: "GKENetworkParamSet", + Name: "test-params", + }, + want: true, + }, + { + desc: "valid case insensitive kind", + ref: &networkv1.NetworkParametersReference{ + Group: networkingGKEGroup, + Kind: "gKeNeTwOrkParamSet", + Name: "test-params", + }, + want: true, + }, + { + desc: "nil ref", + ref: nil, + want: false, + }, + { + desc: "invalid group", + ref: &networkv1.NetworkParametersReference{ + Group: "somethingelse.k8s.io", + Kind: "GKENetworkParamSet", + Name: "test-params", + }, + want: false, + }, + { + desc: "invalid kind", + ref: &networkv1.NetworkParametersReference{ + Group: networkingGKEGroup, + Kind: "OtherParamSet", + Name: "test-params", + }, + want: false, + }, + { + desc: "empty name", + ref: &networkv1.NetworkParametersReference{ + Group: networkingGKEGroup, + Kind: "GKENetworkParamSet", + Name: "", + }, + want: false, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + got := refersGKENetworkParamSet(tc.ref) + if tc.want != got { + t.Errorf("refersGKENetworkParamSet(%+v) wanted %v but got %v", tc.ref, tc.want, got) + } + }) + } +} + +func TestNodeIPForNetwork(t *testing.T) { + cases := []struct { + desc string + node *apiv1.Node + network string + want string + }{ + { + desc: "no annotation", + network: "test-network", + node: &apiv1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "test-node", Annotations: map[string]string{}}, + }, + want: "", + }, + { + desc: "annotation that has the network", + network: "test-network", + node: &apiv1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "test-node", Annotations: map[string]string{ + networkv1.NorthInterfacesAnnotationKey: northInterfacesAnnotation(t, networkv1.NorthInterfacesAnnotation{ + { + Network: "default", + IpAddress: "10.0.0.1", + }, + { + Network: "test-network", + IpAddress: "192.168.0.1", + }, + }), + }}, + }, + want: "192.168.0.1", + }, + { + desc: "annotation that does not have the network", + network: "test-network", + node: &apiv1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "test-node", Annotations: map[string]string{ + networkv1.NorthInterfacesAnnotationKey: northInterfacesAnnotation(t, networkv1.NorthInterfacesAnnotation{ + { + Network: "default", + IpAddress: "10.0.0.1", + }, + { + Network: "other-network", + IpAddress: "192.168.0.1", + }, + }), + }}, + }, + want: "", + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + got := NodeIPForNetwork(tc.node, tc.network) + if tc.want != got { + t.Errorf("NodeIPForNetwork(%+v, %q) wanted %v but got %v", tc.node, tc.network, tc.want, got) + } + }) + } +} + +func TestIsConnectedToNetwork(t *testing.T) { + cases := []struct { + desc string + node *apiv1.Node + network string + want bool + }{ + { + desc: "no annotation", + network: "test-network", + node: &apiv1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "test-node", Annotations: map[string]string{}}, + }, + want: false, + }, + { + desc: "annotation that has the network", + network: "test-network", + node: &apiv1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "test-node", Annotations: map[string]string{ + networkv1.NorthInterfacesAnnotationKey: northInterfacesAnnotation(t, networkv1.NorthInterfacesAnnotation{ + { + Network: "default", + IpAddress: "10.0.0.1", + }, + { + Network: "test-network", + IpAddress: "192.168.0.1", + }, + }), + }}, + }, + want: true, + }, + { + desc: "annotation that does not have the network", + network: "test-network", + node: &apiv1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "test-node", Annotations: map[string]string{ + networkv1.NorthInterfacesAnnotationKey: northInterfacesAnnotation(t, networkv1.NorthInterfacesAnnotation{ + { + Network: "default", + IpAddress: "10.0.0.1", + }, + { + Network: "other-network", + IpAddress: "192.168.0.1", + }, + }), + }}, + }, + want: false, + }, + } + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + got := IsConnectedToNetwork(tc.node, tc.network) + if tc.want != got { + t.Errorf("IsConnectedToNetwork(%+v, %q) wanted %v but got %v", tc.node, tc.network, tc.want, got) + } + }) + } +} + +func northInterfacesAnnotation(t *testing.T, annotation networkv1.NorthInterfacesAnnotation) string { + annotationString, err := networkv1.MarshalNorthInterfacesAnnotation(annotation) + if err != nil { + t.Errorf("failed to marshal north interfaces annotation") + } + return annotationString +} diff --git a/pkg/neg/controller.go b/pkg/neg/controller.go index f06183b6ad..ff6e8c957a 100644 --- a/pkg/neg/controller.go +++ b/pkg/neg/controller.go @@ -39,6 +39,7 @@ import ( "k8s.io/ingress-gce/pkg/controller/translator" "k8s.io/ingress-gce/pkg/flags" usageMetrics "k8s.io/ingress-gce/pkg/metrics" + "k8s.io/ingress-gce/pkg/multinetwork" "k8s.io/ingress-gce/pkg/neg/metrics" syncMetrics "k8s.io/ingress-gce/pkg/neg/metrics" "k8s.io/ingress-gce/pkg/neg/readiness" @@ -66,10 +67,13 @@ type Controller struct { namer negtypes.NetworkEndpointGroupNamer l4Namer namer2.L4ResourcesNamer zoneGetter negtypes.ZoneGetter + cloud negtypes.NetworkEndpointGroupCloud hasSynced func() bool ingressLister cache.Indexer serviceLister cache.Indexer + networkLister cache.Indexer + gkeNetworkParamSetLister cache.Indexer client kubernetes.Interface defaultBackendService utils.ServicePort enableASM bool @@ -113,6 +117,8 @@ func NewController( nodeInformer cache.SharedIndexInformer, endpointSliceInformer cache.SharedIndexInformer, svcNegInformer cache.SharedIndexInformer, + networkInformer cache.SharedIndexInformer, + gkeNetworkParamSetInformer cache.SharedIndexInformer, hasSynced func() bool, controllerMetrics *usageMetrics.ControllerMetrics, l4Namer namer2.L4ResourcesNamer, @@ -186,28 +192,39 @@ func NewController( } manager.reflector = reflector + var networkIndexer cache.Indexer + if networkInformer != nil { + networkIndexer = networkInformer.GetIndexer() + } + var gkeNetworkParamSetIndexer cache.Indexer + if gkeNetworkParamSetInformer != nil { + gkeNetworkParamSetIndexer = gkeNetworkParamSetInformer.GetIndexer() + } negController := &Controller{ - client: kubeClient, - manager: manager, - resyncPeriod: resyncPeriod, - gcPeriod: gcPeriod, - recorder: recorder, - zoneGetter: zoneGetter, - namer: namer, - l4Namer: l4Namer, - defaultBackendService: defaultBackendService, - hasSynced: hasSynced, - ingressLister: ingressInformer.GetIndexer(), - serviceLister: serviceInformer.GetIndexer(), - serviceQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "neg_service_queue"), - endpointQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "neg_endpoint_queue"), - nodeQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "neg_node_queue"), - syncTracker: utils.NewTimeTracker(), - reflector: reflector, - usageCollector: controllerMetrics, - syncerMetrics: syncerMetrics, - runL4: runL4Controller, - logger: logger, + client: kubeClient, + manager: manager, + resyncPeriod: resyncPeriod, + gcPeriod: gcPeriod, + recorder: recorder, + zoneGetter: zoneGetter, + cloud: cloud, + namer: namer, + l4Namer: l4Namer, + defaultBackendService: defaultBackendService, + hasSynced: hasSynced, + ingressLister: ingressInformer.GetIndexer(), + serviceLister: serviceInformer.GetIndexer(), + networkLister: networkIndexer, + gkeNetworkParamSetLister: gkeNetworkParamSetIndexer, + serviceQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "neg_service_queue"), + endpointQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "neg_endpoint_queue"), + nodeQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "neg_node_queue"), + syncTracker: utils.NewTimeTracker(), + reflector: reflector, + usageCollector: controllerMetrics, + syncerMetrics: syncerMetrics, + runL4: runL4Controller, + logger: logger, } if runIngress { ingressInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ @@ -569,8 +586,12 @@ func (c *Controller) mergeVmIpNEGsPortInfo(service *apiv1.Service, name types.Na onlyLocal := helpers.RequestsOnlyLocalTraffic(service) // Update usage metrics. negUsage.VmIpNeg = usageMetrics.NewVmIpNegType(onlyLocal) + networkInfo, err := multinetwork.ServiceNetwork(service, c.networkLister, c.gkeNetworkParamSetLister, c.cloud) + if err != nil { + return err + } - return portInfoMap.Merge(negtypes.NewPortInfoMapForVMIPNEG(name.Namespace, name.Name, c.l4Namer, onlyLocal)) + return portInfoMap.Merge(negtypes.NewPortInfoMapForVMIPNEG(name.Namespace, name.Name, c.l4Namer, onlyLocal, networkInfo)) } // mergeDefaultBackendServicePortInfoMap merge the PortInfoMap for the default backend service into portInfoMap diff --git a/pkg/neg/controller_test.go b/pkg/neg/controller_test.go index f42d2182cb..43932ded0a 100644 --- a/pkg/neg/controller_test.go +++ b/pkg/neg/controller_test.go @@ -123,6 +123,8 @@ func newTestControllerWithParamsAndContext(kubeClient kubernetes.Interface, test testContext.NodeInformer, testContext.EndpointSliceInformer, testContext.SvcNegInformer, + testContext.NetworkInformer, + testContext.GKENetworkParamSetInformer, func() bool { return true }, metrics.FakeControllerMetrics(), testContext.L4Namer, @@ -371,7 +373,7 @@ func TestEnableNEGServiceWithL4ILB(t *testing.T) { t.Fatalf("Service was not created.(*apiv1.Service) successfully, err: %v", err) } expectedPortInfoMap := negtypes.NewPortInfoMapForVMIPNEG(testServiceNamespace, testServiceName, - controller.l4Namer, false) + controller.l4Namer, false, nil) // There will be only one entry in the map for key, val := range expectedPortInfoMap { prevSyncerKey = manager.getSyncerKey(testServiceNamespace, testServiceName, key, val) @@ -393,7 +395,7 @@ func TestEnableNEGServiceWithL4ILB(t *testing.T) { t.Fatalf("Failed to process updated L4 ILB service: %v", err) } expectedPortInfoMap = negtypes.NewPortInfoMapForVMIPNEG(testServiceNamespace, testServiceName, - controller.l4Namer, true) + controller.l4Namer, true, nil) // There will be only one entry in the map for key, val := range expectedPortInfoMap { updatedSyncerKey = manager.getSyncerKey(testServiceNamespace, testServiceName, key, val) diff --git a/pkg/neg/manager.go b/pkg/neg/manager.go index 1b71b4c8b3..16aec48baa 100644 --- a/pkg/neg/manager.go +++ b/pkg/neg/manager.go @@ -219,9 +219,14 @@ func (manager *syncerManager) EnsureSyncers(namespace, name string, newPorts neg continue } + var k8sNetwork string + if portInfo.NetworkInfo != nil { + k8sNetwork = portInfo.NetworkInfo.K8sNetwork + } + // determine the implementation that calculates NEG endpoints on each sync. epc := negsyncer.GetEndpointsCalculator(manager.nodeLister, manager.podLister, manager.zoneGetter, - syncerKey, portInfo.EpCalculatorMode, manager.logger.WithValues("service", klog.KRef(syncerKey.Namespace, syncerKey.Name), "negName", syncerKey.NegName), manager.lpConfig) + syncerKey, portInfo.EpCalculatorMode, manager.logger.WithValues("service", klog.KRef(syncerKey.Namespace, syncerKey.Name), "negName", syncerKey.NegName), manager.lpConfig, k8sNetwork) syncer = negsyncer.NewTransactionSyncer( syncerKey, manager.recorder, @@ -238,6 +243,7 @@ func (manager *syncerManager) EnsureSyncers(namespace, name string, newPorts neg manager.svcNegClient, manager.syncerMetrics, !manager.namer.IsNEG(portInfo.NegName), + portInfo.NetworkInfo, manager.logger, ) manager.syncerMap[syncerKey] = syncer diff --git a/pkg/neg/syncers/endpoints_calculator.go b/pkg/neg/syncers/endpoints_calculator.go index 10dc4564a2..4a8a257568 100644 --- a/pkg/neg/syncers/endpoints_calculator.go +++ b/pkg/neg/syncers/endpoints_calculator.go @@ -24,6 +24,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" listers "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" + "k8s.io/ingress-gce/pkg/multinetwork" "k8s.io/ingress-gce/pkg/neg/types" "k8s.io/ingress-gce/pkg/utils" "k8s.io/klog/v2" @@ -43,15 +44,17 @@ type LocalL4ILBEndpointsCalculator struct { subsetSizeLimit int svcId string logger klog.Logger + network string } -func NewLocalL4ILBEndpointsCalculator(nodeLister listers.NodeLister, zoneGetter types.ZoneGetter, svcId string, logger klog.Logger) *LocalL4ILBEndpointsCalculator { +func NewLocalL4ILBEndpointsCalculator(nodeLister listers.NodeLister, zoneGetter types.ZoneGetter, svcId string, logger klog.Logger, network string) *LocalL4ILBEndpointsCalculator { return &LocalL4ILBEndpointsCalculator{ nodeLister: nodeLister, zoneGetter: zoneGetter, subsetSizeLimit: maxSubsetSizeLocal, svcId: svcId, logger: logger.WithName("LocalL4ILBEndpointsCalculator"), + network: network, } } @@ -91,6 +94,10 @@ func (l *LocalL4ILBEndpointsCalculator) CalculateEndpoints(eds []types.Endpoints l.logger.Info("Dropping Node from subset since it is not a valid LB candidate", "nodeName", node.Name) continue } + if l.network != "" && !multinetwork.IsConnectedToNetwork(node, l.network) { + l.logger.Info("Node not connected to service network", "nodeName", node.Name, "network", l.network) + continue + } zone, err := l.zoneGetter.GetZoneForNode(node.Name) if err != nil { l.logger.Error(err, "Unable to find zone for node, skipping", "nodeName", node.Name) @@ -105,7 +112,7 @@ func (l *LocalL4ILBEndpointsCalculator) CalculateEndpoints(eds []types.Endpoints } // Compute the networkEndpoints, with total endpoints count <= l.subsetSizeLimit klog.V(2).Infof("Got zoneNodeMap as input for service", "zoneNodeMap", nodeMapToString(zoneNodeMap), "serviceID", l.svcId) - subsetMap, err := getSubsetPerZone(zoneNodeMap, l.subsetSizeLimit, l.svcId, currentMap, l.logger) + subsetMap, err := getSubsetPerZone(zoneNodeMap, l.subsetSizeLimit, l.svcId, currentMap, l.logger, l.network) return subsetMap, nil, 0, err } @@ -127,18 +134,21 @@ type ClusterL4ILBEndpointsCalculator struct { // subsetSizeLimit is the max value of the subset size in this mode. subsetSizeLimit int // svcId is the unique identifier for the service, that is used as a salt when hashing nodenames. - svcId string + svcId string + network string logger klog.Logger } -func NewClusterL4ILBEndpointsCalculator(nodeLister listers.NodeLister, zoneGetter types.ZoneGetter, svcId string, logger klog.Logger) *ClusterL4ILBEndpointsCalculator { +func NewClusterL4ILBEndpointsCalculator(nodeLister listers.NodeLister, zoneGetter types.ZoneGetter, svcId string, logger klog.Logger, network string) *ClusterL4ILBEndpointsCalculator { return &ClusterL4ILBEndpointsCalculator{ nodeLister: nodeLister, zoneGetter: zoneGetter, subsetSizeLimit: maxSubsetSizeDefault, svcId: svcId, - logger: logger.WithName("ClusterL4ILBEndpointsCalculator")} + logger: logger.WithName("ClusterL4ILBEndpointsCalculator"), + network: network, + } } // Mode indicates the mode that the EndpointsCalculator is operating in. @@ -153,6 +163,10 @@ func (l *ClusterL4ILBEndpointsCalculator) CalculateEndpoints(_ []types.Endpoints zoneNodeMap := make(map[string][]*v1.Node) for _, node := range nodes { + if l.network != "" && !multinetwork.IsConnectedToNetwork(node, l.network) { + l.logger.Info("Node not connected to service network", "nodeName", node.Name, "network", l.network) + continue + } zone, err := l.zoneGetter.GetZoneForNode(node.Name) if err != nil { l.logger.Error(err, "Unable to find zone for node skipping", "nodeName", node.Name) @@ -162,7 +176,7 @@ func (l *ClusterL4ILBEndpointsCalculator) CalculateEndpoints(_ []types.Endpoints } klog.V(2).Infof("Got zoneNodeMap as input for service", "zoneNodeMap", nodeMapToString(zoneNodeMap), "serviceID", l.svcId) // Compute the networkEndpoints, with total endpoints <= l.subsetSizeLimit. - subsetMap, err := getSubsetPerZone(zoneNodeMap, l.subsetSizeLimit, l.svcId, currentMap, l.logger) + subsetMap, err := getSubsetPerZone(zoneNodeMap, l.subsetSizeLimit, l.svcId, currentMap, l.logger, l.network) return subsetMap, nil, 0, err } diff --git a/pkg/neg/syncers/endpoints_calculator_test.go b/pkg/neg/syncers/endpoints_calculator_test.go index a479495d0c..e5cbb33988 100644 --- a/pkg/neg/syncers/endpoints_calculator_test.go +++ b/pkg/neg/syncers/endpoints_calculator_test.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/types" listers "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" + networkv1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1" negtypes "k8s.io/ingress-gce/pkg/neg/types" "k8s.io/ingress-gce/pkg/utils" "k8s.io/klog/v2" @@ -48,8 +49,10 @@ func TestLocalGetEndpointSet(t *testing.T) { endpointSets map[string]negtypes.NetworkEndpointSet networkEndpointType negtypes.NetworkEndpointType nodeLabelsMap map[string]map[string]string + nodeAnnotationsMap map[string]map[string]string nodeReadyStatusMap map[string]v1.ConditionStatus nodeNames []string + network string }{ { desc: "default endpoints", @@ -101,11 +104,28 @@ func TestLocalGetEndpointSet(t *testing.T) { networkEndpointType: negtypes.VmIpEndpointType, nodeNames: []string{testInstance1, testInstance2, testInstance3, testInstance4, testInstance5, testInstance6}, }, + { + desc: "multinetwork endpoints", + endpointsData: negtypes.EndpointsDataFromEndpointSlices(getDefaultEndpointSlices()), + // only 4 out of 6 nodes are picked since there are > 4 endpoints, but they are found only on 4 nodes. + endpointSets: map[string]negtypes.NetworkEndpointSet{ + negtypes.TestZone1: negtypes.NewNetworkEndpointSet(negtypes.NetworkEndpoint{IP: "20.2.3.1", Node: testInstance1}, negtypes.NetworkEndpoint{IP: "20.2.3.2", Node: testInstance2}), + negtypes.TestZone2: negtypes.NewNetworkEndpointSet(negtypes.NetworkEndpoint{IP: "20.2.3.3", Node: testInstance3}), + }, + network: "other", + nodeAnnotationsMap: map[string]map[string]string{ + testInstance1: {networkv1.NorthInterfacesAnnotationKey: nodeInterfacesAnnotation(t, "other", "20.2.3.1")}, + testInstance2: {networkv1.NorthInterfacesAnnotationKey: nodeInterfacesAnnotation(t, "other", "20.2.3.2")}, + testInstance3: {networkv1.NorthInterfacesAnnotationKey: nodeInterfacesAnnotation(t, "other", "20.2.3.3")}, + }, + //networkEndpointType: negtypes.VmIpEndpointType, + nodeNames: []string{testInstance1, testInstance2, testInstance3, testInstance4, testInstance5, testInstance6}, + }, } svcKey := fmt.Sprintf("%s/%s", testServiceName, testServiceNamespace) - ec := NewLocalL4ILBEndpointsCalculator(nodeLister, zoneGetter, svcKey, klog.TODO()) for _, tc := range testCases { - createNodes(t, tc.nodeNames, tc.nodeLabelsMap, tc.nodeReadyStatusMap, transactionSyncer.nodeLister) + ec := NewLocalL4ILBEndpointsCalculator(nodeLister, zoneGetter, svcKey, klog.TODO(), tc.network) + createNodes(t, tc.nodeNames, tc.nodeLabelsMap, tc.nodeAnnotationsMap, tc.nodeReadyStatusMap, transactionSyncer.nodeLister) retSet, _, _, err := ec.CalculateEndpoints(tc.endpointsData, nil) if err != nil { t.Errorf("For case %q, expect nil error, but got %v.", tc.desc, err) @@ -117,6 +137,20 @@ func TestLocalGetEndpointSet(t *testing.T) { } } +func nodeInterfacesAnnotation(t *testing.T, network, ip string) string { + annotation, err := networkv1.MarshalNorthInterfacesAnnotation(networkv1.NorthInterfacesAnnotation{ + { + Network: network, + IpAddress: ip, + }, + }) + if err != nil { + t.Errorf("could not create node annotations") + return "" + } + return annotation +} + // TestClusterGetEndpointSet verifies the GetEndpointSet method implemented by the ClusterL4ILBEndpointsCalculator. func TestClusterGetEndpointSet(t *testing.T) { t.Parallel() @@ -134,6 +168,7 @@ func TestClusterGetEndpointSet(t *testing.T) { nodeAnnotationsMap map[string]map[string]string nodeReadyStatusMap map[string]v1.ConditionStatus nodeNames []string + network string }{ { desc: "default endpoints", @@ -193,11 +228,29 @@ func TestClusterGetEndpointSet(t *testing.T) { networkEndpointType: negtypes.VmIpEndpointType, nodeNames: []string{testInstance1, testInstance2, testInstance3, testInstance4, testInstance5, testInstance6}, }, + { + desc: "multinetwork endpoints", + endpointsData: negtypes.EndpointsDataFromEndpointSlices(getDefaultEndpointSlices()), + // all nodes are picked since, in this mode, endpoints running do not need to run on the selected node. + endpointSets: map[string]negtypes.NetworkEndpointSet{ + negtypes.TestZone1: negtypes.NewNetworkEndpointSet(negtypes.NetworkEndpoint{IP: "20.2.3.1", Node: testInstance1}, negtypes.NetworkEndpoint{IP: "20.2.3.2", Node: testInstance2}), + negtypes.TestZone2: negtypes.NewNetworkEndpointSet(negtypes.NetworkEndpoint{IP: "20.2.3.3", Node: testInstance3}, negtypes.NetworkEndpoint{IP: "20.2.3.6", Node: testInstance6}), + }, + network: "other", + nodeAnnotationsMap: map[string]map[string]string{ + testInstance1: {networkv1.NorthInterfacesAnnotationKey: nodeInterfacesAnnotation(t, "other", "20.2.3.1")}, + testInstance2: {networkv1.NorthInterfacesAnnotationKey: nodeInterfacesAnnotation(t, "other", "20.2.3.2")}, + testInstance3: {networkv1.NorthInterfacesAnnotationKey: nodeInterfacesAnnotation(t, "other", "20.2.3.3")}, + testInstance6: {networkv1.NorthInterfacesAnnotationKey: nodeInterfacesAnnotation(t, "other", "20.2.3.6")}, + }, + networkEndpointType: negtypes.VmIpEndpointType, + nodeNames: []string{testInstance1, testInstance2, testInstance3, testInstance4, testInstance5, testInstance6}, + }, } svcKey := fmt.Sprintf("%s/%s", testServiceName, testServiceNamespace) - ec := NewClusterL4ILBEndpointsCalculator(nodeLister, zoneGetter, svcKey, klog.TODO()) for _, tc := range testCases { - createNodes(t, tc.nodeNames, tc.nodeLabelsMap, tc.nodeReadyStatusMap, transactionSyncer.nodeLister) + ec := NewClusterL4ILBEndpointsCalculator(nodeLister, zoneGetter, svcKey, klog.TODO(), tc.network) + createNodes(t, tc.nodeNames, tc.nodeLabelsMap, tc.nodeAnnotationsMap, tc.nodeReadyStatusMap, transactionSyncer.nodeLister) retSet, _, _, err := ec.CalculateEndpoints(tc.endpointsData, nil) if err != nil { t.Errorf("For case %q, expect nil error, but got %v.", tc.desc, err) @@ -234,8 +287,8 @@ func TestValidateEndpoints(t *testing.T) { podLister := testContext.PodInformer.GetIndexer() nodeLister := listers.NewNodeLister(testContext.NodeInformer.GetIndexer()) L7EndpointsCalculator := NewL7EndpointsCalculator(zoneGetter, podLister, testPortName, negtypes.VmIpPortEndpointType, klog.TODO(), negtypes.PodLabelPropagationConfig{}) - L4LocalEndpointCalculator := NewLocalL4ILBEndpointsCalculator(nodeLister, zoneGetter, svcKey, klog.TODO()) - L4ClusterEndpointCalculator := NewClusterL4ILBEndpointsCalculator(nodeLister, zoneGetter, svcKey, klog.TODO()) + L4LocalEndpointCalculator := NewLocalL4ILBEndpointsCalculator(nodeLister, zoneGetter, svcKey, klog.TODO(), "") + L4ClusterEndpointCalculator := NewClusterL4ILBEndpointsCalculator(nodeLister, zoneGetter, svcKey, klog.TODO(), "") testEndpointPodMap := map[negtypes.NetworkEndpoint]types.NamespacedName{ { @@ -816,7 +869,7 @@ func TestValidateEndpoints(t *testing.T) { } } -func createNodes(t *testing.T, nodeNames []string, nodeLabels map[string]map[string]string, nodeReadyStatus map[string]v1.ConditionStatus, nodeIndexer cache.Indexer) { +func createNodes(t *testing.T, nodeNames []string, nodeLabels map[string]map[string]string, nodeAnnotations map[string]map[string]string, nodeReadyStatus map[string]v1.ConditionStatus, nodeIndexer cache.Indexer) { t.Helper() for i, nodeName := range nodeNames { var labels, annotations map[string]string @@ -824,6 +877,9 @@ func createNodes(t *testing.T, nodeNames []string, nodeLabels map[string]map[str if nodeLabels != nil { labels = nodeLabels[nodeName] } + if nodeAnnotations != nil { + annotations = nodeAnnotations[nodeName] + } if nodeReadyStatus != nil { status, ok := nodeReadyStatus[nodeName] if ok { diff --git a/pkg/neg/syncers/subsets.go b/pkg/neg/syncers/subsets.go index 7da9dd117c..862c410acf 100644 --- a/pkg/neg/syncers/subsets.go +++ b/pkg/neg/syncers/subsets.go @@ -23,6 +23,7 @@ import ( "sort" v1 "k8s.io/api/core/v1" + "k8s.io/ingress-gce/pkg/multinetwork" negtypes "k8s.io/ingress-gce/pkg/neg/types" "k8s.io/ingress-gce/pkg/utils" "k8s.io/klog/v2" @@ -158,7 +159,7 @@ func sortZones(nodesPerZone map[string][]*v1.Node) []ZoneInfo { // Since the number of nodes will keep increasing in successive zones due to the sorting, even if fewer nodes were // present in some zones, more nodes will be picked from other nodes, taking the total subset size to the given limit // whenever possible. -func getSubsetPerZone(nodesPerZone map[string][]*v1.Node, totalLimit int, svcID string, currentMap map[string]negtypes.NetworkEndpointSet, logger klog.Logger) (map[string]negtypes.NetworkEndpointSet, error) { +func getSubsetPerZone(nodesPerZone map[string][]*v1.Node, totalLimit int, svcID string, currentMap map[string]negtypes.NetworkEndpointSet, logger klog.Logger, network string) (map[string]negtypes.NetworkEndpointSet, error) { result := make(map[string]negtypes.NetworkEndpointSet) var currentList []negtypes.NetworkEndpoint @@ -182,7 +183,13 @@ func getSubsetPerZone(nodesPerZone map[string][]*v1.Node, totalLimit int, svcID } subset := pickSubsetsMinRemovals(nodesPerZone[zone.Name], svcID, subsetSize, currentList) for _, node := range subset { - result[zone.Name].Insert(negtypes.NetworkEndpoint{Node: node.Name, IP: utils.GetNodePrimaryIP(node)}) + var ip string + if network != "" { + ip = multinetwork.NodeIPForNetwork(node, network) + } else { + ip = utils.GetNodePrimaryIP(node) + } + result[zone.Name].Insert(negtypes.NetworkEndpoint{Node: node.Name, IP: ip}) } totalLimit -= len(subset) zonesRemaining-- diff --git a/pkg/neg/syncers/subsets_test.go b/pkg/neg/syncers/subsets_test.go index 466d3cd8b1..3833244119 100644 --- a/pkg/neg/syncers/subsets_test.go +++ b/pkg/neg/syncers/subsets_test.go @@ -189,7 +189,7 @@ func TestUnevenNodesInZones(t *testing.T) { }, } for _, tc := range testCases { - subsetMap, err := getSubsetPerZone(tc.nodesMap, tc.subsetLimit, tc.svcKey, nil, klog.TODO()) + subsetMap, err := getSubsetPerZone(tc.nodesMap, tc.subsetLimit, tc.svcKey, nil, klog.TODO(), "") if err != nil { t.Errorf("Failed to get subset for test '%s', err %v", tc.description, err) } diff --git a/pkg/neg/syncers/transaction.go b/pkg/neg/syncers/transaction.go index a76bd3c282..9ac4eeadaa 100644 --- a/pkg/neg/syncers/transaction.go +++ b/pkg/neg/syncers/transaction.go @@ -31,6 +31,7 @@ import ( corev1 "k8s.io/api/core/v1" discovery "k8s.io/api/discovery/v1" "k8s.io/ingress-gce/pkg/flags" + "k8s.io/ingress-gce/pkg/multinetwork" "k8s.io/ingress-gce/pkg/utils/endpointslices" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -93,6 +94,9 @@ type transactionSyncer struct { // customName indicates whether the NEG name is a generated one or custom one customName bool + // networkInfo contains the information about the network the NEG should be created in + networkInfo *multinetwork.NetworkInfo + logger klog.Logger // errorState indicates if the syncer is in any of 4 error scenarios @@ -126,6 +130,7 @@ func NewTransactionSyncer( svcNegClient svcnegclient.Interface, syncerMetrics *metrics.SyncerMetrics, customName bool, + networkInfo *multinetwork.NetworkInfo, log klog.Logger) negtypes.NegSyncer { logger := log.WithName("Syncer").WithValues("service", klog.KRef(negSyncerKey.Namespace, negSyncerKey.Name), "negName", negSyncerKey.NegName) @@ -152,6 +157,7 @@ func NewTransactionSyncer( errorState: "", logger: logger, enableDegradedMode: flags.F.EnableDegradedMode, + networkInfo: networkInfo, } // Syncer implements life cycle logic syncer := newSyncer(negSyncerKey, serviceLister, recorder, ts, logger) @@ -161,15 +167,15 @@ func NewTransactionSyncer( return syncer } -func GetEndpointsCalculator(nodeLister, podLister cache.Indexer, zoneGetter negtypes.ZoneGetter, syncerKey negtypes.NegSyncerKey, mode negtypes.EndpointsCalculatorMode, logger klog.Logger, lpConfig negtypes.PodLabelPropagationConfig) negtypes.NetworkEndpointsCalculator { +func GetEndpointsCalculator(nodeLister, podLister cache.Indexer, zoneGetter negtypes.ZoneGetter, syncerKey negtypes.NegSyncerKey, mode negtypes.EndpointsCalculatorMode, logger klog.Logger, lpConfig negtypes.PodLabelPropagationConfig, network string) negtypes.NetworkEndpointsCalculator { serviceKey := strings.Join([]string{syncerKey.Name, syncerKey.Namespace}, "/") if syncerKey.NegType == negtypes.VmIpEndpointType { nodeLister := listers.NewNodeLister(nodeLister) switch mode { case negtypes.L4LocalMode: - return NewLocalL4ILBEndpointsCalculator(nodeLister, zoneGetter, serviceKey, logger) + return NewLocalL4ILBEndpointsCalculator(nodeLister, zoneGetter, serviceKey, logger, network) default: - return NewClusterL4ILBEndpointsCalculator(nodeLister, zoneGetter, serviceKey, logger) + return NewClusterL4ILBEndpointsCalculator(nodeLister, zoneGetter, serviceKey, logger, network) } } return NewL7EndpointsCalculator(zoneGetter, podLister, syncerKey.PortTuple.Name, @@ -336,6 +342,7 @@ func (s *transactionSyncer) ensureNetworkEndpointGroups() error { s.recorder, s.NegSyncerKey.GetAPIVersion(), s.customName, + s.networkInfo, ) if err != nil { errList = append(errList, err) diff --git a/pkg/neg/syncers/transaction_test.go b/pkg/neg/syncers/transaction_test.go index 227d3a357c..e91fb327c8 100644 --- a/pkg/neg/syncers/transaction_test.go +++ b/pkg/neg/syncers/transaction_test.go @@ -1390,7 +1390,7 @@ func TestUnknownNodes(t *testing.T) { func newL4ILBTestTransactionSyncer(fakeGCE negtypes.NetworkEndpointGroupCloud, mode negtypes.EndpointsCalculatorMode) (negtypes.NegSyncer, *transactionSyncer) { negsyncer, ts := newTestTransactionSyncer(fakeGCE, negtypes.VmIpEndpointType, false) - ts.endpointsCalculator = GetEndpointsCalculator(ts.nodeLister, ts.podLister, ts.zoneGetter, ts.NegSyncerKey, mode, klog.TODO(), negtypes.PodLabelPropagationConfig{}) + ts.endpointsCalculator = GetEndpointsCalculator(ts.nodeLister, ts.podLister, ts.zoneGetter, ts.NegSyncerKey, mode, klog.TODO(), negtypes.PodLabelPropagationConfig{}, "") return negsyncer, ts } @@ -1432,11 +1432,12 @@ func newTestTransactionSyncer(fakeGCE negtypes.NetworkEndpointGroupCloud, negTyp testContext.SvcNegInformer.GetIndexer(), reflector, GetEndpointsCalculator(testContext.NodeInformer.GetIndexer(), testContext.PodInformer.GetIndexer(), fakeZoneGetter, - svcPort, mode, klog.TODO(), negtypes.PodLabelPropagationConfig{}), + svcPort, mode, klog.TODO(), negtypes.PodLabelPropagationConfig{}, ""), string(kubeSystemUID), testContext.SvcNegClient, metrics.FakeSyncerMetrics(), customName, + nil, klog.TODO(), ) transactionSyncer := negsyncer.(*syncer).core.(*transactionSyncer) diff --git a/pkg/neg/syncers/utils.go b/pkg/neg/syncers/utils.go index 3f740ff383..9740330677 100644 --- a/pkg/neg/syncers/utils.go +++ b/pkg/neg/syncers/utils.go @@ -31,6 +31,7 @@ import ( "k8s.io/client-go/tools/record" negv1beta1 "k8s.io/ingress-gce/pkg/apis/svcneg/v1beta1" "k8s.io/ingress-gce/pkg/composite" + "k8s.io/ingress-gce/pkg/multinetwork" negtypes "k8s.io/ingress-gce/pkg/neg/types" "k8s.io/ingress-gce/pkg/utils" "k8s.io/klog/v2" @@ -113,7 +114,7 @@ func getService(serviceLister cache.Indexer, namespace, name string) *apiv1.Serv } // ensureNetworkEndpointGroup ensures corresponding NEG is configured correctly in the specified zone. -func ensureNetworkEndpointGroup(svcNamespace, svcName, negName, zone, negServicePortName, kubeSystemUID, port string, networkEndpointType negtypes.NetworkEndpointType, cloud negtypes.NetworkEndpointGroupCloud, serviceLister cache.Indexer, recorder record.EventRecorder, version meta.Version, customName bool) (negv1beta1.NegObjectReference, error) { +func ensureNetworkEndpointGroup(svcNamespace, svcName, negName, zone, negServicePortName, kubeSystemUID, port string, networkEndpointType negtypes.NetworkEndpointType, cloud negtypes.NetworkEndpointGroupCloud, serviceLister cache.Indexer, recorder record.EventRecorder, version meta.Version, customName bool, networkInfo *multinetwork.NetworkInfo) (negv1beta1.NegObjectReference, error) { var negRef negv1beta1.NegObjectReference neg, err := cloud.GetNetworkEndpointGroup(negName, zone, version) if err != nil { @@ -124,6 +125,8 @@ func ensureNetworkEndpointGroup(svcNamespace, svcName, negName, zone, negService klog.V(4).Infof("Neg %q in zone %q was not found: %s", negName, zone, err) } + networkURL := negNetwork(cloud, networkInfo) + subnetworkURL := negSubnetwork(networkEndpointType, cloud, networkInfo) needToCreate := false if neg == nil { needToCreate = true @@ -146,8 +149,8 @@ func ensureNetworkEndpointGroup(svcNamespace, svcName, negName, zone, negService if networkEndpointType != negtypes.NonGCPPrivateEndpointType && // Only perform the following checks when the NEGs are not Non-GCP NEGs. // Non-GCP NEGs do not have associated network and subnetwork. - (!utils.EqualResourceIDs(neg.Network, cloud.NetworkURL()) || - !utils.EqualResourceIDs(neg.Subnetwork, cloud.SubnetworkURL())) { + (!utils.EqualResourceIDs(neg.Network, networkURL) || + !utils.EqualResourceIDs(neg.Subnetwork, subnetworkURL)) { needToCreate = true klog.V(2).Infof("NEG %q in %q does not match network and subnetwork of the cluster. Deleting NEG.", negName, zone) @@ -165,13 +168,6 @@ func ensureNetworkEndpointGroup(svcNamespace, svcName, negName, zone, negService if needToCreate { klog.V(2).Infof("Creating NEG %q for %s in %q.", negName, negServicePortName, zone) - var subnetwork string - switch networkEndpointType { - case negtypes.NonGCPPrivateEndpointType: - subnetwork = "" - default: - subnetwork = cloud.SubnetworkURL() - } desc := "" negDesc := utils.NegDescription{ @@ -186,8 +182,8 @@ func ensureNetworkEndpointGroup(svcNamespace, svcName, negName, zone, negService Version: version, Name: negName, NetworkEndpointType: string(networkEndpointType), - Network: cloud.NetworkURL(), - Subnetwork: subnetwork, + Network: networkURL, + Subnetwork: subnetworkURL, Description: desc, }, zone) if err != nil { @@ -217,6 +213,28 @@ func ensureNetworkEndpointGroup(svcNamespace, svcName, negName, zone, negService return negRef, nil } +func negNetwork(cloud negtypes.NetworkEndpointGroupCloud, networkInfo *multinetwork.NetworkInfo) string { + networkURL := cloud.NetworkURL() + if networkInfo != nil { + networkURL = networkInfo.NetworkURL + } + return networkURL +} + +func negSubnetwork(networkEndpointType negtypes.NetworkEndpointType, cloud negtypes.NetworkEndpointGroupCloud, networkInfo *multinetwork.NetworkInfo) string { + var subnetwork string + switch networkEndpointType { + case negtypes.NonGCPPrivateEndpointType: + subnetwork = "" + default: + subnetwork = cloud.SubnetworkURL() + if networkInfo != nil { + subnetwork = networkInfo.SubnetworkURL + } + } + return subnetwork +} + // toZoneNetworkEndpointMap translates addresses in endpoints object into zone and endpoints map, and also return the count for duplicated endpoints func toZoneNetworkEndpointMap(eds []negtypes.EndpointsData, zoneGetter negtypes.ZoneGetter, servicePortName string, networkEndpointType negtypes.NetworkEndpointType, lpConfig negtypes.PodLabelPropagationConfig) (map[string]negtypes.NetworkEndpointSet, negtypes.EndpointPodMap, int, error) { zoneNetworkEndpointMap := map[string]negtypes.NetworkEndpointSet{} diff --git a/pkg/neg/syncers/utils_test.go b/pkg/neg/syncers/utils_test.go index 1b3e130eb5..5e2e20ba72 100644 --- a/pkg/neg/syncers/utils_test.go +++ b/pkg/neg/syncers/utils_test.go @@ -34,6 +34,7 @@ import ( "k8s.io/client-go/tools/cache" negv1beta1 "k8s.io/ingress-gce/pkg/apis/svcneg/v1beta1" "k8s.io/ingress-gce/pkg/composite" + "k8s.io/ingress-gce/pkg/multinetwork" negtypes "k8s.io/ingress-gce/pkg/neg/types" "k8s.io/ingress-gce/pkg/utils" "k8s.io/legacy-cloud-providers/gce" @@ -317,7 +318,9 @@ func TestEnsureNetworkEndpointGroup(t *testing.T) { enableNonGCPMode bool networkEndpointType negtypes.NetworkEndpointType expectedSubnetwork string + expectedNetwork string apiVersion meta.Version + networkInfo *multinetwork.NetworkInfo }{ { description: "Create NEG of type GCE_VM_IP_PORT", @@ -367,77 +370,75 @@ func TestEnsureNetworkEndpointGroup(t *testing.T) { expectedSubnetwork: testSubnetwork, apiVersion: meta.VersionAlpha, }, + { + description: "Create NEG of type GCE_VM_IP_PORT in alternate network", + negName: "gcp-neg", + enableNonGCPMode: false, + networkEndpointType: negtypes.VmIpPortEndpointType, + expectedNetwork: cloud.ResourcePath("network", &meta.Key{Name: "other-network"}), + expectedSubnetwork: cloud.ResourcePath("subnetwork", &meta.Key{Zone: testZone, Name: "other-subnet"}), + apiVersion: meta.VersionGA, + networkInfo: &multinetwork.NetworkInfo{ + IsDefault: false, + VPC: "other-vpc", + Subnetwork: "other-subnet", + K8sNetwork: "other-network", + NetworkURL: cloud.ResourcePath("network", &meta.Key{Name: "other-network"}), + SubnetworkURL: cloud.ResourcePath("subnetwork", &meta.Key{Zone: testZone, Name: "other-subnet"}), + }, + }, } for _, tc := range testCases { - fakeCloud := negtypes.NewFakeNetworkEndpointGroupCloud(testSubnetwork, testNetwork) - _, err := ensureNetworkEndpointGroup( - testServiceNameSpace, - testServiceName, - tc.negName, - testZone, - testNamedPort, - testKubesystemUID, - testPort, - tc.networkEndpointType, - fakeCloud, - nil, - nil, - tc.apiVersion, - false, - ) - if err != nil { - t.Errorf("unexpected error: %s", err) - } + t.Run(tc.description, func(t *testing.T) { + fakeCloud := negtypes.NewFakeNetworkEndpointGroupCloud(testSubnetwork, testNetwork) + _, err := ensureNetworkEndpointGroup(testServiceNameSpace, testServiceName, tc.negName, testZone, testNamedPort, testKubesystemUID, testPort, tc.networkEndpointType, fakeCloud, nil, nil, tc.apiVersion, false, tc.networkInfo) + if err != nil { + t.Errorf("unexpected error: %s", err) + } - neg, err := fakeCloud.GetNetworkEndpointGroup(tc.negName, testZone, tc.apiVersion) - if err != nil { - t.Errorf("Failed to retrieve NEG %q: %v", tc.negName, err) - } + neg, err := fakeCloud.GetNetworkEndpointGroup(tc.negName, testZone, tc.apiVersion) + if err != nil { + t.Errorf("Failed to retrieve NEG %q: %v", tc.negName, err) + } - if neg.NetworkEndpointType != string(tc.networkEndpointType) { - t.Errorf("Unexpected NetworkEndpointType, expecting %q but got %q", tc.networkEndpointType, neg.NetworkEndpointType) - } + if neg.NetworkEndpointType != string(tc.networkEndpointType) { + t.Errorf("Unexpected NetworkEndpointType, expecting %q but got %q", tc.networkEndpointType, neg.NetworkEndpointType) + } - if neg.Subnetwork != tc.expectedSubnetwork { - t.Errorf("Unexpected Subnetwork, expecting %q but got %q", tc.expectedSubnetwork, neg.Subnetwork) - } + if neg.Subnetwork != tc.expectedSubnetwork { + t.Errorf("Unexpected Subnetwork, expecting %q but got %q", tc.expectedSubnetwork, neg.Subnetwork) + } - expectedNegDesc := utils.NegDescription{ - ClusterUID: testKubesystemUID, - Namespace: testServiceNamespace, - ServiceName: testServiceName, - Port: testPort, - } + if tc.expectedNetwork == "" { + tc.expectedNetwork = testNetwork + } + if neg.Network != tc.expectedNetwork { + t.Errorf("Unexpected Network, expecting %q but got %q", tc.expectedNetwork, neg.Network) + } - actualNegDesc, err := utils.NegDescriptionFromString(neg.Description) - if err != nil { - t.Errorf("Invalid neg description: %s", err) - } + expectedNegDesc := utils.NegDescription{ + ClusterUID: testKubesystemUID, + Namespace: testServiceNamespace, + ServiceName: testServiceName, + Port: testPort, + } - if !reflect.DeepEqual(*actualNegDesc, expectedNegDesc) { - t.Errorf("Unexpected neg description: %s, expected %s", neg.Description, expectedNegDesc.String()) - } + actualNegDesc, err := utils.NegDescriptionFromString(neg.Description) + if err != nil { + t.Errorf("Invalid neg description: %s", err) + } + + if !reflect.DeepEqual(*actualNegDesc, expectedNegDesc) { + t.Errorf("Unexpected neg description: %s, expected %s", neg.Description, expectedNegDesc.String()) + } - // Call ensureNetworkEndpointGroup with the same NEG. - _, err = ensureNetworkEndpointGroup( - testServiceNameSpace, - testServiceName, - tc.negName, - testZone, - testNamedPort, - testKubesystemUID, - testPort, - tc.networkEndpointType, - fakeCloud, - nil, - nil, - tc.apiVersion, - false, - ) + // Call ensureNetworkEndpointGroup with the same NEG. + _, err = ensureNetworkEndpointGroup(testServiceNameSpace, testServiceName, tc.negName, testZone, testNamedPort, testKubesystemUID, testPort, tc.networkEndpointType, fakeCloud, nil, nil, tc.apiVersion, false, nil) - if err != nil { - t.Errorf("Unexpected error when called with duplicated NEG: %v", err) - } + if err != nil { + t.Errorf("Unexpected error when called with duplicated NEG: %v", err) + } + }) } } @@ -879,21 +880,7 @@ func TestNameUniqueness(t *testing.T) { networkEndpointType = negtypes.VmIpPortEndpointType ) fakeCloud := negtypes.NewFakeNetworkEndpointGroupCloud(testSubnetwork, testNetwork) - _, err := ensureNetworkEndpointGroup( - testServiceNameSpace, - testServiceName, - negName, - testZone, - testNamedPort, - testKubesystemUID, - testPort, - networkEndpointType, - fakeCloud, - nil, - nil, - apiVersion, - false, - ) + _, err := ensureNetworkEndpointGroup(testServiceNameSpace, testServiceName, negName, testZone, testNamedPort, testKubesystemUID, testPort, networkEndpointType, fakeCloud, nil, nil, apiVersion, false, nil) if err != nil { t.Errorf("Errored while ensuring network endpoint groups: %s", err) } @@ -908,21 +895,7 @@ func TestNameUniqueness(t *testing.T) { } // Call ensureNetworkEndpointGroup with the same NEG name and different service name - _, err = ensureNetworkEndpointGroup( - testServiceNameSpace, - testServiceName2, - negName, - testZone, - testNamedPort, - testKubesystemUID, - testPort, - networkEndpointType, - fakeCloud, - nil, - nil, - apiVersion, - false, - ) + _, err = ensureNetworkEndpointGroup(testServiceNameSpace, testServiceName2, negName, testZone, testNamedPort, testKubesystemUID, testPort, networkEndpointType, fakeCloud, nil, nil, apiVersion, false, nil) if err == nil { t.Errorf("Expected error when called with duplicate NEG name") @@ -950,21 +923,7 @@ func TestNegObjectCrd(t *testing.T) { negtypes.NonGCPPrivateEndpointType, } { fakeCloud := negtypes.NewFakeNetworkEndpointGroupCloud(testSubnetwork, testNetwork) - negObj, err := ensureNetworkEndpointGroup( - testServiceNameSpace, - testServiceName, - negName, - testZone, - testNamedPort, - testKubesystemUID, - testPort, - networkEndpointType, - fakeCloud, - nil, - nil, - apiVersion, - false, - ) + negObj, err := ensureNetworkEndpointGroup(testServiceNameSpace, testServiceName, negName, testZone, testNamedPort, testKubesystemUID, testPort, networkEndpointType, fakeCloud, nil, nil, apiVersion, false, nil) if err != nil { t.Errorf("Errored while ensuring network endpoint groups: %s", err) } @@ -990,21 +949,7 @@ func TestNegObjectCrd(t *testing.T) { } // Call ensureNetworkEndpointGroup with the same NEG name and different service name - negObj, err = ensureNetworkEndpointGroup( - testServiceNameSpace, - testServiceName, - negName, - testZone, - testNamedPort, - testKubesystemUID, - testPort, - networkEndpointType, - fakeCloud, - nil, - nil, - apiVersion, - false, - ) + negObj, err = ensureNetworkEndpointGroup(testServiceNameSpace, testServiceName, negName, testZone, testNamedPort, testKubesystemUID, testPort, networkEndpointType, fakeCloud, nil, nil, apiVersion, false, nil) if err != nil { t.Errorf("Unexpected error when ensuring NEG: %s", err) @@ -1056,6 +1001,7 @@ func TestNEGRecreate(t *testing.T) { expectRecreate bool expectError bool customName bool + networkInfo *multinetwork.NetworkInfo }{ { desc: "incorrect network, empty neg description, GCP endpoint type", @@ -1139,57 +1085,55 @@ func TestNEGRecreate(t *testing.T) { expectRecreate: false, expectError: false, }, + { + desc: "changing service multi network, matching neg description, GCP endpoint type", + network: testNetwork, + subnetwork: testSubnetwork, + negType: negtypes.VmIpEndpointType, + negDescription: matchingNegDesc, + expectRecreate: true, + expectError: false, + }, } for _, tc := range testCases { - fakeGCE := gce.NewFakeGCECloud(gce.DefaultTestClusterValues()) - negtypes.MockNetworkEndpointAPIs(fakeGCE) - fakeCloud := negtypes.NewAdapterWithNetwork(fakeGCE, testNetwork, testSubnetwork) - fakeCloud.CreateNetworkEndpointGroup(&composite.NetworkEndpointGroup{ - Version: apiVersion, - Name: negName, - NetworkEndpointType: string(tc.negType), - Network: tc.network, - Subnetwork: tc.subnetwork, - Description: tc.negDescription, - }, testZone) - - // Ensure with the correct network and subnet - _, err := ensureNetworkEndpointGroup( - testServiceNameSpace, - testServiceName, - negName, - testZone, - testNamedPort, - testKubesystemUID, - testPort, - tc.negType, - fakeCloud, - nil, - nil, - apiVersion, - tc.customName, - ) - if !tc.expectError && err != nil { - t.Errorf("TestCase: %s, Errored while ensuring network endpoint groups: %s", tc.desc, err) - } else if tc.expectError && err == nil { - t.Errorf("TestCase: %s, Expected error when ensure network endpoint groups", tc.desc) - } + t.Run(tc.desc, func(t *testing.T) { - neg, err := fakeCloud.GetNetworkEndpointGroup(negName, testZone, apiVersion) - if err != nil { - t.Errorf("TestCase: %s, Failed to retrieve NEG %q: %v", tc.desc, negName, err) - } + fakeGCE := gce.NewFakeGCECloud(gce.DefaultTestClusterValues()) + negtypes.MockNetworkEndpointAPIs(fakeGCE) + fakeCloud := negtypes.NewAdapterWithNetwork(fakeGCE, testNetwork, testSubnetwork) + fakeCloud.CreateNetworkEndpointGroup(&composite.NetworkEndpointGroup{ + Version: apiVersion, + Name: negName, + NetworkEndpointType: string(tc.negType), + Network: tc.network, + Subnetwork: tc.subnetwork, + Description: tc.negDescription, + }, testZone) + + // Ensure with the correct network and subnet + _, err := ensureNetworkEndpointGroup(testServiceNameSpace, testServiceName, negName, testZone, testNamedPort, testKubesystemUID, testPort, tc.negType, fakeCloud, nil, nil, apiVersion, tc.customName, nil) + if !tc.expectError && err != nil { + t.Errorf("TestCase: %s, Errored while ensuring network endpoint groups: %s", tc.desc, err) + } else if tc.expectError && err == nil { + t.Errorf("TestCase: %s, Expected error when ensure network endpoint groups", tc.desc) + } - if neg == nil { - t.Errorf("TestCase: %s, Failed to find neg", tc.desc) - } + neg, err := fakeCloud.GetNetworkEndpointGroup(negName, testZone, apiVersion) + if err != nil { + t.Errorf("TestCase: %s, Failed to retrieve NEG %q: %v", tc.desc, negName, err) + } - if tc.expectRecreate && (neg.Subnetwork != testSubnetwork || neg.Network != testNetwork) { - t.Errorf("TestCase: %s\n Neg should have been recreated. Expected subnetwork %s, and found %s. Expected network %s, and found %s", tc.desc, testSubnetwork, neg.Subnetwork, testNetwork, testNetwork) - } else if !tc.expectRecreate && (neg.Subnetwork != tc.subnetwork || neg.Network != tc.network) { - t.Errorf("TestCase: %s\n Neg should not have been recreated. Expected subnetwork %s, and found %s. Expected network %s, and found %s", tc.desc, tc.subnetwork, neg.Subnetwork, tc.network, neg.Network) - } + if neg == nil { + t.Errorf("TestCase: %s, Failed to find neg", tc.desc) + } + + if tc.expectRecreate && (neg.Subnetwork != testSubnetwork || neg.Network != testNetwork) { + t.Errorf("TestCase: %s\n Neg should have been recreated. Expected subnetwork %s, and found %s. Expected network %s, and found %s", tc.desc, testSubnetwork, neg.Subnetwork, testNetwork, testNetwork) + } else if !tc.expectRecreate && (neg.Subnetwork != tc.subnetwork || neg.Network != tc.network) { + t.Errorf("TestCase: %s\n Neg should not have been recreated. Expected subnetwork %s, and found %s. Expected network %s, and found %s", tc.desc, tc.subnetwork, neg.Subnetwork, tc.network, neg.Network) + } + }) } } diff --git a/pkg/neg/types/cloudprovideradapter.go b/pkg/neg/types/cloudprovideradapter.go index 4503c2999b..b04645484d 100644 --- a/pkg/neg/types/cloudprovideradapter.go +++ b/pkg/neg/types/cloudprovideradapter.go @@ -112,3 +112,11 @@ func (a *cloudProviderAdapter) NetworkURL() string { func (a *cloudProviderAdapter) SubnetworkURL() string { return a.subnetworkURL } + +func (a *cloudProviderAdapter) NetworkProjectID() string { + return a.c.NetworkProjectID() +} + +func (a *cloudProviderAdapter) Region() string { + return a.c.Region() +} diff --git a/pkg/neg/types/fakes.go b/pkg/neg/types/fakes.go index 260a84f5f5..bb3855e524 100644 --- a/pkg/neg/types/fakes.go +++ b/pkg/neg/types/fakes.go @@ -264,3 +264,11 @@ func (f *FakeNetworkEndpointGroupCloud) NetworkURL() string { func (f *FakeNetworkEndpointGroupCloud) SubnetworkURL() string { return f.Subnetwork } + +func (f *FakeNetworkEndpointGroupCloud) NetworkProjectID() string { + return "test" +} + +func (f *FakeNetworkEndpointGroupCloud) Region() string { + return "test-region" +} diff --git a/pkg/neg/types/interfaces.go b/pkg/neg/types/interfaces.go index cf5709e0e3..088e9ebcb3 100644 --- a/pkg/neg/types/interfaces.go +++ b/pkg/neg/types/interfaces.go @@ -40,6 +40,8 @@ type NetworkEndpointGroupCloud interface { ListNetworkEndpoints(name, zone string, showHealthStatus bool, version meta.Version) ([]*composite.NetworkEndpointWithHealthStatus, error) NetworkURL() string SubnetworkURL() string + NetworkProjectID() string + Region() string } // NetworkEndpointGroupNamer is an interface for generating network endpoint group name. diff --git a/pkg/neg/types/testing.go b/pkg/neg/types/testing.go index cf2e94090d..e790887047 100644 --- a/pkg/neg/types/testing.go +++ b/pkg/neg/types/testing.go @@ -27,6 +27,9 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/tools/cache" + netfake "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake" + informernetwork "k8s.io/cloud-provider-gcp/crd/client/network/informers/externalversions/network/v1" + informergkenetworkparamset "k8s.io/cloud-provider-gcp/crd/client/network/informers/externalversions/network/v1alpha1" svcnegclient "k8s.io/ingress-gce/pkg/svcneg/client/clientset/versioned" negfake "k8s.io/ingress-gce/pkg/svcneg/client/clientset/versioned/fake" informersvcneg "k8s.io/ingress-gce/pkg/svcneg/client/informers/externalversions/svcneg/v1beta1" @@ -52,13 +55,15 @@ type TestContext struct { NegNamer NetworkEndpointGroupNamer L4Namer namer.L4ResourcesNamer - IngressInformer cache.SharedIndexInformer - PodInformer cache.SharedIndexInformer - ServiceInformer cache.SharedIndexInformer - NodeInformer cache.SharedIndexInformer - EndpointInformer cache.SharedIndexInformer - EndpointSliceInformer cache.SharedIndexInformer - SvcNegInformer cache.SharedIndexInformer + IngressInformer cache.SharedIndexInformer + PodInformer cache.SharedIndexInformer + ServiceInformer cache.SharedIndexInformer + NodeInformer cache.SharedIndexInformer + EndpointInformer cache.SharedIndexInformer + EndpointSliceInformer cache.SharedIndexInformer + SvcNegInformer cache.SharedIndexInformer + NetworkInformer cache.SharedIndexInformer + GKENetworkParamSetInformer cache.SharedIndexInformer KubeSystemUID types.UID ResyncPeriod time.Duration @@ -72,6 +77,7 @@ func NewTestContext() *TestContext { func NewTestContextWithKubeClient(kubeClient kubernetes.Interface) *TestContext { negClient := negfake.NewSimpleClientset() + networkClient := netfake.NewSimpleClientset() fakeGCE := gce.NewFakeGCECloud(gce.DefaultTestClusterValues()) MockNetworkEndpointAPIs(fakeGCE) @@ -79,20 +85,22 @@ func NewTestContextWithKubeClient(kubeClient kubernetes.Interface) *TestContext l4namer := namer.NewL4Namer(kubeSystemUID, clusterNamer) return &TestContext{ - KubeClient: kubeClient, - SvcNegClient: negClient, - Cloud: fakeGCE, - NegNamer: clusterNamer, - L4Namer: l4namer, - IngressInformer: informernetworking.NewIngressInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), - PodInformer: informerv1.NewPodInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), - ServiceInformer: informerv1.NewServiceInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), - EndpointInformer: informerv1.NewEndpointsInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), - EndpointSliceInformer: discoveryinformer.NewEndpointSliceInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), - NodeInformer: informerv1.NewNodeInformer(kubeClient, resyncPeriod, utils.NewNamespaceIndexer()), - SvcNegInformer: informersvcneg.NewServiceNetworkEndpointGroupInformer(negClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), - KubeSystemUID: kubeSystemUID, - ResyncPeriod: resyncPeriod, - NumGCWorkers: numGCWorkers, + KubeClient: kubeClient, + SvcNegClient: negClient, + Cloud: fakeGCE, + NegNamer: clusterNamer, + L4Namer: l4namer, + IngressInformer: informernetworking.NewIngressInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), + PodInformer: informerv1.NewPodInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), + ServiceInformer: informerv1.NewServiceInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), + EndpointInformer: informerv1.NewEndpointsInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), + EndpointSliceInformer: discoveryinformer.NewEndpointSliceInformer(kubeClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), + NodeInformer: informerv1.NewNodeInformer(kubeClient, resyncPeriod, utils.NewNamespaceIndexer()), + SvcNegInformer: informersvcneg.NewServiceNetworkEndpointGroupInformer(negClient, namespace, resyncPeriod, utils.NewNamespaceIndexer()), + NetworkInformer: informernetwork.NewNetworkInformer(networkClient, resyncPeriod, utils.NewNamespaceIndexer()), + GKENetworkParamSetInformer: informergkenetworkparamset.NewGKENetworkParamSetInformer(networkClient, resyncPeriod, utils.NewNamespaceIndexer()), + KubeSystemUID: kubeSystemUID, + ResyncPeriod: resyncPeriod, + NumGCWorkers: numGCWorkers, } } diff --git a/pkg/neg/types/types.go b/pkg/neg/types/types.go index 99d197482e..cbbb087d30 100644 --- a/pkg/neg/types/types.go +++ b/pkg/neg/types/types.go @@ -28,6 +28,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/ingress-gce/pkg/annotations" + "k8s.io/ingress-gce/pkg/multinetwork" "k8s.io/ingress-gce/pkg/utils" "k8s.io/ingress-gce/pkg/utils/namer" ) @@ -124,6 +125,8 @@ type PortInfo struct { // This is applicable in GCE_VM_IP NEGs where the endpoints are the nodes instead of pods. // L7 NEGs will have either "" or L7Mode. EpCalculatorMode EndpointsCalculatorMode + + NetworkInfo *multinetwork.NetworkInfo } // PortInfoMapKey is the Key of PortInfoMap @@ -153,24 +156,20 @@ func NewPortInfoMap(namespace, name string, svcPortTupleSet SvcPortTupleSet, nam // NewPortInfoMapForVMIPNEG creates PortInfoMap with empty port tuple. Since VM_IP NEGs target // the node instead of the pod, there is no port info to be stored. -func NewPortInfoMapForVMIPNEG(namespace, name string, namer namer.L4ResourcesNamer, local bool) PortInfoMap { +func NewPortInfoMapForVMIPNEG(namespace, name string, namer namer.L4ResourcesNamer, local bool, networkInfo *multinetwork.NetworkInfo) PortInfoMap { ret := PortInfoMap{} - svcPortSet := make(SvcPortTupleSet) - svcPortSet.Insert( - // Insert Empty PortTuple for VmIp NEGs. - SvcPortTuple{}, - ) - for svcPortTuple := range svcPortSet { - mode := L4ClusterMode - if local { - mode = L4LocalMode - } - negName := namer.L4Backend(namespace, name) - ret[PortInfoMapKey{svcPortTuple.Port}] = PortInfo{ - PortTuple: svcPortTuple, - NegName: negName, - EpCalculatorMode: mode, - } + portTuple := SvcPortTuple{} + + mode := L4ClusterMode + if local { + mode = L4LocalMode + } + negName := namer.L4Backend(namespace, name) + ret[PortInfoMapKey{portTuple.Port}] = PortInfo{ + PortTuple: portTuple, + NegName: negName, + EpCalculatorMode: mode, + NetworkInfo: networkInfo, } return ret } @@ -202,6 +201,7 @@ func (p1 PortInfoMap) Merge(p2 PortInfoMap) error { // Turn on the readiness gate if one of them is on mergedInfo.ReadinessGate = mergedInfo.ReadinessGate || portInfo.ReadinessGate mergedInfo.EpCalculatorMode = portInfo.EpCalculatorMode + mergedInfo.NetworkInfo = portInfo.NetworkInfo p1[mapKey] = mergedInfo } diff --git a/pkg/neg/types/types_test.go b/pkg/neg/types/types_test.go index 82490a191d..9b6ddb15a1 100644 --- a/pkg/neg/types/types_test.go +++ b/pkg/neg/types/types_test.go @@ -682,8 +682,8 @@ func TestEndpointsCalculatorMode(t *testing.T) { portInfoMap PortInfoMap expectMode EndpointsCalculatorMode }{ - {"L4 Local Mode", NewPortInfoMapForVMIPNEG("testns", "testsvc", testContext.L4Namer, true), L4LocalMode}, - {"L4 Cluster Mode", NewPortInfoMapForVMIPNEG("testns", "testsvc", testContext.L4Namer, false), L4ClusterMode}, + {"L4 Local Mode", NewPortInfoMapForVMIPNEG("testns", "testsvc", testContext.L4Namer, true, nil), L4LocalMode}, + {"L4 Cluster Mode", NewPortInfoMapForVMIPNEG("testns", "testsvc", testContext.L4Namer, false, nil), L4ClusterMode}, {"L7 Mode", NewPortInfoMap("testns", "testsvc", NewSvcPortTupleSet(SvcPortTuple{Name: "http", Port: 80, TargetPort: "targetPort"}), testContext.NegNamer, false, nil), L7Mode}, {"Empty tupleset returns L7 Mode", NewPortInfoMap("testns", "testsvc", nil, testContext.NegNamer, false, nil), L7Mode}, } { diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/BUILD b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/BUILD new file mode 100644 index 0000000000..a971f005e6 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/BUILD @@ -0,0 +1,30 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "fake", + srcs = [ + "clientset_generated.go", + "doc.go", + "register.go", + ], + importpath = "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:meta", + "//vendor/k8s.io/apimachinery/pkg/runtime", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema", + "//vendor/k8s.io/apimachinery/pkg/runtime/serializer", + "//vendor/k8s.io/apimachinery/pkg/util/runtime", + "//vendor/k8s.io/apimachinery/pkg/watch", + "//vendor/k8s.io/client-go/discovery", + "//vendor/k8s.io/client-go/discovery/fake", + "//vendor/k8s.io/client-go/testing", + "//vendor/k8s.io/cloud-provider-gcp/crd/apis/network/v1:network", + "//vendor/k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1", + "//vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned", + "//vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1:network", + "//vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake", + "//vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1", + "//vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake", + ], +) diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/clientset_generated.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 0000000000..43b70b3058 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,89 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + clientset "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned" + networkingv1 "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1" + fakenetworkingv1 "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake" + networkingv1alpha1 "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1" + fakenetworkingv1alpha1 "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +var _ clientset.Interface = &Clientset{} + +// NetworkingV1alpha1 retrieves the NetworkingV1alpha1Client +func (c *Clientset) NetworkingV1alpha1() networkingv1alpha1.NetworkingV1alpha1Interface { + return &fakenetworkingv1alpha1.FakeNetworkingV1alpha1{Fake: &c.Fake} +} + +// NetworkingV1 retrieves the NetworkingV1Client +func (c *Clientset) NetworkingV1() networkingv1.NetworkingV1Interface { + return &fakenetworkingv1.FakeNetworkingV1{Fake: &c.Fake} +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/doc.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/doc.go new file mode 100644 index 0000000000..50d0812d7f --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/register.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/register.go new file mode 100644 index 0000000000..26726b8d9f --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake/register.go @@ -0,0 +1,58 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + networkingv1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1" + networkingv1alpha1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + networkingv1alpha1.AddToScheme, + networkingv1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/BUILD b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/BUILD new file mode 100644 index 0000000000..39fe2a3bbb --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/BUILD @@ -0,0 +1,26 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "fake", + srcs = [ + "doc.go", + "fake_network.go", + "fake_network_client.go", + "fake_networkinterface.go", + "fake_networkinterfacelist.go", + "fake_networklist.go", + ], + importpath = "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:meta", + "//vendor/k8s.io/apimachinery/pkg/labels", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema", + "//vendor/k8s.io/apimachinery/pkg/types", + "//vendor/k8s.io/apimachinery/pkg/watch", + "//vendor/k8s.io/client-go/rest", + "//vendor/k8s.io/client-go/testing", + "//vendor/k8s.io/cloud-provider-gcp/crd/apis/network/v1:network", + "//vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1:network", + ], +) diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/doc.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/doc.go new file mode 100644 index 0000000000..1672f9cfa1 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_network.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_network.go new file mode 100644 index 0000000000..29a26c60f7 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_network.go @@ -0,0 +1,133 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + networkv1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1" +) + +// FakeNetworks implements NetworkInterface +type FakeNetworks struct { + Fake *FakeNetworkingV1 +} + +var networksResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1", Resource: "networks"} + +var networksKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1", Kind: "Network"} + +// Get takes name of the network, and returns the corresponding network object, and an error if there is any. +func (c *FakeNetworks) Get(ctx context.Context, name string, options v1.GetOptions) (result *networkv1.Network, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(networksResource, name), &networkv1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*networkv1.Network), err +} + +// List takes label and field selectors, and returns the list of Networks that match those selectors. +func (c *FakeNetworks) List(ctx context.Context, opts v1.ListOptions) (result *networkv1.NetworkList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(networksResource, networksKind, opts), &networkv1.NetworkList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &networkv1.NetworkList{ListMeta: obj.(*networkv1.NetworkList).ListMeta} + for _, item := range obj.(*networkv1.NetworkList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested networks. +func (c *FakeNetworks) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(networksResource, opts)) +} + +// Create takes the representation of a network and creates it. Returns the server's representation of the network, and an error, if there is any. +func (c *FakeNetworks) Create(ctx context.Context, network *networkv1.Network, opts v1.CreateOptions) (result *networkv1.Network, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(networksResource, network), &networkv1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*networkv1.Network), err +} + +// Update takes the representation of a network and updates it. Returns the server's representation of the network, and an error, if there is any. +func (c *FakeNetworks) Update(ctx context.Context, network *networkv1.Network, opts v1.UpdateOptions) (result *networkv1.Network, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(networksResource, network), &networkv1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*networkv1.Network), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeNetworks) UpdateStatus(ctx context.Context, network *networkv1.Network, opts v1.UpdateOptions) (*networkv1.Network, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(networksResource, "status", network), &networkv1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*networkv1.Network), err +} + +// Delete takes name of the network and deletes it. Returns an error if one occurs. +func (c *FakeNetworks) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(networksResource, name), &networkv1.Network{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeNetworks) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(networksResource, listOpts) + + _, err := c.Fake.Invokes(action, &networkv1.NetworkList{}) + return err +} + +// Patch applies the patch and returns the patched network. +func (c *FakeNetworks) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *networkv1.Network, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(networksResource, name, pt, data, subresources...), &networkv1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*networkv1.Network), err +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_network_client.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_network_client.go new file mode 100644 index 0000000000..293c61735c --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_network_client.go @@ -0,0 +1,52 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1" +) + +type FakeNetworkingV1 struct { + *testing.Fake +} + +func (c *FakeNetworkingV1) Networks() v1.NetworkInterface { + return &FakeNetworks{c} +} + +func (c *FakeNetworkingV1) NetworkInterfaces(namespace string) v1.NetworkInterfaceInterface { + return &FakeNetworkInterfaces{c, namespace} +} + +func (c *FakeNetworkingV1) NetworkInterfaceLists(namespace string) v1.NetworkInterfaceListInterface { + return &FakeNetworkInterfaceLists{c, namespace} +} + +func (c *FakeNetworkingV1) NetworkLists() v1.NetworkListInterface { + return &FakeNetworkLists{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNetworkingV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_networkinterface.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_networkinterface.go new file mode 100644 index 0000000000..f39d5e3e75 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_networkinterface.go @@ -0,0 +1,142 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + networkv1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1" +) + +// FakeNetworkInterfaces implements NetworkInterfaceInterface +type FakeNetworkInterfaces struct { + Fake *FakeNetworkingV1 + ns string +} + +var networkinterfacesResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1", Resource: "networkinterfaces"} + +var networkinterfacesKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1", Kind: "NetworkInterface"} + +// Get takes name of the networkInterface, and returns the corresponding networkInterface object, and an error if there is any. +func (c *FakeNetworkInterfaces) Get(ctx context.Context, name string, options v1.GetOptions) (result *networkv1.NetworkInterface, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(networkinterfacesResource, c.ns, name), &networkv1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*networkv1.NetworkInterface), err +} + +// List takes label and field selectors, and returns the list of NetworkInterfaces that match those selectors. +func (c *FakeNetworkInterfaces) List(ctx context.Context, opts v1.ListOptions) (result *networkv1.NetworkInterfaceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(networkinterfacesResource, networkinterfacesKind, c.ns, opts), &networkv1.NetworkInterfaceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &networkv1.NetworkInterfaceList{ListMeta: obj.(*networkv1.NetworkInterfaceList).ListMeta} + for _, item := range obj.(*networkv1.NetworkInterfaceList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested networkInterfaces. +func (c *FakeNetworkInterfaces) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(networkinterfacesResource, c.ns, opts)) + +} + +// Create takes the representation of a networkInterface and creates it. Returns the server's representation of the networkInterface, and an error, if there is any. +func (c *FakeNetworkInterfaces) Create(ctx context.Context, networkInterface *networkv1.NetworkInterface, opts v1.CreateOptions) (result *networkv1.NetworkInterface, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(networkinterfacesResource, c.ns, networkInterface), &networkv1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*networkv1.NetworkInterface), err +} + +// Update takes the representation of a networkInterface and updates it. Returns the server's representation of the networkInterface, and an error, if there is any. +func (c *FakeNetworkInterfaces) Update(ctx context.Context, networkInterface *networkv1.NetworkInterface, opts v1.UpdateOptions) (result *networkv1.NetworkInterface, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(networkinterfacesResource, c.ns, networkInterface), &networkv1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*networkv1.NetworkInterface), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeNetworkInterfaces) UpdateStatus(ctx context.Context, networkInterface *networkv1.NetworkInterface, opts v1.UpdateOptions) (*networkv1.NetworkInterface, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(networkinterfacesResource, "status", c.ns, networkInterface), &networkv1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*networkv1.NetworkInterface), err +} + +// Delete takes name of the networkInterface and deletes it. Returns an error if one occurs. +func (c *FakeNetworkInterfaces) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(networkinterfacesResource, c.ns, name), &networkv1.NetworkInterface{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeNetworkInterfaces) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(networkinterfacesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &networkv1.NetworkInterfaceList{}) + return err +} + +// Patch applies the patch and returns the patched networkInterface. +func (c *FakeNetworkInterfaces) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *networkv1.NetworkInterface, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(networkinterfacesResource, c.ns, name, pt, data, subresources...), &networkv1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*networkv1.NetworkInterface), err +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_networkinterfacelist.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_networkinterfacelist.go new file mode 100644 index 0000000000..940cfa7522 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_networkinterfacelist.go @@ -0,0 +1,49 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" + networkv1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1" +) + +// FakeNetworkInterfaceLists implements NetworkInterfaceListInterface +type FakeNetworkInterfaceLists struct { + Fake *FakeNetworkingV1 + ns string +} + +var networkinterfacelistsResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1", Resource: "networkinterfacelists"} + +var networkinterfacelistsKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1", Kind: "NetworkInterfaceList"} + +// Get takes name of the networkInterfaceList, and returns the corresponding networkInterfaceList object, and an error if there is any. +func (c *FakeNetworkInterfaceLists) Get(ctx context.Context, name string, options v1.GetOptions) (result *networkv1.NetworkInterfaceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(networkinterfacelistsResource, c.ns, name), &networkv1.NetworkInterfaceList{}) + + if obj == nil { + return nil, err + } + return obj.(*networkv1.NetworkInterfaceList), err +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_networklist.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_networklist.go new file mode 100644 index 0000000000..adf9b5767e --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake/fake_networklist.go @@ -0,0 +1,47 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" + networkv1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1" +) + +// FakeNetworkLists implements NetworkListInterface +type FakeNetworkLists struct { + Fake *FakeNetworkingV1 +} + +var networklistsResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1", Resource: "networklists"} + +var networklistsKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1", Kind: "NetworkList"} + +// Get takes name of the networkList, and returns the corresponding networkList object, and an error if there is any. +func (c *FakeNetworkLists) Get(ctx context.Context, name string, options v1.GetOptions) (result *networkv1.NetworkList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(networklistsResource, name), &networkv1.NetworkList{}) + if obj == nil { + return nil, err + } + return obj.(*networkv1.NetworkList), err +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/BUILD b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/BUILD new file mode 100644 index 0000000000..c396b2742c --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/BUILD @@ -0,0 +1,28 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "fake", + srcs = [ + "doc.go", + "fake_gkenetworkparamset.go", + "fake_gkenetworkparamsetlist.go", + "fake_network.go", + "fake_network_client.go", + "fake_networkinterface.go", + "fake_networkinterfacelist.go", + "fake_networklist.go", + ], + importpath = "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:meta", + "//vendor/k8s.io/apimachinery/pkg/labels", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema", + "//vendor/k8s.io/apimachinery/pkg/types", + "//vendor/k8s.io/apimachinery/pkg/watch", + "//vendor/k8s.io/client-go/rest", + "//vendor/k8s.io/client-go/testing", + "//vendor/k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1", + "//vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1", + ], +) diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/doc.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/doc.go new file mode 100644 index 0000000000..1672f9cfa1 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_gkenetworkparamset.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_gkenetworkparamset.go new file mode 100644 index 0000000000..f062e4f35f --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_gkenetworkparamset.go @@ -0,0 +1,133 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1" +) + +// FakeGKENetworkParamSets implements GKENetworkParamSetInterface +type FakeGKENetworkParamSets struct { + Fake *FakeNetworkingV1alpha1 +} + +var gkenetworkparamsetsResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1alpha1", Resource: "gkenetworkparamsets"} + +var gkenetworkparamsetsKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1alpha1", Kind: "GKENetworkParamSet"} + +// Get takes name of the gKENetworkParamSet, and returns the corresponding gKENetworkParamSet object, and an error if there is any. +func (c *FakeGKENetworkParamSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.GKENetworkParamSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(gkenetworkparamsetsResource, name), &v1alpha1.GKENetworkParamSet{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.GKENetworkParamSet), err +} + +// List takes label and field selectors, and returns the list of GKENetworkParamSets that match those selectors. +func (c *FakeGKENetworkParamSets) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.GKENetworkParamSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(gkenetworkparamsetsResource, gkenetworkparamsetsKind, opts), &v1alpha1.GKENetworkParamSetList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.GKENetworkParamSetList{ListMeta: obj.(*v1alpha1.GKENetworkParamSetList).ListMeta} + for _, item := range obj.(*v1alpha1.GKENetworkParamSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested gKENetworkParamSets. +func (c *FakeGKENetworkParamSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(gkenetworkparamsetsResource, opts)) +} + +// Create takes the representation of a gKENetworkParamSet and creates it. Returns the server's representation of the gKENetworkParamSet, and an error, if there is any. +func (c *FakeGKENetworkParamSets) Create(ctx context.Context, gKENetworkParamSet *v1alpha1.GKENetworkParamSet, opts v1.CreateOptions) (result *v1alpha1.GKENetworkParamSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(gkenetworkparamsetsResource, gKENetworkParamSet), &v1alpha1.GKENetworkParamSet{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.GKENetworkParamSet), err +} + +// Update takes the representation of a gKENetworkParamSet and updates it. Returns the server's representation of the gKENetworkParamSet, and an error, if there is any. +func (c *FakeGKENetworkParamSets) Update(ctx context.Context, gKENetworkParamSet *v1alpha1.GKENetworkParamSet, opts v1.UpdateOptions) (result *v1alpha1.GKENetworkParamSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(gkenetworkparamsetsResource, gKENetworkParamSet), &v1alpha1.GKENetworkParamSet{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.GKENetworkParamSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeGKENetworkParamSets) UpdateStatus(ctx context.Context, gKENetworkParamSet *v1alpha1.GKENetworkParamSet, opts v1.UpdateOptions) (*v1alpha1.GKENetworkParamSet, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(gkenetworkparamsetsResource, "status", gKENetworkParamSet), &v1alpha1.GKENetworkParamSet{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.GKENetworkParamSet), err +} + +// Delete takes name of the gKENetworkParamSet and deletes it. Returns an error if one occurs. +func (c *FakeGKENetworkParamSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(gkenetworkparamsetsResource, name), &v1alpha1.GKENetworkParamSet{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeGKENetworkParamSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(gkenetworkparamsetsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.GKENetworkParamSetList{}) + return err +} + +// Patch applies the patch and returns the patched gKENetworkParamSet. +func (c *FakeGKENetworkParamSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.GKENetworkParamSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(gkenetworkparamsetsResource, name, pt, data, subresources...), &v1alpha1.GKENetworkParamSet{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.GKENetworkParamSet), err +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_gkenetworkparamsetlist.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_gkenetworkparamsetlist.go new file mode 100644 index 0000000000..dc34adf5ea --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_gkenetworkparamsetlist.go @@ -0,0 +1,47 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" + v1alpha1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1" +) + +// FakeGKENetworkParamSetLists implements GKENetworkParamSetListInterface +type FakeGKENetworkParamSetLists struct { + Fake *FakeNetworkingV1alpha1 +} + +var gkenetworkparamsetlistsResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1alpha1", Resource: "gkenetworkparamsetlists"} + +var gkenetworkparamsetlistsKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1alpha1", Kind: "GKENetworkParamSetList"} + +// Get takes name of the gKENetworkParamSetList, and returns the corresponding gKENetworkParamSetList object, and an error if there is any. +func (c *FakeGKENetworkParamSetLists) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.GKENetworkParamSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(gkenetworkparamsetlistsResource, name), &v1alpha1.GKENetworkParamSetList{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.GKENetworkParamSetList), err +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_network.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_network.go new file mode 100644 index 0000000000..32dbd1d6d4 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_network.go @@ -0,0 +1,133 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1" +) + +// FakeNetworks implements NetworkInterface +type FakeNetworks struct { + Fake *FakeNetworkingV1alpha1 +} + +var networksResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1alpha1", Resource: "networks"} + +var networksKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1alpha1", Kind: "Network"} + +// Get takes name of the network, and returns the corresponding network object, and an error if there is any. +func (c *FakeNetworks) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Network, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(networksResource, name), &v1alpha1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Network), err +} + +// List takes label and field selectors, and returns the list of Networks that match those selectors. +func (c *FakeNetworks) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NetworkList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(networksResource, networksKind, opts), &v1alpha1.NetworkList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.NetworkList{ListMeta: obj.(*v1alpha1.NetworkList).ListMeta} + for _, item := range obj.(*v1alpha1.NetworkList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested networks. +func (c *FakeNetworks) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(networksResource, opts)) +} + +// Create takes the representation of a network and creates it. Returns the server's representation of the network, and an error, if there is any. +func (c *FakeNetworks) Create(ctx context.Context, network *v1alpha1.Network, opts v1.CreateOptions) (result *v1alpha1.Network, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(networksResource, network), &v1alpha1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Network), err +} + +// Update takes the representation of a network and updates it. Returns the server's representation of the network, and an error, if there is any. +func (c *FakeNetworks) Update(ctx context.Context, network *v1alpha1.Network, opts v1.UpdateOptions) (result *v1alpha1.Network, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(networksResource, network), &v1alpha1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Network), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeNetworks) UpdateStatus(ctx context.Context, network *v1alpha1.Network, opts v1.UpdateOptions) (*v1alpha1.Network, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(networksResource, "status", network), &v1alpha1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Network), err +} + +// Delete takes name of the network and deletes it. Returns an error if one occurs. +func (c *FakeNetworks) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(networksResource, name), &v1alpha1.Network{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeNetworks) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(networksResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.NetworkList{}) + return err +} + +// Patch applies the patch and returns the patched network. +func (c *FakeNetworks) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Network, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(networksResource, name, pt, data, subresources...), &v1alpha1.Network{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Network), err +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_network_client.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_network_client.go new file mode 100644 index 0000000000..93e706e95a --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_network_client.go @@ -0,0 +1,60 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1alpha1 "k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1" +) + +type FakeNetworkingV1alpha1 struct { + *testing.Fake +} + +func (c *FakeNetworkingV1alpha1) GKENetworkParamSets() v1alpha1.GKENetworkParamSetInterface { + return &FakeGKENetworkParamSets{c} +} + +func (c *FakeNetworkingV1alpha1) GKENetworkParamSetLists() v1alpha1.GKENetworkParamSetListInterface { + return &FakeGKENetworkParamSetLists{c} +} + +func (c *FakeNetworkingV1alpha1) Networks() v1alpha1.NetworkInterface { + return &FakeNetworks{c} +} + +func (c *FakeNetworkingV1alpha1) NetworkInterfaces(namespace string) v1alpha1.NetworkInterfaceInterface { + return &FakeNetworkInterfaces{c, namespace} +} + +func (c *FakeNetworkingV1alpha1) NetworkInterfaceLists(namespace string) v1alpha1.NetworkInterfaceListInterface { + return &FakeNetworkInterfaceLists{c, namespace} +} + +func (c *FakeNetworkingV1alpha1) NetworkLists() v1alpha1.NetworkListInterface { + return &FakeNetworkLists{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNetworkingV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_networkinterface.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_networkinterface.go new file mode 100644 index 0000000000..cdd481b256 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_networkinterface.go @@ -0,0 +1,142 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1" +) + +// FakeNetworkInterfaces implements NetworkInterfaceInterface +type FakeNetworkInterfaces struct { + Fake *FakeNetworkingV1alpha1 + ns string +} + +var networkinterfacesResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1alpha1", Resource: "networkinterfaces"} + +var networkinterfacesKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1alpha1", Kind: "NetworkInterface"} + +// Get takes name of the networkInterface, and returns the corresponding networkInterface object, and an error if there is any. +func (c *FakeNetworkInterfaces) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NetworkInterface, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(networkinterfacesResource, c.ns, name), &v1alpha1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NetworkInterface), err +} + +// List takes label and field selectors, and returns the list of NetworkInterfaces that match those selectors. +func (c *FakeNetworkInterfaces) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NetworkInterfaceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(networkinterfacesResource, networkinterfacesKind, c.ns, opts), &v1alpha1.NetworkInterfaceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.NetworkInterfaceList{ListMeta: obj.(*v1alpha1.NetworkInterfaceList).ListMeta} + for _, item := range obj.(*v1alpha1.NetworkInterfaceList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested networkInterfaces. +func (c *FakeNetworkInterfaces) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(networkinterfacesResource, c.ns, opts)) + +} + +// Create takes the representation of a networkInterface and creates it. Returns the server's representation of the networkInterface, and an error, if there is any. +func (c *FakeNetworkInterfaces) Create(ctx context.Context, networkInterface *v1alpha1.NetworkInterface, opts v1.CreateOptions) (result *v1alpha1.NetworkInterface, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(networkinterfacesResource, c.ns, networkInterface), &v1alpha1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NetworkInterface), err +} + +// Update takes the representation of a networkInterface and updates it. Returns the server's representation of the networkInterface, and an error, if there is any. +func (c *FakeNetworkInterfaces) Update(ctx context.Context, networkInterface *v1alpha1.NetworkInterface, opts v1.UpdateOptions) (result *v1alpha1.NetworkInterface, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(networkinterfacesResource, c.ns, networkInterface), &v1alpha1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NetworkInterface), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeNetworkInterfaces) UpdateStatus(ctx context.Context, networkInterface *v1alpha1.NetworkInterface, opts v1.UpdateOptions) (*v1alpha1.NetworkInterface, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(networkinterfacesResource, "status", c.ns, networkInterface), &v1alpha1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NetworkInterface), err +} + +// Delete takes name of the networkInterface and deletes it. Returns an error if one occurs. +func (c *FakeNetworkInterfaces) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(networkinterfacesResource, c.ns, name), &v1alpha1.NetworkInterface{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeNetworkInterfaces) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(networkinterfacesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.NetworkInterfaceList{}) + return err +} + +// Patch applies the patch and returns the patched networkInterface. +func (c *FakeNetworkInterfaces) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NetworkInterface, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(networkinterfacesResource, c.ns, name, pt, data, subresources...), &v1alpha1.NetworkInterface{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NetworkInterface), err +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_networkinterfacelist.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_networkinterfacelist.go new file mode 100644 index 0000000000..65be024427 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_networkinterfacelist.go @@ -0,0 +1,49 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" + v1alpha1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1" +) + +// FakeNetworkInterfaceLists implements NetworkInterfaceListInterface +type FakeNetworkInterfaceLists struct { + Fake *FakeNetworkingV1alpha1 + ns string +} + +var networkinterfacelistsResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1alpha1", Resource: "networkinterfacelists"} + +var networkinterfacelistsKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1alpha1", Kind: "NetworkInterfaceList"} + +// Get takes name of the networkInterfaceList, and returns the corresponding networkInterfaceList object, and an error if there is any. +func (c *FakeNetworkInterfaceLists) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NetworkInterfaceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(networkinterfacelistsResource, c.ns, name), &v1alpha1.NetworkInterfaceList{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NetworkInterfaceList), err +} diff --git a/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_networklist.go b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_networklist.go new file mode 100644 index 0000000000..a3d52b5573 --- /dev/null +++ b/vendor/k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake/fake_networklist.go @@ -0,0 +1,47 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" + v1alpha1 "k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1" +) + +// FakeNetworkLists implements NetworkListInterface +type FakeNetworkLists struct { + Fake *FakeNetworkingV1alpha1 +} + +var networklistsResource = schema.GroupVersionResource{Group: "networking.gke.io", Version: "v1alpha1", Resource: "networklists"} + +var networklistsKind = schema.GroupVersionKind{Group: "networking.gke.io", Version: "v1alpha1", Kind: "NetworkList"} + +// Get takes name of the networkList, and returns the corresponding networkList object, and an error if there is any. +func (c *FakeNetworkLists) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NetworkList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(networklistsResource, name), &v1alpha1.NetworkList{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NetworkList), err +} diff --git a/vendor/modules.txt b/vendor/modules.txt index f12d576fa9..c5c1fc266d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -795,9 +795,12 @@ k8s.io/cloud-provider/volume/helpers k8s.io/cloud-provider-gcp/crd/apis/network/v1 k8s.io/cloud-provider-gcp/crd/apis/network/v1alpha1 k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned +k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/fake k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/scheme k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1 +k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1/fake k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1 +k8s.io/cloud-provider-gcp/crd/client/network/clientset/versioned/typed/network/v1alpha1/fake k8s.io/cloud-provider-gcp/crd/client/network/informers/externalversions/internalinterfaces k8s.io/cloud-provider-gcp/crd/client/network/informers/externalversions/network/v1 k8s.io/cloud-provider-gcp/crd/client/network/informers/externalversions/network/v1alpha1