Files
velero/internal/resourcepolicies/volume_resources_validator_test.go
T
Shubham PampattiwarandGitHub 0eb1040a0a
Run the E2E test on kind / build (push) Failing after 6m23s
Run the E2E test on kind / setup-test-matrix (push) Successful in 3s
Run the E2E test on kind / run-e2e-test (push) Has been skipped
Main CI / Build (push) Failing after 38s
Close stale issues and PRs / stale (push) Successful in 9s
Trivy Nightly Scan / Trivy nightly scan (velero, main) (push) Failing after 1m5s
Trivy Nightly Scan / Trivy nightly scan (velero-restore-helper, main) (push) Failing after 55s
Add labels as a criteria for volume policy (#8713)
* Add labels as a criteria for volume policy

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

add changelog file

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

handle err

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

use labels selector.matches

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

make update

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

remove fetching pvc from volume policy filtering

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

add more ut coverage

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

* minor updates

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

use VolumeFilterData struct in GetMatchAction func

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

update parsePVC func and add more ut

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

lint fix

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

---------

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>
2025-02-26 10:02:45 -05:00

475 lines
11 KiB
Go

/*
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 resourcepolicies
import (
"testing"
"k8s.io/apimachinery/pkg/api/resource"
)
func TestCapacityConditionValidate(t *testing.T) {
testCases := []struct {
name string
capacity *capacity
wantErr bool
}{
{
name: "lower and upper are both zero",
capacity: &capacity{lower: *resource.NewQuantity(0, resource.DecimalSI), upper: *resource.NewQuantity(0, resource.DecimalSI)},
wantErr: false,
},
{
name: "lower is zero and upper is greater than zero",
capacity: &capacity{lower: *resource.NewQuantity(0, resource.DecimalSI), upper: *resource.NewQuantity(100, resource.DecimalSI)},
wantErr: false,
},
{
name: "lower is greater than upper",
capacity: &capacity{lower: *resource.NewQuantity(100, resource.DecimalSI), upper: *resource.NewQuantity(50, resource.DecimalSI)},
wantErr: true,
},
{
name: "lower and upper are equal",
capacity: &capacity{lower: *resource.NewQuantity(100, resource.DecimalSI), upper: *resource.NewQuantity(100, resource.DecimalSI)},
wantErr: false,
},
{
name: "lower is greater than zero and upper is zero",
capacity: &capacity{lower: *resource.NewQuantity(100, resource.DecimalSI), upper: *resource.NewQuantity(0, resource.DecimalSI)},
wantErr: false,
},
{
name: "lower and upper are both not zero and lower is less than upper",
capacity: &capacity{lower: *resource.NewQuantity(100, resource.DecimalSI), upper: *resource.NewQuantity(200, resource.DecimalSI)},
wantErr: false,
},
{
name: "lower and upper are both not zero and lower is equal to upper",
capacity: &capacity{lower: *resource.NewQuantity(100, resource.DecimalSI), upper: *resource.NewQuantity(100, resource.DecimalSI)},
wantErr: false,
},
{
name: "lower and upper are both not zero and lower is greater than upper",
capacity: &capacity{lower: *resource.NewQuantity(200, resource.DecimalSI), upper: *resource.NewQuantity(100, resource.DecimalSI)},
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
c := &capacityCondition{capacity: *tc.capacity}
err := c.validate()
if (err != nil) != tc.wantErr {
t.Fatalf("Expected error %v, but got error %v", tc.wantErr, err)
}
})
}
}
func TestValidate(t *testing.T) {
testCases := []struct {
name string
res *ResourcePolicies
wantErr bool
}{
{
name: "unknown key in yaml",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"unknown": "",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
},
},
},
},
wantErr: true,
},
{
name: "error format of capacity",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
},
},
},
},
wantErr: true,
},
{
name: "error format of storageClass",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"storageClass": "ebs-sc",
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
},
},
},
},
wantErr: true,
},
{
name: "error format of csi",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": "aws.efs.csi.driver",
},
},
},
},
wantErr: true,
},
{
name: "error format of csi driver",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": []string{"aws.efs.csi.driver"},
}),
},
},
},
},
wantErr: true,
},
{
name: "error format of csi driver volumeAttributes",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
"volumeAttributes": "test",
}),
},
},
},
},
wantErr: true,
},
{
name: "unsupported version",
res: &ResourcePolicies{
Version: "v2",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
},
},
},
},
wantErr: true,
},
{
name: "unsupported action",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "unsupported"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
},
},
},
},
wantErr: true,
},
{
name: "error format of nfs",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"nfs": "aws.efs.csi.driver",
},
},
},
},
wantErr: true,
},
{
name: "supported format volume policies only csi driver",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
},
},
},
},
wantErr: false,
},
{
name: "unsupported format volume policies only csi volumeattributes",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"csi": any(
map[string]any{
"volumeAttributes": map[string]string{
"key1": "value1",
},
}),
},
},
},
},
wantErr: true,
},
{
name: "supported format volume policies with csi driver and volumeattributes",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
"volumeAttributes": map[string]string{
"key1": "value1",
},
}),
},
},
},
},
wantErr: false,
},
{
name: "supported format volume policies",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
"nfs": any(
map[string]any{
"server": "192.168.20.90",
"path": "/mnt/data/",
}),
},
},
},
},
wantErr: false,
},
{
name: "supported format volume policies, action type snapshot",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "snapshot"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
"nfs": any(
map[string]any{
"server": "192.168.20.90",
"path": "/mnt/data/",
}),
},
},
},
},
wantErr: false,
},
{
name: "supported format volume policies, action type fs-backup",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "fs-backup"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
"nfs": any(
map[string]any{
"server": "192.168.20.90",
"path": "/mnt/data/",
}),
},
},
},
},
wantErr: false,
},
{
name: "supported format volume policies, action type fs-backup and snapshot",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: Snapshot},
Conditions: map[string]any{
"storageClass": []string{"gp2"},
},
},
{
Action: Action{Type: FSBackup},
Conditions: map[string]any{
"nfs": any(
map[string]any{
"server": "192.168.20.90",
"path": "/mnt/data/",
}),
},
},
},
},
wantErr: false,
},
{
name: "supported format volume policies with pvcLabels (valid map)",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"pvcLabels": map[string]string{
"environment": "production",
"app": "database",
},
},
},
},
},
wantErr: false,
},
{
name: "error format volume policies with pvcLabels (not a map)",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"pvcLabels": "production",
},
},
},
},
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
policies := &Policies{}
err1 := policies.BuildPolicy(tc.res)
err2 := policies.Validate()
if tc.wantErr {
if err1 == nil && err2 == nil {
t.Fatalf("Expected error %v, but not get error", tc.wantErr)
}
} else {
if err1 != nil || err2 != nil {
t.Fatalf("Expected error %v, but got error %v %v", tc.wantErr, err1, err2)
}
}
})
}
}