mirror of https://github.com/kubernetes/kops.git
				
				
				
			
		
			
				
	
	
		
			212 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			212 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"
 | 
						|
 | 
						|
	inCluster.Spec.Networking.Topology.ControlPlane = kopsapi.TopologyPrivate
 | 
						|
	inCluster.Spec.Networking.Topology.Nodes = kopsapi.TopologyPrivate
 | 
						|
 | 
						|
	err := cloudup.PerformAssignments(inCluster, mockcloud)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("Failed to perform assignments: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	assetBuilder := assets.NewAssetBuilder(inCluster.Spec.Assets, inCluster.Spec.KubernetesVersion, false)
 | 
						|
	basePath, _ := vfs.Context.BuildVfsPath(inCluster.Spec.ConfigBase)
 | 
						|
	clientset := vfsclientset.NewVFSClientset(basePath)
 | 
						|
	cluster, err := cloudup.PopulateClusterSpec(ctx, clientset, inCluster, 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)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |