2015-12-14 07:32:37 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2015-12-14 07:32:37 +00:00
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 .
* /
2017-07-12 01:58:31 +00:00
package storage
2015-12-14 07:32:37 +00:00
import (
2018-09-24 10:09:20 +00:00
"fmt"
"strconv"
2017-06-22 18:24:23 +00:00
"k8s.io/api/core/v1"
2017-01-25 13:13:07 +00:00
"k8s.io/apimachinery/pkg/api/resource"
2017-01-17 03:38:19 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-01-27 20:42:17 +00:00
"k8s.io/apimachinery/pkg/util/intstr"
2017-01-24 14:35:22 +00:00
"k8s.io/apimachinery/pkg/util/uuid"
2016-04-07 17:21:31 +00:00
"k8s.io/kubernetes/test/e2e/framework"
2018-09-24 10:09:20 +00:00
"k8s.io/kubernetes/test/e2e/storage/utils"
2017-08-29 08:32:08 +00:00
imageutils "k8s.io/kubernetes/test/utils/image"
2015-12-14 07:32:37 +00:00
. "github.com/onsi/ginkgo"
2016-08-16 01:09:48 +00:00
. "github.com/onsi/gomega"
)
const (
// These numbers are obtained empirically.
// If you make them too low, you'll get flaky
// tests instead of failing ones if the race bug reappears.
// If you make volume counts or pod counts too high,
// the tests may fail because mounting configmap/git_repo
// volumes is not very fast and the tests may time out
// waiting for pods to become Running.
// And of course the higher are the numbers, the
// slower are the tests.
wrappedVolumeRaceConfigMapVolumeCount = 50
wrappedVolumeRaceConfigMapPodCount = 5
wrappedVolumeRaceConfigMapIterationCount = 3
wrappedVolumeRaceGitRepoVolumeCount = 50
wrappedVolumeRaceGitRepoPodCount = 5
wrappedVolumeRaceGitRepoIterationCount = 3
wrappedVolumeRaceRCNamePrefix = "wrapped-volume-race-"
2015-12-14 07:32:37 +00:00
)
2017-11-29 22:08:28 +00:00
var _ = utils . SIGDescribe ( "EmptyDir wrapper volumes" , func ( ) {
2016-04-07 17:21:31 +00:00
f := framework . NewDefaultFramework ( "emptydir-wrapper" )
2015-12-14 07:32:37 +00:00
2018-09-24 10:09:20 +00:00
/ *
Release : v1 .13
Testname : EmptyDir Wrapper Volume , Secret and ConfigMap volumes , no conflict
Description : Secret volume and ConfigMap volume is created with data . Pod MUST be able to start with Secret and ConfigMap volumes mounted into the container .
* /
framework . ConformanceIt ( "should not conflict" , func ( ) {
2016-07-26 15:13:18 +00:00
name := "emptydir-wrapper-test-" + string ( uuid . NewUUID ( ) )
2015-12-14 07:32:37 +00:00
volumeName := "secret-volume"
volumeMountPath := "/etc/secret-volume"
2016-11-18 20:55:17 +00:00
secret := & v1 . Secret {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2015-12-14 07:32:37 +00:00
Namespace : f . Namespace . Name ,
Name : name ,
} ,
Data : map [ string ] [ ] byte {
"data-1" : [ ] byte ( "value-1\n" ) ,
} ,
}
var err error
2017-10-25 15:54:32 +00:00
if secret , err = f . ClientSet . CoreV1 ( ) . Secrets ( f . Namespace . Name ) . Create ( secret ) ; err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "unable to create test secret %s: %v" , secret . Name , err )
2015-12-14 07:32:37 +00:00
}
2018-08-29 18:12:14 +00:00
configMapVolumeName := "configmap-volume"
configMapVolumeMountPath := "/etc/configmap-volume"
configMap := & v1 . ConfigMap {
ObjectMeta : metav1 . ObjectMeta {
Namespace : f . Namespace . Name ,
Name : name ,
} ,
BinaryData : map [ string ] [ ] byte {
"data-1" : [ ] byte ( "value-1\n" ) ,
} ,
}
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 )
}
2015-12-14 07:32:37 +00:00
2016-11-18 20:55:17 +00:00
pod := & v1 . Pod {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-07-26 15:13:18 +00:00
Name : "pod-secrets-" + string ( uuid . NewUUID ( ) ) ,
2015-12-14 07:32:37 +00:00
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . PodSpec {
Volumes : [ ] v1 . Volume {
2015-12-14 07:32:37 +00:00
{
Name : volumeName ,
2016-11-18 20:55:17 +00:00
VolumeSource : v1 . VolumeSource {
Secret : & v1 . SecretVolumeSource {
2015-12-14 07:32:37 +00:00
SecretName : name ,
} ,
} ,
} ,
{
2018-08-29 18:12:14 +00:00
Name : configMapVolumeName ,
2016-11-18 20:55:17 +00:00
VolumeSource : v1 . VolumeSource {
2018-08-29 18:12:14 +00:00
ConfigMap : & v1 . ConfigMapVolumeSource {
LocalObjectReference : v1 . LocalObjectReference {
Name : name ,
} ,
2015-12-14 07:32:37 +00:00
} ,
} ,
} ,
} ,
2016-11-18 20:55:17 +00:00
Containers : [ ] v1 . Container {
2015-12-14 07:32:37 +00:00
{
Name : "secret-test" ,
2017-08-29 08:32:08 +00:00
Image : imageutils . GetE2EImage ( imageutils . TestWebserver ) ,
2016-11-18 20:55:17 +00:00
VolumeMounts : [ ] v1 . VolumeMount {
2015-12-14 07:32:37 +00:00
{
Name : volumeName ,
MountPath : volumeMountPath ,
ReadOnly : true ,
} ,
{
2018-08-29 18:12:14 +00:00
Name : configMapVolumeName ,
MountPath : configMapVolumeMountPath ,
2015-12-14 07:32:37 +00:00
} ,
} ,
} ,
} ,
} ,
}
2016-10-11 19:35:09 +00:00
pod = f . PodClient ( ) . CreateSync ( pod )
2016-08-16 01:09:48 +00:00
2015-12-14 07:32:37 +00:00
defer func ( ) {
By ( "Cleaning up the secret" )
2017-10-25 15:54:32 +00:00
if err := f . ClientSet . CoreV1 ( ) . Secrets ( f . Namespace . Name ) . Delete ( secret . Name , nil ) ; err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "unable to delete secret %v: %v" , secret . Name , err )
2015-12-14 07:32:37 +00:00
}
2018-08-29 18:12:14 +00:00
By ( "Cleaning up the configmap" )
if err := f . ClientSet . CoreV1 ( ) . ConfigMaps ( f . Namespace . Name ) . Delete ( configMap . Name , nil ) ; err != nil {
framework . Failf ( "unable to delete configmap %v: %v" , configMap . Name , err )
}
By ( "Cleaning up the pod" )
2017-10-25 15:54:32 +00:00
if err = f . ClientSet . CoreV1 ( ) . Pods ( f . Namespace . Name ) . Delete ( pod . Name , metav1 . NewDeleteOptions ( 0 ) ) ; err != nil {
2018-08-29 18:12:14 +00:00
framework . Failf ( "unable to delete pod %v: %v" , pod . Name , err )
2015-12-14 07:32:37 +00:00
}
} ( )
} )
2016-08-16 01:09:48 +00:00
// The following two tests check for the problem fixed in #29641.
// In order to reproduce it you need to revert the fix, e.g. via
// git revert -n df1e925143daf34199b55ffb91d0598244888cce
// or
// curl -sL https://github.com/kubernetes/kubernetes/pull/29641.patch | patch -p1 -R
//
// After that these tests will fail because some of the pods
// they create never enter Running state.
//
// They need to be [Serial] and [Slow] because they try to induce
// the race by creating pods with many volumes and container volume mounts,
// which takes considerable time and may interfere with other tests.
//
// Probably should also try making tests for secrets and downwardapi,
// but these cases are harder because tmpfs-based emptyDir
// appears to be less prone to the race problem.
2018-09-24 10:09:20 +00:00
/ *
Release : v1 .13
Testname : EmptyDir Wrapper Volume , ConfigMap volumes , no race
Description : Slow by design [ ~ 180 Seconds ] .
Create 50 ConfigMaps Volumes and 5 replicas of pod with these ConfigMapvolumes mounted . Pod MUST NOT fail waiting for Volumes .
* /
framework . ConformanceIt ( "should not cause race condition when used for configmaps [Serial] [Slow]" , func ( ) {
2016-08-16 01:09:48 +00:00
configMapNames := createConfigmapsForRace ( f )
defer deleteConfigMaps ( f , configMapNames )
volumes , volumeMounts := makeConfigMapVolumes ( configMapNames )
for i := 0 ; i < wrappedVolumeRaceConfigMapIterationCount ; i ++ {
testNoWrappedVolumeRace ( f , volumes , volumeMounts , wrappedVolumeRaceConfigMapPodCount )
}
} )
2018-09-24 10:09:20 +00:00
// Slow by design [~150 Seconds].
// This test uses deprecated GitRepo VolumeSource so it MUST not be promoted to Conformance.
// To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod’ s container.
// This projected volume maps approach can also be tested with secrets and downwardapi VolumeSource but are less prone to the race problem.
2017-06-02 02:21:14 +00:00
It ( "should not cause race condition when used for git_repo [Serial] [Slow]" , func ( ) {
2016-08-16 01:09:48 +00:00
gitURL , gitRepo , cleanup := createGitServer ( f )
defer cleanup ( )
volumes , volumeMounts := makeGitRepoVolumes ( gitURL , gitRepo )
for i := 0 ; i < wrappedVolumeRaceGitRepoIterationCount ; i ++ {
testNoWrappedVolumeRace ( f , volumes , volumeMounts , wrappedVolumeRaceGitRepoPodCount )
}
} )
2015-12-14 07:32:37 +00:00
} )
2016-08-16 01:09:48 +00:00
func createGitServer ( f * framework . Framework ) ( gitURL string , gitRepo string , cleanup func ( ) ) {
var err error
gitServerPodName := "git-server-" + string ( uuid . NewUUID ( ) )
containerPort := 8000
labels := map [ string ] string { "name" : gitServerPodName }
2016-11-18 20:55:17 +00:00
gitServerPod := & v1 . Pod {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-08-16 01:09:48 +00:00
Name : gitServerPodName ,
Labels : labels ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-08-16 01:09:48 +00:00
{
Name : "git-repo" ,
2017-08-29 08:32:08 +00:00
Image : imageutils . GetE2EImage ( imageutils . Fakegitserver ) ,
2016-08-16 01:09:48 +00:00
ImagePullPolicy : "IfNotPresent" ,
2016-11-18 20:55:17 +00:00
Ports : [ ] v1 . ContainerPort {
2016-08-16 01:09:48 +00:00
{ ContainerPort : int32 ( containerPort ) } ,
} ,
} ,
} ,
} ,
}
2016-10-11 19:35:09 +00:00
f . PodClient ( ) . CreateSync ( gitServerPod )
2016-08-16 01:09:48 +00:00
// Portal IP and port
httpPort := 2345
2016-11-18 20:55:17 +00:00
gitServerSvc := & v1 . Service {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-08-16 01:09:48 +00:00
Name : "git-server-svc" ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . ServiceSpec {
2016-08-16 01:09:48 +00:00
Selector : labels ,
2016-11-18 20:55:17 +00:00
Ports : [ ] v1 . ServicePort {
2016-08-16 01:09:48 +00:00
{
Name : "http-portal" ,
Port : int32 ( httpPort ) ,
TargetPort : intstr . FromInt ( containerPort ) ,
} ,
} ,
} ,
}
2017-10-25 15:54:32 +00:00
if gitServerSvc , err = f . ClientSet . CoreV1 ( ) . Services ( f . Namespace . Name ) . Create ( gitServerSvc ) ; err != nil {
2016-08-16 01:09:48 +00:00
framework . Failf ( "unable to create test git server service %s: %v" , gitServerSvc . Name , err )
}
return "http://" + gitServerSvc . Spec . ClusterIP + ":" + strconv . Itoa ( httpPort ) , "test" , func ( ) {
By ( "Cleaning up the git server pod" )
2017-10-25 15:54:32 +00:00
if err := f . ClientSet . CoreV1 ( ) . Pods ( f . Namespace . Name ) . Delete ( gitServerPod . Name , metav1 . NewDeleteOptions ( 0 ) ) ; err != nil {
2016-08-16 01:09:48 +00:00
framework . Failf ( "unable to delete git server pod %v: %v" , gitServerPod . Name , err )
}
By ( "Cleaning up the git server svc" )
2017-10-25 15:54:32 +00:00
if err := f . ClientSet . CoreV1 ( ) . Services ( f . Namespace . Name ) . Delete ( gitServerSvc . Name , nil ) ; err != nil {
2016-08-16 01:09:48 +00:00
framework . Failf ( "unable to delete git server svc %v: %v" , gitServerSvc . Name , err )
}
}
}
2016-11-18 20:55:17 +00:00
func makeGitRepoVolumes ( gitURL , gitRepo string ) ( volumes [ ] v1 . Volume , volumeMounts [ ] v1 . VolumeMount ) {
2016-08-16 01:09:48 +00:00
for i := 0 ; i < wrappedVolumeRaceGitRepoVolumeCount ; i ++ {
volumeName := fmt . Sprintf ( "racey-git-repo-%d" , i )
2016-11-18 20:55:17 +00:00
volumes = append ( volumes , v1 . Volume {
2016-08-16 01:09:48 +00:00
Name : volumeName ,
2016-11-18 20:55:17 +00:00
VolumeSource : v1 . VolumeSource {
GitRepo : & v1 . GitRepoVolumeSource {
2016-08-16 01:09:48 +00:00
Repository : gitURL ,
Directory : gitRepo ,
} ,
} ,
} )
2016-11-18 20:55:17 +00:00
volumeMounts = append ( volumeMounts , v1 . VolumeMount {
2016-08-16 01:09:48 +00:00
Name : volumeName ,
MountPath : fmt . Sprintf ( "/etc/git-volume-%d" , i ) ,
} )
}
return
}
func createConfigmapsForRace ( f * framework . Framework ) ( configMapNames [ ] string ) {
By ( fmt . Sprintf ( "Creating %d configmaps" , wrappedVolumeRaceConfigMapVolumeCount ) )
for i := 0 ; i < wrappedVolumeRaceConfigMapVolumeCount ; i ++ {
configMapName := fmt . Sprintf ( "racey-configmap-%d" , i )
configMapNames = append ( configMapNames , configMapName )
2016-11-18 20:55:17 +00:00
configMap := & v1 . ConfigMap {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-08-16 01:09:48 +00:00
Namespace : f . Namespace . Name ,
Name : configMapName ,
} ,
Data : map [ string ] string {
"data-1" : "value-1" ,
} ,
}
2017-10-25 15:54:32 +00:00
_ , err := f . ClientSet . CoreV1 ( ) . ConfigMaps ( f . Namespace . Name ) . Create ( configMap )
2016-08-16 01:09:48 +00:00
framework . ExpectNoError ( err )
}
return
}
func deleteConfigMaps ( f * framework . Framework , configMapNames [ ] string ) {
By ( "Cleaning up the configMaps" )
for _ , configMapName := range configMapNames {
2017-10-25 15:54:32 +00:00
err := f . ClientSet . CoreV1 ( ) . ConfigMaps ( f . Namespace . Name ) . Delete ( configMapName , nil )
2016-08-16 01:09:48 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) , "unable to delete configMap %v" , configMapName )
}
}
2016-11-18 20:55:17 +00:00
func makeConfigMapVolumes ( configMapNames [ ] string ) ( volumes [ ] v1 . Volume , volumeMounts [ ] v1 . VolumeMount ) {
2016-08-16 01:09:48 +00:00
for i , configMapName := range configMapNames {
volumeName := fmt . Sprintf ( "racey-configmap-%d" , i )
2016-11-18 20:55:17 +00:00
volumes = append ( volumes , v1 . Volume {
2016-08-16 01:09:48 +00:00
Name : volumeName ,
2016-11-18 20:55:17 +00:00
VolumeSource : v1 . VolumeSource {
ConfigMap : & v1 . ConfigMapVolumeSource {
LocalObjectReference : v1 . LocalObjectReference {
2016-08-16 01:09:48 +00:00
Name : configMapName ,
} ,
2016-11-18 20:55:17 +00:00
Items : [ ] v1 . KeyToPath {
2016-08-16 01:09:48 +00:00
{
Key : "data-1" ,
Path : "data-1" ,
} ,
} ,
} ,
} ,
} )
2016-11-18 20:55:17 +00:00
volumeMounts = append ( volumeMounts , v1 . VolumeMount {
2016-08-16 01:09:48 +00:00
Name : volumeName ,
MountPath : fmt . Sprintf ( "/etc/config-%d" , i ) ,
} )
}
return
}
2016-11-18 20:55:17 +00:00
func testNoWrappedVolumeRace ( f * framework . Framework , volumes [ ] v1 . Volume , volumeMounts [ ] v1 . VolumeMount , podCount int32 ) {
2016-08-16 01:09:48 +00:00
rcName := wrappedVolumeRaceRCNamePrefix + string ( uuid . NewUUID ( ) )
2016-10-19 13:55:39 +00:00
nodeList := framework . GetReadySchedulableNodesOrDie ( f . ClientSet )
2016-08-16 01:09:48 +00:00
Expect ( len ( nodeList . Items ) ) . To ( BeNumerically ( ">" , 0 ) )
targetNode := nodeList . Items [ 0 ]
By ( "Creating RC which spawns configmap-volume pods" )
2016-11-30 16:51:12 +00:00
affinity := & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "kubernetes.io/hostname" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { targetNode . Name } ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-08-16 01:09:48 +00:00
}
2016-11-18 20:55:17 +00:00
rc := & v1 . ReplicationController {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-08-16 01:09:48 +00:00
Name : rcName ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . ReplicationControllerSpec {
Replicas : & podCount ,
2016-08-16 01:09:48 +00:00
Selector : map [ string ] string {
"name" : rcName ,
} ,
2016-11-18 20:55:17 +00:00
Template : & v1 . PodTemplateSpec {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-11-30 16:51:12 +00:00
Labels : map [ string ] string { "name" : rcName } ,
2016-08-16 01:09:48 +00:00
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-08-16 01:09:48 +00:00
{
Name : "test-container" ,
2018-08-07 01:18:35 +00:00
Image : imageutils . GetE2EImage ( imageutils . BusyBox ) ,
2016-08-16 01:09:48 +00:00
Command : [ ] string { "sleep" , "10000" } ,
2016-11-18 20:55:17 +00:00
Resources : v1 . ResourceRequirements {
Requests : v1 . ResourceList {
v1 . ResourceCPU : resource . MustParse ( "10m" ) ,
2016-08-16 01:09:48 +00:00
} ,
} ,
VolumeMounts : volumeMounts ,
} ,
} ,
2016-11-30 16:51:12 +00:00
Affinity : affinity ,
2016-11-18 20:55:17 +00:00
DNSPolicy : v1 . DNSDefault ,
2016-08-16 01:09:48 +00:00
Volumes : volumes ,
} ,
} ,
} ,
}
2017-10-25 15:54:32 +00:00
_ , err := f . ClientSet . CoreV1 ( ) . ReplicationControllers ( f . Namespace . Name ) . Create ( rc )
2016-08-16 01:09:48 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) , "error creating replication controller" )
defer func ( ) {
2018-05-17 15:27:44 +00:00
err := framework . DeleteRCAndWaitForGC ( f . ClientSet , f . Namespace . Name , rcName )
2016-08-16 01:09:48 +00:00
framework . ExpectNoError ( err )
} ( )
2016-10-18 13:00:38 +00:00
pods , err := framework . PodsCreated ( f . ClientSet , f . Namespace . Name , rcName , podCount )
2016-08-16 01:09:48 +00:00
By ( "Ensuring each pod is running" )
// Wait for the pods to enter the running state. Waiting loops until the pods
// are running so non-running pods cause a timeout for this test.
for _ , pod := range pods . Items {
if pod . DeletionTimestamp != nil {
continue
}
err = f . WaitForPodRunning ( pod . Name )
Expect ( err ) . NotTo ( HaveOccurred ( ) , "Failed waiting for pod %s to enter running state" , pod . Name )
}
}