diff --git a/controllers/registry.go b/controllers/registry.go index e49e93bbf0..05baf95f56 100644 --- a/controllers/registry.go +++ b/controllers/registry.go @@ -60,6 +60,7 @@ const ( AzureProvider = "azure" GCPProvider = "gcp" Region = "region" + Profile = "profile" S3URL = "s3Url" InsecureSkipTLSVerify = "insecureSkipTLSVerify" StorageAccount = "storageAccount" @@ -383,9 +384,12 @@ func (r *VeleroReconciler) getAWSRegistryEnvVars(bsl *velerov1.BackupStorageLoca r.Log.Info(fmt.Sprintf("Error fetching provider secret %s for backupstoragelocation %s/%s", secretName, bsl.Namespace, bsl.Name)) return nil, err } - + awsProfile := "default" + if value, exists := bsl.Spec.Config[Profile]; exists { + awsProfile = value + } // parse the secret and get aws access_key and aws secret_key - AWSAccessKey, AWSSecretKey, err := r.parseAWSSecret(secret, secretKey) + AWSAccessKey, AWSSecretKey, err := r.parseAWSSecret(secret, secretKey, awsProfile) if err != nil { r.Log.Info(fmt.Sprintf("Error parsing provider secret %s for backupstoragelocation %s/%s", secretName, bsl.Namespace, bsl.Name)) return nil, err @@ -502,12 +506,11 @@ func (r *VeleroReconciler) getSecretNameAndKey(credential *corev1.SecretKeySelec return secretName, secretKey } -func (r *VeleroReconciler) parseAWSSecret(secret corev1.Secret, secretKey string) (string, string, error) { +func (r *VeleroReconciler) parseAWSSecret(secret corev1.Secret, secretKey string, matchProfile string) (string, string, error) { - AWSAccessKey, AWSSecretKey := "", "" - // this logic only supports single profile presence in the aws credentials file + AWSAccessKey, AWSSecretKey, profile := "", "", "" splitString := strings.Split(string(secret.Data[secretKey]), "\n") - keyNameRegex, err := regexp.Compile(`\[.*\]`) //ignore lines such as [default] + keyNameRegex, err := regexp.Compile(`\[.*\]`) if err != nil { return AWSAccessKey, AWSSecretKey, errors.New("parseAWSSecret faulty regex: keyNameRegex") } @@ -519,46 +522,66 @@ func (r *VeleroReconciler) parseAWSSecret(secret corev1.Secret, secretKey string if err != nil { return AWSAccessKey, AWSSecretKey, errors.New("parseAWSSecret faulty regex: awsSecretKeyRegex") } - for _, line := range splitString { + for index, line := range splitString { if line == "" { continue } if keyNameRegex.MatchString(line) { - continue - } - // check for access key - matchedAccessKey := awsAccessKeyRegex.MatchString(line) - - if err != nil { - r.Log.Info("Error finding access key id for the supplied AWS credential") - return AWSAccessKey, AWSSecretKey, err - } - - if matchedAccessKey { - cleanedLine := strings.ReplaceAll(line, " ", "") - splitLine := strings.Split(cleanedLine, "=") - if len(splitLine) != 2 { - r.Log.Info("Could not parse secret for AWS Access key") - return AWSAccessKey, AWSSecretKey, errors.New("secret parsing error") + awsProfileRegex, err := regexp.Compile(`\[|\]`) + if err != nil { + return AWSAccessKey, AWSSecretKey, errors.New("parseAWSSecret faulty regex: keyNameRegex") } - AWSAccessKey = splitLine[1] - continue - } + cleanedLine := strings.ReplaceAll(line, " ", "") + parsedProfile := awsProfileRegex.ReplaceAllString(cleanedLine, "") + if parsedProfile == matchProfile { + profile = matchProfile + // check for end of arr + if index+1 >= len(splitString) { + break + } + for _, profLine := range splitString[index+1:] { + if profLine == "" { + continue + } + matchedAccessKey := awsAccessKeyRegex.MatchString(profLine) - // check for secret key - matchedSecretKey := awsSecretKeyRegex.MatchString(line) + if err != nil { + r.Log.Info("Error finding access key id for the supplied AWS credential") + return AWSAccessKey, AWSSecretKey, err + } + // check for access key + if matchedAccessKey { + cleanedLine := strings.ReplaceAll(profLine, " ", "") + splitLine := strings.Split(cleanedLine, "=") + if len(splitLine) != 2 { + r.Log.Info("Could not parse secret for AWS Access key") + return AWSAccessKey, AWSSecretKey, errors.New("secret parsing error") + } + AWSAccessKey = splitLine[1] + continue + } - if matchedSecretKey { - cleanedLine := strings.ReplaceAll(line, " ", "") - splitLine := strings.Split(cleanedLine, "=") - if len(splitLine) != 2 { - r.Log.Info("Could not parse secret for AWS Secret key") - return AWSAccessKey, AWSSecretKey, errors.New("secret parsing error") + // check for secret key + matchedSecretKey := awsSecretKeyRegex.MatchString(profLine) + + if matchedSecretKey { + cleanedLine := strings.ReplaceAll(profLine, " ", "") + splitLine := strings.Split(cleanedLine, "=") + if len(splitLine) != 2 { + r.Log.Info("Could not parse secret for AWS Secret key") + return AWSAccessKey, AWSSecretKey, errors.New("secret parsing error") + } + AWSSecretKey = splitLine[1] + continue + } + } } - AWSSecretKey = splitLine[1] - continue } } + if profile == "" { + r.Log.Info("Error finding AWS Profile for the supplied AWS credential") + return AWSAccessKey, AWSSecretKey, errors.New("Error finding AWS Profile for the supplied AWS credential") + } if AWSAccessKey == "" { r.Log.Info("Error finding access key id for the supplied AWS credential") return AWSAccessKey, AWSSecretKey, errors.New("error finding access key id for the supplied AWS credential") diff --git a/controllers/registry_test.go b/controllers/registry_test.go index bbf171aeb1..ccf0c7d4f7 100644 --- a/controllers/registry_test.go +++ b/controllers/registry_test.go @@ -49,6 +49,7 @@ func getFakeClientFromObjectsForRegistry(objs ...client.Object) (client.WithWatc } const ( + testProfile = "someProfile" testAccessKey = "someAccessKey" testSecretAccessKey = "someSecretAccessKey" testStoragekey = "someStorageKey" @@ -59,7 +60,11 @@ var ( secretData = map[string][]byte{ "cloud": []byte("[default]" + "\n" + "aws_access_key_id=" + testAccessKey + "\n" + - "aws_secret_access_key=" + testSecretAccessKey), + "aws_secret_access_key=" + testSecretAccessKey + + "\n[test-profile]\n" + + "aws_access_key_id=" + testAccessKey + "\n" + + "aws_secret_access_key=" + testSecretAccessKey, + ), } secretAzureData = map[string][]byte{ "cloud": []byte("[default]" + "\n" + @@ -479,6 +484,7 @@ func TestVeleroReconciler_getAWSRegistryEnvVars(t *testing.T) { name string bsl *velerov1.BackupStorageLocation wantRegistryContainerEnvVar []corev1.EnvVar + wantProfile string secret *corev1.Secret wantErr bool }{ @@ -500,6 +506,7 @@ func TestVeleroReconciler_getAWSRegistryEnvVars(t *testing.T) { Region: "aws-region", S3URL: "https://sr-url-aws-domain.com", InsecureSkipTLSVerify: "false", + Profile: "test-profile", }, }, }, @@ -510,6 +517,7 @@ func TestVeleroReconciler_getAWSRegistryEnvVars(t *testing.T) { }, Data: secretData, }, + wantProfile: "test-profile", }, } for _, tt := range tests { diff --git a/tests/e2e/apps.go b/tests/e2e/apps.go index c139777098..456ca62fb4 100755 --- a/tests/e2e/apps.go +++ b/tests/e2e/apps.go @@ -102,7 +102,7 @@ func areApplicationPodsRunning(namespace string) wait.ConditionFunc { if len(condition.Message) > 0 { ginkgo.GinkgoWriter.Write([]byte(fmt.Sprintf("Pod not running with condition: %s\n", condition.Message))) } - } + } return false, nil } } diff --git a/tests/e2e/registry_helpers.go b/tests/e2e/registry_helpers.go index c2ae00651a..364b18b6f0 100755 --- a/tests/e2e/registry_helpers.go +++ b/tests/e2e/registry_helpers.go @@ -22,21 +22,21 @@ func areRegistryDeploymentsAvailable(namespace string) wait.ConditionFunc { LabelSelector: "app.kubernetes.io/component=Registry", } // get pods in the oadp-operator-e2e namespace with label selector - deploymentList, err := client.AppsV1().Deployments(namespace).List(context.TODO(),registryListOptions) + deploymentList, err := client.AppsV1().Deployments(namespace).List(context.TODO(), registryListOptions) if err != nil { return false, nil } if len(deploymentList.Items) == 0 { - return false, fmt.Errorf("registry deployment is not yet created") + return false, fmt.Errorf("registry deployment is not yet created") } // loop until deployment status is 'Running' or timeout for _, deploymentInfo := range deploymentList.Items { for _, conditions := range deploymentInfo.Status.Conditions { - if conditions.Type == appsv1.DeploymentAvailable && conditions.Status != corev1.ConditionTrue{ - return false, fmt.Errorf("registry deployment is not yet available.\nconditions: %v", deploymentInfo.Status.Conditions) + if conditions.Type == appsv1.DeploymentAvailable && conditions.Status != corev1.ConditionTrue { + return false, fmt.Errorf("registry deployment is not yet available.\nconditions: %v", deploymentInfo.Status.Conditions) } } } return true, nil } -} \ No newline at end of file +}