Skip to content

Commit

Permalink
Merge pull request kubernetes-sigs#3071 from sedefsavas/add-e2e-to-li…
Browse files Browse the repository at this point in the history
…nter

Include test package to linter checks
  • Loading branch information
k8s-ci-robot committed Jan 11, 2022
2 parents f1edce6 + c6478c4 commit 796dc2a
Show file tree
Hide file tree
Showing 35 changed files with 261 additions and 322 deletions.
11 changes: 11 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ issues:
- linters:
- unparam
text: always receives
# Dot imports for gomega or ginkgo are allowed
# within test files.
- path: _test\.go
text: should not use dot imports
- path: (framework|e2e)/.*.go
text: should not use dot imports
- path: _test\.go
text: cyclomatic complexity
- linters:
- unparam
text: (.+) - (`t`|`g`) is unused
Expand All @@ -227,6 +235,9 @@ issues:

run:
timeout: 10m
build-tags:
- tools
- e2e
skip-files:
- "zz_generated.*\\.go$"
- ".*conversion.*\\.go$"
Expand Down
79 changes: 44 additions & 35 deletions test/e2e/shared/aws.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build e2e
// +build e2e

/*
Expand Down Expand Up @@ -101,7 +102,7 @@ func NewAWSSessionWithKey(accessKey *iam.AccessKey) client.ConfigProvider {
return sess
}

// createCloudFormationStack ensures the cloudformation stack is up to date
// createCloudFormationStack ensures the cloudformation stack is up to date.
func createCloudFormationStack(prov client.ConfigProvider, t *cfn_bootstrap.Template, tags map[string]string) error {
Byf("Creating AWS CloudFormation stack for AWS IAM resources: stack-name=%s", t.Spec.StackName)
CFN := cfn.New(prov)
Expand Down Expand Up @@ -141,11 +142,12 @@ func deleteResourcesInCloudFormation(prov client.ConfigProvider, t *cfn_bootstra
tayp := val.AWSCloudFormationType()
if tayp == configservice.ResourceTypeAwsIamRole {
role := val.(*cfn_iam.Role)
iamSvc.DeleteRole(&iam.DeleteRoleInput{RoleName: aws.String(role.RoleName)})
_, err := iamSvc.DeleteRole(&iam.DeleteRoleInput{RoleName: aws.String(role.RoleName)})
Expect(err).NotTo(HaveOccurred())
}
if val.AWSCloudFormationType() == "AWS::IAM::InstanceProfile" {
profile := val.(*cfn_iam.InstanceProfile)
iamSvc.DeleteInstanceProfile(&iam.DeleteInstanceProfileInput{InstanceProfileName: aws.String(profile.InstanceProfileName)})
_, _ = iamSvc.DeleteInstanceProfile(&iam.DeleteInstanceProfileInput{InstanceProfileName: aws.String(profile.InstanceProfileName)})
}
if val.AWSCloudFormationType() == "AWS::IAM::ManagedPolicy" {
policy := val.(*cfn_iam.ManagedPolicy)
Expand All @@ -154,15 +156,15 @@ func deleteResourcesInCloudFormation(prov client.ConfigProvider, t *cfn_bootstra
if len(policies.Policies) > 0 {
for _, p := range policies.Policies {
if aws.StringValue(p.PolicyName) == policy.ManagedPolicyName {
iamSvc.DeletePolicy(&iam.DeletePolicyInput{PolicyArn: p.Arn})
_, _ = iamSvc.DeletePolicy(&iam.DeletePolicyInput{PolicyArn: p.Arn})
break
}
}
}
}
if val.AWSCloudFormationType() == configservice.ResourceTypeAwsIamGroup {
group := val.(*cfn_iam.Group)
iamSvc.DeleteGroup(&iam.DeleteGroupInput{GroupName: aws.String(group.GroupName)})
_, _ = iamSvc.DeleteGroup(&iam.DeleteGroupInput{GroupName: aws.String(group.GroupName)})
}
}
}
Expand All @@ -173,7 +175,7 @@ func deleteMultitenancyRoles(prov client.ConfigProvider) {
DeleteRole(prov, "multi-tenancy-nested-role")
}

// detachAllPoliciesForRole detaches all policies for role
// detachAllPoliciesForRole detaches all policies for role.
func detachAllPoliciesForRole(prov client.ConfigProvider, name string) error {
iamSvc := iam.New(prov)

Expand All @@ -198,11 +200,11 @@ func detachAllPoliciesForRole(prov client.ConfigProvider, name string) error {
return nil
}

// Best effort deletes roles.
// DeleteRole deletes roles in a best effort manner.
func DeleteRole(prov client.ConfigProvider, name string) {
iamSvc := iam.New(prov)

// if role does not exist, return
// if role does not exist, return.
_, err := iamSvc.GetRole(&iam.GetRoleInput{RoleName: aws.String(name)})
if err != nil {
return
Expand All @@ -212,7 +214,10 @@ func DeleteRole(prov client.ConfigProvider, name string) {
return
}

iamSvc.DeleteRole(&iam.DeleteRoleInput{RoleName: aws.String(name)})
_, err = iamSvc.DeleteRole(&iam.DeleteRoleInput{RoleName: aws.String(name)})
if err != nil {
return
}
}

func GetPolicyArn(prov client.ConfigProvider, name string) string {
Expand All @@ -230,7 +235,7 @@ func GetPolicyArn(prov client.ConfigProvider, name string) string {
return ""
}

// deleteCloudFormationStack removes the provisioned clusterawsadm stack
// deleteCloudFormationStack removes the provisioned clusterawsadm stack.
func deleteCloudFormationStack(prov client.ConfigProvider, t *cfn_bootstrap.Template) {
Byf("Deleting %s CloudFormation stack", t.Spec.StackName)
CFN := cfn.New(prov)
Expand All @@ -248,19 +253,20 @@ func deleteCloudFormationStack(prov client.ConfigProvider, t *cfn_bootstrap.Temp
err = cfnSvc.DeleteStack(t.Spec.StackName, retainResources)
Expect(err).NotTo(HaveOccurred())
}
CFN.WaitUntilStackDeleteComplete(&cfn.DescribeStacksInput{
err = CFN.WaitUntilStackDeleteComplete(&cfn.DescribeStacksInput{
StackName: aws.String(t.Spec.StackName),
})
Expect(err).NotTo(HaveOccurred())
}

func ensureTestImageUploaded(e2eCtx *E2EContext) (string, string, error) {
func ensureTestImageUploaded(e2eCtx *E2EContext) error {
sessionForRepo := NewAWSSessionRepoWithKey(e2eCtx.Environment.BootstrapAccessKey)

ecrSvc := ecrpublic.New(sessionForRepo)
repoName := ""
if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
output, err := ecrSvc.CreateRepository(&ecrpublic.CreateRepositoryInput{
RepositoryName: aws.String("capa/update"),
RepositoryName: aws.String("capa/up"),
})

if err != nil {
Expand All @@ -278,57 +284,57 @@ func ensureTestImageUploaded(e2eCtx *E2EContext) (string, string, error) {

return true, nil
}, awserrors.UnrecognizedClientException); err != nil {
return "", "", nil
return err
}

cmd := exec.Command("docker", "inspect", "--format='{{index .Id}}'", "gcr.io/k8s-staging-cluster-api/capa-manager:e2e")
var stdOut bytes.Buffer
cmd.Stdout = &stdOut
err := cmd.Run()
if err != nil {
return "", "", err
return err
}

imageSha := strings.ReplaceAll(strings.TrimSuffix(string(stdOut.Bytes()), "\n"), "'", "")
imageSha := strings.ReplaceAll(strings.TrimSuffix(stdOut.String(), "\n"), "'", "")

ecrImageName := repoName + ":e2e"
cmd = exec.Command("docker", "tag", imageSha, ecrImageName)
cmd = exec.Command("docker", "tag", imageSha, ecrImageName) //nolint:gosec
err = cmd.Run()
if err != nil {
return "", "", err
return err
}

outToken, err := ecrSvc.GetAuthorizationToken(&ecrpublic.GetAuthorizationTokenInput{})
if err != nil {
return "", "", err
return err
}

// Auth token is in username:password format. To login using it, we need to decode first and separate password and username
decodedUsernamePassword, _ := b64.StdEncoding.DecodeString(aws.StringValue(outToken.AuthorizationData.AuthorizationToken))

strList := strings.Split(string(decodedUsernamePassword), ":")
if len(strList) != 2 {
return "", "", errors.New("Failed to decode ECR authentication token")
return errors.New("failed to decode ECR authentication token")
}

cmd = exec.Command("docker", "login", "--username", strList[0], "--password", strList[1], "public.ecr.aws")
cmd = exec.Command("docker", "login", "--username", strList[0], "--password", strList[1], "public.ecr.aws") //nolint:gosec
err = cmd.Run()
if err != nil {
return "", "", err
return err
}

cmd = exec.Command("docker", "push", ecrImageName)
err = cmd.Run()
if err != nil {
return "", "", err
return err
}
e2eCtx.E2EConfig.Variables["CAPI_IMAGES_REGISTRY"] = repoName
e2eCtx.E2EConfig.Variables["E2E_IMAGE_TAG"] = "e2e"
return "", "", nil
return nil
}

// ensureNoServiceLinkedRoles removes an auto-created IAM role, and tests
// the controller's IAM permissions to use ELB and Spot instances successfully
// the controller's IAM permissions to use ELB and Spot instances successfully.
func ensureNoServiceLinkedRoles(prov client.ConfigProvider) {
Byf("Deleting AWS IAM Service Linked Role: role-name=AWSServiceRoleForElasticLoadBalancing")
iamSvc := iam.New(prov)
Expand All @@ -348,7 +354,7 @@ func ensureNoServiceLinkedRoles(prov client.ConfigProvider) {
}
}

// ensureSSHKeyPair ensures A SSH key is present under the name
// ensureSSHKeyPair ensures A SSH key is present under the name.
func ensureSSHKeyPair(prov client.ConfigProvider, keyPairName string) {
Byf("Ensuring presence of SSH key in EC2: key-name=%s", keyPairName)
ec2c := ec2.New(prov)
Expand All @@ -372,7 +378,7 @@ func ensureStackTags(prov client.ConfigProvider, stackName string, expectedTags
}
}

// encodeCredentials leverages clusterawsadm to encode AWS credentials
// encodeCredentials leverages clusterawsadm to encode AWS credentials.
func encodeCredentials(accessKey *iam.AccessKey, region string) string {
creds := credentials.AWSCredentials{
Region: region,
Expand Down Expand Up @@ -424,18 +430,21 @@ func DumpCloudTrailEvents(e2eCtx *E2EContext) {
},
)
if err != nil {
fmt.Fprintf(GinkgoWriter, "couldn't get AWS CloudTrail events: err=%s", err)
fmt.Fprintf(GinkgoWriter, "couldn't get AWS CloudTrail events: err=%v", err)
}
logPath := filepath.Join(e2eCtx.Settings.ArtifactFolder, "cloudtrail-events.yaml")
dat, err := yaml.Marshal(events)
if err != nil {
fmt.Fprintf(GinkgoWriter, "Failed to marshal AWS CloudTrail events: err=%v", err)
}
if err := os.WriteFile(logPath, dat, 0600); err != nil {
fmt.Fprintf(GinkgoWriter, "couldn't write cloudtrail events to file: file=%s err=%s", logPath, err)
return
}
}

// conformanceImageID looks up a specific image for a given
// Kubernetes version in the e2econfig
// Kubernetes version in the e2econfig.
func conformanceImageID(e2eCtx *E2EContext) string {
ver := e2eCtx.E2EConfig.GetVariable("CONFORMANCE_CI_ARTIFACTS_KUBERNETES_VERSION")
strippedVer := strings.Replace(ver, "v", "", 1)
Expand Down Expand Up @@ -527,7 +536,7 @@ func (s *ServiceQuota) updateServiceQuotaRequestStatus(serviceQuotasClient *serv
ServiceCode: aws.String(s.ServiceCode),
}
latestRequest := &servicequotas.RequestedServiceQuotaChange{}
serviceQuotasClient.ListRequestedServiceQuotaChangeHistoryPages(params,
_ = serviceQuotasClient.ListRequestedServiceQuotaChangeHistoryPages(params,
func(page *servicequotas.ListRequestedServiceQuotaChangeHistoryOutput, lastPage bool) bool {
for _, v := range page.RequestedQuotas {
if int(aws.Float64Value(v.DesiredValue)) >= s.DesiredMinimumValue && aws.StringValue(v.QuotaCode) == s.QuotaCode && aws.TimeValue(v.Created).After(aws.TimeValue(latestRequest.Created)) {
Expand Down Expand Up @@ -568,7 +577,6 @@ func DumpEKSClusters(ctx context.Context, e2eCtx *E2EContext) {
}
dumpEKSCluster(describeOutput.Cluster, logPath)
}

}

func dumpEKSCluster(cluster *eks.Cluster, logPath string) {
Expand All @@ -580,21 +588,22 @@ func dumpEKSCluster(cluster *eks.Cluster, logPath string) {

fileName := fmt.Sprintf("%s.yaml", *cluster.Name)
clusterLog := path.Join(logPath, fileName)
f, err := os.OpenFile(clusterLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm)
f, err := os.OpenFile(clusterLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm) //nolint:gosec
if err != nil {
fmt.Fprintf(GinkgoWriter, "couldn't open log file: name=%s err=%s", clusterLog, err)
return
}
defer f.Close()
defer f.Close() //nolint:gosec

if err := os.WriteFile(f.Name(), clusterYAML, 0600); err != nil {
fmt.Fprintf(GinkgoWriter, "couldn't write cluster yaml to file: name=%s file=%s err=%s", *cluster.Name, f.Name(), err)
return
}
}

// To calculate how much resources a test consumes, these helper functions below can be used.
// ListNATGateways(e2eCtx), ListRunningEC2(e2eCtx), ListVPC(e2eCtx), ListVpcInternetGateways(e2eCtx)
// To calculate how much resources a test consumes, these helper functions below can be used.
// ListVpcInternetGateways, ListNATGateways, ListRunningEC2, ListVPC

func ListVpcInternetGateways(e2eCtx *E2EContext) ([]*ec2.InternetGateway, error) {
ec2Svc := ec2.New(e2eCtx.AWSSession)

Expand Down
9 changes: 5 additions & 4 deletions test/e2e/shared/cluster.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build e2e
// +build e2e

/*
Expand Down Expand Up @@ -32,7 +33,7 @@ import (
)

// createClusterctlLocalRepository generates a clusterctl repository.
// Must always be run after kubetest.NewConfiguration
// Must always be run after kubetest.NewConfiguration.
func createClusterctlLocalRepository(config *clusterctl.E2EConfig, repositoryFolder string) string {
createRepositoryInput := clusterctl.CreateRepositoryInput{
E2EConfig: config,
Expand All @@ -50,7 +51,7 @@ func createClusterctlLocalRepository(config *clusterctl.E2EConfig, repositoryFol
return clusterctlConfig
}

// setupBootstrapCluster installs Cluster API components via clusterctl
// setupBootstrapCluster installs Cluster API components via clusterctl.
func setupBootstrapCluster(config *clusterctl.E2EConfig, scheme *runtime.Scheme, useExistingCluster bool) (bootstrap.ClusterProvider, framework.ClusterProxy) {
var clusterProvider bootstrap.ClusterProvider
kubeconfigPath := ""
Expand All @@ -73,7 +74,7 @@ func setupBootstrapCluster(config *clusterctl.E2EConfig, scheme *runtime.Scheme,
return clusterProvider, clusterProxy
}

// initBootstrapCluster uses kind to create a cluster
// initBootstrapCluster uses kind to create a cluster.
func initBootstrapCluster(e2eCtx *E2EContext) {
// NOTE: the following originally used clusterctl.InitManagementClusterAndWatchControllerLogs.
// This can be used again when https://github.com/kubernetes-sigs/cluster-api/issues/3983 is completed
Expand All @@ -87,7 +88,7 @@ func initBootstrapCluster(e2eCtx *E2EContext) {
}, e2eCtx.E2EConfig.GetIntervals(e2eCtx.Environment.BootstrapClusterProxy.GetName(), "wait-controllers")...)
}

// tearDown the bootstrap kind cluster
// tearDown the bootstrap kind cluster.
func tearDown(bootstrapClusterProvider bootstrap.ClusterProvider, bootstrapClusterProxy framework.ClusterProxy) {
if bootstrapClusterProxy != nil {
bootstrapClusterProxy.Dispose(context.TODO())
Expand Down
Loading

0 comments on commit 796dc2a

Please sign in to comment.