mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-08 14:21:18 +00:00
Add include/exclude policy to resources policy
fixes #8610 This commit extends the resources policy, such that user can define resource include exclude filters in the policy and reuse it in different backups. Signed-off-by: Daniel Jiang <daniel.jiang@broadcom.com>
This commit is contained in:
@@ -13,6 +13,7 @@ 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 (
|
||||
@@ -20,6 +21,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
@@ -49,24 +52,58 @@ type Action struct {
|
||||
Parameters map[string]any `yaml:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// volumePolicy defined policy to conditions to match Volumes and related action to handle matched Volumes
|
||||
// IncludeExcludePolicy defined policy to include or exclude resources based on the names
|
||||
type IncludeExcludePolicy struct {
|
||||
// The following fields have the same semantics as those from the spec of backup.
|
||||
// Refer to the comment in the velerov1api.BackupSpec for more details.
|
||||
IncludedClusterScopedResources []string `yaml:"includedClusterScopedResources"`
|
||||
ExcludedClusterScopedResources []string `yaml:"excludedClusterScopedResources"`
|
||||
IncludedNamespaceScopedResources []string `yaml:"includedNamespaceScopedResources"`
|
||||
ExcludedNamespaceScopedResources []string `yaml:"excludedNamespaceScopedResources"`
|
||||
}
|
||||
|
||||
func (p *IncludeExcludePolicy) Validate() error {
|
||||
if err := p.validateIncludeExclude(p.IncludedClusterScopedResources, p.ExcludedClusterScopedResources); err != nil {
|
||||
return err
|
||||
}
|
||||
return p.validateIncludeExclude(p.IncludedNamespaceScopedResources, p.ExcludedNamespaceScopedResources)
|
||||
}
|
||||
|
||||
func (p *IncludeExcludePolicy) validateIncludeExclude(includesList, excludesList []string) error {
|
||||
includes := sets.NewString(includesList...)
|
||||
excludes := sets.NewString(excludesList...)
|
||||
|
||||
if includes.Has("*") || excludes.Has("*") {
|
||||
return fmt.Errorf("cannot use '*' in includes or excludes filters in the policy")
|
||||
}
|
||||
for _, itm := range excludes.List() {
|
||||
if includes.Has(itm) {
|
||||
return fmt.Errorf("excludes list cannot contain an item in the includes list: %s", itm)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VolumePolicy defined policy to conditions to match Volumes and related action to handle matched Volumes
|
||||
type VolumePolicy struct {
|
||||
// Conditions defined list of conditions to match Volumes
|
||||
Conditions map[string]any `yaml:"conditions"`
|
||||
Action Action `yaml:"action"`
|
||||
}
|
||||
|
||||
// resourcePolicies currently defined slice of volume policies to handle backup
|
||||
// ResourcePolicies currently defined slice of volume policies to handle backup
|
||||
type ResourcePolicies struct {
|
||||
Version string `yaml:"version"`
|
||||
VolumePolicies []VolumePolicy `yaml:"volumePolicies"`
|
||||
Version string `yaml:"version"`
|
||||
VolumePolicies []VolumePolicy `yaml:"volumePolicies"`
|
||||
IncludeExcludePolicy *IncludeExcludePolicy `yaml:"includeExcludePolicy"`
|
||||
// we may support other resource policies in the future, and they could be added separately
|
||||
// OtherResourcePolicies []OtherResourcePolicy
|
||||
}
|
||||
|
||||
type Policies struct {
|
||||
version string
|
||||
volumePolicies []volPolicy
|
||||
version string
|
||||
volumePolicies []volPolicy
|
||||
includeExcludePolicy *IncludeExcludePolicy
|
||||
// OtherPolicies
|
||||
}
|
||||
|
||||
@@ -115,6 +152,7 @@ func (p *Policies) BuildPolicy(resPolicies *ResourcePolicies) error {
|
||||
// Other resource policies
|
||||
|
||||
p.version = resPolicies.Version
|
||||
p.includeExcludePolicy = resPolicies.IncludeExcludePolicy
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -175,9 +213,20 @@ func (p *Policies) Validate() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.GetIncludeExcludePolicy() != nil {
|
||||
if err := p.GetIncludeExcludePolicy().Validate(); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Policies) GetIncludeExcludePolicy() *IncludeExcludePolicy {
|
||||
return p.includeExcludePolicy
|
||||
}
|
||||
|
||||
func GetResourcePoliciesFromBackup(
|
||||
backup velerov1api.Backup,
|
||||
client crclient.Client,
|
||||
|
||||
@@ -453,6 +453,102 @@ func TestValidate(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: " '*' in the filters of include exclude policy - 1",
|
||||
res: &ResourcePolicies{
|
||||
Version: "v1",
|
||||
VolumePolicies: []VolumePolicy{
|
||||
{
|
||||
Action: Action{Type: "skip"},
|
||||
Conditions: map[string]any{
|
||||
"pvcLabels": map[string]string{
|
||||
"environment": "production",
|
||||
"app": "database",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
IncludeExcludePolicy: &IncludeExcludePolicy{
|
||||
IncludedClusterScopedResources: []string{"*"},
|
||||
ExcludedClusterScopedResources: []string{"crds"},
|
||||
IncludedNamespaceScopedResources: []string{"pods"},
|
||||
ExcludedNamespaceScopedResources: []string{"secrets"},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: " '*' in the filters of include exclude policy - 2",
|
||||
res: &ResourcePolicies{
|
||||
Version: "v1",
|
||||
VolumePolicies: []VolumePolicy{
|
||||
{
|
||||
Action: Action{Type: "skip"},
|
||||
Conditions: map[string]any{
|
||||
"pvcLabels": map[string]string{
|
||||
"environment": "production",
|
||||
"app": "database",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
IncludeExcludePolicy: &IncludeExcludePolicy{
|
||||
IncludedClusterScopedResources: []string{"persistentvolumes"},
|
||||
ExcludedClusterScopedResources: []string{"crds"},
|
||||
IncludedNamespaceScopedResources: []string{"pods"},
|
||||
ExcludedNamespaceScopedResources: []string{"*"},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: " dup item in both the include and exclude filters of include exclude policy",
|
||||
res: &ResourcePolicies{
|
||||
Version: "v1",
|
||||
VolumePolicies: []VolumePolicy{
|
||||
{
|
||||
Action: Action{Type: "skip"},
|
||||
Conditions: map[string]any{
|
||||
"pvcLabels": map[string]string{
|
||||
"environment": "production",
|
||||
"app": "database",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
IncludeExcludePolicy: &IncludeExcludePolicy{
|
||||
IncludedClusterScopedResources: []string{"persistentvolumes"},
|
||||
ExcludedClusterScopedResources: []string{"crds"},
|
||||
IncludedNamespaceScopedResources: []string{"pods", "configmaps"},
|
||||
ExcludedNamespaceScopedResources: []string{"secrets", "pods"},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: " valid volume policies and valid include/exclude policy",
|
||||
res: &ResourcePolicies{
|
||||
Version: "v1",
|
||||
VolumePolicies: []VolumePolicy{
|
||||
{
|
||||
Action: Action{Type: "skip"},
|
||||
Conditions: map[string]any{
|
||||
"pvcLabels": map[string]string{
|
||||
"environment": "production",
|
||||
"app": "database",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
IncludeExcludePolicy: &IncludeExcludePolicy{
|
||||
IncludedClusterScopedResources: []string{"persistentvolumes"},
|
||||
ExcludedClusterScopedResources: []string{"crds"},
|
||||
IncludedNamespaceScopedResources: []string{"pods", "configmaps"},
|
||||
ExcludedNamespaceScopedResources: []string{"secrets"},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user