Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Real e2e #573

Merged
merged 7 commits into from
Feb 14, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 18 additions & 1 deletion config/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ genrule(
"//cmd/clusterctl/examples/aws:out/aws_manager_image_patch.yaml",
"//cmd/clusterctl/examples/aws:test-credentials",
"config",
":credential_file",
"//:WORKSPACE",
],
outs = ["aws_provider.yaml"],
cmd = """CONFIG_SRCDIR={root_dir}/config && \\
cmd = """install -D $(location :credential_file) $(@D)/../cmd/clusterctl/examples/aws/out/credentials && \\
CONFIG_SRCDIR={root_dir}/config && \\
cp -R $$CONFIG_SRCDIR/default $(@D)/default && \\
cp -R $$CONFIG_SRCDIR/manager $(@D)/manager && \\
{kustomize} build $(@D)/default > $@
Expand All @@ -55,3 +57,18 @@ genrule(
tools = ["@io_k8s_sigs_kustomize//:kustomize"],
visibility = ["//visibility:public"],
)

genrule(
name = "credential_file",
outs = ["credentials"],
visibility = ["//visibility:public"],
cmd = " && ".join([
"touch $@",
"export AWS_ACCESS_KEY_ID=$$(grep ^AWS_ACCESS_KEY_ID bazel-out/volatile-status.txt | cut -f2 -d\" \")",
"export AWS_SECRET_ACCESS_KEY=$$(grep ^AWS_SECRET_ACCESS_KEY bazel-out/volatile-status.txt | cut -f2 -d\" \")",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this cause issues with local dev workflows by assuming creds are always in bazel-out/volatile-status.txt?

Or am I potentially misreading what this is doing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

volatile status gets repopulated from env when you run go test, so basically it's just assuming these are in the user's environment. I don't really know how else to get the creds inside, though it seems like @randomvariable is changing how this works anyway?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be able to use bazel configs as switches to choose where it looks. Too much work right now I think though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reading, will need to support AWS_SESSION_TOKEN too, but can fix up in follow up PR.

"echo '[default]' >> $@",
"echo aws_access_key_id = $$AWS_ACCESS_KEY_ID >> $@",
"echo aws_secret_access_key = $$AWS_SECRET_ACCESS_KEY >> $@",
]),
stamp = 1,
)
1 change: 1 addition & 0 deletions hack/checkin_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import sys
import httplib
import urllib
import os
Expand Down
2 changes: 2 additions & 0 deletions hack/print-workspace-status.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,6 @@ GIT_VERSION ${GIT_VERSION-}
GIT_BRANCH ${GIT_BRANCH-}
GIT_RELEASE_TAG ${GIT_RELEASE_TAG-}
GIT_RELEASE_COMMIT ${GIT_RELEASE_COMMIT-}
AWS_ACCESS_KEY_ID ${AWS_ACCESS_KEY_ID-}
AWS_SECRET_ACCESS_KEY ${AWS_SECRET_ACCESS_KEY-}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these here only for current test/debugging purposes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not very many ways to get external variables into Bazel unfortunately :( This was the best solution I've found.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the output of hack/print-workspace-status.sh shown in the logs that are uploaded for viewing in test-grid?

EOF
2 changes: 1 addition & 1 deletion scripts/ci-bazel-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ set -o pipefail
REPO_ROOT=$(dirname "${BASH_SOURCE}")/..

cd $REPO_ROOT
bazel test --define='gotags=integration' --test_output all //test/e2e/...
bazel test --define='gotags=integration' --test_output all //test/integration/...
bazel_status=$?
python hack/coalesce.py
exit $bazel_status
29 changes: 18 additions & 11 deletions test/e2e/BUILD
Original file line number Diff line number Diff line change
@@ -1,43 +1,50 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
load("@io_bazel_rules_go//go:def.bzl", "go_test")

go_test(
name = "go_default_test",
size = "large",
srcs = [
"aws_test.go",
"e2e_suite_test.go",
"metacluster_test.go",
],
args = [
"-kindBinary=$(location @io_k8s_sigs_kind//:kind)",
"-kubectlBinary=$(location @io_k8s_kubernetes//cmd/kubectl:kubectl)",
"-awsProviderYAML=$(location //config:aws-provider-yaml)",
"-clusterAPIYAML=$(location //vendor/sigs.k8s.io/cluster-api/config:cluster-api-yaml)",
"-managerImageTar=$(location //cmd/manager:manager-amd64.tar)",
"-credFile=$(location //config:credential_file)",
],
data = [
"//config:aws-provider-yaml",
"//config:credential_file",
"//vendor/sigs.k8s.io/cluster-api/config:cluster-api-yaml",
"//cmd/manager:manager-amd64.tar",
"@io_k8s_kubernetes//cmd/kubectl:kubectl",
"@io_k8s_sigs_kind//:kind",
],
embed = [":go_default_library"],
rundir = ".",
deps = [
"//pkg/apis/awsprovider/v1alpha1:go_default_library",
"//pkg/cloud/aws/services/awserrors:go_default_library",
"//pkg/cloud/aws/services/cloudformation:go_default_library",
"//pkg/cloud/aws/services/sts:go_default_library",
"//test/e2e/util/kind:go_default_library",
"//vendor/github.com/aws/aws-sdk-go/aws:go_default_library",
"//vendor/github.com/aws/aws-sdk-go/aws/client:go_default_library",
"//vendor/github.com/aws/aws-sdk-go/aws/credentials:go_default_library",
"//vendor/github.com/aws/aws-sdk-go/aws/session:go_default_library",
"//vendor/github.com/aws/aws-sdk-go/service/cloudformation:go_default_library",
"//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library",
"//vendor/github.com/aws/aws-sdk-go/service/sts:go_default_library",
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
"//vendor/github.com/onsi/gomega/gstruct:go_default_library",
"//vendor/github.com/onsi/gomega/types:go_default_library",
"//vendor/k8s.io/api/apps/v1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1:go_default_library",
"//vendor/sigs.k8s.io/cluster-api/pkg/client/clientset_generated/clientset:go_default_library",
],
)

go_library(
name = "go_default_library",
srcs = ["e2e.go"],
importpath = "sigs.k8s.io/cluster-api-provider-aws/test/e2e",
visibility = ["//visibility:public"],
)
217 changes: 217 additions & 0 deletions test/e2e/aws_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
Copyright 2018 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 e2e_test

import (
"flag"
"time"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"
"github.com/onsi/gomega/types"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
cfn "github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/aws/aws-sdk-go/service/ec2"
awssts "github.com/aws/aws-sdk-go/service/sts"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"

capa "sigs.k8s.io/cluster-api-provider-aws/pkg/apis/awsprovider/v1alpha1"
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/services/awserrors"
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/services/cloudformation"
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/services/sts"
"sigs.k8s.io/cluster-api-provider-aws/test/e2e/util/kind"
capi "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
clientset "sigs.k8s.io/cluster-api/pkg/client/clientset_generated/clientset"
)

const (
kindTimeout = 5 * 60
namespace = "capa-test"
clusterName = "capa-test-cluster"
controlPlaneName = "capa-test-control-plane"

kubeletVersion = "v1.13.2"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to pull kubeletVersion from the example manifests? Currently we only really publish one supported version and I worry that this might get out of sync and be confusing to troubleshoot over time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it'll take a bit of work. Make this a TODO and issue and can see how to handle it later. Also applies to the image generation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TOO LATE did it anyway

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@randomvariable what do you mean by image generation? do you mean the AMIs? We're already using compile-time docker images from Bazel.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AMIs. Related to #576 (review)

instanceType = "t2.medium"
awsRegion = "us-east-1"
stackName = "cluster-api-provider-aws-sigs-k8s-io"
keyPairName = "cluster-api-provider-aws-sigs-k8s-io"
)

var credFile = flag.String("credFile", "", "path to an AWS credentials file")

var _ = Describe("AWS", func() {
var (
cluster kind.Cluster
client *clientset.Clientset
)
BeforeEach(func() {
cluster.Setup()
cfg := cluster.RestConfig()
var err error
client, err = clientset.NewForConfig(cfg)
Expect(err).To(BeNil())
}, kindTimeout)

AfterEach(func() {
cluster.Teardown()
})

Describe("control plane node", func() {
It("should be running", func() {

sess := getSession()
accountID := getAccountID(sess)

createKeyPair(sess)
createIAMRoles(sess, accountID)

createNamespace(cluster.KubeClient())

By("Creating a cluster")
clusterapi := client.ClusterV1alpha1().Clusters(namespace)
_, err := clusterapi.Create(makeCluster())
Expect(err).To(BeNil())

By("Creating a machine")
machineapi := client.ClusterV1alpha1().Machines(namespace)
_, err = machineapi.Create(makeMachine())
Expect(err).To(BeNil())

Eventually(
func() (*capa.AWSMachineProviderStatus, error) {
machine, err := machineapi.Get(controlPlaneName, metav1.GetOptions{})
if err != nil {
return nil, err
}
return capa.MachineStatusFromProviderStatus(machine.Status.ProviderStatus)
},
10*time.Minute, 15*time.Second,
).Should(beHealthy())
})
})
})

func beHealthy() types.GomegaMatcher {
return PointTo(
MatchFields(IgnoreExtras, Fields{
"InstanceState": PointTo(Equal(capa.InstanceStateRunning)),
}),
)
}

func makeCluster() *capi.Cluster {
clusterSpec, err := capa.EncodeClusterSpec(&capa.AWSClusterProviderSpec{
Region: awsRegion,
SSHKeyName: keyPairName,
})
Expect(err).To(BeNil())

return &capi.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: clusterName,
},
Spec: capi.ClusterSpec{
ClusterNetwork: capi.ClusterNetworkingConfig{
Services: capi.NetworkRanges{
CIDRBlocks: []string{"10.96.0.0/12"},
},
Pods: capi.NetworkRanges{
CIDRBlocks: []string{"192.168.0.0/16"},
},
ServiceDomain: "cluster.local",
},
ProviderSpec: capi.ProviderSpec{
Value: clusterSpec,
},
},
}
}

func makeMachine() *capi.Machine {
providerSpec, err := capa.EncodeMachineSpec(&capa.AWSMachineProviderSpec{
InstanceType: instanceType,
IAMInstanceProfile: "control-plane.cluster-api-provider-aws.sigs.k8s.io",
KeyName: keyPairName,
})
Expect(err).To(BeNil())

return &capi.Machine{
ObjectMeta: metav1.ObjectMeta{
Name: controlPlaneName,
Labels: map[string]string{
"set": "controlplane",
"cluster.k8s.io/cluster-name": clusterName,
},
},
Spec: capi.MachineSpec{
Versions: capi.MachineVersionInfo{
Kubelet: kubeletVersion,
ControlPlane: kubeletVersion,
},
ProviderSpec: capi.ProviderSpec{
Value: providerSpec,
},
},
}
}

func createNamespace(client kubernetes.Interface) {
_, err := client.CoreV1().Namespaces().Create(&corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
})
Expect(err).To(BeNil())
}

func getAccountID(prov client.ConfigProvider) string {
stsSvc := sts.NewService(awssts.New(prov))
accountID, err := stsSvc.AccountID()
Expect(err).To(BeNil())
return accountID
}

func createIAMRoles(prov client.ConfigProvider, accountID string) {
cfnSvc := cloudformation.NewService(cfn.New(prov))
Expect(
cfnSvc.ReconcileBootstrapStack(stackName, accountID),
).To(Succeed())
}

func createKeyPair(prov client.ConfigProvider) {
ec2c := ec2.New(prov)
_, err := ec2c.CreateKeyPair(&ec2.CreateKeyPairInput{KeyName: aws.String(keyPairName)})
if code, _ := awserrors.Code(err); code != "InvalidKeyPair.Duplicate" {
Expect(err).To(BeNil())
}
}

func getSession() client.ConfigProvider {
creds := credentials.NewCredentials(&credentials.SharedCredentialsProvider{
Filename: *credFile,
})
sess, err := session.NewSession(aws.NewConfig().WithCredentials(creds).WithRegion(awsRegion))
Expect(err).To(BeNil())
return sess
}
1 change: 1 addition & 0 deletions test/e2e/util/kind/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ go_library(
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
],
)
11 changes: 9 additions & 2 deletions test/e2e/util/kind/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

Expand Down Expand Up @@ -95,10 +96,16 @@ func (c *Cluster) applyYAML() {
))
}

// KubeConfig returns an absolute path to the Kube Config
func (c *Cluster) KubeClient() kubernetes.Interface {
// RestConfig returns a rest configuration pointed at the provisioned cluster
func (c *Cluster) RestConfig() *restclient.Config {
cfg, err := clientcmd.BuildConfigFromFlags("", c.kubepath)
gomega.ExpectWithOffset(1, err).To(gomega.BeNil())
return cfg
}

// KubeClient returns a Kubernetes client pointing at the provisioned cluster
func (c *Cluster) KubeClient() kubernetes.Interface {
cfg := c.RestConfig()
client, err := kubernetes.NewForConfig(cfg)
gomega.ExpectWithOffset(1, err).To(gomega.BeNil())
return client
Expand Down
Loading