Skip to content

Commit

Permalink
Merge pull request #19316 from hashicorp/f-servicecat-provisioning-ar…
Browse files Browse the repository at this point in the history
…tifact

r/servicecatalog_provisioning_artifact: New resource
  • Loading branch information
YakDriver committed May 20, 2021
2 parents 32a7484 + 9d153a0 commit 6c604df
Show file tree
Hide file tree
Showing 11 changed files with 1,005 additions and 98 deletions.
3 changes: 3 additions & 0 deletions .changelog/19316.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_servicecatalog_provisioning_artifact
```
13 changes: 13 additions & 0 deletions aws/internal/service/servicecatalog/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,16 @@ func TagOptionResourceAssociationParseID(id string) (string, string, error) {
func TagOptionResourceAssociationID(tagOptionID, resourceID string) string {
return strings.Join([]string{tagOptionID, resourceID}, ":")
}

func ProvisioningArtifactID(artifactID, productID string) string {
return strings.Join([]string{artifactID, productID}, ":")
}

func ProvisioningArtifactParseID(id string) (string, string, error) {
parts := strings.SplitN(id, ":", 2)

if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return "", "", fmt.Errorf("unexpected format of ID (%s), expected artifactID:productID", id)
}
return parts[0], parts[1], nil
}
25 changes: 25 additions & 0 deletions aws/internal/service/servicecatalog/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,28 @@ func TagOptionResourceAssociationStatus(conn *servicecatalog.ServiceCatalog, tag
return output, servicecatalog.StatusAvailable, err
}
}

func ProvisioningArtifactStatus(conn *servicecatalog.ServiceCatalog, id, productID string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &servicecatalog.DescribeProvisioningArtifactInput{
ProvisioningArtifactId: aws.String(id),
ProductId: aws.String(productID),
}

output, err := conn.DescribeProvisioningArtifact(input)

if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) {
return nil, StatusNotFound, err
}

if err != nil {
return nil, servicecatalog.StatusFailed, err
}

if output == nil || output.ProvisioningArtifactDetail == nil {
return nil, StatusUnavailable, err
}

return output, aws.StringValue(output.Status), err
}
}
47 changes: 44 additions & 3 deletions aws/internal/service/servicecatalog/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,22 @@ const (
TagOptionResourceAssociationReadyTimeout = 3 * time.Minute
TagOptionResourceAssociationDeleteTimeout = 3 * time.Minute

ProvisioningArtifactReadyTimeout = 3 * time.Minute
ProvisioningArtifactDeletedTimeout = 3 * time.Minute

StatusNotFound = "NOT_FOUND"
StatusUnavailable = "UNAVAILABLE"

// AWS documentation is wrong, says that status will be "AVAILABLE" but it is actually "CREATED"
ProductStatusCreated = "CREATED"
StatusCreated = "CREATED"

OrganizationAccessStatusError = "ERROR"
)

func ProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID string) (*servicecatalog.DescribeProductAsAdminOutput, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{servicecatalog.StatusCreating, StatusNotFound, StatusUnavailable},
Target: []string{servicecatalog.StatusAvailable, ProductStatusCreated},
Target: []string{servicecatalog.StatusAvailable, StatusCreated},
Refresh: ProductStatus(conn, acceptLanguage, productID),
Timeout: ProductReadyTimeout,
}
Expand All @@ -63,7 +66,7 @@ func ProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID

func ProductDeleted(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID string) (*servicecatalog.DescribeProductAsAdminOutput, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{servicecatalog.StatusCreating, servicecatalog.StatusAvailable, ProductStatusCreated, StatusUnavailable},
Pending: []string{servicecatalog.StatusCreating, servicecatalog.StatusAvailable, StatusCreated, StatusUnavailable},
Target: []string{StatusNotFound},
Refresh: ProductStatus(conn, acceptLanguage, productID),
Timeout: ProductDeleteTimeout,
Expand Down Expand Up @@ -366,3 +369,41 @@ func TagOptionResourceAssociationDeleted(conn *servicecatalog.ServiceCatalog, ta

return err
}

func ProvisioningArtifactReady(conn *servicecatalog.ServiceCatalog, id, productID string) (*servicecatalog.DescribeProvisioningArtifactOutput, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{servicecatalog.StatusCreating, StatusNotFound, StatusUnavailable},
Target: []string{servicecatalog.StatusAvailable, StatusCreated},
Refresh: ProvisioningArtifactStatus(conn, id, productID),
Timeout: ProvisioningArtifactReadyTimeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*servicecatalog.DescribeProvisioningArtifactOutput); ok {
return output, err
}

return nil, err
}

func ProvisioningArtifactDeleted(conn *servicecatalog.ServiceCatalog, id, productID string) error {
stateConf := &resource.StateChangeConf{
Pending: []string{servicecatalog.StatusCreating, servicecatalog.StatusAvailable, StatusCreated, StatusUnavailable},
Target: []string{StatusNotFound},
Refresh: ProvisioningArtifactStatus(conn, id, productID),
Timeout: ProvisioningArtifactDeletedTimeout,
}

_, err := stateConf.WaitForState()

if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) {
return nil
}

if err != nil {
return err
}

return nil
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,7 @@ func Provider() *schema.Provider {
"aws_servicecatalog_tag_option": resourceAwsServiceCatalogTagOption(),
"aws_servicecatalog_tag_option_resource_association": resourceAwsServiceCatalogTagOptionResourceAssociation(),
"aws_servicecatalog_product_portfolio_association": resourceAwsServiceCatalogProductPortfolioAssociation(),
"aws_servicecatalog_provisioning_artifact": resourceAwsServiceCatalogProvisioningArtifact(),
"aws_service_discovery_http_namespace": resourceAwsServiceDiscoveryHttpNamespace(),
"aws_service_discovery_private_dns_namespace": resourceAwsServiceDiscoveryPrivateDnsNamespace(),
"aws_service_discovery_public_dns_namespace": resourceAwsServiceDiscoveryPublicDnsNamespace(),
Expand Down
42 changes: 19 additions & 23 deletions aws/resource_aws_servicecatalog_constraint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,31 +240,27 @@ resource "aws_s3_bucket_object" "test" {
bucket = aws_s3_bucket.test.id
key = "%[1]s.json"
content = <<EOF
{
"Resources" : {
"MyVPC": {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"CidrBlock" : "10.0.0.0/16",
"Tags" : [
{"Key": "Name", "Value": "Primary_CF_VPC"}
]
content = jsonencode({
AWSTemplateFormatVersion = "2010-09-09"
Resources = {
MyVPC = {
Type = "AWS::EC2::VPC"
Properties = {
CidrBlock = "10.1.0.0/16"
}
}
}
},
"Outputs" : {
"DefaultSgId" : {
"Description": "The ID of default security group",
"Value" : { "Fn::GetAtt" : [ "MyVPC", "DefaultSecurityGroup" ]}
},
"VpcID" : {
"Description": "The VPC ID",
"Value" : { "Ref" : "MyVPC" }
Outputs = {
VpcID = {
Description = "VPC ID"
Value = {
Ref = "MyVPC"
}
}
}
}
}
EOF
})
}
resource "aws_servicecatalog_product" "test" {
Expand All @@ -275,7 +271,7 @@ resource "aws_servicecatalog_product" "test" {
provisioning_artifact_parameters {
disable_template_validation = true
name = %[1]q
template_url = "s3://${aws_s3_bucket.test.id}/${aws_s3_bucket_object.test.key}"
template_url = "https://${aws_s3_bucket.test.bucket_regional_domain_name}/${aws_s3_bucket_object.test.key}"
type = "CLOUD_FORMATION_TEMPLATE"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,31 +227,27 @@ func testAccAWSServiceCatalogProductPortfolioAssociationConfig_base(rName string
resource "aws_cloudformation_stack" "test" {
name = %[1]q
template_body = <<STACK
{
"Resources" : {
"MyVPC": {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"CidrBlock" : "10.0.0.0/16",
"Tags" : [
{"Key": "Name", "Value": "Primary_CF_VPC"}
]
template_body = jsonencode({
AWSTemplateFormatVersion = "2010-09-09"
Resources = {
MyVPC = {
Type = "AWS::EC2::VPC"
Properties = {
CidrBlock = "10.1.0.0/16"
}
}
}
},
"Outputs" : {
"DefaultSgId" : {
"Description": "The ID of default security group",
"Value" : { "Fn::GetAtt" : [ "MyVPC", "DefaultSecurityGroup" ]}
},
"VpcID" : {
"Description": "The VPC ID",
"Value" : { "Ref" : "MyVPC" }
Outputs = {
VpcID = {
Description = "VPC ID"
Value = {
Ref = "MyVPC"
}
}
}
}
}
STACK
})
}
resource "aws_servicecatalog_product" "test" {
Expand Down
94 changes: 44 additions & 50 deletions aws/resource_aws_servicecatalog_product_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import (
// add sweeper to delete known test servicecat products
func init() {
resource.AddTestSweepers("aws_servicecatalog_product", &resource.Sweeper{
Name: "aws_servicecatalog_product",
Dependencies: []string{},
F: testSweepServiceCatalogProducts,
Name: "aws_servicecatalog_product",
Dependencies: []string{
"aws_servicecatalog_provisioning_artifact",
},
F: testSweepServiceCatalogProducts,
})
}

Expand Down Expand Up @@ -104,7 +106,7 @@ func TestAccAWSServiceCatalogProduct_basic(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.name", rName),
resource.TestCheckResourceAttrSet(resourceName, "provisioning_artifact_parameters.0.template_url"),
resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.type", servicecatalog.ProvisioningArtifactTypeCloudFormationTemplate),
resource.TestCheckResourceAttr(resourceName, "status", waiter.ProductStatusCreated),
resource.TestCheckResourceAttr(resourceName, "status", waiter.StatusCreated),
resource.TestCheckResourceAttr(resourceName, "support_description", "supportbeskrivning"),
resource.TestCheckResourceAttr(resourceName, "support_email", "support@example.com"),
resource.TestCheckResourceAttr(resourceName, "support_url", "http://example.com"),
Expand Down Expand Up @@ -320,31 +322,27 @@ resource "aws_s3_bucket_object" "test" {
bucket = aws_s3_bucket.test.id
key = "%[1]s.json"
content = <<EOF
{
"Resources" : {
"MyVPC": {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"CidrBlock" : "10.0.0.0/16",
"Tags" : [
{"Key": "Name", "Value": "Primary_CF_VPC"}
]
content = jsonencode({
AWSTemplateFormatVersion = "2010-09-09"
Resources = {
MyVPC = {
Type = "AWS::EC2::VPC"
Properties = {
CidrBlock = "10.1.0.0/16"
}
}
}
},
"Outputs" : {
"DefaultSgId" : {
"Description": "The ID of default security group",
"Value" : { "Fn::GetAtt" : [ "MyVPC", "DefaultSecurityGroup" ]}
},
"VpcID" : {
"Description": "The VPC ID",
"Value" : { "Ref" : "MyVPC" }
Outputs = {
VpcID = {
Description = "VPC ID"
Value = {
Ref = "MyVPC"
}
}
}
}
}
EOF
})
}
`, rName)
}
Expand All @@ -367,7 +365,7 @@ resource "aws_servicecatalog_product" "test" {
description = "artefaktbeskrivning"
disable_template_validation = true
name = %[1]q
template_url = "https://s3.${data.aws_partition.current.dns_suffix}/${aws_s3_bucket.test.id}/${aws_s3_bucket_object.test.key}"
template_url = "https://${aws_s3_bucket.test.bucket_regional_domain_name}/${aws_s3_bucket_object.test.key}"
type = "CLOUD_FORMATION_TEMPLATE"
}
Expand Down Expand Up @@ -396,7 +394,7 @@ resource "aws_servicecatalog_product" "test" {
description = "artefaktbeskrivning"
disable_template_validation = true
name = %[1]q
template_url = "https://s3.${data.aws_partition.current.dns_suffix}/${aws_s3_bucket.test.id}/${aws_s3_bucket_object.test.key}"
template_url = "https://${aws_s3_bucket.test.bucket_regional_domain_name}/${aws_s3_bucket_object.test.key}"
type = "CLOUD_FORMATION_TEMPLATE"
}
Expand All @@ -413,31 +411,27 @@ func testAccAWSServiceCatalogProductConfig_physicalID(rName string) string {
resource "aws_cloudformation_stack" "test" {
name = %[1]q
template_body = <<STACK
{
"Resources" : {
"MyVPC": {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"CidrBlock" : "10.0.0.0/16",
"Tags" : [
{"Key": "Name", "Value": "Primary_CF_VPC"}
]
template_body = jsonencode({
AWSTemplateFormatVersion = "2010-09-09"
Resources = {
MyVPC = {
Type = "AWS::EC2::VPC"
Properties = {
CidrBlock = "10.1.0.0/16"
}
}
}
},
"Outputs" : {
"DefaultSgId" : {
"Description": "The ID of default security group",
"Value" : { "Fn::GetAtt" : [ "MyVPC", "DefaultSecurityGroup" ]}
},
"VpcID" : {
"Description": "The VPC ID",
"Value" : { "Ref" : "MyVPC" }
Outputs = {
VpcID = {
Description = "VPC ID"
Value = {
Ref = "MyVPC"
}
}
}
}
}
STACK
})
}
resource "aws_servicecatalog_product" "test" {
Expand Down
Loading

0 comments on commit 6c604df

Please sign in to comment.