-
Notifications
You must be signed in to change notification settings - Fork 9.2k
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
New Resource: aws_servicecatalog_product #2064
Conversation
@Ninir can you do a quick review and provide feedback on the suggested approach when you have a moment? |
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.
Hi @bw-intuit
thanks for sending the PR.
I left you some comments there. It may feel like a lot of feedback, but I'm confident we'll get through it together 😅 Let me know if anything's unclear or if you need further help.
Besides what I mentioned inline:
- It seems that the resource creation can take a short while and we should wait until the creation is complete - i.e. use StateChangeConf, example here: https://github.com/terraform-providers/terraform-provider-aws/blob/680afc8f836c14074d5502dc820128d289f552f3/aws/resource_aws_batch_job_queue.go#L65-L77
- Can you add a test which is adding, updating and removing artifacts?
- Do you mind adding documentation for this new resource?
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/awserr" | ||
|
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.
Nitpick: We tend to group all 3rd party imports in a single block.
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.
updating
Create: schema.DefaultTimeout(30 * time.Minute), | ||
Update: schema.DefaultTimeout(30 * time.Minute), | ||
Delete: schema.DefaultTimeout(30 * time.Minute), | ||
}, |
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.
Those custom timeout are not used anywhere, do you mind removing the definition?
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 catch, removing
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"created_time": { |
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.
Nitpick: Is there any good use case / reason for exposing this field? I'm not suggesting it's necessarily wrong, just curious what the user would do with it.
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.
No specific use case, removing. I didn't know the philosophy on including lesser used field for completeness vs being a bit more concise.
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"id": { |
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.
Computed id
(meta)field is always automatically available for all resources which is why we disallow the explicit definition in the schema:
TF_ACC=1 go test ./aws -v -run=TestAccAWSServiceCatalogProduct -timeout 120m
=== RUN TestAccAWSServiceCatalogProductBasic
--- FAIL: TestAccAWSServiceCatalogProductBasic (3.49s)
testing.go:518: Step 0 error: config is invalid: provider.aws: Internal validation of the provider failed! This is always a bug
with the provider itself, and not a user issue. Please report
this bug:
1 error(s) occurred:
* resource aws_servicecatalog_product: id is a reserved field name
Do you mind removing it?
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.
Got it, removing
conn := meta.(*AWSClient).scconn | ||
input := servicecatalog.CreateProductInput{} | ||
|
||
if v, ok := d.GetOk("name"); ok { |
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.
Generally speaking GetOk
helper is there for checking if an optional field was defined or not. This field is however required (as well as many other fields below which are being checked via GetOk
). Using Get()
would also allow us to simplify the code here a bit, e.g.
input := servicecatalog.CreateProductInput{
IdempotencyToken: resource.UniqueId(),
Name: aws.String(d.Get("name").(string)),
Owner: aws.String(d.Get("owner").(string)),
ProductType: aws.String(d.Get("product_type").(string)),
ProvisioningArtifactParameters: expandServiceCatalogProvisioningArtifacts(d.Get("provisioning_artifact").(*schema.Set).List())
}
which brings me to two other notes:
- We should generate a token we know for sure is going to be unique regardless of time. The chance of generating the same token twice is low, but not entirely impossible as Terraform can create resources in parallel. The helper I used in the above snippet comes from
github.com/hashicorp/terraform/helper/resource
and we use it for this exact purpose in other resources, e.g. EFS. While the implementation looks very similar (uses time too) it also uses mutex to guarantee uniqueness, at least within the scope of a single process. - We tend to decouple all logic that has anything to do with conversation between schema-friendly format (
map[string]interface{}
/schema.Set
etc.) and SDK structs. We call these functions expanders (schema -> SDK struct) and flatteners (SDK struct -> schema). This allows us to simplify and shorten overall LOC in the CRUD and make it easier to read. We usually keep all those helpers inaws/structure.go
.
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAWSServiceCatalogProductBasic(t *testing.T) { |
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.
Do you mind following the convention of TestAccAWSResourceName_(basic|another|test)
here? This convention allows us to easily filter tests for a specific resource without unintentionally running tests for other resources whose name overlaps with another resource.
e.g. if Amazon decided to introduce ServiceCatalogProductSomething
then we'd be forced to run tests for that resource because the only filter we can use is -run=TestAccAWSServiceCatalogProduct
. If instead we add the underscore we can filter like -run=TestAccAWSServiceCatalogProduct_
or -run=TestAccAWSServiceCatalogProductSomething_
which is much more precise.
} | ||
} | ||
|
||
func testAccCheckServiceCatlaogProductDestroy(s *terraform.State) error { |
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.
Typo ^ 👀
conn := testAccProvider.Meta().(*AWSClient).scconn | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "aws_servicecatalog_portfolio" { |
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.
Copy-paste error? I assume this should be aws_servicecatalog_product
.
_, err := conn.DescribeProduct(&input) | ||
if err == nil { | ||
return fmt.Errorf("Product still exists") | ||
} |
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.
Do you mind filtering the error here via isAWSErr(err, servicecatalog.ErrCodeResourceNotFoundException, "")
and still error out on any other error? i.e.
if err != nil {
if isAWSErr(err, servicecatalog.ErrCodeResourceNotFoundException, "") {
return nil
}
return err
}
return fmt.Errorf("Product still exists")
return true | ||
} | ||
return false | ||
}, |
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.
We can in fact source the URL from the API, so we shouldn't need the suppression function here:
https://docs.aws.amazon.com/servicecatalog/latest/dg/API_DescribeProvisioningArtifact.html#servicecatalog-DescribeProvisioningArtifact-response-Info
@radeksimko was about to get create / read / import working. Can you verify the direction is accurate and I will cleanup the code, address remaining comments and implement remaining functions? Thanks in advance |
Hope this PR will be done soon so i can enrich my tests for service catalog related data sources (product, launch path and provisioning artifact) and resource (product provisioning), making it ready for PR |
@bw-intuit i can give a hand on this if you don't mind. |
I'm forking @bw-intuit branch and making some changes per @radeksimko comments. I would likely to create a new PR to facilitate the review. Any objection? |
I created PR #4980 for review. I took into consideration all review comments and it's based on @bw-intuit branch. |
This appears to be superseded by #4980, which contains all the previous commits, so closing this one in preference of the newer pull request. |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks! |
@Ninir working on the service catalog product resource and wanted to get feedback on some coding decisions.
Each SC product will need to be created with an artifact (http://docs.aws.amazon.com/servicecatalog/latest/dg/API_CreateProduct.html#servicecatalog-CreateProduct-request-ProvisioningArtifactParameters)
I have moved the variables that describe it to an artifact block which will be managed as part of the service catalog resource for example:
There will also be a resource created for additional artifacts, however it will not be able to manage the artifact created with the product (http://docs.aws.amazon.com/servicecatalog/latest/dg/API_CreateProvisioningArtifact.html).
Does this approach make sense? Let me know and I'll polish it for review.