-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat cloud cost credentials data - 218 #317
Merged
Merged
Changes from 5 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
cb21981
add resource and data for azure cost cred
samuel-br 6da1bf6
remove mistake files
samuel-br 225b68d
Merge branch 'main' of https://github.com/env0/terraform-provider-env…
samuel-br 86ab291
add data
samuel-br d271d95
add provider
samuel-br 25abca2
Merge branch 'main' of https://github.com/env0/terraform-provider-env…
samuel-br c8b024e
Update env0/data_aws_cost_credentials.go
samuel-br 656d2c9
update
samuel-br 4eec18f
write schema and errors
samuel-br 712061b
Merge branch 'main' of https://github.com/env0/terraform-provider-env…
samuel-br faf5f15
add one func to all resource
samuel-br e01e852
Merge branch 'main' of https://github.com/env0/terraform-provider-env…
samuel-br cbf1148
fix typo
samuel-br b8e1491
fix DRY
samuel-br 145fefd
fix conflict
samuel-br bc09e0d
Merge branch 'main' into feat_cloud_cost_cred_data-#218
yaronya File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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 dataAwsCostCredentials() *schema.Resource { | ||
return &schema.Resource{ | ||
ReadContext: dataAwsCostCredentialsRead, | ||
|
||
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 dataAwsCostCredentialsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
var err diag.Diagnostics | ||
var credentials client.Credentials | ||
|
||
id, ok := d.GetOk("id") | ||
if ok { | ||
credentials, err = getAwsCostCredentialsById(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 = getAwsCostCredentialsByName(name.(string), meta) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
d.SetId(credentials.Id) | ||
d.Set("name", credentials.Name) | ||
|
||
return nil | ||
} | ||
|
||
func getAwsCostCredentialsByName(name interface{}, meta interface{}) (client.Credentials, diag.Diagnostics) { | ||
apiClient := meta.(client.ApiClientInterface) | ||
credentialsList, err := apiClient.CloudCredentialsList() | ||
if err != nil { | ||
return client.Credentials{}, diag.Errorf("Could not query AWS Cost Credentials by name: %v", err) | ||
} | ||
|
||
credentialsByNameAndType := make([]client.Credentials, 0) | ||
for _, candidate := range credentialsList { | ||
if candidate.Name == name.(string) && candidate.Type == string(client.AwsCostCredentialsType) { | ||
credentialsByNameAndType = append(credentialsByNameAndType, candidate) | ||
} | ||
} | ||
|
||
if len(credentialsByNameAndType) > 1 { | ||
return client.Credentials{}, diag.Errorf("Found multiple AWS Cost Credentials for name: %s", name) | ||
} | ||
if len(credentialsByNameAndType) == 0 { | ||
return client.Credentials{}, diag.Errorf("Could not find AWS Cost Credentials with name: %s", name) | ||
} | ||
return credentialsByNameAndType[0], nil | ||
} | ||
|
||
func getAwsCostCredentialsById(id string, meta interface{}) (client.Credentials, diag.Diagnostics) { | ||
apiClient := meta.(client.ApiClientInterface) | ||
credentials, err := apiClient.CloudCredentials(id) | ||
if credentials.Type != string(client.AwsCostCredentialsType) { | ||
return client.Credentials{}, diag.Errorf("Found credentials which are not AWS Cost Credentials: %v", credentials) | ||
samuel-br marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
if err != nil { | ||
return client.Credentials{}, diag.Errorf("Could not query AWS Cost Credentials: %v", err) | ||
} | ||
return credentials, 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,112 @@ | ||
package env0 | ||
|
||
import ( | ||
"regexp" | ||
"testing" | ||
|
||
"github.com/env0/terraform-provider-env0/client" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
) | ||
|
||
func TestUnitAwsCostCredentialsData(t *testing.T) { | ||
awsCred := client.Credentials{ | ||
Id: "11111", | ||
Name: "testdata", | ||
OrganizationId: "id", | ||
Type: "AWS_ASSUMED_ROLE", | ||
} | ||
|
||
credWithInvalidType := client.Credentials{ | ||
Id: awsCred.Id, | ||
Name: awsCred.Name, | ||
OrganizationId: awsCred.OrganizationId, | ||
Type: "Invalid-type", | ||
} | ||
|
||
otherAwsCred := client.Credentials{ | ||
Id: "22222", | ||
Name: "notTestdata", | ||
OrganizationId: "OtherId", | ||
Type: "AWS_ACCESS_KEYS_FOR_DEPLOYMENT", | ||
} | ||
|
||
AwsCredFieldsByName := map[string]interface{}{"name": awsCred.Name} | ||
AwsCredFieldsById := map[string]interface{}{"id": awsCred.Id} | ||
|
||
resourceType := "env0_aws_cost_credentials" | ||
resourceName := "testdata" | ||
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", awsCred.Id), | ||
resource.TestCheckResourceAttr(accessor, "name", awsCred.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), | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
mockGetAwsCredCall := func(returnValue client.Credentials) func(mockFunc *client.MockApiClientInterface) { | ||
return func(mock *client.MockApiClientInterface) { | ||
mock.EXPECT().CloudCredentials(awsCred.Id).AnyTimes().Return(returnValue, nil) | ||
} | ||
} | ||
|
||
mockListAwsCredCall := func(returnValue []client.Credentials) func(mockFunc *client.MockApiClientInterface) { | ||
return func(mock *client.MockApiClientInterface) { | ||
mock.EXPECT().CloudCredentialsList().AnyTimes().Return(returnValue, nil) | ||
} | ||
} | ||
|
||
t.Run("By ID", func(t *testing.T) { | ||
runUnitTest(t, | ||
getValidTestCase(AwsCredFieldsById), | ||
mockGetAwsCredCall(awsCred), | ||
) | ||
}) | ||
|
||
t.Run("By Name", func(t *testing.T) { | ||
runUnitTest(t, | ||
getValidTestCase(AwsCredFieldsByName), | ||
mockListAwsCredCall([]client.Credentials{awsCred, otherAwsCred, credWithInvalidType}), | ||
) | ||
}) | ||
|
||
t.Run("Throw error when no name or id is supplied", func(t *testing.T) { | ||
runUnitTest(t, | ||
getErrorTestCase(map[string]interface{}{}, "one of `id,name` must be specified"), | ||
func(mock *client.MockApiClientInterface) {}, | ||
) | ||
}) | ||
|
||
t.Run("Throw error when by name and more than one aws-credential exists with the relevant name", func(t *testing.T) { | ||
runUnitTest(t, | ||
getErrorTestCase(AwsCredFieldsByName, "Found multiple AWS Cost Credentials for name: testdata"), | ||
mockListAwsCredCall([]client.Credentials{awsCred, awsCred, awsCred}), | ||
) | ||
}) | ||
|
||
t.Run("Throw error when by name and no aws-credential found with that name", func(t *testing.T) { | ||
runUnitTest(t, | ||
getErrorTestCase(AwsCredFieldsByName, "Could not find AWS Cost Credentials with name: testdata"), | ||
mockListAwsCredCall([]client.Credentials{otherAwsCred, credWithInvalidType}), | ||
) | ||
}) | ||
|
||
} |
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,93 @@ | ||
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 dataAzureCostCredentials() *schema.Resource { | ||
return &schema.Resource{ | ||
ReadContext: dataAzureCostCredentialsRead, | ||
|
||
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 dataAzureCostCredentialsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
var err diag.Diagnostics | ||
var credentials client.Credentials | ||
|
||
id, ok := d.GetOk("id") | ||
if ok { | ||
credentials, err = getAzureCostCredentialsById(id.(string), meta) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
name, _ := d.Get("name").(string) // name must be specified here | ||
credentials, err = getAzureCostCredentialsByName(name, meta) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
d.SetId(credentials.Id) | ||
d.Set("name", credentials.Name) | ||
|
||
return nil | ||
} | ||
|
||
func getAzureCostCredentialsByName(name interface{}, meta interface{}) (client.Credentials, diag.Diagnostics) { | ||
apiClient := meta.(client.ApiClientInterface) | ||
credentialsList, err := apiClient.CloudCredentialsList() | ||
if err != nil { | ||
return client.Credentials{}, diag.Errorf("Could not query Azure Credentials by name: %v", err) | ||
} | ||
|
||
credentialsByNameAndType := make([]client.Credentials, 0) | ||
for _, candidate := range credentialsList { | ||
if candidate.Name == name.(string) && isValidAzureCostCredentialsType(candidate.Type) { | ||
credentialsByNameAndType = append(credentialsByNameAndType, candidate) | ||
} | ||
} | ||
|
||
if len(credentialsByNameAndType) > 1 { | ||
return client.Credentials{}, diag.Errorf("Found multiple Azure cost Credentials for name: %s", name) | ||
} | ||
if len(credentialsByNameAndType) == 0 { | ||
return client.Credentials{}, diag.Errorf("Could not find Azure cost Credentials with name: %s", name) | ||
} | ||
return credentialsByNameAndType[0], nil | ||
} | ||
|
||
func getAzureCostCredentialsById(id string, meta interface{}) (client.Credentials, diag.Diagnostics) { | ||
apiClient := meta.(client.ApiClientInterface) | ||
credentials, err := apiClient.CloudCredentials(id) | ||
if !isValidAzureCostCredentialsType(credentials.Type) { | ||
return client.Credentials{}, diag.Errorf("Found credentials which are not Azure Credentials: %v", credentials) | ||
} | ||
if err != nil { | ||
return client.Credentials{}, diag.Errorf("Could not query Azure Credentials: %v", err) | ||
} | ||
return credentials, nil | ||
} | ||
|
||
func isValidAzureCostCredentialsType(credentialsType string) bool { | ||
return client.AzureCredentialsType(credentialsType) == client.AzureCostCredentialsType | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the new common
writeResourceData
instead. Have a look at existing usages of it to get the idea.Note: this comment is relevant to all other resources
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point ill do it, just a little note, the function you mention based on the name of the field in schema against the field name in the struct , in aws creds we have 'arn' in schema but the struct field is 'RoleArn so in some places like that we cant use those functions, or we can just change the name of the field in struct/schema
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4eec18f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So how did you solve that arn -> RoleArn tranform?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this specific code there is no
arn
attribute so I do used the function you suggested , but in resource(no data resource) for example I cant use it, another problem in this function is when the value of the filed in the struct is struct itself likevalue
inawscredentialscreate
but for this I have a solution, anyway its not enough because the problem we talked above, unless we change the schema field name torole_arn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok understood.
Regarding your last sentence - I do think we should change it to
role_arn
so: