-
Notifications
You must be signed in to change notification settings - Fork 580
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
Real e2e #573
Changes from 6 commits
d9b9d65
0b0b123
05957fe
c638833
42fb724
2f98204
6a16332
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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-} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these here only for current test/debugging purposes? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the output of |
||
EOF |
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"], | ||
) |
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" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TOO LATE did it anyway There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.