From 4e25f59dc1d8ec257b6b4e27834bb00e33ccccf7 Mon Sep 17 00:00:00 2001 From: Daniel Jiang Date: Tue, 16 Aug 2022 13:50:28 +0800 Subject: [PATCH] Add parameter "uploader-type" to velero server (#5212) This commit adds the parameter "uploader-type" to velero server, add exposes the setting via "velero install" in CLI. fixes #5062 Signed-off-by: Daniel Jiang Signed-off-by: Daniel Jiang --- changelogs/unreleased/5212-reasonerjt | 1 + pkg/cmd/cli/install/install.go | 10 ++++++++ pkg/cmd/server/server.go | 9 +++++++ pkg/install/deployment.go | 12 +++++++++- pkg/install/deployment_test.go | 4 ++++ pkg/install/resources.go | 2 ++ pkg/uploader/types.go | 26 +++++++++++++++++--- pkg/uploader/types_test.go | 34 +++++++++++++++++++++++++++ 8 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/5212-reasonerjt create mode 100644 pkg/uploader/types_test.go diff --git a/changelogs/unreleased/5212-reasonerjt b/changelogs/unreleased/5212-reasonerjt new file mode 100644 index 0000000000..be58b9adb7 --- /dev/null +++ b/changelogs/unreleased/5212-reasonerjt @@ -0,0 +1 @@ +Add parameter "uploader-type" to velero server \ No newline at end of file diff --git a/pkg/cmd/cli/install/install.go b/pkg/cmd/cli/install/install.go index 0f1819fa86..a908ff23f6 100644 --- a/pkg/cmd/cli/install/install.go +++ b/pkg/cmd/cli/install/install.go @@ -24,6 +24,8 @@ import ( "strings" "time" + "github.com/vmware-tanzu/velero/pkg/uploader" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -74,6 +76,7 @@ type InstallOptions struct { CACertFile string Features string DefaultVolumesToRestic bool + UploaderType string } // BindFlags adds command line values to the options struct. @@ -110,6 +113,7 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) { flags.StringVar(&o.CACertFile, "cacert", o.CACertFile, "File containing a certificate bundle to use when verifying TLS connections to the object store. Optional.") flags.StringVar(&o.Features, "features", o.Features, "Comma separated list of Velero feature flags to be set on the Velero deployment and the restic daemonset, if restic is enabled") flags.BoolVar(&o.DefaultVolumesToRestic, "default-volumes-to-restic", o.DefaultVolumesToRestic, "Bool flag to configure Velero server to use restic by default to backup all pod volumes on all backups. Optional.") + flags.StringVar(&o.UploaderType, "uploader-type", o.UploaderType, fmt.Sprintf("The type of uploader to transfer the data of pod volumes, the supported values are '%s', '%s'", uploader.ResticType, uploader.KopiaType)) } // NewInstallOptions instantiates a new, default InstallOptions struct. @@ -135,6 +139,7 @@ func NewInstallOptions() *InstallOptions { NoDefaultBackupLocation: false, CRDsOnly: false, DefaultVolumesToRestic: false, + UploaderType: uploader.ResticType, } } @@ -195,6 +200,7 @@ func (o *InstallOptions) AsVeleroOptions() (*install.VeleroOptions, error) { CACertData: caCertData, Features: strings.Split(o.Features, ","), DefaultVolumesToRestic: o.DefaultVolumesToRestic, + UploaderType: o.UploaderType, }, nil } @@ -327,6 +333,10 @@ func (o *InstallOptions) Validate(c *cobra.Command, args []string, f client.Fact return err } + if err := uploader.ValidateUploaderType(o.UploaderType); err != nil { + return err + } + // If we're only installing CRDs, we can skip the rest of the validation. if o.CRDsOnly { return nil diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index f45a302207..8a0251f1b3 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -27,6 +27,8 @@ import ( "strings" "time" + "github.com/vmware-tanzu/velero/pkg/uploader" + "github.com/bombsimon/logrusr" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -127,6 +129,7 @@ type serverConfig struct { defaultResticMaintenanceFrequency time.Duration garbageCollectionFrequency time.Duration defaultVolumesToRestic bool + uploaderType string } type controllerRunInfo struct { @@ -157,6 +160,7 @@ func NewCommand(f client.Factory) *cobra.Command { formatFlag: logging.NewFormatFlag(), defaultResticMaintenanceFrequency: restic.DefaultMaintenanceFrequency, defaultVolumesToRestic: restic.DefaultVolumesToRestic, + uploaderType: uploader.ResticType, } ) @@ -222,6 +226,7 @@ func NewCommand(f client.Factory) *cobra.Command { command.Flags().DurationVar(&config.defaultResticMaintenanceFrequency, "default-restic-prune-frequency", config.defaultResticMaintenanceFrequency, "How often 'restic prune' is run for restic repositories by default.") command.Flags().DurationVar(&config.garbageCollectionFrequency, "garbage-collection-frequency", config.garbageCollectionFrequency, "How often garbage collection is run for expired backups.") command.Flags().BoolVar(&config.defaultVolumesToRestic, "default-volumes-to-restic", config.defaultVolumesToRestic, "Backup all volumes with restic by default.") + command.Flags().StringVar(&config.uploaderType, "uploader-type", config.uploaderType, "Type of uploader to handle the transfer of data of pod volumes") return command } @@ -251,6 +256,10 @@ type server struct { } func newServer(f client.Factory, config serverConfig, logger *logrus.Logger) (*server, error) { + if err := uploader.ValidateUploaderType(config.uploaderType); err != nil { + return nil, err + } + if config.clientQPS < 0.0 { return nil, errors.New("client-qps must be positive") } diff --git a/pkg/install/deployment.go b/pkg/install/deployment.go index ebeb936f61..cf34f175f1 100644 --- a/pkg/install/deployment.go +++ b/pkg/install/deployment.go @@ -44,6 +44,7 @@ type podTemplateConfig struct { plugins []string features []string defaultVolumesToRestic bool + uploaderType string } func WithImage(image string) podTemplateOption { @@ -83,7 +84,6 @@ func WithEnvFromSecretKey(varName, secret, key string) podTemplateOption { func WithSecret(secretPresent bool) podTemplateOption { return func(c *podTemplateConfig) { c.withSecret = secretPresent - } } @@ -123,6 +123,12 @@ func WithFeatures(features []string) podTemplateOption { } } +func WithUploaderType(t string) podTemplateOption { + return func(c *podTemplateConfig) { + c.uploaderType = t + } +} + func WithDefaultVolumesToRestic() podTemplateOption { return func(c *podTemplateConfig) { c.defaultVolumesToRestic = true @@ -155,6 +161,10 @@ func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment args = append(args, "--default-volumes-to-restic=true") } + if len(c.uploaderType) > 0 { + args = append(args, fmt.Sprintf("--uploader-type=%s", c.uploaderType)) + } + deployment := &appsv1.Deployment{ ObjectMeta: objectMeta(namespace, "velero"), TypeMeta: metav1.TypeMeta{ diff --git a/pkg/install/deployment_test.go b/pkg/install/deployment_test.go index 616db03246..ef5f871a06 100644 --- a/pkg/install/deployment_test.go +++ b/pkg/install/deployment_test.go @@ -57,4 +57,8 @@ func TestDeployment(t *testing.T) { deploy = Deployment("velero", WithFeatures([]string{"EnableCSI", "foo", "bar", "baz"})) assert.Len(t, deploy.Spec.Template.Spec.Containers[0].Args, 2) assert.Equal(t, "--features=EnableCSI,foo,bar,baz", deploy.Spec.Template.Spec.Containers[0].Args[1]) + + deploy = Deployment("velero", WithUploaderType("kopia")) + assert.Len(t, deploy.Spec.Template.Spec.Containers[0].Args, 2) + assert.Equal(t, "--uploader-type=kopia", deploy.Spec.Template.Spec.Containers[0].Args[1]) } diff --git a/pkg/install/resources.go b/pkg/install/resources.go index 78a9ed6891..7053b87c59 100644 --- a/pkg/install/resources.go +++ b/pkg/install/resources.go @@ -232,6 +232,7 @@ type VeleroOptions struct { CACertData []byte Features []string DefaultVolumesToRestic bool + UploaderType string } func AllCRDs() *unstructured.UnstructuredList { @@ -287,6 +288,7 @@ func AllResources(o *VeleroOptions) *unstructured.UnstructuredList { WithSecret(secretPresent), WithDefaultResticMaintenanceFrequency(o.DefaultResticMaintenanceFrequency), WithGarbageCollectionFrequency(o.GarbageCollectionFrequency), + WithUploaderType(o.UploaderType), } if len(o.Features) > 0 { diff --git a/pkg/uploader/types.go b/pkg/uploader/types.go index 27a864c844..134e36cceb 100644 --- a/pkg/uploader/types.go +++ b/pkg/uploader/types.go @@ -1,9 +1,12 @@ /* -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. 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. @@ -13,11 +16,28 @@ limitations under the License. package uploader +import ( + "fmt" + "strings" +) + const ( - VeleroBackup string = "backup" - VeleroRestore string = "restore" + ResticType = "restic" + KopiaType = "kopia" + VeleroBackup = "backup" + VeleroRestore = "restore" ) +// ValidateUploaderType validates if the input param is a valid uploader type. +// It will return an error if it's invalid. +func ValidateUploaderType(t string) error { + t = strings.TrimSpace(t) + if t != ResticType && t != KopiaType { + return fmt.Errorf("invalid uploader type '%s', valid upload types are: '%s', '%s'", t, ResticType, KopiaType) + } + return nil +} + type SnapshotInfo struct { ID string `json:"id"` Size int64 `json:"Size"` diff --git a/pkg/uploader/types_test.go b/pkg/uploader/types_test.go new file mode 100644 index 0000000000..492051bf2e --- /dev/null +++ b/pkg/uploader/types_test.go @@ -0,0 +1,34 @@ +package uploader + +import "testing" + +func TestValidateUploaderType(t *testing.T) { + tests := []struct { + name string + input string + wantErr bool + }{ + { + "'restic' is a valid type", + "restic", + false, + }, + { + "' kopia ' is a valid type (space will be trimmed)", + " kopia ", + false, + }, + { + "'anything_else' is invalid", + "anything_else", + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidateUploaderType(tt.input); (err != nil) != tt.wantErr { + t.Errorf("ValidateUploaderType(), input = '%s' error = %v, wantErr %v", tt.input, err, tt.wantErr) + } + }) + } +}