mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 13:50:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			240 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2015 The Kubernetes Authors All rights reserved.
 | |
| 
 | |
| 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 persistentvolume
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"k8s.io/kubernetes/pkg/api"
 | |
| 	"k8s.io/kubernetes/pkg/api/errors"
 | |
| 	"k8s.io/kubernetes/pkg/api/resource"
 | |
| 	"k8s.io/kubernetes/pkg/api/testapi"
 | |
| 	client "k8s.io/kubernetes/pkg/client/unversioned"
 | |
| 	fake_cloud "k8s.io/kubernetes/pkg/cloudprovider/providers/fake"
 | |
| 	"k8s.io/kubernetes/pkg/util"
 | |
| 	"k8s.io/kubernetes/pkg/volume"
 | |
| 	"k8s.io/kubernetes/pkg/watch"
 | |
| )
 | |
| 
 | |
| func TestProvisionerRunStop(t *testing.T) {
 | |
| 	controller, _ := makeTestController()
 | |
| 
 | |
| 	if len(controller.stopChannels) != 0 {
 | |
| 		t.Errorf("Non-running provisioner should not have any stopChannels.  Got %v", len(controller.stopChannels))
 | |
| 	}
 | |
| 
 | |
| 	controller.Run()
 | |
| 
 | |
| 	if len(controller.stopChannels) != 2 {
 | |
| 		t.Errorf("Running provisioner should have exactly 2 stopChannels.  Got %v", len(controller.stopChannels))
 | |
| 	}
 | |
| 
 | |
| 	controller.Stop()
 | |
| 
 | |
| 	if len(controller.stopChannels) != 0 {
 | |
| 		t.Errorf("Non-running provisioner should not have any stopChannels.  Got %v", len(controller.stopChannels))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func makeTestVolume() *api.PersistentVolume {
 | |
| 	return &api.PersistentVolume{
 | |
| 		ObjectMeta: api.ObjectMeta{
 | |
| 			Annotations: map[string]string{},
 | |
| 			Name:        "pv01",
 | |
| 		},
 | |
| 		Spec: api.PersistentVolumeSpec{
 | |
| 			PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
 | |
| 			AccessModes:                   []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
 | |
| 			Capacity: api.ResourceList{
 | |
| 				api.ResourceName(api.ResourceStorage): resource.MustParse("10Gi"),
 | |
| 			},
 | |
| 			PersistentVolumeSource: api.PersistentVolumeSource{
 | |
| 				HostPath: &api.HostPathVolumeSource{
 | |
| 					Path: "/tmp/data01",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func makeTestClaim() *api.PersistentVolumeClaim {
 | |
| 	return &api.PersistentVolumeClaim{
 | |
| 		ObjectMeta: api.ObjectMeta{
 | |
| 			Annotations: map[string]string{},
 | |
| 			Name:        "claim01",
 | |
| 			Namespace:   "ns",
 | |
| 			SelfLink:    testapi.Default.SelfLink("pvc", ""),
 | |
| 		},
 | |
| 		Spec: api.PersistentVolumeClaimSpec{
 | |
| 			AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
 | |
| 			Resources: api.ResourceRequirements{
 | |
| 				Requests: api.ResourceList{
 | |
| 					api.ResourceName(api.ResourceStorage): resource.MustParse("8G"),
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func makeTestController() (*PersistentVolumeProvisionerController, *mockControllerClient) {
 | |
| 	mockClient := &mockControllerClient{}
 | |
| 	mockVolumePlugin := &volume.FakeVolumePlugin{}
 | |
| 	controller, _ := NewPersistentVolumeProvisionerController(mockClient, 1*time.Second, nil, mockVolumePlugin, &fake_cloud.FakeCloud{})
 | |
| 	return controller, mockClient
 | |
| }
 | |
| 
 | |
| func TestReconcileClaim(t *testing.T) {
 | |
| 	controller, mockClient := makeTestController()
 | |
| 	pvc := makeTestClaim()
 | |
| 
 | |
| 	// watch would have added the claim to the store
 | |
| 	controller.claimStore.Add(pvc)
 | |
| 	err := controller.reconcileClaim(pvc)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("Unexpected error: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// non-provisionable PVC should not have created a volume on reconciliation
 | |
| 	if mockClient.volume != nil {
 | |
| 		t.Error("Unexpected volume found in mock client.  Expected nil")
 | |
| 	}
 | |
| 
 | |
| 	pvc.Annotations[qosProvisioningKey] = "foo"
 | |
| 
 | |
| 	err = controller.reconcileClaim(pvc)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("Unexpected error: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// PVC requesting provisioning should have a PV created for it
 | |
| 	if mockClient.volume == nil {
 | |
| 		t.Error("Expected to find bound volume but got nil")
 | |
| 	}
 | |
| 
 | |
| 	if mockClient.volume.Spec.ClaimRef.Name != pvc.Name {
 | |
| 		t.Errorf("Expected PV to be bound to %s but got %s", mockClient.volume.Spec.ClaimRef.Name, pvc.Name)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestReconcileVolume(t *testing.T) {
 | |
| 
 | |
| 	controller, mockClient := makeTestController()
 | |
| 	pv := makeTestVolume()
 | |
| 	pvc := makeTestClaim()
 | |
| 
 | |
| 	err := controller.reconcileVolume(pv)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("Unexpected error %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// watch adds claim to the store.
 | |
| 	// we need to add it to our mock client to mimic normal Get call
 | |
| 	controller.claimStore.Add(pvc)
 | |
| 	mockClient.claim = pvc
 | |
| 
 | |
| 	// pretend the claim and volume are bound, no provisioning required
 | |
| 	claimRef, _ := api.GetReference(pvc)
 | |
| 	pv.Spec.ClaimRef = claimRef
 | |
| 	err = controller.reconcileVolume(pv)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("Unexpected error %v", err)
 | |
| 	}
 | |
| 
 | |
| 	pv.Annotations[pvProvisioningRequiredAnnotationKey] = "!pvProvisioningCompleted"
 | |
| 	pv.Annotations[qosProvisioningKey] = "foo"
 | |
| 	err = controller.reconcileVolume(pv)
 | |
| 
 | |
| 	if !isAnnotationMatch(pvProvisioningRequiredAnnotationKey, pvProvisioningCompletedAnnotationValue, mockClient.volume.Annotations) {
 | |
| 		t.Errorf("Expected %s but got %s", pvProvisioningRequiredAnnotationKey, mockClient.volume.Annotations[pvProvisioningRequiredAnnotationKey])
 | |
| 	}
 | |
| }
 | |
| 
 | |
| var _ controllerClient = &mockControllerClient{}
 | |
| 
 | |
| type mockControllerClient struct {
 | |
| 	volume *api.PersistentVolume
 | |
| 	claim  *api.PersistentVolumeClaim
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) GetPersistentVolume(name string) (*api.PersistentVolume, error) {
 | |
| 	return c.volume, nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) CreatePersistentVolume(pv *api.PersistentVolume) (*api.PersistentVolume, error) {
 | |
| 	if pv.GenerateName != "" && pv.Name == "" {
 | |
| 		pv.Name = fmt.Sprintf(pv.GenerateName, util.NewUUID())
 | |
| 	}
 | |
| 	c.volume = pv
 | |
| 	return c.volume, nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) ListPersistentVolumes(options api.ListOptions) (*api.PersistentVolumeList, error) {
 | |
| 	return &api.PersistentVolumeList{
 | |
| 		Items: []api.PersistentVolume{*c.volume},
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) WatchPersistentVolumes(options api.ListOptions) (watch.Interface, error) {
 | |
| 	return watch.NewFake(), nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) UpdatePersistentVolume(pv *api.PersistentVolume) (*api.PersistentVolume, error) {
 | |
| 	return c.CreatePersistentVolume(pv)
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) DeletePersistentVolume(volume *api.PersistentVolume) error {
 | |
| 	c.volume = nil
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) UpdatePersistentVolumeStatus(volume *api.PersistentVolume) (*api.PersistentVolume, error) {
 | |
| 	return volume, nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) GetPersistentVolumeClaim(namespace, name string) (*api.PersistentVolumeClaim, error) {
 | |
| 	if c.claim != nil {
 | |
| 		return c.claim, nil
 | |
| 	} else {
 | |
| 		return nil, errors.NewNotFound(api.Resource("persistentvolumes"), name)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) ListPersistentVolumeClaims(namespace string, options api.ListOptions) (*api.PersistentVolumeClaimList, error) {
 | |
| 	return &api.PersistentVolumeClaimList{
 | |
| 		Items: []api.PersistentVolumeClaim{*c.claim},
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) WatchPersistentVolumeClaims(namespace string, options api.ListOptions) (watch.Interface, error) {
 | |
| 	return watch.NewFake(), nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) UpdatePersistentVolumeClaim(claim *api.PersistentVolumeClaim) (*api.PersistentVolumeClaim, error) {
 | |
| 	c.claim = claim
 | |
| 	return c.claim, nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) UpdatePersistentVolumeClaimStatus(claim *api.PersistentVolumeClaim) (*api.PersistentVolumeClaim, error) {
 | |
| 	return claim, nil
 | |
| }
 | |
| 
 | |
| func (c *mockControllerClient) GetKubeClient() client.Interface {
 | |
| 	return nil
 | |
| }
 |