diff --git a/pkg/controller/persistentvolume/types.go b/pkg/controller/persistentvolume/persistentvolume_index.go similarity index 78% rename from pkg/controller/persistentvolume/types.go rename to pkg/controller/persistentvolume/persistentvolume_index.go index 42ca3680180..c323ef49744 100644 --- a/pkg/controller/persistentvolume/types.go +++ b/pkg/controller/persistentvolume/persistentvolume_index.go @@ -24,34 +24,9 @@ import ( "k8s.io/kubernetes/pkg/client/cache" ) -const ( - // A PVClaim can request a quality of service tier by adding this annotation. The value of the annotation - // is arbitrary. The values are pre-defined by a cluster admin and known to users when requesting a QoS. - // For example tiers might be gold, silver, and tin and the admin configures what that means for each volume plugin that can provision a volume. - // Values in the alpha version of this feature are not meaningful, but will be in the full version of this feature. - qosProvisioningKey = "volume.alpha.kubernetes.io/storage-class" - // Name of a tag attached to a real volume in cloud (e.g. AWS EBS or GCE PD) - // with namespace of a persistent volume claim used to create this volume. - cloudVolumeCreatedForClaimNamespaceTag = "kubernetes.io/created-for/pvc/namespace" - // Name of a tag attached to a real volume in cloud (e.g. AWS EBS or GCE PD) - // with name of a persistent volume claim used to create this volume. - cloudVolumeCreatedForClaimNameTag = "kubernetes.io/created-for/pvc/name" - // Name of a tag attached to a real volume in cloud (e.g. AWS EBS or GCE PD) - // with name of appropriate Kubernetes persistent volume . - cloudVolumeCreatedForVolumeNameTag = "kubernetes.io/created-for/pv/name" -) - // persistentVolumeOrderedIndex is a cache.Store that keeps persistent volumes indexed by AccessModes and ordered by storage capacity. type persistentVolumeOrderedIndex struct { - cache.Indexer -} - -var _ cache.Store = &persistentVolumeOrderedIndex{} // persistentVolumeOrderedIndex is a Store - -func NewPersistentVolumeOrderedIndex() *persistentVolumeOrderedIndex { - return &persistentVolumeOrderedIndex{ - cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"accessmodes": accessModesIndexFunc}), - } + store cache.Indexer } // accessModesIndexFunc is an indexing function that returns a persistent volume's AccessModes as a string @@ -63,15 +38,15 @@ func accessModesIndexFunc(obj interface{}) ([]string, error) { return []string{""}, fmt.Errorf("object is not a persistent volume: %v", obj) } -// ListByAccessModes returns all volumes with the given set of AccessModeTypes *in order* of their storage capacity (low to high) -func (pvIndex *persistentVolumeOrderedIndex) ListByAccessModes(modes []api.PersistentVolumeAccessMode) ([]*api.PersistentVolume, error) { +// listByAccessModes returns all volumes with the given set of AccessModeTypes *in order* of their storage capacity (low to high) +func (pvIndex *persistentVolumeOrderedIndex) listByAccessModes(modes []api.PersistentVolumeAccessMode) ([]*api.PersistentVolume, error) { pv := &api.PersistentVolume{ Spec: api.PersistentVolumeSpec{ AccessModes: modes, }, } - objs, err := pvIndex.Index("accessmodes", pv) + objs, err := pvIndex.store.Index("accessmodes", pv) if err != nil { return nil, err } @@ -101,7 +76,7 @@ func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *api.PersistentVo allPossibleModes := pvIndex.allPossibleMatchingAccessModes(claim.Spec.AccessModes) for _, modes := range allPossibleModes { - volumes, err := pvIndex.ListByAccessModes(modes) + volumes, err := pvIndex.listByAccessModes(modes) if err != nil { return nil, err } @@ -123,10 +98,14 @@ func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *api.PersistentVo } } - // a claim requesting provisioning will have an exact match pre-bound to the claim. - // no need to search through unbound volumes. The matching volume will be created by the provisioner - // and will match above when the claim is re-processed by the binder. - if keyExists(qosProvisioningKey, claim.Annotations) { + // We want to provision volumes if the annotation is set even if there + // is matching PV. Therefore, do not look for available PV and let + // a new volume to be provisioned. + // + // When provisioner creates a new PV to this claim, an exact match + // pre-bound to the claim will be found by the checks above during + // subsequent claim sync. + if hasAnnotation(claim.ObjectMeta, annClass) { return nil, nil } @@ -213,7 +192,7 @@ func matchStorageCapacity(pvA, pvB *api.PersistentVolume) bool { // func (pvIndex *persistentVolumeOrderedIndex) allPossibleMatchingAccessModes(requestedModes []api.PersistentVolumeAccessMode) [][]api.PersistentVolumeAccessMode { matchedModes := [][]api.PersistentVolumeAccessMode{} - keys := pvIndex.Indexer.ListIndexFuncValues("accessmodes") + keys := pvIndex.store.ListIndexFuncValues("accessmodes") for _, key := range keys { indexedModes := api.GetAccessModesFromString(key) if containedInAll(indexedModes, requestedModes) { diff --git a/pkg/controller/persistentvolume/persistentvolume_index_test.go b/pkg/controller/persistentvolume/persistentvolume_index_test.go index 7bb6c5387bd..61134f13700 100644 --- a/pkg/controller/persistentvolume/persistentvolume_index_test.go +++ b/pkg/controller/persistentvolume/persistentvolume_index_test.go @@ -22,12 +22,17 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/client/cache" ) +func newPersistentVolumeOrderedIndex() persistentVolumeOrderedIndex { + return persistentVolumeOrderedIndex{cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"accessmodes": accessModesIndexFunc})} +} + func TestMatchVolume(t *testing.T) { - volList := NewPersistentVolumeOrderedIndex() + volList := newPersistentVolumeOrderedIndex() for _, pv := range createTestVolumes() { - volList.Add(pv) + volList.store.Add(pv) } scenarios := map[string]struct { @@ -122,7 +127,7 @@ func TestMatchVolume(t *testing.T) { } func TestMatchingWithBoundVolumes(t *testing.T) { - volumeIndex := NewPersistentVolumeOrderedIndex() + volumeIndex := newPersistentVolumeOrderedIndex() // two similar volumes, one is bound pv1 := &api.PersistentVolume{ ObjectMeta: api.ObjectMeta{ @@ -158,8 +163,8 @@ func TestMatchingWithBoundVolumes(t *testing.T) { }, } - volumeIndex.Add(pv1) - volumeIndex.Add(pv2) + volumeIndex.store.Add(pv1) + volumeIndex.store.Add(pv2) claim := &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ @@ -189,12 +194,12 @@ func TestMatchingWithBoundVolumes(t *testing.T) { } func TestSort(t *testing.T) { - volList := NewPersistentVolumeOrderedIndex() + volList := newPersistentVolumeOrderedIndex() for _, pv := range createTestVolumes() { - volList.Add(pv) + volList.store.Add(pv) } - volumes, err := volList.ListByAccessModes([]api.PersistentVolumeAccessMode{api.ReadWriteOnce, api.ReadOnlyMany}) + volumes, err := volList.listByAccessModes([]api.PersistentVolumeAccessMode{api.ReadWriteOnce, api.ReadOnlyMany}) if err != nil { t.Error("Unexpected error retrieving volumes by access modes:", err) } @@ -205,7 +210,7 @@ func TestSort(t *testing.T) { } } - volumes, err = volList.ListByAccessModes([]api.PersistentVolumeAccessMode{api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany}) + volumes, err = volList.listByAccessModes([]api.PersistentVolumeAccessMode{api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany}) if err != nil { t.Error("Unexpected error retrieving volumes by access modes:", err) } @@ -218,9 +223,9 @@ func TestSort(t *testing.T) { } func TestAllPossibleAccessModes(t *testing.T) { - index := NewPersistentVolumeOrderedIndex() + index := newPersistentVolumeOrderedIndex() for _, pv := range createTestVolumes() { - index.Add(pv) + index.store.Add(pv) } // the mock PVs creates contain 2 types of accessmodes: RWO+ROX and RWO+ROW+RWX @@ -292,10 +297,10 @@ func TestFindingVolumeWithDifferentAccessModes(t *testing.T) { }, } - index := NewPersistentVolumeOrderedIndex() - index.Add(gce) - index.Add(ebs) - index.Add(nfs) + index := newPersistentVolumeOrderedIndex() + index.store.Add(gce) + index.store.Add(ebs) + index.store.Add(nfs) volume, _ := index.findBestMatchForClaim(claim) if volume.Name != ebs.Name { @@ -521,10 +526,10 @@ func TestFindingPreboundVolumes(t *testing.T) { pv5 := testVolume("pv5", "5Gi") pv8 := testVolume("pv8", "8Gi") - index := NewPersistentVolumeOrderedIndex() - index.Add(pv1) - index.Add(pv5) - index.Add(pv8) + index := newPersistentVolumeOrderedIndex() + index.store.Add(pv1) + index.store.Add(pv5) + index.store.Add(pv8) // expected exact match on size volume, _ := index.findBestMatchForClaim(claim)