mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-04 07:49:35 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			267 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2015 The Kubernetes Authors.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package e2e
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"time"
 | 
						|
 | 
						|
	. "github.com/onsi/ginkgo"
 | 
						|
	"k8s.io/kubernetes/pkg/api"
 | 
						|
	"k8s.io/kubernetes/pkg/api/resource"
 | 
						|
	"k8s.io/kubernetes/pkg/api/testapi"
 | 
						|
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
						|
	client "k8s.io/kubernetes/pkg/client/unversioned"
 | 
						|
	"k8s.io/kubernetes/test/e2e/framework"
 | 
						|
)
 | 
						|
 | 
						|
// Clean both server and client pods.
 | 
						|
func persistentVolumeTestCleanup(client *client.Client, config VolumeTestConfig) {
 | 
						|
	defer GinkgoRecover()
 | 
						|
 | 
						|
	podClient := client.Pods(config.namespace)
 | 
						|
 | 
						|
	if config.serverImage != "" {
 | 
						|
		err := podClient.Delete(config.prefix+"-server", nil)
 | 
						|
		if err != nil {
 | 
						|
			framework.Failf("Failed to delete the server pod: %v", err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func deletePersistentVolume(c *client.Client, pv *api.PersistentVolume) {
 | 
						|
	// Delete the PersistentVolume
 | 
						|
	framework.Logf("Deleting PersistentVolume")
 | 
						|
	err := c.PersistentVolumes().Delete(pv.Name)
 | 
						|
	if err != nil {
 | 
						|
		framework.Failf("Delete PersistentVolume failed: %v", err)
 | 
						|
	}
 | 
						|
	// Wait for PersistentVolume to Delete
 | 
						|
	framework.WaitForPersistentVolumeDeleted(c, pv.Name, 3*time.Second, 30*time.Second)
 | 
						|
}
 | 
						|
 | 
						|
var _ = framework.KubeDescribe("PersistentVolumes", func() {
 | 
						|
	f := framework.NewDefaultFramework("pv")
 | 
						|
	var c *client.Client
 | 
						|
	var ns string
 | 
						|
	BeforeEach(func() {
 | 
						|
		c = f.Client
 | 
						|
		ns = f.Namespace.Name
 | 
						|
	})
 | 
						|
 | 
						|
	It("should create a PersistentVolume, Claim, and a client Pod that will test the read/write access of the volume[Flaky]", func() {
 | 
						|
		config := VolumeTestConfig{
 | 
						|
			namespace:   ns,
 | 
						|
			prefix:      "nfs",
 | 
						|
			serverImage: "gcr.io/google_containers/volume-nfs:0.6",
 | 
						|
			serverPorts: []int{2049},
 | 
						|
		}
 | 
						|
 | 
						|
		defer func() {
 | 
						|
			persistentVolumeTestCleanup(c, config)
 | 
						|
		}()
 | 
						|
 | 
						|
		// Create the nfs server pod
 | 
						|
		pod := startVolumeServer(c, config)
 | 
						|
		serverIP := pod.Status.PodIP
 | 
						|
		framework.Logf("NFS server IP address: %v", serverIP)
 | 
						|
 | 
						|
		// Define the PersistentVolume and PersistentVolumeClaim
 | 
						|
		pv := makePersistentVolume(serverIP)
 | 
						|
		pvc := makePersistentVolumeClaim(ns)
 | 
						|
 | 
						|
		// Create the PersistentVolume and wait for PersistentVolume.Status.Phase to be Available
 | 
						|
		// defer deletion to clean up the PV should the test fail post-creation.
 | 
						|
		framework.Logf("Creating PersistentVolume")
 | 
						|
		pv, err := c.PersistentVolumes().Create(pv)
 | 
						|
		if err != nil {
 | 
						|
			framework.Failf("Create PersistentVolume failed: %v", err)
 | 
						|
		}
 | 
						|
		defer deletePersistentVolume(c, pv)
 | 
						|
		framework.WaitForPersistentVolumePhase(api.VolumeAvailable, c, pv.Name, 1*time.Second, 20*time.Second)
 | 
						|
 | 
						|
		// Create the PersistentVolumeClaim and wait for Bound phase
 | 
						|
		framework.Logf("Creating PersistentVolumeClaim")
 | 
						|
		pvc, err = c.PersistentVolumeClaims(ns).Create(pvc)
 | 
						|
		if err != nil {
 | 
						|
			framework.Failf("Create PersistentVolumeClaim failed: %v", err)
 | 
						|
		}
 | 
						|
		framework.WaitForPersistentVolumeClaimPhase(api.ClaimBound, c, ns, pvc.Name, 3*time.Second, 300*time.Second)
 | 
						|
 | 
						|
		// Wait for PersistentVolume.Status.Phase to be Bound. Can take several minutes.
 | 
						|
		err = framework.WaitForPersistentVolumePhase(api.VolumeBound, c, pv.Name, 3*time.Second, 300*time.Second)
 | 
						|
		if err != nil {
 | 
						|
			framework.Failf("PersistentVolume failed to enter a bound state: %+v", err)
 | 
						|
		}
 | 
						|
		// Check the PersistentVolume.ClaimRef.UID for non-nil value as confirmation of the bound state.
 | 
						|
		framework.Logf("Checking PersistentVolume ClaimRef is non-nil")
 | 
						|
		pv, err = c.PersistentVolumes().Get(pv.Name)
 | 
						|
		if pv.Spec.ClaimRef == nil || len(pv.Spec.ClaimRef.UID) == 0 {
 | 
						|
			pvJson, _ := json.MarshalIndent(pv, "", "  ")
 | 
						|
			framework.Failf("Expected PersistentVolume to be bound, but got nil ClaimRef or UID: %+v", string(pvJson))
 | 
						|
		}
 | 
						|
 | 
						|
		// Check the PersistentVolumeClaim.Status.Phase for Bound state
 | 
						|
		framework.Logf("Checking PersistentVolumeClaim status is Bound")
 | 
						|
		pvc, err = c.PersistentVolumeClaims(ns).Get(pvc.Name)
 | 
						|
		if pvcPhase := pvc.Status.Phase; pvcPhase != "Bound" {
 | 
						|
			framework.Failf("Expected PersistentVolumeClaim status Bound. Actual:  %+v.  Error: %+v", pvcPhase, err)
 | 
						|
		}
 | 
						|
 | 
						|
		// Check that the PersistentVolume's ClaimRef contains the UID of the PersistendVolumeClaim
 | 
						|
		if pvc.ObjectMeta.UID != pv.Spec.ClaimRef.UID {
 | 
						|
			framework.Failf("Binding failed: PersistentVolumeClaim UID does not match PersistentVolume's ClaimRef UID. ")
 | 
						|
		}
 | 
						|
 | 
						|
		// writePod writes to the nfs volume
 | 
						|
		framework.Logf("Creating writePod")
 | 
						|
		pvc, _ = c.PersistentVolumeClaims(ns).Get(pvc.Name)
 | 
						|
		writePod := makeWritePod(ns, pvc.Name)
 | 
						|
		writePod, err = c.Pods(ns).Create(writePod)
 | 
						|
		if err != nil {
 | 
						|
			framework.Failf("Create writePod failed: %+v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		// Wait for the writePod to complete it's lifecycle
 | 
						|
		err = framework.WaitForPodSuccessInNamespace(c, writePod.Name, writePod.Spec.Containers[0].Name, writePod.Namespace)
 | 
						|
		if err != nil {
 | 
						|
			framework.Failf("WritePod exited with error: %+v", err)
 | 
						|
		} else {
 | 
						|
			framework.Logf("WritePod exited without error.")
 | 
						|
		}
 | 
						|
 | 
						|
		// Delete the PersistentVolumeClaim
 | 
						|
		framework.Logf("Deleting PersistentVolumeClaim to trigger PV Recycling")
 | 
						|
		err = c.PersistentVolumeClaims(ns).Delete(pvc.Name)
 | 
						|
		if err != nil {
 | 
						|
			framework.Failf("Delete PersistentVolumeClaim failed: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		// Wait for the PersistentVolume phase to return to Available
 | 
						|
		framework.Logf("Waiting for recycling process to complete.")
 | 
						|
		err = framework.WaitForPersistentVolumePhase(api.VolumeAvailable, c, pv.Name, 3*time.Second, 300*time.Second)
 | 
						|
		if err != nil {
 | 
						|
			framework.Failf("Recycling failed: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		// Examine the PersistentVolume.ClaimRef and UID.  Expect nil values.
 | 
						|
		pv, err = c.PersistentVolumes().Get(pv.Name)
 | 
						|
		if pv.Spec.ClaimRef != nil && len(pv.Spec.ClaimRef.UID) > 0 {
 | 
						|
			crjson, _ := json.MarshalIndent(pv.Spec.ClaimRef, "", "  ")
 | 
						|
			framework.Failf("Expected a nil ClaimRef or UID. Found: ", string(crjson))
 | 
						|
		}
 | 
						|
 | 
						|
	})
 | 
						|
})
 | 
						|
 | 
						|
func makePersistentVolume(serverIP string) *api.PersistentVolume {
 | 
						|
	// Takes an NFS server IP address and returns a PersistentVolume object for instantiation.
 | 
						|
	// Specs are expected to match this test's PersistentVolumeClaim
 | 
						|
	return &api.PersistentVolume{
 | 
						|
		ObjectMeta: api.ObjectMeta{
 | 
						|
			GenerateName: "nfs-",
 | 
						|
		},
 | 
						|
		Spec: api.PersistentVolumeSpec{
 | 
						|
			PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRecycle,
 | 
						|
			Capacity: api.ResourceList{
 | 
						|
				api.ResourceName(api.ResourceStorage): resource.MustParse("2Gi"),
 | 
						|
			},
 | 
						|
			PersistentVolumeSource: api.PersistentVolumeSource{
 | 
						|
				NFS: &api.NFSVolumeSource{
 | 
						|
					Server:   serverIP,
 | 
						|
					Path:     "/exports",
 | 
						|
					ReadOnly: false,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			AccessModes: []api.PersistentVolumeAccessMode{
 | 
						|
				api.ReadWriteOnce,
 | 
						|
				api.ReadOnlyMany,
 | 
						|
				api.ReadWriteMany,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func makePersistentVolumeClaim(ns string) *api.PersistentVolumeClaim {
 | 
						|
	// Takes a namespace and returns a PersistentVolumeClaim object for instantiation.
 | 
						|
	// Specs are expected to match this test's PersistentVolume
 | 
						|
	return &api.PersistentVolumeClaim{
 | 
						|
		ObjectMeta: api.ObjectMeta{
 | 
						|
			GenerateName: "pvc-",
 | 
						|
			Namespace:    ns,
 | 
						|
		},
 | 
						|
		Spec: api.PersistentVolumeClaimSpec{
 | 
						|
			AccessModes: []api.PersistentVolumeAccessMode{
 | 
						|
				api.ReadWriteOnce,
 | 
						|
				api.ReadOnlyMany,
 | 
						|
				api.ReadWriteMany,
 | 
						|
			},
 | 
						|
			Resources: api.ResourceRequirements{
 | 
						|
				Requests: api.ResourceList{
 | 
						|
					api.ResourceName(api.ResourceStorage): resource.MustParse("1Gi"),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func makeWritePod(ns string, pvcName string) *api.Pod {
 | 
						|
	// Prepare pod that mounts the NFS volume again and
 | 
						|
	// checks that /mnt/index.html was scrubbed there
 | 
						|
 | 
						|
	var isPrivileged bool = true
 | 
						|
	return &api.Pod{
 | 
						|
		TypeMeta: unversioned.TypeMeta{
 | 
						|
			Kind:       "Pod",
 | 
						|
			APIVersion: testapi.Default.GroupVersion().String(),
 | 
						|
		},
 | 
						|
		ObjectMeta: api.ObjectMeta{
 | 
						|
			GenerateName: "write-pod-",
 | 
						|
			Namespace:    ns,
 | 
						|
		},
 | 
						|
		Spec: api.PodSpec{
 | 
						|
			Containers: []api.Container{
 | 
						|
				{
 | 
						|
					Name:    "write-pod",
 | 
						|
					Image:   "gcr.io/google_containers/busybox:1.24",
 | 
						|
					Command: []string{"/bin/sh"},
 | 
						|
					Args:    []string{"-c", "touch /mnt/SUCCESS && exit 0 || exit 1"},
 | 
						|
					VolumeMounts: []api.VolumeMount{
 | 
						|
						{
 | 
						|
							Name:      "nfs-pvc",
 | 
						|
							MountPath: "/mnt",
 | 
						|
						},
 | 
						|
					},
 | 
						|
					SecurityContext: &api.SecurityContext{
 | 
						|
						Privileged: &isPrivileged,
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			Volumes: []api.Volume{
 | 
						|
				{
 | 
						|
					Name: "nfs-pvc",
 | 
						|
					VolumeSource: api.VolumeSource{
 | 
						|
						PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{
 | 
						|
							ClaimName: pvcName,
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 |