Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate namespace in velero backup create command #4057

1 change: 1 addition & 0 deletions changelogs/unreleased/4057-codegold79
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Validate namespace in Velero backup create command
9 changes: 8 additions & 1 deletion pkg/cmd/cli/backup/create.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 the Velero contributors.
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.
Expand Down Expand Up @@ -27,6 +27,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeerrs "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/client-go/tools/cache"

velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
Expand All @@ -37,6 +38,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
veleroclient "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
v1 "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/velero/v1"
"github.com/vmware-tanzu/velero/pkg/util/collections"
)

const DefaultBackupTTL time.Duration = 30 * 24 * time.Hour
Expand Down Expand Up @@ -162,6 +164,11 @@ func (o *CreateOptions) Validate(c *cobra.Command, args []string, f client.Facto
return fmt.Errorf("A backup name is required, unless you are creating based on a schedule.")
}

errs := collections.ValidateNamespaceIncludesExcludes(o.IncludeNamespaces, o.ExcludeNamespaces)
if len(errs) > 0 {
return kubeerrs.NewAggregate(errs)
}

if o.StorageLocation != "" {
location := &velerov1api.BackupStorageLocation{}
if err := client.Get(context.Background(), kbclient.ObjectKey{
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/cli/backup/create_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 the Velero contributors.
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.
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/backup_controller.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright the Velero contributors.
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.
Expand Down Expand Up @@ -424,7 +424,7 @@ func (c *backupController) prepareBackupRequest(backup *velerov1api.Backup) *pkg
}

// validate the included/excluded namespaces
for _, err := range collections.ValidateIncludesExcludes(request.Spec.IncludedNamespaces, request.Spec.ExcludedNamespaces) {
for _, err := range collections.ValidateNamespaceIncludesExcludes(request.Spec.IncludedNamespaces, request.Spec.ExcludedNamespaces) {
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded namespace lists: %v", err))
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/backup_deletion_controller_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright the Velero contributors.
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.
Expand Down
45 changes: 44 additions & 1 deletion pkg/util/collections/includes_excludes.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 the Velero contributors.
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.
Expand All @@ -21,6 +21,7 @@ import (

"github.com/gobwas/glob"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/api/validation"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"

Expand Down Expand Up @@ -154,6 +155,48 @@ func ValidateIncludesExcludes(includesList, excludesList []string) []error {
return errs
}

// ValidateNamespaceIncludesExcludes checks provided lists of included and
// excluded namespaces to ensure they are a valid set of IncludesExcludes data.
func ValidateNamespaceIncludesExcludes(includesList, excludesList []string) []error {
errs := ValidateIncludesExcludes(includesList, excludesList)

includes := sets.NewString(includesList...)
excludes := sets.NewString(excludesList...)

for _, itm := range includes.List() {
// Although asterisks is not a valid Kubernetes namespace name, it is
// allowed here.
if itm != "*" {
if nsErrs := validateNamespaceName(itm); nsErrs != nil {
errs = append(errs, nsErrs...)
}
}
}

for _, itm := range excludes.List() {
// Asterisks in excludes list have been checked previously.
if itm != "*" {
if nsErrs := validateNamespaceName(itm); nsErrs != nil {
errs = append(errs, nsErrs...)
}
}
}

return errs
}

func validateNamespaceName(ns string) []error {
var errs []error

if errMsgs := validation.ValidateNamespaceName(ns, false); errMsgs != nil {
for _, msg := range errMsgs {
errs = append(errs, errors.Errorf("invalid namespace %q: %s", ns, msg))
}
}

return errs
}

// GenerateIncludesExcludes constructs an IncludesExcludes struct by taking the provided
// include/exclude slices, applying the specified mapping function to each item in them,
// and adding the output of the function to the new struct. If the mapping function returns
Expand Down
Loading