diff --git a/pkg/cloudprovider/providers/gce/BUILD b/pkg/cloudprovider/providers/gce/BUILD index 034e4a4a895..9634a21b5e9 100644 --- a/pkg/cloudprovider/providers/gce/BUILD +++ b/pkg/cloudprovider/providers/gce/BUILD @@ -106,6 +106,7 @@ go_test( importpath = "k8s.io/kubernetes/pkg/cloudprovider/providers/gce", deps = [ "//pkg/cloudprovider:go_default_library", + "//pkg/cloudprovider/providers/gce/cloud:go_default_library", "//pkg/kubelet/apis:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/stretchr/testify/require:go_default_library", diff --git a/pkg/cloudprovider/providers/gce/cloud/BUILD b/pkg/cloudprovider/providers/gce/cloud/BUILD index 3df8f7a5e97..6ff7c13d8e5 100644 --- a/pkg/cloudprovider/providers/gce/cloud/BUILD +++ b/pkg/cloudprovider/providers/gce/cloud/BUILD @@ -57,6 +57,7 @@ filegroup( "//pkg/cloudprovider/providers/gce/cloud/filter:all-srcs", "//pkg/cloudprovider/providers/gce/cloud/gen:all-srcs", "//pkg/cloudprovider/providers/gce/cloud/meta:all-srcs", + "//pkg/cloudprovider/providers/gce/cloud/mock:all-srcs", ], tags = ["automanaged"], visibility = ["//visibility:public"], diff --git a/pkg/cloudprovider/providers/gce/cloud/mock/BUILD b/pkg/cloudprovider/providers/gce/cloud/mock/BUILD new file mode 100644 index 00000000000..50a9026dc06 --- /dev/null +++ b/pkg/cloudprovider/providers/gce/cloud/mock/BUILD @@ -0,0 +1,26 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["mock.go"], + importpath = "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/mock", + visibility = ["//visibility:public"], + deps = [ + "//pkg/cloudprovider/providers/gce/cloud:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/pkg/cloudprovider/providers/gce/cloud/mock/mock.go b/pkg/cloudprovider/providers/gce/cloud/mock/mock.go new file mode 100644 index 00000000000..d681149287d --- /dev/null +++ b/pkg/cloudprovider/providers/gce/cloud/mock/mock.go @@ -0,0 +1,52 @@ +/* +Copyright 2017 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 mock encapsulates mocks for testing GCE provider functionality. +// These methods are used to override the mock objects' methods in order to +// intercept the standard processing and to add custom logic for test purposes. +// +// // Example usage: +// cloud := cloud.NewMockGCE() +// cloud.MockTargetPools.AddInstanceHook = mock.AddInstanceHook + +package mock + +import ( + "context" + "fmt" + "net/http" + + ga "google.golang.org/api/compute/v1" + "google.golang.org/api/googleapi" + cloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud" + "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta" +) + +func AddInstanceHook(m *cloud.MockTargetPools, ctx context.Context, key *meta.Key, req *ga.TargetPoolsAddInstanceRequest) error { + pool, err := m.Get(ctx, key) + if err != nil { + return &googleapi.Error{ + Code: http.StatusNotFound, + Message: fmt.Sprintf("Key: %s was not found in TargetPools", key.String()), + } + } + + for _, instance := range req.Instances { + pool.Instances = append(pool.Instances, instance.Instance) + } + + return nil +} diff --git a/pkg/cloudprovider/providers/gce/gce_loadbalancer_external_test.go b/pkg/cloudprovider/providers/gce/gce_loadbalancer_external_test.go index e6643e706ac..365333bd65b 100644 --- a/pkg/cloudprovider/providers/gce/gce_loadbalancer_external_test.go +++ b/pkg/cloudprovider/providers/gce/gce_loadbalancer_external_test.go @@ -29,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/cloudprovider" "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud" + "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/mock" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" ) @@ -258,22 +259,6 @@ var apiService = &v1.Service{ }, } -var nodes = []*v1.Node{ - &v1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: nodeName, - Labels: map[string]string{ - kubeletapis.LabelHostname: nodeName, - }, - }, - Status: v1.NodeStatus{ - NodeInfo: v1.NodeSystemInfo{ - KubeProxyVersion: "v1.7.2", - }, - }, - }, -} - func fakeGCECloud() (*GCECloud, error) { client, err := newOauthClient(nil) if err != nil { @@ -293,6 +278,7 @@ func fakeGCECloud() (*GCECloud, error) { } cloud := cloud.NewMockGCE() + cloud.MockTargetPools.AddInstanceHook = mock.AddInstanceHook zonesWithNodes := createNodeZones([]string{zone}) gce := GCECloud{ @@ -307,7 +293,11 @@ func fakeGCECloud() (*GCECloud, error) { c: cloud, } - gce.InsertInstance( + return &gce, nil +} + +func createExternalLoadBalancer(gce *GCECloud) (*v1.LoadBalancerStatus, error) { + err := gce.InsertInstance( gceProjectId, zone, &compute.Instance{ @@ -318,10 +308,26 @@ func fakeGCECloud() (*GCECloud, error) { }, ) - return &gce, nil -} + if err != nil { + return nil, err + } + + nodes := []*v1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: nodeName, + Labels: map[string]string{ + kubeletapis.LabelHostname: nodeName, + }, + }, + Status: v1.NodeStatus{ + NodeInfo: v1.NodeSystemInfo{ + KubeProxyVersion: "v1.7.2", + }, + }, + }, + } -func createExternalLoadBalancer(gce *GCECloud) (*v1.LoadBalancerStatus, error) { status, err := gce.ensureExternalLoadBalancer( clusterName, clusterID, @@ -354,7 +360,7 @@ func TestEnsureExternalLoadBalancer(t *testing.T) { require.NoError(t, err) assert.Equal(t, lbName, pool.Name) assert.NotEmpty(t, pool.HealthChecks) - assert.NotEmpty(t, pool.Instances) + assert.Equal(t, 1, len(pool.Instances)) // Check that HealthCheck is created hcName := MakeNodesHealthCheckName(clusterID) @@ -375,8 +381,64 @@ func TestUpdateExternalLoadBalancer(t *testing.T) { require.NoError(t, err) createExternalLoadBalancer(gce) - err = gce.updateExternalLoadBalancer(clusterName, apiService, nodes) + newNodeName := "test-node-2" + gce.InsertInstance( + gceProjectId, + zone, + &compute.Instance{ + Name: newNodeName, + Tags: &compute.Tags{ + Items: []string{newNodeName}, + }, + }, + ) + + newNodes := []*v1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: nodeName, + Labels: map[string]string{ + kubeletapis.LabelHostname: nodeName, + }, + }, + Status: v1.NodeStatus{ + NodeInfo: v1.NodeSystemInfo{ + KubeProxyVersion: "v1.7.2", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: newNodeName, + Labels: map[string]string{ + kubeletapis.LabelHostname: newNodeName, + }, + }, + Status: v1.NodeStatus{ + NodeInfo: v1.NodeSystemInfo{ + KubeProxyVersion: "v1.7.2", + }, + }, + }, + } + + err = gce.updateExternalLoadBalancer(clusterName, apiService, newNodes) assert.NoError(t, err) + + lbName := cloudprovider.GetLoadBalancerName(apiService) + + // Check that TargetPool is updated with the new node + pool, err := gce.GetTargetPool(lbName, gceRegion) + require.NoError(t, err) + + assert.Equal( + t, + []string{ + fmt.Sprintf("/zones/%s/instances/%s", zone, nodeName), + fmt.Sprintf("/zones/%s/instances/%s", zone, newNodeName), + }, + pool.Instances, + ) } func TestEnsureExternalLoadBalancerDeleted(t *testing.T) {