diff --git a/internal/services/apimanagement/api_management_product_tag_resource.go b/internal/services/apimanagement/api_management_product_tag_resource.go new file mode 100644 index 000000000000..5533c1e1922a --- /dev/null +++ b/internal/services/apimanagement/api_management_product_tag_resource.go @@ -0,0 +1,130 @@ +package apimanagement + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/schemaz" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceApiManagementProductTag() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceApiManagementProductTagCreate, + Read: resourceApiManagementProductTagRead, + Delete: resourceApiManagementProductTagDelete, + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.ProductTagID(id) + return err + }), + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "api_management_product_id": schemaz.SchemaApiManagementChildName(), + + "api_management_name": schemaz.SchemaApiManagementName(), + + "resource_group_name": azure.SchemaResourceGroupName(), + + "name": schemaz.SchemaApiManagementChildName(), + }, + } +} + +func resourceApiManagementProductTagCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.TagClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id := parse.NewProductTagID(subscriptionId, d.Get("resource_group_name").(string), d.Get("api_management_name").(string), d.Get("api_management_product_id").(string), d.Get("name").(string)) + + if d.IsNewResource() { + existing, err := client.GetByProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of existing %s: %s", id, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_api_management_product_tag", id.ID()) + } + } + + resp, err := client.AssignToProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + return fmt.Errorf(" creating product tag (id : %s): %+v", id, err) + } + d.SetId(*resp.ID) + + return resourceApiManagementProductTagRead(d, meta) +} + +func resourceApiManagementProductTagRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.TagClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ProductTagID(d.Id()) + if err != nil { + return err + } + + resp, err := client.GetByProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("%s was not found - removing from state!", *id) + d.SetId("") + return nil + } + + return fmt.Errorf("making Read request on %s: %+v", *id, err) + } + + productTagId, err := parse.ProductTagID(*resp.ID) + if err != nil { + return err + } + + d.Set("api_management_product_id", productTagId.ProductName) + d.Set("api_management_name", productTagId.ServiceName) + d.Set("resource_group_name", productTagId.ResourceGroup) + d.Set("name", productTagId.TagName) + + return nil +} + +func resourceApiManagementProductTagDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.TagClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ProductTagID(d.Id()) + if err != nil { + return err + } + + log.Printf("[DEBUG] Deleting %s", *id) + resp, err := client.DetachFromProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + if !utils.ResponseWasNotFound(resp) { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + } + + return nil +} diff --git a/internal/services/apimanagement/api_management_product_tag_resource_test.go b/internal/services/apimanagement/api_management_product_tag_resource_test.go new file mode 100644 index 000000000000..080b8c08de4e --- /dev/null +++ b/internal/services/apimanagement/api_management_product_tag_resource_test.go @@ -0,0 +1,121 @@ +package apimanagement_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ApiManagementProductTagResource struct{} + +func TestAccApiManagementProductTag_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_product_tag", "test") + r := ApiManagementProductTagResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("api_management_product_id").Exists(), + check.That(data.ResourceName).Key("api_management_name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("name").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccApiManagementProductTag_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_product_tag", "test") + r := ApiManagementProductTagResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func (ApiManagementProductTagResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.ProductTagID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.ApiManagement.TagClient.GetByProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + return nil, fmt.Errorf("reading %s: %+v", *id, err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (ApiManagementProductTagResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_api_management" "test" { + name = "acctestAM-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + publisher_name = "pub1" + publisher_email = "pub1@email.com" + + sku_name = "Consumption_0" +} + +resource "azurerm_api_management_product" "test" { + product_id = "test-product" + api_management_name = azurerm_api_management.test.name + resource_group_name = azurerm_resource_group.test.name + display_name = "Test Product" + subscription_required = false + published = false +} + +resource "azurerm_api_management_tag" "test" { + api_management_id = azurerm_api_management.test.id + name = "acctestTag-%d" +} + +resource "azurerm_api_management_product_tag" "test" { + api_management_product_id = azurerm_api_management_product.test.product_id + api_management_name = azurerm_api_management.test.name + resource_group_name = azurerm_resource_group.test.name + name = azurerm_api_management_tag.test.name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r ApiManagementProductTagResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_product_tag" "import" { + api_management_product_id = azurerm_api_management_product_tag.test.api_management_product_id + api_management_name = azurerm_api_management_product_tag.test.api_management_name + resource_group_name = azurerm_api_management_product_tag.test.resource_group_name + name = azurerm_api_management_product_tag.test.name +} +`, r.basic(data)) +} diff --git a/internal/services/apimanagement/parse/product_tag.go b/internal/services/apimanagement/parse/product_tag.go new file mode 100644 index 000000000000..799a0a3cd5ea --- /dev/null +++ b/internal/services/apimanagement/parse/product_tag.go @@ -0,0 +1,81 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type ProductTagId struct { + SubscriptionId string + ResourceGroup string + ServiceName string + ProductName string + TagName string +} + +func NewProductTagID(subscriptionId, resourceGroup, serviceName, productName, tagName string) ProductTagId { + return ProductTagId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ServiceName: serviceName, + ProductName: productName, + TagName: tagName, + } +} + +func (id ProductTagId) String() string { + segments := []string{ + fmt.Sprintf("Tag Name %q", id.TagName), + fmt.Sprintf("Product Name %q", id.ProductName), + fmt.Sprintf("Service Name %q", id.ServiceName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Product Tag", segmentsStr) +} + +func (id ProductTagId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ApiManagement/service/%s/products/%s/tags/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) +} + +// ProductTagID parses a ProductTag ID into an ProductTagId struct +func ProductTagID(input string) (*ProductTagId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ProductTagId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ServiceName, err = id.PopSegment("service"); err != nil { + return nil, err + } + if resourceId.ProductName, err = id.PopSegment("products"); err != nil { + return nil, err + } + if resourceId.TagName, err = id.PopSegment("tags"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/apimanagement/parse/product_tag_test.go b/internal/services/apimanagement/parse/product_tag_test.go new file mode 100644 index 000000000000..90a6dc472ca8 --- /dev/null +++ b/internal/services/apimanagement/parse/product_tag_test.go @@ -0,0 +1,144 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = ProductTagId{} + +func TestProductTagIDFormatter(t *testing.T) { + actual := NewProductTagID("12345678-1234-9876-4563-123456789012", "resGroup1", "service1", "product1", "tagId1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/tagId1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestProductTagID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ProductTagId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/", + Error: true, + }, + + { + // missing value for ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/", + Error: true, + }, + + { + // missing ProductName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/", + Error: true, + }, + + { + // missing value for ProductName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/", + Error: true, + }, + + { + // missing TagName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/", + Error: true, + }, + + { + // missing value for TagName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/tagId1", + Expected: &ProductTagId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ServiceName: "service1", + ProductName: "product1", + TagName: "tagId1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APIMANAGEMENT/SERVICE/SERVICE1/PRODUCTS/PRODUCT1/TAGS/TAGID1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ProductTagID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ServiceName != v.Expected.ServiceName { + t.Fatalf("Expected %q but got %q for ServiceName", v.Expected.ServiceName, actual.ServiceName) + } + if actual.ProductName != v.Expected.ProductName { + t.Fatalf("Expected %q but got %q for ProductName", v.Expected.ProductName, actual.ProductName) + } + if actual.TagName != v.Expected.TagName { + t.Fatalf("Expected %q but got %q for TagName", v.Expected.TagName, actual.TagName) + } + } +} diff --git a/internal/services/apimanagement/registration.go b/internal/services/apimanagement/registration.go index c743a0563791..8e3672c4a859 100644 --- a/internal/services/apimanagement/registration.go +++ b/internal/services/apimanagement/registration.go @@ -73,6 +73,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_api_management_openid_connect_provider": resourceApiManagementOpenIDConnectProvider(), "azurerm_api_management_policy": resourceApiManagementPolicy(), "azurerm_api_management_product": resourceApiManagementProduct(), + "azurerm_api_management_product_tag": resourceApiManagementProductTag(), "azurerm_api_management_product_api": resourceApiManagementProductApi(), "azurerm_api_management_product_group": resourceApiManagementProductGroup(), "azurerm_api_management_product_policy": resourceApiManagementProductPolicy(), diff --git a/internal/services/apimanagement/resourceids.go b/internal/services/apimanagement/resourceids.go index 23a8c7fe2898..457dc3c6cb84 100644 --- a/internal/services/apimanagement/resourceids.go +++ b/internal/services/apimanagement/resourceids.go @@ -30,6 +30,7 @@ package apimanagement //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProductApi -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/apis/api1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProductGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/groups/group1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProductPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/policies/policy1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProductTag -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/tagId1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Property -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/namedValues/namedvalue1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Subscription -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/subscriptions/subscription1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=User -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/users/user1 diff --git a/internal/services/apimanagement/validate/product_tag_id.go b/internal/services/apimanagement/validate/product_tag_id.go new file mode 100644 index 000000000000..9827d25af5b5 --- /dev/null +++ b/internal/services/apimanagement/validate/product_tag_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" +) + +func ProductTagID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ProductTagID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/apimanagement/validate/product_tag_id_test.go b/internal/services/apimanagement/validate/product_tag_id_test.go new file mode 100644 index 000000000000..75d10408ab8f --- /dev/null +++ b/internal/services/apimanagement/validate/product_tag_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestProductTagID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/", + Valid: false, + }, + + { + // missing value for ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/", + Valid: false, + }, + + { + // missing ProductName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/", + Valid: false, + }, + + { + // missing value for ProductName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/", + Valid: false, + }, + + { + // missing TagName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/", + Valid: false, + }, + + { + // missing value for TagName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/tagId1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APIMANAGEMENT/SERVICE/SERVICE1/PRODUCTS/PRODUCT1/TAGS/TAGID1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ProductTagID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/website/docs/r/api_management_product_tag.html.markdown b/website/docs/r/api_management_product_tag.html.markdown new file mode 100644 index 000000000000..ecd31728a896 --- /dev/null +++ b/website/docs/r/api_management_product_tag.html.markdown @@ -0,0 +1,89 @@ +--- +subcategory: "API Management" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_api_management_product_tag" +description: |- + Manages an API Management Product tag +--- + +# azurerm_api_management_product_tag + +Manages an API Management Product tag + + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_api_management" "example" { + name = "example-apim" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + publisher_name = "My Company" + publisher_email = "company@terraform.io" + + sku_name = "Developer_1" +} + +resource "azurerm_api_management_product" "example" { + product_id = "test-product" + api_management_name = azurerm_api_management.example.name + resource_group_name = azurerm_resource_group.example.name + display_name = "Test Product" + subscription_required = true + approval_required = true + published = true +} + +resource "azurerm_api_management_tag" "example" { + api_management_id = data.azurerm_api_management.example.id + name = "example-tag" +} + +resource "azurerm_api_management_product_tag" "example" { + api_management_product_id = azurerm_api_management_product.example.product_id + api_management_name = data.azurerm_api_management.example.name + resource_group_name = data.azurerm_resource_group.example.name + name = azurerm_api_management_tag.example1.name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `api_management_name` - (Required) The name of the API Management Service. Changing this forces a new resource to be created. + +* `api_management_product_id` - (Required) The name of the API Management product. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the Resource Group in which the API Management Service should be exist. Changing this forces a new resource to be created. + +* `name` - (Required) The name which should be used for this API Management Tag. Changing this forces a new API Management Tag to be created. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the API Management Product. + +## Timeouts + +The `timeouts` block allows you to +specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the API Management Product. +* `update` - (Defaults to 30 minutes) Used when updating the API Management Product. +* `read` - (Defaults to 5 minutes) Used when retrieving the API Management Product. +* `delete` - (Defaults to 30 minutes) Used when deleting the API Management Product. + +## Import + +API Management Products can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_api_management_product_tag.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.ApiManagement/service/instance1/products/myproduct/tags/mytag +```