Skip to content

Commit

Permalink
[CLOUD-1337] Introduce the babylon vault service endpoint resource (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
dedoussis authored Jul 16, 2021
1 parent 2cdf9aa commit fe782b7
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/utils/tfhelper"
)

const SERVICE_CONNECTION_TYPE string = "babylon-service-endpoint-aws-iam"
const DEFAULT_SESSION_NAME string = "azure-pipelines-task"
const BABYLON_AWS_IAM_SERVICE_CONNECTION_TYPE string = "babylon-service-endpoint-aws-iam"
const BABYLON_AWS_IAM_DEFAULT_SESSION_NAME string = "azure-pipelines-task"

func ResourceServiceEndpointBabylonAwsIam() *schema.Resource {
r := genBaseServiceEndpointResource(flattenServiceEndpointBabylonAwsIam, expandServiceEndpointBabylonAwsIam)
Expand All @@ -33,7 +33,7 @@ func ResourceServiceEndpointBabylonAwsIam() *schema.Resource {
Type: schema.TypeString,
Optional: true,
Description: "Session name to be used when assuming the role. The session name should match the one specified in the trust policies of the regional IAM roles.",
Default: DEFAULT_SESSION_NAME,
Default: BABYLON_AWS_IAM_DEFAULT_SESSION_NAME,
}
secretHashKey, secretHashSchema := tfhelper.GenerateSecreteMemoSchema("password")
r.Schema[secretHashKey] = secretHashSchema
Expand All @@ -53,7 +53,7 @@ func expandServiceEndpointBabylonAwsIam(d *schema.ResourceData) (*serviceendpoin
Scheme: converter.String("UsernamePassword"),
}
serviceEndpoint.Data = &map[string]string{}
serviceEndpoint.Type = converter.String(SERVICE_CONNECTION_TYPE)
serviceEndpoint.Type = converter.String(BABYLON_AWS_IAM_SERVICE_CONNECTION_TYPE)
serviceEndpoint.Url = converter.String("https://aws.amazon.com/")
return serviceEndpoint, projectID, nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,14 @@ func Test_expandServiceEndpointBabylonAwsIam(t *testing.T) {
"username": "user",
"password": "password",
"globalRoleArn": "roleArn",
"globalStsSessionName": "azure-pipelines-task",
"globalStsSessionName": BABYLON_AWS_IAM_DEFAULT_SESSION_NAME,
},
Scheme: converter.String("UsernamePassword"),
},
Data: &map[string]string{},
Description: converter.String("Managed by Terraform"),
Owner: converter.String("library"),
Type: converter.String("babylon-service-endpoint-aws-iam"),
Type: converter.String(BABYLON_AWS_IAM_SERVICE_CONNECTION_TYPE),
Name: converter.String(""),
Url: converter.String("https://aws.amazon.com/"),
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package serviceendpoint

import (
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/microsoft/azure-devops-go-api/azuredevops/serviceendpoint"
"github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/utils/converter"
"github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/utils/tfhelper"
)

const BABYLON_VAULT_SERVICE_CONNECTION_TYPE string = "babylon-service-endpoint-vault"

func ResourceServiceEndpointBabylonVault() *schema.Resource {
r := genBaseServiceEndpointResource(flattenServiceEndpointBabylonVault, expandServiceEndpointBabylonVault)
r.Schema["url"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateFunc: func(i interface{}, key string) (_ []string, errors []error) {
url, ok := i.(string)
if !ok {
errors = append(errors, fmt.Errorf("expected type of %q to be string", key))
return
}
if strings.HasSuffix(url, "/") {
errors = append(errors, fmt.Errorf("%q should not end with slash, got %q.", key, url))
return
}
return validation.IsURLWithHTTPorHTTPS(url, key)
},
Description: "Url for the Vault Server",
}

r.Schema["vault_role"] = &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "Vault role to log in as",
}
return r
}

// Convert internal Terraform data structure to an AzDO data structure
func expandServiceEndpointBabylonVault(d *schema.ResourceData) (*serviceendpoint.ServiceEndpoint, *string, error) {
serviceEndpoint, projectID := doBaseExpansion(d)
serviceEndpoint.Authorization = &serviceendpoint.EndpointAuthorization{
Parameters: &map[string]string{},
Scheme: converter.String("None"),
}
serviceEndpoint.Data = &map[string]string{"vaultRole": d.Get("vault_role").(string)}
serviceEndpoint.Type = converter.String(BABYLON_VAULT_SERVICE_CONNECTION_TYPE)
serviceEndpoint.Url = converter.String(d.Get("url").(string))
return serviceEndpoint, projectID, nil
}

// Convert AzDO data structure to internal Terraform data structure
func flattenServiceEndpointBabylonVault(d *schema.ResourceData, serviceEndpoint *serviceendpoint.ServiceEndpoint, projectID *string) {
doBaseFlattening(d, serviceEndpoint, projectID)
tfhelper.HelpFlattenSecret(d, "password")

d.Set("url", *serviceEndpoint.Url)
d.Set("vault_role", (*serviceEndpoint.Data)["vaultRole"])
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package serviceendpoint

import (
"testing"

"github.com/go-test/deep"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/microsoft/azure-devops-go-api/azuredevops/serviceendpoint"
"github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/utils/converter"
)

func TestResourceServiceEndpointBabylonVault(t *testing.T) {
tests := []struct {
name string
expectedSchema map[string]*schema.Schema
}{
{
name: "test",
expectedSchema: map[string]*schema.Schema{
"url": {
Type: schema.TypeString,
Required: true,
Description: "Url for the Vault Server",
},
"vault_role": {
Type: schema.TypeString,
Required: true,
Description: "Vault role to log in as",
},
"project_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringIsNotWhiteSpace,
},
"service_endpoint_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringIsNotWhiteSpace,
},
"description": {
Type: schema.TypeString,
Optional: true,
Default: "Managed by Terraform",
ValidateFunc: validation.StringIsNotWhiteSpace,
},
"authorization": {
Type: schema.TypeMap,
Optional: true,
Computed: true,
ValidateFunc: validation.StringIsNotWhiteSpace,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

resource := ResourceServiceEndpointBabylonVault()
resourceSchema := resource.Schema

if diff := deep.Equal(resourceSchema, tt.expectedSchema); len(diff) > 0 {
t.Errorf("ResourceServiceEndpointBabylonVault() mismatch:\n%s", diff)
}
})
}
}

func Test_expandServiceEndpointBabylonVault(t *testing.T) {
type args struct {
url string
vaultRole string
project string
}
tests := []struct {
name string
args args
want *serviceendpoint.ServiceEndpoint
wantProject *string
wantErr bool
}{
{
name: "test expandServiceEndpoint",
args: args{
url: "https://vault.babylonhealth.com",
vaultRole: "devtest",
project: "project",
},
want: &serviceendpoint.ServiceEndpoint{
Authorization: &serviceendpoint.EndpointAuthorization{
Parameters: &map[string]string{},
Scheme: converter.String("None"),
},
Data: &map[string]string{
"vaultRole": "devtest",
},
Description: converter.String("Managed by Terraform"),
Owner: converter.String("library"),
Type: converter.String(BABYLON_VAULT_SERVICE_CONNECTION_TYPE),
Name: converter.String(""),
Url: converter.String("https://vault.babylonhealth.com"),
},
wantProject: converter.String("project"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := ResourceServiceEndpointBabylonVault()
resourceData := schema.TestResourceDataRaw(t, r.Schema, nil)

multiErr := &multierror.Error{}

err := resourceData.Set("url", tt.args.url)
if err != nil {
multiErr = multierror.Append(err, multiErr.Errors...)
}

err = resourceData.Set("vault_role", tt.args.vaultRole)
if err != nil {
multiErr = multierror.Append(err, multiErr.Errors...)
}

err = resourceData.Set("project_id", tt.args.project)
if err != nil {
multiErr = multierror.Append(err, multiErr.Errors...)
}

if err != nil {
t.Error(err)
}

got, got1, err := expandServiceEndpointBabylonVault(resourceData)
if (err != nil) != tt.wantErr {
t.Errorf("ResourceServiceEndpointBabylonVault() error = %v, wantErr %v", err, tt.wantErr)
return
}
if diff := deep.Equal(got, tt.want); len(diff) > 0 {
t.Errorf("ResourceServiceEndpointBabylonVault() mismatch:\n%s", diff)
}

if diff := deep.Equal(got1, tt.wantProject); len(diff) > 0 {
t.Errorf("ResourceServiceEndpointBabylonVault() got1 = %v, want %v", got1, tt.wantProject)
}
})
}
}

func Test_flattenServiceEndpointBabylonVault(t *testing.T) {
type args struct {
d *schema.ResourceData
serviceEndpoint *serviceendpoint.ServiceEndpoint
projectID *string
}
tests := []struct {
name string
args args
expected map[string]string
}{
{
name: "Test flattenServiceEndpoint - secret updated",
args: args{
d: &schema.ResourceData{},
serviceEndpoint: &serviceendpoint.ServiceEndpoint{
Id: converter.UUID("1ceae7ff-565c-4cdf-9214-6e2246cba764"),
Url: converter.String("https://vault.babylonhealth.com"),
Data: &map[string]string{"vaultRole": "devtest"},
Authorization: &serviceendpoint.EndpointAuthorization{
Parameters: &map[string]string{},
Scheme: converter.String("None"),
},
},
projectID: converter.String("project"),
},
expected: map[string]string{
"id": "1ceae7ff-565c-4cdf-9214-6e2246cba764",
"authorization.%": "1",
"authorization.scheme": "None",
"description": "",
"url": "https://vault.babylonhealth.com",
"vault_role": "devtest",
"project_id": "project",
"service_endpoint_name": "",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := ResourceServiceEndpointBabylonVault()

resourceData := schema.TestResourceDataRaw(t, r.Schema, nil)

flattenServiceEndpointBabylonVault(resourceData, tt.args.serviceEndpoint, tt.args.projectID)
state := resourceData.State()

if diff := deep.Equal(tt.expected, state.Attributes); len(diff) > 0 {
t.Errorf("mismatch:\n%s", diff)
}
})
}
}
1 change: 1 addition & 0 deletions azuredevops/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func Provider() *schema.Provider {
"azuredevops_serviceendpoint_npm": serviceendpoint.ResourceServiceEndpointNpm(),
"azuredevops_serviceendpoint_genericwebhook": serviceendpoint.ResourceServiceEndpointGenericWebhook(),
"azuredevops_serviceendpoint_babylonawsiam": serviceendpoint.ResourceServiceEndpointBabylonAwsIam(),
"azuredevops_serviceendpoint_babylonvault": serviceendpoint.ResourceServiceEndpointBabylonVault(),
"azuredevops_git_repository": git.ResourceGitRepository(),
"azuredevops_user_entitlement": memberentitlementmanagement.ResourceUserEntitlement(),
"azuredevops_group_membership": graph.ResourceGroupMembership(),
Expand Down
1 change: 1 addition & 0 deletions azuredevops/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func TestProvider_HasChildResources(t *testing.T) {
"azuredevops_serviceendpoint_kubernetes",
"azuredevops_serviceendpoint_aws",
"azuredevops_serviceendpoint_babylonawsiam",
"azuredevops_serviceendpoint_babylonvault",
"azuredevops_serviceendpoint_genericwebhook",
"azuredevops_serviceendpoint_artifactory",
"azuredevops_serviceendpoint_sonarqube",
Expand Down

0 comments on commit fe782b7

Please sign in to comment.