Merge pull request #69042 from rramkumar1/fake-gce-1
Expose public function to init fake GCECloud + add common hooks
This commit is contained in:
		| @@ -20,6 +20,7 @@ go_library( | ||||
|         "gce_clusterid.go", | ||||
|         "gce_clusters.go", | ||||
|         "gce_disks.go", | ||||
|         "gce_fake.go", | ||||
|         "gce_firewall.go", | ||||
|         "gce_forwardingrule.go", | ||||
|         "gce_healthchecks.go", | ||||
| @@ -50,6 +51,7 @@ go_library( | ||||
|         "//pkg/cloudprovider/providers/gce/cloud:go_default_library", | ||||
|         "//pkg/cloudprovider/providers/gce/cloud/filter:go_default_library", | ||||
|         "//pkg/cloudprovider/providers/gce/cloud/meta:go_default_library", | ||||
|         "//pkg/cloudprovider/providers/gce/cloud/mock:go_default_library", | ||||
|         "//pkg/controller:go_default_library", | ||||
|         "//pkg/features:go_default_library", | ||||
|         "//pkg/kubelet/apis:go_default_library", | ||||
| @@ -120,7 +122,6 @@ go_test( | ||||
|         "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||
|         "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", | ||||
|         "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", | ||||
|         "//staging/src/k8s.io/client-go/tools/cache:go_default_library", | ||||
|         "//staging/src/k8s.io/client-go/tools/record:go_default_library", | ||||
|         "//vendor/github.com/stretchr/testify/assert:go_default_library", | ||||
|         "//vendor/github.com/stretchr/testify/require:go_default_library", | ||||
|   | ||||
| @@ -44,6 +44,8 @@ var ( | ||||
| 	InUseError = &googleapi.Error{Code: http.StatusBadRequest, Message: "It's being used by god."} | ||||
| 	// InternalServerError is shared variable with error code StatusInternalServerError for error verification. | ||||
| 	InternalServerError = &googleapi.Error{Code: http.StatusInternalServerError} | ||||
| 	// UnauthorizedErr wraps a Google API error with code StatusForbidden. | ||||
| 	UnauthorizedErr = &googleapi.Error{Code: http.StatusForbidden} | ||||
| ) | ||||
|  | ||||
| // gceObject is an abstraction of all GCE API object in go client | ||||
| @@ -436,6 +438,63 @@ func UpdateRegionBackendServiceHook(ctx context.Context, key *meta.Key, obj *ga. | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // UpdateBackendServiceHook defines the hook for updating a BackendService. | ||||
| // It replaces the object with the same key in the mock with the updated object. | ||||
| func UpdateBackendServiceHook(ctx context.Context, key *meta.Key, obj *ga.BackendService, m *cloud.MockBackendServices) error { | ||||
| 	_, err := m.Get(ctx, key) | ||||
| 	if err != nil { | ||||
| 		return &googleapi.Error{ | ||||
| 			Code:    http.StatusNotFound, | ||||
| 			Message: fmt.Sprintf("Key: %s was not found in BackendServices", key.String()), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	obj.Name = key.Name | ||||
| 	projectID := m.ProjectRouter.ProjectID(ctx, "ga", "backendServices") | ||||
| 	obj.SelfLink = cloud.SelfLink(meta.VersionGA, projectID, "backendServices", key) | ||||
|  | ||||
| 	m.Objects[*key] = &cloud.MockBackendServicesObj{Obj: obj} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // UpdateAlphaBackendServiceHook defines the hook for updating an alpha BackendService. | ||||
| // It replaces the object with the same key in the mock with the updated object. | ||||
| func UpdateAlphaBackendServiceHook(ctx context.Context, key *meta.Key, obj *alpha.BackendService, m *cloud.MockAlphaBackendServices) error { | ||||
| 	_, err := m.Get(ctx, key) | ||||
| 	if err != nil { | ||||
| 		return &googleapi.Error{ | ||||
| 			Code:    http.StatusNotFound, | ||||
| 			Message: fmt.Sprintf("Key: %s was not found in BackendServices", key.String()), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	obj.Name = key.Name | ||||
| 	projectID := m.ProjectRouter.ProjectID(ctx, "alpha", "backendServices") | ||||
| 	obj.SelfLink = cloud.SelfLink(meta.VersionAlpha, projectID, "backendServices", key) | ||||
|  | ||||
| 	m.Objects[*key] = &cloud.MockBackendServicesObj{Obj: obj} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // UpdateURLMapHook defines the hook for updating a UrlMap. | ||||
| // It replaces the object with the same key in the mock with the updated object. | ||||
| func UpdateURLMapHook(ctx context.Context, key *meta.Key, obj *ga.UrlMap, m *cloud.MockUrlMaps) error { | ||||
| 	_, err := m.Get(ctx, key) | ||||
| 	if err != nil { | ||||
| 		return &googleapi.Error{ | ||||
| 			Code:    http.StatusNotFound, | ||||
| 			Message: fmt.Sprintf("Key: %s was not found in UrlMaps", key.String()), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	obj.Name = key.Name | ||||
| 	projectID := m.ProjectRouter.ProjectID(ctx, "ga", "urlMaps") | ||||
| 	obj.SelfLink = cloud.SelfLink(meta.VersionGA, projectID, "urlMaps", key) | ||||
|  | ||||
| 	m.Objects[*key] = &cloud.MockUrlMapsObj{Obj: obj} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // InsertFirewallsUnauthorizedErrHook mocks firewall insertion. A forbidden error will be thrown as return. | ||||
| func InsertFirewallsUnauthorizedErrHook(ctx context.Context, key *meta.Key, obj *ga.Firewall, m *cloud.MockFirewalls) (bool, error) { | ||||
| 	return true, &googleapi.Error{Code: http.StatusForbidden} | ||||
| @@ -496,6 +555,16 @@ func DeleteAddressesInternalErrHook(ctx context.Context, key *meta.Key, m *cloud | ||||
| 	return true, InternalServerError | ||||
| } | ||||
|  | ||||
| // InsertAlphaBackendServiceUnauthorizedErrHook mocks inserting an alpha BackendService and returns a forbidden error. | ||||
| func InsertAlphaBackendServiceUnauthorizedErrHook(ctx context.Context, key *meta.Key, obj *alpha.BackendService, m *cloud.MockAlphaBackendServices) (bool, error) { | ||||
| 	return true, UnauthorizedErr | ||||
| } | ||||
|  | ||||
| // UpdateAlphaBackendServiceUnauthorizedErrHook mocks updating an alpha BackendService and returns a forbidden error. | ||||
| func UpdateAlphaBackendServiceUnauthorizedErrHook(ctx context.Context, key *meta.Key, obj *alpha.BackendService, m *cloud.MockAlphaBackendServices) error { | ||||
| 	return UnauthorizedErr | ||||
| } | ||||
|  | ||||
| // GetRegionBackendServicesErrHook mocks getting region backend service and returns an internal server error. | ||||
| func GetRegionBackendServicesErrHook(ctx context.Context, key *meta.Key, m *cloud.MockRegionBackendServices) (bool, *ga.BackendService, error) { | ||||
| 	return true, nil, InternalServerError | ||||
|   | ||||
							
								
								
									
										83
									
								
								pkg/cloudprovider/providers/gce/gce_fake.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								pkg/cloudprovider/providers/gce/gce_fake.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| /* | ||||
| Copyright 2018 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. | ||||
| */ | ||||
|  | ||||
| package gce | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
|  | ||||
| 	compute "google.golang.org/api/compute/v1" | ||||
| 	"k8s.io/client-go/tools/cache" | ||||
| 	"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud" | ||||
| ) | ||||
|  | ||||
| type TestClusterValues struct { | ||||
| 	ProjectID         string | ||||
| 	Region            string | ||||
| 	ZoneName          string | ||||
| 	SecondaryZoneName string | ||||
| 	ClusterID         string | ||||
| 	ClusterName       string | ||||
| } | ||||
|  | ||||
| func DefaultTestClusterValues() TestClusterValues { | ||||
| 	return TestClusterValues{ | ||||
| 		ProjectID:         "test-project", | ||||
| 		Region:            "us-central1", | ||||
| 		ZoneName:          "us-central1-b", | ||||
| 		SecondaryZoneName: "us-central1-c", | ||||
| 		ClusterID:         "test-cluster-id", | ||||
| 		ClusterName:       "Test Cluster Name", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func FakeGCECloud(vals TestClusterValues) *GCECloud { | ||||
| 	return simpleFakeGCECloud(vals) | ||||
| } | ||||
|  | ||||
| type fakeRoundTripper struct{} | ||||
|  | ||||
| func (*fakeRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { | ||||
| 	return nil, fmt.Errorf("err: test used fake http client") | ||||
| } | ||||
|  | ||||
| // Stubs ClusterID so that ClusterID.getOrInitialize() does not require calling | ||||
| // gce.Initialize() | ||||
| func fakeClusterID(clusterID string) ClusterID { | ||||
| 	return ClusterID{ | ||||
| 		clusterID: &clusterID, | ||||
| 		store: cache.NewStore(func(obj interface{}) (string, error) { | ||||
| 			return "", nil | ||||
| 		}), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func simpleFakeGCECloud(vals TestClusterValues) *GCECloud { | ||||
| 	client := &http.Client{Transport: &fakeRoundTripper{}} | ||||
| 	service, _ := compute.New(client) | ||||
| 	gce := &GCECloud{ | ||||
| 		region:           vals.Region, | ||||
| 		service:          service, | ||||
| 		managedZones:     []string{vals.ZoneName}, | ||||
| 		projectID:        vals.ProjectID, | ||||
| 		networkProjectID: vals.ProjectID, | ||||
| 		ClusterID:        fakeClusterID(vals.ClusterID), | ||||
| 	} | ||||
| 	c := cloud.NewMockGCE(&gceProjectRouter{gce}) | ||||
| 	gce.c = c | ||||
| 	return gce | ||||
| } | ||||
| @@ -23,9 +23,7 @@ package gce | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| @@ -35,12 +33,9 @@ import ( | ||||
|  | ||||
| 	"k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/client-go/tools/cache" | ||||
| 	"k8s.io/client-go/tools/record" | ||||
| 	v1_service "k8s.io/kubernetes/pkg/api/v1/service" | ||||
| 	"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud" | ||||
| 	"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta" | ||||
| 	"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/mock" | ||||
| 	kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" | ||||
| ) | ||||
|  | ||||
| @@ -54,26 +49,6 @@ const ( | ||||
| 	errStrUnsupportedTier   = "unsupported network tier: \"" + wrongTier + "\"" | ||||
| ) | ||||
|  | ||||
| type TestClusterValues struct { | ||||
| 	ProjectID         string | ||||
| 	Region            string | ||||
| 	ZoneName          string | ||||
| 	SecondaryZoneName string | ||||
| 	ClusterID         string | ||||
| 	ClusterName       string | ||||
| } | ||||
|  | ||||
| func DefaultTestClusterValues() TestClusterValues { | ||||
| 	return TestClusterValues{ | ||||
| 		ProjectID:         "test-project", | ||||
| 		Region:            "us-central1", | ||||
| 		ZoneName:          "us-central1-b", | ||||
| 		SecondaryZoneName: "us-central1-c", | ||||
| 		ClusterID:         "test-cluster-id", | ||||
| 		ClusterName:       "Test Cluster Name", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func fakeLoadbalancerService(lbType string) *v1.Service { | ||||
| 	return &v1.Service{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| @@ -92,73 +67,6 @@ var ( | ||||
| 	FilewallChangeMsg = fmt.Sprintf("%s %s %s", v1.EventTypeNormal, eventReasonManualChange, eventMsgFirewallChange) | ||||
| ) | ||||
|  | ||||
| type fakeRoundTripper struct{} | ||||
|  | ||||
| func (*fakeRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { | ||||
| 	return nil, fmt.Errorf("err: test used fake http client") | ||||
| } | ||||
|  | ||||
| func fakeGCECloud(vals TestClusterValues) (*GCECloud, error) { | ||||
| 	client := &http.Client{Transport: &fakeRoundTripper{}} | ||||
|  | ||||
| 	service, err := compute.New(client) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// Used in disk unit tests | ||||
| 	fakeManager := newFakeManager(vals.ProjectID, vals.Region) | ||||
| 	zonesWithNodes := createNodeZones([]string{vals.ZoneName}) | ||||
|  | ||||
| 	alphaFeatureGate := NewAlphaFeatureGate([]string{}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	gce := &GCECloud{ | ||||
| 		region:             vals.Region, | ||||
| 		service:            service, | ||||
| 		manager:            fakeManager, | ||||
| 		managedZones:       []string{vals.ZoneName}, | ||||
| 		projectID:          vals.ProjectID, | ||||
| 		networkProjectID:   vals.ProjectID, | ||||
| 		AlphaFeatureGate:   alphaFeatureGate, | ||||
| 		nodeZones:          zonesWithNodes, | ||||
| 		nodeInformerSynced: func() bool { return true }, | ||||
| 		ClusterID:          fakeClusterID(vals.ClusterID), | ||||
| 	} | ||||
|  | ||||
| 	c := cloud.NewMockGCE(&gceProjectRouter{gce}) | ||||
| 	c.MockTargetPools.AddInstanceHook = mock.AddInstanceHook | ||||
| 	c.MockTargetPools.RemoveInstanceHook = mock.RemoveInstanceHook | ||||
| 	c.MockForwardingRules.InsertHook = mock.InsertFwdRuleHook | ||||
| 	c.MockAddresses.InsertHook = mock.InsertAddressHook | ||||
| 	c.MockAlphaAddresses.InsertHook = mock.InsertAlphaAddressHook | ||||
| 	c.MockAlphaAddresses.X = mock.AddressAttributes{} | ||||
| 	c.MockAddresses.X = mock.AddressAttributes{} | ||||
|  | ||||
| 	c.MockInstanceGroups.X = mock.InstanceGroupAttributes{ | ||||
| 		InstanceMap: make(map[meta.Key]map[string]*compute.InstanceWithNamedPorts), | ||||
| 		Lock:        &sync.Mutex{}, | ||||
| 	} | ||||
| 	c.MockInstanceGroups.AddInstancesHook = mock.AddInstancesHook | ||||
| 	c.MockInstanceGroups.RemoveInstancesHook = mock.RemoveInstancesHook | ||||
| 	c.MockInstanceGroups.ListInstancesHook = mock.ListInstancesHook | ||||
|  | ||||
| 	c.MockRegionBackendServices.UpdateHook = mock.UpdateRegionBackendServiceHook | ||||
| 	c.MockHealthChecks.UpdateHook = mock.UpdateHealthCheckHook | ||||
| 	c.MockFirewalls.UpdateHook = mock.UpdateFirewallHook | ||||
|  | ||||
| 	keyGA := meta.GlobalKey("key-ga") | ||||
| 	c.MockZones.Objects[*keyGA] = &cloud.MockZonesObj{ | ||||
| 		Obj: &compute.Zone{Name: vals.ZoneName, Region: gce.getRegionLink(vals.Region)}, | ||||
| 	} | ||||
|  | ||||
| 	gce.c = c | ||||
|  | ||||
| 	return gce, nil | ||||
| } | ||||
|  | ||||
| func createAndInsertNodes(gce *GCECloud, nodeNames []string, zoneName string) ([]*v1.Node, error) { | ||||
| 	nodes := []*v1.Node{} | ||||
|  | ||||
| @@ -208,17 +116,6 @@ func createAndInsertNodes(gce *GCECloud, nodeNames []string, zoneName string) ([ | ||||
| 	return nodes, nil | ||||
| } | ||||
|  | ||||
| // Stubs ClusterID so that ClusterID.getOrInitialize() does not require calling | ||||
| // gce.Initialize() | ||||
| func fakeClusterID(clusterID string) ClusterID { | ||||
| 	return ClusterID{ | ||||
| 		clusterID: &clusterID, | ||||
| 		store: cache.NewStore(func(obj interface{}) (string, error) { | ||||
| 			return "", nil | ||||
| 		}), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func assertExternalLbResources(t *testing.T, gce *GCECloud, apiService *v1.Service, vals TestClusterValues, nodeNames []string) { | ||||
| 	lbName := gce.GetLoadBalancerName(context.TODO(), "", apiService) | ||||
| 	hcName := MakeNodesHealthCheckName(vals.ClusterID) | ||||
|   | ||||
| @@ -24,17 +24,55 @@ import ( | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"k8s.io/api/core/v1" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| 	"k8s.io/apimachinery/pkg/util/sets" | ||||
| 	"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud" | ||||
| 	"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta" | ||||
| 	"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/mock" | ||||
|  | ||||
| 	"cloud.google.com/go/compute/metadata" | ||||
| 	compute "google.golang.org/api/compute/v1" | ||||
| 	"google.golang.org/api/googleapi" | ||||
| ) | ||||
|  | ||||
| func fakeGCECloud(vals TestClusterValues) (*GCECloud, error) { | ||||
| 	gce := simpleFakeGCECloud(vals) | ||||
|  | ||||
| 	gce.AlphaFeatureGate = NewAlphaFeatureGate([]string{}) | ||||
| 	gce.nodeInformerSynced = func() bool { return true } | ||||
|  | ||||
| 	mockGCE := gce.c.(*cloud.MockGCE) | ||||
| 	mockGCE.MockTargetPools.AddInstanceHook = mock.AddInstanceHook | ||||
| 	mockGCE.MockTargetPools.RemoveInstanceHook = mock.RemoveInstanceHook | ||||
| 	mockGCE.MockForwardingRules.InsertHook = mock.InsertFwdRuleHook | ||||
| 	mockGCE.MockAddresses.InsertHook = mock.InsertAddressHook | ||||
| 	mockGCE.MockAlphaAddresses.InsertHook = mock.InsertAlphaAddressHook | ||||
| 	mockGCE.MockAlphaAddresses.X = mock.AddressAttributes{} | ||||
| 	mockGCE.MockAddresses.X = mock.AddressAttributes{} | ||||
|  | ||||
| 	mockGCE.MockInstanceGroups.X = mock.InstanceGroupAttributes{ | ||||
| 		InstanceMap: make(map[meta.Key]map[string]*compute.InstanceWithNamedPorts), | ||||
| 		Lock:        &sync.Mutex{}, | ||||
| 	} | ||||
| 	mockGCE.MockInstanceGroups.AddInstancesHook = mock.AddInstancesHook | ||||
| 	mockGCE.MockInstanceGroups.RemoveInstancesHook = mock.RemoveInstancesHook | ||||
| 	mockGCE.MockInstanceGroups.ListInstancesHook = mock.ListInstancesHook | ||||
|  | ||||
| 	mockGCE.MockRegionBackendServices.UpdateHook = mock.UpdateRegionBackendServiceHook | ||||
| 	mockGCE.MockHealthChecks.UpdateHook = mock.UpdateHealthCheckHook | ||||
| 	mockGCE.MockFirewalls.UpdateHook = mock.UpdateFirewallHook | ||||
|  | ||||
| 	keyGA := meta.GlobalKey("key-ga") | ||||
| 	mockGCE.MockZones.Objects[*keyGA] = &cloud.MockZonesObj{ | ||||
| 		Obj: &compute.Zone{Name: vals.ZoneName, Region: gce.getRegionLink(vals.Region)}, | ||||
| 	} | ||||
|  | ||||
| 	return gce, nil | ||||
| } | ||||
|  | ||||
| type gceInstance struct { | ||||
| 	Zone  string | ||||
| 	Name  string | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 k8s-ci-robot
					k8s-ci-robot