283 lines
9.1 KiB
Go
283 lines
9.1 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 framework
|
|
|
|
import (
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
|
|
"github.com/vmware-tanzu/velero/pkg/discovery"
|
|
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
|
|
biav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v1"
|
|
biav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2"
|
|
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
|
|
riav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2"
|
|
"github.com/vmware-tanzu/velero/pkg/util/collections"
|
|
)
|
|
|
|
/*
|
|
Velero has a variety of Actions that can be executed on Kubernetes resources. The Actions (BackupItemAction, RestoreItemAction
|
|
and others) implement the Applicable interface which returns a ResourceSelector for the Action. The ResourceSelector
|
|
can specify namespaces, resource names and labels to include or exclude. The ResourceSelector is resolved into lists
|
|
of namespaces and resources present in the backup to be matched against. These lists and the label selector are then used to
|
|
decide whether or not the ResolvedAction should be used for a particular resource.
|
|
*/
|
|
|
|
// ResolvedAction is an action that has had the namespaces, resources names and labels to include or exclude resolved
|
|
type ResolvedAction interface {
|
|
// ShouldUse returns true if the resolved namespaces, resource names and labels match those passed in the parameters.
|
|
// metadata is optional and may be nil
|
|
ShouldUse(groupResource schema.GroupResource, namespace string, metadata metav1.Object,
|
|
log logrus.FieldLogger) bool
|
|
}
|
|
|
|
// resolvedAction is a core struct that holds the resolved namespaces, resource names and labels
|
|
type resolvedAction struct {
|
|
ResourceIncludesExcludes *collections.IncludesExcludes
|
|
NamespaceIncludesExcludes *collections.IncludesExcludes
|
|
Selector labels.Selector
|
|
}
|
|
|
|
func (recv resolvedAction) ShouldUse(groupResource schema.GroupResource, namespace string, metadata metav1.Object,
|
|
log logrus.FieldLogger) bool {
|
|
if !recv.ResourceIncludesExcludes.ShouldInclude(groupResource.String()) {
|
|
log.Debug("Skipping action because it does not apply to this resource")
|
|
return false
|
|
}
|
|
|
|
if namespace != "" && !recv.NamespaceIncludesExcludes.ShouldInclude(namespace) {
|
|
log.Debug("Skipping action because it does not apply to this namespace")
|
|
return false
|
|
}
|
|
|
|
if namespace == "" && !recv.NamespaceIncludesExcludes.IncludeEverything() {
|
|
log.Debug("Skipping action because resource is cluster-scoped and action only applies to specific namespaces")
|
|
return false
|
|
}
|
|
|
|
if metadata != nil && !recv.Selector.Matches(labels.Set(metadata.GetLabels())) {
|
|
log.Debug("Skipping action because label selector does not match")
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// resolveAction resolves the resources, namespaces and selector into fully-qualified versions
|
|
func resolveAction(helper discovery.Helper, action velero.Applicable) (resources *collections.IncludesExcludes,
|
|
namespaces *collections.IncludesExcludes, selector labels.Selector, err error) {
|
|
resourceSelector, err := action.AppliesTo()
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
resources = collections.GetResourceIncludesExcludes(helper, resourceSelector.IncludedResources, resourceSelector.ExcludedResources)
|
|
namespaces = collections.NewIncludesExcludes().Includes(resourceSelector.IncludedNamespaces...).Excludes(resourceSelector.ExcludedNamespaces...)
|
|
|
|
selector = labels.Everything()
|
|
if resourceSelector.LabelSelector != "" {
|
|
if selector, err = labels.Parse(resourceSelector.LabelSelector); err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
type BackupItemResolvedAction struct {
|
|
biav1.BackupItemAction
|
|
resolvedAction
|
|
}
|
|
|
|
func NewBackupItemActionResolver(actions []biav1.BackupItemAction) BackupItemActionResolver {
|
|
return BackupItemActionResolver{
|
|
actions: actions,
|
|
}
|
|
}
|
|
|
|
type BackupItemResolvedActionV2 struct {
|
|
biav2.BackupItemAction
|
|
resolvedAction
|
|
}
|
|
|
|
func NewBackupItemActionResolverV2(actions []biav2.BackupItemAction) BackupItemActionResolverV2 {
|
|
return BackupItemActionResolverV2{
|
|
actions: actions,
|
|
}
|
|
}
|
|
|
|
func NewRestoreItemActionResolver(actions []riav1.RestoreItemAction) RestoreItemActionResolver {
|
|
return RestoreItemActionResolver{
|
|
actions: actions,
|
|
}
|
|
}
|
|
|
|
func NewRestoreItemActionResolverV2(actions []riav2.RestoreItemAction) RestoreItemActionResolverV2 {
|
|
return RestoreItemActionResolverV2{
|
|
actions: actions,
|
|
}
|
|
}
|
|
|
|
func NewDeleteItemActionResolver(actions []velero.DeleteItemAction) DeleteItemActionResolver {
|
|
return DeleteItemActionResolver{
|
|
actions: actions,
|
|
}
|
|
}
|
|
|
|
type ActionResolver interface {
|
|
ResolveAction(helper discovery.Helper, action velero.Applicable, log logrus.FieldLogger) (ResolvedAction, error)
|
|
}
|
|
|
|
type BackupItemActionResolver struct {
|
|
actions []biav1.BackupItemAction
|
|
}
|
|
|
|
func (recv BackupItemActionResolver) ResolveActions(helper discovery.Helper, log logrus.FieldLogger) ([]BackupItemResolvedAction, error) {
|
|
var resolved []BackupItemResolvedAction
|
|
for _, action := range recv.actions {
|
|
resources, namespaces, selector, err := resolveAction(helper, action)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res := BackupItemResolvedAction{
|
|
BackupItemAction: action,
|
|
resolvedAction: resolvedAction{
|
|
ResourceIncludesExcludes: resources,
|
|
NamespaceIncludesExcludes: namespaces,
|
|
Selector: selector,
|
|
},
|
|
}
|
|
resolved = append(resolved, res)
|
|
}
|
|
return resolved, nil
|
|
}
|
|
|
|
type BackupItemActionResolverV2 struct {
|
|
actions []biav2.BackupItemAction
|
|
}
|
|
|
|
func (recv BackupItemActionResolverV2) ResolveActions(helper discovery.Helper, log logrus.FieldLogger) ([]BackupItemResolvedActionV2, error) {
|
|
var resolved []BackupItemResolvedActionV2
|
|
for _, action := range recv.actions {
|
|
log.Debugf("resolving BackupItemAction for: %v", action)
|
|
resources, namespaces, selector, err := resolveAction(helper, action)
|
|
if err != nil {
|
|
log.WithError(errors.WithStack(err)).Debugf("resolveAction error, action: %v", action)
|
|
return nil, err
|
|
}
|
|
res := BackupItemResolvedActionV2{
|
|
BackupItemAction: action,
|
|
resolvedAction: resolvedAction{
|
|
ResourceIncludesExcludes: resources,
|
|
NamespaceIncludesExcludes: namespaces,
|
|
Selector: selector,
|
|
},
|
|
}
|
|
resolved = append(resolved, res)
|
|
}
|
|
return resolved, nil
|
|
}
|
|
|
|
type RestoreItemResolvedAction struct {
|
|
riav1.RestoreItemAction
|
|
resolvedAction
|
|
}
|
|
|
|
type RestoreItemResolvedActionV2 struct {
|
|
riav2.RestoreItemAction
|
|
resolvedAction
|
|
}
|
|
|
|
type RestoreItemActionResolver struct {
|
|
actions []riav1.RestoreItemAction
|
|
}
|
|
|
|
func (recv RestoreItemActionResolver) ResolveActions(helper discovery.Helper, log logrus.FieldLogger) ([]RestoreItemResolvedAction, error) {
|
|
var resolved []RestoreItemResolvedAction
|
|
for _, action := range recv.actions {
|
|
resources, namespaces, selector, err := resolveAction(helper, action)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res := RestoreItemResolvedAction{
|
|
RestoreItemAction: action,
|
|
resolvedAction: resolvedAction{
|
|
ResourceIncludesExcludes: resources,
|
|
NamespaceIncludesExcludes: namespaces,
|
|
Selector: selector,
|
|
},
|
|
}
|
|
resolved = append(resolved, res)
|
|
}
|
|
return resolved, nil
|
|
}
|
|
|
|
type RestoreItemActionResolverV2 struct {
|
|
actions []riav2.RestoreItemAction
|
|
}
|
|
|
|
func (recv RestoreItemActionResolverV2) ResolveActions(helper discovery.Helper, log logrus.FieldLogger) ([]RestoreItemResolvedActionV2, error) {
|
|
var resolved []RestoreItemResolvedActionV2
|
|
for _, action := range recv.actions {
|
|
resources, namespaces, selector, err := resolveAction(helper, action)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res := RestoreItemResolvedActionV2{
|
|
RestoreItemAction: action,
|
|
resolvedAction: resolvedAction{
|
|
ResourceIncludesExcludes: resources,
|
|
NamespaceIncludesExcludes: namespaces,
|
|
Selector: selector,
|
|
},
|
|
}
|
|
resolved = append(resolved, res)
|
|
}
|
|
return resolved, nil
|
|
}
|
|
|
|
type DeleteItemResolvedAction struct {
|
|
velero.DeleteItemAction
|
|
resolvedAction
|
|
}
|
|
|
|
type DeleteItemActionResolver struct {
|
|
actions []velero.DeleteItemAction
|
|
}
|
|
|
|
func (recv DeleteItemActionResolver) ResolveActions(helper discovery.Helper, log logrus.FieldLogger) ([]DeleteItemResolvedAction, error) {
|
|
var resolved []DeleteItemResolvedAction
|
|
for _, action := range recv.actions {
|
|
resources, namespaces, selector, err := resolveAction(helper, action)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res := DeleteItemResolvedAction{
|
|
DeleteItemAction: action,
|
|
resolvedAction: resolvedAction{
|
|
ResourceIncludesExcludes: resources,
|
|
NamespaceIncludesExcludes: namespaces,
|
|
Selector: selector,
|
|
},
|
|
}
|
|
resolved = append(resolved, res)
|
|
}
|
|
return resolved, nil
|
|
}
|