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 <jiangd@vmware.com> Signed-off-by: Daniel Jiang <jiangd@vmware.com>pull/5190/head
parent
71e4430840
commit
4e25f59dc1
|
@ -0,0 +1 @@
|
|||
Add parameter "uploader-type" to velero server
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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])
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
const (
|
||||
VeleroBackup string = "backup"
|
||||
VeleroRestore string = "restore"
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
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"`
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue