Example #1
// DoTestStorageClasses tests storage classes for one api version.
func DoTestStorageClasses(t *testing.T, client *client.Client, ns *api.Namespace) {
	// Make a storage class object.
	s := storage.StorageClass{
		TypeMeta: unversioned.TypeMeta{
			Kind: "StorageClass",
		ObjectMeta: api.ObjectMeta{
			Name: "gold",
		Provisioner: provisionerPluginName,

	if _, err := client.Storage().StorageClasses().Create(&s); err != nil {
		t.Errorf("unable to create test storage class: %v", err)
	defer deleteStorageClassOrErrorf(t, client, s.Namespace, s.Name)

	// Template for pvcs that specify a storage class
	pvc := &api.PersistentVolumeClaim{
		ObjectMeta: api.ObjectMeta{
			Name:      "XXX",
			Namespace: ns.Name,
			Annotations: map[string]string{
				storageutil.StorageClassAnnotation: "gold",
		Spec: api.PersistentVolumeClaimSpec{
			Resources:   api.ResourceRequirements{Requests: api.ResourceList{api.ResourceName(api.ResourceStorage): resource.MustParse("1G")}},
			AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},

	pvc.ObjectMeta.Name = "uses-storageclass"
	if _, err := client.PersistentVolumeClaims(ns.Name).Create(pvc); err != nil {
		t.Errorf("Failed to create pvc: %v", err)
	defer deletePersistentVolumeClaimOrErrorf(t, client, ns.Name, pvc.Name)
Example #2
func deleteStorageClassOrErrorf(t *testing.T, c *client.Client, ns, name string) {
	if err := c.Storage().StorageClasses().Delete(name); err != nil {
		t.Errorf("unable to delete storage class %v: %v", name, err)
Example #3
	// filled in BeforeEach
	var c *client.Client
	var ns string

	BeforeEach(func() {
		c = f.Client
		ns = f.Namespace.Name

	framework.KubeDescribe("DynamicProvisioner", func() {
		It("should create and delete persistent volumes [Slow]", func() {
			framework.SkipUnlessProviderIs("openstack", "gce", "aws", "gke")

			By("creating a StorageClass")
			class := newStorageClass()
			_, err := c.Storage().StorageClasses().Create(class)
			defer c.Storage().StorageClasses().Delete(class.Name)

			By("creating a claim with a dynamic provisioning annotation")
			claim := newClaim(ns, false)
			defer func() {
			claim, err = c.PersistentVolumeClaims(ns).Create(claim)

			testDynamicProvisioning(c, claim)
func testDynamicProvisioning(t storageClassTest, client *client.Client, claim *api.PersistentVolumeClaim, class *storage.StorageClass) {
	if class != nil {
		By("creating a StorageClass " + class.Name)
		class, err := client.Storage().StorageClasses().Create(class)
		defer func() {
			framework.Logf("deleting storage class %s", class.Name)

	By("creating a claim")
	claim, err := client.PersistentVolumeClaims(claim.Namespace).Create(claim)
	defer func() {
		framework.Logf("deleting claim %s/%s", claim.Namespace, claim.Name)
	err = framework.WaitForPersistentVolumeClaimPhase(api.ClaimBound, client, claim.Namespace, claim.Name, framework.Poll, framework.ClaimProvisionTimeout)

	By("checking the claim")
	// Get new copy of the claim
	claim, err = client.PersistentVolumeClaims(claim.Namespace).Get(claim.Name)

	// Get the bound PV
	pv, err := client.PersistentVolumes().Get(claim.Spec.VolumeName)

	// Check sizes
	expectedCapacity := resource.MustParse(t.expectedSize)
	pvCapacity := pv.Spec.Capacity[api.ResourceName(api.ResourceStorage)]

	requestedCapacity := resource.MustParse(t.claimSize)
	claimCapacity := claim.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]

	// Check PV properties
	By("checking the PV")
	expectedAccessModes := []api.PersistentVolumeAccessMode{api.ReadWriteOnce}

	// Run the checker
	if t.pvCheck != nil {
		err = t.pvCheck(pv)

	// We start two pods:
	// - The first writes 'hello word' to the /mnt/test (= the volume).
	// - The second one runs grep 'hello world' on /mnt/test.
	// If both succeed, Kubernetes actually allocated something that is
	// persistent across pods.
	By("checking the created volume is writable")
	runInPodWithVolume(client, claim.Namespace, claim.Name, "echo 'hello world' > /mnt/test/data")

	By("checking the created volume is readable and retains data")
	runInPodWithVolume(client, claim.Namespace, claim.Name, "grep 'hello world' /mnt/test/data")

	// Ugly hack: if we delete the AWS/GCE/OpenStack volume here, it will
	// probably collide with destruction of the pods above - the pods
	// still have the volume attached (kubelet is slow...) and deletion
	// of attached volume is not allowed by AWS/GCE/OpenStack.
	// Kubernetes *will* retry deletion several times in
	// pvclaimbinder-sync-period.
	// So, technically, this sleep is not needed. On the other hand,
	// the sync perion is 10 minutes and we really don't want to wait
	// 10 minutes here. There is no way how to see if kubelet is
	// finished with cleaning volumes. A small sleep here actually
	// speeds up the test!
	// Three minutes should be enough to clean up the pods properly.
	// We've seen GCE PD detach to take more than 1 minute.
	By("Sleeping to let kubelet destroy all pods")
	time.Sleep(3 * time.Minute)

	By("deleting the claim")

	// Wait for the PV to get deleted too.
	framework.ExpectNoError(framework.WaitForPersistentVolumeDeleted(client, pv.Name, 5*time.Second, 20*time.Minute))