Skip to content

Commit

Permalink
tests/integration: Use the helpers from tftestenv
Browse files Browse the repository at this point in the history
Replace the common cloud provider helpers with the helpers in tftestenv.

Signed-off-by: Sunny <darkowlzz@protonmail.com>
  • Loading branch information
darkowlzz committed Jul 26, 2022
1 parent 726494d commit c96012a
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 258 deletions.
114 changes: 12 additions & 102 deletions tests/integration/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,75 +18,20 @@ package integration

import (
"context"
"fmt"
"log"
"os"

tfjson "github.com/hashicorp/terraform-json"

tftestenv "github.com/fluxcd/image-reflector-controller/tests/tftestenv"
)

// Based on https://docs.aws.amazon.com/eks/latest/userguide/create-kubeconfig.html
const kubeConfigTmpl = `
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: %[1]s
server: %[2]s
name: %[3]s
contexts:
- context:
cluster: %[3]s
user: %[4]s
name: %[3]s
current-context: %[3]s
kind: Config
preferences: {}
users:
- name: %[4]s
user:
token: %[5]s
`

// kubeconfigWithClusterAuthToken returns a kubeconfig with the given cluster
// authentication token.
func kubeconfigWithClusterAuthToken(token, caData, endpoint, user, clusterName string) string {
return fmt.Sprintf(kubeConfigTmpl, caData, endpoint, clusterName, user, token)
}

// getEKSClientToken fetches the EKS cluster client token.
func getEKSClientToken(ctx context.Context, clusterName string) ([]byte, error) {
err := tftestenv.RunCommand(ctx, "build",
fmt.Sprintf("aws eks get-token --cluster-name %s | jq -r .status.token > token", clusterName),
tftestenv.RunCommandOptions{},
)
if err != nil {
return nil, err
}
return os.ReadFile("build/token")
}

// createKubeconfigEKS constructs kubeconfig from the terraform state output at
// the given kubeconfig path.
func createKubeconfigEKS(ctx context.Context, state map[string]*tfjson.StateOutput, kcPath string) error {
clusterName := state["eks_cluster_name"].Value.(string)
eksHost := state["eks_cluster_endpoint"].Value.(string)
eksClusterArn := state["eks_cluster_arn"].Value.(string)
eksCa := state["eks_cluster_ca_certificate"].Value.(string)
eksToken, err := getEKSClientToken(ctx, clusterName)
if err != nil {
return fmt.Errorf("failed to obtain auth token: %w", err)
}

kubeconfigYaml := kubeconfigWithClusterAuthToken(string(eksToken), eksCa, eksHost, eksClusterArn, clusterName)

f, err := os.Create(kcPath)
if err != nil {
return err
}
_, err = fmt.Fprint(f, kubeconfigYaml)
return err
return tftestenv.CreateKubeconfigEKS(ctx, clusterName, eksHost, eksClusterArn, eksCa, kcPath)
}

// registryLoginECR logs into the container/artifact registries using the
Expand All @@ -95,67 +40,32 @@ func registryLoginECR(ctx context.Context, output map[string]*tfjson.StateOutput
// NOTE: ECR provides pre-existing registry per account. It requires
// repositories to be created explicitly using their API before pushing
// image.
testRepoURL := output["ecr_repository_url"].Value.(string)
ircRepoURL := output["ecr_image_reflector_controller_repo_url"].Value.(string)
testRepos := map[string]string{}
region := output["region"].Value.(string)

if err := tftestenv.RunCommand(ctx, "./",
fmt.Sprintf("aws ecr get-login-password --region %s | docker login --username AWS --password-stdin %s", region, testRepoURL),
tftestenv.RunCommandOptions{},
); err != nil {
testRepoURL := output["ecr_repository_url"].Value.(string)
if err := tftestenv.RegistryLoginECR(ctx, region, testRepoURL); err != nil {
return nil, err
}
testRepos["ecr"] = testRepoURL

if err := tftestenv.RunCommand(ctx, "./",
fmt.Sprintf("aws ecr get-login-password --region %s | docker login --username AWS --password-stdin %s", region, ircRepoURL),
tftestenv.RunCommandOptions{},
); err != nil {
// Log into the image-reflector-controller repository to be able to push to
// it. This image is not used in testing and need not be included in
// testRepos.
ircRepoURL := output["ecr_image_reflector_controller_repo_url"].Value.(string)
if err := tftestenv.RegistryLoginECR(ctx, region, ircRepoURL); err != nil {
return nil, err
}

return map[string]string{"ecr": testRepoURL}, nil
return testRepos, nil
}

// pushFluxTestImagesECR pushes flux image that is being tested. It must be
// called after registryLoginECR to ensure the local docker client is already
// logged in and is capable of pushing the test images.
func pushFluxTestImagesECR(ctx context.Context, localImgs map[string]string, output map[string]*tfjson.StateOutput) (map[string]string, error) {
// NOTE: Unlike Azure Container Registry and Google Artifact Registry, ECR
// does not support dynamic image repositories. A new repository for a new
// image has to be explicitly created. Therefore, the single local image
// is retagged and pushed in the already created repository.
if len(localImgs) != 1 {
return nil, fmt.Errorf("ECR repository supports pushing one image only, got: %v", localImgs)
}

// Get the registry name and construct the image names accordingly.
repo := output["ecr_image_reflector_controller_repo_url"].Value.(string)

remoteImage := repo + ":test"

// Extract the component name and local image.
var name, localImage string
for n, i := range localImgs {
name, localImage = n, i
}

if err := tftestenv.RunCommand(ctx, "./",
fmt.Sprintf("docker tag %s %s", localImage, remoteImage),
tftestenv.RunCommandOptions{},
); err != nil {
return nil, err
}

log.Printf("pushing flux test image %s\n", remoteImage)

if err := tftestenv.RunCommand(ctx, "./",
fmt.Sprintf("docker push %s", remoteImage),
tftestenv.RunCommandOptions{},
); err != nil {
return nil, err
}

return map[string]string{
name: remoteImage,
}, nil
return tftestenv.PushTestAppImagesECR(ctx, localImgs, remoteImage)
}
27 changes: 9 additions & 18 deletions tests/integration/azure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package integration
import (
"context"
"fmt"
"os"

tfjson "github.com/hashicorp/terraform-json"

Expand All @@ -33,38 +32,30 @@ func createKubeConfigAKS(ctx context.Context, state map[string]*tfjson.StateOutp
if !ok || kubeconfigYaml == "" {
return fmt.Errorf("failed to obtain kubeconfig from tf output")
}

f, err := os.Create(kcPath)
if err != nil {
return err
}
_, err = fmt.Fprint(f, kubeconfigYaml)
if err != nil {
return err
}
return f.Close()
return tftestenv.CreateKubeconfigAKS(ctx, kubeconfigYaml, kcPath)
}

// registryLoginACR logs into the container/artifact registries using the
// provider's CLI tools and returns a list of test repositories.
func registryLoginACR(ctx context.Context, output map[string]*tfjson.StateOutput) (map[string]string, error) {
// NOTE: ACR registry accept dynamic repository creation by just pushing a
// new image with a new repository name.
registryURL := output["acr_registry_url"].Value.(string)
testRepos := map[string]string{}

if err := tftestenv.RunCommand(ctx, "./",
fmt.Sprintf("az acr login --name %s", registryURL), tftestenv.RunCommandOptions{},
); err != nil {
registryURL := output["acr_registry_url"].Value.(string)
if err := tftestenv.RegistryLoginACR(ctx, registryURL); err != nil {
return nil, err
}
return map[string]string{"acr": registryURL + "/" + randStringRunes(5)}, nil
testRepos["acr"] = registryURL + "/" + randStringRunes(5)

return testRepos, nil
}

// pushFluxTestImagesACR pushes flux images that are being tested. It must be
// called after registryLoginACR to ensure the local docker client is already
// logged in and is capable of pushing the test images.
func pushFluxTestImagesACR(ctx context.Context, localImgs map[string]string, output map[string]*tfjson.StateOutput) (map[string]string, error) {
// Get the registry name and construct the image names accordingly.
repo := output["acr_registry_url"].Value.(string)
return retagAndPush(ctx, repo, localImgs)
registryURL := output["acr_registry_url"].Value.(string)
return tftestenv.PushTestAppImagesACR(ctx, localImgs, registryURL)
}
60 changes: 16 additions & 44 deletions tests/integration/gcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package integration
import (
"context"
"fmt"
"os"

tfjson "github.com/hashicorp/terraform-json"

Expand All @@ -33,67 +32,40 @@ func createKubeconfigGKE(ctx context.Context, state map[string]*tfjson.StateOutp
if !ok || kubeconfigYaml == "" {
return fmt.Errorf("failed to obtain kubeconfig from tf output")
}

f, err := os.Create(kcPath)
if err != nil {
return err
}
_, err = fmt.Fprint(f, kubeconfigYaml)
if err != nil {
return err
}
return f.Close()
return tftestenv.CreateKubeconfigGKE(ctx, kubeconfigYaml, kcPath)
}

// registryLoginGCR logs into the container/artifact registries using the
// provider's CLI tools and returns a list of test repositories.
func registryLoginGCR(ctx context.Context, output map[string]*tfjson.StateOutput) (map[string]string, error) {
// NOTE: GCR accepts dynamic repository creation by just pushing a new image
// with a new repository name.
testRepos := map[string]string{}

repoURL := output["gcr_repository_url"].Value.(string)
if err := tftestenv.RunCommand(ctx, "./",
fmt.Sprintf("gcloud auth configure-docker %s", repoURL),
tftestenv.RunCommandOptions{},
); err != nil {
if err := tftestenv.RegistryLoginGCR(ctx, repoURL); err != nil {
return nil, err
}
testRepos["gcr"] = repoURL + "/" + randStringRunes(5)

artifactRegistry, artifactURL := getGoogleArtifactRegistryAndRepository(output)
if err := tftestenv.RunCommand(ctx, "./",
fmt.Sprintf("gcloud auth configure-docker %s", artifactRegistry),
tftestenv.RunCommandOptions{},
); err != nil {
project := output["gcp_project"].Value.(string)
region := output["gcp_region"].Value.(string)
repositoryID := output["gcp_artifact_repository"].Value.(string)
artifactRegistryURL, artifactRepoURL := tftestenv.GetGoogleArtifactRegistryAndRepository(project, region, repositoryID)
if err := tftestenv.RegistryLoginGCR(ctx, artifactRegistryURL); err != nil {
return nil, err
}
testRepos["artifact_registry"] = artifactRepoURL + "/" + randStringRunes(5)

return map[string]string{
"gcr": repoURL + "/" + randStringRunes(5),
"artifact_registry": artifactURL + "/" + randStringRunes(5),
}, nil
}

func getGoogleArtifactRegistryAndRepository(output map[string]*tfjson.StateOutput) (string, string) {
// NOTE: Artifact Registry calls a registry a "repository". A repository can
// contain multiple different images, unlike ECR or ACR where a repository
// can contain multiple tags of only a single image.
// Artifact Registry also supports dynamic repository(image) creation by
// pushing a new image with a new image name once a new registry(repository)
// is created.
location := output["gcp_region"].Value.(string)
project := output["gcp_project"].Value.(string)
repository := output["gcp_artifact_repository"].Value.(string)
// Use the fixed docker formatted repository suffix with the location to
// create the registry address.
artifactRegistry := fmt.Sprintf("%s-docker.pkg.dev", location)
artifactRepository := fmt.Sprintf("%s/%s/%s", artifactRegistry, project, repository)
return artifactRegistry, artifactRepository
return testRepos, nil
}

// pushFluxTestImagesGCR pushes flux images that are being tested. It must be
// called after registryLoginGCR to ensure the local docker client is already
// logged in and is capable of pushing the test images.
func pushFluxTestImagesGCR(ctx context.Context, localImgs map[string]string, output map[string]*tfjson.StateOutput) (map[string]string, error) {
// Get the repository name and construct the image names accordingly.
_, repo := getGoogleArtifactRegistryAndRepository(output)
return retagAndPush(ctx, repo, localImgs)
project := output["gcp_project"].Value.(string)
region := output["gcp_region"].Value.(string)
repositoryID := output["gcp_artifact_repository"].Value.(string)
return tftestenv.PushTestAppImagesGCR(ctx, localImgs, project, region, repositoryID)
}
20 changes: 10 additions & 10 deletions tests/integration/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ replace github.com/fluxcd/image-reflector-controller/tests/tftestenv => ../tftes
require (
github.com/fluxcd/image-reflector-controller/api v0.18.0
github.com/fluxcd/image-reflector-controller/tests/tftestenv v0.0.0
github.com/google/go-containerregistry v0.9.0
github.com/hashicorp/terraform-json v0.14.0
github.com/onsi/gomega v1.18.1
k8s.io/apimachinery v0.24.1
Expand All @@ -16,11 +15,11 @@ require (
require (
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.11.4 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.12.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/cli v20.10.16+incompatible // indirect
github.com/docker/cli v20.10.17+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.16+incompatible // indirect
github.com/docker/docker v20.10.17+incompatible // indirect
github.com/docker/docker-credential-helpers v0.6.4 // indirect
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
Expand All @@ -33,6 +32,7 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-containerregistry v0.11.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
Expand All @@ -43,7 +43,7 @@ require (
github.com/imdario/mergo v0.3.12 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.4 // indirect
github.com/klauspost/compress v1.15.8 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand All @@ -52,15 +52,15 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/vbatts/tar-split v0.11.2 // indirect
github.com/zclconf/go-cty v1.10.0 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
golang.org/x/net v0.0.0-20220516155154-20f960328961 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92 // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
Expand Down

0 comments on commit c96012a

Please sign in to comment.