diff --git a/test/e2e/cluster_upgrade.go b/test/e2e/cluster_upgrade.go index a8ba5df15b9..0e4539bbf7b 100644 --- a/test/e2e/cluster_upgrade.go +++ b/test/e2e/cluster_upgrade.go @@ -31,6 +31,7 @@ import ( var upgradeTests = []upgrades.Test{ &upgrades.ServiceUpgradeTest{}, + &upgrades.SecretUpgradeTest{}, } var _ = framework.KubeDescribe("Upgrade [Feature:Upgrade]", func() { diff --git a/test/e2e/framework/pods.go b/test/e2e/framework/pods.go index 7907e63fe3d..669f0549087 100644 --- a/test/e2e/framework/pods.go +++ b/test/e2e/framework/pods.go @@ -49,6 +49,16 @@ func (f *Framework) PodClient() *PodClient { } } +// Convenience method for getting a pod client interface in an alternative namespace, +// possibly applying test-suite specific transformations to the pod spec, e.g. for +// node e2e pod scheduling. +func (f *Framework) PodClientNS(namespace string) *PodClient { + return &PodClient{ + f: f, + PodInterface: f.ClientSet.Core().Pods(namespace), + } +} + type PodClient struct { f *Framework v1core.PodInterface diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index 1389bf1d742..558bedc6640 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -2110,8 +2110,11 @@ func (f *Framework) MatchContainerOutput( containerName string, expectedOutput []string, matcher func(string, ...interface{}) gomegatypes.GomegaMatcher) error { - podClient := f.PodClient() - ns := f.Namespace.Name + ns := pod.ObjectMeta.Namespace + if ns == "" { + ns = f.Namespace.Name + } + podClient := f.PodClientNS(ns) createdPod := podClient.Create(pod) defer func() { diff --git a/test/e2e/upgrades/BUILD b/test/e2e/upgrades/BUILD index b2d4125d555..e26811814f3 100644 --- a/test/e2e/upgrades/BUILD +++ b/test/e2e/upgrades/BUILD @@ -10,6 +10,7 @@ load( go_library( name = "go_default_library", srcs = [ + "secrets.go", "services.go", "upgrade.go", ], @@ -18,6 +19,8 @@ go_library( "//pkg/api/v1:go_default_library", "//test/e2e/framework:go_default_library", "//vendor:github.com/onsi/ginkgo", + "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", + "//vendor:k8s.io/apimachinery/pkg/util/uuid", "//vendor:k8s.io/apimachinery/pkg/util/wait", ], ) diff --git a/test/e2e/upgrades/secrets.go b/test/e2e/upgrades/secrets.go new file mode 100644 index 00000000000..29e7c39a6c6 --- /dev/null +++ b/test/e2e/upgrades/secrets.go @@ -0,0 +1,145 @@ +/* +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 upgrades + +import ( + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/uuid" + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/test/e2e/framework" + + . "github.com/onsi/ginkgo" +) + +// SecretUpgradeTest test that a secret is available before and after +// a cluster upgrade. +type SecretUpgradeTest struct { + secret *v1.Secret +} + +// Setup creates a secret and then verifies that a pod can consume it. +func (t *SecretUpgradeTest) Setup(f *framework.Framework) { + secretName := "upgrade-secret" + + // Grab a unique namespace so we don't collide. + ns, err := f.CreateNamespace("secret-upgrade", nil) + framework.ExpectNoError(err) + + t.secret = &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: secretName, + }, + Data: map[string][]byte{ + "data": []byte("keep it secret"), + }, + } + + By("Creating a secret") + if t.secret, err = f.ClientSet.Core().Secrets(ns.Name).Create(t.secret); err != nil { + framework.Failf("unable to create test secret %s: %v", t.secret.Name, err) + } + + By("Making sure the secret is consumable") + t.testPod(f) +} + +// Test waits for the upgrade to complete, and then verifies that a +// pod can still consume the secret. +func (t *SecretUpgradeTest) Test(f *framework.Framework, done <-chan struct{}, upgrade UpgradeType) { + <-done + By("Consuming the secret after upgrade") + t.testPod(f) +} + +// Teardown cleans up any remaining resources. +func (t *SecretUpgradeTest) Teardown(f *framework.Framework) { + // rely on the namespace deletion to clean up everything +} + +// testPod creates a pod that consumes a secret and prints it out. The +// output is then verified. +func (t *SecretUpgradeTest) testPod(f *framework.Framework) { + volumeName := "secret-volume" + volumeMountPath := "/etc/secret-volume" + + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod-secrets-" + string(uuid.NewUUID()), + Namespace: t.secret.ObjectMeta.Namespace, + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: volumeName, + VolumeSource: v1.VolumeSource{ + Secret: &v1.SecretVolumeSource{ + SecretName: t.secret.ObjectMeta.Name, + }, + }, + }, + }, + Containers: []v1.Container{ + { + Name: "secret-volume-test", + Image: "gcr.io/google_containers/mounttest:0.7", + Args: []string{ + fmt.Sprintf("--file_content=%s/data", volumeMountPath), + fmt.Sprintf("--file_mode=%s/data", volumeMountPath), + }, + VolumeMounts: []v1.VolumeMount{ + { + Name: volumeName, + MountPath: volumeMountPath, + }, + }, + }, + { + Name: "secret-env-test", + Image: "gcr.io/google_containers/busybox:1.24", + Command: []string{"sh", "-c", "env"}, + Env: []v1.EnvVar{ + { + Name: "SECRET_DATA", + ValueFrom: &v1.EnvVarSource{ + SecretKeyRef: &v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: t.secret.ObjectMeta.Name, + }, + Key: "data", + }, + }, + }, + }, + }, + }, + RestartPolicy: v1.RestartPolicyNever, + }, + } + + expectedOutput := []string{ + "content of file \"/etc/secret-volume/data\": keep it secret", + "mode of file \"/etc/secret-volume/data\": -rw-r--r--", + } + + f.TestContainerOutput("volume consume secrets", pod, 0, expectedOutput) + + expectedOutput = []string{"SECRET_DATA=keep it secret"} + f.TestContainerOutput("env consume secrets", pod, 1, expectedOutput) +}