From db6706763098d9415fbc0f086b46983d9e8857e8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:03:46 -0400 Subject: [PATCH 01/11] i/r/servicecat_tag_option_budget_assoc: Add finder --- .../service/servicecatalog/finder/finder.go | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/aws/internal/service/servicecatalog/finder/finder.go b/aws/internal/service/servicecatalog/finder/finder.go index 252ddc8a86d..497218da55b 100644 --- a/aws/internal/service/servicecatalog/finder/finder.go +++ b/aws/internal/service/servicecatalog/finder/finder.go @@ -69,3 +69,32 @@ func ProductPortfolioAssociation(conn *servicecatalog.ServiceCatalog, acceptLang return result, err } + +func BudgetResourceAssociation(conn *servicecatalog.ServiceCatalog, budgetName, resourceID string) (*servicecatalog.BudgetDetail, error) { + input := &servicecatalog.ListBudgetsForResourceInput{ + ResourceId: aws.String(resourceID), + } + + var result *servicecatalog.BudgetDetail + + err := conn.ListBudgetsForResourcePages(input, func(page *servicecatalog.ListBudgetsForResourceOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, budget := range page.Budgets { + if budget == nil { + continue + } + + if aws.StringValue(budget.BudgetName) == budgetName { + result = budget + return false + } + } + + return !lastPage + }) + + return result, err +} From dbc84f2470d7030b11c4302bd45cfbe28890d12b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:04:12 -0400 Subject: [PATCH 02/11] i/r/servicecat_tag_option_budget_assoc: Add id funcs --- aws/internal/service/servicecatalog/id.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/aws/internal/service/servicecatalog/id.go b/aws/internal/service/servicecatalog/id.go index 0c545813232..1aa89da2789 100644 --- a/aws/internal/service/servicecatalog/id.go +++ b/aws/internal/service/servicecatalog/id.go @@ -32,3 +32,17 @@ func ProductPortfolioAssociationParseID(id string) (string, string, string, erro func ProductPortfolioAssociationCreateID(acceptLanguage, portfolioID, productID string) string { return strings.Join([]string{acceptLanguage, portfolioID, productID}, ":") } + +func BudgetResourceAssociationParseID(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), budgetName:resourceID", id) + } + + return parts[0], parts[1], nil +} + +func BudgetResourceAssociationID(budgetName, resourceID string) string { + return strings.Join([]string{budgetName, resourceID}, ":") +} From 57e169a6f18b0cf3496c36e2c985f18c5c811a5b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:04:42 -0400 Subject: [PATCH 03/11] i/r/servicecat_tag_option_budget_assoc: Add waiter/status funcs --- .../service/servicecatalog/waiter/status.go | 24 ++++++++++++++ .../service/servicecatalog/waiter/waiter.go | 33 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index fa895722c72..ad804e572e6 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -226,3 +226,27 @@ func ServiceActionStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, id return output.ServiceActionDetail, servicecatalog.StatusAvailable, nil } } + +func BudgetResourceAssociationStatus(conn *servicecatalog.ServiceCatalog, budgetName, resourceID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.BudgetResourceAssociation(conn, budgetName, resourceID) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil, StatusNotFound, &resource.NotFoundError{ + Message: fmt.Sprintf("tag option resource association not found (%s): %s", tfservicecatalog.BudgetResourceAssociationID(budgetName, resourceID), err), + } + } + + if err != nil { + return nil, servicecatalog.StatusFailed, fmt.Errorf("error describing tag option resource association: %w", err) + } + + if output == nil { + return nil, StatusNotFound, &resource.NotFoundError{ + Message: fmt.Sprintf("finding tag option resource association (%s): empty response", tfservicecatalog.BudgetResourceAssociationID(budgetName, resourceID)), + } + } + + return output, servicecatalog.StatusAvailable, err + } +} diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index 4d58948483a..530a0629f7c 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -29,6 +29,9 @@ const ( ServiceActionReadyTimeout = 3 * time.Minute ServiceActionDeleteTimeout = 3 * time.Minute + BudgetResourceAssociationReadyTimeout = 3 * time.Minute + BudgetResourceAssociationDeleteTimeout = 3 * time.Minute + StatusNotFound = "NOT_FOUND" StatusUnavailable = "UNAVAILABLE" @@ -300,3 +303,33 @@ func ServiceActionDeleted(conn *servicecatalog.ServiceCatalog, acceptLanguage, i return err } + +func BudgetResourceAssociationReady(conn *servicecatalog.ServiceCatalog, budgetName, resourceID string) (*servicecatalog.BudgetDetail, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusNotFound, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: BudgetResourceAssociationStatus(conn, budgetName, resourceID), + Timeout: BudgetResourceAssociationReadyTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*servicecatalog.BudgetDetail); ok { + return output, err + } + + return nil, err +} + +func BudgetResourceAssociationDeleted(conn *servicecatalog.ServiceCatalog, budgetName, resourceID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{servicecatalog.StatusAvailable}, + Target: []string{StatusNotFound, StatusUnavailable}, + Refresh: BudgetResourceAssociationStatus(conn, budgetName, resourceID), + Timeout: BudgetResourceAssociationDeleteTimeout, + } + + _, err := stateConf.WaitForState() + + return err +} From ca214f1042c742e916103ee1e249e766392f788d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:05:28 -0400 Subject: [PATCH 04/11] provider: Add new resource --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index e19ff3f6484..8bccd0f5150 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1021,6 +1021,7 @@ func Provider() *schema.Provider { "aws_securityhub_organization_admin_account": resourceAwsSecurityHubOrganizationAdminAccount(), "aws_securityhub_product_subscription": resourceAwsSecurityHubProductSubscription(), "aws_securityhub_standards_subscription": resourceAwsSecurityHubStandardsSubscription(), + "aws_servicecatalog_budget_resource_association": resourceAwsServiceCatalogBudgetResourceAssociation(), "aws_servicecatalog_constraint": resourceAwsServiceCatalogConstraint(), "aws_servicecatalog_organizations_access": resourceAwsServiceCatalogOrganizationsAccess(), "aws_servicecatalog_portfolio": resourceAwsServiceCatalogPortfolio(), From a70c472ae2678acd0631eb9f6de49eba03c7c30d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:06:05 -0400 Subject: [PATCH 05/11] r/servicecatalog_budget_resource_association: New resource --- ...vicecatalog_budget_resource_association.go | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_budget_resource_association.go diff --git a/aws/resource_aws_servicecatalog_budget_resource_association.go b/aws/resource_aws_servicecatalog_budget_resource_association.go new file mode 100644 index 00000000000..1d7a4925a9f --- /dev/null +++ b/aws/resource_aws_servicecatalog_budget_resource_association.go @@ -0,0 +1,146 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func resourceAwsServiceCatalogBudgetResourceAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsServiceCatalogBudgetResourceAssociationCreate, + Read: resourceAwsServiceCatalogBudgetResourceAssociationRead, + Delete: resourceAwsServiceCatalogBudgetResourceAssociationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "budget_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "resource_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceAwsServiceCatalogBudgetResourceAssociationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + input := &servicecatalog.AssociateBudgetWithResourceInput{ + BudgetName: aws.String(d.Get("budget_name").(string)), + ResourceId: aws.String(d.Get("resource_id").(string)), + } + + var output *servicecatalog.AssociateBudgetWithResourceOutput + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + var err error + + output, err = conn.AssociateBudgetWithResource(input) + + if tfawserr.ErrMessageContains(err, servicecatalog.ErrCodeInvalidParametersException, "profile does not exist") { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + output, err = conn.AssociateBudgetWithResource(input) + } + + if err != nil { + return fmt.Errorf("error associating Service Catalog Budget with Resource: %w", err) + } + + if output == nil { + return fmt.Errorf("error creating Service Catalog Budget Resource Association: empty response") + } + + d.SetId(tfservicecatalog.BudgetResourceAssociationID(d.Get("budget_name").(string), d.Get("resource_id").(string))) + + return resourceAwsServiceCatalogBudgetResourceAssociationRead(d, meta) +} + +func resourceAwsServiceCatalogBudgetResourceAssociationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + budgetName, resourceID, err := tfservicecatalog.BudgetResourceAssociationParseID(d.Id()) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", d.Id(), err) + } + + output, err := waiter.BudgetResourceAssociationReady(conn, budgetName, resourceID) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Service Catalog Budget Resource Association (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error describing Service Catalog Budget Resource Association (%s): %w", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting Service Catalog Budget Resource Association (%s): empty response", d.Id()) + } + + d.Set("resource_id", resourceID) + d.Set("budget_name", output.BudgetName) + + return nil +} + +func resourceAwsServiceCatalogBudgetResourceAssociationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + budgetName, resourceID, err := tfservicecatalog.BudgetResourceAssociationParseID(d.Id()) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", d.Id(), err) + } + + input := &servicecatalog.DisassociateBudgetFromResourceInput{ + ResourceId: aws.String(resourceID), + BudgetName: aws.String(budgetName), + } + + _, err = conn.DisassociateBudgetFromResource(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return fmt.Errorf("error disassociating Service Catalog Budget from Resource (%s): %w", d.Id(), err) + } + + err = waiter.BudgetResourceAssociationDeleted(conn, budgetName, resourceID) + + if err != nil && !tfresource.NotFound(err) { + return fmt.Errorf("error waiting for Service Catalog Budget Resource Disassociation (%s): %w", d.Id(), err) + } + + return nil +} From c8d14eb18a7e0ba2e68b82d5e2c4f462a2fba844 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:06:40 -0400 Subject: [PATCH 06/11] tests/r/servicecatalog_budget_resource_association: New resource --- ...atalog_budget_resource_association_test.go | 268 ++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_budget_resource_association_test.go diff --git a/aws/resource_aws_servicecatalog_budget_resource_association_test.go b/aws/resource_aws_servicecatalog_budget_resource_association_test.go new file mode 100644 index 00000000000..1faf44cbfde --- /dev/null +++ b/aws/resource_aws_servicecatalog_budget_resource_association_test.go @@ -0,0 +1,268 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/servicecatalog" + multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +// add sweeper to delete known test servicecat budget resource associations +func init() { + resource.AddTestSweepers("aws_servicecatalog_budget_resource_association", &resource.Sweeper{ + Name: "aws_servicecatalog_budget_resource_association", + Dependencies: []string{}, + F: testSweepServiceCatalogBudgetResourceAssociations, + }) +} + +func testSweepServiceCatalogBudgetResourceAssociations(region string) error { + client, err := sharedClientForRegion(region) + + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + + conn := client.(*AWSClient).scconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + + input := &servicecatalog.ListPortfoliosInput{} + + err = conn.ListPortfoliosPages(input, func(page *servicecatalog.ListPortfoliosOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, port := range page.PortfolioDetails { + if port == nil { + continue + } + + resInput := &servicecatalog.ListBudgetsForResourceInput{ + ResourceId: port.Id, + } + + err = conn.ListBudgetsForResourcePages(resInput, func(page *servicecatalog.ListBudgetsForResourceOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, budget := range page.Budgets { + if budget == nil { + continue + } + + r := resourceAwsServiceCatalogBudgetResourceAssociation() + d := r.Data(nil) + d.SetId(tfservicecatalog.BudgetResourceAssociationID(aws.StringValue(budget.BudgetName), aws.StringValue(port.Id))) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + return !lastPage + }) + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Budget Resource (Portfolio) Associations for %s: %w", region, err)) + } + + prodInput := &servicecatalog.SearchProductsAsAdminInput{} + + err = conn.SearchProductsAsAdminPages(prodInput, func(page *servicecatalog.SearchProductsAsAdminOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, pvd := range page.ProductViewDetails { + if pvd == nil || pvd.ProductViewSummary == nil { + continue + } + + resInput := &servicecatalog.ListBudgetsForResourceInput{ + ResourceId: pvd.ProductViewSummary.ProductId, + } + + err = conn.ListBudgetsForResourcePages(resInput, func(page *servicecatalog.ListBudgetsForResourceOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, budget := range page.Budgets { + if budget == nil { + continue + } + + r := resourceAwsServiceCatalogBudgetResourceAssociation() + d := r.Data(nil) + d.SetId(tfservicecatalog.BudgetResourceAssociationID(aws.StringValue(budget.BudgetName), aws.StringValue(pvd.ProductViewSummary.ProductId))) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + return !lastPage + }) + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Budget Resource (Product) Associations for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Service Catalog Budget Resource Associations for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Service Catalog Budget Resource Associations sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + +func TestAccAWSServiceCatalogBudgetResourceAssociation_basic(t *testing.T) { + resourceName := "aws_servicecatalog_budget_resource_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogBudgetResourceAssociationConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogBudgetResourceAssociationExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", "aws_servicecatalog_portfolio.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "budget_name", "aws_budgets_budget.test", "name"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSServiceCatalogBudgetResourceAssociation_disappears(t *testing.T) { + resourceName := "aws_servicecatalog_budget_resource_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogBudgetResourceAssociationConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogBudgetResourceAssociationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsServiceCatalogBudgetResourceAssociation(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).scconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_servicecatalog_budget_resource_association" { + continue + } + + budgetName, resourceID, err := tfservicecatalog.BudgetResourceAssociationParseID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", rs.Primary.ID, err) + } + + err = waiter.BudgetResourceAssociationDeleted(conn, budgetName, resourceID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return fmt.Errorf("waiting for Service Catalog Budget Resource Association to be destroyed (%s): %w", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckAwsServiceCatalogBudgetResourceAssociationExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + + if !ok { + return fmt.Errorf("resource not found: %s", resourceName) + } + + budgetName, resourceID, err := tfservicecatalog.BudgetResourceAssociationParseID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", rs.Primary.ID, err) + } + + conn := testAccProvider.Meta().(*AWSClient).scconn + + _, err = waiter.BudgetResourceAssociationReady(conn, budgetName, resourceID) + + if err != nil { + return fmt.Errorf("waiting for Service Catalog Budget Resource Association existence (%s): %w", rs.Primary.ID, err) + } + + return nil + } +} + +func testAccAWSServiceCatalogBudgetResourceAssociationConfig_base(rName, budgetType, limitAmount, limitUnit, timePeriodStart, timeUnit string) string { + return fmt.Sprintf(` +resource "aws_servicecatalog_portfolio" "test" { + name = %[1]q + description = %[1]q + provider_name = %[1]q +} + +resource "aws_budgets_budget" "test" { + name = %[1]q + budget_type = %[2]q + limit_amount = %[3]q + limit_unit = %[4]q + time_period_start = %[5]q + time_unit = %[6]q +} +`, rName, budgetType, limitAmount, limitUnit, timePeriodStart, timeUnit) +} + +func testAccAWSServiceCatalogBudgetResourceAssociationConfig_basic(rName string) string { + return composeConfig(testAccAWSServiceCatalogBudgetResourceAssociationConfig_base(rName, "COST", "100.0", "USD", "2017-01-01_12:00", "MONTHLY"), fmt.Sprintf(` +resource "aws_servicecatalog_budget_resource_association" "test" { + resource_id = aws_servicecatalog_portfolio.test.id + budget_name = %[1]q +} +`, rName)) +} From b90d414f636564cd4f62df22f5196b162457bf6b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:07:08 -0400 Subject: [PATCH 07/11] docs/r/servicecatalog_budget_resource_association: New resource --- ..._budget_resource_association.html.markdown | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 website/docs/r/servicecatalog_budget_resource_association.html.markdown diff --git a/website/docs/r/servicecatalog_budget_resource_association.html.markdown b/website/docs/r/servicecatalog_budget_resource_association.html.markdown new file mode 100644 index 00000000000..7673ba5751d --- /dev/null +++ b/website/docs/r/servicecatalog_budget_resource_association.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_budget_resource_association" +description: |- + Manages a Service Catalog Budget Resource Association +--- + +# Resource: aws_servicecatalog_budget_resource_association + +Manages a Service Catalog Budget Resource Association. + +-> A "resource" is either a Service Catalog portfolio or product. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_servicecatalog_budget_resource_association" "example" { + budget_name = "budget-pjtvyakdlyo3m" + resource_id = "prod-dnigbtea24ste" +} +``` + +## Argument Reference + +The following arguments are required: + +* `budget_name` - (Required) Budget name. +* `resource_id` - (Required) Resource identifier. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Identifier of the association. + +## Import + +`aws_servicecatalog_budget_resource_association` can be imported using the budget name and resource ID, e.g. + +``` +$ terraform import aws_servicecatalog_budget_resource_association.example budget-pjtvyakdlyo3m:prod-dnigbtea24ste +``` From 70ef01faaaf4172692b7ea3e1788a607a44938f0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 09:14:59 -0400 Subject: [PATCH 08/11] tests/r/servicecatalog_budget_resource_association: Precheck --- ...aws_servicecatalog_budget_resource_association_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_servicecatalog_budget_resource_association_test.go b/aws/resource_aws_servicecatalog_budget_resource_association_test.go index 1faf44cbfde..160fb3c9886 100644 --- a/aws/resource_aws_servicecatalog_budget_resource_association_test.go +++ b/aws/resource_aws_servicecatalog_budget_resource_association_test.go @@ -141,8 +141,8 @@ func TestAccAWSServiceCatalogBudgetResourceAssociation_basic(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("budgets", t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID, "budgets"), Providers: testAccProviders, CheckDestroy: testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy, Steps: []resource.TestStep{ @@ -168,8 +168,8 @@ func TestAccAWSServiceCatalogBudgetResourceAssociation_disappears(t *testing.T) rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("budgets", t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID, "budgets"), Providers: testAccProviders, CheckDestroy: testAccCheckAwsServiceCatalogBudgetResourceAssociationDestroy, Steps: []resource.TestStep{ From e32f493e3ba205c41dff686b4157fffd6a44cc74 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 12:26:41 -0400 Subject: [PATCH 09/11] r/servicecatalog_budget_resource_association: Add changelog --- .changelog/19452.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19452.txt diff --git a/.changelog/19452.txt b/.changelog/19452.txt new file mode 100644 index 00000000000..970016a5d0e --- /dev/null +++ b/.changelog/19452.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_servicecatalog_budget_resource_association +``` \ No newline at end of file From 0680c37f382659966e010083e2e4dc3b39b7e244 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 12:27:03 -0400 Subject: [PATCH 10/11] r/eks_addon: Add changelog --- .changelog/19454.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19454.txt diff --git a/.changelog/19454.txt b/.changelog/19454.txt new file mode 100644 index 00000000000..6ff5b428703 --- /dev/null +++ b/.changelog/19454.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_eks_addon: Use `service_account_role_arn`, if set, on updates +``` \ No newline at end of file From acb3ebfcc67eb0e4ef457e09dff5e0a6d0990497 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 12:28:25 -0400 Subject: [PATCH 11/11] docs/r/servicecatalog_budg_res_assoc: Update --- .../r/servicecatalog_budget_resource_association.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/servicecatalog_budget_resource_association.html.markdown b/website/docs/r/servicecatalog_budget_resource_association.html.markdown index 7673ba5751d..f1071ef69ef 100644 --- a/website/docs/r/servicecatalog_budget_resource_association.html.markdown +++ b/website/docs/r/servicecatalog_budget_resource_association.html.markdown @@ -10,7 +10,7 @@ description: |- Manages a Service Catalog Budget Resource Association. --> A "resource" is either a Service Catalog portfolio or product. +-> **Tip:** A "resource" is either a Service Catalog portfolio or product. ## Example Usage