-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: add new OIDC credentials creation and assigment (AWS Resource)
- Loading branch information
1 parent
7ef0e10
commit 5d28bb1
Showing
9 changed files
with
358 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
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 resourceAwsOidcCredentials() *schema.Resource { | ||
return &schema.Resource{ | ||
CreateContext: resourceAwsOidcCredentialsCreate, | ||
UpdateContext: resourceAwsOidcCredentialsUpdate, | ||
ReadContext: resourceCredentialsRead(AWS_OIDC_TYPE), | ||
DeleteContext: resourceCredentialsDelete, | ||
|
||
Importer: &schema.ResourceImporter{StateContext: resourceCredentialsImport(AWS_OIDC_TYPE)}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Description: "name for the oidc credentials", | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"role_arn": { | ||
Type: schema.TypeString, | ||
Description: "the aws role arn", | ||
Required: true, | ||
}, | ||
"duration": { | ||
Type: schema.TypeInt, | ||
Description: "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)", | ||
Optional: true, | ||
ValidateDiagFunc: NewIntInValidator([]int{3600, 7200, 14400, 18000, 28800, 43200}), | ||
Default: 18000, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceAwsOidcCredentialsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
apiClient := meta.(client.ApiClientInterface) | ||
|
||
value := client.AwsCredentialsValuePayload{} | ||
if err := readResourceData(&value, d); err != nil { | ||
return diag.Errorf("schema resource data deserialization failed: %v", err) | ||
} | ||
|
||
value.RoleArn = d.Get("role_arn").(string) // tfschema is set (for older resources) need to manually set the role arn. | ||
|
||
request := client.AwsCredentialsCreatePayload{ | ||
Name: d.Get("name").(string), | ||
Value: value, | ||
Type: client.AwsOidcCredentialsType, | ||
} | ||
|
||
credentials, err := apiClient.CredentialsCreate(&request) | ||
if err != nil { | ||
return diag.Errorf("could not create aws oidc credentials: %v", err) | ||
} | ||
|
||
d.SetId(credentials.Id) | ||
|
||
return nil | ||
} | ||
|
||
func resourceAwsOidcCredentialsUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
apiClient := meta.(client.ApiClientInterface) | ||
|
||
value := client.AwsCredentialsValuePayload{} | ||
if err := readResourceData(&value, d); err != nil { | ||
return diag.Errorf("schema resource data deserialization failed: %v", err) | ||
} | ||
|
||
value.RoleArn = d.Get("role_arn").(string) // tfschema is set (for older resources) need to manually set the role arn. | ||
|
||
request := client.AwsCredentialsCreatePayload{ | ||
Value: value, | ||
Type: client.AwsOidcCredentialsType, | ||
} | ||
|
||
if _, err := apiClient.CredentialsUpdate(d.Id(), &request); err != nil { | ||
return diag.Errorf("could not update aws oidc credentials: %s %v", d.Id(), err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
package env0 | ||
|
||
import ( | ||
"fmt" | ||
"regexp" | ||
"strconv" | ||
"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" | ||
"go.uber.org/mock/gomock" | ||
) | ||
|
||
func TestUnitAwsOidcCredentialsResource(t *testing.T) { | ||
resourceType := "env0_aws_oidc_credentials" | ||
resourceName := "test" | ||
resourceNameImport := resourceType + "." + resourceName | ||
accessor := resourceAccessor(resourceType, resourceName) | ||
|
||
duration := 3600 | ||
updatedDuration := 2 * duration | ||
|
||
awsCredentialsResource := map[string]interface{}{ | ||
"name": "test", | ||
"role_arn": "11111", | ||
"duration": strconv.Itoa(duration), | ||
} | ||
|
||
updatedAwsCredentialsResource := map[string]interface{}{ | ||
"name": "test", | ||
"role_arn": "22222", | ||
"duration": strconv.Itoa(updatedDuration), | ||
} | ||
|
||
createPayload := client.AwsCredentialsCreatePayload{ | ||
Name: awsCredentialsResource["name"].(string), | ||
Value: client.AwsCredentialsValuePayload{ | ||
RoleArn: awsCredentialsResource["role_arn"].(string), | ||
Duration: duration, | ||
}, | ||
Type: client.AwsOidcCredentialsType, | ||
} | ||
|
||
updatePayload := client.AwsCredentialsCreatePayload{ | ||
Value: client.AwsCredentialsValuePayload{ | ||
RoleArn: updatedAwsCredentialsResource["role_arn"].(string), | ||
Duration: updatedDuration, | ||
}, | ||
Type: client.AwsOidcCredentialsType, | ||
} | ||
|
||
returnValues := client.Credentials{ | ||
Id: "f595c4b6-0a24-4c22-89f7-7030045de30f", | ||
Name: "test", | ||
OrganizationId: "id", | ||
Type: string(client.AwsOidcCredentialsType), | ||
} | ||
|
||
otherTypeReturnValues := client.Credentials{ | ||
Id: "f595c4b6-0a24-4c22-89f7-7030045de30a", | ||
Name: "test", | ||
OrganizationId: "id", | ||
Type: "AWS_....", | ||
} | ||
|
||
updateReturnValues := client.Credentials{ | ||
Id: returnValues.Id, | ||
Name: returnValues.Name, | ||
OrganizationId: "id", | ||
Type: string(client.AwsOidcCredentialsType), | ||
} | ||
|
||
testCaseForCreateAndUpdate := resource.TestCase{ | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: resourceConfigCreate(resourceType, resourceName, awsCredentialsResource), | ||
Check: resource.ComposeAggregateTestCheckFunc( | ||
resource.TestCheckResourceAttr(accessor, "name", awsCredentialsResource["name"].(string)), | ||
resource.TestCheckResourceAttr(accessor, "role_arn", awsCredentialsResource["role_arn"].(string)), | ||
resource.TestCheckResourceAttr(accessor, "id", returnValues.Id), | ||
resource.TestCheckResourceAttr(accessor, "duration", awsCredentialsResource["duration"].(string)), | ||
), | ||
}, | ||
{ | ||
Config: resourceConfigCreate(resourceType, resourceName, updatedAwsCredentialsResource), | ||
Check: resource.ComposeAggregateTestCheckFunc( | ||
resource.TestCheckResourceAttr(accessor, "name", updatedAwsCredentialsResource["name"].(string)), | ||
resource.TestCheckResourceAttr(accessor, "role_arn", updatedAwsCredentialsResource["role_arn"].(string)), | ||
resource.TestCheckResourceAttr(accessor, "id", updateReturnValues.Id), | ||
resource.TestCheckResourceAttr(accessor, "duration", updatedAwsCredentialsResource["duration"].(string)), | ||
), | ||
}, | ||
}, | ||
} | ||
|
||
t.Run("create and update", func(t *testing.T) { | ||
runUnitTest(t, testCaseForCreateAndUpdate, func(mock *client.MockApiClientInterface) { | ||
gomock.InOrder( | ||
mock.EXPECT().CredentialsCreate(&createPayload).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentials(returnValues.Id).Times(2).Return(returnValues, nil), | ||
mock.EXPECT().CredentialsUpdate(returnValues.Id, &updatePayload).Times(1).Return(updateReturnValues, nil), | ||
mock.EXPECT().CloudCredentials(updateReturnValues.Id).Times(1).Return(updateReturnValues, nil), | ||
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil), | ||
) | ||
}) | ||
}) | ||
|
||
t.Run("drift", func(t *testing.T) { | ||
stepConfig := resourceConfigCreate(resourceType, resourceName, awsCredentialsResource) | ||
|
||
createTestCase := resource.TestCase{ | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: stepConfig, | ||
}, | ||
{ | ||
Config: stepConfig, | ||
}, | ||
}, | ||
} | ||
|
||
runUnitTest(t, createTestCase, func(mock *client.MockApiClientInterface) { | ||
gomock.InOrder( | ||
mock.EXPECT().CredentialsCreate(&createPayload).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentials(returnValues.Id).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentials(returnValues.Id).Times(1).Return(returnValues, http.NewMockFailedResponseError(404)), | ||
mock.EXPECT().CredentialsCreate(&createPayload).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentials(returnValues.Id).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil), | ||
) | ||
}) | ||
}) | ||
|
||
t.Run("import by name", func(t *testing.T) { | ||
testCase := resource.TestCase{ | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: resourceConfigCreate(resourceType, resourceName, awsCredentialsResource), | ||
}, | ||
{ | ||
ResourceName: resourceNameImport, | ||
ImportState: true, | ||
ImportStateId: awsCredentialsResource["name"].(string), | ||
ImportStateVerify: true, | ||
ImportStateVerifyIgnore: []string{"role_arn", "duration"}, | ||
}, | ||
}, | ||
} | ||
|
||
runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) { | ||
gomock.InOrder( | ||
mock.EXPECT().CredentialsCreate(&createPayload).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentials(returnValues.Id).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentialsList().Times(1).Return([]client.Credentials{otherTypeReturnValues, returnValues}, nil), | ||
mock.EXPECT().CloudCredentials(returnValues.Id).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil), | ||
) | ||
}) | ||
}) | ||
|
||
t.Run("import by id", func(t *testing.T) { | ||
testCase := resource.TestCase{ | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: resourceConfigCreate(resourceType, resourceName, awsCredentialsResource), | ||
}, | ||
{ | ||
ResourceName: resourceNameImport, | ||
ImportState: true, | ||
ImportStateId: returnValues.Id, | ||
ImportStateVerify: true, | ||
ImportStateVerifyIgnore: []string{"role_arn", "duration"}, | ||
}, | ||
}, | ||
} | ||
|
||
runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) { | ||
gomock.InOrder( | ||
mock.EXPECT().CredentialsCreate(&createPayload).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentials(returnValues.Id).Times(3).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil), | ||
) | ||
}) | ||
}) | ||
|
||
t.Run("import by id not found", func(t *testing.T) { | ||
testCase := resource.TestCase{ | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: resourceConfigCreate(resourceType, resourceName, awsCredentialsResource), | ||
}, | ||
{ | ||
ResourceName: resourceNameImport, | ||
ImportState: true, | ||
ImportStateId: otherTypeReturnValues.Id, | ||
ImportStateVerify: true, | ||
ExpectError: regexp.MustCompile("credentials not found"), | ||
}, | ||
}, | ||
} | ||
|
||
runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) { | ||
gomock.InOrder( | ||
mock.EXPECT().CredentialsCreate(&createPayload).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentials(returnValues.Id).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentials(otherTypeReturnValues.Id).Times(1).Return(client.Credentials{}, &client.NotFoundError{}), | ||
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil), | ||
) | ||
}) | ||
}) | ||
|
||
t.Run("import by name not found", func(t *testing.T) { | ||
testCase := resource.TestCase{ | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: resourceConfigCreate(resourceType, resourceName, awsCredentialsResource), | ||
}, | ||
{ | ||
ResourceName: resourceNameImport, | ||
ImportState: true, | ||
ImportStateId: awsCredentialsResource["name"].(string), | ||
ImportStateVerify: true, | ||
ExpectError: regexp.MustCompile(fmt.Sprintf("credentials with name %v not found", awsCredentialsResource["name"].(string))), | ||
}, | ||
}, | ||
} | ||
|
||
runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) { | ||
gomock.InOrder( | ||
mock.EXPECT().CredentialsCreate(&createPayload).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentials(returnValues.Id).Times(1).Return(returnValues, nil), | ||
mock.EXPECT().CloudCredentialsList().Times(1).Return([]client.Credentials{otherTypeReturnValues}, nil), | ||
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil), | ||
) | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
terraform import env0_aws_oidc_credentials.by_id d31a6b30-5f69-4d24-937c-22322754934e | ||
terraform import env0_aws_oidc_credentials.by_name "credentials name" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
resource "env0_aws_oidc_credentials" "credentials" { | ||
name = "example" | ||
role_arn = "arn::role::34" | ||
duration = 3600 | ||
} |
Oops, something went wrong.