mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 23:37:01 +00:00
Merge pull request #34638 from screeley44/k8-get-sc
Automatic merge from submit-queue Adding default StorageClass annotation printout for resource_printer and describer and some refactoring adding ISDEFAULT for _kubectl get storageclass_ output ``` [root@screeley-sc1 gce]# kubectl get storageclass NAME TYPE ISDEFAULT another-class kubernetes.io/gce-pd NO generic1-slow kubernetes.io/gce-pd YES generic2-fast kubernetes.io/gce-pd YES ``` ```release-note Add ISDEFAULT to kubectl get storageClass output ``` @kubernetes/sig-storage
This commit is contained in:
commit
91b7e1f9c3
@ -236,6 +236,20 @@ var standardFinalizers = sets.NewString(
|
||||
FinalizerOrphan,
|
||||
)
|
||||
|
||||
// HasAnnotation returns a bool if passed in annotation exists
|
||||
func HasAnnotation(obj ObjectMeta, ann string) bool {
|
||||
_, found := obj.Annotations[ann]
|
||||
return found
|
||||
}
|
||||
|
||||
// SetMetaDataAnnotation sets the annotation and value
|
||||
func SetMetaDataAnnotation(obj *ObjectMeta, ann string, value string) {
|
||||
if obj.Annotations == nil {
|
||||
obj.Annotations = make(map[string]string)
|
||||
}
|
||||
obj.Annotations[ann] = value
|
||||
}
|
||||
|
||||
func IsStandardFinalizerName(str string) bool {
|
||||
return standardFinalizers.Has(str)
|
||||
}
|
||||
|
136
pkg/apis/storage/util/helpers.go
Normal file
136
pkg/apis/storage/util/helpers.go
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
Copyright 2016 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 util
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// IsDefaultStorageClassAnnotation represents a StorageClass annotation that
|
||||
// marks a class as the default StorageClass
|
||||
//TODO: Update IsDefaultStorageClassannotation and remove Beta when no longer used
|
||||
const IsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class"
|
||||
const BetaIsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class"
|
||||
|
||||
// AlphaStorageClassAnnotation represents the previous alpha storage class
|
||||
// annotation. it's no longer used and held here for posterity.
|
||||
const AlphaStorageClassAnnotation = "volume.alpha.kubernetes.io/storage-class"
|
||||
|
||||
// BetaStorageClassAnnotation represents the beta/previous StorageClass annotation.
|
||||
// It's currently still used and will be held for backwards compatibility
|
||||
const BetaStorageClassAnnotation = "volume.beta.kubernetes.io/storage-class"
|
||||
|
||||
// StorageClassAnnotation represents the storage class associated with a resource.
|
||||
// It currently matches the Beta value and can change when official is set.
|
||||
// - in PersistentVolumeClaim it represents required class to match.
|
||||
// Only PersistentVolumes with the same class (i.e. annotation with the same
|
||||
// value) can be bound to the claim. In case no such volume exists, the
|
||||
// controller will provision a new one using StorageClass instance with
|
||||
// the same name as the annotation value.
|
||||
// - in PersistentVolume it represents storage class to which the persistent
|
||||
// volume belongs.
|
||||
//TODO: Update this to final annotation value as it matches BetaStorageClassAnnotation for now
|
||||
const StorageClassAnnotation = "volume.beta.kubernetes.io/storage-class"
|
||||
|
||||
// GetVolumeStorageClass returns value of StorageClassAnnotation or empty string in case
|
||||
// the annotation does not exist.
|
||||
// TODO: change to PersistentVolume.Spec.Class value when this attribute is
|
||||
// introduced.
|
||||
func GetVolumeStorageClass(volume *api.PersistentVolume) string {
|
||||
if class, found := volume.Annotations[StorageClassAnnotation]; found {
|
||||
return class
|
||||
}
|
||||
|
||||
// 'nil' is interpreted as "", i.e. the volume does not belong to any class.
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetClaimStorageClass returns name of class that is requested by given claim.
|
||||
// Request for `nil` class is interpreted as request for class "",
|
||||
// i.e. for a classless PV.
|
||||
// TODO: change to PersistentVolumeClaim.Spec.Class value when this
|
||||
// attribute is introduced.
|
||||
func GetClaimStorageClass(claim *api.PersistentVolumeClaim) string {
|
||||
if class, found := claim.Annotations[StorageClassAnnotation]; found {
|
||||
return class
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetStorageClassAnnotation returns the StorageClass value
|
||||
// if the annotation is set, empty string if not
|
||||
// TODO: remove Alpha and Beta when no longer used or needed
|
||||
func GetStorageClassAnnotation(obj api.ObjectMeta) string {
|
||||
if class, ok := obj.Annotations[StorageClassAnnotation]; ok {
|
||||
return class
|
||||
}
|
||||
if class, ok := obj.Annotations[BetaStorageClassAnnotation]; ok {
|
||||
return class
|
||||
}
|
||||
if class, ok := obj.Annotations[AlphaStorageClassAnnotation]; ok {
|
||||
return class
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// HasStorageClassAnnotation returns a boolean
|
||||
// if the annotation is set
|
||||
// TODO: remove Alpha and Beta when no longer used or needed
|
||||
func HasStorageClassAnnotation(obj api.ObjectMeta) bool {
|
||||
if _, found := obj.Annotations[StorageClassAnnotation]; found {
|
||||
return found
|
||||
}
|
||||
if _, found := obj.Annotations[BetaStorageClassAnnotation]; found {
|
||||
return found
|
||||
}
|
||||
if _, found := obj.Annotations[AlphaStorageClassAnnotation]; found {
|
||||
return found
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
// IsDefaultAnnotationText returns a pretty Yes/No String if
|
||||
// the annotation is set
|
||||
// TODO: remove Beta when no longer needed
|
||||
func IsDefaultAnnotationText(obj api.ObjectMeta) string {
|
||||
if obj.Annotations[IsDefaultStorageClassAnnotation] == "true" {
|
||||
return "Yes"
|
||||
}
|
||||
if obj.Annotations[BetaIsDefaultStorageClassAnnotation] == "true" {
|
||||
return "Yes"
|
||||
}
|
||||
|
||||
return "No"
|
||||
}
|
||||
|
||||
// IsDefaultAnnotation returns a boolean if
|
||||
// the annotation is set
|
||||
// TODO: remove Beta when no longer needed
|
||||
func IsDefaultAnnotation(obj api.ObjectMeta) bool {
|
||||
if obj.Annotations[IsDefaultStorageClassAnnotation] == "true" {
|
||||
return true
|
||||
}
|
||||
if obj.Annotations[BetaIsDefaultStorageClassAnnotation] == "true" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
@ -21,6 +21,7 @@ import (
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
)
|
||||
|
||||
// Test single call to syncClaim and syncVolume methods.
|
||||
@ -430,14 +431,14 @@ func TestSync(t *testing.T) {
|
||||
"13-1 - binding to class",
|
||||
[]*api.PersistentVolume{
|
||||
newVolume("volume13-1-1", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain),
|
||||
newVolume("volume13-1-2", "10Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, annClass),
|
||||
newVolume("volume13-1-2", "10Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, storageutil.StorageClassAnnotation),
|
||||
},
|
||||
[]*api.PersistentVolume{
|
||||
newVolume("volume13-1-1", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain),
|
||||
newVolume("volume13-1-2", "10Gi", "uid13-1", "claim13-1", api.VolumeBound, api.PersistentVolumeReclaimRetain, annBoundByController, annClass),
|
||||
newVolume("volume13-1-2", "10Gi", "uid13-1", "claim13-1", api.VolumeBound, api.PersistentVolumeReclaimRetain, annBoundByController, storageutil.StorageClassAnnotation),
|
||||
},
|
||||
newClaimArray("claim13-1", "uid13-1", "1Gi", "", api.ClaimPending, annClass),
|
||||
withExpectedCapacity("10Gi", newClaimArray("claim13-1", "uid13-1", "1Gi", "volume13-1-2", api.ClaimBound, annBoundByController, annClass, annBindCompleted)),
|
||||
newClaimArray("claim13-1", "uid13-1", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
withExpectedCapacity("10Gi", newClaimArray("claim13-1", "uid13-1", "1Gi", "volume13-1-2", api.ClaimBound, annBoundByController, storageutil.StorageClassAnnotation, annBindCompleted)),
|
||||
noevents, noerrors, testSyncClaim,
|
||||
},
|
||||
{
|
||||
@ -445,11 +446,11 @@ func TestSync(t *testing.T) {
|
||||
// smaller PV with a class available
|
||||
"13-2 - binding without a class",
|
||||
[]*api.PersistentVolume{
|
||||
newVolume("volume13-2-1", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, annClass),
|
||||
newVolume("volume13-2-1", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, storageutil.StorageClassAnnotation),
|
||||
newVolume("volume13-2-2", "10Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain),
|
||||
},
|
||||
[]*api.PersistentVolume{
|
||||
newVolume("volume13-2-1", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, annClass),
|
||||
newVolume("volume13-2-1", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, storageutil.StorageClassAnnotation),
|
||||
newVolume("volume13-2-2", "10Gi", "uid13-2", "claim13-2", api.VolumeBound, api.PersistentVolumeReclaimRetain, annBoundByController),
|
||||
},
|
||||
newClaimArray("claim13-2", "uid13-2", "1Gi", "", api.ClaimPending),
|
||||
@ -462,14 +463,14 @@ func TestSync(t *testing.T) {
|
||||
"13-3 - binding to specific a class",
|
||||
volumeWithClass("silver", []*api.PersistentVolume{
|
||||
newVolume("volume13-3-1", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain),
|
||||
newVolume("volume13-3-2", "10Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, annClass),
|
||||
newVolume("volume13-3-2", "10Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, storageutil.StorageClassAnnotation),
|
||||
}),
|
||||
volumeWithClass("silver", []*api.PersistentVolume{
|
||||
newVolume("volume13-3-1", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain),
|
||||
newVolume("volume13-3-2", "10Gi", "uid13-3", "claim13-3", api.VolumeBound, api.PersistentVolumeReclaimRetain, annBoundByController, annClass),
|
||||
newVolume("volume13-3-2", "10Gi", "uid13-3", "claim13-3", api.VolumeBound, api.PersistentVolumeReclaimRetain, annBoundByController, storageutil.StorageClassAnnotation),
|
||||
}),
|
||||
newClaimArray("claim13-3", "uid13-3", "1Gi", "", api.ClaimPending, annClass),
|
||||
withExpectedCapacity("10Gi", newClaimArray("claim13-3", "uid13-3", "1Gi", "volume13-3-2", api.ClaimBound, annBoundByController, annBindCompleted, annClass)),
|
||||
newClaimArray("claim13-3", "uid13-3", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
withExpectedCapacity("10Gi", newClaimArray("claim13-3", "uid13-3", "1Gi", "volume13-3-2", api.ClaimBound, annBoundByController, annBindCompleted, storageutil.StorageClassAnnotation)),
|
||||
noevents, noerrors, testSyncClaim,
|
||||
},
|
||||
{
|
||||
|
@ -34,6 +34,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
@ -650,7 +651,7 @@ func newVolume(name, capacity, boundToClaimUID, boundToClaimName string, phase a
|
||||
switch a {
|
||||
case annDynamicallyProvisioned:
|
||||
volume.Annotations[a] = mockPluginName
|
||||
case annClass:
|
||||
case storageutil.StorageClassAnnotation:
|
||||
volume.Annotations[a] = "gold"
|
||||
default:
|
||||
volume.Annotations[a] = "yes"
|
||||
@ -699,13 +700,13 @@ func withMessage(message string, volumes []*api.PersistentVolume) []*api.Persist
|
||||
return volumes
|
||||
}
|
||||
|
||||
// volumeWithClass saves given class into annClass annotation.
|
||||
// volumeWithClass saves given class into storage.StorageClassAnnotation annotation.
|
||||
// Meant to be used to compose claims specified inline in a test.
|
||||
func volumeWithClass(className string, volumes []*api.PersistentVolume) []*api.PersistentVolume {
|
||||
if volumes[0].Annotations == nil {
|
||||
volumes[0].Annotations = map[string]string{annClass: className}
|
||||
volumes[0].Annotations = map[string]string{storageutil.StorageClassAnnotation: className}
|
||||
} else {
|
||||
volumes[0].Annotations[annClass] = className
|
||||
volumes[0].Annotations[storageutil.StorageClassAnnotation] = className
|
||||
}
|
||||
return volumes
|
||||
}
|
||||
@ -747,7 +748,7 @@ func newClaim(name, claimUID, capacity, boundToVolume string, phase api.Persiste
|
||||
claim.Annotations = make(map[string]string)
|
||||
for _, a := range annotations {
|
||||
switch a {
|
||||
case annClass:
|
||||
case storageutil.StorageClassAnnotation:
|
||||
claim.Annotations[a] = "gold"
|
||||
default:
|
||||
claim.Annotations[a] = "yes"
|
||||
@ -774,13 +775,13 @@ func newClaimArray(name, claimUID, capacity, boundToVolume string, phase api.Per
|
||||
}
|
||||
}
|
||||
|
||||
// claimWithClass saves given class into annClass annotation.
|
||||
// claimWithClass saves given class into storage.StorageClassAnnotation annotation.
|
||||
// Meant to be used to compose claims specified inline in a test.
|
||||
func claimWithClass(className string, claims []*api.PersistentVolumeClaim) []*api.PersistentVolumeClaim {
|
||||
if claims[0].Annotations == nil {
|
||||
claims[0].Annotations = map[string]string{annClass: className}
|
||||
claims[0].Annotations = map[string]string{storageutil.StorageClassAnnotation: className}
|
||||
} else {
|
||||
claims[0].Annotations[annClass] = className
|
||||
claims[0].Annotations[storageutil.StorageClassAnnotation] = className
|
||||
}
|
||||
return claims
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
)
|
||||
@ -92,7 +93,7 @@ func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *api.PersistentVo
|
||||
var smallestVolumeSize int64
|
||||
requestedQty := claim.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
|
||||
requestedSize := requestedQty.Value()
|
||||
requestedClass := getClaimClass(claim)
|
||||
requestedClass := storageutil.GetClaimStorageClass(claim)
|
||||
|
||||
var selector labels.Selector
|
||||
if claim.Spec.Selector != nil {
|
||||
@ -133,7 +134,7 @@ func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *api.PersistentVo
|
||||
// with existing PVs, findByClaim must find only PVs that are
|
||||
// pre-bound to the claim (by dynamic provisioning). TODO: remove in
|
||||
// 1.5
|
||||
if hasAnnotation(claim.ObjectMeta, annAlphaClass) {
|
||||
if api.HasAnnotation(claim.ObjectMeta, storageutil.AlphaStorageClassAnnotation) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -146,7 +147,7 @@ func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *api.PersistentVo
|
||||
} else if selector != nil && !selector.Matches(labels.Set(volume.Labels)) {
|
||||
continue
|
||||
}
|
||||
if getVolumeClass(volume) != requestedClass {
|
||||
if storageutil.GetVolumeStorageClass(volume) != requestedClass {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
)
|
||||
|
||||
func TestMatchVolume(t *testing.T) {
|
||||
@ -177,7 +178,7 @@ func TestMatchVolume(t *testing.T) {
|
||||
Name: "claim01",
|
||||
Namespace: "myns",
|
||||
Annotations: map[string]string{
|
||||
annClass: "silver",
|
||||
storageutil.StorageClassAnnotation: "silver",
|
||||
},
|
||||
},
|
||||
Spec: api.PersistentVolumeClaimSpec{
|
||||
@ -202,7 +203,7 @@ func TestMatchVolume(t *testing.T) {
|
||||
Name: "claim01",
|
||||
Namespace: "myns",
|
||||
Annotations: map[string]string{
|
||||
annClass: "silver",
|
||||
storageutil.StorageClassAnnotation: "silver",
|
||||
},
|
||||
},
|
||||
Spec: api.PersistentVolumeClaimSpec{
|
||||
@ -626,7 +627,7 @@ func createTestVolumes() []*api.PersistentVolume {
|
||||
"should-exist": "true",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
annClass: "silver",
|
||||
storageutil.StorageClassAnnotation: "silver",
|
||||
},
|
||||
},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
@ -646,7 +647,7 @@ func createTestVolumes() []*api.PersistentVolume {
|
||||
UID: "gce-pd-silver2",
|
||||
Name: "gce0024",
|
||||
Annotations: map[string]string{
|
||||
annClass: "silver",
|
||||
storageutil.StorageClassAnnotation: "silver",
|
||||
},
|
||||
},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
@ -666,7 +667,7 @@ func createTestVolumes() []*api.PersistentVolume {
|
||||
UID: "gce-pd-gold",
|
||||
Name: "gce0025",
|
||||
Annotations: map[string]string{
|
||||
annClass: "gold",
|
||||
storageutil.StorageClassAnnotation: "gold",
|
||||
},
|
||||
},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
)
|
||||
|
||||
var class1Parameters = map[string]string{
|
||||
@ -108,10 +109,10 @@ func TestProvisionSync(t *testing.T) {
|
||||
// Provision a volume (with a default class)
|
||||
"11-1 - successful provision with storage class 1",
|
||||
novolumes,
|
||||
newVolumeArray("pvc-uid11-1", "1Gi", "uid11-1", "claim11-1", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, annClass),
|
||||
newClaimArray("claim11-1", "uid11-1", "1Gi", "", api.ClaimPending, annClass),
|
||||
newVolumeArray("pvc-uid11-1", "1Gi", "uid11-1", "claim11-1", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-1", "uid11-1", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
// Binding will be completed in the next syncClaim
|
||||
newClaimArray("claim11-1", "uid11-1", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-1", "uid11-1", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
noevents, noerrors, wrapTestWithProvisionCalls([]provisionCall{provision1Success}, testSyncClaim),
|
||||
},
|
||||
{
|
||||
@ -119,8 +120,8 @@ func TestProvisionSync(t *testing.T) {
|
||||
"11-2 - plugin not found",
|
||||
novolumes,
|
||||
novolumes,
|
||||
newClaimArray("claim11-2", "uid11-2", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-2", "uid11-2", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-2", "uid11-2", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-2", "uid11-2", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
[]string{"Warning ProvisioningFailed"}, noerrors,
|
||||
testSyncClaim,
|
||||
},
|
||||
@ -129,8 +130,8 @@ func TestProvisionSync(t *testing.T) {
|
||||
"11-3 - newProvisioner failure",
|
||||
novolumes,
|
||||
novolumes,
|
||||
newClaimArray("claim11-3", "uid11-3", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-3", "uid11-3", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-3", "uid11-3", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-3", "uid11-3", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
[]string{"Warning ProvisioningFailed"}, noerrors,
|
||||
wrapTestWithProvisionCalls([]provisionCall{}, testSyncClaim),
|
||||
},
|
||||
@ -139,18 +140,18 @@ func TestProvisionSync(t *testing.T) {
|
||||
"11-4 - provision failure",
|
||||
novolumes,
|
||||
novolumes,
|
||||
newClaimArray("claim11-4", "uid11-4", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-4", "uid11-4", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-4", "uid11-4", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-4", "uid11-4", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
[]string{"Warning ProvisioningFailed"}, noerrors,
|
||||
wrapTestWithProvisionCalls([]provisionCall{provision1Error}, testSyncClaim),
|
||||
},
|
||||
{
|
||||
// No provisioning if there is a matching volume available
|
||||
"11-6 - provisioning when there is a volume available",
|
||||
newVolumeArray("volume11-6", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, annClass),
|
||||
newVolumeArray("volume11-6", "1Gi", "uid11-6", "claim11-6", api.VolumeBound, api.PersistentVolumeReclaimRetain, annBoundByController, annClass),
|
||||
newClaimArray("claim11-6", "uid11-6", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-6", "uid11-6", "1Gi", "volume11-6", api.ClaimBound, annClass, annBoundByController, annBindCompleted),
|
||||
newVolumeArray("volume11-6", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain, storageutil.StorageClassAnnotation),
|
||||
newVolumeArray("volume11-6", "1Gi", "uid11-6", "claim11-6", api.VolumeBound, api.PersistentVolumeReclaimRetain, annBoundByController, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-6", "uid11-6", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-6", "uid11-6", "1Gi", "volume11-6", api.ClaimBound, storageutil.StorageClassAnnotation, annBoundByController, annBindCompleted),
|
||||
noevents, noerrors,
|
||||
// No provisioning plugin confingure - makes the test fail when
|
||||
// the controller errorneously tries to provision something
|
||||
@ -161,16 +162,16 @@ func TestProvisionSync(t *testing.T) {
|
||||
// a volume.
|
||||
"11-7 - claim is bound before provisioning",
|
||||
novolumes,
|
||||
newVolumeArray("pvc-uid11-7", "1Gi", "uid11-7", "claim11-7", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, annClass),
|
||||
newClaimArray("claim11-7", "uid11-7", "1Gi", "", api.ClaimPending, annClass),
|
||||
newVolumeArray("pvc-uid11-7", "1Gi", "uid11-7", "claim11-7", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-7", "uid11-7", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
// The claim would be bound in next syncClaim
|
||||
newClaimArray("claim11-7", "uid11-7", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-7", "uid11-7", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
noevents, noerrors,
|
||||
wrapTestWithInjectedOperation(wrapTestWithProvisionCalls([]provisionCall{}, testSyncClaim), func(ctrl *PersistentVolumeController, reactor *volumeReactor) {
|
||||
// Create a volume before provisionClaimOperation starts.
|
||||
// This similates a parallel controller provisioning the volume.
|
||||
reactor.lock.Lock()
|
||||
volume := newVolume("pvc-uid11-7", "1Gi", "uid11-7", "claim11-7", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, annClass)
|
||||
volume := newVolume("pvc-uid11-7", "1Gi", "uid11-7", "claim11-7", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, storageutil.StorageClassAnnotation)
|
||||
reactor.volumes[volume.Name] = volume
|
||||
reactor.lock.Unlock()
|
||||
}),
|
||||
@ -180,10 +181,10 @@ func TestProvisionSync(t *testing.T) {
|
||||
// second retry succeeds
|
||||
"11-8 - cannot save provisioned volume",
|
||||
novolumes,
|
||||
newVolumeArray("pvc-uid11-8", "1Gi", "uid11-8", "claim11-8", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, annClass),
|
||||
newClaimArray("claim11-8", "uid11-8", "1Gi", "", api.ClaimPending, annClass),
|
||||
newVolumeArray("pvc-uid11-8", "1Gi", "uid11-8", "claim11-8", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-8", "uid11-8", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
// Binding will be completed in the next syncClaim
|
||||
newClaimArray("claim11-8", "uid11-8", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-8", "uid11-8", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
noevents,
|
||||
[]reactorError{
|
||||
// Inject error to the first
|
||||
@ -199,8 +200,8 @@ func TestProvisionSync(t *testing.T) {
|
||||
"11-9 - cannot save provisioned volume, delete succeeds",
|
||||
novolumes,
|
||||
novolumes,
|
||||
newClaimArray("claim11-9", "uid11-9", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-9", "uid11-9", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-9", "uid11-9", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-9", "uid11-9", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
[]string{"Warning ProvisioningFailed"},
|
||||
[]reactorError{
|
||||
// Inject error to five kubeclient.PersistentVolumes.Create()
|
||||
@ -224,8 +225,8 @@ func TestProvisionSync(t *testing.T) {
|
||||
"11-10 - cannot save provisioned volume, no delete plugin found",
|
||||
novolumes,
|
||||
novolumes,
|
||||
newClaimArray("claim11-10", "uid11-10", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-10", "uid11-10", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-10", "uid11-10", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-10", "uid11-10", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
[]string{"Warning ProvisioningFailed", "Warning ProvisioningCleanupFailed"},
|
||||
[]reactorError{
|
||||
// Inject error to five kubeclient.PersistentVolumes.Create()
|
||||
@ -245,8 +246,8 @@ func TestProvisionSync(t *testing.T) {
|
||||
"11-11 - cannot save provisioned volume, deleter fails",
|
||||
novolumes,
|
||||
novolumes,
|
||||
newClaimArray("claim11-11", "uid11-11", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-11", "uid11-11", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-11", "uid11-11", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-11", "uid11-11", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
[]string{"Warning ProvisioningFailed", "Warning ProvisioningCleanupFailed"},
|
||||
[]reactorError{
|
||||
// Inject error to five kubeclient.PersistentVolumes.Create()
|
||||
@ -275,8 +276,8 @@ func TestProvisionSync(t *testing.T) {
|
||||
"11-12 - cannot save provisioned volume, delete succeeds 2nd time",
|
||||
novolumes,
|
||||
novolumes,
|
||||
newClaimArray("claim11-12", "uid11-12", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-12", "uid11-12", "1Gi", "", api.ClaimPending, annClass),
|
||||
newClaimArray("claim11-12", "uid11-12", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim11-12", "uid11-12", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
[]string{"Warning ProvisioningFailed"},
|
||||
[]reactorError{
|
||||
// Inject error to five kubeclient.PersistentVolumes.Create()
|
||||
@ -365,9 +366,9 @@ func TestAlphaProvisionSync(t *testing.T) {
|
||||
"14-1 - successful alpha provisioning",
|
||||
novolumes,
|
||||
newVolumeArray("pvc-uid14-1", "1Gi", "uid14-1", "claim14-1", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned),
|
||||
newClaimArray("claim14-1", "uid14-1", "1Gi", "", api.ClaimPending, annAlphaClass),
|
||||
newClaimArray("claim14-1", "uid14-1", "1Gi", "", api.ClaimPending, storageutil.AlphaStorageClassAnnotation),
|
||||
// Binding will be completed in the next syncClaim
|
||||
newClaimArray("claim14-1", "uid14-1", "1Gi", "", api.ClaimPending, annAlphaClass),
|
||||
newClaimArray("claim14-1", "uid14-1", "1Gi", "", api.ClaimPending, storageutil.AlphaStorageClassAnnotation),
|
||||
noevents, noerrors, wrapTestWithProvisionCalls([]provisionCall{provisionAlphaSuccess}, testSyncClaim),
|
||||
},
|
||||
{
|
||||
@ -379,9 +380,9 @@ func TestAlphaProvisionSync(t *testing.T) {
|
||||
newVolume("volume14-2", "1Gi", "", "", api.VolumePending, api.PersistentVolumeReclaimRetain),
|
||||
newVolume("pvc-uid14-2", "1Gi", "uid14-2", "claim14-2", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned),
|
||||
},
|
||||
newClaimArray("claim14-2", "uid14-2", "1Gi", "", api.ClaimPending, annAlphaClass),
|
||||
newClaimArray("claim14-2", "uid14-2", "1Gi", "", api.ClaimPending, storageutil.AlphaStorageClassAnnotation),
|
||||
// Binding will be completed in the next syncClaim
|
||||
newClaimArray("claim14-2", "uid14-2", "1Gi", "", api.ClaimPending, annAlphaClass),
|
||||
newClaimArray("claim14-2", "uid14-2", "1Gi", "", api.ClaimPending, storageutil.AlphaStorageClassAnnotation),
|
||||
noevents, noerrors, wrapTestWithProvisionCalls([]provisionCall{provisionAlphaSuccess}, testSyncClaim),
|
||||
},
|
||||
}
|
||||
@ -408,10 +409,10 @@ func TestProvisionMultiSync(t *testing.T) {
|
||||
// Provision a volume with binding
|
||||
"12-1 - successful provision",
|
||||
novolumes,
|
||||
newVolumeArray("pvc-uid12-1", "1Gi", "uid12-1", "claim12-1", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, annClass),
|
||||
newClaimArray("claim12-1", "uid12-1", "1Gi", "", api.ClaimPending, annClass),
|
||||
newVolumeArray("pvc-uid12-1", "1Gi", "uid12-1", "claim12-1", api.VolumeBound, api.PersistentVolumeReclaimDelete, annBoundByController, annDynamicallyProvisioned, storageutil.StorageClassAnnotation),
|
||||
newClaimArray("claim12-1", "uid12-1", "1Gi", "", api.ClaimPending, storageutil.StorageClassAnnotation),
|
||||
// Binding will be completed in the next syncClaim
|
||||
newClaimArray("claim12-1", "uid12-1", "1Gi", "pvc-uid12-1", api.ClaimBound, annClass, annBoundByController, annBindCompleted),
|
||||
newClaimArray("claim12-1", "uid12-1", "1Gi", "pvc-uid12-1", api.ClaimBound, storageutil.StorageClassAnnotation, annBoundByController, annBindCompleted),
|
||||
noevents, noerrors, wrapTestWithProvisionCalls([]provisionCall{provision1Success}, testSyncClaim),
|
||||
},
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/record"
|
||||
@ -110,20 +111,6 @@ const annBindCompleted = "pv.kubernetes.io/bind-completed"
|
||||
// pre-bound). Value of this annotation does not matter.
|
||||
const annBoundByController = "pv.kubernetes.io/bound-by-controller"
|
||||
|
||||
// annClass annotation represents the storage class associated with a resource:
|
||||
// - in PersistentVolumeClaim it represents required class to match.
|
||||
// Only PersistentVolumes with the same class (i.e. annotation with the same
|
||||
// value) can be bound to the claim. In case no such volume exists, the
|
||||
// controller will provision a new one using StorageClass instance with
|
||||
// the same name as the annotation value.
|
||||
// - in PersistentVolume it represents storage class to which the persistent
|
||||
// volume belongs.
|
||||
const annClass = "volume.beta.kubernetes.io/storage-class"
|
||||
|
||||
// alphaAnnClass annotation represents the previous alpha storage class
|
||||
// annotation. it's no longer used and held here for posterity.
|
||||
const annAlphaClass = "volume.alpha.kubernetes.io/storage-class"
|
||||
|
||||
// This annotation is added to a PV that has been dynamically provisioned by
|
||||
// Kubernetes. Its value is name of volume plugin that created the volume.
|
||||
// It serves both user (to show where a PV comes from) and Kubernetes (to
|
||||
@ -199,7 +186,7 @@ type PersistentVolumeController struct {
|
||||
func (ctrl *PersistentVolumeController) syncClaim(claim *api.PersistentVolumeClaim) error {
|
||||
glog.V(4).Infof("synchronizing PersistentVolumeClaim[%s]: %s", claimToClaimKey(claim), getClaimStatusForLogging(claim))
|
||||
|
||||
if !hasAnnotation(claim.ObjectMeta, annBindCompleted) {
|
||||
if !api.HasAnnotation(claim.ObjectMeta, annBindCompleted) {
|
||||
return ctrl.syncUnboundClaim(claim)
|
||||
} else {
|
||||
return ctrl.syncBoundClaim(claim)
|
||||
@ -224,8 +211,7 @@ func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *api.PersistentVo
|
||||
glog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: no volume found", claimToClaimKey(claim))
|
||||
// No PV could be found
|
||||
// OBSERVATION: pvc is "Pending", will retry
|
||||
// TODO: remove Alpha check in 1.5
|
||||
if getClaimClass(claim) != "" || hasAnnotation(claim.ObjectMeta, annAlphaClass) {
|
||||
if storageutil.GetClaimStorageClass(claim) != "" || api.HasAnnotation(claim.ObjectMeta, storageutil.AlphaStorageClassAnnotation) {
|
||||
if err = ctrl.provisionClaim(claim); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -297,7 +283,7 @@ func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *api.PersistentVo
|
||||
} else {
|
||||
// User asked for a PV that is claimed by someone else
|
||||
// OBSERVATION: pvc is "Pending", pv is "Bound"
|
||||
if !hasAnnotation(claim.ObjectMeta, annBoundByController) {
|
||||
if !api.HasAnnotation(claim.ObjectMeta, annBoundByController) {
|
||||
glog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume already bound to different claim by user, will retry later", claimToClaimKey(claim))
|
||||
// User asked for a specific PV, retry later
|
||||
if _, err = ctrl.updateClaimStatus(claim, api.ClaimPending, nil); err != nil {
|
||||
@ -318,7 +304,7 @@ func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *api.PersistentVo
|
||||
// syncBoundClaim is the main controller method to decide what to do with a
|
||||
// bound claim.
|
||||
func (ctrl *PersistentVolumeController) syncBoundClaim(claim *api.PersistentVolumeClaim) error {
|
||||
// hasAnnotation(pvc, annBindCompleted)
|
||||
// HasAnnotation(pvc, annBindCompleted)
|
||||
// This PVC has previously been bound
|
||||
// OBSERVATION: pvc is not "Pending"
|
||||
// [Unit test set 3]
|
||||
@ -462,7 +448,7 @@ func (ctrl *PersistentVolumeController) syncVolume(volume *api.PersistentVolume)
|
||||
}
|
||||
return nil
|
||||
} else if claim.Spec.VolumeName == "" {
|
||||
if hasAnnotation(volume.ObjectMeta, annBoundByController) {
|
||||
if api.HasAnnotation(volume.ObjectMeta, annBoundByController) {
|
||||
// The binding is not completed; let PVC sync handle it
|
||||
glog.V(4).Infof("synchronizing PersistentVolume[%s]: volume not bound yet, waiting for syncClaim to fix it", volume.Name)
|
||||
} else {
|
||||
@ -497,7 +483,7 @@ func (ctrl *PersistentVolumeController) syncVolume(volume *api.PersistentVolume)
|
||||
return nil
|
||||
} else {
|
||||
// Volume is bound to a claim, but the claim is bound elsewhere
|
||||
if hasAnnotation(volume.ObjectMeta, annDynamicallyProvisioned) && volume.Spec.PersistentVolumeReclaimPolicy == api.PersistentVolumeReclaimDelete {
|
||||
if api.HasAnnotation(volume.ObjectMeta, annDynamicallyProvisioned) && volume.Spec.PersistentVolumeReclaimPolicy == api.PersistentVolumeReclaimDelete {
|
||||
// This volume was dynamically provisioned for this claim. The
|
||||
// claim got bound elsewhere, and thus this volume is not
|
||||
// needed. Delete it.
|
||||
@ -510,7 +496,7 @@ func (ctrl *PersistentVolumeController) syncVolume(volume *api.PersistentVolume)
|
||||
} else {
|
||||
// Volume is bound to a claim, but the claim is bound elsewhere
|
||||
// and it's not dynamically provisioned.
|
||||
if hasAnnotation(volume.ObjectMeta, annBoundByController) {
|
||||
if api.HasAnnotation(volume.ObjectMeta, annBoundByController) {
|
||||
// This is part of the normal operation of the controller; the
|
||||
// controller tried to use this volume for a claim but the claim
|
||||
// was fulfilled by another volume. We did this; fix it.
|
||||
@ -734,8 +720,8 @@ func (ctrl *PersistentVolumeController) bindVolumeToClaim(volume *api.Persistent
|
||||
}
|
||||
|
||||
// Set annBoundByController if it is not set yet
|
||||
if shouldSetBoundByController && !hasAnnotation(volumeClone.ObjectMeta, annBoundByController) {
|
||||
setAnnotation(&volumeClone.ObjectMeta, annBoundByController, "yes")
|
||||
if shouldSetBoundByController && !api.HasAnnotation(volumeClone.ObjectMeta, annBoundByController) {
|
||||
api.SetMetaDataAnnotation(&volumeClone.ObjectMeta, annBoundByController, "yes")
|
||||
dirty = true
|
||||
}
|
||||
|
||||
@ -791,14 +777,14 @@ func (ctrl *PersistentVolumeController) bindClaimToVolume(claim *api.PersistentV
|
||||
}
|
||||
|
||||
// Set annBoundByController if it is not set yet
|
||||
if shouldSetBoundByController && !hasAnnotation(claimClone.ObjectMeta, annBoundByController) {
|
||||
setAnnotation(&claimClone.ObjectMeta, annBoundByController, "yes")
|
||||
if shouldSetBoundByController && !api.HasAnnotation(claimClone.ObjectMeta, annBoundByController) {
|
||||
api.SetMetaDataAnnotation(&claimClone.ObjectMeta, annBoundByController, "yes")
|
||||
dirty = true
|
||||
}
|
||||
|
||||
// Set annBindCompleted if it is not set yet
|
||||
if !hasAnnotation(claimClone.ObjectMeta, annBindCompleted) {
|
||||
setAnnotation(&claimClone.ObjectMeta, annBindCompleted, "yes")
|
||||
if !api.HasAnnotation(claimClone.ObjectMeta, annBindCompleted) {
|
||||
api.SetMetaDataAnnotation(&claimClone.ObjectMeta, annBindCompleted, "yes")
|
||||
dirty = true
|
||||
}
|
||||
|
||||
@ -884,7 +870,7 @@ func (ctrl *PersistentVolumeController) unbindVolume(volume *api.PersistentVolum
|
||||
return fmt.Errorf("Unexpected volume cast error : %v", volumeClone)
|
||||
}
|
||||
|
||||
if hasAnnotation(volume.ObjectMeta, annBoundByController) {
|
||||
if api.HasAnnotation(volume.ObjectMeta, annBoundByController) {
|
||||
// The volume was bound by the controller.
|
||||
volumeClone.Spec.ClaimRef = nil
|
||||
delete(volumeClone.Annotations, annBoundByController)
|
||||
@ -1208,7 +1194,7 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(claimObj interfa
|
||||
return
|
||||
}
|
||||
|
||||
claimClass := getClaimClass(claim)
|
||||
claimClass := storageutil.GetClaimStorageClass(claim)
|
||||
glog.V(4).Infof("provisionClaimOperation [%s] started, class: %q", claimToClaimKey(claim), claimClass)
|
||||
|
||||
// A previous doProvisionClaim may just have finished while we were waiting for
|
||||
@ -1294,13 +1280,13 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(claimObj interfa
|
||||
volume.Status.Phase = api.VolumeBound
|
||||
|
||||
// Add annBoundByController (used in deleting the volume)
|
||||
setAnnotation(&volume.ObjectMeta, annBoundByController, "yes")
|
||||
setAnnotation(&volume.ObjectMeta, annDynamicallyProvisioned, plugin.GetPluginName())
|
||||
// For Alpha provisioning behavior, do not add annClass for volumes created
|
||||
// by annAlphaClass
|
||||
// TODO: remove this check in 1.5, annClass will be always non-empty there.
|
||||
api.SetMetaDataAnnotation(&volume.ObjectMeta, annBoundByController, "yes")
|
||||
api.SetMetaDataAnnotation(&volume.ObjectMeta, annDynamicallyProvisioned, plugin.GetPluginName())
|
||||
// For Alpha provisioning behavior, do not add storage.BetaStorageClassAnnotations for volumes created
|
||||
// by storage.AlphaStorageClassAnnotation
|
||||
// TODO: remove this check in 1.5, storage.StorageClassAnnotation will be always non-empty there.
|
||||
if claimClass != "" {
|
||||
setAnnotation(&volume.ObjectMeta, annClass, claimClass)
|
||||
api.SetMetaDataAnnotation(&volume.ObjectMeta, storageutil.StorageClassAnnotation, claimClass)
|
||||
}
|
||||
|
||||
// Try to create the PV object several times
|
||||
@ -1402,12 +1388,12 @@ func (ctrl *PersistentVolumeController) newRecyclerEventRecorder(volume *api.Per
|
||||
// provisioner is requested.
|
||||
func (ctrl *PersistentVolumeController) findProvisionablePlugin(claim *api.PersistentVolumeClaim) (vol.ProvisionableVolumePlugin, *storage.StorageClass, error) {
|
||||
// TODO: remove this alpha behavior in 1.5
|
||||
alpha := hasAnnotation(claim.ObjectMeta, annAlphaClass)
|
||||
beta := hasAnnotation(claim.ObjectMeta, annClass)
|
||||
alpha := api.HasAnnotation(claim.ObjectMeta, storageutil.AlphaStorageClassAnnotation)
|
||||
beta := api.HasAnnotation(claim.ObjectMeta, storageutil.BetaStorageClassAnnotation)
|
||||
if alpha && beta {
|
||||
// Both Alpha and Beta annotations are set. Do beta.
|
||||
alpha = false
|
||||
msg := fmt.Sprintf("both %q and %q annotations are present, using %q", annAlphaClass, annClass, annClass)
|
||||
msg := fmt.Sprintf("both %q and %q annotations are present, using %q", storageutil.AlphaStorageClassAnnotation, storageutil.BetaStorageClassAnnotation, storageutil.BetaStorageClassAnnotation)
|
||||
ctrl.eventRecorder.Event(claim, api.EventTypeNormal, "ProvisioningIgnoreAlpha", msg)
|
||||
}
|
||||
if alpha {
|
||||
@ -1417,7 +1403,7 @@ func (ctrl *PersistentVolumeController) findProvisionablePlugin(claim *api.Persi
|
||||
|
||||
// provisionClaim() which leads here is never called with claimClass=="", we
|
||||
// can save some checks.
|
||||
claimClass := getClaimClass(claim)
|
||||
claimClass := storageutil.GetClaimStorageClass(claim)
|
||||
classObj, found, err := ctrl.classes.GetByKey(claimClass)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@ -1469,7 +1455,7 @@ func (ctrl *PersistentVolumeController) findAlphaProvisionablePlugin() (vol.Prov
|
||||
func (ctrl *PersistentVolumeController) findDeletablePlugin(volume *api.PersistentVolume) (vol.DeletableVolumePlugin, error) {
|
||||
// Find a plugin. Try to find the same plugin that provisioned the volume
|
||||
var plugin vol.DeletableVolumePlugin
|
||||
if hasAnnotation(volume.ObjectMeta, annDynamicallyProvisioned) {
|
||||
if api.HasAnnotation(volume.ObjectMeta, annDynamicallyProvisioned) {
|
||||
provisionPluginName := volume.Annotations[annDynamicallyProvisioned]
|
||||
if provisionPluginName != "" {
|
||||
plugin, err := ctrl.volumePluginMgr.FindDeletablePluginByName(provisionPluginName)
|
||||
|
@ -496,27 +496,15 @@ func (ctrl *PersistentVolumeController) upgradeVolumeFrom1_2(volume *api.Persist
|
||||
|
||||
// Stateless functions
|
||||
|
||||
func hasAnnotation(obj api.ObjectMeta, ann string) bool {
|
||||
_, found := obj.Annotations[ann]
|
||||
return found
|
||||
}
|
||||
|
||||
func setAnnotation(obj *api.ObjectMeta, ann string, value string) {
|
||||
if obj.Annotations == nil {
|
||||
obj.Annotations = make(map[string]string)
|
||||
}
|
||||
obj.Annotations[ann] = value
|
||||
}
|
||||
|
||||
func getClaimStatusForLogging(claim *api.PersistentVolumeClaim) string {
|
||||
bound := hasAnnotation(claim.ObjectMeta, annBindCompleted)
|
||||
boundByController := hasAnnotation(claim.ObjectMeta, annBoundByController)
|
||||
bound := api.HasAnnotation(claim.ObjectMeta, annBindCompleted)
|
||||
boundByController := api.HasAnnotation(claim.ObjectMeta, annBoundByController)
|
||||
|
||||
return fmt.Sprintf("phase: %s, bound to: %q, bindCompleted: %v, boundByController: %v", claim.Status.Phase, claim.Spec.VolumeName, bound, boundByController)
|
||||
}
|
||||
|
||||
func getVolumeStatusForLogging(volume *api.PersistentVolume) string {
|
||||
boundByController := hasAnnotation(volume.ObjectMeta, annBoundByController)
|
||||
boundByController := api.HasAnnotation(volume.ObjectMeta, annBoundByController)
|
||||
claimName := ""
|
||||
if volume.Spec.ClaimRef != nil {
|
||||
claimName = fmt.Sprintf("%s/%s (uid: %s)", volume.Spec.ClaimRef.Namespace, volume.Spec.ClaimRef.Name, volume.Spec.ClaimRef.UID)
|
||||
@ -592,29 +580,3 @@ func storeObjectUpdate(store cache.Store, obj interface{}, className string) (bo
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// getVolumeClass returns value of annClass annotation or empty string in case
|
||||
// the annotation does not exist.
|
||||
// TODO: change to PersistentVolume.Spec.Class value when this attribute is
|
||||
// introduced.
|
||||
func getVolumeClass(volume *api.PersistentVolume) string {
|
||||
if class, found := volume.Annotations[annClass]; found {
|
||||
return class
|
||||
}
|
||||
|
||||
// 'nil' is interpreted as "", i.e. the volume does not belong to any class.
|
||||
return ""
|
||||
}
|
||||
|
||||
// getClaimClass returns name of class that is requested by given claim.
|
||||
// Request for `nil` class is interpreted as request for class "",
|
||||
// i.e. for a classless PV.
|
||||
func getClaimClass(claim *api.PersistentVolumeClaim) string {
|
||||
// TODO: change to PersistentVolumeClaim.Spec.Class value when this
|
||||
// attribute is introduced.
|
||||
if class, found := claim.Annotations[annClass]; found {
|
||||
return class
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
|
||||
@ -734,6 +735,7 @@ func (d *PersistentVolumeDescriber) Describe(namespace, name string, describerSe
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
fmt.Fprintf(out, "Name:\t%s\n", pv.Name)
|
||||
printLabelsMultiline(out, "Labels", pv.Labels)
|
||||
fmt.Fprintf(out, "StorageClass:\t%s\n", storageutil.GetStorageClassAnnotation(pv.ObjectMeta))
|
||||
fmt.Fprintf(out, "Status:\t%s\n", pv.Status.Phase)
|
||||
if pv.Spec.ClaimRef != nil {
|
||||
fmt.Fprintf(out, "Claim:\t%s\n", pv.Spec.ClaimRef.Namespace+"/"+pv.Spec.ClaimRef.Name)
|
||||
@ -803,6 +805,7 @@ func (d *PersistentVolumeClaimDescriber) Describe(namespace, name string, descri
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
fmt.Fprintf(out, "Name:\t%s\n", pvc.Name)
|
||||
fmt.Fprintf(out, "Namespace:\t%s\n", pvc.Namespace)
|
||||
fmt.Fprintf(out, "StorageClass:\t%s\n", storageutil.GetStorageClassAnnotation(pvc.ObjectMeta))
|
||||
fmt.Fprintf(out, "Status:\t%v\n", pvc.Status.Phase)
|
||||
fmt.Fprintf(out, "Volume:\t%s\n", pvc.Spec.VolumeName)
|
||||
printLabelsMultiline(out, "Labels", pvc.Labels)
|
||||
@ -2365,6 +2368,7 @@ func (s *StorageClassDescriber) Describe(namespace, name string, describerSettin
|
||||
}
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
fmt.Fprintf(out, "Name:\t%s\n", sc.Name)
|
||||
fmt.Fprintf(out, "IsDefaultClass:\t%s\n", storageutil.IsDefaultAnnotationText(sc.ObjectMeta))
|
||||
fmt.Fprintf(out, "Annotations:\t%s\n", labels.FormatLabels(sc.Annotations))
|
||||
fmt.Fprintf(out, "Provisioner:\t%s\n", sc.Provisioner)
|
||||
fmt.Fprintf(out, "Parameters:\t%s\n", labels.FormatLabels(sc.Parameters))
|
||||
|
@ -44,6 +44,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||
@ -2082,6 +2083,10 @@ func printNetworkPolicyList(list *extensions.NetworkPolicyList, w io.Writer, opt
|
||||
|
||||
func printStorageClass(sc *storage.StorageClass, w io.Writer, options PrintOptions) error {
|
||||
name := sc.Name
|
||||
|
||||
if storageutil.IsDefaultAnnotation(sc.ObjectMeta) {
|
||||
name += " (default)"
|
||||
}
|
||||
provtype := sc.Provisioner
|
||||
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s\t", name, provtype); err != nil {
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
@ -94,12 +95,6 @@ func (a *claimDefaulterPlugin) Stop() {
|
||||
}
|
||||
}
|
||||
|
||||
// This is a stand-in until we have a real field. This string should be a const somewhere.
|
||||
const classAnnotation = "volume.beta.kubernetes.io/storage-class"
|
||||
|
||||
// This indicates that a particular StorageClass nominates itself as the system default.
|
||||
const isDefaultAnnotation = "storageclass.beta.kubernetes.io/is-default-class"
|
||||
|
||||
// Admit sets the default value of a PersistentVolumeClaim's storage class, in case the user did
|
||||
// not provide a value.
|
||||
//
|
||||
@ -121,8 +116,7 @@ func (c *claimDefaulterPlugin) Admit(a admission.Attributes) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, found := pvc.Annotations[classAnnotation]
|
||||
if found {
|
||||
if storageutil.HasStorageClassAnnotation(pvc.ObjectMeta) {
|
||||
// The user asked for a class.
|
||||
return nil
|
||||
}
|
||||
@ -142,7 +136,7 @@ func (c *claimDefaulterPlugin) Admit(a admission.Attributes) error {
|
||||
if pvc.ObjectMeta.Annotations == nil {
|
||||
pvc.ObjectMeta.Annotations = map[string]string{}
|
||||
}
|
||||
pvc.Annotations[classAnnotation] = def.Name
|
||||
pvc.Annotations[storageutil.StorageClassAnnotation] = def.Name
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -154,7 +148,7 @@ func getDefaultClass(store cache.Store) (*storage.StorageClass, error) {
|
||||
if !ok {
|
||||
return nil, errors.NewInternalError(fmt.Errorf("error converting stored object to StorageClass: %v", c))
|
||||
}
|
||||
if class.Annotations[isDefaultAnnotation] == "true" {
|
||||
if storageutil.IsDefaultAnnotation(class.ObjectMeta) {
|
||||
defaultClasses = append(defaultClasses, class)
|
||||
glog.V(4).Infof("getDefaultClass added: %s", class.Name)
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
"k8s.io/kubernetes/pkg/conversion"
|
||||
)
|
||||
|
||||
@ -36,7 +37,7 @@ func TestAdmission(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "default1",
|
||||
Annotations: map[string]string{
|
||||
isDefaultAnnotation: "true",
|
||||
storageutil.IsDefaultStorageClassAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Provisioner: "default1",
|
||||
@ -48,7 +49,7 @@ func TestAdmission(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "default2",
|
||||
Annotations: map[string]string{
|
||||
isDefaultAnnotation: "true",
|
||||
storageutil.IsDefaultStorageClassAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Provisioner: "default2",
|
||||
@ -61,7 +62,7 @@ func TestAdmission(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "nondefault1",
|
||||
Annotations: map[string]string{
|
||||
isDefaultAnnotation: "false",
|
||||
storageutil.IsDefaultStorageClassAnnotation: "false",
|
||||
},
|
||||
},
|
||||
Provisioner: "nondefault1",
|
||||
@ -84,7 +85,7 @@ func TestAdmission(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "nondefault2",
|
||||
Annotations: map[string]string{
|
||||
isDefaultAnnotation: "",
|
||||
storageutil.IsDefaultStorageClassAnnotation: "",
|
||||
},
|
||||
},
|
||||
Provisioner: "nondefault1",
|
||||
@ -98,7 +99,7 @@ func TestAdmission(t *testing.T) {
|
||||
Name: "claimWithClass",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
classAnnotation: "foo",
|
||||
storageutil.StorageClassAnnotation: "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -110,7 +111,7 @@ func TestAdmission(t *testing.T) {
|
||||
Name: "claimWithEmptyClass",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
classAnnotation: "",
|
||||
storageutil.StorageClassAnnotation: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -218,7 +219,7 @@ func TestAdmission(t *testing.T) {
|
||||
|
||||
class := ""
|
||||
if claim.Annotations != nil {
|
||||
if value, ok := claim.Annotations[classAnnotation]; ok {
|
||||
if value, ok := claim.Annotations[storageutil.StorageClassAnnotation]; ok {
|
||||
class = value
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
|
||||
@ -172,11 +173,11 @@ func newClaim(ns string, alpha bool) *api.PersistentVolumeClaim {
|
||||
|
||||
if alpha {
|
||||
claim.Annotations = map[string]string{
|
||||
"volume.alpha.kubernetes.io/storage-class": "",
|
||||
storageutil.AlphaStorageClassAnnotation: "",
|
||||
}
|
||||
} else {
|
||||
claim.Annotations = map[string]string{
|
||||
"volume.beta.kubernetes.io/storage-class": "fast",
|
||||
storageutil.StorageClassAnnotation: "fast",
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
fake_cloud "k8s.io/kubernetes/pkg/cloudprovider/providers/fake"
|
||||
@ -884,7 +885,7 @@ func TestPersistentVolumeProvisionMultiPVCs(t *testing.T) {
|
||||
for i := 0; i < objCount; i++ {
|
||||
pvc := createPVC("pvc-provision-"+strconv.Itoa(i), ns.Name, "1G", []api.PersistentVolumeAccessMode{api.ReadWriteOnce})
|
||||
pvc.Annotations = map[string]string{
|
||||
"volume.beta.kubernetes.io/storage-class": "gold",
|
||||
storageutil.StorageClassAnnotation: "gold",
|
||||
}
|
||||
pvcs[i] = pvc
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/test/integration/framework"
|
||||
@ -72,7 +73,7 @@ func DoTestStorageClasses(t *testing.T, client *client.Client, ns *api.Namespace
|
||||
Name: "XXX",
|
||||
Namespace: ns.Name,
|
||||
Annotations: map[string]string{
|
||||
"volume.beta.kubernetes.io/storage-class": "gold",
|
||||
storageutil.StorageClassAnnotation: "gold",
|
||||
},
|
||||
},
|
||||
Spec: api.PersistentVolumeClaimSpec{
|
||||
|
Loading…
Reference in New Issue
Block a user