mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 17:30:00 +00:00
Add ReclaimPolicy field to StorageClass
This commit is contained in:
parent
bc1a58ae3a
commit
0356a840ff
@ -138,6 +138,10 @@ func TestDefaulting(t *testing.T) {
|
|||||||
{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ExternalAdmissionHookConfigurationList"}: {},
|
{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ExternalAdmissionHookConfigurationList"}: {},
|
||||||
{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicy"}: {},
|
{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicy"}: {},
|
||||||
{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicyList"}: {},
|
{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicyList"}: {},
|
||||||
|
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClass"}: {},
|
||||||
|
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClassList"}: {},
|
||||||
|
{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClass"}: {},
|
||||||
|
{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClassList"}: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1))
|
f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1))
|
||||||
|
@ -40,6 +40,7 @@ import (
|
|||||||
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
policyfuzzer "k8s.io/kubernetes/pkg/apis/policy/fuzzer"
|
policyfuzzer "k8s.io/kubernetes/pkg/apis/policy/fuzzer"
|
||||||
rbacfuzzer "k8s.io/kubernetes/pkg/apis/rbac/fuzzer"
|
rbacfuzzer "k8s.io/kubernetes/pkg/apis/rbac/fuzzer"
|
||||||
|
storagefuzzer "k8s.io/kubernetes/pkg/apis/storage/fuzzer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// overrideGenericFuncs override some generic fuzzer funcs from k8s.io/apiserver in order to have more realistic
|
// overrideGenericFuncs override some generic fuzzer funcs from k8s.io/apiserver in order to have more realistic
|
||||||
@ -100,4 +101,5 @@ var FuzzerFuncs = fuzzer.MergeFuzzerFuncs(
|
|||||||
policyfuzzer.Funcs,
|
policyfuzzer.Funcs,
|
||||||
certificatesfuzzer.Funcs,
|
certificatesfuzzer.Funcs,
|
||||||
admissionregistrationfuzzer.Funcs,
|
admissionregistrationfuzzer.Funcs,
|
||||||
|
storagefuzzer.Funcs,
|
||||||
)
|
)
|
||||||
|
@ -17,10 +17,20 @@ limitations under the License.
|
|||||||
package fuzzer
|
package fuzzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
fuzz "github.com/google/gofuzz"
|
||||||
|
|
||||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Funcs returns the fuzzer functions for the storage api group.
|
// Funcs returns the fuzzer functions for the storage api group.
|
||||||
var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||||
return []interface{}{}
|
return []interface{}{
|
||||||
|
func(obj *storage.StorageClass, c fuzz.Continue) {
|
||||||
|
c.FuzzNoCustom(obj) // fuzz self without calling this function again
|
||||||
|
reclamationPolicies := []api.PersistentVolumeReclaimPolicy{api.PersistentVolumeReclaimDelete, api.PersistentVolumeReclaimRetain}
|
||||||
|
obj.ReclaimPolicy = &reclamationPolicies[c.Rand.Intn(len(reclamationPolicies))]
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,10 @@ limitations under the License.
|
|||||||
|
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
// +genclient
|
// +genclient
|
||||||
// +genclient:nonNamespaced
|
// +genclient:nonNamespaced
|
||||||
@ -46,6 +49,11 @@ type StorageClass struct {
|
|||||||
// 512, with a cumulative max size of 256K
|
// 512, with a cumulative max size of 256K
|
||||||
// +optional
|
// +optional
|
||||||
Parameters map[string]string
|
Parameters map[string]string
|
||||||
|
|
||||||
|
// reclaimPolicy is the reclaim policy that dynamically provisioned
|
||||||
|
// PersistentVolumes of this storage class are created with
|
||||||
|
// +optional
|
||||||
|
ReclaimPolicy *api.PersistentVolumeReclaimPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
34
pkg/apis/storage/v1/defaults.go
Normal file
34
pkg/apis/storage/v1/defaults.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
storagev1 "k8s.io/api/storage/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||||
|
return RegisterDefaults(scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetDefaults_StorageClass(obj *storagev1.StorageClass) {
|
||||||
|
if obj.ReclaimPolicy == nil {
|
||||||
|
obj.ReclaimPolicy = new(v1.PersistentVolumeReclaimPolicy)
|
||||||
|
*obj.ReclaimPolicy = v1.PersistentVolumeReclaimDelete
|
||||||
|
}
|
||||||
|
}
|
@ -41,5 +41,5 @@ func init() {
|
|||||||
// We only register manually written functions here. The registration of the
|
// We only register manually written functions here. The registration of the
|
||||||
// generated functions takes place in the generated files. The separation
|
// generated functions takes place in the generated files. The separation
|
||||||
// makes the code compile even when the generated files are missing.
|
// makes the code compile even when the generated files are missing.
|
||||||
localSchemeBuilder.Register(RegisterDefaults)
|
localSchemeBuilder.Register(addDefaultingFuncs)
|
||||||
}
|
}
|
||||||
|
34
pkg/apis/storage/v1beta1/defaults.go
Normal file
34
pkg/apis/storage/v1beta1/defaults.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 v1beta1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||||
|
return RegisterDefaults(scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetDefaults_StorageClass(obj *storagev1beta1.StorageClass) {
|
||||||
|
if obj.ReclaimPolicy == nil {
|
||||||
|
obj.ReclaimPolicy = new(v1.PersistentVolumeReclaimPolicy)
|
||||||
|
*obj.ReclaimPolicy = v1.PersistentVolumeReclaimDelete
|
||||||
|
}
|
||||||
|
}
|
@ -41,5 +41,5 @@ func init() {
|
|||||||
// We only register manually written functions here. The registration of the
|
// We only register manually written functions here. The registration of the
|
||||||
// generated functions takes place in the generated files. The separation
|
// generated functions takes place in the generated files. The separation
|
||||||
// makes the code compile even when the generated files are missing.
|
// makes the code compile even when the generated files are missing.
|
||||||
localSchemeBuilder.Register(RegisterDefaults)
|
localSchemeBuilder.Register(addDefaultingFuncs)
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,10 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/validation"
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/apis/storage"
|
"k8s.io/kubernetes/pkg/apis/storage"
|
||||||
)
|
)
|
||||||
@ -31,6 +33,7 @@ func ValidateStorageClass(storageClass *storage.StorageClass) field.ErrorList {
|
|||||||
allErrs := apivalidation.ValidateObjectMeta(&storageClass.ObjectMeta, false, apivalidation.ValidateClassName, field.NewPath("metadata"))
|
allErrs := apivalidation.ValidateObjectMeta(&storageClass.ObjectMeta, false, apivalidation.ValidateClassName, field.NewPath("metadata"))
|
||||||
allErrs = append(allErrs, validateProvisioner(storageClass.Provisioner, field.NewPath("provisioner"))...)
|
allErrs = append(allErrs, validateProvisioner(storageClass.Provisioner, field.NewPath("provisioner"))...)
|
||||||
allErrs = append(allErrs, validateParameters(storageClass.Parameters, field.NewPath("parameters"))...)
|
allErrs = append(allErrs, validateParameters(storageClass.Parameters, field.NewPath("parameters"))...)
|
||||||
|
allErrs = append(allErrs, validateReclaimPolicy(storageClass.ReclaimPolicy, field.NewPath("reclaimPolicy"))...)
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
@ -45,6 +48,10 @@ func ValidateStorageClassUpdate(storageClass, oldStorageClass *storage.StorageCl
|
|||||||
if storageClass.Provisioner != oldStorageClass.Provisioner {
|
if storageClass.Provisioner != oldStorageClass.Provisioner {
|
||||||
allErrs = append(allErrs, field.Forbidden(field.NewPath("provisioner"), "updates to provisioner are forbidden."))
|
allErrs = append(allErrs, field.Forbidden(field.NewPath("provisioner"), "updates to provisioner are forbidden."))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *storageClass.ReclaimPolicy != *oldStorageClass.ReclaimPolicy {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(field.NewPath("reclaimPolicy"), "updates to reclaimPolicy are forbidden."))
|
||||||
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,3 +94,17 @@ func validateParameters(params map[string]string, fldPath *field.Path) field.Err
|
|||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var supportedReclaimPolicy = sets.NewString(string(api.PersistentVolumeReclaimDelete), string(api.PersistentVolumeReclaimRetain))
|
||||||
|
|
||||||
|
// validateReclaimPolicy tests that the reclaim policy is one of the supported. It is up to the volume plugin to reject
|
||||||
|
// provisioning for storage classes with impossible reclaim policies, e.g. EBS is not Recyclable
|
||||||
|
func validateReclaimPolicy(reclaimPolicy *api.PersistentVolumeReclaimPolicy, fldPath *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
if len(string(*reclaimPolicy)) > 0 {
|
||||||
|
if !supportedReclaimPolicy.Has(string(*reclaimPolicy)) {
|
||||||
|
allErrs = append(allErrs, field.NotSupported(fldPath, reclaimPolicy, supportedReclaimPolicy.List()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
@ -21,21 +21,27 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/storage"
|
"k8s.io/kubernetes/pkg/apis/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateStorageClass(t *testing.T) {
|
func TestValidateStorageClass(t *testing.T) {
|
||||||
|
deleteReclaimPolicy := api.PersistentVolumeReclaimPolicy("Delete")
|
||||||
|
retainReclaimPolicy := api.PersistentVolumeReclaimPolicy("Retain")
|
||||||
|
recycleReclaimPolicy := api.PersistentVolumeReclaimPolicy("Recycle")
|
||||||
successCases := []storage.StorageClass{
|
successCases := []storage.StorageClass{
|
||||||
{
|
{
|
||||||
// empty parameters
|
// empty parameters
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||||
Provisioner: "kubernetes.io/foo-provisioner",
|
Provisioner: "kubernetes.io/foo-provisioner",
|
||||||
Parameters: map[string]string{},
|
Parameters: map[string]string{},
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// nil parameters
|
// nil parameters
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||||
Provisioner: "kubernetes.io/foo-provisioner",
|
Provisioner: "kubernetes.io/foo-provisioner",
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// some parameters
|
// some parameters
|
||||||
@ -46,6 +52,13 @@ func TestValidateStorageClass(t *testing.T) {
|
|||||||
"foo-parameter": "free-form-string",
|
"foo-parameter": "free-form-string",
|
||||||
"foo-parameter2": "{\"embedded\": \"json\", \"with\": {\"structures\":\"inside\"}}",
|
"foo-parameter2": "{\"embedded\": \"json\", \"with\": {\"structures\":\"inside\"}}",
|
||||||
},
|
},
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// retain reclaimPolicy
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||||
|
Provisioner: "kubernetes.io/foo-provisioner",
|
||||||
|
ReclaimPolicy: &retainReclaimPolicy,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,12 +81,14 @@ func TestValidateStorageClass(t *testing.T) {
|
|||||||
|
|
||||||
errorCases := map[string]storage.StorageClass{
|
errorCases := map[string]storage.StorageClass{
|
||||||
"namespace is present": {
|
"namespace is present": {
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
|
||||||
Provisioner: "kubernetes.io/foo-provisioner",
|
Provisioner: "kubernetes.io/foo-provisioner",
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
"invalid provisioner": {
|
"invalid provisioner": {
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||||
Provisioner: "kubernetes.io/invalid/provisioner",
|
Provisioner: "kubernetes.io/invalid/provisioner",
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
"invalid empty parameter name": {
|
"invalid empty parameter name": {
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||||
@ -81,15 +96,23 @@ func TestValidateStorageClass(t *testing.T) {
|
|||||||
Parameters: map[string]string{
|
Parameters: map[string]string{
|
||||||
"": "value",
|
"": "value",
|
||||||
},
|
},
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
"provisioner: Required value": {
|
"provisioner: Required value": {
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||||
Provisioner: "",
|
Provisioner: "",
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
"too long parameters": {
|
"too long parameters": {
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||||
Provisioner: "kubernetes.io/foo",
|
Provisioner: "kubernetes.io/foo",
|
||||||
Parameters: longParameters,
|
Parameters: longParameters,
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
|
},
|
||||||
|
"invalid reclaimpolicy": {
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||||
|
Provisioner: "kubernetes.io/foo",
|
||||||
|
ReclaimPolicy: &recycleReclaimPolicy,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ var class1Parameters = map[string]string{
|
|||||||
var class2Parameters = map[string]string{
|
var class2Parameters = map[string]string{
|
||||||
"param2": "value2",
|
"param2": "value2",
|
||||||
}
|
}
|
||||||
|
var deleteReclaimPolicy = v1.PersistentVolumeReclaimDelete
|
||||||
var storageClasses = []*storage.StorageClass{
|
var storageClasses = []*storage.StorageClass{
|
||||||
{
|
{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
@ -41,8 +42,9 @@ var storageClasses = []*storage.StorageClass{
|
|||||||
Name: "gold",
|
Name: "gold",
|
||||||
},
|
},
|
||||||
|
|
||||||
Provisioner: mockPluginName,
|
Provisioner: mockPluginName,
|
||||||
Parameters: class1Parameters,
|
Parameters: class1Parameters,
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
@ -51,8 +53,9 @@ var storageClasses = []*storage.StorageClass{
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "silver",
|
Name: "silver",
|
||||||
},
|
},
|
||||||
Provisioner: mockPluginName,
|
Provisioner: mockPluginName,
|
||||||
Parameters: class2Parameters,
|
Parameters: class2Parameters,
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
@ -61,8 +64,9 @@ var storageClasses = []*storage.StorageClass{
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "external",
|
Name: "external",
|
||||||
},
|
},
|
||||||
Provisioner: "vendor.com/my-volume",
|
Provisioner: "vendor.com/my-volume",
|
||||||
Parameters: class1Parameters,
|
Parameters: class1Parameters,
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
@ -71,8 +75,9 @@ var storageClasses = []*storage.StorageClass{
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "unknown-internal",
|
Name: "unknown-internal",
|
||||||
},
|
},
|
||||||
Provisioner: "kubernetes.io/unknown",
|
Provisioner: "kubernetes.io/unknown",
|
||||||
Parameters: class1Parameters,
|
Parameters: class1Parameters,
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1309,7 +1309,7 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(claimObj interfa
|
|||||||
tags[CloudVolumeCreatedForVolumeNameTag] = pvName
|
tags[CloudVolumeCreatedForVolumeNameTag] = pvName
|
||||||
|
|
||||||
options := vol.VolumeOptions{
|
options := vol.VolumeOptions{
|
||||||
PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete,
|
PersistentVolumeReclaimPolicy: *storageClass.ReclaimPolicy,
|
||||||
CloudTags: &tags,
|
CloudTags: &tags,
|
||||||
ClusterName: ctrl.clusterName,
|
ClusterName: ctrl.clusterName,
|
||||||
PVName: pvName,
|
PVName: pvName,
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
|
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
storageapi "k8s.io/kubernetes/pkg/apis/storage"
|
storageapi "k8s.io/kubernetes/pkg/apis/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||||
)
|
)
|
||||||
@ -42,6 +43,7 @@ func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validNewStorageClass(name string) *storageapi.StorageClass {
|
func validNewStorageClass(name string) *storageapi.StorageClass {
|
||||||
|
deleteReclaimPolicy := api.PersistentVolumeReclaimDelete
|
||||||
return &storageapi.StorageClass{
|
return &storageapi.StorageClass{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -50,6 +52,7 @@ func validNewStorageClass(name string) *storageapi.StorageClass {
|
|||||||
Parameters: map[string]string{
|
Parameters: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
},
|
},
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,12 +67,14 @@ func TestCreate(t *testing.T) {
|
|||||||
test := registrytest.New(t, storage.Store).ClusterScope()
|
test := registrytest.New(t, storage.Store).ClusterScope()
|
||||||
storageClass := validNewStorageClass("foo")
|
storageClass := validNewStorageClass("foo")
|
||||||
storageClass.ObjectMeta = metav1.ObjectMeta{GenerateName: "foo"}
|
storageClass.ObjectMeta = metav1.ObjectMeta{GenerateName: "foo"}
|
||||||
|
deleteReclaimPolicy := api.PersistentVolumeReclaimDelete
|
||||||
test.TestCreate(
|
test.TestCreate(
|
||||||
// valid
|
// valid
|
||||||
storageClass,
|
storageClass,
|
||||||
// invalid
|
// invalid
|
||||||
&storageapi.StorageClass{
|
&storageapi.StorageClass{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "*BadName!"},
|
ObjectMeta: metav1.ObjectMeta{Name: "*BadName!"},
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/storage"
|
"k8s.io/kubernetes/pkg/apis/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ func TestStorageClassStrategy(t *testing.T) {
|
|||||||
t.Errorf("StorageClass should not allow create on update")
|
t.Errorf("StorageClass should not allow create on update")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteReclaimPolicy := api.PersistentVolumeReclaimDelete
|
||||||
storageClass := &storage.StorageClass{
|
storageClass := &storage.StorageClass{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "valid-class",
|
Name: "valid-class",
|
||||||
@ -41,6 +43,7 @@ func TestStorageClassStrategy(t *testing.T) {
|
|||||||
Parameters: map[string]string{
|
Parameters: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
},
|
},
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
}
|
}
|
||||||
|
|
||||||
Strategy.PrepareForCreate(ctx, storageClass)
|
Strategy.PrepareForCreate(ctx, storageClass)
|
||||||
@ -59,6 +62,7 @@ func TestStorageClassStrategy(t *testing.T) {
|
|||||||
Parameters: map[string]string{
|
Parameters: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
},
|
},
|
||||||
|
ReclaimPolicy: &deleteReclaimPolicy,
|
||||||
}
|
}
|
||||||
|
|
||||||
Strategy.PrepareForUpdate(ctx, newStorageClass, storageClass)
|
Strategy.PrepareForUpdate(ctx, newStorageClass, storageClass)
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,6 +44,11 @@ type StorageClass struct {
|
|||||||
// create volumes of this storage class.
|
// create volumes of this storage class.
|
||||||
// +optional
|
// +optional
|
||||||
Parameters map[string]string `json:"parameters,omitempty" protobuf:"bytes,3,rep,name=parameters"`
|
Parameters map[string]string `json:"parameters,omitempty" protobuf:"bytes,3,rep,name=parameters"`
|
||||||
|
|
||||||
|
// Dynamically provisioned PersistentVolumes of this storage class are
|
||||||
|
// created with this reclaimPolicy. Defaults to Delete.
|
||||||
|
// +optional
|
||||||
|
ReclaimPolicy *v1.PersistentVolumeReclaimPolicy `json:"reclaimPolicy,omitempty" protobuf:"bytes,4,opt,name=reclaimPolicy,casttype=k8s.io/api/core/v1.PersistentVolumeReclaimPolicy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package v1beta1
|
package v1beta1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,6 +44,11 @@ type StorageClass struct {
|
|||||||
// create volumes of this storage class.
|
// create volumes of this storage class.
|
||||||
// +optional
|
// +optional
|
||||||
Parameters map[string]string `json:"parameters,omitempty" protobuf:"bytes,3,rep,name=parameters"`
|
Parameters map[string]string `json:"parameters,omitempty" protobuf:"bytes,3,rep,name=parameters"`
|
||||||
|
|
||||||
|
// Dynamically provisioned PersistentVolumes of this storage class are
|
||||||
|
// created with this reclaimPolicy. Defaults to Delete.
|
||||||
|
// +optional
|
||||||
|
ReclaimPolicy *v1.PersistentVolumeReclaimPolicy `json:"reclaimPolicy,omitempty" protobuf:"bytes,4,opt,name=reclaimPolicy,casttype=k8s.io/api/core/v1.PersistentVolumeReclaimPolicy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
Loading…
Reference in New Issue
Block a user