mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
Fresh dep ensure
This commit is contained in:
57
vendor/k8s.io/kubernetes/test/e2e/common/BUILD
generated
vendored
57
vendor/k8s.io/kubernetes/test/e2e/common/BUILD
generated
vendored
@ -12,6 +12,7 @@ go_library(
|
||||
"autoscaling_utils.go",
|
||||
"configmap.go",
|
||||
"configmap_volume.go",
|
||||
"container.go",
|
||||
"container_probe.go",
|
||||
"docker_containers.go",
|
||||
"downward_api.go",
|
||||
@ -21,51 +22,69 @@ go_library(
|
||||
"expansion.go",
|
||||
"host_path.go",
|
||||
"init_container.go",
|
||||
"kubelet.go",
|
||||
"kubelet_etc_hosts.go",
|
||||
"lifecycle_hook.go",
|
||||
"networking.go",
|
||||
"node_lease.go",
|
||||
"pods.go",
|
||||
"privileged.go",
|
||||
"projected.go",
|
||||
"projected_combined.go",
|
||||
"projected_configmap.go",
|
||||
"projected_downwardapi.go",
|
||||
"projected_secret.go",
|
||||
"runtime.go",
|
||||
"secrets.go",
|
||||
"secrets_volume.go",
|
||||
"security_context.go",
|
||||
"sysctl.go",
|
||||
"ttlafterfinished.go",
|
||||
"util.go",
|
||||
"volumes.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/test/e2e/common",
|
||||
deps = [
|
||||
"//pkg/api/v1/node:go_default_library",
|
||||
"//pkg/api/v1/pod:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/conditions:go_default_library",
|
||||
"//pkg/kubelet:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/kubelet/images:go_default_library",
|
||||
"//pkg/kubelet/sysctl:go_default_library",
|
||||
"//pkg/security/apparmor:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//pkg/util/slice:go_default_library",
|
||||
"//staging/src/k8s.io/api/autoscaling/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/batch/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/coordination/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/scale:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/watch:go_default_library",
|
||||
"//test/e2e/framework:go_default_library",
|
||||
"//test/utils:go_default_library",
|
||||
"//test/utils/image:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/onsi/ginkgo:go_default_library",
|
||||
"//vendor/github.com/onsi/gomega:go_default_library",
|
||||
"//vendor/github.com/onsi/gomega/types:go_default_library",
|
||||
"//vendor/golang.org/x/net/websocket:go_default_library",
|
||||
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/scale:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
2
vendor/k8s.io/kubernetes/test/e2e/common/apparmor.go
generated
vendored
2
vendor/k8s.io/kubernetes/test/e2e/common/apparmor.go
generated
vendored
@ -117,7 +117,7 @@ done`, testCmd)
|
||||
Affinity: loaderAffinity,
|
||||
Containers: []api.Container{{
|
||||
Name: "test",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", testCmd},
|
||||
}},
|
||||
RestartPolicy: api.RestartPolicyNever,
|
||||
|
26
vendor/k8s.io/kubernetes/test/e2e/common/autoscaling_utils.go
generated
vendored
26
vendor/k8s.io/kubernetes/test/e2e/common/autoscaling_utils.go
generated
vendored
@ -43,7 +43,7 @@ import (
|
||||
const (
|
||||
dynamicConsumptionTimeInSeconds = 30
|
||||
staticConsumptionTimeInSeconds = 3600
|
||||
dynamicRequestSizeInMillicores = 20
|
||||
dynamicRequestSizeInMillicores = 100
|
||||
dynamicRequestSizeInMegabytes = 100
|
||||
dynamicRequestSizeCustomMetric = 10
|
||||
port = 80
|
||||
@ -359,6 +359,10 @@ func (rc *ResourceConsumer) GetReplicas() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rc *ResourceConsumer) GetHpa(name string) (*autoscalingv1.HorizontalPodAutoscaler, error) {
|
||||
return rc.clientSet.AutoscalingV1().HorizontalPodAutoscalers(rc.nsName).Get(name, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (rc *ResourceConsumer) WaitForReplicas(desiredReplicas int, duration time.Duration) {
|
||||
interval := 20 * time.Second
|
||||
err := wait.PollImmediate(interval, duration, func() (bool, error) {
|
||||
@ -369,13 +373,25 @@ func (rc *ResourceConsumer) WaitForReplicas(desiredReplicas int, duration time.D
|
||||
framework.ExpectNoErrorWithOffset(1, err, "timeout waiting %v for %d replicas", duration, desiredReplicas)
|
||||
}
|
||||
|
||||
func (rc *ResourceConsumer) EnsureDesiredReplicas(desiredReplicas int, duration time.Duration) {
|
||||
func (rc *ResourceConsumer) EnsureDesiredReplicas(desiredReplicas int, duration time.Duration, hpaName string) {
|
||||
rc.EnsureDesiredReplicasInRange(desiredReplicas, desiredReplicas, duration, hpaName)
|
||||
}
|
||||
|
||||
func (rc *ResourceConsumer) EnsureDesiredReplicasInRange(minDesiredReplicas, maxDesiredReplicas int, duration time.Duration, hpaName string) {
|
||||
interval := 10 * time.Second
|
||||
err := wait.PollImmediate(interval, duration, func() (bool, error) {
|
||||
replicas := rc.GetReplicas()
|
||||
framework.Logf("expecting there to be %d replicas (are: %d)", desiredReplicas, replicas)
|
||||
if replicas != desiredReplicas {
|
||||
return false, fmt.Errorf("number of replicas changed unexpectedly")
|
||||
framework.Logf("expecting there to be in [%d, %d] replicas (are: %d)", minDesiredReplicas, maxDesiredReplicas, replicas)
|
||||
as, err := rc.GetHpa(hpaName)
|
||||
if err != nil {
|
||||
framework.Logf("Error getting HPA: %s", err)
|
||||
} else {
|
||||
framework.Logf("HPA status: %+v", as.Status)
|
||||
}
|
||||
if replicas < minDesiredReplicas {
|
||||
return false, fmt.Errorf("number of replicas below target")
|
||||
} else if replicas > maxDesiredReplicas {
|
||||
return false, fmt.Errorf("number of replicas above target")
|
||||
} else {
|
||||
return false, nil // Expected number of replicas found. Continue polling until timeout.
|
||||
}
|
||||
|
41
vendor/k8s.io/kubernetes/test/e2e/common/configmap.go
generated
vendored
41
vendor/k8s.io/kubernetes/test/e2e/common/configmap.go
generated
vendored
@ -20,19 +20,21 @@ import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
)
|
||||
|
||||
var _ = Describe("[sig-api-machinery] ConfigMap", func() {
|
||||
var _ = Describe("[sig-node] ConfigMap", func() {
|
||||
f := framework.NewDefaultFramework("configmap")
|
||||
|
||||
/*
|
||||
Testname: configmap-in-env-field
|
||||
Description: Make sure config map value can be used as an environment
|
||||
variable in the container (on container.env field)
|
||||
Release : v1.9
|
||||
Testname: ConfigMap, from environment field
|
||||
Description: Create a Pod with an environment variable value set using a value from ConfigMap. A ConfigMap value MUST be accessible in the container environment.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable via environment variable [NodeConformance]", func() {
|
||||
name := "configmap-test-" + string(uuid.NewUUID())
|
||||
@ -51,7 +53,7 @@ var _ = Describe("[sig-api-machinery] ConfigMap", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "env-test",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
@ -78,9 +80,9 @@ var _ = Describe("[sig-api-machinery] ConfigMap", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: configmap-envfrom-field
|
||||
Description: Make sure config map value can be used as an source for
|
||||
environment variables in the container (on container.envFrom field)
|
||||
Release: v1.9
|
||||
Testname: ConfigMap, from environment variables
|
||||
Description: Create a Pod with a environment source from ConfigMap. All ConfigMap values MUST be available as environment variables in the container.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable via the environment [NodeConformance]", func() {
|
||||
name := "configmap-test-" + string(uuid.NewUUID())
|
||||
@ -99,7 +101,7 @@ var _ = Describe("[sig-api-machinery] ConfigMap", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "env-test",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
@ -121,6 +123,11 @@ var _ = Describe("[sig-api-machinery] ConfigMap", func() {
|
||||
"p_data_1=value-1", "p_data_2=value-2", "p_data_3=value-3",
|
||||
})
|
||||
})
|
||||
|
||||
It("should fail to create configMap in volume due to empty configmap key", func() {
|
||||
configMap, err := newConfigMapWithEmptyKey(f)
|
||||
Expect(err).To(HaveOccurred(), "created configMap %q with empty key in namespace %q", configMap.Name, f.Namespace.Name)
|
||||
})
|
||||
})
|
||||
|
||||
func newEnvFromConfigMap(f *framework.Framework, name string) *v1.ConfigMap {
|
||||
@ -136,3 +143,19 @@ func newEnvFromConfigMap(f *framework.Framework, name string) *v1.ConfigMap {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigMapWithEmptyKey(f *framework.Framework) (*v1.ConfigMap, error) {
|
||||
name := "configmap-test-emptyKey-" + string(uuid.NewUUID())
|
||||
configMap := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: name,
|
||||
},
|
||||
Data: map[string]string{
|
||||
"": "value-1",
|
||||
},
|
||||
}
|
||||
|
||||
By(fmt.Sprintf("Creating configMap that has name %s", configMap.Name))
|
||||
return f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap)
|
||||
}
|
||||
|
212
vendor/k8s.io/kubernetes/test/e2e/common/configmap_volume.go
generated
vendored
212
vendor/k8s.io/kubernetes/test/e2e/common/configmap_volume.go
generated
vendored
@ -27,24 +27,25 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
)
|
||||
|
||||
var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
f := framework.NewDefaultFramework("configmap")
|
||||
|
||||
/*
|
||||
Testname: configmap-nomap-simple
|
||||
Description: Make sure config map without mappings works by mounting it
|
||||
to a volume with a custom path (mapping) on the pod with no other settings.
|
||||
Release : v1.9
|
||||
Testname: ConfigMap Volume, without mapping
|
||||
Description: Create a ConfigMap, create a Pod that mounts a volume and populates the volume with data stored in the ConfigMap. The ConfigMap that is created MUST be accessible to read from the newly created Pod using the volume mount. The data content of the file MUST be readable and verified and file modes MUST default to 0x644.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume [NodeConformance]", func() {
|
||||
doConfigMapE2EWithoutMappings(f, 0, 0, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: configmap-nomap-default-mode
|
||||
Description: Make sure config map without mappings works by mounting it
|
||||
to a volume with a custom path (mapping) on the pod with defaultMode set
|
||||
Release : v1.9
|
||||
Testname: ConfigMap Volume, without mapping, volume mode set
|
||||
Description: Create a ConfigMap, create a Pod that mounts a volume and populates the volume with data stored in the ConfigMap. File mode is changed to a custom value of '0x400'. The ConfigMap that is created MUST be accessible to read from the newly created Pod using the volume mount. The data content of the file MUST be readable and verified and file modes MUST be set to the custom value of ‘0x400’
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with defaultMode set [NodeConformance]", func() {
|
||||
defaultMode := int32(0400)
|
||||
@ -57,9 +58,9 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: configmap-nomap-user
|
||||
Description: Make sure config map without mappings works by mounting it
|
||||
to a volume with a custom path (mapping) on the pod as non-root.
|
||||
Release : v1.9
|
||||
Testname: ConfigMap Volume, without mapping, non-root user
|
||||
Description: Create a ConfigMap, create a Pod that mounts a volume and populates the volume with data stored in the ConfigMap. Pod is run as a non-root user with uid=1000. The ConfigMap that is created MUST be accessible to read from the newly created Pod using the volume mount. The file on the volume MUST have file mode set to default value of 0x644.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume as non-root [NodeConformance]", func() {
|
||||
doConfigMapE2EWithoutMappings(f, 1000, 0, nil)
|
||||
@ -70,19 +71,18 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: configmap-simple-mapped
|
||||
Description: Make sure config map works by mounting it to a volume with
|
||||
a custom path (mapping) on the pod with no other settings and make sure
|
||||
the pod actually consumes it.
|
||||
Release : v1.9
|
||||
Testname: ConfigMap Volume, with mapping
|
||||
Description: Create a ConfigMap, create a Pod that mounts a volume and populates the volume with data stored in the ConfigMap. Files are mapped to a path in the volume. The ConfigMap that is created MUST be accessible to read from the newly created Pod using the volume mount. The data content of the file MUST be readable and verified and file modes MUST default to 0x644.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings [NodeConformance]", func() {
|
||||
doConfigMapE2EWithMappings(f, 0, 0, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: configmap-with-item-mode-mapped
|
||||
Description: Make sure config map works with an item mode (e.g. 0400)
|
||||
for the config map item.
|
||||
Release : v1.9
|
||||
Testname: ConfigMap Volume, with mapping, volume mode set
|
||||
Description: Create a ConfigMap, create a Pod that mounts a volume and populates the volume with data stored in the ConfigMap. Files are mapped to a path in the volume. File mode is changed to a custom value of '0x400'. The ConfigMap that is created MUST be accessible to read from the newly created Pod using the volume mount. The data content of the file MUST be readable and verified and file modes MUST be set to the custom value of ‘0x400’
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings and Item mode set [NodeConformance]", func() {
|
||||
mode := int32(0400)
|
||||
@ -90,8 +90,9 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: configmap-simple-user-mapped
|
||||
Description: Make sure config map works when it is mounted as non-root.
|
||||
Release : v1.9
|
||||
Testname: ConfigMap Volume, with mapping, non-root user
|
||||
Description: Create a ConfigMap, create a Pod that mounts a volume and populates the volume with data stored in the ConfigMap. Files are mapped to a path in the volume. Pod is run as a non-root user with uid=1000. The ConfigMap that is created MUST be accessible to read from the newly created Pod using the volume mount. The file on the volume MUST have file mode set to default value of 0x644.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings as non-root [NodeConformance]", func() {
|
||||
doConfigMapE2EWithMappings(f, 1000, 0, nil)
|
||||
@ -102,9 +103,9 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: configmap-update-test
|
||||
Description: Make sure update operation is working on config map and
|
||||
the result is observed on volumes mounted in containers.
|
||||
Release : v1.9
|
||||
Testname: ConfigMap Volume, update
|
||||
Description: The ConfigMap that is created MUST be accessible to read from the newly created Pod using the volume mount that is mapped to custom path in the Pod. When the ConfigMap is updated the change to the config map MUST be verified by reading the content from the mounted file in the Pod.
|
||||
*/
|
||||
framework.ConformanceIt("updates should be reflected in volume [NodeConformance]", func() {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
@ -151,7 +152,7 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: containerName,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volume/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -184,7 +185,12 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
Eventually(pollLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-2"))
|
||||
})
|
||||
|
||||
It("binary data should be reflected in volume [NodeConformance]", func() {
|
||||
/*
|
||||
Release: v1.12
|
||||
Testname: ConfigMap Volume, text data, binary data
|
||||
Description: The ConfigMap that is created with text data and binary data MUST be accessible to read from the newly created Pod using the volume mount that is mapped to custom path in the Pod. ConfigMap's text data and binary data MUST be verified by reading the content from the mounted files in the Pod.
|
||||
*/
|
||||
framework.ConformanceIt("binary data should be reflected in volume [NodeConformance]", func() {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
|
||||
|
||||
@ -233,7 +239,7 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: containerName1,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volume/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -245,7 +251,7 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
},
|
||||
{
|
||||
Name: containerName2,
|
||||
Image: "busybox",
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"hexdump", "-C", "/etc/configmap-volume/dump.bin"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -276,9 +282,9 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: configmap-CUD-test
|
||||
Description: Make sure Create, Update, Delete operations are all working
|
||||
on config map and the result is observed on volumes mounted in containers.
|
||||
Release : v1.9
|
||||
Testname: ConfigMap Volume, create, update and delete
|
||||
Description: The ConfigMap that is created MUST be accessible to read from the newly created Pod using the volume mount that is mapped to custom path in the Pod. When the config map is updated the change to the config map MUST be verified by reading the content from the mounted file in the Pod. Also when the item(file) is deleted from the map that MUST result in a error reading that item(file).
|
||||
*/
|
||||
framework.ConformanceIt("optional updates should be reflected in volume [NodeConformance]", func() {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
@ -379,7 +385,7 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: deleteContainerName,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/delete/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -391,7 +397,7 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
},
|
||||
{
|
||||
Name: updateContainerName,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/update/data-3"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -403,7 +409,7 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
},
|
||||
{
|
||||
Name: createContainerName,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/create/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -459,9 +465,9 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: configmap-multiple-volumes
|
||||
Description: Make sure config map works when it mounted as two different
|
||||
volumes on the same node.
|
||||
Release : v1.9
|
||||
Testname: ConfigMap Volume, multiple volume maps
|
||||
Description: The ConfigMap that is created MUST be accessible to read from the newly created Pod using the volume mount that is mapped to multiple paths in the Pod. The content MUST be accessible from all the mapped volume mounts.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable in multiple volumes in the same pod [NodeConformance]", func() {
|
||||
var (
|
||||
@ -509,7 +515,7 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "configmap-volume-test",
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{"--file_content=/etc/configmap-volume/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -534,6 +540,26 @@ var _ = Describe("[sig-storage] ConfigMap", func() {
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
//The pod is in pending during volume creation until the configMap objects are available
|
||||
//or until mount the configMap volume times out. There is no configMap object defined for the pod, so it should return timout exception unless it is marked optional.
|
||||
//Slow (~5 mins)
|
||||
It("Should fail non-optional pod creation due to configMap object does not exist [Slow]", func() {
|
||||
volumeMountPath := "/etc/configmap-volumes"
|
||||
podName := "pod-configmaps-" + string(uuid.NewUUID())
|
||||
err := createNonOptionalConfigMapPod(f, volumeMountPath, podName)
|
||||
Expect(err).To(HaveOccurred(), "created pod %q with non-optional configMap in namespace %q", podName, f.Namespace.Name)
|
||||
})
|
||||
|
||||
//ConfigMap object defined for the pod, If a key is specified which is not present in the ConfigMap,
|
||||
// the volume setup will error unless it is marked optional, during the pod creation.
|
||||
//Slow (~5 mins)
|
||||
It("Should fail non-optional pod creation due to the key in the configMap object does not exist [Slow]", func() {
|
||||
volumeMountPath := "/etc/configmap-volumes"
|
||||
podName := "pod-configmaps-" + string(uuid.NewUUID())
|
||||
err := createNonOptionalConfigMapPodWithConfig(f, volumeMountPath, podName)
|
||||
Expect(err).To(HaveOccurred(), "created pod %q with non-optional configMap in namespace %q", podName, f.Namespace.Name)
|
||||
})
|
||||
})
|
||||
|
||||
func newConfigMap(f *framework.Framework, name string) *v1.ConfigMap {
|
||||
@ -589,7 +615,7 @@ func doConfigMapE2EWithoutMappings(f *framework.Framework, uid, fsGroup int64, d
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "configmap-volume-test",
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{
|
||||
"--file_content=/etc/configmap-volume/data-1",
|
||||
"--file_mode=/etc/configmap-volume/data-1"},
|
||||
@ -675,7 +701,7 @@ func doConfigMapE2EWithMappings(f *framework.Framework, uid, fsGroup int64, item
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "configmap-volume-test",
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{"--file_content=/etc/configmap-volume/path/to/data-2",
|
||||
"--file_mode=/etc/configmap-volume/path/to/data-2"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
@ -718,3 +744,115 @@ func doConfigMapE2EWithMappings(f *framework.Framework, uid, fsGroup int64, item
|
||||
}
|
||||
f.TestContainerOutput("consume configMaps", pod, 0, output)
|
||||
}
|
||||
|
||||
func createNonOptionalConfigMapPod(f *framework.Framework, volumeMountPath, podName string) error {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
|
||||
falseValue := false
|
||||
|
||||
createName := "cm-test-opt-create-" + string(uuid.NewUUID())
|
||||
createContainerName := "createcm-volume-test"
|
||||
createVolumeName := "createcm-volume"
|
||||
|
||||
//creating a pod without configMap object created, by mentioning the configMap volume source's local reference name
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: createName,
|
||||
},
|
||||
Optional: &falseValue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: createContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/create/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "create"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
By("Creating the pod")
|
||||
pod = f.PodClient().Create(pod)
|
||||
return f.WaitForPodRunning(pod.Name)
|
||||
}
|
||||
|
||||
func createNonOptionalConfigMapPodWithConfig(f *framework.Framework, volumeMountPath, podName string) error {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
|
||||
falseValue := false
|
||||
|
||||
createName := "cm-test-opt-create-" + string(uuid.NewUUID())
|
||||
createContainerName := "createcm-volume-test"
|
||||
createVolumeName := "createcm-volume"
|
||||
configMap := newConfigMap(f, createName)
|
||||
|
||||
By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
|
||||
var err error
|
||||
if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
||||
}
|
||||
//creating a pod with configMap object, but with different key which is not present in configMap object.
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: createName,
|
||||
},
|
||||
Items: []v1.KeyToPath{
|
||||
{
|
||||
Key: "data-4",
|
||||
Path: "path/to/data-4",
|
||||
},
|
||||
},
|
||||
Optional: &falseValue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: createContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/create/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "create"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
By("Creating the pod")
|
||||
pod = f.PodClient().Create(pod)
|
||||
return f.WaitForPodRunning(pod.Name)
|
||||
}
|
||||
|
134
vendor/k8s.io/kubernetes/test/e2e/common/container.go
generated
vendored
Normal file
134
vendor/k8s.io/kubernetes/test/e2e/common/container.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
Copyright 2016 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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
)
|
||||
|
||||
const (
|
||||
ContainerStatusRetryTimeout = time.Minute * 5
|
||||
ContainerStatusPollInterval = time.Second * 1
|
||||
)
|
||||
|
||||
// One pod one container
|
||||
type ConformanceContainer struct {
|
||||
Container v1.Container
|
||||
RestartPolicy v1.RestartPolicy
|
||||
Volumes []v1.Volume
|
||||
ImagePullSecrets []string
|
||||
|
||||
PodClient *framework.PodClient
|
||||
podName string
|
||||
PodSecurityContext *v1.PodSecurityContext
|
||||
}
|
||||
|
||||
func (cc *ConformanceContainer) Create() {
|
||||
cc.podName = cc.Container.Name + string(uuid.NewUUID())
|
||||
imagePullSecrets := []v1.LocalObjectReference{}
|
||||
for _, s := range cc.ImagePullSecrets {
|
||||
imagePullSecrets = append(imagePullSecrets, v1.LocalObjectReference{Name: s})
|
||||
}
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: cc.podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: cc.RestartPolicy,
|
||||
Containers: []v1.Container{
|
||||
cc.Container,
|
||||
},
|
||||
SecurityContext: cc.PodSecurityContext,
|
||||
Volumes: cc.Volumes,
|
||||
ImagePullSecrets: imagePullSecrets,
|
||||
},
|
||||
}
|
||||
cc.PodClient.Create(pod)
|
||||
}
|
||||
|
||||
func (cc *ConformanceContainer) Delete() error {
|
||||
return cc.PodClient.Delete(cc.podName, metav1.NewDeleteOptions(0))
|
||||
}
|
||||
|
||||
func (cc *ConformanceContainer) IsReady() (bool, error) {
|
||||
pod, err := cc.PodClient.Get(cc.podName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return podutil.IsPodReady(pod), nil
|
||||
}
|
||||
|
||||
func (cc *ConformanceContainer) GetPhase() (v1.PodPhase, error) {
|
||||
pod, err := cc.PodClient.Get(cc.podName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return v1.PodUnknown, err
|
||||
}
|
||||
return pod.Status.Phase, nil
|
||||
}
|
||||
|
||||
func (cc *ConformanceContainer) GetStatus() (v1.ContainerStatus, error) {
|
||||
pod, err := cc.PodClient.Get(cc.podName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return v1.ContainerStatus{}, err
|
||||
}
|
||||
statuses := pod.Status.ContainerStatuses
|
||||
if len(statuses) != 1 || statuses[0].Name != cc.Container.Name {
|
||||
return v1.ContainerStatus{}, fmt.Errorf("unexpected container statuses %v", statuses)
|
||||
}
|
||||
return statuses[0], nil
|
||||
}
|
||||
|
||||
func (cc *ConformanceContainer) Present() (bool, error) {
|
||||
_, err := cc.PodClient.Get(cc.podName, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if errors.IsNotFound(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
type ContainerState string
|
||||
|
||||
const (
|
||||
ContainerStateWaiting ContainerState = "Waiting"
|
||||
ContainerStateRunning ContainerState = "Running"
|
||||
ContainerStateTerminated ContainerState = "Terminated"
|
||||
ContainerStateUnknown ContainerState = "Unknown"
|
||||
)
|
||||
|
||||
func GetContainerState(state v1.ContainerState) ContainerState {
|
||||
if state.Waiting != nil {
|
||||
return ContainerStateWaiting
|
||||
}
|
||||
if state.Running != nil {
|
||||
return ContainerStateRunning
|
||||
}
|
||||
if state.Terminated != nil {
|
||||
return ContainerStateTerminated
|
||||
}
|
||||
return ContainerStateUnknown
|
||||
}
|
57
vendor/k8s.io/kubernetes/test/e2e/common/container_probe.go
generated
vendored
57
vendor/k8s.io/kubernetes/test/e2e/common/container_probe.go
generated
vendored
@ -50,9 +50,9 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-readiness-probe-initial-delay
|
||||
Description: Make sure that pod with readiness probe should not be
|
||||
ready before initial delay and never restart.
|
||||
Release : v1.9
|
||||
Testname: Pod readiness probe, with initial delay
|
||||
Description: Create a Pod that is configured with a initial delay set on the readiness probe. Check the Pod Start time to compare to the initial delay. The Pod MUST be ready only after the specified initial delay.
|
||||
*/
|
||||
framework.ConformanceIt("with readiness probe should not be ready before initial delay and never restart [NodeConformance]", func() {
|
||||
p := podClient.Create(makePodSpec(probe.withInitialDelay().build(), nil))
|
||||
@ -82,9 +82,10 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-readiness-probe-failure
|
||||
Description: Make sure that pod with readiness probe that fails should
|
||||
never be ready and never restart.
|
||||
Release : v1.9
|
||||
Testname: Pod readiness probe, failure
|
||||
Description: Create a Pod with a readiness probe that fails consistently. When this Pod is created,
|
||||
then the Pod MUST never be ready, never be running and restart count MUST be zero.
|
||||
*/
|
||||
framework.ConformanceIt("with readiness probe that fails should never be ready and never restart [NodeConformance]", func() {
|
||||
p := podClient.Create(makePodSpec(probe.withFailing().build(), nil))
|
||||
@ -107,9 +108,9 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-cat-liveness-probe-restarted
|
||||
Description: Make sure the pod is restarted with a cat /tmp/health
|
||||
liveness probe.
|
||||
Release : v1.9
|
||||
Testname: Pod liveness probe, using local file, restart
|
||||
Description: Create a Pod with liveness probe that uses ExecAction handler to cat /temp/health file. The Container deletes the file /temp/health after 10 second, triggering liveness probe to fail. The Pod MUST now be killed and restarted incrementing restart count to 1.
|
||||
*/
|
||||
framework.ConformanceIt("should be restarted with a exec \"cat /tmp/health\" liveness probe [NodeConformance]", func() {
|
||||
runLivenessTest(f, &v1.Pod{
|
||||
@ -121,7 +122,7 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "liveness",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/sh", "-c", "echo ok >/tmp/health; sleep 10; rm -rf /tmp/health; sleep 600"},
|
||||
LivenessProbe: &v1.Probe{
|
||||
Handler: v1.Handler{
|
||||
@ -139,9 +140,9 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-cat-liveness-probe-not-restarted
|
||||
Description: Make sure the pod is not restarted with a cat /tmp/health
|
||||
liveness probe.
|
||||
Release : v1.9
|
||||
Testname: Pod liveness probe, using local file, no restart
|
||||
Description: Pod is created with liveness probe that uses ‘exec’ command to cat /temp/health file. Liveness probe MUST not fail to check health and the restart count should remain 0.
|
||||
*/
|
||||
framework.ConformanceIt("should *not* be restarted with a exec \"cat /tmp/health\" liveness probe [NodeConformance]", func() {
|
||||
runLivenessTest(f, &v1.Pod{
|
||||
@ -153,7 +154,7 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "liveness",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/sh", "-c", "echo ok >/tmp/health; sleep 600"},
|
||||
LivenessProbe: &v1.Probe{
|
||||
Handler: v1.Handler{
|
||||
@ -171,9 +172,9 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-http-liveness-probe-restarted
|
||||
Description: Make sure when http liveness probe fails, the pod should
|
||||
be restarted.
|
||||
Release : v1.9
|
||||
Testname: Pod liveness probe, using http endpoint, restart
|
||||
Description: A Pod is created with liveness probe on http endpoint /healthz. The http handler on the /healthz will return a http error after 10 seconds since the Pod is started. This MUST result in liveness check failure. The Pod MUST now be killed and restarted incrementing restart count to 1.
|
||||
*/
|
||||
framework.ConformanceIt("should be restarted with a /healthz http liveness probe [NodeConformance]", func() {
|
||||
runLivenessTest(f, &v1.Pod{
|
||||
@ -205,9 +206,9 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
|
||||
// Slow by design (5 min)
|
||||
/*
|
||||
Testname: pods-restart-count
|
||||
Description: Make sure when a pod gets restarted, its start count
|
||||
should increase.
|
||||
Release : v1.9
|
||||
Testname: Pod liveness probe, using http endpoint, multiple restarts (slow)
|
||||
Description: A Pod is created with liveness probe on http endpoint /healthz. The http handler on the /healthz will return a http error after 10 seconds since the Pod is started. This MUST result in liveness check failure. The Pod MUST now be killed and restarted incrementing restart count to 1. The liveness probe must fail again after restart once the http handler for /healthz enpoind on the Pod returns an http error after 10 seconds from the start. Restart counts MUST increment everytime health check fails, measure upto 5 restart.
|
||||
*/
|
||||
framework.ConformanceIt("should have monotonically increasing restart count [Slow][NodeConformance]", func() {
|
||||
runLivenessTest(f, &v1.Pod{
|
||||
@ -238,9 +239,9 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-http-liveness-probe-not-restarted
|
||||
Description: Make sure when http liveness probe succeeds, the pod
|
||||
should not be restarted.
|
||||
Release : v1.9
|
||||
Testname: Pod liveness probe, using http endpoint, failure
|
||||
Description: A Pod is created with liveness probe on http endpoint ‘/’. Liveness probe on this endpoint will not fail. When liveness probe does not fail then the restart count MUST remain zero.
|
||||
*/
|
||||
framework.ConformanceIt("should *not* be restarted with a /healthz http liveness probe [NodeConformance]", func() {
|
||||
runLivenessTest(f, &v1.Pod{
|
||||
@ -252,7 +253,7 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "liveness",
|
||||
Image: imageutils.GetE2EImage(imageutils.NginxSlim),
|
||||
Image: imageutils.GetE2EImage(imageutils.Nginx),
|
||||
Ports: []v1.ContainerPort{{ContainerPort: 80}},
|
||||
LivenessProbe: &v1.Probe{
|
||||
Handler: v1.Handler{
|
||||
@ -272,9 +273,9 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-docker-liveness-probe-timeout
|
||||
Description: Make sure that the pod is restarted with a docker exec
|
||||
liveness probe with timeout.
|
||||
Release : v1.9
|
||||
Testname: Pod liveness probe, docker exec, restart
|
||||
Description: A Pod is created with liveness probe with a Exec action on the Pod. If the liveness probe call does not return within the timeout specified, liveness probe MUST restart the Pod.
|
||||
*/
|
||||
It("should be restarted with a docker exec liveness probe with timeout ", func() {
|
||||
// TODO: enable this test once the default exec handler supports timeout.
|
||||
@ -288,7 +289,7 @@ var _ = framework.KubeDescribe("Probing container", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "liveness",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/sh", "-c", "sleep 600"},
|
||||
LivenessProbe: &v1.Probe{
|
||||
Handler: v1.Handler{
|
||||
|
28
vendor/k8s.io/kubernetes/test/e2e/common/docker_containers.go
generated
vendored
28
vendor/k8s.io/kubernetes/test/e2e/common/docker_containers.go
generated
vendored
@ -28,10 +28,9 @@ var _ = framework.KubeDescribe("Docker Containers", func() {
|
||||
f := framework.NewDefaultFramework("containers")
|
||||
|
||||
/*
|
||||
Testname: container-without-command-args
|
||||
Description: When a Pod is created neither 'command' nor 'args' are
|
||||
provided for a Container, ensure that the docker image's default
|
||||
command and args are used.
|
||||
Release : v1.9
|
||||
Testname: Docker containers, without command and arguments
|
||||
Description: Default command and arguments from the docker image entrypoint MUST be used when Pod does not specify the container command
|
||||
*/
|
||||
framework.ConformanceIt("should use the image defaults if command and args are blank [NodeConformance]", func() {
|
||||
f.TestContainerOutput("use defaults", entrypointTestPod(), 0, []string{
|
||||
@ -40,10 +39,9 @@ var _ = framework.KubeDescribe("Docker Containers", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: container-with-args
|
||||
Description: When a Pod is created and 'args' are provided for a
|
||||
Container, ensure that they take precedent to the docker image's
|
||||
default arguments, but that the default command is used.
|
||||
Release : v1.9
|
||||
Testname: Docker containers, with arguments
|
||||
Description: Default command and from the docker image entrypoint MUST be used when Pod does not specify the container command but the arguments from Pod spec MUST override when specified.
|
||||
*/
|
||||
framework.ConformanceIt("should be able to override the image's default arguments (docker cmd) [NodeConformance]", func() {
|
||||
pod := entrypointTestPod()
|
||||
@ -57,10 +55,9 @@ var _ = framework.KubeDescribe("Docker Containers", func() {
|
||||
// Note: when you override the entrypoint, the image's arguments (docker cmd)
|
||||
// are ignored.
|
||||
/*
|
||||
Testname: container-with-command
|
||||
Description: When a Pod is created and 'command' is provided for a
|
||||
Container, ensure that it takes precedent to the docker image's default
|
||||
command.
|
||||
Release : v1.9
|
||||
Testname: Docker containers, with command
|
||||
Description: Default command from the docker image entrypoint MUST NOT be used when Pod specifies the container command. Command from Pod spec MUST override the command in the image.
|
||||
*/
|
||||
framework.ConformanceIt("should be able to override the image's default command (docker entrypoint) [NodeConformance]", func() {
|
||||
pod := entrypointTestPod()
|
||||
@ -72,10 +69,9 @@ var _ = framework.KubeDescribe("Docker Containers", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: container-with-command-args
|
||||
Description: When a Pod is created and 'command' and 'args' are
|
||||
provided for a Container, ensure that they take precedent to the docker
|
||||
image's default command and arguments.
|
||||
Release : v1.9
|
||||
Testname: Docker containers, with command and arguments
|
||||
Description: Default command and arguments from the docker image entrypoint MUST NOT be used when Pod specifies the container command and arguments. Command and arguments from Pod spec MUST override the command and arguments in the image.
|
||||
*/
|
||||
framework.ConformanceIt("should be able to override the image's default command and arguments [NodeConformance]", func() {
|
||||
pod := entrypointTestPod()
|
||||
|
44
vendor/k8s.io/kubernetes/test/e2e/common/downward_api.go
generated
vendored
44
vendor/k8s.io/kubernetes/test/e2e/common/downward_api.go
generated
vendored
@ -23,8 +23,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
utilversion "k8s.io/kubernetes/pkg/util/version"
|
||||
utilversion "k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
)
|
||||
@ -34,13 +35,13 @@ var (
|
||||
podUIDVersion = utilversion.MustParseSemantic("v1.8.0")
|
||||
)
|
||||
|
||||
var _ = Describe("[sig-api-machinery] Downward API", func() {
|
||||
var _ = Describe("[sig-node] Downward API", func() {
|
||||
f := framework.NewDefaultFramework("downward-api")
|
||||
|
||||
/*
|
||||
Testname: downwardapi-env-name-namespace-podip
|
||||
Description: Ensure that downward API can provide pod's name, namespace
|
||||
and IP address as environment variables.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI, environment for name, namespace and ip
|
||||
Description: Downward API MUST expose Pod and Container fields as environment variables. Specify Pod Name, namespace and IP as environment variable in the Pod Spec are visible at runtime in the container.
|
||||
*/
|
||||
framework.ConformanceIt("should provide pod name, namespace and IP address as env vars [NodeConformance]", func() {
|
||||
podName := "downward-api-" + string(uuid.NewUUID())
|
||||
@ -84,9 +85,9 @@ var _ = Describe("[sig-api-machinery] Downward API", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-env-host-ip
|
||||
Description: Ensure that downward API can provide an IP address for
|
||||
host node as an environment variable.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI, environment for host ip
|
||||
Description: Downward API MUST expose Pod and Container fields as environment variables. Specify host IP as environment variable in the Pod Spec are visible at runtime in the container.
|
||||
*/
|
||||
framework.ConformanceIt("should provide host IP as an env var [NodeConformance]", func() {
|
||||
framework.SkipUnlessServerVersionGTE(hostIPVersion, f.ClientSet.Discovery())
|
||||
@ -111,9 +112,9 @@ var _ = Describe("[sig-api-machinery] Downward API", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-env-limits-requests
|
||||
Description: Ensure that downward API can provide CPU/memory limit
|
||||
and CPU/memory request as environment variables.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI, environment for CPU and memory limits and requests
|
||||
Description: Downward API MUST expose CPU request amd Memory request set through environment variables at runtime in the container.
|
||||
*/
|
||||
framework.ConformanceIt("should provide container's limits.cpu/memory and requests.cpu/memory as env vars [NodeConformance]", func() {
|
||||
podName := "downward-api-" + string(uuid.NewUUID())
|
||||
@ -162,10 +163,9 @@ var _ = Describe("[sig-api-machinery] Downward API", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-env-default-allocatable
|
||||
Description: Ensure that downward API can provide default node
|
||||
allocatable values for CPU and memory as environment variables if CPU
|
||||
and memory limits are not specified for a container.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI, environment for default CPU and memory limits and requests
|
||||
Description: Downward API MUST expose CPU request amd Memory limits set through environment variables at runtime in the container.
|
||||
*/
|
||||
framework.ConformanceIt("should provide default limits.cpu/memory from node allocatable [NodeConformance]", func() {
|
||||
podName := "downward-api-" + string(uuid.NewUUID())
|
||||
@ -200,7 +200,7 @@ var _ = Describe("[sig-api-machinery] Downward API", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
Env: env,
|
||||
},
|
||||
@ -213,9 +213,9 @@ var _ = Describe("[sig-api-machinery] Downward API", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-env-pod-uid
|
||||
Description: Ensure that downward API can provide pod UID as an
|
||||
environment variable.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI, environment for Pod UID
|
||||
Description: Downward API MUST expose Pod UID set through environment variables at runtime in the container.
|
||||
*/
|
||||
framework.ConformanceIt("should provide pod UID as env vars [NodeConformance]", func() {
|
||||
framework.SkipUnlessServerVersionGTE(podUIDVersion, f.ClientSet.Discovery())
|
||||
@ -300,7 +300,7 @@ var _ = framework.KubeDescribe("Downward API [Serial] [Disruptive] [NodeFeature:
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
Env: env,
|
||||
},
|
||||
@ -325,7 +325,7 @@ func testDownwardAPI(f *framework.Framework, podName string, env []v1.EnvVar, ex
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
@ -357,7 +357,7 @@ func testDownwardAPIForEphemeralStorage(f *framework.Framework, podName string,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
|
81
vendor/k8s.io/kubernetes/test/e2e/common/downwardapi_volume.go
generated
vendored
81
vendor/k8s.io/kubernetes/test/e2e/common/downwardapi_volume.go
generated
vendored
@ -25,6 +25,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@ -32,7 +33,7 @@ import (
|
||||
|
||||
var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
// How long to wait for a log pod to be displayed
|
||||
const podLogTimeout = 2 * time.Minute
|
||||
const podLogTimeout = 3 * time.Minute
|
||||
f := framework.NewDefaultFramework("downward-api")
|
||||
var podClient *framework.PodClient
|
||||
BeforeEach(func() {
|
||||
@ -40,9 +41,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-podname
|
||||
Description: Ensure that downward API can provide pod's name through
|
||||
DownwardAPIVolumeFiles.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, pod name
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains a item for the Pod name. The container runtime MUST be able to access Pod name from the specified path on the mounted volume.
|
||||
*/
|
||||
framework.ConformanceIt("should provide podname only [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
@ -54,9 +55,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-set-default-mode
|
||||
Description: Ensure that downward API can set default file permission
|
||||
mode for DownwardAPIVolumeFiles if no mode is specified.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, volume mode 0400
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource with the volumesource mode set to -r-------- and DownwardAPIVolumeFiles contains a item for the Pod name. The container runtime MUST be able to access Pod name from the specified path on the mounted volume.
|
||||
*/
|
||||
framework.ConformanceIt("should set DefaultMode on files [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
@ -69,9 +70,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-set-mode
|
||||
Description: Ensure that downward API can set file permission mode for
|
||||
DownwardAPIVolumeFiles.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, file mode 0400
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains a item for the Pod name with the file mode set to -r--------. The container runtime MUST be able to access Pod name from the specified path on the mounted volume.
|
||||
*/
|
||||
framework.ConformanceIt("should set mode on item file [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
@ -113,9 +114,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-update-label
|
||||
Description: Ensure that downward API updates labels in
|
||||
DownwardAPIVolumeFiles when pod's labels get modified.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, update label
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains list of items for each of the Pod labels. The container runtime MUST be able to access Pod labels from the specified path on the mounted volume. Update the labels by adding a new label to the running Pod. The new label MUST be available from the mounted volume.
|
||||
*/
|
||||
framework.ConformanceIt("should update labels on modification [NodeConformance]", func() {
|
||||
labels := map[string]string{}
|
||||
@ -145,9 +146,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-update-annotation
|
||||
Description: Ensure that downward API updates annotations in
|
||||
DownwardAPIVolumeFiles when pod's annotations get modified.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, update annotations
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains list of items for each of the Pod annotations. The container runtime MUST be able to access Pod annotations from the specified path on the mounted volume. Update the annotations by adding a new annotation to the running Pod. The new annotation MUST be available from the mounted volume.
|
||||
*/
|
||||
framework.ConformanceIt("should update annotations on modification [NodeConformance]", func() {
|
||||
annotations := map[string]string{}
|
||||
@ -179,9 +180,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-cpu-limit
|
||||
Description: Ensure that downward API can provide container's CPU limit
|
||||
through DownwardAPIVolumeFiles.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, CPU limits
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains a item for the CPU limits. The container runtime MUST be able to access CPU limits from the specified path on the mounted volume.
|
||||
*/
|
||||
framework.ConformanceIt("should provide container's cpu limit [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
@ -193,9 +194,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-memory-limit
|
||||
Description: Ensure that downward API can provide container's memory
|
||||
limit through DownwardAPIVolumeFiles.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, memory limits
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains a item for the memory limits. The container runtime MUST be able to access memory limits from the specified path on the mounted volume.
|
||||
*/
|
||||
framework.ConformanceIt("should provide container's memory limit [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
@ -207,9 +208,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-cpu-request
|
||||
Description: Ensure that downward API can provide container's CPU
|
||||
request through DownwardAPIVolumeFiles.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, CPU request
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains a item for the CPU request. The container runtime MUST be able to access CPU request from the specified path on the mounted volume.
|
||||
*/
|
||||
framework.ConformanceIt("should provide container's cpu request [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
@ -221,9 +222,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-memory-request
|
||||
Description: Ensure that downward API can provide container's memory
|
||||
request through DownwardAPIVolumeFiles.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, memory request
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains a item for the memory request. The container runtime MUST be able to access memory request from the specified path on the mounted volume.
|
||||
*/
|
||||
framework.ConformanceIt("should provide container's memory request [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
@ -235,10 +236,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-default-cpu
|
||||
Description: Ensure that downward API can provide default node
|
||||
allocatable value for CPU through DownwardAPIVolumeFiles if CPU
|
||||
limit is not specified for a container.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, CPU limit, default node allocatable
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains a item for the CPU limits. CPU limits is not specified for the container. The container runtime MUST be able to access CPU limits from the specified path on the mounted volume and the value MUST be default node allocatable.
|
||||
*/
|
||||
framework.ConformanceIt("should provide node allocatable (cpu) as default cpu limit if the limit is not set [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
@ -248,10 +248,9 @@ var _ = Describe("[sig-storage] Downward API volume", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: downwardapi-volume-default-memory
|
||||
Description: Ensure that downward API can provide default node
|
||||
allocatable value for memory through DownwardAPIVolumeFiles if memory
|
||||
limit is not specified for a container.
|
||||
Release : v1.9
|
||||
Testname: DownwardAPI volume, memory limit, default node allocatable
|
||||
Description: A Pod is configured with DownwardAPIVolumeSource and DownwartAPIVolumeFiles contains a item for the memory limits. memory limits is not specified for the container. The container runtime MUST be able to access memory limits from the specified path on the mounted volume and the value MUST be default node allocatable.
|
||||
*/
|
||||
framework.ConformanceIt("should provide node allocatable (memory) as default memory limit if the limit is not set [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
@ -268,7 +267,7 @@ func downwardAPIVolumePodForModeTest(name, filePath string, itemMode, defaultMod
|
||||
pod.Spec.Containers = []v1.Container{
|
||||
{
|
||||
Name: "client-container",
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--file_mode=" + filePath},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -294,7 +293,7 @@ func downwardAPIVolumePodForSimpleTest(name string, filePath string) *v1.Pod {
|
||||
pod.Spec.Containers = []v1.Container{
|
||||
{
|
||||
Name: "client-container",
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--file_content=" + filePath},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -325,7 +324,7 @@ func downwardAPIVolumeBaseContainers(name, filePath string) []v1.Container {
|
||||
return []v1.Container{
|
||||
{
|
||||
Name: name,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--file_content=" + filePath},
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
@ -353,7 +352,7 @@ func downwardAPIVolumeDefaultBaseContainer(name, filePath string) []v1.Container
|
||||
return []v1.Container{
|
||||
{
|
||||
Name: name,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--file_content=" + filePath},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -372,7 +371,7 @@ func downwardAPIVolumePodForUpdateTest(name string, labels, annotations map[stri
|
||||
pod.Spec.Containers = []v1.Container{
|
||||
{
|
||||
Name: "client-container",
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=" + filePath},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
|
97
vendor/k8s.io/kubernetes/test/e2e/common/empty_dir.go
generated
vendored
97
vendor/k8s.io/kubernetes/test/e2e/common/empty_dir.go
generated
vendored
@ -67,139 +67,126 @@ var _ = Describe("[sig-storage] EmptyDir volumes", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-mode-tmpfs
|
||||
Description: For a Pod created with an 'emptyDir' Volume with 'medium'
|
||||
of 'Memory', ensure the volume has 0777 unix file permissions and tmpfs
|
||||
mount type.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium memory, volume mode default
|
||||
Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume MUST have mode set as -rwxrwxrwx and mount type set to tmpfs.
|
||||
*/
|
||||
framework.ConformanceIt("volume on tmpfs should have the correct mode [NodeConformance]", func() {
|
||||
doTestVolumeMode(f, testImageRootUid, v1.StorageMediumMemory)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-root-0644-tmpfs
|
||||
Description: For a Pod created with an 'emptyDir' Volume with 'medium'
|
||||
of 'Memory', ensure a root owned file with 0644 unix file permissions
|
||||
is created correctly, has tmpfs mount type, and enforces the permissions.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium memory, volume mode 0644
|
||||
Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0644. The volume MUST have mode -rw-r--r-- and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (root,0644,tmpfs) [NodeConformance]", func() {
|
||||
doTest0644(f, testImageRootUid, v1.StorageMediumMemory)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-root-0666-tmpfs
|
||||
Description: For a Pod created with an 'emptyDir' Volume with 'medium'
|
||||
of 'Memory', ensure a root owned file with 0666 unix file permissions
|
||||
is created correctly, has tmpfs mount type, and enforces the permissions.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium memory, volume mode 0666
|
||||
Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0666. The volume MUST have mode -rw-rw-rw- and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (root,0666,tmpfs) [NodeConformance]", func() {
|
||||
doTest0666(f, testImageRootUid, v1.StorageMediumMemory)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-root-0777-tmpfs
|
||||
Description: For a Pod created with an 'emptyDir' Volume with 'medium'
|
||||
of 'Memory', ensure a root owned file with 0777 unix file permissions
|
||||
is created correctly, has tmpfs mount type, and enforces the permissions.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium memory, volume mode 0777
|
||||
Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0777. The volume MUST have mode set as -rwxrwxrwx and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (root,0777,tmpfs) [NodeConformance]", func() {
|
||||
doTest0777(f, testImageRootUid, v1.StorageMediumMemory)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-user-0644-tmpfs
|
||||
Description: For a Pod created with an 'emptyDir' Volume with 'medium'
|
||||
of 'Memory', ensure a user owned file with 0644 unix file permissions
|
||||
is created correctly, has tmpfs mount type, and enforces the permissions.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium memory, volume mode 0644, non-root user
|
||||
Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0644. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rw-r--r-- and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (non-root,0644,tmpfs) [NodeConformance]", func() {
|
||||
doTest0644(f, testImageNonRootUid, v1.StorageMediumMemory)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-user-0666-tmpfs
|
||||
Description: For a Pod created with an 'emptyDir' Volume with 'medium'
|
||||
of 'Memory', ensure a user owned file with 0666 unix file permissions
|
||||
is created correctly, has tmpfs mount type, and enforces the permissions.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium memory, volume mode 0666,, non-root user
|
||||
Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0666. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rw-rw-rw- and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (non-root,0666,tmpfs) [NodeConformance]", func() {
|
||||
doTest0666(f, testImageNonRootUid, v1.StorageMediumMemory)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-user-0777-tmpfs
|
||||
Description: For a Pod created with an 'emptyDir' Volume with 'medium'
|
||||
of 'Memory', ensure a user owned file with 0777 unix file permissions
|
||||
is created correctly, has tmpfs mount type, and enforces the permissions.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium memory, volume mode 0777, non-root user
|
||||
Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0777. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rwxrwxrwx and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (non-root,0777,tmpfs) [NodeConformance]", func() {
|
||||
doTest0777(f, testImageNonRootUid, v1.StorageMediumMemory)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-mode
|
||||
Description: For a Pod created with an 'emptyDir' Volume, ensure the
|
||||
volume has 0777 unix file permissions.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium default, volume mode default
|
||||
Description: A Pod created with an 'emptyDir' Volume, the volume MUST have mode set as -rwxrwxrwx and mount type set to tmpfs.
|
||||
*/
|
||||
framework.ConformanceIt("volume on default medium should have the correct mode [NodeConformance]", func() {
|
||||
doTestVolumeMode(f, testImageRootUid, v1.StorageMediumDefault)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-root-0644
|
||||
Description: For a Pod created with an 'emptyDir' Volume, ensure a
|
||||
root owned file with 0644 unix file permissions is created and enforced
|
||||
correctly.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium default, volume mode 0644
|
||||
Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0644. The volume MUST have mode -rw-r--r-- and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (root,0644,default) [NodeConformance]", func() {
|
||||
doTest0644(f, testImageRootUid, v1.StorageMediumDefault)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-root-0666
|
||||
Description: For a Pod created with an 'emptyDir' Volume, ensure a
|
||||
root owned file with 0666 unix file permissions is created and enforced
|
||||
correctly.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium default, volume mode 0666
|
||||
Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0666. The volume MUST have mode -rw-rw-rw- and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (root,0666,default) [NodeConformance]", func() {
|
||||
doTest0666(f, testImageRootUid, v1.StorageMediumDefault)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-root-0777
|
||||
Description: For a Pod created with an 'emptyDir' Volume, ensure a
|
||||
root owned file with 0777 unix file permissions is created and enforced
|
||||
correctly.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium default, volume mode 0777
|
||||
Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0777. The volume MUST have mode set as -rwxrwxrwx and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (root,0777,default) [NodeConformance]", func() {
|
||||
doTest0777(f, testImageRootUid, v1.StorageMediumDefault)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-user-0644
|
||||
Description: For a Pod created with an 'emptyDir' Volume, ensure a
|
||||
user owned file with 0644 unix file permissions is created and enforced
|
||||
correctly.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium default, volume mode 0644
|
||||
Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0644. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rw-r--r-- and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (non-root,0644,default) [NodeConformance]", func() {
|
||||
doTest0644(f, testImageNonRootUid, v1.StorageMediumDefault)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-user-0666
|
||||
Description: For a Pod created with an 'emptyDir' Volume, ensure a
|
||||
user owned file with 0666 unix file permissions is created and enforced
|
||||
correctly.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium default, volume mode 0666
|
||||
Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0666. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rw-rw-rw- and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (non-root,0666,default) [NodeConformance]", func() {
|
||||
doTest0666(f, testImageNonRootUid, v1.StorageMediumDefault)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-emptydir-user-0777
|
||||
Description: For a Pod created with an 'emptyDir' Volume, ensure a
|
||||
user owned file with 0777 unix file permissions is created and enforced
|
||||
correctly.
|
||||
Release : v1.9
|
||||
Testname: EmptyDir, medium default, volume mode 0777
|
||||
Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0777. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rwxrwxrwx and mount type set to tmpfs and the contents MUST be readable.
|
||||
*/
|
||||
framework.ConformanceIt("should support (non-root,0777,default) [NodeConformance]", func() {
|
||||
doTest0777(f, testImageNonRootUid, v1.StorageMediumDefault)
|
||||
|
31
vendor/k8s.io/kubernetes/test/e2e/common/expansion.go
generated
vendored
31
vendor/k8s.io/kubernetes/test/e2e/common/expansion.go
generated
vendored
@ -21,6 +21,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@ -33,9 +34,9 @@ var _ = framework.KubeDescribe("Variable Expansion", func() {
|
||||
f := framework.NewDefaultFramework("var-expansion")
|
||||
|
||||
/*
|
||||
Testname: var-expansion-env
|
||||
Description: Make sure environment variables can be set using an
|
||||
expansion of previously defined environment variables
|
||||
Release : v1.9
|
||||
Testname: Environment variables, expansion
|
||||
Description: Create a Pod with environment variables. Environment variables defined using previously defined environment variables MUST expand to proper values.
|
||||
*/
|
||||
framework.ConformanceIt("should allow composing env vars into new env vars [NodeConformance]", func() {
|
||||
podName := "var-expansion-" + string(uuid.NewUUID())
|
||||
@ -48,7 +49,7 @@ var _ = framework.KubeDescribe("Variable Expansion", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
@ -78,9 +79,9 @@ var _ = framework.KubeDescribe("Variable Expansion", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: var-expansion-command
|
||||
Description: Make sure a container's commands can be set using an
|
||||
expansion of environment variables.
|
||||
Release : v1.9
|
||||
Testname: Environment variables, command expansion
|
||||
Description: Create a Pod with environment variables and container command using them. Container command using the defined environment variables MUST expand to proper values.
|
||||
*/
|
||||
framework.ConformanceIt("should allow substituting values in a container's command [NodeConformance]", func() {
|
||||
podName := "var-expansion-" + string(uuid.NewUUID())
|
||||
@ -93,7 +94,7 @@ var _ = framework.KubeDescribe("Variable Expansion", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "TEST_VAR=wrong echo \"$(TEST_VAR)\""},
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
@ -113,9 +114,9 @@ var _ = framework.KubeDescribe("Variable Expansion", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: var-expansion-arg
|
||||
Description: Make sure a container's args can be set using an
|
||||
expansion of environment variables.
|
||||
Release : v1.9
|
||||
Testname: Environment variables, command argument expansion
|
||||
Description: Create a Pod with environment variables and container command arguments using them. Container command arguments using the defined environment variables MUST expand to proper values.
|
||||
*/
|
||||
framework.ConformanceIt("should allow substituting values in a container's args [NodeConformance]", func() {
|
||||
podName := "var-expansion-" + string(uuid.NewUUID())
|
||||
@ -128,7 +129,7 @@ var _ = framework.KubeDescribe("Variable Expansion", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c"},
|
||||
Args: []string{"TEST_VAR=wrong echo \"$(TEST_VAR)\""},
|
||||
Env: []v1.EnvVar{
|
||||
@ -164,7 +165,7 @@ var _ = framework.KubeDescribe("Variable Expansion", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "test -d /testcontainer/" + podName + ";echo $?"},
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
@ -225,7 +226,7 @@ var _ = framework.KubeDescribe("Variable Expansion", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "POD_NAME",
|
||||
@ -274,7 +275,7 @@ var _ = framework.KubeDescribe("Variable Expansion", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "dapi-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "POD_NAME",
|
||||
|
97
vendor/k8s.io/kubernetes/test/e2e/common/host_path.go
generated
vendored
97
vendor/k8s.io/kubernetes/test/e2e/common/host_path.go
generated
vendored
@ -24,6 +24,7 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
)
|
||||
@ -40,10 +41,9 @@ var _ = Describe("[sig-storage] HostPath", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: volume-hostpath-mode
|
||||
Description: For a Pod created with a 'HostPath' Volume, ensure the
|
||||
volume is a directory with 0777 unix file permissions and that is has
|
||||
the sticky bit (mode flag t) set.
|
||||
Release : v1.9
|
||||
Testname: Host path, volume mode default
|
||||
Description: Create a Pod with host volume mounted. The volume mounted MUST be a directory with permissions mode -rwxrwxrwx and that is has the sticky bit (mode flag t) set.
|
||||
*/
|
||||
framework.ConformanceIt("should give a volume the correct mode [NodeConformance]", func() {
|
||||
source := &v1.HostPathVolumeSource{
|
||||
@ -116,91 +116,6 @@ var _ = Describe("[sig-storage] HostPath", func() {
|
||||
"content of file \"" + filePathInReader + "\": mount-tester new file",
|
||||
})
|
||||
})
|
||||
|
||||
It("should support existing directory subPath", func() {
|
||||
framework.SkipUnlessSSHKeyPresent()
|
||||
|
||||
subPath := "sub-path"
|
||||
fileName := "test-file"
|
||||
retryDuration := 180
|
||||
|
||||
filePathInWriter := path.Join(volumePath, fileName)
|
||||
filePathInReader := path.Join(volumePath, subPath, fileName)
|
||||
|
||||
source := &v1.HostPathVolumeSource{
|
||||
Path: "/tmp",
|
||||
}
|
||||
pod := testPodWithHostVol(volumePath, source)
|
||||
nodeList := framework.GetReadySchedulableNodesOrDie(f.ClientSet)
|
||||
pod.Spec.NodeName = nodeList.Items[0].Name
|
||||
|
||||
// Create the subPath directory on the host
|
||||
existing := path.Join(source.Path, subPath)
|
||||
result, err := framework.SSH(fmt.Sprintf("mkdir -p %s", existing), framework.GetNodeExternalIP(&nodeList.Items[0]), framework.TestContext.Provider)
|
||||
framework.LogSSHResult(result)
|
||||
framework.ExpectNoError(err)
|
||||
if result.Code != 0 {
|
||||
framework.Failf("mkdir returned non-zero")
|
||||
}
|
||||
|
||||
// Write the file in the subPath from container 0
|
||||
container := &pod.Spec.Containers[0]
|
||||
container.VolumeMounts[0].SubPath = subPath
|
||||
container.Args = []string{
|
||||
fmt.Sprintf("--new_file_0644=%v", filePathInWriter),
|
||||
fmt.Sprintf("--file_mode=%v", filePathInWriter),
|
||||
}
|
||||
|
||||
// Read it from outside the subPath from container 1
|
||||
pod.Spec.Containers[1].Args = []string{
|
||||
fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
|
||||
fmt.Sprintf("--retry_time=%d", retryDuration),
|
||||
}
|
||||
|
||||
f.TestContainerOutput("hostPath subPath", pod, 1, []string{
|
||||
"content of file \"" + filePathInReader + "\": mount-tester new file",
|
||||
})
|
||||
})
|
||||
|
||||
// TODO consolidate common code of this test and above
|
||||
It("should support existing single file subPath", func() {
|
||||
framework.SkipUnlessSSHKeyPresent()
|
||||
|
||||
subPath := "sub-path-test-file"
|
||||
retryDuration := 180
|
||||
|
||||
filePathInReader := path.Join(volumePath, subPath)
|
||||
|
||||
source := &v1.HostPathVolumeSource{
|
||||
Path: "/tmp",
|
||||
}
|
||||
pod := testPodWithHostVol(volumePath, source)
|
||||
nodeList := framework.GetReadySchedulableNodesOrDie(f.ClientSet)
|
||||
pod.Spec.NodeName = nodeList.Items[0].Name
|
||||
|
||||
// Create the subPath file on the host
|
||||
existing := path.Join(source.Path, subPath)
|
||||
result, err := framework.SSH(fmt.Sprintf("echo \"mount-tester new file\" > %s", existing), framework.GetNodeExternalIP(&nodeList.Items[0]), framework.TestContext.Provider)
|
||||
framework.LogSSHResult(result)
|
||||
framework.ExpectNoError(err)
|
||||
if result.Code != 0 {
|
||||
framework.Failf("echo returned non-zero")
|
||||
}
|
||||
|
||||
// Mount the file to the subPath in container 0
|
||||
container := &pod.Spec.Containers[0]
|
||||
container.VolumeMounts[0].SubPath = subPath
|
||||
|
||||
// Read it from outside the subPath from container 1
|
||||
pod.Spec.Containers[1].Args = []string{
|
||||
fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
|
||||
fmt.Sprintf("--retry_time=%d", retryDuration),
|
||||
}
|
||||
|
||||
f.TestContainerOutput("hostPath subPath", pod, 1, []string{
|
||||
"content of file \"" + filePathInReader + "\": mount-tester new file",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
//These constants are borrowed from the other test.
|
||||
@ -236,7 +151,7 @@ func testPodWithHostVol(path string, source *v1.HostPathVolumeSource) *v1.Pod {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: containerName1,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: volumeName,
|
||||
@ -249,7 +164,7 @@ func testPodWithHostVol(path string, source *v1.HostPathVolumeSource) *v1.Pod {
|
||||
},
|
||||
{
|
||||
Name: containerName2,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: volumeName,
|
||||
|
86
vendor/k8s.io/kubernetes/test/e2e/common/init_container.go
generated
vendored
86
vendor/k8s.io/kubernetes/test/e2e/common/init_container.go
generated
vendored
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
@ -26,6 +27,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
watchtools "k8s.io/client-go/tools/watch"
|
||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||
"k8s.io/kubernetes/pkg/client/conditions"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
@ -42,7 +44,15 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
podClient = f.PodClient()
|
||||
})
|
||||
|
||||
It("should invoke init containers on a RestartNever pod", func() {
|
||||
/*
|
||||
Release: v1.12
|
||||
Testname: init-container-starts-app-restartnever-pod
|
||||
Description: Ensure that all InitContainers are started
|
||||
and all containers in pod are voluntarily terminated with exit status 0,
|
||||
and the system is not going to restart any of these containers
|
||||
when Pod has restart policy as RestartNever.
|
||||
*/
|
||||
framework.ConformanceIt("should invoke init containers on a RestartNever pod", func() {
|
||||
By("creating the pod")
|
||||
name := "pod-init-" + string(uuid.NewUUID())
|
||||
value := strconv.Itoa(time.Now().Nanosecond())
|
||||
@ -59,19 +69,19 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: "init1",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/true"},
|
||||
},
|
||||
{
|
||||
Name: "init2",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/true"},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "run1",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/true"},
|
||||
},
|
||||
},
|
||||
@ -82,7 +92,9 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
w, err := podClient.Watch(metav1.SingleObject(startedPod.ObjectMeta))
|
||||
Expect(err).NotTo(HaveOccurred(), "error watching a pod")
|
||||
wr := watch.NewRecorder(w)
|
||||
event, err := watch.Until(framework.PodStartTimeout, wr, conditions.PodCompleted)
|
||||
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), framework.PodStartTimeout)
|
||||
defer cancel()
|
||||
event, err := watchtools.UntilWithoutRetry(ctx, wr, conditions.PodCompleted)
|
||||
Expect(err).To(BeNil())
|
||||
framework.CheckInvariants(wr.Events(), framework.ContainerInitInvariant)
|
||||
endPod := event.Object.(*v1.Pod)
|
||||
@ -99,7 +111,15 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
}
|
||||
})
|
||||
|
||||
It("should invoke init containers on a RestartAlways pod", func() {
|
||||
/*
|
||||
Release: v1.12
|
||||
Testname: init-container-starts-app-restartalways-pod
|
||||
Description: Ensure that all InitContainers are started
|
||||
and all containers in pod started
|
||||
and at least one container is still running or is in the process of being restarted
|
||||
when Pod has restart policy as RestartAlways.
|
||||
*/
|
||||
framework.ConformanceIt("should invoke init containers on a RestartAlways pod", func() {
|
||||
By("creating the pod")
|
||||
name := "pod-init-" + string(uuid.NewUUID())
|
||||
value := strconv.Itoa(time.Now().Nanosecond())
|
||||
@ -115,12 +135,12 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: "init1",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/true"},
|
||||
},
|
||||
{
|
||||
Name: "init2",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/true"},
|
||||
},
|
||||
},
|
||||
@ -131,7 +151,7 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
Resources: v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
||||
v1.ResourceMemory: *resource.NewQuantity(30*1024*1024, resource.DecimalSI),
|
||||
v1.ResourceMemory: *resource.NewQuantity(50*1024*1024, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -143,7 +163,9 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
w, err := podClient.Watch(metav1.SingleObject(startedPod.ObjectMeta))
|
||||
Expect(err).NotTo(HaveOccurred(), "error watching a pod")
|
||||
wr := watch.NewRecorder(w)
|
||||
event, err := watch.Until(framework.PodStartTimeout, wr, conditions.PodRunning)
|
||||
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), framework.PodStartTimeout)
|
||||
defer cancel()
|
||||
event, err := watchtools.UntilWithoutRetry(ctx, wr, conditions.PodRunning)
|
||||
Expect(err).To(BeNil())
|
||||
framework.CheckInvariants(wr.Events(), framework.ContainerInitInvariant)
|
||||
endPod := event.Object.(*v1.Pod)
|
||||
@ -160,7 +182,15 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
}
|
||||
})
|
||||
|
||||
It("should not start app containers if init containers fail on a RestartAlways pod", func() {
|
||||
/*
|
||||
Release: v1.12
|
||||
Testname: init-container-fails-stops-app-restartalways-pod
|
||||
Description: Ensure that app container is not started
|
||||
when all InitContainers failed to start
|
||||
and Pod has restarted for few occurrences
|
||||
and pod has restart policy as RestartAlways.
|
||||
*/
|
||||
framework.ConformanceIt("should not start app containers if init containers fail on a RestartAlways pod", func() {
|
||||
By("creating the pod")
|
||||
name := "pod-init-" + string(uuid.NewUUID())
|
||||
value := strconv.Itoa(time.Now().Nanosecond())
|
||||
@ -177,12 +207,12 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: "init1",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/false"},
|
||||
},
|
||||
{
|
||||
Name: "init2",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/true"},
|
||||
},
|
||||
},
|
||||
@ -193,7 +223,7 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
Resources: v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
||||
v1.ResourceMemory: *resource.NewQuantity(30*1024*1024, resource.DecimalSI),
|
||||
v1.ResourceMemory: *resource.NewQuantity(50*1024*1024, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -206,8 +236,10 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
Expect(err).NotTo(HaveOccurred(), "error watching a pod")
|
||||
|
||||
wr := watch.NewRecorder(w)
|
||||
event, err := watch.Until(
|
||||
framework.PodStartTimeout, wr,
|
||||
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), framework.PodStartTimeout)
|
||||
defer cancel()
|
||||
event, err := watchtools.UntilWithoutRetry(
|
||||
ctx, wr,
|
||||
// check for the first container to fail at least once
|
||||
func(evt watch.Event) (bool, error) {
|
||||
switch t := evt.Object.(type) {
|
||||
@ -268,7 +300,13 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
Expect(len(endPod.Status.InitContainerStatuses)).To(Equal(2))
|
||||
})
|
||||
|
||||
It("should not start app containers and fail the pod if init containers fail on a RestartNever pod", func() {
|
||||
/*
|
||||
Release: v1.12
|
||||
Testname: init-container-fails-stops-app-restartnever-pod
|
||||
Description: Ensure that app container is not started
|
||||
when at least one InitContainer fails to start and Pod has restart policy as RestartNever.
|
||||
*/
|
||||
framework.ConformanceIt("should not start app containers and fail the pod if init containers fail on a RestartNever pod", func() {
|
||||
By("creating the pod")
|
||||
name := "pod-init-" + string(uuid.NewUUID())
|
||||
value := strconv.Itoa(time.Now().Nanosecond())
|
||||
@ -285,24 +323,24 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: "init1",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/true"},
|
||||
},
|
||||
{
|
||||
Name: "init2",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/false"},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "run1",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/true"},
|
||||
Resources: v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
||||
v1.ResourceMemory: *resource.NewQuantity(30*1024*1024, resource.DecimalSI),
|
||||
v1.ResourceMemory: *resource.NewQuantity(50*1024*1024, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -316,8 +354,10 @@ var _ = framework.KubeDescribe("InitContainer [NodeConformance]", func() {
|
||||
Expect(err).NotTo(HaveOccurred(), "error watching a pod")
|
||||
|
||||
wr := watch.NewRecorder(w)
|
||||
event, err := watch.Until(
|
||||
framework.PodStartTimeout, wr,
|
||||
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), framework.PodStartTimeout)
|
||||
defer cancel()
|
||||
event, err := watchtools.UntilWithoutRetry(
|
||||
ctx, wr,
|
||||
// check for the second container to fail at least once
|
||||
func(evt watch.Event) (bool, error) {
|
||||
switch t := evt.Object.(type) {
|
||||
|
227
vendor/k8s.io/kubernetes/test/e2e/common/kubelet.go
generated
vendored
Normal file
227
vendor/k8s.io/kubernetes/test/e2e/common/kubelet.go
generated
vendored
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
Copyright 2016 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 common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = framework.KubeDescribe("Kubelet", func() {
|
||||
f := framework.NewDefaultFramework("kubelet-test")
|
||||
var podClient *framework.PodClient
|
||||
BeforeEach(func() {
|
||||
podClient = f.PodClient()
|
||||
})
|
||||
Context("when scheduling a busybox command in a pod", func() {
|
||||
podName := "busybox-scheduling-" + string(uuid.NewUUID())
|
||||
|
||||
/*
|
||||
Release : v1.13
|
||||
Testname: Kubelet, log output, default
|
||||
Description: By default the stdout and stderr from the process being executed in a pod MUST be sent to the pod's logs.
|
||||
*/
|
||||
framework.ConformanceIt("should print the output to logs [NodeConformance]", func() {
|
||||
podClient.CreateSync(&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
// Don't restart the Pod since it is expected to exit
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: framework.BusyBoxImage,
|
||||
Name: podName,
|
||||
Command: []string{"sh", "-c", "echo 'Hello World' ; sleep 240"},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
Eventually(func() string {
|
||||
sinceTime := metav1.NewTime(time.Now().Add(time.Duration(-1 * time.Hour)))
|
||||
rc, err := podClient.GetLogs(podName, &v1.PodLogOptions{SinceTime: &sinceTime}).Stream()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer rc.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(rc)
|
||||
return buf.String()
|
||||
}, time.Minute, time.Second*4).Should(Equal("Hello World\n"))
|
||||
})
|
||||
})
|
||||
Context("when scheduling a busybox command that always fails in a pod", func() {
|
||||
var podName string
|
||||
|
||||
BeforeEach(func() {
|
||||
podName = "bin-false" + string(uuid.NewUUID())
|
||||
podClient.Create(&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
// Don't restart the Pod since it is expected to exit
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: framework.BusyBoxImage,
|
||||
Name: podName,
|
||||
Command: []string{"/bin/false"},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.13
|
||||
Testname: Kubelet, failed pod, terminated reason
|
||||
Description: Create a Pod with terminated state. Pod MUST have only one container. Container MUST be in terminated state and MUST have an terminated reason.
|
||||
*/
|
||||
framework.ConformanceIt("should have an terminated reason [NodeConformance]", func() {
|
||||
Eventually(func() error {
|
||||
podData, err := podClient.Get(podName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(podData.Status.ContainerStatuses) != 1 {
|
||||
return fmt.Errorf("expected only one container in the pod %q", podName)
|
||||
}
|
||||
contTerminatedState := podData.Status.ContainerStatuses[0].State.Terminated
|
||||
if contTerminatedState == nil {
|
||||
return fmt.Errorf("expected state to be terminated. Got pod status: %+v", podData.Status)
|
||||
}
|
||||
if contTerminatedState.ExitCode == 0 || contTerminatedState.Reason == "" {
|
||||
return fmt.Errorf("expected non-zero exitCode and non-empty terminated state reason. Got exitCode: %+v and terminated state reason: %+v", contTerminatedState.ExitCode, contTerminatedState.Reason)
|
||||
}
|
||||
return nil
|
||||
}, time.Minute, time.Second*4).Should(BeNil())
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.13
|
||||
Testname: Kubelet, failed pod, delete
|
||||
Description: Create a Pod with terminated state. This terminated pod MUST be able to be deleted.
|
||||
*/
|
||||
framework.ConformanceIt("should be possible to delete [NodeConformance]", func() {
|
||||
err := podClient.Delete(podName, &metav1.DeleteOptions{})
|
||||
Expect(err).To(BeNil(), fmt.Sprintf("Error deleting Pod %v", err))
|
||||
})
|
||||
})
|
||||
Context("when scheduling a busybox Pod with hostAliases", func() {
|
||||
podName := "busybox-host-aliases" + string(uuid.NewUUID())
|
||||
|
||||
/*
|
||||
Release : v1.13
|
||||
Testname: Kubelet, hostAliases
|
||||
Description: Create a Pod with hostAliases and a container with command to output /etc/hosts entries. Pod's logs MUST have matching entries of specified hostAliases to the output of /etc/hosts entries.
|
||||
*/
|
||||
framework.ConformanceIt("should write entries to /etc/hosts [NodeConformance]", func() {
|
||||
podClient.CreateSync(&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
// Don't restart the Pod since it is expected to exit
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: framework.BusyBoxImage,
|
||||
Name: podName,
|
||||
Command: []string{"/bin/sh", "-c", "cat /etc/hosts; sleep 6000"},
|
||||
},
|
||||
},
|
||||
HostAliases: []v1.HostAlias{
|
||||
{
|
||||
IP: "123.45.67.89",
|
||||
Hostnames: []string{"foo", "bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
Eventually(func() error {
|
||||
rc, err := podClient.GetLogs(podName, &v1.PodLogOptions{}).Stream()
|
||||
defer rc.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(rc)
|
||||
hostsFileContent := buf.String()
|
||||
|
||||
if !strings.Contains(hostsFileContent, "123.45.67.89\tfoo\tbar") {
|
||||
return fmt.Errorf("expected hosts file to contain entries from HostAliases. Got:\n%+v", hostsFileContent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}, time.Minute, time.Second*4).Should(BeNil())
|
||||
})
|
||||
})
|
||||
Context("when scheduling a read only busybox container", func() {
|
||||
podName := "busybox-readonly-fs" + string(uuid.NewUUID())
|
||||
|
||||
/*
|
||||
Release : v1.13
|
||||
Testname: Kubelet, pod with read only root file system
|
||||
Description: Create a Pod with security context set with ReadOnlyRootFileSystem set to true. The Pod then tries to write to the /file on the root, write operation to the root filesystem MUST fail as expected.
|
||||
*/
|
||||
framework.ConformanceIt("should not write to root filesystem [NodeConformance]", func() {
|
||||
isReadOnly := true
|
||||
podClient.CreateSync(&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
// Don't restart the Pod since it is expected to exit
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: framework.BusyBoxImage,
|
||||
Name: podName,
|
||||
Command: []string{"/bin/sh", "-c", "echo test > /file; sleep 240"},
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
ReadOnlyRootFilesystem: &isReadOnly,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
Eventually(func() string {
|
||||
rc, err := podClient.GetLogs(podName, &v1.PodLogOptions{}).Stream()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer rc.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(rc)
|
||||
return buf.String()
|
||||
}, time.Minute, time.Second*4).Should(Equal("/bin/sh: can't create /file: Read-only file system\n"))
|
||||
})
|
||||
})
|
||||
})
|
13
vendor/k8s.io/kubernetes/test/e2e/common/kubelet_etc_hosts.go
generated
vendored
13
vendor/k8s.io/kubernetes/test/e2e/common/kubelet_etc_hosts.go
generated
vendored
@ -20,10 +20,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
. "github.com/onsi/ginkgo"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
)
|
||||
@ -51,9 +51,12 @@ var _ = framework.KubeDescribe("KubeletManagedEtcHosts", func() {
|
||||
}
|
||||
|
||||
/*
|
||||
Testname: kubelet-managed-etc-hosts
|
||||
Description: Make sure Kubelet correctly manages /etc/hosts and mounts
|
||||
it into the container.
|
||||
Release : v1.9
|
||||
Testname: Kubelet, managed etc hosts
|
||||
Description: Create a Pod with containers with hostNetwork set to false, one of the containers mounts the /etc/hosts file form the host. Create a second Pod with hostNetwork set to true.
|
||||
1. The Pod with hostNetwork=false MUST have /etc/hosts of containers managed by the Kubelet.
|
||||
2. The Pod with hostNetwork=false but the container mounts /etc/hosts file from the host. The /etc/hosts file MUST not be managed by the Kubelet.
|
||||
3. The Pod with hostNetwork=true , /etc/hosts file MUST not be managed by the Kubelet.
|
||||
*/
|
||||
framework.ConformanceIt("should test kubelet managed /etc/hosts file [NodeConformance]", func() {
|
||||
By("Setting up the test")
|
||||
@ -123,7 +126,7 @@ func assertManagedStatus(
|
||||
}
|
||||
}
|
||||
|
||||
glog.Warningf(
|
||||
klog.Warningf(
|
||||
"For pod: %s, name: %s, expected %t, (/etc/hosts was %q), (/etc/hosts-original was %q), retryCount: %d",
|
||||
podName, name, expectedIsManaged, etcHostsContent, etcHostsOriginalContent, retryCount)
|
||||
|
||||
|
173
vendor/k8s.io/kubernetes/test/e2e/common/lifecycle_hook.go
generated
vendored
Normal file
173
vendor/k8s.io/kubernetes/test/e2e/common/lifecycle_hook.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
Copyright 2016 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 common
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = framework.KubeDescribe("Container Lifecycle Hook", func() {
|
||||
f := framework.NewDefaultFramework("container-lifecycle-hook")
|
||||
var podClient *framework.PodClient
|
||||
const (
|
||||
podCheckInterval = 1 * time.Second
|
||||
postStartWaitTimeout = 2 * time.Minute
|
||||
preStopWaitTimeout = 30 * time.Second
|
||||
)
|
||||
Context("when create a pod with lifecycle hook", func() {
|
||||
var targetIP string
|
||||
podHandleHookRequest := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-handle-http-request",
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "pod-handle-http-request",
|
||||
Image: imageutils.GetE2EImage(imageutils.Netexec),
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
ContainerPort: 8080,
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
BeforeEach(func() {
|
||||
podClient = f.PodClient()
|
||||
By("create the container to handle the HTTPGet hook request.")
|
||||
newPod := podClient.CreateSync(podHandleHookRequest)
|
||||
targetIP = newPod.Status.PodIP
|
||||
})
|
||||
testPodWithHook := func(podWithHook *v1.Pod) {
|
||||
By("create the pod with lifecycle hook")
|
||||
podClient.CreateSync(podWithHook)
|
||||
if podWithHook.Spec.Containers[0].Lifecycle.PostStart != nil {
|
||||
By("check poststart hook")
|
||||
Eventually(func() error {
|
||||
return podClient.MatchContainerOutput(podHandleHookRequest.Name, podHandleHookRequest.Spec.Containers[0].Name,
|
||||
`GET /echo\?msg=poststart`)
|
||||
}, postStartWaitTimeout, podCheckInterval).Should(BeNil())
|
||||
}
|
||||
By("delete the pod with lifecycle hook")
|
||||
podClient.DeleteSync(podWithHook.Name, metav1.NewDeleteOptions(15), framework.DefaultPodDeletionTimeout)
|
||||
if podWithHook.Spec.Containers[0].Lifecycle.PreStop != nil {
|
||||
By("check prestop hook")
|
||||
Eventually(func() error {
|
||||
return podClient.MatchContainerOutput(podHandleHookRequest.Name, podHandleHookRequest.Spec.Containers[0].Name,
|
||||
`GET /echo\?msg=prestop`)
|
||||
}, preStopWaitTimeout, podCheckInterval).Should(BeNil())
|
||||
}
|
||||
}
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Pod Lifecycle, post start exec hook
|
||||
Description: When a post start handler is specified in the container lifecycle using a ‘Exec’ action, then the handler MUST be invoked after the start of the container. A server pod is created that will serve http requests, create a second pod with a container lifecycle specifying a post start that invokes the server pod using ExecAction to validate that the post start is executed.
|
||||
*/
|
||||
framework.ConformanceIt("should execute poststart exec hook properly [NodeConformance]", func() {
|
||||
lifecycle := &v1.Lifecycle{
|
||||
PostStart: &v1.Handler{
|
||||
Exec: &v1.ExecAction{
|
||||
Command: []string{"sh", "-c", "curl http://" + targetIP + ":8080/echo?msg=poststart"},
|
||||
},
|
||||
},
|
||||
}
|
||||
podWithHook := getPodWithHook("pod-with-poststart-exec-hook", imageutils.GetE2EImage(imageutils.Hostexec), lifecycle)
|
||||
testPodWithHook(podWithHook)
|
||||
})
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Pod Lifecycle, prestop exec hook
|
||||
Description: When a pre-stop handler is specified in the container lifecycle using a ‘Exec’ action, then the handler MUST be invoked before the container is terminated. A server pod is created that will serve http requests, create a second pod with a container lifecycle specifying a pre-stop that invokes the server pod using ExecAction to validate that the pre-stop is executed.
|
||||
*/
|
||||
framework.ConformanceIt("should execute prestop exec hook properly [NodeConformance]", func() {
|
||||
lifecycle := &v1.Lifecycle{
|
||||
PreStop: &v1.Handler{
|
||||
Exec: &v1.ExecAction{
|
||||
Command: []string{"sh", "-c", "curl http://" + targetIP + ":8080/echo?msg=prestop"},
|
||||
},
|
||||
},
|
||||
}
|
||||
podWithHook := getPodWithHook("pod-with-prestop-exec-hook", imageutils.GetE2EImage(imageutils.Hostexec), lifecycle)
|
||||
testPodWithHook(podWithHook)
|
||||
})
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Pod Lifecycle, post start http hook
|
||||
Description: When a post start handler is specified in the container lifecycle using a HttpGet action, then the handler MUST be invoked after the start of the container. A server pod is created that will serve http requests, create a second pod with a container lifecycle specifying a post start that invokes the server pod to validate that the post start is executed.
|
||||
*/
|
||||
framework.ConformanceIt("should execute poststart http hook properly [NodeConformance]", func() {
|
||||
lifecycle := &v1.Lifecycle{
|
||||
PostStart: &v1.Handler{
|
||||
HTTPGet: &v1.HTTPGetAction{
|
||||
Path: "/echo?msg=poststart",
|
||||
Host: targetIP,
|
||||
Port: intstr.FromInt(8080),
|
||||
},
|
||||
},
|
||||
}
|
||||
podWithHook := getPodWithHook("pod-with-poststart-http-hook", imageutils.GetPauseImageName(), lifecycle)
|
||||
testPodWithHook(podWithHook)
|
||||
})
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Pod Lifecycle, prestop http hook
|
||||
Description: When a pre-stop handler is specified in the container lifecycle using a ‘HttpGet’ action, then the handler MUST be invoked before the container is terminated. A server pod is created that will serve http requests, create a second pod with a container lifecycle specifying a pre-stop that invokes the server pod to validate that the pre-stop is executed.
|
||||
*/
|
||||
framework.ConformanceIt("should execute prestop http hook properly [NodeConformance]", func() {
|
||||
lifecycle := &v1.Lifecycle{
|
||||
PreStop: &v1.Handler{
|
||||
HTTPGet: &v1.HTTPGetAction{
|
||||
Path: "/echo?msg=prestop",
|
||||
Host: targetIP,
|
||||
Port: intstr.FromInt(8080),
|
||||
},
|
||||
},
|
||||
}
|
||||
podWithHook := getPodWithHook("pod-with-prestop-http-hook", imageutils.GetPauseImageName(), lifecycle)
|
||||
testPodWithHook(podWithHook)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func getPodWithHook(name string, image string, lifecycle *v1.Lifecycle) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: name,
|
||||
Image: image,
|
||||
Lifecycle: lifecycle,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
28
vendor/k8s.io/kubernetes/test/e2e/common/networking.go
generated
vendored
28
vendor/k8s.io/kubernetes/test/e2e/common/networking.go
generated
vendored
@ -31,9 +31,10 @@ var _ = Describe("[sig-network] Networking", func() {
|
||||
// expect exactly one unique hostname. Each of these endpoints reports
|
||||
// its own hostname.
|
||||
/*
|
||||
Testname: networking-intra-pod-http
|
||||
Description: Try to hit test endpoints from a test container and make
|
||||
sure each of them can report a unique hostname.
|
||||
Release : v1.9
|
||||
Testname: Networking, intra pod http
|
||||
Description: Create a hostexec pod that is capable of curl to netcat commands. Create a test Pod that will act as a webserver front end exposing ports 8080 for tcp and 8081 for udp. The netserver service proxies are created on specified number of nodes.
|
||||
The kubectl exec on the webserver container MUST reach a http port on the each of service proxy endpoints in the cluster and the request MUST be successful. Container will execute curl command to reach the service port within specified max retry limit and MUST result in reporting unique hostnames.
|
||||
*/
|
||||
framework.ConformanceIt("should function for intra-pod communication: http [NodeConformance]", func() {
|
||||
config := framework.NewCoreNetworkingTestConfig(f)
|
||||
@ -43,9 +44,10 @@ var _ = Describe("[sig-network] Networking", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: networking-intra-pod-udp
|
||||
Description: Try to hit test endpoints from a test container using udp
|
||||
and make sure each of them can report a unique hostname.
|
||||
Release : v1.9
|
||||
Testname: Networking, intra pod udp
|
||||
Description: Create a hostexec pod that is capable of curl to netcat commands. Create a test Pod that will act as a webserver front end exposing ports 8080 for tcp and 8081 for udp. The netserver service proxies are created on specified number of nodes.
|
||||
The kubectl exec on the webserver container MUST reach a udp port on the each of service proxy endpoints in the cluster and the request MUST be successful. Container will execute curl command to reach the service port within specified max retry limit and MUST result in reporting unique hostnames.
|
||||
*/
|
||||
framework.ConformanceIt("should function for intra-pod communication: udp [NodeConformance]", func() {
|
||||
config := framework.NewCoreNetworkingTestConfig(f)
|
||||
@ -55,9 +57,10 @@ var _ = Describe("[sig-network] Networking", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: networking-node-pod-http
|
||||
Description: Try to hit test endpoints from the pod and make sure each
|
||||
of them can report a unique hostname.
|
||||
Release : v1.9
|
||||
Testname: Networking, intra pod http, from node
|
||||
Description: Create a hostexec pod that is capable of curl to netcat commands. Create a test Pod that will act as a webserver front end exposing ports 8080 for tcp and 8081 for udp. The netserver service proxies are created on specified number of nodes.
|
||||
The kubectl exec on the webserver container MUST reach a http port on the each of service proxy endpoints in the cluster using a http post(protocol=tcp) and the request MUST be successful. Container will execute curl command to reach the service port within specified max retry limit and MUST result in reporting unique hostnames.
|
||||
*/
|
||||
framework.ConformanceIt("should function for node-pod communication: http [NodeConformance]", func() {
|
||||
config := framework.NewCoreNetworkingTestConfig(f)
|
||||
@ -67,9 +70,10 @@ var _ = Describe("[sig-network] Networking", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: networking-node-pod-udp
|
||||
Description: Try to hit test endpoints from the pod using udp and make sure
|
||||
each of them can report a unique hostname.
|
||||
Release : v1.9
|
||||
Testname: Networking, intra pod http, from node
|
||||
Description: Create a hostexec pod that is capable of curl to netcat commands. Create a test Pod that will act as a webserver front end exposing ports 8080 for tcp and 8081 for udp. The netserver service proxies are created on specified number of nodes.
|
||||
The kubectl exec on the webserver container MUST reach a http port on the each of service proxy endpoints in the cluster using a http post(protocol=udp) and the request MUST be successful. Container will execute curl command to reach the service port within specified max retry limit and MUST result in reporting unique hostnames.
|
||||
*/
|
||||
framework.ConformanceIt("should function for node-pod communication: udp [NodeConformance]", func() {
|
||||
config := framework.NewCoreNetworkingTestConfig(f)
|
||||
|
166
vendor/k8s.io/kubernetes/test/e2e/common/node_lease.go
generated
vendored
Normal file
166
vendor/k8s.io/kubernetes/test/e2e/common/node_lease.go
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
coordv1beta1 "k8s.io/api/coordination/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
|
||||
v1node "k8s.io/kubernetes/pkg/api/v1/node"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = framework.KubeDescribe("[Feature:NodeLease][NodeAlphaFeature:NodeLease]", func() {
|
||||
var nodeName string
|
||||
f := framework.NewDefaultFramework("node-lease-test")
|
||||
|
||||
BeforeEach(func() {
|
||||
nodes := framework.GetReadySchedulableNodesOrDie(f.ClientSet)
|
||||
Expect(len(nodes.Items)).NotTo(BeZero())
|
||||
nodeName = nodes.Items[0].ObjectMeta.Name
|
||||
})
|
||||
|
||||
Context("when the NodeLease feature is enabled", func() {
|
||||
It("the kubelet should create and update a lease in the kube-node-lease namespace", func() {
|
||||
leaseClient := f.ClientSet.CoordinationV1beta1().Leases(corev1.NamespaceNodeLease)
|
||||
var (
|
||||
err error
|
||||
lease *coordv1beta1.Lease
|
||||
)
|
||||
By("check that lease for this Kubelet exists in the kube-node-lease namespace")
|
||||
Eventually(func() error {
|
||||
lease, err = leaseClient.Get(nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 5*time.Minute, 5*time.Second).Should(BeNil())
|
||||
// check basic expectations for the lease
|
||||
Expect(expectLease(lease, nodeName)).To(BeNil())
|
||||
|
||||
By("check that node lease is updated at least once within the lease duration")
|
||||
Eventually(func() error {
|
||||
newLease, err := leaseClient.Get(nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// check basic expectations for the latest lease
|
||||
if err := expectLease(newLease, nodeName); err != nil {
|
||||
return err
|
||||
}
|
||||
// check that RenewTime has been updated on the latest lease
|
||||
newTime := (*newLease.Spec.RenewTime).Time
|
||||
oldTime := (*lease.Spec.RenewTime).Time
|
||||
if !newTime.After(oldTime) {
|
||||
return fmt.Errorf("new lease has time %v, which is not after old lease time %v", newTime, oldTime)
|
||||
}
|
||||
return nil
|
||||
}, time.Duration(*lease.Spec.LeaseDurationSeconds)*time.Second,
|
||||
time.Duration(*lease.Spec.LeaseDurationSeconds/4)*time.Second)
|
||||
})
|
||||
|
||||
It("the kubelet should report node status infrequently", func() {
|
||||
By("wait until node is ready")
|
||||
framework.WaitForNodeToBeReady(f.ClientSet, nodeName, 5*time.Minute)
|
||||
|
||||
By("wait until there is node lease")
|
||||
var err error
|
||||
var lease *coordv1beta1.Lease
|
||||
Eventually(func() error {
|
||||
lease, err = f.ClientSet.CoordinationV1beta1().Leases(corev1.NamespaceNodeLease).Get(nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 5*time.Minute, 5*time.Second).Should(BeNil())
|
||||
// check basic expectations for the lease
|
||||
Expect(expectLease(lease, nodeName)).To(BeNil())
|
||||
leaseDuration := time.Duration(*lease.Spec.LeaseDurationSeconds) * time.Second
|
||||
|
||||
By("verify NodeStatus report period is longer than lease duration")
|
||||
// NodeStatus is reported from node to master when there is some change or
|
||||
// enough time has passed. So for here, keep checking the time diff
|
||||
// between 2 NodeStatus report, until it is longer than lease duration (
|
||||
// the same as nodeMonitorGracePeriod).
|
||||
heartbeatTime := getNextReadyConditionHeartbeatTime(f.ClientSet, nodeName, metav1.Time{})
|
||||
Eventually(func() error {
|
||||
nextHeartbeatTime := getNextReadyConditionHeartbeatTime(f.ClientSet, nodeName, heartbeatTime)
|
||||
|
||||
if nextHeartbeatTime.Time.After(heartbeatTime.Time.Add(leaseDuration)) {
|
||||
return nil
|
||||
}
|
||||
heartbeatTime = nextHeartbeatTime
|
||||
return fmt.Errorf("node status report period is shorter than lease duration")
|
||||
|
||||
// Enter next round immediately.
|
||||
}, 5*time.Minute, time.Nanosecond).Should(BeNil())
|
||||
|
||||
By("verify node is still in ready status even though node status report is infrequent")
|
||||
// This check on node status is only meaningful when this e2e test is
|
||||
// running as cluster e2e test, because node e2e test does not create and
|
||||
// run controller manager, i.e., no node lifecycle controller.
|
||||
node, err := f.ClientSet.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
||||
Expect(err).To(BeNil())
|
||||
_, readyCondition := v1node.GetNodeCondition(&node.Status, corev1.NodeReady)
|
||||
Expect(readyCondition.Status).To(Equal(corev1.ConditionTrue))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func getNextReadyConditionHeartbeatTime(clientSet clientset.Interface, nodeName string, prevHeartbeatTime metav1.Time) metav1.Time {
|
||||
var newHeartbeatTime metav1.Time
|
||||
Eventually(func() error {
|
||||
node, err := clientSet.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, readyCondition := v1node.GetNodeCondition(&node.Status, corev1.NodeReady)
|
||||
Expect(readyCondition.Status).To(Equal(corev1.ConditionTrue))
|
||||
newHeartbeatTime = readyCondition.LastHeartbeatTime
|
||||
if prevHeartbeatTime.Before(&newHeartbeatTime) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("heartbeat has not changed yet")
|
||||
}, 5*time.Minute, 5*time.Second).Should(BeNil())
|
||||
return newHeartbeatTime
|
||||
}
|
||||
|
||||
func expectLease(lease *coordv1beta1.Lease, nodeName string) error {
|
||||
// expect values for HolderIdentity, LeaseDurationSeconds, and RenewTime
|
||||
if lease.Spec.HolderIdentity == nil {
|
||||
return fmt.Errorf("Spec.HolderIdentity should not be nil")
|
||||
}
|
||||
if lease.Spec.LeaseDurationSeconds == nil {
|
||||
return fmt.Errorf("Spec.LeaseDurationSeconds should not be nil")
|
||||
}
|
||||
if lease.Spec.RenewTime == nil {
|
||||
return fmt.Errorf("Spec.RenewTime should not be nil")
|
||||
}
|
||||
// ensure that the HolderIdentity matches the node name
|
||||
if *lease.Spec.HolderIdentity != nodeName {
|
||||
return fmt.Errorf("Spec.HolderIdentity (%v) should match the node name (%v)", *lease.Spec.HolderIdentity, nodeName)
|
||||
}
|
||||
return nil
|
||||
}
|
142
vendor/k8s.io/kubernetes/test/e2e/common/pods.go
generated
vendored
142
vendor/k8s.io/kubernetes/test/e2e/common/pods.go
generated
vendored
@ -29,6 +29,7 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
@ -36,16 +37,20 @@ import (
|
||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||
"k8s.io/kubernetes/pkg/kubelet"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
)
|
||||
|
||||
var (
|
||||
buildBackOffDuration = time.Minute
|
||||
syncLoopFrequency = 10 * time.Second
|
||||
maxBackOffTolerance = time.Duration(1.3 * float64(kubelet.MaxContainerBackOff))
|
||||
// maxReadyStatusUpdateTolerance specifies the latency that allows kubelet to update pod status.
|
||||
// When kubelet is under heavy load (tests may be parallelized), the delay may be longer, hence
|
||||
// causing tests to be flaky.
|
||||
maxReadyStatusUpdateTolerance = 10 * time.Second
|
||||
)
|
||||
|
||||
// testHostIP tests that a pod gets a host IP
|
||||
@ -129,9 +134,9 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-created-pod-assigned-hostip
|
||||
Description: Make sure when a pod is created that it is assigned a host IP
|
||||
Address.
|
||||
Release : v1.9
|
||||
Testname: Pods, assigned hostip
|
||||
Description: Create a Pod. Pod status MUST return successfully and contains a valid IP address.
|
||||
*/
|
||||
framework.ConformanceIt("should get a host IP [NodeConformance]", func() {
|
||||
name := "pod-hostip-" + string(uuid.NewUUID())
|
||||
@ -151,9 +156,9 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-submitted-removed
|
||||
Description: Makes sure a pod is created, a watch can be setup for the pod,
|
||||
pod creation was observed, pod is deleted, and pod deletion is observed.
|
||||
Release : v1.9
|
||||
Testname: Pods, lifecycle
|
||||
Description: A Pod is created with a unique label. Pod MUST be accessible when queried using the label selector upon creation. Add a watch, check if the Pod is running. Pod then deleted, The pod deletion timestamp is observed. The watch MUST return the pod deleted event. Query with the original selector for the Pod MUST return empty list.
|
||||
*/
|
||||
framework.ConformanceIt("should be submitted and removed [NodeConformance]", func() {
|
||||
By("creating the pod")
|
||||
@ -171,7 +176,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: imageutils.GetE2EImage(imageutils.NginxSlim),
|
||||
Image: imageutils.GetE2EImage(imageutils.Nginx),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -277,8 +282,9 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-updated-successfully
|
||||
Description: Make sure it is possible to successfully update a pod's labels.
|
||||
Release : v1.9
|
||||
Testname: Pods, update
|
||||
Description: Create a Pod with a unique label. Query for the Pod with the label as selector MUST be successful. Update the pod to change the value of the Label. Query for the Pod with the new value for the label MUST be successful.
|
||||
*/
|
||||
framework.ConformanceIt("should be updated [NodeConformance]", func() {
|
||||
By("creating the pod")
|
||||
@ -296,7 +302,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: imageutils.GetE2EImage(imageutils.NginxSlim),
|
||||
Image: imageutils.GetE2EImage(imageutils.Nginx),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -330,10 +336,9 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-update-active-deadline-seconds
|
||||
Description: Make sure it is possible to create a pod, update its
|
||||
activeDeadlineSecondsValue, and then waits for the deadline to pass
|
||||
and verifies the pod is terminated.
|
||||
Release : v1.9
|
||||
Testname: Pods, ActiveDeadlineSeconds
|
||||
Description: Create a Pod with a unique label. Query for the Pod with the label as selector MUST be successful. The Pod is updated with ActiveDeadlineSeconds set on the Pod spec. Pod MUST terminate of the specified time elapses.
|
||||
*/
|
||||
framework.ConformanceIt("should allow activeDeadlineSeconds to be updated [NodeConformance]", func() {
|
||||
By("creating the pod")
|
||||
@ -351,7 +356,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: imageutils.GetE2EImage(imageutils.NginxSlim),
|
||||
Image: imageutils.GetE2EImage(imageutils.Nginx),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -377,9 +382,9 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: pods-contain-services-environment-variables
|
||||
Description: Make sure that when a pod is created it contains environment
|
||||
variables for each active service.
|
||||
Release : v1.9
|
||||
Testname: Pods, service environment variables
|
||||
Description: Create a server Pod listening on port 9376. A Service called fooservice is created for the server Pod listening on port 8765 targeting port 8080. If a new Pod is created in the cluster then the Pod MUST have the fooservice environment variables available from this new Pod. The new create Pod MUST have environment variables such as FOOSERVICE_SERVICE_HOST, FOOSERVICE_SERVICE_PORT, FOOSERVICE_PORT, FOOSERVICE_PORT_8765_TCP_PORT, FOOSERVICE_PORT_8765_TCP_PROTO, FOOSERVICE_PORT_8765_TCP and FOOSERVICE_PORT_8765_TCP_ADDR that are populated with proper values.
|
||||
*/
|
||||
framework.ConformanceIt("should contain environment variables for services [NodeConformance]", func() {
|
||||
// Make a pod that will be a service.
|
||||
@ -442,7 +447,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: containerName,
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
},
|
||||
},
|
||||
@ -467,7 +472,13 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
}, maxRetries, "Container should have service environment variables set")
|
||||
})
|
||||
|
||||
It("should support remote command execution over websockets [NodeConformance]", func() {
|
||||
/*
|
||||
Release : v1.13
|
||||
Testname: Pods, remote command execution over websocket
|
||||
Description: A Pod is created. Websocket is created to retrieve exec command output from this pod.
|
||||
Message retrieved form Websocket MUST match with expected exec command output.
|
||||
*/
|
||||
framework.ConformanceIt("should support remote command execution over websockets [NodeConformance]", func() {
|
||||
config, err := framework.LoadConfig()
|
||||
Expect(err).NotTo(HaveOccurred(), "unable to get base config")
|
||||
|
||||
@ -481,7 +492,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "main",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/sh", "-c", "echo container is alive; sleep 600"},
|
||||
},
|
||||
},
|
||||
@ -499,8 +510,8 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
Param("stderr", "1").
|
||||
Param("stdout", "1").
|
||||
Param("container", pod.Spec.Containers[0].Name).
|
||||
Param("command", "cat").
|
||||
Param("command", "/etc/resolv.conf")
|
||||
Param("command", "echo").
|
||||
Param("command", "remote execution test")
|
||||
|
||||
url := req.URL()
|
||||
ws, err := framework.OpenWebSocketForURL(url, config, []string{"channel.k8s.io"})
|
||||
@ -536,14 +547,20 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
if buf.Len() == 0 {
|
||||
return fmt.Errorf("Unexpected output from server")
|
||||
}
|
||||
if !strings.Contains(buf.String(), "nameserver") {
|
||||
return fmt.Errorf("Expected to find 'nameserver' in %q", buf.String())
|
||||
if !strings.Contains(buf.String(), "remote execution test") {
|
||||
return fmt.Errorf("Expected to find 'remote execution test' in %q", buf.String())
|
||||
}
|
||||
return nil
|
||||
}, time.Minute, 10*time.Second).Should(BeNil())
|
||||
})
|
||||
|
||||
It("should support retrieving logs from the container over websockets [NodeConformance]", func() {
|
||||
/*
|
||||
Release : v1.13
|
||||
Testname: Pods, logs from websockets
|
||||
Description: A Pod is created. Websocket is created to retrieve log of a container from this pod.
|
||||
Message retrieved form Websocket MUST match with container's output.
|
||||
*/
|
||||
framework.ConformanceIt("should support retrieving logs from the container over websockets [NodeConformance]", func() {
|
||||
config, err := framework.LoadConfig()
|
||||
Expect(err).NotTo(HaveOccurred(), "unable to get base config")
|
||||
|
||||
@ -557,7 +574,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "main",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/sh", "-c", "echo container is alive; sleep 10000"},
|
||||
},
|
||||
},
|
||||
@ -600,6 +617,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
}
|
||||
})
|
||||
|
||||
// Slow (~7 mins)
|
||||
It("should have their auto-restart back-off timer reset on image update [Slow][NodeConformance]", func() {
|
||||
podName := "pod-back-off-image"
|
||||
containerName := "back-off"
|
||||
@ -612,7 +630,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: containerName,
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/sh", "-c", "sleep 5", "/crash/missing"},
|
||||
},
|
||||
},
|
||||
@ -623,7 +641,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
|
||||
By("updating the image")
|
||||
podClient.Update(podName, func(pod *v1.Pod) {
|
||||
pod.Spec.Containers[0].Image = imageutils.GetE2EImage(imageutils.NginxSlim)
|
||||
pod.Spec.Containers[0].Image = imageutils.GetE2EImage(imageutils.Nginx)
|
||||
})
|
||||
|
||||
time.Sleep(syncLoopFrequency)
|
||||
@ -640,7 +658,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
}
|
||||
})
|
||||
|
||||
// Slow issue #19027 (20 mins)
|
||||
// Slow by design (~27 mins) issue #19027
|
||||
It("should cap back-off at MaxContainerBackOff [Slow][NodeConformance]", func() {
|
||||
podName := "back-off-cap"
|
||||
containerName := "back-off-cap"
|
||||
@ -653,7 +671,7 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: containerName,
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/sh", "-c", "sleep 5", "/crash/missing"},
|
||||
},
|
||||
},
|
||||
@ -694,4 +712,64 @@ var _ = framework.KubeDescribe("Pods", func() {
|
||||
framework.Failf("expected %s back-off got=%s on delay2", kubelet.MaxContainerBackOff, delay2)
|
||||
}
|
||||
})
|
||||
|
||||
// TODO(freehan): label the test to be [NodeConformance] after tests are proven to be stable.
|
||||
It("should support pod readiness gates [NodeFeature:PodReadinessGate]", func() {
|
||||
podName := "pod-ready"
|
||||
readinessGate1 := "k8s.io/test-condition1"
|
||||
readinessGate2 := "k8s.io/test-condition2"
|
||||
patchStatusFmt := `{"status":{"conditions":[{"type":%q, "status":%q}]}}`
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
Labels: map[string]string{"test": "pod-readiness-gate"},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "pod-readiness-gate",
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"/bin/sh", "-c", "echo container is alive; sleep 10000"},
|
||||
},
|
||||
},
|
||||
ReadinessGates: []v1.PodReadinessGate{
|
||||
{ConditionType: v1.PodConditionType(readinessGate1)},
|
||||
{ConditionType: v1.PodConditionType(readinessGate2)},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
validatePodReadiness := func(expectReady bool) {
|
||||
Expect(wait.Poll(time.Second, maxReadyStatusUpdateTolerance, func() (bool, error) {
|
||||
podReady := podClient.PodIsReady(podName)
|
||||
res := expectReady == podReady
|
||||
if !res {
|
||||
framework.Logf("Expect the Ready condition of pod %q to be %v, but got %v", podName, expectReady, podReady)
|
||||
}
|
||||
return res, nil
|
||||
})).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
By("submitting the pod to kubernetes")
|
||||
podClient.CreateSync(pod)
|
||||
Expect(podClient.PodIsReady(podName)).To(BeFalse(), "Expect pod's Ready condition to be false initially.")
|
||||
|
||||
By(fmt.Sprintf("patching pod status with condition %q to true", readinessGate1))
|
||||
_, err := podClient.Patch(podName, types.StrategicMergePatchType, []byte(fmt.Sprintf(patchStatusFmt, readinessGate1, "True")), "status")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
// Sleep for 10 seconds.
|
||||
time.Sleep(maxReadyStatusUpdateTolerance)
|
||||
Expect(podClient.PodIsReady(podName)).To(BeFalse(), "Expect pod's Ready condition to be false with only one condition in readinessGates equal to True")
|
||||
|
||||
By(fmt.Sprintf("patching pod status with condition %q to true", readinessGate2))
|
||||
_, err = podClient.Patch(podName, types.StrategicMergePatchType, []byte(fmt.Sprintf(patchStatusFmt, readinessGate2, "True")), "status")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
validatePodReadiness(true)
|
||||
|
||||
By(fmt.Sprintf("patching pod status with condition %q to false", readinessGate1))
|
||||
_, err = podClient.Patch(podName, types.StrategicMergePatchType, []byte(fmt.Sprintf(patchStatusFmt, readinessGate1, "False")), "status")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
validatePodReadiness(false)
|
||||
|
||||
})
|
||||
})
|
||||
|
5
vendor/k8s.io/kubernetes/test/e2e/common/privileged.go
generated
vendored
5
vendor/k8s.io/kubernetes/test/e2e/common/privileged.go
generated
vendored
@ -24,6 +24,7 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
)
|
||||
|
||||
type PrivilegedPodTestConfig struct {
|
||||
@ -90,14 +91,14 @@ func (c *PrivilegedPodTestConfig) createPodsSpec() *v1.Pod {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: c.privilegedContainer,
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
ImagePullPolicy: v1.PullIfNotPresent,
|
||||
SecurityContext: &v1.SecurityContext{Privileged: &isPrivileged},
|
||||
Command: []string{"/bin/sleep", "10000"},
|
||||
},
|
||||
{
|
||||
Name: c.notPrivilegedContainer,
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
ImagePullPolicy: v1.PullIfNotPresent,
|
||||
SecurityContext: &v1.SecurityContext{Privileged: ¬Privileged},
|
||||
Command: []string{"/bin/sleep", "10000"},
|
||||
|
1675
vendor/k8s.io/kubernetes/test/e2e/common/projected.go
generated
vendored
1675
vendor/k8s.io/kubernetes/test/e2e/common/projected.go
generated
vendored
File diff suppressed because it is too large
Load Diff
147
vendor/k8s.io/kubernetes/test/e2e/common/projected_combined.go
generated
vendored
Normal file
147
vendor/k8s.io/kubernetes/test/e2e/common/projected_combined.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
Copyright 2014 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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
)
|
||||
|
||||
var _ = Describe("[sig-storage] Projected combined", func() {
|
||||
f := framework.NewDefaultFramework("projected")
|
||||
|
||||
// Test multiple projections
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, multiple projections
|
||||
Description: A Pod is created with a projected volume source for secrets, configMap and downwardAPI with pod name, cpu and memory limits and cpu and memory requests. Pod MUST be able to read the secrets, configMap values and the cpu and memory limits as well as cpu and memory requests from the mounted DownwardAPIVolumeFiles.
|
||||
*/
|
||||
framework.ConformanceIt("should project all components that make up the projection API [Projection][NodeConformance]", func() {
|
||||
var err error
|
||||
podName := "projected-volume-" + string(uuid.NewUUID())
|
||||
secretName := "secret-projected-all-test-volume-" + string(uuid.NewUUID())
|
||||
configMapName := "configmap-projected-all-test-volume-" + string(uuid.NewUUID())
|
||||
configMap := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: configMapName,
|
||||
},
|
||||
Data: map[string]string{
|
||||
"configmap-data": "configmap-value-1",
|
||||
},
|
||||
}
|
||||
secret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: secretName,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"secret-data": []byte("secret-value-1"),
|
||||
},
|
||||
}
|
||||
|
||||
By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
|
||||
if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
||||
}
|
||||
By(fmt.Sprintf("Creating secret with name %s", secret.Name))
|
||||
if secret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", secret.Name, err)
|
||||
}
|
||||
|
||||
pod := projectedAllVolumeBasePod(podName, secretName, configMapName, nil, nil)
|
||||
pod.Spec.Containers = []v1.Container{
|
||||
{
|
||||
Name: "projected-all-volume-test",
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "cat /all/podname && cat /all/secret-data && cat /all/configmap-data"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "podinfo",
|
||||
MountPath: "/all",
|
||||
ReadOnly: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
f.TestContainerOutput("Check all projections for projected volume plugin", pod, 0, []string{
|
||||
fmt.Sprintf("%s", podName),
|
||||
"secret-value-1",
|
||||
"configmap-value-1",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func projectedAllVolumeBasePod(podName string, secretName string, configMapName string, labels, annotations map[string]string) *v1.Pod {
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "podinfo",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
DownwardAPI: &v1.DownwardAPIProjection{
|
||||
Items: []v1.DownwardAPIVolumeFile{
|
||||
{
|
||||
Path: "podname",
|
||||
FieldRef: &v1.ObjectFieldSelector{
|
||||
APIVersion: "v1",
|
||||
FieldPath: "metadata.name",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Secret: &v1.SecretProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: secretName,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: configMapName,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
return pod
|
||||
}
|
683
vendor/k8s.io/kubernetes/test/e2e/common/projected_configmap.go
generated
vendored
Normal file
683
vendor/k8s.io/kubernetes/test/e2e/common/projected_configmap.go
generated
vendored
Normal file
@ -0,0 +1,683 @@
|
||||
/*
|
||||
Copyright 2014 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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("[sig-storage] Projected configMap", func() {
|
||||
f := framework.NewDefaultFramework("projected")
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, ConfigMap, volume mode default
|
||||
Description: A Pod is created with projected volume source ‘ConfigMap’ to store a configMap with default permission mode. Pod MUST be able to read the content of the ConfigMap successfully and the mode on the volume MUST be -rw-r—-r—-.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume [NodeConformance]", func() {
|
||||
doProjectedConfigMapE2EWithoutMappings(f, 0, 0, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, ConfigMap, volume mode 0400
|
||||
Description: A Pod is created with projected volume source ‘ConfigMap’ to store a configMap with permission mode set to 0400. Pod MUST be able to read the content of the ConfigMap successfully and the mode on the volume MUST be -r——-——-—-.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with defaultMode set [NodeConformance]", func() {
|
||||
defaultMode := int32(0400)
|
||||
doProjectedConfigMapE2EWithoutMappings(f, 0, 0, &defaultMode)
|
||||
})
|
||||
|
||||
It("should be consumable from pods in volume as non-root with defaultMode and fsGroup set [NodeFeature:FSGroup]", func() {
|
||||
defaultMode := int32(0440) /* setting fsGroup sets mode to at least 440 */
|
||||
doProjectedConfigMapE2EWithoutMappings(f, 1000, 1001, &defaultMode)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, ConfigMap, non-root user
|
||||
Description: A Pod is created with projected volume source ‘ConfigMap’ to store a configMap as non-root user with uid 1000. Pod MUST be able to read the content of the ConfigMap successfully and the mode on the volume MUST be -rw—r——r—-.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume as non-root [NodeConformance]", func() {
|
||||
doProjectedConfigMapE2EWithoutMappings(f, 1000, 0, nil)
|
||||
})
|
||||
|
||||
It("should be consumable from pods in volume as non-root with FSGroup [NodeFeature:FSGroup]", func() {
|
||||
doProjectedConfigMapE2EWithoutMappings(f, 1000, 1001, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, ConfigMap, mapped
|
||||
Description: A Pod is created with projected volume source ‘ConfigMap’ to store a configMap with default permission mode. The ConfigMap is also mapped to a custom path. Pod MUST be able to read the content of the ConfigMap from the custom location successfully and the mode on the volume MUST be -rw—r——r—-.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings [NodeConformance]", func() {
|
||||
doProjectedConfigMapE2EWithMappings(f, 0, 0, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, ConfigMap, mapped, volume mode 0400
|
||||
Description: A Pod is created with projected volume source ‘ConfigMap’ to store a configMap with permission mode set to 0400. The ConfigMap is also mapped to a custom path. Pod MUST be able to read the content of the ConfigMap from the custom location successfully and the mode on the volume MUST be -r-—r——r—-.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings and Item mode set [NodeConformance]", func() {
|
||||
mode := int32(0400)
|
||||
doProjectedConfigMapE2EWithMappings(f, 0, 0, &mode)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, ConfigMap, mapped, non-root user
|
||||
Description: A Pod is created with projected volume source ‘ConfigMap’ to store a configMap as non-root user with uid 1000. The ConfigMap is also mapped to a custom path. Pod MUST be able to read the content of the ConfigMap from the custom location successfully and the mode on the volume MUST be -r-—r——r—-.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings as non-root [NodeConformance]", func() {
|
||||
doProjectedConfigMapE2EWithMappings(f, 1000, 0, nil)
|
||||
})
|
||||
|
||||
It("should be consumable from pods in volume with mappings as non-root with FSGroup [NodeFeature:FSGroup]", func() {
|
||||
doProjectedConfigMapE2EWithMappings(f, 1000, 1001, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, ConfigMap, update
|
||||
Description: A Pod is created with projected volume source ‘ConfigMap’ to store a configMap and performs a create and update to new value. Pod MUST be able to create the configMap with value-1. Pod MUST be able to update the value in the confgiMap to value-2.
|
||||
*/
|
||||
framework.ConformanceIt("updates should be reflected in volume [NodeConformance]", func() {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
|
||||
|
||||
name := "projected-configmap-test-upd-" + string(uuid.NewUUID())
|
||||
volumeName := "projected-configmap-volume"
|
||||
volumeMountPath := "/etc/projected-configmap-volume"
|
||||
containerName := "projected-configmap-volume-test"
|
||||
configMap := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: name,
|
||||
},
|
||||
Data: map[string]string{
|
||||
"data-1": "value-1",
|
||||
},
|
||||
}
|
||||
|
||||
By(fmt.Sprintf("Creating projection with configMap that has name %s", configMap.Name))
|
||||
var err error
|
||||
if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-projected-configmaps-" + string(uuid.NewUUID()),
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: volumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: containerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-configmap-volume/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: volumeName,
|
||||
MountPath: volumeMountPath,
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
By("Creating the pod")
|
||||
f.PodClient().CreateSync(pod)
|
||||
|
||||
pollLogs := func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, containerName)
|
||||
}
|
||||
|
||||
Eventually(pollLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-1"))
|
||||
|
||||
By(fmt.Sprintf("Updating configmap %v", configMap.Name))
|
||||
configMap.ResourceVersion = "" // to force update
|
||||
configMap.Data["data-1"] = "value-2"
|
||||
_, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(configMap)
|
||||
Expect(err).NotTo(HaveOccurred(), "Failed to update configmap %q in namespace %q", configMap.Name, f.Namespace.Name)
|
||||
|
||||
By("waiting to observe update in volume")
|
||||
Eventually(pollLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-2"))
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, ConfigMap, create, update and delete
|
||||
Description: Create a Pod with three containers with ConfigMaps namely a create, update and delete container. Create Container when started MUST not have configMap, update and delete containers MUST be created with a ConfigMap value as ‘value-1’. Create a configMap in the create container, the Pod MUST be able to read the configMap from the create container. Update the configMap in the update container, Pod MUST be able to read the updated configMap value. Delete the configMap in the delete container. Pod MUST fail to read the configMap from the delete container.
|
||||
*/
|
||||
framework.ConformanceIt("optional updates should be reflected in volume [NodeConformance]", func() {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
|
||||
trueVal := true
|
||||
volumeMountPath := "/etc/projected-configmap-volumes"
|
||||
|
||||
deleteName := "cm-test-opt-del-" + string(uuid.NewUUID())
|
||||
deleteContainerName := "delcm-volume-test"
|
||||
deleteVolumeName := "deletecm-volume"
|
||||
deleteConfigMap := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: deleteName,
|
||||
},
|
||||
Data: map[string]string{
|
||||
"data-1": "value-1",
|
||||
},
|
||||
}
|
||||
|
||||
updateName := "cm-test-opt-upd-" + string(uuid.NewUUID())
|
||||
updateContainerName := "updcm-volume-test"
|
||||
updateVolumeName := "updatecm-volume"
|
||||
updateConfigMap := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: updateName,
|
||||
},
|
||||
Data: map[string]string{
|
||||
"data-1": "value-1",
|
||||
},
|
||||
}
|
||||
|
||||
createName := "cm-test-opt-create-" + string(uuid.NewUUID())
|
||||
createContainerName := "createcm-volume-test"
|
||||
createVolumeName := "createcm-volume"
|
||||
createConfigMap := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: createName,
|
||||
},
|
||||
Data: map[string]string{
|
||||
"data-1": "value-1",
|
||||
},
|
||||
}
|
||||
|
||||
By(fmt.Sprintf("Creating configMap with name %s", deleteConfigMap.Name))
|
||||
var err error
|
||||
if deleteConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(deleteConfigMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", deleteConfigMap.Name, err)
|
||||
}
|
||||
|
||||
By(fmt.Sprintf("Creating configMap with name %s", updateConfigMap.Name))
|
||||
if updateConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(updateConfigMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", updateConfigMap.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-projected-configmaps-" + string(uuid.NewUUID()),
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: deleteVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: deleteName,
|
||||
},
|
||||
Optional: &trueVal,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: updateVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: updateName,
|
||||
},
|
||||
Optional: &trueVal,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: createVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: createName,
|
||||
},
|
||||
Optional: &trueVal,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: deleteContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-configmap-volumes/delete/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: deleteVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "delete"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: updateContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-configmap-volumes/update/data-3"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: updateVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "update"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: createContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-configmap-volumes/create/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "create"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
By("Creating the pod")
|
||||
f.PodClient().CreateSync(pod)
|
||||
|
||||
pollCreateLogs := func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, createContainerName)
|
||||
}
|
||||
Eventually(pollCreateLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("Error reading file /etc/projected-configmap-volumes/create/data-1"))
|
||||
|
||||
pollUpdateLogs := func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, updateContainerName)
|
||||
}
|
||||
Eventually(pollUpdateLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("Error reading file /etc/projected-configmap-volumes/update/data-3"))
|
||||
|
||||
pollDeleteLogs := func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, deleteContainerName)
|
||||
}
|
||||
Eventually(pollDeleteLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-1"))
|
||||
|
||||
By(fmt.Sprintf("Deleting configmap %v", deleteConfigMap.Name))
|
||||
err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Delete(deleteConfigMap.Name, &metav1.DeleteOptions{})
|
||||
Expect(err).NotTo(HaveOccurred(), "Failed to delete configmap %q in namespace %q", deleteConfigMap.Name, f.Namespace.Name)
|
||||
|
||||
By(fmt.Sprintf("Updating configmap %v", updateConfigMap.Name))
|
||||
updateConfigMap.ResourceVersion = "" // to force update
|
||||
delete(updateConfigMap.Data, "data-1")
|
||||
updateConfigMap.Data["data-3"] = "value-3"
|
||||
_, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(updateConfigMap)
|
||||
Expect(err).NotTo(HaveOccurred(), "Failed to update configmap %q in namespace %q", updateConfigMap.Name, f.Namespace.Name)
|
||||
|
||||
By(fmt.Sprintf("Creating configMap with name %s", createConfigMap.Name))
|
||||
if createConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(createConfigMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", createConfigMap.Name, err)
|
||||
}
|
||||
|
||||
By("waiting to observe update in volume")
|
||||
|
||||
Eventually(pollCreateLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-1"))
|
||||
Eventually(pollUpdateLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-3"))
|
||||
Eventually(pollDeleteLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("Error reading file /etc/projected-configmap-volumes/delete/data-1"))
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, ConfigMap, multiple volume paths
|
||||
Description: A Pod is created with a projected volume source ‘ConfigMap’ to store a configMap. The configMap is mapped to two different volume mounts. Pod MUST be able to read the content of the configMap successfully from the two volume mounts.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable in multiple volumes in the same pod [NodeConformance]", func() {
|
||||
var (
|
||||
name = "projected-configmap-test-volume-" + string(uuid.NewUUID())
|
||||
volumeName = "projected-configmap-volume"
|
||||
volumeMountPath = "/etc/projected-configmap-volume"
|
||||
volumeName2 = "projected-configmap-volume-2"
|
||||
volumeMountPath2 = "/etc/projected-configmap-volume-2"
|
||||
configMap = newConfigMap(f, name)
|
||||
)
|
||||
|
||||
By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
|
||||
var err error
|
||||
if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-projected-configmaps-" + string(uuid.NewUUID()),
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: volumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: volumeName2,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "projected-configmap-volume-test",
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{"--file_content=/etc/projected-configmap-volume/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: volumeName,
|
||||
MountPath: volumeMountPath,
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: volumeName2,
|
||||
MountPath: volumeMountPath2,
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
f.TestContainerOutput("consume configMaps", pod, 0, []string{
|
||||
"content of file \"/etc/projected-configmap-volume/data-1\": value-1",
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
//The pod is in pending during volume creation until the configMap objects are available
|
||||
//or until mount the configMap volume times out. There is no configMap object defined for the pod, so it should return timout exception unless it is marked optional.
|
||||
//Slow (~5 mins)
|
||||
It("Should fail non-optional pod creation due to configMap object does not exist [Slow]", func() {
|
||||
volumeMountPath := "/etc/projected-configmap-volumes"
|
||||
podName := "pod-projected-configmaps-" + string(uuid.NewUUID())
|
||||
err := createNonOptionalConfigMapPod(f, volumeMountPath, podName)
|
||||
Expect(err).To(HaveOccurred(), "created pod %q with non-optional configMap in namespace %q", podName, f.Namespace.Name)
|
||||
})
|
||||
|
||||
//ConfigMap object defined for the pod, If a key is specified which is not present in the ConfigMap,
|
||||
// the volume setup will error unless it is marked optional, during the pod creation.
|
||||
//Slow (~5 mins)
|
||||
It("Should fail non-optional pod creation due to the key in the configMap object does not exist [Slow]", func() {
|
||||
volumeMountPath := "/etc/configmap-volumes"
|
||||
podName := "pod-configmaps-" + string(uuid.NewUUID())
|
||||
err := createNonOptionalConfigMapPodWithConfig(f, volumeMountPath, podName)
|
||||
Expect(err).To(HaveOccurred(), "created pod %q with non-optional configMap in namespace %q", podName, f.Namespace.Name)
|
||||
})
|
||||
})
|
||||
|
||||
func doProjectedConfigMapE2EWithoutMappings(f *framework.Framework, uid, fsGroup int64, defaultMode *int32) {
|
||||
userID := int64(uid)
|
||||
groupID := int64(fsGroup)
|
||||
|
||||
var (
|
||||
name = "projected-configmap-test-volume-" + string(uuid.NewUUID())
|
||||
volumeName = "projected-configmap-volume"
|
||||
volumeMountPath = "/etc/projected-configmap-volume"
|
||||
configMap = newConfigMap(f, name)
|
||||
)
|
||||
|
||||
By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
|
||||
var err error
|
||||
if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-projected-configmaps-" + string(uuid.NewUUID()),
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: volumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "projected-configmap-volume-test",
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{
|
||||
"--file_content=/etc/projected-configmap-volume/data-1",
|
||||
"--file_mode=/etc/projected-configmap-volume/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: volumeName,
|
||||
MountPath: volumeMountPath,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
if userID != 0 {
|
||||
pod.Spec.SecurityContext.RunAsUser = &userID
|
||||
}
|
||||
|
||||
if groupID != 0 {
|
||||
pod.Spec.SecurityContext.FSGroup = &groupID
|
||||
}
|
||||
|
||||
if defaultMode != nil {
|
||||
//pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].ConfigMap.DefaultMode = defaultMode
|
||||
pod.Spec.Volumes[0].VolumeSource.Projected.DefaultMode = defaultMode
|
||||
} else {
|
||||
mode := int32(0644)
|
||||
defaultMode = &mode
|
||||
}
|
||||
|
||||
modeString := fmt.Sprintf("%v", os.FileMode(*defaultMode))
|
||||
output := []string{
|
||||
"content of file \"/etc/projected-configmap-volume/data-1\": value-1",
|
||||
"mode of file \"/etc/projected-configmap-volume/data-1\": " + modeString,
|
||||
}
|
||||
f.TestContainerOutput("consume configMaps", pod, 0, output)
|
||||
}
|
||||
|
||||
func doProjectedConfigMapE2EWithMappings(f *framework.Framework, uid, fsGroup int64, itemMode *int32) {
|
||||
userID := int64(uid)
|
||||
groupID := int64(fsGroup)
|
||||
|
||||
var (
|
||||
name = "projected-configmap-test-volume-map-" + string(uuid.NewUUID())
|
||||
volumeName = "projected-configmap-volume"
|
||||
volumeMountPath = "/etc/projected-configmap-volume"
|
||||
configMap = newConfigMap(f, name)
|
||||
)
|
||||
|
||||
By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
|
||||
|
||||
var err error
|
||||
if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-projected-configmaps-" + string(uuid.NewUUID()),
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: volumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
ConfigMap: &v1.ConfigMapProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
Items: []v1.KeyToPath{
|
||||
{
|
||||
Key: "data-2",
|
||||
Path: "path/to/data-2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "projected-configmap-volume-test",
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{"--file_content=/etc/projected-configmap-volume/path/to/data-2",
|
||||
"--file_mode=/etc/projected-configmap-volume/path/to/data-2"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: volumeName,
|
||||
MountPath: volumeMountPath,
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
if userID != 0 {
|
||||
pod.Spec.SecurityContext.RunAsUser = &userID
|
||||
}
|
||||
|
||||
if groupID != 0 {
|
||||
pod.Spec.SecurityContext.FSGroup = &groupID
|
||||
}
|
||||
|
||||
if itemMode != nil {
|
||||
//pod.Spec.Volumes[0].VolumeSource.ConfigMap.Items[0].Mode = itemMode
|
||||
pod.Spec.Volumes[0].VolumeSource.Projected.DefaultMode = itemMode
|
||||
} else {
|
||||
mode := int32(0644)
|
||||
itemMode = &mode
|
||||
}
|
||||
|
||||
// Just check file mode if fsGroup is not set. If fsGroup is set, the
|
||||
// final mode is adjusted and we are not testing that case.
|
||||
output := []string{
|
||||
"content of file \"/etc/projected-configmap-volume/path/to/data-2\": value-2",
|
||||
}
|
||||
if fsGroup == 0 {
|
||||
modeString := fmt.Sprintf("%v", os.FileMode(*itemMode))
|
||||
output = append(output, "mode of file \"/etc/projected-configmap-volume/path/to/data-2\": "+modeString)
|
||||
}
|
||||
f.TestContainerOutput("consume configMaps", pod, 0, output)
|
||||
}
|
398
vendor/k8s.io/kubernetes/test/e2e/common/projected_downwardapi.go
generated
vendored
Normal file
398
vendor/k8s.io/kubernetes/test/e2e/common/projected_downwardapi.go
generated
vendored
Normal file
@ -0,0 +1,398 @@
|
||||
/*
|
||||
Copyright 2014 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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("[sig-storage] Projected downwardAPI", func() {
|
||||
f := framework.NewDefaultFramework("projected")
|
||||
|
||||
// How long to wait for a log pod to be displayed
|
||||
const podLogTimeout = 2 * time.Minute
|
||||
var podClient *framework.PodClient
|
||||
BeforeEach(func() {
|
||||
podClient = f.PodClient()
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, pod name
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests. Pod MUST be able to read the pod name from the mounted DownwardAPIVolumeFiles.
|
||||
*/
|
||||
framework.ConformanceIt("should provide podname only [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
pod := downwardAPIVolumePodForSimpleTest(podName, "/etc/podinfo/podname")
|
||||
|
||||
f.TestContainerOutput("downward API volume plugin", pod, 0, []string{
|
||||
fmt.Sprintf("%s\n", podName),
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, volume mode 0400
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests. The default mode for the volume mount is set to 0400. Pod MUST be able to read the pod name from the mounted DownwardAPIVolumeFiles and the volume mode must be -r—-—————.
|
||||
*/
|
||||
framework.ConformanceIt("should set DefaultMode on files [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
defaultMode := int32(0400)
|
||||
pod := projectedDownwardAPIVolumePodForModeTest(podName, "/etc/podinfo/podname", nil, &defaultMode)
|
||||
|
||||
f.TestContainerOutput("downward API volume plugin", pod, 0, []string{
|
||||
"mode of file \"/etc/podinfo/podname\": -r--------",
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, volume mode 0400
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests. The default mode for the volume mount is set to 0400. Pod MUST be able to read the pod name from the mounted DownwardAPIVolumeFiles and the volume mode must be -r—-—————.
|
||||
*/
|
||||
framework.ConformanceIt("should set mode on item file [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
mode := int32(0400)
|
||||
pod := projectedDownwardAPIVolumePodForModeTest(podName, "/etc/podinfo/podname", &mode, nil)
|
||||
|
||||
f.TestContainerOutput("downward API volume plugin", pod, 0, []string{
|
||||
"mode of file \"/etc/podinfo/podname\": -r--------",
|
||||
})
|
||||
})
|
||||
|
||||
It("should provide podname as non-root with fsgroup [NodeFeature:FSGroup]", func() {
|
||||
podName := "metadata-volume-" + string(uuid.NewUUID())
|
||||
uid := int64(1001)
|
||||
gid := int64(1234)
|
||||
pod := downwardAPIVolumePodForSimpleTest(podName, "/etc/podinfo/podname")
|
||||
pod.Spec.SecurityContext = &v1.PodSecurityContext{
|
||||
RunAsUser: &uid,
|
||||
FSGroup: &gid,
|
||||
}
|
||||
f.TestContainerOutput("downward API volume plugin", pod, 0, []string{
|
||||
fmt.Sprintf("%s\n", podName),
|
||||
})
|
||||
})
|
||||
|
||||
It("should provide podname as non-root with fsgroup and defaultMode [NodeFeature:FSGroup]", func() {
|
||||
podName := "metadata-volume-" + string(uuid.NewUUID())
|
||||
uid := int64(1001)
|
||||
gid := int64(1234)
|
||||
mode := int32(0440) /* setting fsGroup sets mode to at least 440 */
|
||||
pod := projectedDownwardAPIVolumePodForModeTest(podName, "/etc/podinfo/podname", &mode, nil)
|
||||
pod.Spec.SecurityContext = &v1.PodSecurityContext{
|
||||
RunAsUser: &uid,
|
||||
FSGroup: &gid,
|
||||
}
|
||||
f.TestContainerOutput("downward API volume plugin", pod, 0, []string{
|
||||
"mode of file \"/etc/podinfo/podname\": -r--r-----",
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, update labels
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests and label items. Pod MUST be able to read the labels from the mounted DownwardAPIVolumeFiles. Labels are then updated. Pod MUST be able to read the updated values for the Labels.
|
||||
*/
|
||||
framework.ConformanceIt("should update labels on modification [NodeConformance]", func() {
|
||||
labels := map[string]string{}
|
||||
labels["key1"] = "value1"
|
||||
labels["key2"] = "value2"
|
||||
|
||||
podName := "labelsupdate" + string(uuid.NewUUID())
|
||||
pod := projectedDownwardAPIVolumePodForUpdateTest(podName, labels, map[string]string{}, "/etc/podinfo/labels")
|
||||
containerName := "client-container"
|
||||
By("Creating the pod")
|
||||
podClient.CreateSync(pod)
|
||||
|
||||
Eventually(func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, podName, containerName)
|
||||
},
|
||||
podLogTimeout, framework.Poll).Should(ContainSubstring("key1=\"value1\"\n"))
|
||||
|
||||
//modify labels
|
||||
podClient.Update(podName, func(pod *v1.Pod) {
|
||||
pod.Labels["key3"] = "value3"
|
||||
})
|
||||
|
||||
Eventually(func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, containerName)
|
||||
},
|
||||
podLogTimeout, framework.Poll).Should(ContainSubstring("key3=\"value3\"\n"))
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, update annotation
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests and annotation items. Pod MUST be able to read the annotations from the mounted DownwardAPIVolumeFiles. Annotations are then updated. Pod MUST be able to read the updated values for the Annotations.
|
||||
*/
|
||||
framework.ConformanceIt("should update annotations on modification [NodeConformance]", func() {
|
||||
annotations := map[string]string{}
|
||||
annotations["builder"] = "bar"
|
||||
podName := "annotationupdate" + string(uuid.NewUUID())
|
||||
pod := projectedDownwardAPIVolumePodForUpdateTest(podName, map[string]string{}, annotations, "/etc/podinfo/annotations")
|
||||
|
||||
containerName := "client-container"
|
||||
By("Creating the pod")
|
||||
podClient.CreateSync(pod)
|
||||
|
||||
pod, err := podClient.Get(pod.Name, metav1.GetOptions{})
|
||||
Expect(err).NotTo(HaveOccurred(), "Failed to get pod %q", pod.Name)
|
||||
|
||||
Eventually(func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, containerName)
|
||||
},
|
||||
podLogTimeout, framework.Poll).Should(ContainSubstring("builder=\"bar\"\n"))
|
||||
|
||||
//modify annotations
|
||||
podClient.Update(podName, func(pod *v1.Pod) {
|
||||
pod.Annotations["builder"] = "foo"
|
||||
})
|
||||
|
||||
Eventually(func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, containerName)
|
||||
},
|
||||
podLogTimeout, framework.Poll).Should(ContainSubstring("builder=\"foo\"\n"))
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, CPU limits
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests. Pod MUST be able to read the cpu limits from the mounted DownwardAPIVolumeFiles.
|
||||
*/
|
||||
framework.ConformanceIt("should provide container's cpu limit [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
pod := downwardAPIVolumeForContainerResources(podName, "/etc/podinfo/cpu_limit")
|
||||
|
||||
f.TestContainerOutput("downward API volume plugin", pod, 0, []string{
|
||||
fmt.Sprintf("2\n"),
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, memory limits
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests. Pod MUST be able to read the memory limits from the mounted DownwardAPIVolumeFiles.
|
||||
*/
|
||||
framework.ConformanceIt("should provide container's memory limit [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
pod := downwardAPIVolumeForContainerResources(podName, "/etc/podinfo/memory_limit")
|
||||
|
||||
f.TestContainerOutput("downward API volume plugin", pod, 0, []string{
|
||||
fmt.Sprintf("67108864\n"),
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, CPU request
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests. Pod MUST be able to read the cpu request from the mounted DownwardAPIVolumeFiles.
|
||||
*/
|
||||
framework.ConformanceIt("should provide container's cpu request [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
pod := downwardAPIVolumeForContainerResources(podName, "/etc/podinfo/cpu_request")
|
||||
|
||||
f.TestContainerOutput("downward API volume plugin", pod, 0, []string{
|
||||
fmt.Sprintf("1\n"),
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, memory request
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests. Pod MUST be able to read the memory request from the mounted DownwardAPIVolumeFiles.
|
||||
*/
|
||||
framework.ConformanceIt("should provide container's memory request [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
pod := downwardAPIVolumeForContainerResources(podName, "/etc/podinfo/memory_request")
|
||||
|
||||
f.TestContainerOutput("downward API volume plugin", pod, 0, []string{
|
||||
fmt.Sprintf("33554432\n"),
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, CPU limit, node allocatable
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests. The CPU and memory resources for requests and limits are NOT specified for the container. Pod MUST be able to read the default cpu limits from the mounted DownwardAPIVolumeFiles.
|
||||
*/
|
||||
framework.ConformanceIt("should provide node allocatable (cpu) as default cpu limit if the limit is not set [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
pod := downwardAPIVolumeForDefaultContainerResources(podName, "/etc/podinfo/cpu_limit")
|
||||
|
||||
f.TestContainerOutputRegexp("downward API volume plugin", pod, 0, []string{"[1-9]"})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, DownwardAPI, memory limit, node allocatable
|
||||
Description: A Pod is created with a projected volume source for downwardAPI with pod name, cpu and memory limits and cpu and memory requests. The CPU and memory resources for requests and limits are NOT specified for the container. Pod MUST be able to read the default memory limits from the mounted DownwardAPIVolumeFiles.
|
||||
*/
|
||||
framework.ConformanceIt("should provide node allocatable (memory) as default memory limit if the limit is not set [NodeConformance]", func() {
|
||||
podName := "downwardapi-volume-" + string(uuid.NewUUID())
|
||||
pod := downwardAPIVolumeForDefaultContainerResources(podName, "/etc/podinfo/memory_limit")
|
||||
|
||||
f.TestContainerOutputRegexp("downward API volume plugin", pod, 0, []string{"[1-9]"})
|
||||
})
|
||||
})
|
||||
|
||||
func projectedDownwardAPIVolumePodForModeTest(name, filePath string, itemMode, defaultMode *int32) *v1.Pod {
|
||||
pod := projectedDownwardAPIVolumeBasePod(name, nil, nil)
|
||||
|
||||
pod.Spec.Containers = []v1.Container{
|
||||
{
|
||||
Name: "client-container",
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--file_mode=" + filePath},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "podinfo",
|
||||
MountPath: "/etc/podinfo",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if itemMode != nil {
|
||||
pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].DownwardAPI.Items[0].Mode = itemMode
|
||||
}
|
||||
if defaultMode != nil {
|
||||
pod.Spec.Volumes[0].VolumeSource.Projected.DefaultMode = defaultMode
|
||||
}
|
||||
|
||||
return pod
|
||||
}
|
||||
|
||||
func projectedDownwardAPIVolumePodForUpdateTest(name string, labels, annotations map[string]string, filePath string) *v1.Pod {
|
||||
pod := projectedDownwardAPIVolumeBasePod(name, labels, annotations)
|
||||
|
||||
pod.Spec.Containers = []v1.Container{
|
||||
{
|
||||
Name: "client-container",
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", "--retry_time=1200", "--file_content_in_loop=" + filePath},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "podinfo",
|
||||
MountPath: "/etc/podinfo",
|
||||
ReadOnly: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
applyLabelsAndAnnotationsToProjectedDownwardAPIPod(labels, annotations, pod)
|
||||
return pod
|
||||
}
|
||||
|
||||
func projectedDownwardAPIVolumeBasePod(name string, labels, annotations map[string]string) *v1.Pod {
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "podinfo",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
DownwardAPI: &v1.DownwardAPIProjection{
|
||||
Items: []v1.DownwardAPIVolumeFile{
|
||||
{
|
||||
Path: "podname",
|
||||
FieldRef: &v1.ObjectFieldSelector{
|
||||
APIVersion: "v1",
|
||||
FieldPath: "metadata.name",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "cpu_limit",
|
||||
ResourceFieldRef: &v1.ResourceFieldSelector{
|
||||
ContainerName: "client-container",
|
||||
Resource: "limits.cpu",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "cpu_request",
|
||||
ResourceFieldRef: &v1.ResourceFieldSelector{
|
||||
ContainerName: "client-container",
|
||||
Resource: "requests.cpu",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "memory_limit",
|
||||
ResourceFieldRef: &v1.ResourceFieldSelector{
|
||||
ContainerName: "client-container",
|
||||
Resource: "limits.memory",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "memory_request",
|
||||
ResourceFieldRef: &v1.ResourceFieldSelector{
|
||||
ContainerName: "client-container",
|
||||
Resource: "requests.memory",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
return pod
|
||||
}
|
||||
|
||||
func applyLabelsAndAnnotationsToProjectedDownwardAPIPod(labels, annotations map[string]string, pod *v1.Pod) {
|
||||
if len(labels) > 0 {
|
||||
pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].DownwardAPI.Items = append(pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].DownwardAPI.Items, v1.DownwardAPIVolumeFile{
|
||||
Path: "labels",
|
||||
FieldRef: &v1.ObjectFieldSelector{
|
||||
APIVersion: "v1",
|
||||
FieldPath: "metadata.labels",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if len(annotations) > 0 {
|
||||
pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].DownwardAPI.Items = append(pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].DownwardAPI.Items, v1.DownwardAPIVolumeFile{
|
||||
Path: "annotations",
|
||||
FieldRef: &v1.ObjectFieldSelector{
|
||||
APIVersion: "v1",
|
||||
FieldPath: "metadata.annotations",
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
582
vendor/k8s.io/kubernetes/test/e2e/common/projected_secret.go
generated
vendored
Normal file
582
vendor/k8s.io/kubernetes/test/e2e/common/projected_secret.go
generated
vendored
Normal file
@ -0,0 +1,582 @@
|
||||
/*
|
||||
Copyright 2014 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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("[sig-storage] Projected secret", func() {
|
||||
f := framework.NewDefaultFramework("projected")
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, Secrets, volume mode default
|
||||
Description: A Pod is created with a projected volume source ‘secret’ to store a secret with a specified key with default permission mode. Pod MUST be able to read the content of the key successfully and the mode MUST be -rw-r--r-- by default.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume [NodeConformance]", func() {
|
||||
doProjectedSecretE2EWithoutMapping(f, nil /* default mode */, "projected-secret-test-"+string(uuid.NewUUID()), nil, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, Secrets, volume mode 0400
|
||||
Description: A Pod is created with a projected volume source ‘secret’ to store a secret with a specified key with permission mode set to 0x400 on the Pod. Pod MUST be able to read the content of the key successfully and the mode MUST be -r—-—————.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with defaultMode set [NodeConformance]", func() {
|
||||
defaultMode := int32(0400)
|
||||
doProjectedSecretE2EWithoutMapping(f, &defaultMode, "projected-secret-test-"+string(uuid.NewUUID()), nil, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Project Volume, Secrets, non-root, custom fsGroup
|
||||
Description: A Pod is created with a projected volume source ‘secret’ to store a secret with a specified key. The volume has permission mode set to 0440, fsgroup set to 1001 and user set to non-root uid of 1000. Pod MUST be able to read the content of the key successfully and the mode MUST be -r—-r————-.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume as non-root with defaultMode and fsGroup set [NodeConformance]", func() {
|
||||
defaultMode := int32(0440) /* setting fsGroup sets mode to at least 440 */
|
||||
fsGroup := int64(1001)
|
||||
uid := int64(1000)
|
||||
doProjectedSecretE2EWithoutMapping(f, &defaultMode, "projected-secret-test-"+string(uuid.NewUUID()), &fsGroup, &uid)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, Secrets, mapped
|
||||
Description: A Pod is created with a projected volume source ‘secret’ to store a secret with a specified key with default permission mode. The secret is also mapped to a custom path. Pod MUST be able to read the content of the key successfully and the mode MUST be -r—-—————— on the mapped volume.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings [NodeConformance]", func() {
|
||||
doProjectedSecretE2EWithMapping(f, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, Secrets, mapped, volume mode 0400
|
||||
Description: A Pod is created with a projected volume source ‘secret’ to store a secret with a specified key with permission mode set to 0400. The secret is also mapped to a specific name. Pod MUST be able to read the content of the key successfully and the mode MUST be -r—-—————— on the mapped volume.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings and Item Mode set [NodeConformance]", func() {
|
||||
mode := int32(0400)
|
||||
doProjectedSecretE2EWithMapping(f, &mode)
|
||||
})
|
||||
|
||||
It("should be able to mount in a volume regardless of a different secret existing with same name in different namespace [NodeConformance]", func() {
|
||||
var (
|
||||
namespace2 *v1.Namespace
|
||||
err error
|
||||
secret2Name = "projected-secret-test-" + string(uuid.NewUUID())
|
||||
)
|
||||
|
||||
if namespace2, err = f.CreateNamespace("secret-namespace", nil); err != nil {
|
||||
framework.Failf("unable to create new namespace %s: %v", namespace2.Name, err)
|
||||
}
|
||||
|
||||
secret2 := secretForTest(namespace2.Name, secret2Name)
|
||||
secret2.Data = map[string][]byte{
|
||||
"this_should_not_match_content_of_other_secret": []byte("similarly_this_should_not_match_content_of_other_secret\n"),
|
||||
}
|
||||
if secret2, err = f.ClientSet.CoreV1().Secrets(namespace2.Name).Create(secret2); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", secret2.Name, err)
|
||||
}
|
||||
doProjectedSecretE2EWithoutMapping(f, nil /* default mode */, secret2.Name, nil, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, Secrets, mapped, multiple paths
|
||||
Description: A Pod is created with a projected volume source ‘secret’ to store a secret with a specified key. The secret is mapped to two different volume mounts. Pod MUST be able to read the content of the key successfully from the two volume mounts and the mode MUST be -r—-—————— on the mapped volumes.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable in multiple volumes in a pod [NodeConformance]", func() {
|
||||
// This test ensures that the same secret can be mounted in multiple
|
||||
// volumes in the same pod. This test case exists to prevent
|
||||
// regressions that break this use-case.
|
||||
var (
|
||||
name = "projected-secret-test-" + string(uuid.NewUUID())
|
||||
volumeName = "projected-secret-volume"
|
||||
volumeMountPath = "/etc/projected-secret-volume"
|
||||
volumeName2 = "projected-secret-volume-2"
|
||||
volumeMountPath2 = "/etc/projected-secret-volume-2"
|
||||
secret = secretForTest(f.Namespace.Name, name)
|
||||
)
|
||||
|
||||
By(fmt.Sprintf("Creating secret with name %s", secret.Name))
|
||||
var err error
|
||||
if secret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", secret.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-projected-secrets-" + string(uuid.NewUUID()),
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: volumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
Secret: &v1.SecretProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: volumeName2,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
Secret: &v1.SecretProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "secret-volume-test",
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{
|
||||
"--file_content=/etc/projected-secret-volume/data-1",
|
||||
"--file_mode=/etc/projected-secret-volume/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: volumeName,
|
||||
MountPath: volumeMountPath,
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: volumeName2,
|
||||
MountPath: volumeMountPath2,
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
f.TestContainerOutput("consume secrets", pod, 0, []string{
|
||||
"content of file \"/etc/projected-secret-volume/data-1\": value-1",
|
||||
"mode of file \"/etc/projected-secret-volume/data-1\": -rw-r--r--",
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.9
|
||||
Testname: Projected Volume, Secrets, create, update delete
|
||||
Description: Create a Pod with three containers with secrets namely a create, update and delete container. Create Container when started MUST no have a secret, update and delete containers MUST be created with a secret value. Create a secret in the create container, the Pod MUST be able to read the secret from the create container. Update the secret in the update container, Pod MUST be able to read the updated secret value. Delete the secret in the delete container. Pod MUST fail to read the secret from the delete container.
|
||||
*/
|
||||
framework.ConformanceIt("optional updates should be reflected in volume [NodeConformance]", func() {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
|
||||
trueVal := true
|
||||
volumeMountPath := "/etc/projected-secret-volumes"
|
||||
|
||||
deleteName := "s-test-opt-del-" + string(uuid.NewUUID())
|
||||
deleteContainerName := "dels-volume-test"
|
||||
deleteVolumeName := "deletes-volume"
|
||||
deleteSecret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: deleteName,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"data-1": []byte("value-1"),
|
||||
},
|
||||
}
|
||||
|
||||
updateName := "s-test-opt-upd-" + string(uuid.NewUUID())
|
||||
updateContainerName := "upds-volume-test"
|
||||
updateVolumeName := "updates-volume"
|
||||
updateSecret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: updateName,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"data-1": []byte("value-1"),
|
||||
},
|
||||
}
|
||||
|
||||
createName := "s-test-opt-create-" + string(uuid.NewUUID())
|
||||
createContainerName := "creates-volume-test"
|
||||
createVolumeName := "creates-volume"
|
||||
createSecret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: createName,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"data-1": []byte("value-1"),
|
||||
},
|
||||
}
|
||||
|
||||
By(fmt.Sprintf("Creating secret with name %s", deleteSecret.Name))
|
||||
var err error
|
||||
if deleteSecret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(deleteSecret); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", deleteSecret.Name, err)
|
||||
}
|
||||
|
||||
By(fmt.Sprintf("Creating secret with name %s", updateSecret.Name))
|
||||
if updateSecret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(updateSecret); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", updateSecret.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-projected-secrets-" + string(uuid.NewUUID()),
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: deleteVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
Secret: &v1.SecretProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: deleteName,
|
||||
},
|
||||
Optional: &trueVal,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: updateVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
Secret: &v1.SecretProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: updateName,
|
||||
},
|
||||
Optional: &trueVal,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: createVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
Secret: &v1.SecretProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: createName,
|
||||
},
|
||||
Optional: &trueVal,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: deleteContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-secret-volumes/delete/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: deleteVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "delete"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: updateContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-secret-volumes/update/data-3"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: updateVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "update"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: createContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-secret-volumes/create/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "create"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
By("Creating the pod")
|
||||
f.PodClient().CreateSync(pod)
|
||||
|
||||
pollCreateLogs := func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, createContainerName)
|
||||
}
|
||||
Eventually(pollCreateLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("Error reading file /etc/projected-secret-volumes/create/data-1"))
|
||||
|
||||
pollUpdateLogs := func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, updateContainerName)
|
||||
}
|
||||
Eventually(pollUpdateLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("Error reading file /etc/projected-secret-volumes/update/data-3"))
|
||||
|
||||
pollDeleteLogs := func() (string, error) {
|
||||
return framework.GetPodLogs(f.ClientSet, f.Namespace.Name, pod.Name, deleteContainerName)
|
||||
}
|
||||
Eventually(pollDeleteLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-1"))
|
||||
|
||||
By(fmt.Sprintf("Deleting secret %v", deleteSecret.Name))
|
||||
err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(deleteSecret.Name, &metav1.DeleteOptions{})
|
||||
Expect(err).NotTo(HaveOccurred(), "Failed to delete secret %q in namespace %q", deleteSecret.Name, f.Namespace.Name)
|
||||
|
||||
By(fmt.Sprintf("Updating secret %v", updateSecret.Name))
|
||||
updateSecret.ResourceVersion = "" // to force update
|
||||
delete(updateSecret.Data, "data-1")
|
||||
updateSecret.Data["data-3"] = []byte("value-3")
|
||||
_, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Update(updateSecret)
|
||||
Expect(err).NotTo(HaveOccurred(), "Failed to update secret %q in namespace %q", updateSecret.Name, f.Namespace.Name)
|
||||
|
||||
By(fmt.Sprintf("Creating secret with name %s", createSecret.Name))
|
||||
if createSecret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(createSecret); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", createSecret.Name, err)
|
||||
}
|
||||
|
||||
By("waiting to observe update in volume")
|
||||
|
||||
Eventually(pollCreateLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-1"))
|
||||
Eventually(pollUpdateLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-3"))
|
||||
Eventually(pollDeleteLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("Error reading file /etc/projected-secret-volumes/delete/data-1"))
|
||||
})
|
||||
|
||||
//The secret is in pending during volume creation until the secret objects are available
|
||||
//or until mount the secret volume times out. There is no secret object defined for the pod, so it should return timout exception unless it is marked optional.
|
||||
//Slow (~5 mins)
|
||||
It("Should fail non-optional pod creation due to secret object does not exist [Slow]", func() {
|
||||
volumeMountPath := "/etc/projected-secret-volumes"
|
||||
podName := "pod-secrets-" + string(uuid.NewUUID())
|
||||
err := createNonOptionalSecretPod(f, volumeMountPath, podName)
|
||||
Expect(err).To(HaveOccurred(), "created pod %q with non-optional secret in namespace %q", podName, f.Namespace.Name)
|
||||
})
|
||||
|
||||
//Secret object defined for the pod, If a key is specified which is not present in the secret,
|
||||
// the volume setup will error unless it is marked optional, during the pod creation.
|
||||
//Slow (~5 mins)
|
||||
It("Should fail non-optional pod creation due to the key in the secret object does not exist [Slow]", func() {
|
||||
volumeMountPath := "/etc/secret-volumes"
|
||||
podName := "pod-secrets-" + string(uuid.NewUUID())
|
||||
err := createNonOptionalSecretPodWithSecret(f, volumeMountPath, podName)
|
||||
Expect(err).To(HaveOccurred(), "created pod %q with non-optional secret in namespace %q", podName, f.Namespace.Name)
|
||||
})
|
||||
})
|
||||
|
||||
func doProjectedSecretE2EWithoutMapping(f *framework.Framework, defaultMode *int32,
|
||||
secretName string, fsGroup *int64, uid *int64) {
|
||||
var (
|
||||
volumeName = "projected-secret-volume"
|
||||
volumeMountPath = "/etc/projected-secret-volume"
|
||||
secret = secretForTest(f.Namespace.Name, secretName)
|
||||
)
|
||||
|
||||
By(fmt.Sprintf("Creating projection with secret that has name %s", secret.Name))
|
||||
var err error
|
||||
if secret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", secret.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-projected-secrets-" + string(uuid.NewUUID()),
|
||||
Namespace: f.Namespace.Name,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: volumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
Secret: &v1.SecretProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: secretName,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "projected-secret-volume-test",
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{
|
||||
"--file_content=/etc/projected-secret-volume/data-1",
|
||||
"--file_mode=/etc/projected-secret-volume/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: volumeName,
|
||||
MountPath: volumeMountPath,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
if defaultMode != nil {
|
||||
//pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].Secret.DefaultMode = defaultMode
|
||||
pod.Spec.Volumes[0].VolumeSource.Projected.DefaultMode = defaultMode
|
||||
} else {
|
||||
mode := int32(0644)
|
||||
defaultMode = &mode
|
||||
}
|
||||
|
||||
if fsGroup != nil || uid != nil {
|
||||
pod.Spec.SecurityContext = &v1.PodSecurityContext{
|
||||
FSGroup: fsGroup,
|
||||
RunAsUser: uid,
|
||||
}
|
||||
}
|
||||
|
||||
modeString := fmt.Sprintf("%v", os.FileMode(*defaultMode))
|
||||
expectedOutput := []string{
|
||||
"content of file \"/etc/projected-secret-volume/data-1\": value-1",
|
||||
"mode of file \"/etc/projected-secret-volume/data-1\": " + modeString,
|
||||
}
|
||||
|
||||
f.TestContainerOutput("consume secrets", pod, 0, expectedOutput)
|
||||
}
|
||||
|
||||
func doProjectedSecretE2EWithMapping(f *framework.Framework, mode *int32) {
|
||||
var (
|
||||
name = "projected-secret-test-map-" + string(uuid.NewUUID())
|
||||
volumeName = "projected-secret-volume"
|
||||
volumeMountPath = "/etc/projected-secret-volume"
|
||||
secret = secretForTest(f.Namespace.Name, name)
|
||||
)
|
||||
|
||||
By(fmt.Sprintf("Creating projection with secret that has name %s", secret.Name))
|
||||
var err error
|
||||
if secret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", secret.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-projected-secrets-" + string(uuid.NewUUID()),
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: volumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Projected: &v1.ProjectedVolumeSource{
|
||||
Sources: []v1.VolumeProjection{
|
||||
{
|
||||
Secret: &v1.SecretProjection{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
Items: []v1.KeyToPath{
|
||||
{
|
||||
Key: "data-1",
|
||||
Path: "new-path-data-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "projected-secret-volume-test",
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{
|
||||
"--file_content=/etc/projected-secret-volume/new-path-data-1",
|
||||
"--file_mode=/etc/projected-secret-volume/new-path-data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: volumeName,
|
||||
MountPath: volumeMountPath,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
if mode != nil {
|
||||
//pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].Secret.Items[0].Mode = mode
|
||||
pod.Spec.Volumes[0].VolumeSource.Projected.DefaultMode = mode
|
||||
} else {
|
||||
defaultItemMode := int32(0644)
|
||||
mode = &defaultItemMode
|
||||
}
|
||||
|
||||
modeString := fmt.Sprintf("%v", os.FileMode(*mode))
|
||||
expectedOutput := []string{
|
||||
"content of file \"/etc/projected-secret-volume/new-path-data-1\": value-1",
|
||||
"mode of file \"/etc/projected-secret-volume/new-path-data-1\": " + modeString,
|
||||
}
|
||||
|
||||
f.TestContainerOutput("consume secrets", pod, 0, expectedOutput)
|
||||
}
|
391
vendor/k8s.io/kubernetes/test/e2e/common/runtime.go
generated
vendored
Normal file
391
vendor/k8s.io/kubernetes/test/e2e/common/runtime.go
generated
vendored
Normal file
@ -0,0 +1,391 @@
|
||||
/*
|
||||
Copyright 2016 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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/pkg/kubelet/images"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
gomegatypes "github.com/onsi/gomega/types"
|
||||
)
|
||||
|
||||
var _ = framework.KubeDescribe("Container Runtime", func() {
|
||||
f := framework.NewDefaultFramework("container-runtime")
|
||||
|
||||
Describe("blackbox test", func() {
|
||||
Context("when starting a container that exits", func() {
|
||||
|
||||
/*
|
||||
Release : v1.13
|
||||
Testname: Container Runtime, Restart Policy, Pod Phases
|
||||
Description: If the restart policy is set to ‘Always’, Pod MUST be restarted when terminated, If restart policy is ‘OnFailure’, Pod MUST be started only if it is terminated with non-zero exit code. If the restart policy is ‘Never’, Pod MUST never be restarted. All these three test cases MUST verify the restart counts accordingly.
|
||||
*/
|
||||
framework.ConformanceIt("should run with the expected status [NodeConformance]", func() {
|
||||
restartCountVolumeName := "restart-count"
|
||||
restartCountVolumePath := "/restart-count"
|
||||
testContainer := v1.Container{
|
||||
Image: framework.BusyBoxImage,
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
MountPath: restartCountVolumePath,
|
||||
Name: restartCountVolumeName,
|
||||
},
|
||||
},
|
||||
}
|
||||
testVolumes := []v1.Volume{
|
||||
{
|
||||
Name: restartCountVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
EmptyDir: &v1.EmptyDirVolumeSource{Medium: v1.StorageMediumMemory},
|
||||
},
|
||||
},
|
||||
}
|
||||
testCases := []struct {
|
||||
Name string
|
||||
RestartPolicy v1.RestartPolicy
|
||||
Phase v1.PodPhase
|
||||
State ContainerState
|
||||
RestartCount int32
|
||||
Ready bool
|
||||
}{
|
||||
{"terminate-cmd-rpa", v1.RestartPolicyAlways, v1.PodRunning, ContainerStateRunning, 2, true},
|
||||
{"terminate-cmd-rpof", v1.RestartPolicyOnFailure, v1.PodSucceeded, ContainerStateTerminated, 1, false},
|
||||
{"terminate-cmd-rpn", v1.RestartPolicyNever, v1.PodFailed, ContainerStateTerminated, 0, false},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
|
||||
// It failed at the 1st run, then succeeded at 2nd run, then run forever
|
||||
cmdScripts := `
|
||||
f=%s
|
||||
count=$(echo 'hello' >> $f ; wc -l $f | awk {'print $1'})
|
||||
if [ $count -eq 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
if [ $count -eq 2 ]; then
|
||||
exit 0
|
||||
fi
|
||||
while true; do sleep 1; done
|
||||
`
|
||||
tmpCmd := fmt.Sprintf(cmdScripts, path.Join(restartCountVolumePath, "restartCount"))
|
||||
testContainer.Name = testCase.Name
|
||||
testContainer.Command = []string{"sh", "-c", tmpCmd}
|
||||
terminateContainer := ConformanceContainer{
|
||||
PodClient: f.PodClient(),
|
||||
Container: testContainer,
|
||||
RestartPolicy: testCase.RestartPolicy,
|
||||
Volumes: testVolumes,
|
||||
PodSecurityContext: &v1.PodSecurityContext{
|
||||
SELinuxOptions: &v1.SELinuxOptions{
|
||||
Level: "s0",
|
||||
},
|
||||
},
|
||||
}
|
||||
terminateContainer.Create()
|
||||
defer terminateContainer.Delete()
|
||||
|
||||
By(fmt.Sprintf("Container '%s': should get the expected 'RestartCount'", testContainer.Name))
|
||||
Eventually(func() (int32, error) {
|
||||
status, err := terminateContainer.GetStatus()
|
||||
return status.RestartCount, err
|
||||
}, ContainerStatusRetryTimeout, ContainerStatusPollInterval).Should(Equal(testCase.RestartCount))
|
||||
|
||||
By(fmt.Sprintf("Container '%s': should get the expected 'Phase'", testContainer.Name))
|
||||
Eventually(terminateContainer.GetPhase, ContainerStatusRetryTimeout, ContainerStatusPollInterval).Should(Equal(testCase.Phase))
|
||||
|
||||
By(fmt.Sprintf("Container '%s': should get the expected 'Ready' condition", testContainer.Name))
|
||||
Expect(terminateContainer.IsReady()).Should(Equal(testCase.Ready))
|
||||
|
||||
status, err := terminateContainer.GetStatus()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
|
||||
By(fmt.Sprintf("Container '%s': should get the expected 'State'", testContainer.Name))
|
||||
Expect(GetContainerState(status.State)).To(Equal(testCase.State))
|
||||
|
||||
By(fmt.Sprintf("Container '%s': should be possible to delete [NodeConformance]", testContainer.Name))
|
||||
Expect(terminateContainer.Delete()).To(Succeed())
|
||||
Eventually(terminateContainer.Present, ContainerStatusRetryTimeout, ContainerStatusPollInterval).Should(BeFalse())
|
||||
}
|
||||
})
|
||||
|
||||
rootUser := int64(0)
|
||||
nonRootUser := int64(10000)
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
container v1.Container
|
||||
phase v1.PodPhase
|
||||
message gomegatypes.GomegaMatcher
|
||||
}{
|
||||
{
|
||||
name: "if TerminationMessagePath is set [NodeConformance]",
|
||||
container: v1.Container{
|
||||
Image: framework.BusyBoxImage,
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"/bin/echo -n DONE > /dev/termination-log"},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
RunAsUser: &rootUser,
|
||||
},
|
||||
},
|
||||
phase: v1.PodSucceeded,
|
||||
message: Equal("DONE"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "if TerminationMessagePath is set as non-root user and at a non-default path [NodeConformance]",
|
||||
container: v1.Container{
|
||||
Image: framework.BusyBoxImage,
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"/bin/echo -n DONE > /dev/termination-custom-log"},
|
||||
TerminationMessagePath: "/dev/termination-custom-log",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
RunAsUser: &nonRootUser,
|
||||
},
|
||||
},
|
||||
phase: v1.PodSucceeded,
|
||||
message: Equal("DONE"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "from log output if TerminationMessagePolicy FallbackToLogOnError is set [NodeConformance]",
|
||||
container: v1.Container{
|
||||
Image: framework.BusyBoxImage,
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"/bin/echo -n DONE; /bin/false"},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
|
||||
},
|
||||
phase: v1.PodFailed,
|
||||
message: Equal("DONE\n"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "as empty when pod succeeds and TerminationMessagePolicy FallbackToLogOnError is set [NodeConformance]",
|
||||
container: v1.Container{
|
||||
Image: framework.BusyBoxImage,
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"/bin/echo DONE; /bin/true"},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
|
||||
},
|
||||
phase: v1.PodSucceeded,
|
||||
message: Equal(""),
|
||||
},
|
||||
|
||||
{
|
||||
name: "from file when pod succeeds and TerminationMessagePolicy FallbackToLogOnError is set [NodeConformance]",
|
||||
container: v1.Container{
|
||||
Image: framework.BusyBoxImage,
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"/bin/echo -n OK > /dev/termination-log; /bin/echo DONE; /bin/true"},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
|
||||
},
|
||||
phase: v1.PodSucceeded,
|
||||
message: Equal("OK"),
|
||||
},
|
||||
} {
|
||||
It(fmt.Sprintf("should report termination message %s", testCase.name), func() {
|
||||
testCase.container.Name = "termination-message-container"
|
||||
c := ConformanceContainer{
|
||||
PodClient: f.PodClient(),
|
||||
Container: testCase.container,
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
}
|
||||
|
||||
By("create the container")
|
||||
c.Create()
|
||||
defer c.Delete()
|
||||
|
||||
By(fmt.Sprintf("wait for the container to reach %s", testCase.phase))
|
||||
Eventually(c.GetPhase, ContainerStatusRetryTimeout, ContainerStatusPollInterval).Should(Equal(testCase.phase))
|
||||
|
||||
By("get the container status")
|
||||
status, err := c.GetStatus()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("the container should be terminated")
|
||||
Expect(GetContainerState(status.State)).To(Equal(ContainerStateTerminated))
|
||||
|
||||
By("the termination message should be set")
|
||||
Expect(status.State.Terminated.Message).Should(testCase.message)
|
||||
|
||||
By("delete the container")
|
||||
Expect(c.Delete()).To(Succeed())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Context("when running a container with a new image", func() {
|
||||
// The service account only has pull permission
|
||||
auth := `
|
||||
{
|
||||
"auths": {
|
||||
"https://gcr.io": {
|
||||
"auth": "X2pzb25fa2V5OnsKICAidHlwZSI6ICJzZXJ2aWNlX2FjY291bnQiLAogICJwcm9qZWN0X2lkIjogImF1dGhlbnRpY2F0ZWQtaW1hZ2UtcHVsbGluZyIsCiAgInByaXZhdGVfa2V5X2lkIjogImI5ZjJhNjY0YWE5YjIwNDg0Y2MxNTg2MDYzZmVmZGExOTIyNGFjM2IiLAogICJwcml2YXRlX2tleSI6ICItLS0tLUJFR0lOIFBSSVZBVEUgS0VZLS0tLS1cbk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzdTSG5LVEVFaVlMamZcbkpmQVBHbUozd3JCY2VJNTBKS0xxS21GWE5RL3REWGJRK2g5YVl4aldJTDhEeDBKZTc0bVovS01uV2dYRjVLWlNcbm9BNktuSU85Yi9SY1NlV2VpSXRSekkzL1lYVitPNkNjcmpKSXl4anFWam5mVzJpM3NhMzd0OUE5VEZkbGZycm5cbjR6UkpiOWl4eU1YNGJMdHFGR3ZCMDNOSWl0QTNzVlo1ODhrb1FBZmgzSmhhQmVnTWorWjRSYko0aGVpQlFUMDNcbnZVbzViRWFQZVQ5RE16bHdzZWFQV2dydDZOME9VRGNBRTl4bGNJek11MjUzUG4vSzgySFpydEx4akd2UkhNVXhcbng0ZjhwSnhmQ3h4QlN3Z1NORit3OWpkbXR2b0wwRmE3ZGducFJlODZWRDY2ejNZenJqNHlLRXRqc2hLZHl5VWRcbkl5cVhoN1JSQWdNQkFBRUNnZ0VBT3pzZHdaeENVVlFUeEFka2wvSTVTRFVidi9NazRwaWZxYjJEa2FnbmhFcG9cbjFJajJsNGlWMTByOS9uenJnY2p5VlBBd3pZWk1JeDFBZVF0RDdoUzRHWmFweXZKWUc3NkZpWFpQUm9DVlB6b3VcbmZyOGRDaWFwbDV0enJDOWx2QXNHd29DTTdJWVRjZmNWdDdjRTEyRDNRS3NGNlo3QjJ6ZmdLS251WVBmK0NFNlRcbmNNMHkwaCtYRS9kMERvSERoVy96YU1yWEhqOFRvd2V1eXRrYmJzNGYvOUZqOVBuU2dET1lQd2xhbFZUcitGUWFcbkpSd1ZqVmxYcEZBUW14M0Jyd25rWnQzQ2lXV2lGM2QrSGk5RXRVYnRWclcxYjZnK1JRT0licWFtcis4YlJuZFhcbjZWZ3FCQWtKWjhSVnlkeFVQMGQxMUdqdU9QRHhCbkhCbmM0UW9rSXJFUUtCZ1FEMUNlaWN1ZGhXdGc0K2dTeGJcbnplanh0VjFONDFtZHVjQnpvMmp5b1dHbzNQVDh3ckJPL3lRRTM0cU9WSi9pZCs4SThoWjRvSWh1K0pBMDBzNmdcblRuSXErdi9kL1RFalk4MW5rWmlDa21SUFdiWHhhWXR4UjIxS1BYckxOTlFKS2ttOHRkeVh5UHFsOE1veUdmQ1dcbjJ2aVBKS05iNkhabnY5Q3lqZEo5ZzJMRG5RS0JnUUREcVN2eURtaGViOTIzSW96NGxlZ01SK205Z2xYVWdTS2dcbkVzZlllbVJmbU5XQitDN3ZhSXlVUm1ZNU55TXhmQlZXc3dXRldLYXhjK0krYnFzZmx6elZZdFpwMThNR2pzTURcbmZlZWZBWDZCWk1zVXQ3Qmw3WjlWSjg1bnRFZHFBQ0xwWitaLzN0SVJWdWdDV1pRMWhrbmxHa0dUMDI0SkVFKytcbk55SDFnM2QzUlFLQmdRQ1J2MXdKWkkwbVBsRklva0tGTkh1YTBUcDNLb1JTU1hzTURTVk9NK2xIckcxWHJtRjZcbkMwNGNTKzQ0N0dMUkxHOFVUaEpKbTRxckh0Ti9aK2dZOTYvMm1xYjRIakpORDM3TVhKQnZFYTN5ZUxTOHEvK1JcbjJGOU1LamRRaU5LWnhQcG84VzhOSlREWTVOa1BaZGh4a2pzSHdVNGRTNjZwMVRESUU0MGd0TFpaRFFLQmdGaldcbktyblFpTnEzOS9iNm5QOFJNVGJDUUFKbmR3anhTUU5kQTVmcW1rQTlhRk9HbCtqamsxQ1BWa0tNSWxLSmdEYkpcbk9heDl2OUc2Ui9NSTFIR1hmV3QxWU56VnRocjRIdHNyQTB0U3BsbWhwZ05XRTZWejZuQURqdGZQSnMyZUdqdlhcbmpQUnArdjhjY21MK3dTZzhQTGprM3ZsN2VlNXJsWWxNQndNdUdjUHhBb0dBZWRueGJXMVJMbVZubEFpSEx1L0xcbmxtZkF3RFdtRWlJMFVnK1BMbm9Pdk81dFE1ZDRXMS94RU44bFA0cWtzcGtmZk1Rbk5oNFNZR0VlQlQzMlpxQ1RcbkpSZ2YwWGpveXZ2dXA5eFhqTWtYcnBZL3ljMXpmcVRaQzBNTzkvMVVjMWJSR2RaMmR5M2xSNU5XYXA3T1h5Zk9cblBQcE5Gb1BUWGd2M3FDcW5sTEhyR3pNPVxuLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLVxuIiwKICAiY2xpZW50X2VtYWlsIjogImltYWdlLXB1bGxpbmdAYXV0aGVudGljYXRlZC1pbWFnZS1wdWxsaW5nLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwKICAiY2xpZW50X2lkIjogIjExMzc5NzkxNDUzMDA3MzI3ODcxMiIsCiAgImF1dGhfdXJpIjogImh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi9hdXRoIiwKICAidG9rZW5fdXJpIjogImh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsCiAgImF1dGhfcHJvdmlkZXJfeDUwOV9jZXJ0X3VybCI6ICJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9vYXV0aDIvdjEvY2VydHMiLAogICJjbGllbnRfeDUwOV9jZXJ0X3VybCI6ICJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9yb2JvdC92MS9tZXRhZGF0YS94NTA5L2ltYWdlLXB1bGxpbmclNDBhdXRoZW50aWNhdGVkLWltYWdlLXB1bGxpbmcuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iCn0=",
|
||||
"email": "image-pulling@authenticated-image-pulling.iam.gserviceaccount.com"
|
||||
}
|
||||
}
|
||||
}`
|
||||
secret := &v1.Secret{
|
||||
Data: map[string][]byte{v1.DockerConfigJsonKey: []byte(auth)},
|
||||
Type: v1.SecretTypeDockerConfigJson,
|
||||
}
|
||||
// The following images are not added into NodeImageWhiteList, because this test is
|
||||
// testing image pulling, these images don't need to be prepulled. The ImagePullPolicy
|
||||
// is v1.PullAlways, so it won't be blocked by framework image white list check.
|
||||
for _, testCase := range []struct {
|
||||
description string
|
||||
image string
|
||||
secret bool
|
||||
phase v1.PodPhase
|
||||
waiting bool
|
||||
}{
|
||||
{
|
||||
description: "should not be able to pull image from invalid registry",
|
||||
image: "invalid.com/invalid/alpine:3.1",
|
||||
phase: v1.PodPending,
|
||||
waiting: true,
|
||||
},
|
||||
{
|
||||
description: "should not be able to pull non-existing image from gcr.io",
|
||||
image: "k8s.gcr.io/invalid-image:invalid-tag",
|
||||
phase: v1.PodPending,
|
||||
waiting: true,
|
||||
},
|
||||
{
|
||||
description: "should be able to pull image from gcr.io",
|
||||
image: "gcr.io/google-containers/debian-base:0.4.0",
|
||||
phase: v1.PodRunning,
|
||||
waiting: false,
|
||||
},
|
||||
{
|
||||
description: "should be able to pull image from docker hub",
|
||||
image: "alpine:3.7",
|
||||
phase: v1.PodRunning,
|
||||
waiting: false,
|
||||
},
|
||||
{
|
||||
description: "should not be able to pull from private registry without secret",
|
||||
image: "gcr.io/authenticated-image-pulling/alpine:3.7",
|
||||
phase: v1.PodPending,
|
||||
waiting: true,
|
||||
},
|
||||
{
|
||||
description: "should be able to pull from private registry with secret",
|
||||
image: "gcr.io/authenticated-image-pulling/alpine:3.7",
|
||||
secret: true,
|
||||
phase: v1.PodRunning,
|
||||
waiting: false,
|
||||
},
|
||||
} {
|
||||
testCase := testCase
|
||||
It(testCase.description+" [NodeConformance]", func() {
|
||||
name := "image-pull-test"
|
||||
command := []string{"/bin/sh", "-c", "while true; do sleep 1; done"}
|
||||
container := ConformanceContainer{
|
||||
PodClient: f.PodClient(),
|
||||
Container: v1.Container{
|
||||
Name: name,
|
||||
Image: testCase.image,
|
||||
Command: command,
|
||||
// PullAlways makes sure that the image will always be pulled even if it is present before the test.
|
||||
ImagePullPolicy: v1.PullAlways,
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
}
|
||||
if testCase.secret {
|
||||
secret.Name = "image-pull-secret-" + string(uuid.NewUUID())
|
||||
By("create image pull secret")
|
||||
_, err := f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
defer f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(secret.Name, nil)
|
||||
container.ImagePullSecrets = []string{secret.Name}
|
||||
}
|
||||
// checkContainerStatus checks whether the container status matches expectation.
|
||||
checkContainerStatus := func() error {
|
||||
status, err := container.GetStatus()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get container status: %v", err)
|
||||
}
|
||||
// We need to check container state first. The default pod status is pending, If we check
|
||||
// pod phase first, and the expected pod phase is Pending, the container status may not
|
||||
// even show up when we check it.
|
||||
// Check container state
|
||||
if !testCase.waiting {
|
||||
if status.State.Running == nil {
|
||||
return fmt.Errorf("expected container state: Running, got: %q",
|
||||
GetContainerState(status.State))
|
||||
}
|
||||
}
|
||||
if testCase.waiting {
|
||||
if status.State.Waiting == nil {
|
||||
return fmt.Errorf("expected container state: Waiting, got: %q",
|
||||
GetContainerState(status.State))
|
||||
}
|
||||
reason := status.State.Waiting.Reason
|
||||
if reason != images.ErrImagePull.Error() &&
|
||||
reason != images.ErrImagePullBackOff.Error() {
|
||||
return fmt.Errorf("unexpected waiting reason: %q", reason)
|
||||
}
|
||||
}
|
||||
// Check pod phase
|
||||
phase, err := container.GetPhase()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get pod phase: %v", err)
|
||||
}
|
||||
if phase != testCase.phase {
|
||||
return fmt.Errorf("expected pod phase: %q, got: %q", testCase.phase, phase)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// The image registry is not stable, which sometimes causes the test to fail. Add retry mechanism to make this
|
||||
// less flaky.
|
||||
const flakeRetry = 3
|
||||
for i := 1; i <= flakeRetry; i++ {
|
||||
var err error
|
||||
By("create the container")
|
||||
container.Create()
|
||||
By("check the container status")
|
||||
for start := time.Now(); time.Since(start) < ContainerStatusRetryTimeout; time.Sleep(ContainerStatusPollInterval) {
|
||||
if err = checkContainerStatus(); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
By("delete the container")
|
||||
container.Delete()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if i < flakeRetry {
|
||||
framework.Logf("No.%d attempt failed: %v, retrying...", i, err)
|
||||
} else {
|
||||
framework.Failf("All %d attempts failed: %v", flakeRetry, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
38
vendor/k8s.io/kubernetes/test/e2e/common/secrets.go
generated
vendored
38
vendor/k8s.io/kubernetes/test/e2e/common/secrets.go
generated
vendored
@ -23,17 +23,19 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("[sig-api-machinery] Secrets", func() {
|
||||
f := framework.NewDefaultFramework("secrets")
|
||||
|
||||
/*
|
||||
Testname: secret-env-vars
|
||||
Description: Ensure that secret can be consumed via environment
|
||||
variables.
|
||||
Release : v1.9
|
||||
Testname: Secrets, pod environment field
|
||||
Description: Create a secret. Create a Pod with Container that declares a environment variable which references the secret created to extract a key value from the secret. Pod MUST have the environment variable that contains proper value for the key to the secret.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in env vars [NodeConformance]", func() {
|
||||
name := "secret-test-" + string(uuid.NewUUID())
|
||||
@ -53,7 +55,7 @@ var _ = Describe("[sig-api-machinery] Secrets", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "secret-env-test",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
@ -80,9 +82,9 @@ var _ = Describe("[sig-api-machinery] Secrets", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: secret-configmaps-source
|
||||
Description: Ensure that secret can be consumed via source of a set
|
||||
of ConfigMaps.
|
||||
Release : v1.9
|
||||
Testname: Secrets, pod environment from source
|
||||
Description: Create a secret. Create a Pod with Container that declares a environment variable using ‘EnvFrom’ which references the secret created to extract a key value from the secret. Pod MUST have the environment variable that contains proper value for the key to the secret.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable via the environment [NodeConformance]", func() {
|
||||
name := "secret-test-" + string(uuid.NewUUID())
|
||||
@ -101,7 +103,7 @@ var _ = Describe("[sig-api-machinery] Secrets", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "env-test",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
@ -123,6 +125,11 @@ var _ = Describe("[sig-api-machinery] Secrets", func() {
|
||||
"p_data_1=value-1", "p_data_2=value-2", "p_data_3=value-3",
|
||||
})
|
||||
})
|
||||
|
||||
It("should fail to create secret in volume due to empty secret key", func() {
|
||||
secret, err := createEmptyKeySecretForTest(f)
|
||||
Expect(err).To(HaveOccurred(), "created secret %q with empty key in namespace %q", secret.Name, f.Namespace.Name)
|
||||
})
|
||||
})
|
||||
|
||||
func newEnvFromSecret(namespace, name string) *v1.Secret {
|
||||
@ -138,3 +145,18 @@ func newEnvFromSecret(namespace, name string) *v1.Secret {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createEmptyKeySecretForTest(f *framework.Framework) (*v1.Secret, error) {
|
||||
secretName := "secret-emptyKey-test-" + string(uuid.NewUUID())
|
||||
secret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: secretName,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"": []byte("value-1\n"),
|
||||
},
|
||||
}
|
||||
By(fmt.Sprintf("Creating projection with secret that has name %s", secret.Name))
|
||||
return f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret)
|
||||
}
|
||||
|
190
vendor/k8s.io/kubernetes/test/e2e/common/secrets_volume.go
generated
vendored
190
vendor/k8s.io/kubernetes/test/e2e/common/secrets_volume.go
generated
vendored
@ -25,6 +25,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@ -34,18 +35,18 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
f := framework.NewDefaultFramework("secrets")
|
||||
|
||||
/*
|
||||
Testname: secret-volume-mount-without-mapping
|
||||
Description: Ensure that secret can be mounted without mapping to a
|
||||
pod volume.
|
||||
Release : v1.9
|
||||
Testname: Secrets Volume, default
|
||||
Description: Create a secret. Create a Pod with secret volume source configured into the container. Pod MUST be able to read the secret from the mounted volume from the container runtime and the file mode of the secret MUST be -rw-r--r-- by default.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume [NodeConformance]", func() {
|
||||
doSecretE2EWithoutMapping(f, nil /* default mode */, "secret-test-"+string(uuid.NewUUID()), nil, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: secret-volume-mount-without-mapping-default-mode
|
||||
Description: Ensure that secret can be mounted without mapping to a
|
||||
pod volume in default mode.
|
||||
Release : v1.9
|
||||
Testname: Secrets Volume, volume mode 0400
|
||||
Description: Create a secret. Create a Pod with secret volume source configured into the container with file mode set to 0x400. Pod MUST be able to read the secret from the mounted volume from the container runtime and the file mode of the secret MUST be -r——--—-—- by default.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with defaultMode set [NodeConformance]", func() {
|
||||
defaultMode := int32(0400)
|
||||
@ -53,9 +54,9 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: secret-volume-mount-without-mapping-non-root-default-mode-fsgroup
|
||||
Description: Ensure that secret can be mounted without mapping to a pod
|
||||
volume as non-root in default mode with fsGroup set.
|
||||
Release : v1.9
|
||||
Testname: Secrets Volume, volume mode 0440, fsGroup 1001 and uid 1000
|
||||
Description: Create a secret. Create a Pod with secret volume source configured into the container with file mode set to 0x440 as a non-root user with uid 1000 and fsGroup id 1001. Pod MUST be able to read the secret from the mounted volume from the container runtime and the file mode of the secret MUST be -r——r-—-—- by default.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume as non-root with defaultMode and fsGroup set [NodeConformance]", func() {
|
||||
defaultMode := int32(0440) /* setting fsGroup sets mode to at least 440 */
|
||||
@ -65,25 +66,30 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: secret-volume-mount-with-mapping
|
||||
Description: Ensure that secret can be mounted with mapping to a pod
|
||||
volume.
|
||||
Release : v1.9
|
||||
Testname: Secrets Volume, mapping
|
||||
Description: Create a secret. Create a Pod with secret volume source configured into the container with a custom path. Pod MUST be able to read the secret from the mounted volume from the specified custom path. The file mode of the secret MUST be -rw—r-—r—- by default.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings [NodeConformance]", func() {
|
||||
doSecretE2EWithMapping(f, nil)
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: secret-volume-mount-with-mapping-item-mode
|
||||
Description: Ensure that secret can be mounted with mapping to a pod
|
||||
volume in item mode.
|
||||
Release : v1.9
|
||||
Testname: Secrets Volume, mapping, volume mode 0400
|
||||
Description: Create a secret. Create a Pod with secret volume source configured into the container with a custom path and file mode set to 0x400. Pod MUST be able to read the secret from the mounted volume from the specified custom path. The file mode of the secret MUST be -r-—r-—r—-.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable from pods in volume with mappings and Item Mode set [NodeConformance]", func() {
|
||||
mode := int32(0400)
|
||||
doSecretE2EWithMapping(f, &mode)
|
||||
})
|
||||
|
||||
It("should be able to mount in a volume regardless of a different secret existing with same name in different namespace [NodeConformance]", func() {
|
||||
/*
|
||||
Release : v1.12
|
||||
Testname: Secrets Volume, volume mode default, secret with same name in different namespace
|
||||
Description: Create a secret with same name in two namespaces. Create a Pod with secret volume source configured into the container. Pod MUST be able to read the secrets from the mounted volume from the container runtime and only secrets which are associated with namespace where pod is created. The file mode of the secret MUST be -rw-r--r-- by default.
|
||||
*/
|
||||
framework.ConformanceIt("should be able to mount in a volume regardless of a different secret existing with same name in different namespace [NodeConformance]", func() {
|
||||
var (
|
||||
namespace2 *v1.Namespace
|
||||
err error
|
||||
@ -105,8 +111,9 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: secret-multiple-volume-mounts
|
||||
Description: Ensure that secret can be mounted to multiple pod volumes.
|
||||
Release : v1.9
|
||||
Testname: Secrets Volume, mapping multiple volume paths
|
||||
Description: Create a secret. Create a Pod with two secret volume sources configured into the container in to two different custom paths. Pod MUST be able to read the secret from the both the mounted volumes from the two specified custom paths.
|
||||
*/
|
||||
framework.ConformanceIt("should be consumable in multiple volumes in a pod [NodeConformance]", func() {
|
||||
// This test ensures that the same secret can be mounted in multiple
|
||||
@ -153,7 +160,7 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "secret-volume-test",
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{
|
||||
"--file_content=/etc/secret-volume/data-1",
|
||||
"--file_mode=/etc/secret-volume/data-1"},
|
||||
@ -182,9 +189,9 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: secret-mounted-volume-optional-update-change
|
||||
Description: Ensure that optional update change to secret can be
|
||||
reflected on a mounted volume.
|
||||
Release : v1.9
|
||||
Testname: Secrets Volume, create, update and delete
|
||||
Description: Create a Pod with three containers with secrets volume sources namely a create, update and delete container. Create Container when started MUST not have secret, update and delete containers MUST be created with a secret value. Create a secret in the create container, the Pod MUST be able to read the secret from the create container. Update the secret in the update container, Pod MUST be able to read the updated secret value. Delete the secret in the delete container. Pod MUST fail to read the secret from the delete container.
|
||||
*/
|
||||
framework.ConformanceIt("optional updates should be reflected in volume [NodeConformance]", func() {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
@ -279,7 +286,7 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: deleteContainerName,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/secret-volumes/delete/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -291,7 +298,7 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
},
|
||||
{
|
||||
Name: updateContainerName,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/secret-volumes/update/data-3"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -303,7 +310,7 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
},
|
||||
{
|
||||
Name: createContainerName,
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/secret-volumes/create/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@ -357,6 +364,26 @@ var _ = Describe("[sig-storage] Secrets", func() {
|
||||
Eventually(pollUpdateLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("value-3"))
|
||||
Eventually(pollDeleteLogs, podLogTimeout, framework.Poll).Should(ContainSubstring("Error reading file /etc/secret-volumes/delete/data-1"))
|
||||
})
|
||||
|
||||
//The secret is in pending during volume creation until the secret objects are available
|
||||
//or until mount the secret volume times out. There is no secret object defined for the pod, so it should return timout exception unless it is marked optional.
|
||||
//Slow (~5 mins)
|
||||
It("Should fail non-optional pod creation due to secret object does not exist [Slow]", func() {
|
||||
volumeMountPath := "/etc/secret-volumes"
|
||||
podName := "pod-secrets-" + string(uuid.NewUUID())
|
||||
err := createNonOptionalSecretPod(f, volumeMountPath, podName)
|
||||
Expect(err).To(HaveOccurred(), "created pod %q with non-optional secret in namespace %q", podName, f.Namespace.Name)
|
||||
})
|
||||
|
||||
//Secret object defined for the pod, If a key is specified which is not present in the secret,
|
||||
// the volume setup will error unless it is marked optional, during the pod creation.
|
||||
//Slow (~5 mins)
|
||||
It("Should fail non-optional pod creation due to the key in the secret object does not exist [Slow]", func() {
|
||||
volumeMountPath := "/etc/secret-volumes"
|
||||
podName := "pod-secrets-" + string(uuid.NewUUID())
|
||||
err := createNonOptionalSecretPodWithSecret(f, volumeMountPath, podName)
|
||||
Expect(err).To(HaveOccurred(), "created pod %q with non-optional secret in namespace %q", podName, f.Namespace.Name)
|
||||
})
|
||||
})
|
||||
|
||||
func secretForTest(namespace, name string) *v1.Secret {
|
||||
@ -406,7 +433,7 @@ func doSecretE2EWithoutMapping(f *framework.Framework, defaultMode *int32, secre
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "secret-volume-test",
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{
|
||||
"--file_content=/etc/secret-volume/data-1",
|
||||
"--file_mode=/etc/secret-volume/data-1"},
|
||||
@ -483,7 +510,7 @@ func doSecretE2EWithMapping(f *framework.Framework, mode *int32) {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "secret-volume-test",
|
||||
Image: mountImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Args: []string{
|
||||
"--file_content=/etc/secret-volume/new-path-data-1",
|
||||
"--file_mode=/etc/secret-volume/new-path-data-1"},
|
||||
@ -514,3 +541,112 @@ func doSecretE2EWithMapping(f *framework.Framework, mode *int32) {
|
||||
|
||||
f.TestContainerOutput("consume secrets", pod, 0, expectedOutput)
|
||||
}
|
||||
|
||||
func createNonOptionalSecretPod(f *framework.Framework, volumeMountPath, podName string) error {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
|
||||
falseValue := false
|
||||
|
||||
createName := "s-test-opt-create-" + string(uuid.NewUUID())
|
||||
createContainerName := "creates-volume-test"
|
||||
createVolumeName := "creates-volume"
|
||||
|
||||
//creating a pod without secret object created, by mentioning the secret volume source reference name
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Secret: &v1.SecretVolumeSource{
|
||||
SecretName: createName,
|
||||
Optional: &falseValue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: createContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/secret-volumes/create/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "create"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
By("Creating the pod")
|
||||
pod = f.PodClient().Create(pod)
|
||||
return f.WaitForPodRunning(pod.Name)
|
||||
}
|
||||
|
||||
func createNonOptionalSecretPodWithSecret(f *framework.Framework, volumeMountPath, podName string) error {
|
||||
podLogTimeout := framework.GetPodSecretUpdateTimeout(f.ClientSet)
|
||||
containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
|
||||
falseValue := false
|
||||
|
||||
createName := "s-test-opt-create-" + string(uuid.NewUUID())
|
||||
createContainerName := "creates-volume-test"
|
||||
createVolumeName := "creates-volume"
|
||||
|
||||
secret := secretForTest(f.Namespace.Name, createName)
|
||||
|
||||
By(fmt.Sprintf("Creating secret with name %s", secret.Name))
|
||||
var err error
|
||||
if secret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", secret.Name, err)
|
||||
}
|
||||
//creating a pod with secret object, with the key which is not present in secret object.
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Secret: &v1.SecretVolumeSource{
|
||||
SecretName: createName,
|
||||
Items: []v1.KeyToPath{
|
||||
{
|
||||
Key: "data_4",
|
||||
Path: "value-4\n",
|
||||
},
|
||||
},
|
||||
Optional: &falseValue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: createContainerName,
|
||||
Image: imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
Command: []string{"/mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/secret-volumes/create/data-1"},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: createVolumeName,
|
||||
MountPath: path.Join(volumeMountPath, "create"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
By("Creating the pod")
|
||||
pod = f.PodClient().Create(pod)
|
||||
return f.WaitForPodRunning(pod.Name)
|
||||
}
|
||||
|
266
vendor/k8s.io/kubernetes/test/e2e/common/security_context.go
generated
vendored
Normal file
266
vendor/k8s.io/kubernetes/test/e2e/common/security_context.go
generated
vendored
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
)
|
||||
|
||||
var _ = framework.KubeDescribe("Security Context", func() {
|
||||
f := framework.NewDefaultFramework("security-context-test")
|
||||
var podClient *framework.PodClient
|
||||
BeforeEach(func() {
|
||||
podClient = f.PodClient()
|
||||
})
|
||||
|
||||
Context("When creating a container with runAsUser", func() {
|
||||
makeUserPod := func(podName, image string, command []string, userid int64) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: image,
|
||||
Name: podName,
|
||||
Command: command,
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
RunAsUser: &userid,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
createAndWaitUserPod := func(userid int64) {
|
||||
podName := fmt.Sprintf("busybox-user-%d-%s", userid, uuid.NewUUID())
|
||||
podClient.Create(makeUserPod(podName,
|
||||
framework.BusyBoxImage,
|
||||
[]string{"sh", "-c", fmt.Sprintf("test $(id -u) -eq %d", userid)},
|
||||
userid,
|
||||
))
|
||||
|
||||
podClient.WaitForSuccess(podName, framework.PodStartTimeout)
|
||||
}
|
||||
|
||||
/*
|
||||
Release : v1.12
|
||||
Testname: Security Context: runAsUser (id:65534)
|
||||
Description: Container created with runAsUser option, passing an id (id:65534) uses that
|
||||
given id when running the container.
|
||||
*/
|
||||
It("should run the container with uid 65534 [NodeConformance]", func() {
|
||||
createAndWaitUserPod(65534)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.12
|
||||
Testname: Security Context: runAsUser (id:0)
|
||||
Description: Container created with runAsUser option, passing an id (id:0) uses that
|
||||
given id when running the container.
|
||||
*/
|
||||
It("should run the container with uid 0 [NodeConformance]", func() {
|
||||
createAndWaitUserPod(0)
|
||||
})
|
||||
})
|
||||
|
||||
Context("When creating a pod with readOnlyRootFilesystem", func() {
|
||||
makeUserPod := func(podName, image string, command []string, readOnlyRootFilesystem bool) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: image,
|
||||
Name: podName,
|
||||
Command: command,
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
createAndWaitUserPod := func(readOnlyRootFilesystem bool) string {
|
||||
podName := fmt.Sprintf("busybox-readonly-%v-%s", readOnlyRootFilesystem, uuid.NewUUID())
|
||||
podClient.Create(makeUserPod(podName,
|
||||
framework.BusyBoxImage,
|
||||
[]string{"sh", "-c", "touch checkfile"},
|
||||
readOnlyRootFilesystem,
|
||||
))
|
||||
|
||||
if readOnlyRootFilesystem {
|
||||
podClient.WaitForFailure(podName, framework.PodStartTimeout)
|
||||
} else {
|
||||
podClient.WaitForSuccess(podName, framework.PodStartTimeout)
|
||||
}
|
||||
|
||||
return podName
|
||||
}
|
||||
|
||||
/*
|
||||
Release : v1.12
|
||||
Testname: Security Context: readOnlyRootFilesystem=true.
|
||||
Description: when a container has configured readOnlyRootFilesystem to true, write operations are not allowed.
|
||||
*/
|
||||
It("should run the container with readonly rootfs when readOnlyRootFilesystem=true [NodeConformance]", func() {
|
||||
createAndWaitUserPod(true)
|
||||
})
|
||||
|
||||
/*
|
||||
Release : v1.12
|
||||
Testname: Security Context: readOnlyRootFilesystem=false.
|
||||
Description: when a container has configured readOnlyRootFilesystem to false, write operations are allowed.
|
||||
*/
|
||||
It("should run the container with writable rootfs when readOnlyRootFilesystem=false [NodeConformance]", func() {
|
||||
createAndWaitUserPod(false)
|
||||
})
|
||||
})
|
||||
|
||||
Context("When creating a pod with privileged", func() {
|
||||
makeUserPod := func(podName, image string, command []string, privileged bool) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: image,
|
||||
Name: podName,
|
||||
Command: command,
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
Privileged: &privileged,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
createAndWaitUserPod := func(privileged bool) string {
|
||||
podName := fmt.Sprintf("busybox-privileged-%v-%s", privileged, uuid.NewUUID())
|
||||
podClient.Create(makeUserPod(podName,
|
||||
framework.BusyBoxImage,
|
||||
[]string{"sh", "-c", "ip link add dummy0 type dummy || true"},
|
||||
privileged,
|
||||
))
|
||||
podClient.WaitForSuccess(podName, framework.PodStartTimeout)
|
||||
return podName
|
||||
}
|
||||
|
||||
It("should run the container as unprivileged when false [NodeConformance]", func() {
|
||||
podName := createAndWaitUserPod(false)
|
||||
logs, err := framework.GetPodLogs(f.ClientSet, f.Namespace.Name, podName, podName)
|
||||
if err != nil {
|
||||
framework.Failf("GetPodLogs for pod %q failed: %v", podName, err)
|
||||
}
|
||||
|
||||
framework.Logf("Got logs for pod %q: %q", podName, logs)
|
||||
if !strings.Contains(logs, "Operation not permitted") {
|
||||
framework.Failf("unprivileged container shouldn't be able to create dummy device")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Context("when creating containers with AllowPrivilegeEscalation", func() {
|
||||
makeAllowPrivilegeEscalationPod := func(podName string, allowPrivilegeEscalation *bool, uid int64) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: imageutils.GetE2EImage(imageutils.Nonewprivs),
|
||||
Name: podName,
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
AllowPrivilegeEscalation: allowPrivilegeEscalation,
|
||||
RunAsUser: &uid,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
createAndMatchOutput := func(podName, output string, allowPrivilegeEscalation *bool, uid int64) error {
|
||||
podClient.Create(makeAllowPrivilegeEscalationPod(podName,
|
||||
allowPrivilegeEscalation,
|
||||
uid,
|
||||
))
|
||||
podClient.WaitForSuccess(podName, framework.PodStartTimeout)
|
||||
return podClient.MatchContainerOutput(podName, podName, output)
|
||||
}
|
||||
|
||||
/*
|
||||
Testname: allowPrivilegeEscalation unset and uid != 0.
|
||||
Description: Configuring the allowPrivilegeEscalation unset, allows the privilege escalation operation.
|
||||
A container is configured with allowPrivilegeEscalation not specified (nil) and a given uid which is not 0.
|
||||
When the container is run, the container is run using uid=0.
|
||||
*/
|
||||
It("should allow privilege escalation when not explicitly set and uid != 0 [NodeConformance]", func() {
|
||||
podName := "alpine-nnp-nil-" + string(uuid.NewUUID())
|
||||
if err := createAndMatchOutput(podName, "Effective uid: 0", nil, 1000); err != nil {
|
||||
framework.Failf("Match output for pod %q failed: %v", podName, err)
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: allowPrivilegeEscalation=false.
|
||||
Description: Configuring the allowPrivilegeEscalation to false, does not allow the privilege escalation operation.
|
||||
A container is configured with allowPrivilegeEscalation=false and a given uid (1000) which is not 0.
|
||||
When the container is run, the container is run using uid=1000.
|
||||
*/
|
||||
It("should not allow privilege escalation when false [NodeConformance]", func() {
|
||||
podName := "alpine-nnp-false-" + string(uuid.NewUUID())
|
||||
apeFalse := false
|
||||
if err := createAndMatchOutput(podName, "Effective uid: 1000", &apeFalse, 1000); err != nil {
|
||||
framework.Failf("Match output for pod %q failed: %v", podName, err)
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
Testname: allowPrivilegeEscalation=true.
|
||||
Description: Configuring the allowPrivilegeEscalation to true, allows the privilege escalation operation.
|
||||
A container is configured with allowPrivilegeEscalation=true and a given uid (1000) which is not 0.
|
||||
When the container is run, the container is run using uid=0 (making use of the privilege escalation).
|
||||
*/
|
||||
It("should allow privilege escalation when true [NodeConformance]", func() {
|
||||
podName := "alpine-nnp-true-" + string(uuid.NewUUID())
|
||||
apeTrue := true
|
||||
if err := createAndMatchOutput(podName, "Effective uid: 0", &apeTrue, 1000); err != nil {
|
||||
framework.Failf("Match output for pod %q failed: %v", podName, err)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
3
vendor/k8s.io/kubernetes/test/e2e/common/sysctl.go
generated
vendored
3
vendor/k8s.io/kubernetes/test/e2e/common/sysctl.go
generated
vendored
@ -22,6 +22,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/pkg/kubelet/sysctl"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@ -42,7 +43,7 @@ var _ = framework.KubeDescribe("Sysctls [NodeFeature:Sysctls]", func() {
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "test-container",
|
||||
Image: busyboxImage,
|
||||
Image: imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
|
98
vendor/k8s.io/kubernetes/test/e2e/common/ttlafterfinished.go
generated
vendored
Normal file
98
vendor/k8s.io/kubernetes/test/e2e/common/ttlafterfinished.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
batch "k8s.io/api/batch/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
const dummyFinalizer = "k8s.io/dummy-finalizer"
|
||||
|
||||
var _ = framework.KubeDescribe("TTLAfterFinished", func() {
|
||||
f := framework.NewDefaultFramework("ttlafterfinished")
|
||||
|
||||
alphaFeatureStr := "[Feature:TTLAfterFinished]"
|
||||
It(fmt.Sprintf("Job should be deleted once it finishes after TTL seconds %s", alphaFeatureStr), func() {
|
||||
testFinishedJob(f)
|
||||
})
|
||||
})
|
||||
|
||||
func cleanupJob(f *framework.Framework, job *batch.Job) {
|
||||
ns := f.Namespace.Name
|
||||
c := f.ClientSet
|
||||
|
||||
framework.Logf("Remove the Job's dummy finalizer; the Job should be deleted cascadingly")
|
||||
removeFinalizerFunc := func(j *batch.Job) {
|
||||
j.ObjectMeta.Finalizers = slice.RemoveString(j.ObjectMeta.Finalizers, dummyFinalizer, nil)
|
||||
}
|
||||
_, err := framework.UpdateJobWithRetries(c, ns, job.Name, removeFinalizerFunc)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
framework.WaitForJobGone(c, ns, job.Name, wait.ForeverTestTimeout)
|
||||
|
||||
err = framework.WaitForAllJobPodsGone(c, ns, job.Name)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
func testFinishedJob(f *framework.Framework) {
|
||||
ns := f.Namespace.Name
|
||||
c := f.ClientSet
|
||||
|
||||
parallelism := int32(1)
|
||||
completions := int32(1)
|
||||
backoffLimit := int32(2)
|
||||
ttl := int32(10)
|
||||
|
||||
job := framework.NewTestJob("randomlySucceedOrFail", "rand-non-local", v1.RestartPolicyNever, parallelism, completions, nil, backoffLimit)
|
||||
job.Spec.TTLSecondsAfterFinished = &ttl
|
||||
job.ObjectMeta.Finalizers = []string{dummyFinalizer}
|
||||
defer cleanupJob(f, job)
|
||||
|
||||
framework.Logf("Create a Job %s/%s with TTL", job.Namespace, job.Name)
|
||||
job, err := framework.CreateJob(c, ns, job)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
framework.Logf("Wait for the Job to finish")
|
||||
err = framework.WaitForJobFinish(c, ns, job.Name)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
framework.Logf("Wait for TTL after finished controller to delete the Job")
|
||||
err = framework.WaitForJobDeleting(c, ns, job.Name)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
framework.Logf("Check Job's deletionTimestamp and compare with the time when the Job finished")
|
||||
job, err = framework.GetJob(c, ns, job.Name)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
finishTime := framework.JobFinishTime(job)
|
||||
finishTimeUTC := finishTime.UTC()
|
||||
Expect(finishTime.IsZero()).NotTo(BeTrue())
|
||||
|
||||
deleteAtUTC := job.ObjectMeta.DeletionTimestamp.UTC()
|
||||
Expect(deleteAtUTC).NotTo(BeNil())
|
||||
|
||||
expireAtUTC := finishTimeUTC.Add(time.Duration(ttl) * time.Second)
|
||||
Expect(deleteAtUTC.Before(expireAtUTC)).To(BeFalse())
|
||||
}
|
11
vendor/k8s.io/kubernetes/test/e2e/common/util.go
generated
vendored
11
vendor/k8s.io/kubernetes/test/e2e/common/util.go
generated
vendored
@ -40,11 +40,6 @@ const (
|
||||
NodeE2E Suite = "node e2e"
|
||||
)
|
||||
|
||||
var (
|
||||
mountImage = imageutils.GetE2EImage(imageutils.Mounttest)
|
||||
busyboxImage = "busybox"
|
||||
)
|
||||
|
||||
var CurrentSuite Suite
|
||||
|
||||
// CommonImageWhiteList is the list of images used in common test. These images should be prepulled
|
||||
@ -52,20 +47,20 @@ var CurrentSuite Suite
|
||||
// only used by node e2e test.
|
||||
// TODO(random-liu): Change the image puller pod to use similar mechanism.
|
||||
var CommonImageWhiteList = sets.NewString(
|
||||
"busybox",
|
||||
imageutils.GetE2EImage(imageutils.BusyBox),
|
||||
imageutils.GetE2EImage(imageutils.EntrypointTester),
|
||||
imageutils.GetE2EImage(imageutils.IpcUtils),
|
||||
imageutils.GetE2EImage(imageutils.Liveness),
|
||||
imageutils.GetE2EImage(imageutils.Mounttest),
|
||||
imageutils.GetE2EImage(imageutils.MounttestUser),
|
||||
imageutils.GetE2EImage(imageutils.Netexec),
|
||||
imageutils.GetE2EImage(imageutils.NginxSlim),
|
||||
imageutils.GetE2EImage(imageutils.Nginx),
|
||||
imageutils.GetE2EImage(imageutils.ServeHostname),
|
||||
imageutils.GetE2EImage(imageutils.TestWebserver),
|
||||
imageutils.GetE2EImage(imageutils.Hostexec),
|
||||
imageutils.GetE2EImage(imageutils.VolumeNFSServer),
|
||||
imageutils.GetE2EImage(imageutils.VolumeGlusterServer),
|
||||
imageutils.GetE2EImage(imageutils.E2ENet),
|
||||
imageutils.GetE2EImage(imageutils.Net),
|
||||
)
|
||||
|
||||
func svcByName(name string, port int) *v1.Service {
|
||||
|
2
vendor/k8s.io/kubernetes/test/e2e/common/volumes.go
generated
vendored
2
vendor/k8s.io/kubernetes/test/e2e/common/volumes.go
generated
vendored
@ -62,7 +62,7 @@ var _ = Describe("[sig-storage] GCP Volumes", func() {
|
||||
var c clientset.Interface
|
||||
|
||||
BeforeEach(func() {
|
||||
framework.SkipUnlessNodeOSDistroIs("gci", "ubuntu")
|
||||
framework.SkipUnlessNodeOSDistroIs("gci", "ubuntu", "custom")
|
||||
|
||||
namespace = f.Namespace
|
||||
c = f.ClientSet
|
||||
|
Reference in New Issue
Block a user