Skip to content

Commit

Permalink
Merge pull request #48 from env0/feat-add-aws-credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
HeverFarber authored May 31, 2021
2 parents b0fd0f2 + 056625a commit f6ae019
Show file tree
Hide file tree
Showing 11 changed files with 517 additions and 12 deletions.
56 changes: 56 additions & 0 deletions client/aws_credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package client

import (
"fmt"
)

func (self *ApiClient) AwsCredentials(id string) (ApiKey, error) {
var credentials, err = self.AwsCredentialsList()
if err != nil {
return ApiKey{}, err
}

for _, v := range credentials {
if v.Id == id {
return v, nil
}
}

return ApiKey{}, fmt.Errorf("AwsCredentials: [%s] not found ", id)
}

func (self *ApiClient) AwsCredentialsList() ([]ApiKey, error) {
organizationId, err := self.organizationId()
if err != nil {
return []ApiKey{}, err
}

var credentials []ApiKey
err = self.http.Get("/credentials", map[string]string{"organizationId": organizationId}, &credentials)
if err != nil {
return []ApiKey{}, err
}

return credentials, nil
}

func (self *ApiClient) AwsCredentialsCreate(request AwsCredentialsCreatePayload) (ApiKey, error) {
organizationId, err := self.organizationId()
if err != nil {
return ApiKey{}, err
}

request.Type = "AWS_ASSUMED_ROLE_FOR_DEPLOYMENT"
request.OrganizationId = organizationId

var result ApiKey
err = self.http.Post("/credentials", request, &result)
if err != nil {
return ApiKey{}, err
}
return result, nil
}

func (self *ApiClient) AwsCredentialsDelete(id string) error {
return self.http.Delete("/credentials/" + id)
}
125 changes: 125 additions & 0 deletions client/aws_credentials_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package client_test

import (
. "github.com/env0/terraform-provider-env0/client"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

const awsCredentialsName = "credential_test"

var _ = Describe("AwsCredentials", func() {
var apiKey ApiKey
mockApiKey := ApiKey{
Id: "id1",
Name: "key1",
OrganizationId: organizationId,
Type: "AWS_ASSUMED_ROLE_FOR_DEPLOYMENT",
}

mockApiKeySecond := ApiKey{
Id: "id2",
Name: "key2",
OrganizationId: organizationId,
Type: "AWS_ASSUMED_ROLE_FOR_DEPLOYMENT",
}

keys := []ApiKey{mockApiKey, mockApiKeySecond}

Describe("AwsCredentialsCreate", func() {
BeforeEach(func() {
mockOrganizationIdCall(organizationId)

httpCall = mockHttpClient.EXPECT().
Post("/credentials", AwsCredentialsCreatePayload{
Name: awsCredentialsName,
OrganizationId: organizationId,
Type: "AWS_ASSUMED_ROLE_FOR_DEPLOYMENT",
Value: AwsCredentialsValuePayload{
RoleArn: "role",
ExternalId: "external",
},
},
gomock.Any()).
Do(func(path string, request interface{}, response *ApiKey) {
*response = mockApiKey
})

apiKey, _ = apiClient.AwsCredentialsCreate(AwsCredentialsCreatePayload{
Name: awsCredentialsName,
Value: AwsCredentialsValuePayload{
RoleArn: "role",
ExternalId: "external",
},
})
})

It("Should get organization id", func() {
organizationIdCall.Times(1)
})

It("Should send POST request with params", func() {
httpCall.Times(1)
})

It("Should return key", func() {
Expect(apiKey).To(Equal(mockApiKey))
})
})

Describe("AwsCredentialsDelete", func() {
BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().Delete("/credentials/" + mockApiKey.Id)
apiClient.AwsCredentialsDelete(mockApiKey.Id)
})

It("Should send DELETE request with project id", func() {
httpCall.Times(1)
})
})

Describe("AwsCredentials", func() {
BeforeEach(func() {
mockOrganizationIdCall(organizationId)

httpCall = mockHttpClient.EXPECT().
Get("/credentials", map[string]string{"organizationId": organizationId}, gomock.Any()).
Do(func(path string, request interface{}, response *[]ApiKey) {
*response = keys
})
apiKey, _ = apiClient.AwsCredentials(mockApiKey.Id)
})

It("Should send GET request with project id", func() {
httpCall.Times(1)
})

It("Should return correct key", func() {
Expect(apiKey).To(Equal(mockApiKey))
})
})

Describe("AwsCredentialsList", func() {
var credentials []ApiKey

BeforeEach(func() {
mockOrganizationIdCall(organizationId)

httpCall = mockHttpClient.EXPECT().
Get("/credentials", map[string]string{"organizationId": organizationId}, gomock.Any()).
Do(func(path string, request interface{}, response *[]ApiKey) {
*response = keys
})
credentials, _ = apiClient.AwsCredentialsList()
})

It("Should send GET request with organization id param", func() {
httpCall.Times(1)
})

It("Should return all credentials", func() {
Expect(credentials).To(Equal(keys))
})
})
})
19 changes: 19 additions & 0 deletions client/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,22 @@ type SshKeyCreatePayload struct {
OrganizationId string `json:"organizationId"`
Value string `json:"value"`
}

type AwsCredentialsCreatePayload struct {
Name string `json:"name"`
OrganizationId string `json:"organizationId"`
Type string `json:"type"`
Value AwsCredentialsValuePayload `json:"value"`
}

type AwsCredentialsValuePayload struct {
RoleArn string `json:"roleArn"`
ExternalId string `json:"externalId"`
}

type ApiKey struct {
Id string `json:"id"`
Name string `json:"name"`
OrganizationId string `json:"organizationId"`
Type string `json:"type"`
}
92 changes: 92 additions & 0 deletions env0/data_aws_credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package env0

import (
"context"

"github.com/env0/terraform-provider-env0/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataAwsCredentials() *schema.Resource {
return &schema.Resource{
ReadContext: dataAwsCredentialsRead,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Description: "the name of the credential",
Optional: true,
ExactlyOneOf: []string{"name", "id"},
},
"id": {
Type: schema.TypeString,
Description: "the id of the credential",
Optional: true,
ExactlyOneOf: []string{"name", "id"},
},
},
}
}

func dataAwsCredentialsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var err diag.Diagnostics
var credentials client.ApiKey

id, ok := d.GetOk("id")
if ok {
credentials, err = getAwsCredentialsById(id.(string), meta)
if err != nil {
return err
}
} else {
name, ok := d.GetOk("name")
if !ok {
return diag.Errorf("Either 'name' or 'id' must be specified")
}
credentials, err = getAwsCredentialsByName(name.(string), meta)
if err != nil {
return err
}
}

d.SetId(credentials.Id)
d.Set("name", credentials.Name)

return nil
}

func getAwsCredentialsByName(name interface{}, meta interface{}) (client.ApiKey, diag.Diagnostics) {
apiClient := meta.(*client.ApiClient)
credentialsList, err := apiClient.AwsCredentialsList()
if err != nil {
return client.ApiKey{}, diag.Errorf("Could not query AWS Credentials by name: %v", err)
}

credentialsByNameAndType := make([]client.ApiKey, 0)
for _, candidate := range credentialsList {
if candidate.Name == name.(string) && candidate.Type == "AWS_ASSUMED_ROLE_FOR_DEPLOYMENT" {
credentialsByNameAndType = append(credentialsByNameAndType, candidate)
}
}

if len(credentialsByNameAndType) > 1 {
return client.ApiKey{}, diag.Errorf("Found multiple AWS Credentials for name: %s", name)
}
if len(credentialsByNameAndType) == 0 {
return client.ApiKey{}, diag.Errorf("Could not find AWS Credentials with name: %s", name)
}
return credentialsByNameAndType[0], nil
}

func getAwsCredentialsById(id string, meta interface{}) (client.ApiKey, diag.Diagnostics) {
apiClient := meta.(*client.ApiClient)
credentials, err := apiClient.AwsCredentials(id)
if credentials.Type != "aws_assumed_role" {
return client.ApiKey{}, diag.Errorf("Found credentials which are not AWS Credentials: %v", credentials)
}
if err != nil {
return client.ApiKey{}, diag.Errorf("Could not query AWS Credentials: %v", err)
}
return credentials, nil
}
2 changes: 2 additions & 0 deletions env0/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ func Provider() *schema.Provider {
"env0_configuration_variable": dataConfigurationVariable(),
"env0_template": dataTemplate(),
"env0_ssh_key": dataSshKey(),
"env0_aws_credentials": dataAwsCredentials(),
},
ResourcesMap: map[string]*schema.Resource{
"env0_project": resourceProject(),
"env0_configuration_variable": resourceConfigurationVariable(),
"env0_template": resourceTemplate(),
"env0_ssh_key": resourceSshKey(),
"env0_aws_credentials": resourceAwsCredentials(),
},
ConfigureFunc: configureProvider,
}
Expand Down
Loading

0 comments on commit f6ae019

Please sign in to comment.