Skip to content

Commit

Permalink
Merge branch 'main' into chore-filter-out-scopes-#751
Browse files Browse the repository at this point in the history
  • Loading branch information
TomerHeber authored Nov 28, 2023
2 parents 855a93f + 2ba84fb commit b61a4d0
Show file tree
Hide file tree
Showing 22 changed files with 712 additions and 10 deletions.
1 change: 1 addition & 0 deletions client/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type ApiClientInterface interface {
VariablesFromRepository(payload *VariablesFromRepositoryPayload) ([]ConfigurationVariable, error)
SshKeys() ([]SshKey, error)
SshKeyCreate(payload SshKeyCreatePayload) (*SshKey, error)
SshKeyUpdate(id string, payload *SshKeyUpdatePayload) (*SshKey, error)
SshKeyDelete(id string) error
CredentialsCreate(request CredentialCreatePayload) (Credentials, error)
CredentialsUpdate(id string, request CredentialCreatePayload) (Credentials, error)
Expand Down
15 changes: 15 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.

9 changes: 5 additions & 4 deletions client/cloud_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@ type AzureCredentialsValuePayload struct {
}

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

type AwsCredentialsValuePayload struct {
RoleArn string `json:"roleArn" tfschema:"arn"`
Duration int `json:"duration,omitempty"`
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
AccessKeyId string `json:"accessKeyId,omitempty"`
SecretAccessKey string `json:"secretAccessKey,omitempty"`
}

type GoogleCostCredentialsCreatePayload struct {
Expand Down Expand Up @@ -101,6 +101,7 @@ const (
AwsCostCredentialsType AwsCredentialsType = "AWS_ASSUMED_ROLE"
AwsAssumedRoleCredentialsType AwsCredentialsType = "AWS_ASSUMED_ROLE_FOR_DEPLOYMENT"
AwsAccessKeysCredentialsType AwsCredentialsType = "AWS_ACCESS_KEYS_FOR_DEPLOYMENT"
AwsOidcCredentialsType AwsCredentialsType = "AWS_OIDC"
GcpServiceAccountCredentialsType GcpCredentialsType = "GCP_SERVICE_ACCOUNT_FOR_DEPLOYMENT"
AzureServicePrincipalCredentialsType AzureCredentialsType = "AZURE_SERVICE_PRINCIPAL_FOR_DEPLOYMENT"
)
Expand Down
13 changes: 13 additions & 0 deletions client/sshkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ type SshKeyCreatePayload struct {
Value string `json:"value"`
}

type SshKeyUpdatePayload struct {
Value string `json:"value"`
}

func (client *ApiClient) SshKeyCreate(payload SshKeyCreatePayload) (*SshKey, error) {
organizationId, err := client.OrganizationId()
if err != nil {
Expand All @@ -32,6 +36,15 @@ func (client *ApiClient) SshKeyCreate(payload SshKeyCreatePayload) (*SshKey, err
return &result, nil
}

func (client *ApiClient) SshKeyUpdate(id string, payload *SshKeyUpdatePayload) (*SshKey, error) {
var result SshKey

if err := client.http.Put("/ssh-keys/"+id, payload, &result); err != nil {
return nil, err
}
return &result, nil
}

func (client *ApiClient) SshKeyDelete(id string) error {
return client.http.Delete("/ssh-keys/"+id, nil)
}
Expand Down
33 changes: 33 additions & 0 deletions client/sshkey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,37 @@ var _ = Describe("SshKey", func() {
Expect(sshKeys).Should(ContainElement(mockSshKey))
})
})

Describe("SshKetUpdate", func() {
Describe("Success", func() {
updateMockSshKey := mockSshKey
updateMockSshKey.Value = "new-value"
var updatedSshKey *SshKey
var err error

BeforeEach(func() {
updateSshKeyPayload := SshKeyUpdatePayload{Value: updateMockSshKey.Value}

httpCall = mockHttpClient.EXPECT().
Put("/ssh-keys/"+mockSshKey.Id, &updateSshKeyPayload, gomock.Any()).
Do(func(path string, request interface{}, response *SshKey) {
*response = updateMockSshKey
})

updatedSshKey, err = apiClient.SshKeyUpdate(mockSshKey.Id, &updateSshKeyPayload)
})

It("Should send Put request with expected payload", func() {
httpCall.Times(1)
})

It("Should not return an error", func() {
Expect(err).To(BeNil())
})

It("Should return ssh key received from API", func() {
Expect(*updatedSshKey).To(Equal(updateMockSshKey))
})
})
})
})
21 changes: 21 additions & 0 deletions docs/data-sources/custom_flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "env0_custom_flow Data Source - terraform-provider-env0"
subcategory: ""
description: |-
---

# env0_custom_flow (Data Source)





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

### Optional

- `id` (String) ID of the custom flow
- `name` (String) The name of the custom flow
46 changes: 46 additions & 0 deletions docs/resources/aws_oidc_credentials.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "env0_aws_oidc_credentials Resource - terraform-provider-env0"
subcategory: ""
description: |-
---

# env0_aws_oidc_credentials (Resource)



## Example Usage

```terraform
resource "env0_aws_oidc_credentials" "credentials" {
name = "example"
role_arn = "arn::role::34"
duration = 3600
}
```

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

### Required

- `name` (String) name for the oidc credentials
- `role_arn` (String) the aws role arn

### Optional

- `duration` (Number) the session duration in seconds. If set must be one of the following: 3600 (1h), 7200 (2h), 14400 (4h), 18000 (5h default), 28800 (8h), 43200 (12h)

### Read-Only

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

## Import

Import is supported using the following syntax:

```shell
terraform import env0_aws_oidc_credentials.by_id d31a6b30-5f69-4d24-937c-22322754934e
terraform import env0_aws_oidc_credentials.by_name "credentials name"
```
10 changes: 10 additions & 0 deletions docs/resources/cloud_credentials_project_assignment.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ resource "env0_aws_credentials" "credentials" {
arn = "Example role ARN"
}
resource "env0_aws_oidc_credentials" "credentials" {
name = "example"
role_arn = "Example role ARN"
}
data "env0_project" "project" {
name = "Default Organization Project"
}
Expand All @@ -26,6 +31,11 @@ resource "env0_cloud_credentials_project_assignment" "example" {
credential_id = env0_aws_credentials.credentials.id
project_id = data.env0_project.project.id
}
resource "env0_cloud_credentials_project_assignment" "example_oidc" {
credential_id = env0_aws_oidc_credentials.credentials.id
project_id = data.env0_project.project.id
}
```

<!-- schema generated by tfplugindocs -->
Expand Down
2 changes: 2 additions & 0 deletions env0/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
GCP_COST_TYPE CloudType = "google_cost"
AZURE_COST_TYPE CloudType = "azure_cost"
AWS_COST_TYPE CloudType = "aws_cost"
AWS_OIDC_TYPE CloudType = "aws_oidc"
)

var credentialsTypeToPrefixList map[CloudType][]string = map[CloudType][]string{
Expand All @@ -30,6 +31,7 @@ var credentialsTypeToPrefixList map[CloudType][]string = map[CloudType][]string{
GCP_COST_TYPE: {string(client.GoogleCostCredentialsType)},
AZURE_COST_TYPE: {string(client.AzureCostCredentialsType)},
AWS_COST_TYPE: {string(client.AwsCostCredentialsType)},
AWS_OIDC_TYPE: {string(client.AwsOidcCredentialsType)},
}

func getCredentialsByName(name string, prefixList []string, meta interface{}) (client.Credentials, error) {
Expand Down
55 changes: 55 additions & 0 deletions env0/data_custom_flow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
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 dataCustomFlow() *schema.Resource {
return &schema.Resource{
ReadContext: dataCustomFlowRead,

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

func dataCustomFlowRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var err error
var customFlow *client.CustomFlow

id, ok := d.GetOk("id")
if ok {
customFlow, err = meta.(client.ApiClientInterface).CustomFlow(id.(string))
if err != nil {
return diag.Errorf("failed to get custom flow by id: %v", err)
}
} else {
name := d.Get("name")
customFlow, err = getCustomFlowByName(name.(string), meta)
if err != nil {
return diag.Errorf("failed to get custom flow by name: %v", err)
}
}

if err := writeResourceData(customFlow, d); err != nil {
return diag.Errorf("schema resource data serialization failed: %v", err)
}

return nil
}
100 changes: 100 additions & 0 deletions env0/data_custom_flow_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package env0

import (
"regexp"
"testing"

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

func TestCustomFlowDataSource(t *testing.T) {
customFlow := client.CustomFlow{
Id: "id0",
Name: "name0",
Repository: "rep1",
Path: "path",
}

otherCustomFlow := client.CustomFlow{
Id: "id1",
Name: "name1",
Repository: "rep2",
Path: "path",
}

customFlowFieldsByName := map[string]interface{}{"name": customFlow.Name}
customFlowFieldsById := map[string]interface{}{"id": customFlow.Id}

resourceType := "env0_custom_flow"
resourceName := "test_custom_flow"
accessor := dataSourceAccessor(resourceType, resourceName)

getValidTestCase := func(input map[string]interface{}) resource.TestCase {
return resource.TestCase{
Steps: []resource.TestStep{
{
Config: dataSourceConfigCreate(resourceType, resourceName, input),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(accessor, "id", customFlow.Id),
resource.TestCheckResourceAttr(accessor, "name", customFlow.Name),
),
},
},
}
}

getErrorTestCase := func(input map[string]interface{}, expectedError string) resource.TestCase {
return resource.TestCase{
Steps: []resource.TestStep{
{
Config: dataSourceConfigCreate(resourceType, resourceName, input),
ExpectError: regexp.MustCompile(expectedError),
},
},
}
}

mockListCustomFlowsCall := func(returnValue []client.CustomFlow) func(mockFunc *client.MockApiClientInterface) {
return func(mock *client.MockApiClientInterface) {
mock.EXPECT().CustomFlows(customFlow.Name).AnyTimes().Return(returnValue, nil)
}
}

mockCustomFlowCall := func(returnValue *client.CustomFlow) func(mockFunc *client.MockApiClientInterface) {
return func(mock *client.MockApiClientInterface) {
mock.EXPECT().CustomFlow(customFlow.Id).AnyTimes().Return(returnValue, nil)
}
}

t.Run("By ID", func(t *testing.T) {
runUnitTest(t,
getValidTestCase(customFlowFieldsById),
mockCustomFlowCall(&customFlow),
)
})

t.Run("By Name", func(t *testing.T) {
runUnitTest(t,
getValidTestCase(customFlowFieldsByName),
mockListCustomFlowsCall([]client.CustomFlow{customFlow}),
)
})

t.Run("Throw error when by name and more than one custom flow exists", func(t *testing.T) {
runUnitTest(t,
getErrorTestCase(customFlowFieldsByName, "found multiple custom flows with name"),
mockListCustomFlowsCall([]client.CustomFlow{customFlow, otherCustomFlow, customFlow}),
)
})

t.Run("Throw error when by id and no custom flow found with that id", func(t *testing.T) {
runUnitTest(t,
getErrorTestCase(customFlowFieldsById, "failed to get custom flow by id"),
func(mock *client.MockApiClientInterface) {
mock.EXPECT().CustomFlow(customFlow.Id).Times(1).Return(nil, http.NewMockFailedResponseError(404))
},
)
})
}
Loading

0 comments on commit b61a4d0

Please sign in to comment.