Skip to content

Commit

Permalink
Add Credentials-Project assignment resource (#72)
Browse files Browse the repository at this point in the history
* add creds project assignments

* some provider adjustments

* add client model and adapt provider

* fix typo

* added test file

* update interface

* change sign

* remove fmt

* remove validation flow

* remove description

* added error check

* added more tests

* update api

* tpo

* added to provider

* added example

* added docs

* remove template to project

* moved the docs

* updated the examples

* generated docs

* remove ssh

* fixed example

* added example

* fix wrong endpoint used

* fmt

* fix client/provider/api integration

* regen mocks

* fix most tests

* add model and test

* no 2nd run

* no 2nd run

Co-authored-by: eranelbaz <[email protected]>
  • Loading branch information
roni-frantchi and eranelbaz committed Jun 3, 2021
1 parent 4be2889 commit 7ce7051
Show file tree
Hide file tree
Showing 14 changed files with 383 additions and 9 deletions.
3 changes: 3 additions & 0 deletions client/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ type ApiClientInterface interface {
AwsCredentialsList() ([]ApiKey, error)
AwsCredentialsCreate(request AwsCredentialsCreatePayload) (ApiKey, error)
AwsCredentialsDelete(id string) error
AssignCloudCredentialsToProject(projectId string, credentialId string) (CloudCredentialsProjectAssignment, error)
RemoveCloudCredentialsFromProject(credentialId string, projectId string) error
CloudCredentialIdsInProject(projectId string) ([]string, error)
}

func NewApiClient(client http.HttpClientInterface) ApiClientInterface {
Expand Down
44 changes: 44 additions & 0 deletions client/api_client_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions client/cloud_credentials_project_assignment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package client

func (self *ApiClient) AssignCloudCredentialsToProject(projectId string, credentialId string) (CloudCredentialsProjectAssignment, error) {
var result CloudCredentialsProjectAssignment

err := self.http.Put("/credentials/deployment/"+credentialId+"/project/"+projectId, nil, &result)
if err != nil {
return result, err
}
return result, nil
}

func (self *ApiClient) RemoveCloudCredentialsFromProject(credentialId string, projectId string) error {
return self.http.Delete("/credentials/deployment/" + credentialId + "/project/" + projectId)
}

func (self *ApiClient) CloudCredentialIdsInProject(projectId string) ([]string, error) {
var result CloudCredentialIdsInProjectResponse
err := self.http.Get("/credentials/deployment/project/"+projectId, nil, &result)

if err != nil {
return nil, err
}
return result.CredentialIds, nil
}
115 changes: 115 additions & 0 deletions client/cloud_credentials_project_assignment_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package client_test

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

var _ = Describe("Credentials Project Assignment", func() {
projectId := "projectId"
credentialId := "credentialId"

Describe("AssignCloudCredentialsToProject", func() {
expectedResponse := CloudCredentialsProjectAssignment{
Id: "assigment id",
CredentialId: "credentialId",
ProjectId: projectId,
}
Describe("Successful", func() {
var actualResult CloudCredentialsProjectAssignment
BeforeEach(func() {

httpCall = mockHttpClient.EXPECT().
Put("/credentials/deployment/"+credentialId+"/project/"+projectId, nil, gomock.Any()).
Do(func(path string, request interface{}, response *CloudCredentialsProjectAssignment) {
*response = expectedResponse
}).Times(1)
actualResult, _ = apiClient.AssignCloudCredentialsToProject(projectId, credentialId)

})

It("should return the PUT result", func() {
Expect(actualResult).To(Equal(expectedResponse))
})
})
Describe("On Error", func() {
errorInfo := "error"
var actualError error
BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Put("/credentials/deployment/"+credentialId+"/project/"+projectId, nil, gomock.Any()).
Return(errors.New(errorInfo)).
Times(1)
_, actualError = apiClient.AssignCloudCredentialsToProject(projectId, credentialId)

})

It("should return the error from the api call", func() {
Expect(actualError).ShouldNot(BeNil())
Expect(actualError.Error()).Should(Equal(errorInfo))
})
})
})

Describe("RemoveCloudCredentialsFromProject", func() {
errorInfo := "error"
var actualError error
BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Delete("/credentials/deployment/" + credentialId + "/project/" + projectId).
Return(errors.New(errorInfo)).
Times(1)
actualError = apiClient.RemoveCloudCredentialsFromProject(credentialId, projectId)

})

It("should return the error from the api call", func() {
Expect(actualError).ShouldNot(BeNil())
Expect(actualError.Error()).Should(Equal(errorInfo))
})
})

Describe("CloudCredentialIdsInProject", func() {
Describe("Successful", func() {
var actualResult []string

expectedResponse := CloudCredentialIdsInProjectResponse{
CredentialIds: []string{"credentialId"},
}
BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Get("/credentials/deployment/project/"+projectId, nil, gomock.Any()).
Do(func(path string, request interface{}, response *CloudCredentialIdsInProjectResponse) {
*response = expectedResponse
}).Times(1)
actualResult, _ = apiClient.CloudCredentialIdsInProject(projectId)

})

It("should return the GET result", func() {
Expect(actualResult).To(Equal(expectedResponse.CredentialIds))
})
})
Describe("On Error", func() {
errorInfo := "error"
var actualError error
BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Get("/credentials/deployment/project/"+projectId, nil, gomock.Any()).
Return(errors.New(errorInfo)).
Times(1)
_, actualError = apiClient.CloudCredentialIdsInProject(projectId)

})

It("should return the error from the api call", func() {
Expect(actualError).ShouldNot(BeNil())
Expect(actualError.Error()).Should(Equal(errorInfo))
})
})

})
})
14 changes: 14 additions & 0 deletions client/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@ type TemplateAssignmentToProject struct {
ProjectId string `json:"projectId"`
}

type CloudCredentialIdsInProjectResponse struct {
CredentialIds []string `json:"credentialIds"`
}

type CloudCredentialsProjectAssignmentPatchPayload struct {
CredentialIds []string `json:"credentialIds"`
}

type CloudCredentialsProjectAssignment struct {
Id string `json:"id"`
CredentialId string `json:"credentialId"`
ProjectId string `json:"projectId"`
}

type Template struct {
Author User `json:"author"`
AuthorId string `json:"authorId"`
Expand Down
2 changes: 1 addition & 1 deletion docs/resources/aws_credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ description: |-
## Example Usage

```terraform
resource "env0_aws_credentials" "example" {
resource "env0_aws_credentials" "credentials" {
name = "example"
arn = "Example role ARN"
external_id = "Example external id"
Expand Down
44 changes: 44 additions & 0 deletions docs/resources/cloud_credentials_project_assignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "env0_cloud_credentials_project_assignment Resource - terraform-provider-env0"
subcategory: ""
description: |-
---

# env0_cloud_credentials_project_assignment (Resource)



## Example Usage

```terraform
resource "env0_aws_credentials" "credentials" {
name = "example"
arn = "Example role ARN"
external_id = "Example external id"
}
data "env0_project" "project" {
name = "Default Organization Project"
}
resource "env0_cloud_credentials_project_assignment" "example" {
credential_id = data.env0_aws_credentials.credentials.id
project_id = data.env0_project.project.id
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- **credential_id** (String) id of cloud credentials
- **project_id** (String) id of the project

### Optional

- **id** (String) The ID of this resource.


13 changes: 7 additions & 6 deletions env0/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ func Provider() *schema.Provider {
"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(),
"env0_template_project_assignment": resourceTemplateProjectAssignment(),
"env0_project": resourceProject(),
"env0_configuration_variable": resourceConfigurationVariable(),
"env0_template": resourceTemplate(),
"env0_ssh_key": resourceSshKey(),
"env0_aws_credentials": resourceAwsCredentials(),
"env0_template_project_assignment": resourceTemplateProjectAssignment(),
"env0_cloud_credentials_project_assignment": resourceCloudCredentialsProjectAssignment(),
},
ConfigureContextFunc: configureProvider,
}
Expand Down
85 changes: 85 additions & 0 deletions env0/resource_cloud_credentials_project_assignment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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 resourceCloudCredentialsProjectAssignment() *schema.Resource {
return &schema.Resource{
CreateContext: resourceCloudCredentialsProjectAssignmentCreate,
ReadContext: resourceCloudCredentialsProjectAssignmentRead,
DeleteContext: resourceCloudCredentialsProjectAssignmentDelete,

Schema: map[string]*schema.Schema{
"credential_id": {
Type: schema.TypeString,
Description: "id of cloud credentials",
Required: true,
ForceNew: true,
},
"project_id": {
Type: schema.TypeString,
Description: "id of the project",
Required: true,
ForceNew: true,
},
},
}
}

func resourceCloudCredentialsProjectAssignmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
apiClient := meta.(*client.ApiClient)

credentialId := d.Get("credential_id").(string)
projectId := d.Get("project_id").(string)
result, err := apiClient.AssignCloudCredentialsToProject(projectId, credentialId)
if err != nil {
return diag.Errorf("could not assign cloud credentials to project: %v", err)
}
d.SetId(getResourceId(result.CredentialId, result.ProjectId))
return nil
}

func resourceCloudCredentialsProjectAssignmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
apiClient := meta.(*client.ApiClient)

credentialId := d.Get("credential_id").(string)
projectId := d.Get("project_id").(string)
credentialsList, err := apiClient.CloudCredentialIdsInProject(projectId)
if err != nil {
return diag.Errorf("could not get cloud_credentials: %v", err)
}
found := false
for _, candidate := range credentialsList {
if candidate == credentialId {
found = true
}
}
if !found {
return diag.Errorf("could not find cloud credential project assignment.\n project id = %v, cloud credentials id = %v", projectId, credentialId)
}

d.SetId(getResourceId(credentialId, projectId))

return nil
}

func getResourceId(credentialId string, projectId string) string {
return credentialId + "|" + projectId
}

func resourceCloudCredentialsProjectAssignmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
apiClient := meta.(*client.ApiClient)

credential_id := d.Get("credential_id").(string)
projectId := d.Get("project_id").(string)
err := apiClient.RemoveCloudCredentialsFromProject(credential_id, projectId)
if err != nil {
return diag.Errorf("could not delete cloud credentials from project: %v", err)
}
return nil
}
Loading

0 comments on commit 7ce7051

Please sign in to comment.