mirror of https://github.com/kubernetes/kops.git
				
				
				
			
		
			
				
	
	
		
			209 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			209 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
| Copyright 2020 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 instancegroups
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups"
 | |
| 	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
 | |
| 	"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| 	v1 "k8s.io/api/core/v1"
 | |
| 	v1meta "k8s.io/apimachinery/pkg/apis/meta/v1"
 | |
| 	"k8s.io/client-go/kubernetes/fake"
 | |
| 	kopsapi "k8s.io/kops/pkg/apis/kops"
 | |
| 	"k8s.io/kops/pkg/assets"
 | |
| 	"k8s.io/kops/pkg/client/simple/vfsclientset"
 | |
| 	"k8s.io/kops/pkg/cloudinstances"
 | |
| 	"k8s.io/kops/pkg/testutils"
 | |
| 	"k8s.io/kops/upup/pkg/fi/cloudup"
 | |
| 	"k8s.io/kops/upup/pkg/fi/cloudup/openstack"
 | |
| 	"k8s.io/kops/util/pkg/vfs"
 | |
| )
 | |
| 
 | |
| func getTestSetupOS(t *testing.T, ctx context.Context) (*RollingUpdateCluster, *openstack.MockCloud) {
 | |
| 	vfs.Context.ResetMemfsContext(true)
 | |
| 
 | |
| 	k8sClient := fake.NewSimpleClientset()
 | |
| 
 | |
| 	mockcloud := testutils.SetupMockOpenstack()
 | |
| 
 | |
| 	inCluster := testutils.BuildMinimalCluster("test.k8s.local")
 | |
| 
 | |
| 	inCluster.Spec.CloudProvider.Openstack = &kopsapi.OpenstackSpec{}
 | |
| 	inCluster.Name = "test.k8s.local"
 | |
| 
 | |
| 	err := cloudup.PerformAssignments(inCluster, vfs.Context, mockcloud)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to perform assignments: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	assetBuilder := assets.NewAssetBuilder(vfs.Context, inCluster.Spec.Assets, inCluster.Spec.KubernetesVersion, false)
 | |
| 	basePath, _ := vfs.Context.BuildVfsPath(inCluster.Spec.ConfigStore.Base)
 | |
| 	clientset := vfsclientset.NewVFSClientset(vfs.Context, basePath)
 | |
| 	cluster, err := cloudup.PopulateClusterSpec(ctx, clientset, inCluster, nil, mockcloud, assetBuilder)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to populate cluster spec: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	sshPublicKey := []byte("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF2sghZsClUBXJB4mBMIw8rb0hJWjg1Vz4eUeXwYmTdi92Gf1zNc5xISSip9Y+PWX/jJokPB7tgPnMD/2JOAKhG1bi4ZqB15pYRmbbBekVpM4o4E0dx+czbqjiAm6wlccTrINK5LYenbucAAQt19eH+D0gJwzYUK9SYz1hWnlGS+qurt2bz7rrsG73lN8E2eiNvGtIXqv3GabW/Hea3acOBgCUJQWUDTRu0OmmwxzKbFN/UpNKeRaHlCqwZWjVAsmqA8TX8LIocq7Np7MmIBwt7EpEeZJxThcmC8DEJs9ClAjD+jlLIvMPXKC3JWCPgwCLGxHjy7ckSGFCSzbyPduh")
 | |
| 	sshCredentialStore, err := clientset.SSHCredentialStore(cluster)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to get credential store: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	sshCredentialStore.AddSSHPublicKey(ctx, sshPublicKey)
 | |
| 
 | |
| 	c := &RollingUpdateCluster{
 | |
| 		Cloud:                   mockcloud,
 | |
| 		MasterInterval:          1 * time.Millisecond,
 | |
| 		NodeInterval:            1 * time.Millisecond,
 | |
| 		BastionInterval:         1 * time.Millisecond,
 | |
| 		Force:                   false,
 | |
| 		K8sClient:               k8sClient,
 | |
| 		ClusterValidator:        &successfulClusterValidator{},
 | |
| 		FailOnValidate:          true,
 | |
| 		ValidateTickDuration:    1 * time.Millisecond,
 | |
| 		ValidateSuccessDuration: 5 * time.Millisecond,
 | |
| 		ValidateCount:           2,
 | |
| 		Ctx:                     ctx,
 | |
| 		Cluster:                 cluster,
 | |
| 		Clientset:               clientset,
 | |
| 	}
 | |
| 
 | |
| 	return c, mockcloud
 | |
| }
 | |
| 
 | |
| // Ref: https://github.com/dominikh/go-tools/issues/633#issuecomment-606560616
 | |
| var TempTestSkip = func(t *testing.T, message string) {
 | |
| 	t.Skip(message)
 | |
| }
 | |
| 
 | |
| func TestRollingUpdateDisabledSurgeOS(t *testing.T) {
 | |
| 	ctx := context.TODO()
 | |
| 
 | |
| 	TempTestSkip(t, "Failing in new release PR when build is not yet published")
 | |
| 
 | |
| 	t.Setenv("OS_REGION_NAME", "us-test1")
 | |
| 
 | |
| 	c, cloud := getTestSetupOS(t, ctx)
 | |
| 
 | |
| 	groups, igList := getGroupsAllNeedUpdateOS(t, c)
 | |
| 	err := c.RollingUpdate(groups, igList)
 | |
| 	assert.NoError(t, err, "rolling update")
 | |
| 
 | |
| 	assertGroupInstanceCountOS(t, cloud, "node-1", 3)
 | |
| 	assertGroupInstanceCountOS(t, cloud, "node-2", 3)
 | |
| 	assertGroupInstanceCountOS(t, cloud, "master-1", 2)
 | |
| 	assertGroupInstanceCountOS(t, cloud, "bastion-1", 1)
 | |
| }
 | |
| 
 | |
| func makeGroupOS(t *testing.T, groups map[string]*cloudinstances.CloudInstanceGroup, igList *kopsapi.InstanceGroupList,
 | |
| 	c *RollingUpdateCluster, subnet string, role kopsapi.InstanceGroupRole, count int, needUpdate int) {
 | |
| 	cloud := c.Cloud.(*openstack.MockCloud)
 | |
| 	igif := c.Clientset.InstanceGroupsFor(c.Cluster)
 | |
| 	fakeClient := c.K8sClient.(*fake.Clientset)
 | |
| 
 | |
| 	var newIg kopsapi.InstanceGroup
 | |
| 	switch role {
 | |
| 	case kopsapi.InstanceGroupRoleNode:
 | |
| 		newIg = testutils.BuildMinimalNodeInstanceGroup("nodes-"+subnet, subnet)
 | |
| 	case kopsapi.InstanceGroupRoleControlPlane:
 | |
| 		newIg = testutils.BuildMinimalMasterInstanceGroup(subnet)
 | |
| 	case kopsapi.InstanceGroupRoleBastion:
 | |
| 		newIg = testutils.BuildMinimalBastionInstanceGroup("bastion-"+subnet, subnet)
 | |
| 	}
 | |
| 
 | |
| 	newIg.Spec.MachineType = "n1-standard-2"
 | |
| 	newIg.Spec.Image = "Ubuntu-20.04"
 | |
| 
 | |
| 	igList.Items = append(igList.Items, newIg)
 | |
| 
 | |
| 	ig, err := igif.Create(c.Ctx, &newIg, v1meta.CreateOptions{})
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create ig %v: %v", subnet, err)
 | |
| 	}
 | |
| 
 | |
| 	groups[subnet] = &cloudinstances.CloudInstanceGroup{
 | |
| 		HumanName:     ig.ObjectMeta.Name,
 | |
| 		InstanceGroup: ig,
 | |
| 	}
 | |
| 	for i := 0; i < count; i++ {
 | |
| 		name := subnet + string(rune('a'+i))
 | |
| 		port, err := cloud.CreatePort(ports.CreateOpts{
 | |
| 			Name:      name,
 | |
| 			NetworkID: "test",
 | |
| 		})
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to make port: %v", err)
 | |
| 		}
 | |
| 		server, err := cloud.CreateInstance(servers.CreateOpts{
 | |
| 			Name: name,
 | |
| 			Networks: []servers.Network{
 | |
| 				{
 | |
| 					Port: port.ID,
 | |
| 				},
 | |
| 			},
 | |
| 		}, "")
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to make group: %v", err)
 | |
| 		}
 | |
| 		id := server.ID
 | |
| 		var node *v1.Node
 | |
| 		if role != kopsapi.InstanceGroupRoleBastion {
 | |
| 			node = &v1.Node{
 | |
| 				ObjectMeta: v1meta.ObjectMeta{Name: id + ".local"},
 | |
| 			}
 | |
| 			_ = fakeClient.Tracker().Add(node)
 | |
| 		}
 | |
| 		member := cloudinstances.CloudInstance{
 | |
| 			ID:                 id,
 | |
| 			Node:               node,
 | |
| 			CloudInstanceGroup: groups[subnet],
 | |
| 		}
 | |
| 		if i < needUpdate {
 | |
| 			groups[subnet].NeedUpdate = append(groups[subnet].NeedUpdate, &member)
 | |
| 		} else {
 | |
| 			groups[subnet].Ready = append(groups[subnet].Ready, &member)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func getGroupsAllNeedUpdateOS(t *testing.T, c *RollingUpdateCluster) (map[string]*cloudinstances.CloudInstanceGroup, *kopsapi.InstanceGroupList) {
 | |
| 	groups := make(map[string]*cloudinstances.CloudInstanceGroup)
 | |
| 	igList := &kopsapi.InstanceGroupList{}
 | |
| 	makeGroupOS(t, groups, igList, c, c.Cluster.Spec.Networking.Subnets[0].Name, kopsapi.InstanceGroupRoleNode, 3, 3)
 | |
| 	makeGroupOS(t, groups, igList, c, c.Cluster.Spec.Networking.Subnets[1].Name, kopsapi.InstanceGroupRoleNode, 3, 3)
 | |
| 	makeGroupOS(t, groups, igList, c, c.Cluster.Spec.Networking.Subnets[0].Name, kopsapi.InstanceGroupRoleControlPlane, 1, 1)
 | |
| 	makeGroupOS(t, groups, igList, c, c.Cluster.Spec.Networking.Subnets[1].Name, kopsapi.InstanceGroupRoleControlPlane, 1, 1)
 | |
| 	makeGroupOS(t, groups, igList, c, c.Cluster.Spec.Networking.Subnets[2].Name, kopsapi.InstanceGroupRoleControlPlane, 1, 1)
 | |
| 	makeGroupOS(t, groups, igList, c, c.Cluster.Spec.Networking.Subnets[0].Name, kopsapi.InstanceGroupRoleBastion, 1, 1)
 | |
| 	return groups, igList
 | |
| }
 | |
| 
 | |
| func assertGroupInstanceCountOS(t *testing.T, cloud *openstack.MockCloud, groupName string, expected int) {
 | |
| 	groups, _ := cloud.ListServerGroups(servergroups.ListOpts{})
 | |
| 	for _, g := range groups {
 | |
| 		if g.Name == groupName {
 | |
| 			assert.Lenf(t, g.Members, expected, "%s instances", groupName)
 | |
| 		}
 | |
| 	}
 | |
| }
 |