Support AWS_PROFILE for restic backups/restore operations (#2096)

* Support AWS_PROFILE for restic backups/restore operations

It enables Velero to switch credentials if multiple s3-compatible
backupLocations are present.

Signed-off-by: dinesh <dinesh1042@gmail.com>

* better comments and fixing typos

Signed-off-by: dinesh <dinesh1042@gmail.com>

* add changelog entry

Signed-off-by: dinesh <dinesh1042@gmail.com>
pull/2127/head
Dinesh Yadav 2019-12-09 20:16:02 +05:30 committed by Nolan Brubaker
parent 6391b84dc6
commit 83ef4eb4d0
7 changed files with 88 additions and 5 deletions

View File

@ -0,0 +1 @@
Enableing Velero to switch credentials (`AWS_PROFILE`) if multiple s3-compatible backupLocations are present

View File

@ -227,13 +227,19 @@ func (c *podVolumeBackupController) processBackup(req *velerov1api.PodVolumeBack
req.Spec.Tags, req.Spec.Tags,
) )
// if this is azure, set resticCmd.Env appropriately // Running restic command might need additional provider specific environment variables. Based on the provider, we
// set resticCmd.Env appropriately (currently for Azure and S3 based backuplocations)
var env []string var env []string
if strings.HasPrefix(req.Spec.RepoIdentifier, "azure") { if strings.HasPrefix(req.Spec.RepoIdentifier, "azure") {
if env, err = restic.AzureCmdEnv(c.backupLocationLister, req.Namespace, req.Spec.BackupStorageLocation); err != nil { if env, err = restic.AzureCmdEnv(c.backupLocationLister, req.Namespace, req.Spec.BackupStorageLocation); err != nil {
return c.fail(req, errors.Wrap(err, "error setting restic cmd env").Error(), log) return c.fail(req, errors.Wrap(err, "error setting restic cmd env").Error(), log)
} }
resticCmd.Env = env resticCmd.Env = env
} else if strings.HasPrefix(req.Spec.RepoIdentifier, "s3") {
if env, err = restic.S3CmdEnv(c.backupLocationLister, req.Namespace, req.Spec.BackupStorageLocation); err != nil {
return c.fail(req, errors.Wrap(err, "error setting restic cmd env").Error(), log)
}
resticCmd.Env = env
} }
// If this is a PVC, look for the most recent completed pod volume backup for it and get // If this is a PVC, look for the most recent completed pod volume backup for it and get

View File

@ -328,13 +328,20 @@ func (c *podVolumeRestoreController) restorePodVolume(req *velerov1api.PodVolume
volumePath, volumePath,
) )
// if this is azure, set resticCmd.Env appropriately // Running restic command might need additional provider specific environment variables. Based on the provider, we
// set resticCmd.Env appropriately (currently for Azure and S3 based backuplocations)
if strings.HasPrefix(req.Spec.RepoIdentifier, "azure") { if strings.HasPrefix(req.Spec.RepoIdentifier, "azure") {
env, err := restic.AzureCmdEnv(c.backupLocationLister, req.Namespace, req.Spec.BackupStorageLocation) env, err := restic.AzureCmdEnv(c.backupLocationLister, req.Namespace, req.Spec.BackupStorageLocation)
if err != nil { if err != nil {
return c.failRestore(req, errors.Wrap(err, "error setting restic cmd env").Error(), log) return c.failRestore(req, errors.Wrap(err, "error setting restic cmd env").Error(), log)
} }
resticCmd.Env = env resticCmd.Env = env
} else if strings.HasPrefix(req.Spec.RepoIdentifier, "s3") {
env, err := restic.S3CmdEnv(c.backupLocationLister, req.Namespace, req.Spec.BackupStorageLocation)
if err != nil {
return c.failRestore(req, errors.Wrap(err, "error setting restic cmd env").Error(), log)
}
resticCmd.Env = env
} }
var stdout, stderr string var stdout, stderr string

36
pkg/restic/aws.go Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright 2019 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
const (
// AWS specific environment variable
awsProfileEnvVar = "AWS_PROFILE"
awsProfileKey = "profile"
)
// getS3ResticEnvVars gets the environment variables that restic
// relies on (AWS_PROFILE) based on info in the provided object
// storage location config map.
func getS3ResticEnvVars(config map[string]string) (map[string]string, error) {
result := make(map[string]string)
if profile, ok := config[awsProfileKey]; ok {
result[awsProfileEnvVar] = profile
}
return result, nil
}

View File

@ -114,10 +114,10 @@ func mapLookup(data map[string]string) func(string) string {
} }
} }
// getResticEnvVars gets the environment variables that restic // getAzureResticEnvVars gets the environment variables that restic
// relies on (AZURE_ACCOUNT_NAME and AZURE_ACCOUNT_KEY) based // relies on (AZURE_ACCOUNT_NAME and AZURE_ACCOUNT_KEY) based
// on info in the provided object storage location config map. // on info in the provided object storage location config map.
func getResticEnvVars(config map[string]string) (map[string]string, error) { func getAzureResticEnvVars(config map[string]string) (map[string]string, error) {
storageAccountKey, _, err := getStorageAccountKey(config) storageAccountKey, _, err := getStorageAccountKey(config)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -228,7 +228,7 @@ func AzureCmdEnv(backupLocationLister velerov1listers.BackupStorageLocationListe
return nil, errors.Wrap(err, "error getting backup storage location") return nil, errors.Wrap(err, "error getting backup storage location")
} }
azureVars, err := getResticEnvVars(loc.Spec.Config) azureVars, err := getAzureResticEnvVars(loc.Spec.Config)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error getting azure restic env vars") return nil, errors.Wrap(err, "error getting azure restic env vars")
} }
@ -240,3 +240,26 @@ func AzureCmdEnv(backupLocationLister velerov1listers.BackupStorageLocationListe
return env, nil return env, nil
} }
// S3CmdEnv returns a list of environment variables (in the format var=val) that
// should be used when running a restic command for an S3 backend. This list is
// the current environment, plus the AWS-specific variables restic needs, namely
// a credential profile.
func S3CmdEnv(backupLocationLister velerov1listers.BackupStorageLocationLister, namespace, backupLocation string) ([]string, error) {
loc, err := backupLocationLister.BackupStorageLocations(namespace).Get(backupLocation)
if err != nil {
return nil, errors.Wrap(err, "error getting backup storage location")
}
awsVars, err := getS3ResticEnvVars(loc.Spec.Config)
if err != nil {
return nil, errors.Wrap(err, "error getting aws restic env vars")
}
env := os.Environ()
for k, v := range awsVars {
env = append(env, fmt.Sprintf("%s=%s", k, v))
}
return env, nil
}

View File

@ -254,6 +254,16 @@ func (rm *repositoryManager) exec(cmd *Command, backupLocation string) error {
return err return err
} }
cmd.Env = env cmd.Env = env
} else if strings.HasPrefix(cmd.RepoIdentifier, "s3") {
if !cache.WaitForCacheSync(rm.ctx.Done(), rm.backupLocationInformerSynced) {
return errors.New("timed out waiting for cache to sync")
}
env, err := S3CmdEnv(rm.backupLocationLister, rm.namespace, backupLocation)
if err != nil {
return err
}
cmd.Env = env
} }
stdout, stderr, err := veleroexec.RunCommand(cmd.Cmd()) stdout, stderr, err := veleroexec.RunCommand(cmd.Cmd())