mirror of https://github.com/kubernetes/kops.git
				
				
				
			
		
			
				
	
	
		
			373 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			373 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
| 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 testutils
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"os"
 | |
| 	"path"
 | |
| 	"path/filepath"
 | |
| 	"testing"
 | |
| 
 | |
| 	"google.golang.org/api/compute/v1"
 | |
| 	"k8s.io/kops/cloudmock/aws/mockeventbridge"
 | |
| 	"k8s.io/kops/cloudmock/aws/mocksqs"
 | |
| 
 | |
| 	"github.com/aws/aws-sdk-go-v2/aws"
 | |
| 	"github.com/aws/aws-sdk-go-v2/service/ec2"
 | |
| 	ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
 | |
| 	elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
 | |
| 	"github.com/aws/aws-sdk-go-v2/service/iam"
 | |
| 	route53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
 | |
| 	"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors"
 | |
| 	"github.com/gophercloud/gophercloud/v2/openstack/dns/v2/zones"
 | |
| 	"github.com/gophercloud/gophercloud/v2/openstack/image/v2/images"
 | |
| 	"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/external"
 | |
| 	"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks"
 | |
| 	"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets"
 | |
| 	"k8s.io/klog/v2"
 | |
| 	kopsroot "k8s.io/kops"
 | |
| 	"k8s.io/kops/cloudmock/aws/mockautoscaling"
 | |
| 	"k8s.io/kops/cloudmock/aws/mockec2"
 | |
| 	"k8s.io/kops/cloudmock/aws/mockelb"
 | |
| 	"k8s.io/kops/cloudmock/aws/mockelbv2"
 | |
| 	"k8s.io/kops/cloudmock/aws/mockiam"
 | |
| 	"k8s.io/kops/cloudmock/aws/mockroute53"
 | |
| 	gcemock "k8s.io/kops/cloudmock/gce"
 | |
| 	"k8s.io/kops/cloudmock/openstack/mockblockstorage"
 | |
| 	"k8s.io/kops/cloudmock/openstack/mockcompute"
 | |
| 	"k8s.io/kops/cloudmock/openstack/mockdns"
 | |
| 	"k8s.io/kops/cloudmock/openstack/mockimage"
 | |
| 	"k8s.io/kops/cloudmock/openstack/mockloadbalancer"
 | |
| 	"k8s.io/kops/cloudmock/openstack/mocknetworking"
 | |
| 	"k8s.io/kops/pkg/apis/kops"
 | |
| 	"k8s.io/kops/pkg/featureflag"
 | |
| 	"k8s.io/kops/pkg/pki"
 | |
| 	"k8s.io/kops/upup/pkg/fi"
 | |
| 	"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
 | |
| 	"k8s.io/kops/upup/pkg/fi/cloudup/openstack"
 | |
| 	"k8s.io/kops/util/pkg/vfs"
 | |
| )
 | |
| 
 | |
| type IntegrationTestHarness struct {
 | |
| 	TempDir string
 | |
| 	T       *testing.T
 | |
| 
 | |
| 	// The original kops DefaultChannelBase value, restored on Close
 | |
| 	originalDefaultChannelBase string
 | |
| 
 | |
| 	// originalKopsVersion is the original kops.Version value, restored on Close
 | |
| 	originalKopsVersion string
 | |
| 
 | |
| 	// originalPKIDefaultPrivateKeySize is the saved pki.DefaultPrivateKeySize value, restored on Close
 | |
| 	originalPKIDefaultPrivateKeySize int
 | |
| }
 | |
| 
 | |
| func NewIntegrationTestHarness(t *testing.T) *IntegrationTestHarness {
 | |
| 	featureflag.ParseFlags("-ImageDigest")
 | |
| 	h := &IntegrationTestHarness{T: t}
 | |
| 	tempDir, err := os.MkdirTemp("", "test")
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("failed to create temp dir: %v", err)
 | |
| 	}
 | |
| 	h.TempDir = tempDir
 | |
| 
 | |
| 	vfs.Context.ResetMemfsContext(true)
 | |
| 
 | |
| 	// Generate much smaller keys, as this is often the bottleneck for tests
 | |
| 	h.originalPKIDefaultPrivateKeySize = pki.DefaultPrivateKeySize
 | |
| 	pki.DefaultPrivateKeySize = 1024
 | |
| 
 | |
| 	// Replace the default channel path with a local filesystem path, so we don't try to retrieve it from a server
 | |
| 	{
 | |
| 		channelPath, err := filepath.Abs(path.Join("../../channels/"))
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("error resolving stable channel path: %v", err)
 | |
| 		}
 | |
| 		channelPath += "/"
 | |
| 		h.originalDefaultChannelBase = kops.DefaultChannelBase
 | |
| 
 | |
| 		// Make sure any platform-specific separators that aren't /, are converted to / for use in a file: protocol URL
 | |
| 		kops.DefaultChannelBase = "file://" + filepath.ToSlash(channelPath)
 | |
| 	}
 | |
| 
 | |
| 	return h
 | |
| }
 | |
| 
 | |
| func (h *IntegrationTestHarness) Close() {
 | |
| 	if h.TempDir != "" {
 | |
| 		if os.Getenv("KEEP_TEMP_DIR") != "" {
 | |
| 			klog.Infof("NOT removing temp directory, because KEEP_TEMP_DIR is set: %s", h.TempDir)
 | |
| 		} else {
 | |
| 			err := os.RemoveAll(h.TempDir)
 | |
| 			if err != nil {
 | |
| 				h.T.Fatalf("failed to remove temp dir %q: %v", h.TempDir, err)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if h.originalKopsVersion != "" {
 | |
| 		kopsroot.Version = h.originalKopsVersion
 | |
| 	}
 | |
| 
 | |
| 	if h.originalDefaultChannelBase != "" {
 | |
| 		kops.DefaultChannelBase = h.originalDefaultChannelBase
 | |
| 	}
 | |
| 
 | |
| 	if h.originalPKIDefaultPrivateKeySize != 0 {
 | |
| 		pki.DefaultPrivateKeySize = h.originalPKIDefaultPrivateKeySize
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (h *IntegrationTestHarness) SetupMockAWS() *awsup.MockAWSCloud {
 | |
| 	ctx := context.TODO()
 | |
| 	cloud := awsup.InstallMockAWSCloud("us-test-1", "abc")
 | |
| 	mockEC2 := &mockec2.MockEC2{}
 | |
| 	cloud.MockEC2 = mockEC2
 | |
| 	mockRoute53 := &mockroute53.MockRoute53{}
 | |
| 	cloud.MockRoute53 = mockRoute53
 | |
| 	mockELB := &mockelb.MockELB{}
 | |
| 	cloud.MockELB = mockELB
 | |
| 	mockELBV2 := &mockelbv2.MockELBV2{EC2: mockEC2}
 | |
| 	cloud.MockELBV2 = mockELBV2
 | |
| 	mockIAM := &mockiam.MockIAM{}
 | |
| 	cloud.MockIAM = mockIAM
 | |
| 	mockAutoscaling := &mockautoscaling.MockAutoscaling{}
 | |
| 	cloud.MockAutoscaling = mockAutoscaling
 | |
| 	mockSQS := &mocksqs.MockSQS{}
 | |
| 	cloud.MockSQS = mockSQS
 | |
| 	mockEventBridge := &mockeventbridge.MockEventBridge{}
 | |
| 	cloud.MockEventBridge = mockEventBridge
 | |
| 
 | |
| 	mockRoute53.MockCreateZone(&route53types.HostedZone{
 | |
| 		Id:   aws.String("/hostedzone/Z1AFAKE1ZON3YO"),
 | |
| 		Name: aws.String("example.com."),
 | |
| 		Config: &route53types.HostedZoneConfig{
 | |
| 			PrivateZone: false,
 | |
| 		},
 | |
| 	}, nil)
 | |
| 	mockRoute53.MockCreateZone(&route53types.HostedZone{
 | |
| 		Id:   aws.String("/hostedzone/Z2AFAKE1ZON3NO"),
 | |
| 		Name: aws.String("internal.example.com."),
 | |
| 		Config: &route53types.HostedZoneConfig{
 | |
| 			PrivateZone: true,
 | |
| 		},
 | |
| 	}, []*route53types.VPC{{
 | |
| 		VPCId: aws.String("vpc-23456789"),
 | |
| 	}})
 | |
| 	mockRoute53.MockCreateZone(&route53types.HostedZone{
 | |
| 		Id:   aws.String("/hostedzone/Z3AFAKE1ZOMORE"),
 | |
| 		Name: aws.String("private.example.com."),
 | |
| 		Config: &route53types.HostedZoneConfig{
 | |
| 			PrivateZone: true,
 | |
| 		},
 | |
| 	}, []*route53types.VPC{{
 | |
| 		VPCId: aws.String("vpc-12345678"),
 | |
| 	}})
 | |
| 
 | |
| 	mockEC2.Images = append(mockEC2.Images, &ec2types.Image{
 | |
| 		CreationDate:   aws.String("2022-04-04T00:00:00.000Z"),
 | |
| 		ImageId:        aws.String("ami-12345678"),
 | |
| 		Name:           aws.String("images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20220404"),
 | |
| 		OwnerId:        aws.String(awsup.WellKnownAccountUbuntu),
 | |
| 		RootDeviceName: aws.String("/dev/xvda"),
 | |
| 		Architecture:   ec2types.ArchitectureValuesX8664,
 | |
| 	})
 | |
| 
 | |
| 	mockEC2.CreateVpcWithId(&ec2.CreateVpcInput{
 | |
| 		CidrBlock: aws.String("172.20.0.0/16"),
 | |
| 		TagSpecifications: []ec2types.TagSpecification{
 | |
| 			{
 | |
| 				ResourceType: ec2types.ResourceTypeVpc,
 | |
| 				Tags: []ec2types.Tag{
 | |
| 					{
 | |
| 						Key:   aws.String("kubernetes.io/cluster/minimal.example.com"),
 | |
| 						Value: aws.String(""),
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}, "vpc-12345678")
 | |
| 	mockEC2.CreateInternetGateway(ctx, &ec2.CreateInternetGatewayInput{})
 | |
| 	mockEC2.AttachInternetGateway(ctx, &ec2.AttachInternetGatewayInput{
 | |
| 		InternetGatewayId: aws.String("igw-1"),
 | |
| 		VpcId:             aws.String("vpc-12345678"),
 | |
| 	})
 | |
| 	mockEC2.CreateEgressOnlyInternetGateway(ctx, &ec2.CreateEgressOnlyInternetGatewayInput{
 | |
| 		VpcId: aws.String("vpc-12345678"),
 | |
| 	})
 | |
| 
 | |
| 	mockEC2.CreateRouteTableWithId(&ec2.CreateRouteTableInput{
 | |
| 		VpcId: aws.String("vpc-12345678"),
 | |
| 	}, "rtb-12345678")
 | |
| 
 | |
| 	mockEC2.CreateSubnetWithId(&ec2.CreateSubnetInput{
 | |
| 		VpcId:            aws.String("vpc-12345678"),
 | |
| 		AvailabilityZone: aws.String("us-test-1a"),
 | |
| 		CidrBlock:        aws.String("172.20.32.0/19"),
 | |
| 	}, "subnet-12345678")
 | |
| 	mockEC2.AssociateRouteTable(ctx, &ec2.AssociateRouteTableInput{
 | |
| 		RouteTableId: aws.String("rtb-12345678"),
 | |
| 		SubnetId:     aws.String("subnet-12345678"),
 | |
| 	})
 | |
| 	mockEC2.CreateSubnetWithId(&ec2.CreateSubnetInput{
 | |
| 		VpcId:            aws.String("vpc-12345678"),
 | |
| 		AvailabilityZone: aws.String("us-test-1a"),
 | |
| 		CidrBlock:        aws.String("172.20.4.0/22"),
 | |
| 	}, "subnet-abcdef")
 | |
| 	mockEC2.CreateSubnetWithId(&ec2.CreateSubnetInput{
 | |
| 		VpcId:            aws.String("vpc-12345678"),
 | |
| 		AvailabilityZone: aws.String("us-test-1b"),
 | |
| 		CidrBlock:        aws.String("172.20.8.0/22"),
 | |
| 	}, "subnet-b2345678")
 | |
| 
 | |
| 	mockEC2.AssociateRouteTable(ctx, &ec2.AssociateRouteTableInput{
 | |
| 		RouteTableId: aws.String("rtb-12345678"),
 | |
| 		SubnetId:     aws.String("subnet-abcdef"),
 | |
| 	})
 | |
| 
 | |
| 	mockEC2.AllocateAddressWithId(&ec2.AllocateAddressInput{
 | |
| 		Address: aws.String("123.45.67.8"),
 | |
| 	}, "eipalloc-12345678")
 | |
| 
 | |
| 	mockEC2.CreateNatGatewayWithId(&ec2.CreateNatGatewayInput{
 | |
| 		SubnetId:     aws.String("subnet-12345678"),
 | |
| 		AllocationId: aws.String("eipalloc-12345678"),
 | |
| 	}, "nat-a2345678")
 | |
| 
 | |
| 	mockEC2.AllocateAddressWithId(&ec2.AllocateAddressInput{
 | |
| 		Address: aws.String("2.22.22.22"),
 | |
| 	}, "eipalloc-b2345678")
 | |
| 
 | |
| 	mockEC2.CreateNatGatewayWithId(&ec2.CreateNatGatewayInput{
 | |
| 		SubnetId:     aws.String("subnet-b2345678"),
 | |
| 		AllocationId: aws.String("eipalloc-b2345678"),
 | |
| 	}, "nat-b2345678")
 | |
| 
 | |
| 	mockELBV2.CreateTargetGroup(ctx, &elbv2.CreateTargetGroupInput{
 | |
| 		Name: aws.String("my-external-tg-1"),
 | |
| 	})
 | |
| 	mockELBV2.CreateTargetGroup(ctx, &elbv2.CreateTargetGroupInput{
 | |
| 		Name: aws.String("my-external-tg-2"),
 | |
| 	})
 | |
| 	mockELBV2.CreateTargetGroup(ctx, &elbv2.CreateTargetGroupInput{
 | |
| 		Name: aws.String("my-external-tg-3"),
 | |
| 	})
 | |
| 
 | |
| 	mockIAM.CreateRole(ctx, &iam.CreateRoleInput{
 | |
| 		RoleName: aws.String("kops-custom-node-role"),
 | |
| 	})
 | |
| 	mockIAM.CreateInstanceProfile(ctx, &iam.CreateInstanceProfileInput{
 | |
| 		InstanceProfileName: aws.String("kops-custom-node-role"),
 | |
| 	})
 | |
| 	mockIAM.AddRoleToInstanceProfile(ctx, &iam.AddRoleToInstanceProfileInput{
 | |
| 		InstanceProfileName: aws.String("kops-custom-node-role"),
 | |
| 		RoleName:            aws.String("kops-custom-node-role"),
 | |
| 	})
 | |
| 
 | |
| 	return cloud
 | |
| }
 | |
| 
 | |
| // SetupMockGCE configures a mock GCE cloud provider
 | |
| func (h *IntegrationTestHarness) SetupMockGCE() *gcemock.MockGCECloud {
 | |
| 	project := "testproject"
 | |
| 	region := "us-test1"
 | |
| 
 | |
| 	cloud := gcemock.InstallMockGCECloud(region, project)
 | |
| 
 | |
| 	cloud.Compute().Networks().Insert(project, &compute.Network{
 | |
| 		Name:                  "default",
 | |
| 		AutoCreateSubnetworks: true,
 | |
| 	})
 | |
| 
 | |
| 	cloud.Compute().Subnetworks().Insert(project, region, &compute.Subnetwork{
 | |
| 		Name:    "default",
 | |
| 		Network: "default",
 | |
| 		Region:  region,
 | |
| 	})
 | |
| 
 | |
| 	return cloud
 | |
| }
 | |
| 
 | |
| func SetupMockOpenstack() *openstack.MockCloud {
 | |
| 	c := openstack.InstallMockOpenstackCloud("us-test1")
 | |
| 	c.MockCinderClient = mockblockstorage.CreateClient()
 | |
| 
 | |
| 	c.MockNeutronClient = mocknetworking.CreateClient()
 | |
| 
 | |
| 	c.MockLBClient = mockloadbalancer.CreateClient()
 | |
| 
 | |
| 	c.MockNovaClient = mockcompute.CreateClient(c.MockNeutronClient.ServiceClient())
 | |
| 
 | |
| 	c.MockDNSClient = mockdns.CreateClient()
 | |
| 
 | |
| 	c.MockImageClient = mockimage.CreateClient()
 | |
| 
 | |
| 	extNetworkName := "external"
 | |
| 	networkCreateOpts := networks.CreateOpts{
 | |
| 		Name:         extNetworkName,
 | |
| 		AdminStateUp: fi.PtrTo(true),
 | |
| 	}
 | |
| 	extNetwork := external.CreateOptsExt{
 | |
| 		CreateOptsBuilder: networkCreateOpts,
 | |
| 		External:          fi.PtrTo(true),
 | |
| 	}
 | |
| 	c.CreateNetwork(extNetwork)
 | |
| 	c.SetExternalNetwork(&extNetworkName)
 | |
| 
 | |
| 	extSubnetName := "external"
 | |
| 	extSubnet := subnets.CreateOpts{
 | |
| 		Name:       extSubnetName,
 | |
| 		NetworkID:  extNetworkName,
 | |
| 		EnableDHCP: fi.PtrTo(true),
 | |
| 		CIDR:       "172.20.0.0/22",
 | |
| 	}
 | |
| 	c.CreateSubnet(extSubnet)
 | |
| 	c.SetExternalSubnet(fi.PtrTo(extSubnetName))
 | |
| 	c.SetLBFloatingSubnet(fi.PtrTo(extSubnetName))
 | |
| 	images.Create(context.TODO(), c.MockImageClient.ServiceClient(), images.CreateOpts{
 | |
| 		Name:    "Ubuntu-20.04",
 | |
| 		MinDisk: 12,
 | |
| 	})
 | |
| 	flavors.Create(context.TODO(), c.MockNovaClient.ServiceClient(), flavors.CreateOpts{
 | |
| 		Name:  "n1-standard-2",
 | |
| 		RAM:   8192,
 | |
| 		VCPUs: 8,
 | |
| 		Disk:  fi.PtrTo(16),
 | |
| 	})
 | |
| 	flavors.Create(context.TODO(), c.MockNovaClient.ServiceClient(), flavors.CreateOpts{
 | |
| 		Name:  "n1-standard-1",
 | |
| 		RAM:   8192,
 | |
| 		VCPUs: 4,
 | |
| 		Disk:  fi.PtrTo(16),
 | |
| 	})
 | |
| 	zones.Create(context.TODO(), c.MockDNSClient.ServiceClient(), zones.CreateOpts{
 | |
| 		Name: "minimal-openstack.k8s.local",
 | |
| 	})
 | |
| 	return c
 | |
| }
 | |
| 
 | |
| // MockKopsVersion will set the kops version to the specified value, until Close is called
 | |
| func (h *IntegrationTestHarness) MockKopsVersion(version string) {
 | |
| 	if h.originalKopsVersion != "" {
 | |
| 		h.T.Fatalf("MockKopsVersion called twice (%s and %s)", version, h.originalKopsVersion)
 | |
| 	}
 | |
| 
 | |
| 	h.originalKopsVersion = kopsroot.Version
 | |
| 	kopsroot.Version = version
 | |
| }
 |