Update integrated Restic version and add insecureSkipTLSVerify for Restic CLI
1. Add --insecure-tls for ResticManager's commands. 2. Add --insecure-tls in PodVolumeBackup and PodVolumeRestore controller. 3. Upgrade integrated Restic version to v0.13.1 4. Change --last flag in Restic command to --latest=1 due to Restic version update. Signed-off-by: Xun Jiang <jxun@vmware.com>pull/4839/head
parent
65db2585fb
commit
8064421e83
2
Makefile
2
Makefile
|
@ -82,7 +82,7 @@ see: https://velero.io/docs/main/build-from-source/#making-images-and-updating-v
|
||||||
endef
|
endef
|
||||||
|
|
||||||
# The version of restic binary to be downloaded
|
# The version of restic binary to be downloaded
|
||||||
RESTIC_VERSION ?= 0.12.1
|
RESTIC_VERSION ?= 0.13.1
|
||||||
|
|
||||||
CLI_PLATFORMS ?= linux-amd64 linux-arm linux-arm64 darwin-amd64 darwin-arm64 windows-amd64 linux-ppc64le
|
CLI_PLATFORMS ?= linux-amd64 linux-arm linux-arm64 darwin-amd64 darwin-arm64 windows-amd64 linux-ppc64le
|
||||||
BUILDX_PLATFORMS ?= $(subst -,/,$(ARCH))
|
BUILDX_PLATFORMS ?= $(subst -,/,$(ARCH))
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Update integrated Restic version and add insecureSkipTLSVerify for Restic CLI.
|
|
@ -139,8 +139,26 @@ func (r *PodVolumeBackupReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||||
}
|
}
|
||||||
defer os.Remove(resticDetails.credsFile)
|
defer os.Remove(resticDetails.credsFile)
|
||||||
|
|
||||||
|
backupLocation := &velerov1api.BackupStorageLocation{}
|
||||||
|
if err := r.Client.Get(context.Background(), client.ObjectKey{
|
||||||
|
Namespace: pvb.Namespace,
|
||||||
|
Name: pvb.Spec.BackupStorageLocation,
|
||||||
|
}, backupLocation); err != nil {
|
||||||
|
return ctrl.Result{}, errors.Wrap(err, "error getting backup storage location")
|
||||||
|
}
|
||||||
|
|
||||||
|
// #4820: restrieve insecureSkipTLSVerify from BSL configuration for
|
||||||
|
// AWS plugin. If nothing is return, that means insecureSkipTLSVerify
|
||||||
|
// is not enable for Restic command.
|
||||||
|
skipTLSRet := restic.GetInsecureSkipTLSVerifyFromBSL(backupLocation, log)
|
||||||
|
if len(skipTLSRet) > 0 {
|
||||||
|
resticCmd.ExtraFlags = append(resticCmd.ExtraFlags, skipTLSRet)
|
||||||
|
}
|
||||||
|
|
||||||
|
var stdout, stderr string
|
||||||
|
|
||||||
var emptySnapshot bool
|
var emptySnapshot bool
|
||||||
stdout, stderr, err := r.ResticExec.RunBackup(resticCmd, log, r.updateBackupProgressFunc(&pvb, log))
|
stdout, stderr, err = r.ResticExec.RunBackup(resticCmd, log, r.updateBackupProgressFunc(&pvb, log))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(stderr, "snapshot is empty") {
|
if strings.Contains(stderr, "snapshot is empty") {
|
||||||
emptySnapshot = true
|
emptySnapshot = true
|
||||||
|
@ -156,6 +174,11 @@ func (r *PodVolumeBackupReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||||
cmd.Env = resticDetails.envs
|
cmd.Env = resticDetails.envs
|
||||||
cmd.CACertFile = resticDetails.caCertFile
|
cmd.CACertFile = resticDetails.caCertFile
|
||||||
|
|
||||||
|
// #4820: also apply the insecureTLS flag to Restic snapshots command
|
||||||
|
if len(skipTLSRet) > 0 {
|
||||||
|
cmd.ExtraFlags = append(cmd.ExtraFlags, skipTLSRet)
|
||||||
|
}
|
||||||
|
|
||||||
snapshotID, err = r.ResticExec.GetSnapshotID(cmd)
|
snapshotID, err = r.ResticExec.GetSnapshotID(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r.updateStatusToFailed(ctx, &pvb, err, "getting snapshot id")
|
return r.updateStatusToFailed(ctx, &pvb, err, "getting snapshot id")
|
||||||
|
|
|
@ -385,6 +385,14 @@ func (c *podVolumeRestoreController) restorePodVolume(req *velerov1api.PodVolume
|
||||||
}
|
}
|
||||||
resticCmd.Env = env
|
resticCmd.Env = env
|
||||||
|
|
||||||
|
// #4820: restrieve insecureSkipTLSVerify from BSL configuration for
|
||||||
|
// AWS plugin. If nothing is return, that means insecureSkipTLSVerify
|
||||||
|
// is not enable for Restic command.
|
||||||
|
skipTLSRet := restic.GetInsecureSkipTLSVerifyFromBSL(backupLocation, log)
|
||||||
|
if len(skipTLSRet) > 0 {
|
||||||
|
resticCmd.ExtraFlags = append(resticCmd.ExtraFlags, skipTLSRet)
|
||||||
|
}
|
||||||
|
|
||||||
var stdout, stderr string
|
var stdout, stderr string
|
||||||
|
|
||||||
if stdout, stderr, err = restic.RunRestore(resticCmd, log, c.updateRestoreProgressFunc(req, log)); err != nil {
|
if stdout, stderr, err = restic.RunRestore(resticCmd, log, c.updateRestoreProgressFunc(req, log)); err != nil {
|
||||||
|
|
|
@ -64,7 +64,8 @@ func GetSnapshotCommand(repoIdentifier, passwordFile string, tags map[string]str
|
||||||
Command: "snapshots",
|
Command: "snapshots",
|
||||||
RepoIdentifier: repoIdentifier,
|
RepoIdentifier: repoIdentifier,
|
||||||
PasswordFile: passwordFile,
|
PasswordFile: passwordFile,
|
||||||
ExtraFlags: []string{"--json", "--last", getSnapshotTagFlag(tags)},
|
// "--last" is replaced by "--latest=1" in restic v0.12.1
|
||||||
|
ExtraFlags: []string{"--json", "--latest=1", getSnapshotTagFlag(tags)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ func TestGetSnapshotCommand(t *testing.T) {
|
||||||
assert.Equal(t, "password-file", c.PasswordFile)
|
assert.Equal(t, "password-file", c.PasswordFile)
|
||||||
|
|
||||||
// set up expected flag names
|
// set up expected flag names
|
||||||
expectedFlags := []string{"--json", "--last", "--tag"}
|
expectedFlags := []string{"--json", "--latest=1", "--tag"}
|
||||||
// for tracking actual flag names
|
// for tracking actual flag names
|
||||||
actualFlags := []string{}
|
actualFlags := []string{}
|
||||||
// for tracking actual --tag values as a map
|
// for tracking actual --tag values as a map
|
||||||
|
@ -68,10 +68,11 @@ func TestGetSnapshotCommand(t *testing.T) {
|
||||||
for _, flag := range c.ExtraFlags {
|
for _, flag := range c.ExtraFlags {
|
||||||
// split into 2 parts from the first = sign (if any)
|
// split into 2 parts from the first = sign (if any)
|
||||||
parts := strings.SplitN(flag, "=", 2)
|
parts := strings.SplitN(flag, "=", 2)
|
||||||
// parts[0] is the flag name
|
|
||||||
actualFlags = append(actualFlags, parts[0])
|
|
||||||
// convert --tag data to a map
|
// convert --tag data to a map
|
||||||
if parts[0] == "--tag" {
|
if parts[0] == "--tag" {
|
||||||
|
actualFlags = append(actualFlags, parts[0])
|
||||||
|
|
||||||
// split based on ,
|
// split based on ,
|
||||||
tags := strings.Split(parts[1], ",")
|
tags := strings.Split(parts[1], ",")
|
||||||
// loop through each key-value tag pair
|
// loop through each key-value tag pair
|
||||||
|
@ -81,6 +82,8 @@ func TestGetSnapshotCommand(t *testing.T) {
|
||||||
// record actual key & value
|
// record actual key & value
|
||||||
actualTags[kvs[0]] = kvs[1]
|
actualTags[kvs[0]] = kvs[1]
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
actualFlags = append(actualFlags, flag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -184,7 +185,15 @@ func getSummaryLine(b []byte) ([]byte, error) {
|
||||||
// RunRestore runs a `restic restore` command and monitors the volume size to
|
// RunRestore runs a `restic restore` command and monitors the volume size to
|
||||||
// provide progress updates to the caller.
|
// provide progress updates to the caller.
|
||||||
func RunRestore(restoreCmd *Command, log logrus.FieldLogger, updateFunc func(velerov1api.PodVolumeOperationProgress)) (string, string, error) {
|
func RunRestore(restoreCmd *Command, log logrus.FieldLogger, updateFunc func(velerov1api.PodVolumeOperationProgress)) (string, string, error) {
|
||||||
snapshotSize, err := getSnapshotSize(restoreCmd.RepoIdentifier, restoreCmd.PasswordFile, restoreCmd.CACertFile, restoreCmd.Args[0], restoreCmd.Env)
|
insecureTLSFlag := ""
|
||||||
|
|
||||||
|
for _, extraFlag := range restoreCmd.ExtraFlags {
|
||||||
|
if strings.Contains(extraFlag, resticInsecureTLSFlag) {
|
||||||
|
insecureTLSFlag = extraFlag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshotSize, err := getSnapshotSize(restoreCmd.RepoIdentifier, restoreCmd.PasswordFile, restoreCmd.CACertFile, restoreCmd.Args[0], restoreCmd.Env, insecureTLSFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", errors.Wrap(err, "error getting snapshot size")
|
return "", "", errors.Wrap(err, "error getting snapshot size")
|
||||||
}
|
}
|
||||||
|
@ -230,11 +239,15 @@ func RunRestore(restoreCmd *Command, log logrus.FieldLogger, updateFunc func(vel
|
||||||
return stdout, stderr, err
|
return stdout, stderr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSnapshotSize(repoIdentifier, passwordFile, caCertFile, snapshotID string, env []string) (int64, error) {
|
func getSnapshotSize(repoIdentifier, passwordFile, caCertFile, snapshotID string, env []string, insecureTLS string) (int64, error) {
|
||||||
cmd := StatsCommand(repoIdentifier, passwordFile, snapshotID)
|
cmd := StatsCommand(repoIdentifier, passwordFile, snapshotID)
|
||||||
cmd.Env = env
|
cmd.Env = env
|
||||||
cmd.CACertFile = caCertFile
|
cmd.CACertFile = caCertFile
|
||||||
|
|
||||||
|
if len(insecureTLS) > 0 {
|
||||||
|
cmd.ExtraFlags = append(cmd.ExtraFlags, insecureTLS)
|
||||||
|
}
|
||||||
|
|
||||||
stdout, stderr, err := exec.RunCommand(cmd.Cmd())
|
stdout, stderr, err := exec.RunCommand(cmd.Cmd())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Wrapf(err, "error running command, stderr=%s", stderr)
|
return 0, errors.Wrapf(err, "error running command, stderr=%s", stderr)
|
||||||
|
@ -245,7 +258,7 @@ func getSnapshotSize(repoIdentifier, passwordFile, caCertFile, snapshotID string
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(stdout), &snapshotStats); err != nil {
|
if err := json.Unmarshal([]byte(stdout), &snapshotStats); err != nil {
|
||||||
return 0, errors.Wrap(err, "error unmarshalling restic stats result")
|
return 0, errors.Wrapf(err, "error unmarshalling restic stats result, stdout=%s", stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
return snapshotStats.TotalSize, nil
|
return snapshotStats.TotalSize, nil
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -95,6 +96,16 @@ type repositoryManager struct {
|
||||||
credentialsFileStore credentials.FileStore
|
credentialsFileStore credentials.FileStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// insecureSkipTLSVerifyKey is the flag in BackupStorageLocation's config
|
||||||
|
// to indicate whether to skip TLS verify to setup insecure HTTPS connection.
|
||||||
|
insecureSkipTLSVerifyKey = "insecureSkipTLSVerify"
|
||||||
|
|
||||||
|
// resticInsecureTLSFlag is the flag for Restic command line to indicate
|
||||||
|
// skip TLS verify on https connection.
|
||||||
|
resticInsecureTLSFlag = "--insecure-tls"
|
||||||
|
)
|
||||||
|
|
||||||
// NewRepositoryManager constructs a RepositoryManager.
|
// NewRepositoryManager constructs a RepositoryManager.
|
||||||
func NewRepositoryManager(
|
func NewRepositoryManager(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
@ -184,10 +195,11 @@ func (rm *repositoryManager) ConnectToRepo(repo *velerov1api.ResticRepository) e
|
||||||
defer rm.repoLocker.Unlock(repo.Name)
|
defer rm.repoLocker.Unlock(repo.Name)
|
||||||
|
|
||||||
snapshotsCmd := SnapshotsCommand(repo.Spec.ResticIdentifier)
|
snapshotsCmd := SnapshotsCommand(repo.Spec.ResticIdentifier)
|
||||||
// use the '--last' flag to minimize the amount of data fetched since
|
// use the '--latest=1' flag to minimize the amount of data fetched since
|
||||||
// we're just validating that the repo exists and can be authenticated
|
// we're just validating that the repo exists and can be authenticated
|
||||||
// to.
|
// to.
|
||||||
snapshotsCmd.ExtraFlags = append(snapshotsCmd.ExtraFlags, "--last")
|
// "--last" is replaced by "--latest=1" in restic v0.12.1
|
||||||
|
snapshotsCmd.ExtraFlags = append(snapshotsCmd.ExtraFlags, "--latest=1")
|
||||||
|
|
||||||
return rm.exec(snapshotsCmd, repo.Spec.BackupStorageLocation)
|
return rm.exec(snapshotsCmd, repo.Spec.BackupStorageLocation)
|
||||||
}
|
}
|
||||||
|
@ -265,6 +277,14 @@ func (rm *repositoryManager) exec(cmd *Command, backupLocation string) error {
|
||||||
}
|
}
|
||||||
cmd.Env = env
|
cmd.Env = env
|
||||||
|
|
||||||
|
// #4820: restrieve insecureSkipTLSVerify from BSL configuration for
|
||||||
|
// AWS plugin. If nothing is return, that means insecureSkipTLSVerify
|
||||||
|
// is not enable for Restic command.
|
||||||
|
skipTLSRet := GetInsecureSkipTLSVerifyFromBSL(loc, rm.log)
|
||||||
|
if len(skipTLSRet) > 0 {
|
||||||
|
cmd.ExtraFlags = append(cmd.ExtraFlags, skipTLSRet)
|
||||||
|
}
|
||||||
|
|
||||||
stdout, stderr, err := veleroexec.RunCommand(cmd.Cmd())
|
stdout, stderr, err := veleroexec.RunCommand(cmd.Cmd())
|
||||||
rm.log.WithFields(logrus.Fields{
|
rm.log.WithFields(logrus.Fields{
|
||||||
"repository": cmd.RepoName(),
|
"repository": cmd.RepoName(),
|
||||||
|
@ -278,3 +298,22 @@ func (rm *repositoryManager) exec(cmd *Command, backupLocation string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetInsecureSkipTLSVerifyFromBSL get insecureSkipTLSVerify flag from BSL configuration,
|
||||||
|
// Then return --insecure-tls flag with boolean value as result.
|
||||||
|
func GetInsecureSkipTLSVerifyFromBSL(backupLocation *velerov1api.BackupStorageLocation, logger logrus.FieldLogger) string {
|
||||||
|
result := ""
|
||||||
|
|
||||||
|
if backupLocation == nil {
|
||||||
|
logger.Info("bsl is nil. return empty.")
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
if insecure, _ := strconv.ParseBool(backupLocation.Spec.Config[insecureSkipTLSVerifyKey]); insecure {
|
||||||
|
logger.Debugf("set --insecure-tls=true for Restic command according to BSL %s config", backupLocation.Name)
|
||||||
|
result = resticInsecureTLSFlag + "=true"
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
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 restic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetInsecureSkipTLSVerifyFromBSL(t *testing.T) {
|
||||||
|
log := logrus.StandardLogger()
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
backupLocation *velerov1api.BackupStorageLocation
|
||||||
|
logger logrus.FieldLogger
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"Test with nil BSL. Should return empty string.",
|
||||||
|
nil,
|
||||||
|
log,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Test BSL with no configuration. Should return empty string.",
|
||||||
|
&velerov1api.BackupStorageLocation{
|
||||||
|
Spec: velerov1api.BackupStorageLocationSpec{
|
||||||
|
Provider: "azure",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
log,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Test with AWS BSL's insecureSkipTLSVerify set to false.",
|
||||||
|
&velerov1api.BackupStorageLocation{
|
||||||
|
Spec: velerov1api.BackupStorageLocationSpec{
|
||||||
|
Provider: "aws",
|
||||||
|
Config: map[string]string{
|
||||||
|
"insecureSkipTLSVerify": "false",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
log,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Test with AWS BSL's insecureSkipTLSVerify set to true.",
|
||||||
|
&velerov1api.BackupStorageLocation{
|
||||||
|
Spec: velerov1api.BackupStorageLocationSpec{
|
||||||
|
Provider: "aws",
|
||||||
|
Config: map[string]string{
|
||||||
|
"insecureSkipTLSVerify": "true",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
log,
|
||||||
|
"--insecure-tls=true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Test with Azure BSL's insecureSkipTLSVerify set to invalid.",
|
||||||
|
&velerov1api.BackupStorageLocation{
|
||||||
|
Spec: velerov1api.BackupStorageLocationSpec{
|
||||||
|
Provider: "azure",
|
||||||
|
Config: map[string]string{
|
||||||
|
"insecureSkipTLSVerify": "invalid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
log,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Test with GCP without insecureSkipTLSVerify.",
|
||||||
|
&velerov1api.BackupStorageLocation{
|
||||||
|
Spec: velerov1api.BackupStorageLocationSpec{
|
||||||
|
Provider: "gcp",
|
||||||
|
Config: map[string]string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
log,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Test with AWS without config.",
|
||||||
|
&velerov1api.BackupStorageLocation{
|
||||||
|
Spec: velerov1api.BackupStorageLocationSpec{
|
||||||
|
Provider: "aws",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
log,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
res := GetInsecureSkipTLSVerifyFromBSL(test.backupLocation, test.logger)
|
||||||
|
|
||||||
|
assert.Equal(t, test.expected, res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue