mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-07-19 06:22:25 +00:00
add resourcePolicy on restore CRD
Add resourcePolicy field for restore CRD which is backed by a configmap that holds ClusterScopedFilterPolicy and NamespacedFilterPolicies for restore side filtering. Signed-off-by: Adam Zhang <adam.zhang@broadcom.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Fix issue #9935, add resource policy on restore CRD
|
||||
@@ -404,6 +404,33 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
resourcePolicy:
|
||||
description: |-
|
||||
ResourcePolicy specifies the reference to a ConfigMap containing resource
|
||||
filter policies for this restore. The ConfigMap can contain a
|
||||
namespacedFilterPolicies section that specifies per-namespace resource type
|
||||
filters, label selectors, and resource name patterns, and a
|
||||
clusterScopedFilterPolicy section for per-kind filtering of cluster-scoped
|
||||
resources. The ConfigMap format is the same as for BackupSpec.ResourcePolicy.
|
||||
nullable: true
|
||||
properties:
|
||||
apiGroup:
|
||||
description: |-
|
||||
APIGroup is the group for the resource being referenced.
|
||||
If APIGroup is not specified, the specified Kind must be in the core API group.
|
||||
For any other third-party types, APIGroup is required.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind is the type of resource being referenced
|
||||
type: string
|
||||
name:
|
||||
description: Name is the name of resource being referenced
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
restorePVs:
|
||||
description: |-
|
||||
RestorePVs specifies whether to restore all included
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -331,20 +331,20 @@ func GetResourcePoliciesFromBackup(
|
||||
if err != nil {
|
||||
logger.Errorf("Fail to get ResourcePolicies %s ConfigMap with error %s.",
|
||||
backup.Namespace+"/"+backup.Spec.ResourcePolicy.Name, err.Error())
|
||||
return nil, fmt.Errorf("fail to get ResourcePolicies %s ConfigMap with error %s",
|
||||
backup.Namespace+"/"+backup.Spec.ResourcePolicy.Name, err.Error())
|
||||
return nil, fmt.Errorf("fail to get ResourcePolicies %s ConfigMap: %w",
|
||||
backup.Namespace+"/"+backup.Spec.ResourcePolicy.Name, err)
|
||||
}
|
||||
resourcePolicies, err = getResourcePoliciesFromConfig(policiesConfigMap)
|
||||
if err != nil {
|
||||
logger.Errorf("Fail to read ResourcePolicies from ConfigMap %s with error %s.",
|
||||
backup.Namespace+"/"+backup.Name, err.Error())
|
||||
return nil, fmt.Errorf("fail to read the ResourcePolicies from ConfigMap %s with error %s",
|
||||
backup.Namespace+"/"+backup.Name, err.Error())
|
||||
return nil, fmt.Errorf("fail to read the ResourcePolicies from ConfigMap %s: %w",
|
||||
backup.Namespace+"/"+backup.Name, err)
|
||||
} else if err = resourcePolicies.Validate(); err != nil {
|
||||
logger.Errorf("Fail to validate ResourcePolicies in ConfigMap %s with error %s.",
|
||||
backup.Namespace+"/"+backup.Name, err.Error())
|
||||
return nil, fmt.Errorf("fail to validate ResourcePolicies in ConfigMap %s with error %s",
|
||||
backup.Namespace+"/"+backup.Name, err.Error())
|
||||
return nil, fmt.Errorf("fail to validate ResourcePolicies in ConfigMap %s: %w",
|
||||
backup.Namespace+"/"+backup.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,6 +425,49 @@ func GetResourcePoliciesFromBackupWithGlobal(
|
||||
return backupPolicies, nil
|
||||
}
|
||||
|
||||
// GetResourcePoliciesFromRestore retrieves the resource policies from the ConfigMap referenced in the Restore spec.
|
||||
func GetResourcePoliciesFromRestore(
|
||||
ctx context.Context,
|
||||
restore *velerov1api.Restore,
|
||||
client crclient.Client,
|
||||
logger logrus.FieldLogger,
|
||||
) (resourcePolicies *Policies, err error) {
|
||||
if restore.Spec.ResourcePolicy != nil {
|
||||
if !strings.EqualFold(restore.Spec.ResourcePolicy.Kind, ConfigmapRefType) {
|
||||
return nil, fmt.Errorf("invalid ResourcePolicy kind %q, only %q is supported",
|
||||
restore.Spec.ResourcePolicy.Kind, ConfigmapRefType)
|
||||
}
|
||||
policiesConfigMap := &corev1api.ConfigMap{}
|
||||
err = client.Get(
|
||||
ctx,
|
||||
crclient.ObjectKey{
|
||||
Namespace: restore.Namespace,
|
||||
Name: restore.Spec.ResourcePolicy.Name,
|
||||
},
|
||||
policiesConfigMap,
|
||||
)
|
||||
if err != nil {
|
||||
logger.Errorf("Fail to get ResourcePolicies %s ConfigMap with error %s.",
|
||||
restore.Namespace+"/"+restore.Spec.ResourcePolicy.Name, err.Error())
|
||||
return nil, fmt.Errorf("fail to get ResourcePolicies %s ConfigMap: %w",
|
||||
restore.Namespace+"/"+restore.Spec.ResourcePolicy.Name, err)
|
||||
}
|
||||
resourcePolicies, err = getResourcePoliciesFromConfig(policiesConfigMap)
|
||||
if err != nil {
|
||||
logger.Errorf("Fail to read ResourcePolicies from ConfigMap %s with error %s.",
|
||||
restore.Namespace+"/"+restore.Spec.ResourcePolicy.Name, err.Error())
|
||||
return nil, fmt.Errorf("fail to read the ResourcePolicies from ConfigMap %s: %w",
|
||||
restore.Namespace+"/"+restore.Spec.ResourcePolicy.Name, err)
|
||||
} else if err = resourcePolicies.Validate(); err != nil {
|
||||
logger.Errorf("Fail to validate ResourcePolicies in ConfigMap %s with error %s.",
|
||||
restore.Namespace+"/"+restore.Spec.ResourcePolicy.Name, err.Error())
|
||||
return nil, fmt.Errorf("fail to validate ResourcePolicies in ConfigMap %s: %w",
|
||||
restore.Namespace+"/"+restore.Spec.ResourcePolicy.Name, err)
|
||||
}
|
||||
}
|
||||
return resourcePolicies, nil
|
||||
}
|
||||
|
||||
func getResourcePoliciesFromConfig(cm *corev1api.ConfigMap) (*Policies, error) {
|
||||
if cm == nil {
|
||||
return nil, fmt.Errorf("could not parse config from nil configmap")
|
||||
|
||||
@@ -16,6 +16,7 @@ limitations under the License.
|
||||
package resourcepolicies
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -24,6 +25,8 @@ import (
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
@@ -494,6 +497,49 @@ volumePolicies:
|
||||
assert.Equal(t, p, resPolicies)
|
||||
}
|
||||
|
||||
func TestGetResourcePoliciesFromRestore(t *testing.T) {
|
||||
// Create a test ConfigMap
|
||||
cm := &corev1api.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-configmap",
|
||||
Namespace: "test-namespace",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"test-data": `version: v1
|
||||
volumePolicies:
|
||||
- conditions:
|
||||
capacity: '0,10Gi'
|
||||
csi:
|
||||
driver: disks.csi.driver
|
||||
action:
|
||||
type: skip
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
// Create a fake client
|
||||
client := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(cm).Build()
|
||||
logger := logrus.New()
|
||||
|
||||
restore := velerov1api.Restore{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-restore",
|
||||
},
|
||||
Spec: velerov1api.RestoreSpec{
|
||||
ResourcePolicy: &corev1api.TypedLocalObjectReference{
|
||||
Kind: ConfigmapRefType,
|
||||
Name: "test-configmap",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resPolicies, err := GetResourcePoliciesFromRestore(context.Background(), &restore, client, logger)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "v1", resPolicies.version)
|
||||
assert.Len(t, resPolicies.volumePolicies, 1)
|
||||
}
|
||||
|
||||
func TestGetMatchAction(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
||||
@@ -125,6 +125,16 @@ type RestoreSpec struct {
|
||||
// +nullable
|
||||
ResourceModifier *corev1api.TypedLocalObjectReference `json:"resourceModifier,omitempty"`
|
||||
|
||||
// ResourcePolicy specifies the reference to a ConfigMap containing resource
|
||||
// filter policies for this restore. The ConfigMap can contain a
|
||||
// namespacedFilterPolicies section that specifies per-namespace resource type
|
||||
// filters, label selectors, and resource name patterns, and a
|
||||
// clusterScopedFilterPolicy section for per-kind filtering of cluster-scoped
|
||||
// resources. The ConfigMap format is the same as for BackupSpec.ResourcePolicy.
|
||||
// +optional
|
||||
// +nullable
|
||||
ResourcePolicy *corev1api.TypedLocalObjectReference `json:"resourcePolicy,omitempty"`
|
||||
|
||||
// UploaderConfig specifies the configuration for the restore.
|
||||
// +optional
|
||||
// +nullable
|
||||
|
||||
@@ -1415,6 +1415,11 @@ func (in *RestoreSpec) DeepCopyInto(out *RestoreSpec) {
|
||||
*out = new(corev1.TypedLocalObjectReference)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ResourcePolicy != nil {
|
||||
in, out := &in.ResourcePolicy, &out.ResourcePolicy
|
||||
*out = new(corev1.TypedLocalObjectReference)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.UploaderConfig != nil {
|
||||
in, out := &in.UploaderConfig, &out.UploaderConfig
|
||||
*out = new(UploaderConfigForRestore)
|
||||
|
||||
@@ -19,6 +19,7 @@ package builder
|
||||
import (
|
||||
"time"
|
||||
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
@@ -171,3 +172,12 @@ func (b *RestoreBuilder) ItemOperationTimeout(timeout time.Duration) *RestoreBui
|
||||
b.object.Spec.ItemOperationTimeout.Duration = timeout
|
||||
return b
|
||||
}
|
||||
|
||||
// ResourcePoliciesConfigmap sets the Restore's resource policies configmap.
|
||||
func (b *RestoreBuilder) ResourcePoliciesConfigmap(name string) *RestoreBuilder {
|
||||
b.object.Spec.ResourcePolicy = &corev1api.TypedLocalObjectReference{
|
||||
Kind: "configmap",
|
||||
Name: name,
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright 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 (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRestoreBuilder_ResourcePoliciesConfigmap(t *testing.T) {
|
||||
restore := ForRestore("velero", "my-restore").
|
||||
ResourcePoliciesConfigmap("my-policy-cm").
|
||||
Result()
|
||||
|
||||
assert.Equal(t, "velero", restore.Namespace)
|
||||
assert.Equal(t, "my-restore", restore.Name)
|
||||
assert.NotNil(t, restore.Spec.ResourcePolicy)
|
||||
assert.Equal(t, "configmap", restore.Spec.ResourcePolicy.Kind)
|
||||
assert.Equal(t, "my-policy-cm", restore.Spec.ResourcePolicy.Name)
|
||||
assert.Equal(t, (*string)(nil), restore.Spec.ResourcePolicy.APIGroup)
|
||||
}
|
||||
Reference in New Issue
Block a user