Allows explicit include/exclude of namespaces on restores
- Introduces similar Include/Exclude declaration on the Restore resource and cli flags - Kept support for legacy Namespaces attribute until it could be deprecating. Defining both IncludeNamespaces and Namespaces results in a validation error and the Restore will not be processed (shouldn't be able to occur) Signed-off-by: Justin Nauman <justin.r.nauman@gmail.com>pull/59/head
parent
b20feee7f9
commit
af2a792a9a
|
@ -14,10 +14,11 @@ ark restore create BACKUP
|
|||
### Options
|
||||
|
||||
```
|
||||
--exclude-namespaces stringArray namespaces to exclude from the backup
|
||||
--include-namespaces stringArray namespaces to include in the backup (use '*' for all namespaces) (default *)
|
||||
--label-columns stringArray a comma-separated list of labels to be displayed as columns
|
||||
--labels mapStringString labels to apply to the restore
|
||||
--namespace-mappings mapStringString namespace mappings from name in the backup to desired restored name in the form src1:dst1,src2:dst2,...
|
||||
--namespaces stringArray comma-separated list of namespaces to restore
|
||||
-o, --output string Output display format. For create commands, display the object but do not send it to the server. Valid formats are 'table', 'json', and 'yaml'.
|
||||
--restore-volumes optionalBool[=true] whether to restore volumes from snapshots
|
||||
-l, --selector labelSelector only restore resources matching this label selector (default <none>)
|
||||
|
|
|
@ -24,9 +24,19 @@ type RestoreSpec struct {
|
|||
// from.
|
||||
BackupName string `json:"backupName"`
|
||||
|
||||
// NOTE: This is deprecated. IncludedNamespaces and ExcludedNamespaces
|
||||
// should be used instead
|
||||
// Namespaces is a slice of namespaces in the Ark backup to restore.
|
||||
Namespaces []string `json:"namespaces"`
|
||||
|
||||
// IncludedNamespaces is a slice of namespace names to include objects
|
||||
// from. If empty, all namespaces are included.
|
||||
IncludedNamespaces []string `json:"includedNamespaces"`
|
||||
|
||||
// ExcludedNamespaces contains a list of namespaces that are not
|
||||
// included in the backup.
|
||||
ExcludedNamespaces []string `json:"excludedNamespaces"`
|
||||
|
||||
// NamespaceMapping is a map of source namespace names
|
||||
// to target namespace names to restore into. Any source
|
||||
// namespaces not included in the map will be restored into
|
||||
|
|
|
@ -57,7 +57,8 @@ type CreateOptions struct {
|
|||
BackupName string
|
||||
RestoreVolumes flag.OptionalBool
|
||||
Labels flag.Map
|
||||
Namespaces flag.StringArray
|
||||
IncludeNamespaces flag.StringArray
|
||||
ExcludeNamespaces flag.StringArray
|
||||
NamespaceMappings flag.Map
|
||||
Selector flag.LabelSelector
|
||||
}
|
||||
|
@ -65,15 +66,17 @@ type CreateOptions struct {
|
|||
func NewCreateOptions() *CreateOptions {
|
||||
return &CreateOptions{
|
||||
Labels: flag.NewMap(),
|
||||
IncludeNamespaces: flag.NewStringArray("*"),
|
||||
NamespaceMappings: flag.NewMap().WithEntryDelimiter(",").WithKeyValueDelimiter(":"),
|
||||
RestoreVolumes: flag.NewOptionalBool(nil),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *CreateOptions) BindFlags(flags *pflag.FlagSet) {
|
||||
flags.Var(&o.Labels, "labels", "labels to apply to the restore")
|
||||
flags.Var(&o.Namespaces, "namespaces", "comma-separated list of namespaces to restore")
|
||||
flags.Var(&o.IncludeNamespaces, "include-namespaces", "namespaces to include in the backup (use '*' for all namespaces)")
|
||||
flags.Var(&o.ExcludeNamespaces, "exclude-namespaces", "namespaces to exclude from the backup")
|
||||
flags.Var(&o.NamespaceMappings, "namespace-mappings", "namespace mappings from name in the backup to desired restored name in the form src1:dst1,src2:dst2,...")
|
||||
flags.Var(&o.Labels, "labels", "labels to apply to the restore")
|
||||
flags.VarP(&o.Selector, "selector", "l", "only restore resources matching this label selector")
|
||||
f := flags.VarPF(&o.RestoreVolumes, "restore-volumes", "", "whether to restore volumes from snapshots")
|
||||
// this allows the user to just specify "--restore-volumes" as shorthand for "--restore-volumes=true"
|
||||
|
@ -111,11 +114,12 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
|
|||
Labels: o.Labels.Data(),
|
||||
},
|
||||
Spec: api.RestoreSpec{
|
||||
BackupName: o.BackupName,
|
||||
Namespaces: o.Namespaces,
|
||||
NamespaceMapping: o.NamespaceMappings.Data(),
|
||||
LabelSelector: o.Selector.LabelSelector,
|
||||
RestorePVs: o.RestoreVolumes.Value,
|
||||
BackupName: o.BackupName,
|
||||
IncludedNamespaces: o.IncludeNamespaces,
|
||||
ExcludedNamespaces: o.ExcludeNamespaces,
|
||||
NamespaceMapping: o.NamespaceMappings.Data(),
|
||||
LabelSelector: o.Selector.LabelSelector,
|
||||
RestorePVs: o.RestoreVolumes.Value,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -224,10 +224,17 @@ func (controller *restoreController) processRestore(key string) error {
|
|||
restore.Status.Phase = api.RestorePhaseFailedValidation
|
||||
} else {
|
||||
restore.Status.Phase = api.RestorePhaseInProgress
|
||||
}
|
||||
|
||||
if len(restore.Spec.Namespaces) == 0 {
|
||||
restore.Spec.Namespaces = []string{"*"}
|
||||
if len(restore.Spec.Namespaces) != 0 {
|
||||
glog.V(4).Info("the restore.Spec.Namespaces field has been deprecated. Please use the IncludedNamespaces and ExcludedNamespaces feature instead")
|
||||
|
||||
restore.Spec.IncludedNamespaces = restore.Spec.Namespaces
|
||||
restore.Spec.Namespaces = nil
|
||||
}
|
||||
|
||||
if len(restore.Spec.IncludedNamespaces) == 0 {
|
||||
restore.Spec.IncludedNamespaces = []string{"*"}
|
||||
}
|
||||
}
|
||||
|
||||
// update status
|
||||
|
@ -278,6 +285,10 @@ func (controller *restoreController) getValidationErrors(itm *api.Restore) []str
|
|||
validationErrors = append(validationErrors, "BackupName must be non-empty and correspond to the name of a backup in object storage.")
|
||||
}
|
||||
|
||||
if len(itm.Spec.Namespaces) > 0 && len(itm.Spec.IncludedNamespaces) > 0 {
|
||||
validationErrors = append(validationErrors, "Namespace and ItemNamespaces can not both be defined on the backup spec.")
|
||||
}
|
||||
|
||||
if !controller.pvProviderExists && itm.Spec.RestorePVs != nil && *itm.Spec.RestorePVs {
|
||||
validationErrors = append(validationErrors, "Server is not configured for PV snapshot restores")
|
||||
}
|
||||
|
|
|
@ -73,24 +73,37 @@ func TestProcessRestore(t *testing.T) {
|
|||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "new restore with empty backup name fails validation",
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithRestorableNamespace("ns-1").Restore,
|
||||
name: "restore with both namespaces and includedNamespaces fails validation",
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithNamespace("ns-1").WithIncludedNamespace("another-1").Restore,
|
||||
backup: NewTestBackup().WithName("backup-1").Backup,
|
||||
expectedErr: false,
|
||||
expectedRestoreUpdates: []*api.Restore{
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseFailedValidation).
|
||||
WithRestorableNamespace("ns-1").
|
||||
WithBackup("backup-1").
|
||||
WithNamespace("ns-1").
|
||||
WithIncludedNamespace("another-1").
|
||||
WithValidationError("Namespace and ItemNamespaces can not both be defined on the backup spec.").Restore,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "new restore with empty backup name fails validation",
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithIncludedNamespace("ns-1").Restore,
|
||||
expectedErr: false,
|
||||
expectedRestoreUpdates: []*api.Restore{
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseFailedValidation).
|
||||
WithIncludedNamespace("ns-1").
|
||||
WithValidationError("BackupName must be non-empty and correspond to the name of a backup in object storage.").Restore,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "restore with non-existent backup name fails",
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithRestorableNamespace("ns-1").Restore,
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithIncludedNamespace("ns-1").Restore,
|
||||
expectedErr: false,
|
||||
expectedRestoreUpdates: []*api.Restore{
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithRestorableNamespace("ns-1").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithIncludedNamespace("ns-1").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseCompleted).
|
||||
WithBackup("backup-1").
|
||||
WithRestorableNamespace("ns-1").
|
||||
WithIncludedNamespace("ns-1").
|
||||
WithErrors(api.RestoreResult{
|
||||
Cluster: []string{"backup.ark.heptio.com \"backup-1\" not found"},
|
||||
}).
|
||||
|
@ -99,33 +112,33 @@ func TestProcessRestore(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "restorer throwing an error causes the restore to fail",
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithRestorableNamespace("ns-1").Restore,
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithIncludedNamespace("ns-1").Restore,
|
||||
backup: NewTestBackup().WithName("backup-1").Backup,
|
||||
restorerError: errors.New("blarg"),
|
||||
expectedErr: false,
|
||||
expectedRestoreUpdates: []*api.Restore{
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithRestorableNamespace("ns-1").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithIncludedNamespace("ns-1").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseCompleted).
|
||||
WithBackup("backup-1").
|
||||
WithRestorableNamespace("ns-1").
|
||||
WithIncludedNamespace("ns-1").
|
||||
WithErrors(api.RestoreResult{
|
||||
Namespaces: map[string][]string{
|
||||
"ns-1": {"blarg"},
|
||||
},
|
||||
}).Restore,
|
||||
},
|
||||
expectedRestorerCall: NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithRestorableNamespace("ns-1").Restore,
|
||||
expectedRestorerCall: NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithIncludedNamespace("ns-1").Restore,
|
||||
},
|
||||
{
|
||||
name: "valid restore gets executed",
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithRestorableNamespace("ns-1").Restore,
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithIncludedNamespace("ns-1").Restore,
|
||||
backup: NewTestBackup().WithName("backup-1").Backup,
|
||||
expectedErr: false,
|
||||
expectedRestoreUpdates: []*api.Restore{
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithRestorableNamespace("ns-1").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseCompleted).WithBackup("backup-1").WithRestorableNamespace("ns-1").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithIncludedNamespace("ns-1").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseCompleted).WithBackup("backup-1").WithIncludedNamespace("ns-1").Restore,
|
||||
},
|
||||
expectedRestorerCall: NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithRestorableNamespace("ns-1").Restore,
|
||||
expectedRestorerCall: NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithIncludedNamespace("ns-1").Restore,
|
||||
},
|
||||
{
|
||||
name: "restore with no restorable namespaces gets defaulted to *",
|
||||
|
@ -133,30 +146,30 @@ func TestProcessRestore(t *testing.T) {
|
|||
backup: NewTestBackup().WithName("backup-1").Backup,
|
||||
expectedErr: false,
|
||||
expectedRestoreUpdates: []*api.Restore{
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithRestorableNamespace("*").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseCompleted).WithBackup("backup-1").WithRestorableNamespace("*").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithIncludedNamespace("*").Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseCompleted).WithBackup("backup-1").WithIncludedNamespace("*").Restore,
|
||||
},
|
||||
expectedRestorerCall: NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithRestorableNamespace("*").Restore,
|
||||
expectedRestorerCall: NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithIncludedNamespace("*").Restore,
|
||||
},
|
||||
{
|
||||
name: "valid restore with RestorePVs=true gets executed when allowRestoreSnapshots=true",
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithRestorableNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithIncludedNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
backup: NewTestBackup().WithName("backup-1").Backup,
|
||||
allowRestoreSnapshots: true,
|
||||
expectedErr: false,
|
||||
expectedRestoreUpdates: []*api.Restore{
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithRestorableNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseCompleted).WithBackup("backup-1").WithRestorableNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithIncludedNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseCompleted).WithBackup("backup-1").WithIncludedNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
},
|
||||
expectedRestorerCall: NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithRestorableNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
expectedRestorerCall: NewTestRestore("foo", "bar", api.RestorePhaseInProgress).WithBackup("backup-1").WithIncludedNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
},
|
||||
{
|
||||
name: "restore with RestorePVs=true fails validation when allowRestoreSnapshots=false",
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithRestorableNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
restore: NewTestRestore("foo", "bar", api.RestorePhaseNew).WithBackup("backup-1").WithIncludedNamespace("ns-1").WithRestorePVs(true).Restore,
|
||||
backup: NewTestBackup().WithName("backup-1").Backup,
|
||||
expectedErr: false,
|
||||
expectedRestoreUpdates: []*api.Restore{
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseFailedValidation).WithBackup("backup-1").WithRestorableNamespace("ns-1").WithRestorePVs(true).
|
||||
NewTestRestore("foo", "bar", api.RestorePhaseFailedValidation).WithBackup("backup-1").WithIncludedNamespace("ns-1").WithRestorePVs(true).
|
||||
WithValidationError("Server is not configured for PV snapshot restores").Restore,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -46,6 +46,7 @@ import (
|
|||
arkv1client "github.com/heptio/ark/pkg/generated/clientset/typed/ark/v1"
|
||||
"github.com/heptio/ark/pkg/restore/restorers"
|
||||
"github.com/heptio/ark/pkg/util/kube"
|
||||
"github.com/heptio/ark/pkg/util/collections"
|
||||
)
|
||||
|
||||
// Restorer knows how to restore a backup.
|
||||
|
@ -225,18 +226,18 @@ func (kr *kubernetesRestorer) restoreFromDir(
|
|||
return warnings, errors
|
||||
}
|
||||
|
||||
namespacesToRestore := sets.NewString(restore.Spec.Namespaces...)
|
||||
namespaceFilter := collections.NewIncludesExcludes().Includes(restore.Spec.IncludedNamespaces...).Excludes(restore.Spec.ExcludedNamespaces...)
|
||||
for _, ns := range nses {
|
||||
if !ns.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
nsPath := path.Join(namespacesPath, ns.Name())
|
||||
|
||||
if !namespacesToRestore.Has("*") && !namespacesToRestore.Has(ns.Name()) {
|
||||
if !namespaceFilter.ShouldInclude(ns.Name()) {
|
||||
glog.Infof("Skipping namespace %s", ns.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
w, e := kr.restoreNamespace(restore, ns.Name(), nsPath, prioritizedResources, selector, backup)
|
||||
merge(&warnings, &w)
|
||||
merge(&errors, &e)
|
||||
|
@ -453,7 +454,7 @@ func (kr *kubernetesRestorer) restoreResourceForNamespace(
|
|||
// add an ark-restore label to each resource for easy ID
|
||||
addLabel(unstructuredObj, api.RestoreLabelKey, restore.Name)
|
||||
|
||||
glog.Infof("Restoring item %v", unstructuredObj.GetName())
|
||||
glog.Infof("Restoring %s: %v", obj.GroupVersionKind().Kind, unstructuredObj.GetName())
|
||||
_, err = resourceClient.Create(unstructuredObj)
|
||||
if apierrors.IsAlreadyExists(err) {
|
||||
addToResult(&warnings, namespace, err)
|
||||
|
|
|
@ -102,16 +102,37 @@ func TestRestoreMethod(t *testing.T) {
|
|||
name: "namespacesToRestore having * restores all namespaces",
|
||||
fileSystem: newFakeFileSystem().WithDirectories("bak/cluster", "bak/namespaces/a", "bak/namespaces/b", "bak/namespaces/c"),
|
||||
baseDir: "bak",
|
||||
restore: &api.Restore{Spec: api.RestoreSpec{Namespaces: []string{"*"}}},
|
||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
||||
expectedReadDirs: []string{"bak/cluster", "bak/namespaces", "bak/namespaces/a", "bak/namespaces/b", "bak/namespaces/c"},
|
||||
},
|
||||
{
|
||||
name: "namespacesToRestore properly filters",
|
||||
fileSystem: newFakeFileSystem().WithDirectories("bak/cluster", "bak/namespaces/a", "bak/namespaces/b", "bak/namespaces/c"),
|
||||
baseDir: "bak",
|
||||
restore: &api.Restore{Spec: api.RestoreSpec{Namespaces: []string{"b", "c"}}},
|
||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"b", "c"}}},
|
||||
expectedReadDirs: []string{"bak/cluster", "bak/namespaces", "bak/namespaces/b", "bak/namespaces/c"},
|
||||
},
|
||||
{
|
||||
name: "namespacesToRestore properly filters with inclusion filter",
|
||||
fileSystem: newFakeFileSystem().WithDirectories("bak/cluster", "bak/namespaces/a", "bak/namespaces/b", "bak/namespaces/c"),
|
||||
baseDir: "bak",
|
||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"b", "c"}}},
|
||||
expectedReadDirs: []string{"bak/cluster", "bak/namespaces", "bak/namespaces/b", "bak/namespaces/c"},
|
||||
},
|
||||
{
|
||||
name: "namespacesToRestore properly filters with exclusion filter",
|
||||
fileSystem: newFakeFileSystem().WithDirectories("bak/cluster", "bak/namespaces/a", "bak/namespaces/b", "bak/namespaces/c"),
|
||||
baseDir: "bak",
|
||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}, ExcludedNamespaces: []string{"a"}}},
|
||||
expectedReadDirs: []string{"bak/cluster", "bak/namespaces", "bak/namespaces/b", "bak/namespaces/c"},
|
||||
},
|
||||
{
|
||||
name: "namespacesToRestore properly filters with inclusion & exclusion filters",
|
||||
fileSystem: newFakeFileSystem().WithDirectories("bak/cluster", "bak/namespaces/a", "bak/namespaces/b", "bak/namespaces/c"),
|
||||
baseDir: "bak",
|
||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"a", "b", "c"}, ExcludedNamespaces: []string{"b"}}},
|
||||
expectedReadDirs: []string{"bak/cluster", "bak/namespaces", "bak/namespaces/a", "bak/namespaces/c"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
@ -37,13 +37,10 @@ func (nsr *namespaceRestorer) Handles(obj runtime.Unstructured, restore *api.Res
|
|||
return false
|
||||
}
|
||||
|
||||
for _, restorableNS := range restore.Spec.Namespaces {
|
||||
if restorableNS == nsName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return collections.NewIncludesExcludes().
|
||||
Includes(restore.Spec.IncludedNamespaces...).
|
||||
Excludes(restore.Spec.ExcludedNamespaces...).
|
||||
ShouldInclude(nsName)
|
||||
}
|
||||
|
||||
func (nsr *namespaceRestorer) Prepare(obj runtime.Unstructured, restore *api.Restore, backup *api.Backup) (runtime.Unstructured, error, error) {
|
||||
|
|
|
@ -37,19 +37,31 @@ func TestHandles(t *testing.T) {
|
|||
{
|
||||
name: "restorable NS",
|
||||
obj: NewTestUnstructured().WithName("ns-1").Unstructured,
|
||||
restore: testutil.NewDefaultTestRestore().WithRestorableNamespace("ns-1").Restore,
|
||||
restore: testutil.NewDefaultTestRestore().WithIncludedNamespace("ns-1").Restore,
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
name: "restorable NS via wildcard",
|
||||
obj: NewTestUnstructured().WithName("ns-1").Unstructured,
|
||||
restore: testutil.NewDefaultTestRestore().WithIncludedNamespace("*").Restore,
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
name: "non-restorable NS",
|
||||
obj: NewTestUnstructured().WithName("ns-1").Unstructured,
|
||||
restore: testutil.NewDefaultTestRestore().WithRestorableNamespace("ns-2").Restore,
|
||||
restore: testutil.NewDefaultTestRestore().WithIncludedNamespace("ns-2").Restore,
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
name: "namespace is explicitly excluded",
|
||||
obj: NewTestUnstructured().WithName("ns-1").Unstructured,
|
||||
restore: testutil.NewDefaultTestRestore().WithIncludedNamespace("*").WithExcludedNamespace("ns-1").Restore,
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
name: "namespace obj doesn't have name",
|
||||
obj: NewTestUnstructured().WithMetadata().Unstructured,
|
||||
restore: testutil.NewDefaultTestRestore().WithRestorableNamespace("ns-1").Restore,
|
||||
restore: testutil.NewDefaultTestRestore().WithIncludedNamespace("ns-1").Restore,
|
||||
expect: false,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -45,11 +45,22 @@ func NewDefaultTestRestore() *TestRestore {
|
|||
return NewTestRestore(api.DefaultNamespace, "", api.RestorePhase(""))
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithRestorableNamespace(name string) *TestRestore {
|
||||
|
||||
func (r *TestRestore) WithNamespace(name string) *TestRestore {
|
||||
r.Spec.Namespaces = append(r.Spec.Namespaces, name)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithIncludedNamespace(name string) *TestRestore {
|
||||
r.Spec.IncludedNamespaces = append(r.Spec.IncludedNamespaces, name)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithExcludedNamespace(name string) *TestRestore {
|
||||
r.Spec.ExcludedNamespaces = append(r.Spec.ExcludedNamespaces, name)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithValidationError(err string) *TestRestore {
|
||||
r.Status.ValidationErrors = append(r.Status.ValidationErrors, err)
|
||||
return r
|
||||
|
|
Loading…
Reference in New Issue