mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-05-23 15:41:34 +00:00
Fix statefulsets volumeClaimTemplates storageClassName after use Changing PV/PVC Storage Classes (#4375)
* fix statefulsets volumeClaimTemplates storageClassName after use Changing PV/PVC Storage Classes Signed-off-by: Box-Cube <64300761+Box-Cube@users.noreply.github.com> * Fix (vmware-tanzu#4373) Signed-off-by: Box-Cube <64300761+Box-Cube@users.noreply.github.com> * Fix StatefulSet volumeClaimTemplates storageClassName(vmware-tanzu#4373) Signed-off-by: Box-Cube <64300761+Box-Cube@users.noreply.github.com> * Fix StatefulSet volumeClaimTemplates storageClassName(vmware-tanzu#4373) Signed-off-by: Box-Cube <64300761+Box-Cube@users.noreply.github.com> * Fix StatefulSet volumeClaimTemplates storageClassName(vmware-tanzu#4373) Signed-off-by: Box-Cube <64300761+Box-Cube@users.noreply.github.com> * Change the isStorageClassExist logic Signed-off-by: Box-Cube <64300761+Box-Cube@users.noreply.github.com> * Fix StatefulSet volumeClaimTemplates storageClassName(vmware-tanzu#4373) Signed-off-by: Box-Cube <64300761+Box-Cube@users.noreply.github.com>
This commit is contained in:
1
changelogs/unreleased/4375-Box-Cube
Normal file
1
changelogs/unreleased/4375-Box-Cube
Normal file
@@ -0,0 +1 @@
|
||||
Fix statefulsets volumeClaimTemplates storageClassName when use Changing PV/PVC Storage Classes
|
||||
62
pkg/builder/statefulset_builder.go
Normal file
62
pkg/builder/statefulset_builder.go
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2021 the Velero contributors.
|
||||
|
||||
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 builder
|
||||
|
||||
import (
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// StatefulSetBuilder builds StatefulSet objects.
|
||||
type StatefulSetBuilder struct {
|
||||
object *appsv1.StatefulSet
|
||||
}
|
||||
|
||||
// ForStatefulSet is the constructor for a StatefulSetBuilder.
|
||||
func ForStatefulSet(ns, name string) *StatefulSetBuilder {
|
||||
return &StatefulSetBuilder{
|
||||
object: &appsv1.StatefulSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: appsv1.SchemeGroupVersion.String(),
|
||||
Kind: "StatefulSet",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
Spec: appsv1.StatefulSetSpec{
|
||||
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built StatefulSet.
|
||||
func (b *StatefulSetBuilder) Result() *appsv1.StatefulSet {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// StorageClass sets the StatefulSet's VolumeClaimTemplates storage class name.
|
||||
func (b *StatefulSetBuilder) StorageClass(names ...string) *StatefulSetBuilder {
|
||||
for _, name := range names {
|
||||
nameTmp := name
|
||||
b.object.Spec.VolumeClaimTemplates = append(b.object.Spec.VolumeClaimTemplates,
|
||||
corev1.PersistentVolumeClaim{Spec: corev1.PersistentVolumeClaimSpec{StorageClassName: &nameTmp}})
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -23,7 +23,8 @@ import (
|
||||
|
||||
// StorageClassBuilder builds StorageClass objects.
|
||||
type StorageClassBuilder struct {
|
||||
object *storagev1api.StorageClass
|
||||
object *storagev1api.StorageClass
|
||||
objectSlice []*storagev1api.StorageClass
|
||||
}
|
||||
|
||||
// ForStorageClass is the constructor for a StorageClassBuilder.
|
||||
@@ -54,3 +55,29 @@ func (b *StorageClassBuilder) ObjectMeta(opts ...ObjectMetaOpt) *StorageClassBui
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// ForStorageClassSlice is the constructor for a storageClassSlice in StorageClassBuilder.
|
||||
func ForStorageClassSlice(names ...string) *StorageClassBuilder {
|
||||
var storageClassSlice []*storagev1api.StorageClass
|
||||
for _, name := range names {
|
||||
storageClass := &storagev1api.StorageClass{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: storagev1api.SchemeGroupVersion.String(),
|
||||
Kind: "StorageClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
storageClassSlice = append(storageClassSlice, storageClass)
|
||||
}
|
||||
|
||||
return &StorageClassBuilder{
|
||||
objectSlice: storageClassSlice,
|
||||
}
|
||||
}
|
||||
|
||||
// SliceResult returns the built StorageClass slice.
|
||||
func (b *StorageClassBuilder) SliceResult() []*storagev1api.StorageClass {
|
||||
return b.objectSlice
|
||||
}
|
||||
|
||||
@@ -21,8 +21,11 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
storagev1client "k8s.io/client-go/kubernetes/typed/storage/v1"
|
||||
|
||||
@@ -55,7 +58,7 @@ func NewChangeStorageClassAction(
|
||||
// be run for.
|
||||
func (a *ChangeStorageClassAction) AppliesTo() (velero.ResourceSelector, error) {
|
||||
return velero.ResourceSelector{
|
||||
IncludedResources: []string{"persistentvolumeclaims", "persistentvolumes"},
|
||||
IncludedResources: []string{"persistentvolumeclaims", "persistentvolumes", "statefulsets"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -87,33 +90,72 @@ func (a *ChangeStorageClassAction) Execute(input *velero.RestoreItemActionExecut
|
||||
"name": obj.GetName(),
|
||||
})
|
||||
|
||||
// use the unstructured helpers here since this code is for both PVs and PVCs, and the
|
||||
// field names are the same for both types.
|
||||
storageClass, _, err := unstructured.NestedString(obj.UnstructuredContent(), "spec", "storageClassName")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error getting item's spec.storageClassName")
|
||||
// change StatefulSet volumeClaimTemplates storageClassName
|
||||
if obj.GetKind() == "StatefulSet" {
|
||||
sts := new(appsv1.StatefulSet)
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), sts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(sts.Spec.VolumeClaimTemplates) > 0 {
|
||||
for index, pvc := range sts.Spec.VolumeClaimTemplates {
|
||||
exists, newStorageClass, err := a.isStorageClassExist(log, *pvc.Spec.StorageClassName, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Infof("Updating item's storage class name to %s", newStorageClass)
|
||||
sts.Spec.VolumeClaimTemplates[index].Spec.StorageClassName = &newStorageClass
|
||||
}
|
||||
|
||||
newObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(sts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "convert obj to StatefulSet failed")
|
||||
}
|
||||
obj.Object = newObj
|
||||
}
|
||||
} else {
|
||||
// use the unstructured helpers here since this code is for both PVs and PVCs, and the
|
||||
// field names are the same for both types.
|
||||
storageClass, _, err := unstructured.NestedString(obj.UnstructuredContent(), "spec", "storageClassName")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error getting item's spec.storageClassName")
|
||||
}
|
||||
|
||||
exists, newStorageClass, err := a.isStorageClassExist(log, storageClass, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !exists {
|
||||
return velero.NewRestoreItemActionExecuteOutput(input.Item), nil
|
||||
}
|
||||
|
||||
log.Infof("Updating item's storage class name to %s", newStorageClass)
|
||||
|
||||
if err := unstructured.SetNestedField(obj.UnstructuredContent(), newStorageClass, "spec", "storageClassName"); err != nil {
|
||||
return nil, errors.Wrap(err, "unable to set item's spec.storageClassName")
|
||||
}
|
||||
}
|
||||
return velero.NewRestoreItemActionExecuteOutput(obj), nil
|
||||
}
|
||||
|
||||
func (a *ChangeStorageClassAction) isStorageClassExist(log *logrus.Entry, storageClass string, cm *corev1.ConfigMap) (exists bool, newStorageClass string, err error) {
|
||||
if storageClass == "" {
|
||||
log.Debug("Item has no storage class specified")
|
||||
return velero.NewRestoreItemActionExecuteOutput(input.Item), nil
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
newStorageClass, ok := config.Data[storageClass]
|
||||
newStorageClass, ok := cm.Data[storageClass]
|
||||
if !ok {
|
||||
log.Debugf("No mapping found for storage class %s", storageClass)
|
||||
return velero.NewRestoreItemActionExecuteOutput(input.Item), nil
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
// validate that new storage class exists
|
||||
if _, err := a.storageClassClient.Get(context.TODO(), newStorageClass, metav1.GetOptions{}); err != nil {
|
||||
return nil, errors.Wrapf(err, "error getting storage class %s from API", newStorageClass)
|
||||
return false, "", errors.Wrapf(err, "error getting storage class %s from API", newStorageClass)
|
||||
}
|
||||
|
||||
log.Infof("Updating item's storage class name to %s", newStorageClass)
|
||||
|
||||
if err := unstructured.SetNestedField(obj.UnstructuredContent(), newStorageClass, "spec", "storageClassName"); err != nil {
|
||||
return nil, errors.Wrap(err, "unable to set item's spec.storageClassName")
|
||||
}
|
||||
|
||||
return velero.NewRestoreItemActionExecuteOutput(obj), nil
|
||||
return true, newStorageClass, nil
|
||||
}
|
||||
|
||||
@@ -41,16 +41,17 @@ import (
|
||||
// desired result.
|
||||
func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pvOrPVC interface{}
|
||||
configMap *corev1api.ConfigMap
|
||||
storageClass *storagev1api.StorageClass
|
||||
want interface{}
|
||||
wantErr error
|
||||
name string
|
||||
pvOrPvcOrSTS interface{}
|
||||
configMap *corev1api.ConfigMap
|
||||
storageClass *storagev1api.StorageClass
|
||||
storageClassSlice []*storagev1api.StorageClass
|
||||
want interface{}
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "a valid mapping for a persistent volume is applied correctly",
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
name: "a valid mapping for a persistent volume is applied correctly",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
@@ -59,8 +60,8 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-2").Result(),
|
||||
},
|
||||
{
|
||||
name: "a valid mapping for a persistent volume claim is applied correctly",
|
||||
pvOrPVC: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
name: "a valid mapping for a persistent volume claim is applied correctly",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
@@ -69,8 +70,8 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
want: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-2").Result(),
|
||||
},
|
||||
{
|
||||
name: "when no config map exists for the plugin, the item is returned as-is",
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
name: "when no config map exists for the plugin, the item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/some-other-plugin", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
@@ -78,16 +79,16 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when no storage class mappings exist in the plugin config map, the item is returned as-is",
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
name: "when no storage class mappings exist in the plugin config map, the item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Result(),
|
||||
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume has no storage class, the item is returned as-is",
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").Result(),
|
||||
name: "when persistent volume has no storage class, the item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolume("pv-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
@@ -95,8 +96,8 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
want: builder.ForPersistentVolume("pv-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume claim has no storage class, the item is returned as-is",
|
||||
pvOrPVC: builder.ForPersistentVolumeClaim("velero", "pvc-1").Result(),
|
||||
name: "when persistent volume claim has no storage class, the item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolumeClaim("velero", "pvc-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
@@ -104,8 +105,8 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
want: builder.ForPersistentVolumeClaim("velero", "pvc-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume's storage class has no mapping in the config map, the item is returned as-is",
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
name: "when persistent volume's storage class has no mapping in the config map, the item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-3", "storageclass-4").
|
||||
@@ -113,8 +114,8 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume claim's storage class has no mapping in the config map, the item is returned as-is",
|
||||
pvOrPVC: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
name: "when persistent volume claim's storage class has no mapping in the config map, the item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-3", "storageclass-4").
|
||||
@@ -122,8 +123,8 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
want: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume's storage class is mapped to a nonexistent storage class, an error is returned",
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
name: "when persistent volume's storage class is mapped to a nonexistent storage class, an error is returned",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "nonexistent-storage-class").
|
||||
@@ -131,8 +132,81 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
wantErr: errors.New("error getting storage class nonexistent-storage-class from API: storageclasses.storage.k8s.io \"nonexistent-storage-class\" not found"),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume claim's storage class is mapped to a nonexistent storage class, an error is returned",
|
||||
pvOrPVC: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
name: "when persistent volume claim's storage class is mapped to a nonexistent storage class, an error is returned",
|
||||
pvOrPvcOrSTS: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "nonexistent-storage-class").
|
||||
Result(),
|
||||
wantErr: errors.New("error getting storage class nonexistent-storage-class from API: storageclasses.storage.k8s.io \"nonexistent-storage-class\" not found"),
|
||||
},
|
||||
{
|
||||
name: "when statefulset's VolumeClaimTemplates has only one pvc, a valid mapping for a statefulset is applied correctly",
|
||||
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
Result(),
|
||||
storageClass: builder.ForStorageClass("storageclass-2").Result(),
|
||||
want: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-2").Result(),
|
||||
},
|
||||
{
|
||||
name: "when statefulset's VolumeClaimTemplates has more than one same pvc's storageClassName, a valid mapping for a statefulset is applied correctly",
|
||||
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1", "storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2", "storageclass-3", "storageclass-4").
|
||||
Result(),
|
||||
storageClass: builder.ForStorageClass("storageclass-2").Result(),
|
||||
want: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-2", "storageclass-2").Result(),
|
||||
},
|
||||
{
|
||||
name: "when statefulset's VolumeClaimTemplates has more than one different pvc's storageClassName, a valid mapping for a statefulset is applied correctly",
|
||||
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1", "storageclass-2", "storageclass-3").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-a", "storageclass-2", "storageclass-b", "storageclass-3", "storageclass-c").
|
||||
Result(),
|
||||
storageClassSlice: builder.ForStorageClassSlice("storageclass-a", "storageclass-b", "storageclass-c").SliceResult(),
|
||||
want: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-a", "storageclass-b", "storageclass-c").Result(),
|
||||
},
|
||||
{
|
||||
name: "when no config map exists for the plugin, the statefulset item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/some-other-plugin", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
Result(),
|
||||
want: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when no storage class mappings exist in the plugin config map, the statefulset item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Result(),
|
||||
want: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume claim has no storage class, the statefulset item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Result(),
|
||||
want: builder.ForStatefulSet("velero", "sts-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when statefulset's storage class has no mapping in the config map, the item is returned as-is",
|
||||
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-3", "storageclass-4").
|
||||
Result(),
|
||||
want: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when statefulset's storage class is mapped to a nonexistent storage class, an error is returned",
|
||||
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "nonexistent-storage-class").
|
||||
@@ -161,7 +235,14 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(tc.pvOrPVC)
|
||||
if tc.storageClassSlice != nil {
|
||||
for _, storageClass := range tc.storageClassSlice {
|
||||
_, err := clientset.StorageV1().StorageClasses().Create(context.TODO(), storageClass, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(tc.pvOrPvcOrSTS)
|
||||
require.NoError(t, err)
|
||||
|
||||
input := &velero.RestoreItemActionExecuteInput{
|
||||
|
||||
Reference in New Issue
Block a user