From 09d0075e0ff271d4c166c800a00c3e94e9cef0d9 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 26 Mar 2019 11:22:05 +0100 Subject: [PATCH] New Resource: `azurerm_api_management_api_operation` --- azurerm/config.go | 5 + azurerm/helpers/azure/api_management.go | 227 +++++++ azurerm/provider.go | 1 + ...source_arm_api_management_api_operation.go | 340 +++++++++++ ...e_arm_api_management_api_operation_test.go | 566 ++++++++++++++++++ website/azurerm.erb | 4 + ...api_management_api_operation.html.markdown | 190 ++++++ 7 files changed, 1333 insertions(+) create mode 100644 azurerm/resource_arm_api_management_api_operation.go create mode 100644 azurerm/resource_arm_api_management_api_operation_test.go create mode 100644 website/docs/r/api_management_api_operation.html.markdown diff --git a/azurerm/config.go b/azurerm/config.go index 9d924c2725e0..7290835938eb 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -128,6 +128,7 @@ type ArmClient struct { // API Management apiManagementApiClient apimanagement.APIClient + apiManagementApiOperationsClient apimanagement.APIOperationClient apiManagementGroupClient apimanagement.GroupClient apiManagementGroupUsersClient apimanagement.GroupUserClient apiManagementLoggerClient apimanagement.LoggerClient @@ -502,6 +503,10 @@ func (c *ArmClient) registerApiManagementServiceClients(endpoint, subscriptionId c.configureClient(&apisClient.Client, auth) c.apiManagementApiClient = apisClient + apiOperationsClient := apimanagement.NewAPIOperationClientWithBaseURI(endpoint, subscriptionId) + c.configureClient(&apiOperationsClient.Client, auth) + c.apiManagementApiOperationsClient = apiOperationsClient + groupsClient := apimanagement.NewGroupClientWithBaseURI(endpoint, subscriptionId) c.configureClient(&groupsClient.Client, auth) c.apiManagementGroupClient = groupsClient diff --git a/azurerm/helpers/azure/api_management.go b/azurerm/helpers/azure/api_management.go index e4465f5ba9b2..6f311dddede0 100644 --- a/azurerm/helpers/azure/api_management.go +++ b/azurerm/helpers/azure/api_management.go @@ -1,8 +1,13 @@ package azure import ( + "fmt" + "strings" + + "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2018-01-01/apimanagement" "github.com/hashicorp/terraform/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) func SchemaApiManagementName() *schema.Schema { @@ -70,3 +75,225 @@ func SchemaApiManagementUserDataSourceName() *schema.Schema { ValidateFunc: validate.ApiManagementUserName, } } + +func SchemaApiManagementOperationRepresentation() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "content_type": { + Type: schema.TypeString, + Required: true, + }, + + "form_parameter": SchemaApiManagementOperationParameterContract(), + + "sample": { + Type: schema.TypeString, + Optional: true, + }, + + "schema_id": { + Type: schema.TypeString, + Optional: true, + }, + + "type_name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + } +} + +func ExpandApiManagementOperationRepresentation(input []interface{}) (*[]apimanagement.RepresentationContract, error) { + if len(input) == 0 { + return &[]apimanagement.RepresentationContract{}, nil + } + + outputs := make([]apimanagement.RepresentationContract, 0) + + for _, v := range input { + vs := v.(map[string]interface{}) + + contentType := vs["content_type"].(string) + formParametersRaw := vs["form_parameter"].([]interface{}) + formParameters := ExpandApiManagementOperationParameterContract(formParametersRaw) + sample := vs["sample"].(string) + schemaId := vs["schema_id"].(string) + typeName := vs["type_name"].(string) + + output := apimanagement.RepresentationContract{ + ContentType: utils.String(contentType), + Sample: utils.String(sample), + } + + contentTypeIsFormData := strings.EqualFold(contentType, "multipart/form-data") || strings.EqualFold(contentType, "application/x-www-form-urlencoded") + + // Representation formParameters can only be specified for form data content types (multipart/form-data, application/x-www-form-urlencoded) + if contentTypeIsFormData { + output.FormParameters = formParameters + } else if len(*formParameters) > 0 { + return nil, fmt.Errorf("`form_parameter` cannot be specified for form data content types (multipart/form-data, application/x-www-form-urlencoded)") + } + + // Representation schemaId can only be specified for non form data content types (multipart/form-data, application/x-www-form-urlencoded). + // Representation typeName can only be specified for non form data content types (multipart/form-data, application/x-www-form-urlencoded). + if !contentTypeIsFormData { + output.SchemaID = utils.String(schemaId) + output.TypeName = utils.String(typeName) + } else if schemaId != "" { + return nil, fmt.Errorf("`schema_id` cannot be specified for non-form data content types (multipart/form-data, application/x-www-form-urlencoded)") + } else if typeName != "" { + return nil, fmt.Errorf("`type_name` cannot be specified for non-form data content types (multipart/form-data, application/x-www-form-urlencoded)") + } + + outputs = append(outputs, output) + } + + return &outputs, nil +} + +func FlattenApiManagementOperationRepresentation(input *[]apimanagement.RepresentationContract) []interface{} { + if input == nil { + return []interface{}{} + } + + outputs := make([]interface{}, 0) + + for _, v := range *input { + output := make(map[string]interface{}) + + if v.ContentType != nil { + output["content_type"] = *v.ContentType + } + + output["form_parameter"] = FlattenApiManagementOperationParameterContract(v.FormParameters) + + if v.Sample != nil { + output["sample"] = *v.Sample + } + + if v.SchemaID != nil { + output["schema_id"] = *v.SchemaID + } + + if v.TypeName != nil { + output["type_name"] = *v.TypeName + } + + outputs = append(outputs, output) + } + + return outputs +} + +func SchemaApiManagementOperationParameterContract() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "required": { + Type: schema.TypeBool, + Required: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + }, + "values": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + }, + }, + } +} + +func ExpandApiManagementOperationParameterContract(input []interface{}) *[]apimanagement.ParameterContract { + if len(input) == 0 { + return &[]apimanagement.ParameterContract{} + } + + outputs := make([]apimanagement.ParameterContract, 0) + + for _, v := range input { + vs := v.(map[string]interface{}) + + name := vs["name"].(string) + description := vs["description"].(string) + paramType := vs["type"].(string) + defaultValue := vs["default_value"].(string) + required := vs["required"].(bool) + valuesRaw := vs["values"].(*schema.Set).List() + + output := apimanagement.ParameterContract{ + Name: utils.String(name), + Description: utils.String(description), + Type: utils.String(paramType), + Required: utils.Bool(required), + DefaultValue: utils.String(defaultValue), + Values: utils.ExpandStringArray(valuesRaw), + } + outputs = append(outputs, output) + } + + return &outputs +} + +func FlattenApiManagementOperationParameterContract(input *[]apimanagement.ParameterContract) []interface{} { + if input == nil { + return []interface{}{} + } + + outputs := make([]interface{}, 0) + for _, v := range *input { + output := map[string]interface{}{} + + if v.Name != nil { + output["name"] = *v.Name + } + + if v.Description != nil { + output["description"] = *v.Description + } + + if v.Type != nil { + output["type"] = *v.Type + } + + if v.Required != nil { + output["required"] = *v.Required + } + + if v.DefaultValue != nil { + output["default_value"] = *v.DefaultValue + } + + output["values"] = schema.NewSet(schema.HashString, utils.FlattenStringArray(v.Values)) + + outputs = append(outputs, output) + } + + return outputs +} diff --git a/azurerm/provider.go b/azurerm/provider.go index 5ebae851ffe8..3fabae6b9f04 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -170,6 +170,7 @@ func Provider() terraform.ResourceProvider { ResourcesMap: map[string]*schema.Resource{ "azurerm_api_management": resourceArmApiManagementService(), "azurerm_api_management_api": resourceArmApiManagementApi(), + "azurerm_api_management_api_operation": resourceArmApiManagementApiOperation(), "azurerm_api_management_group": resourceArmApiManagementGroup(), "azurerm_api_management_group_user": resourceArmApiManagementGroupUser(), "azurerm_api_management_logger": resourceArmApiManagementLogger(), diff --git a/azurerm/resource_arm_api_management_api_operation.go b/azurerm/resource_arm_api_management_api_operation.go new file mode 100644 index 000000000000..3a39f3dea69d --- /dev/null +++ b/azurerm/resource_arm_api_management_api_operation.go @@ -0,0 +1,340 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2018-01-01/apimanagement" + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmApiManagementApiOperation() *schema.Resource { + return &schema.Resource{ + Create: resourceArmApiManagementApiOperationCreateUpdate, + Read: resourceArmApiManagementApiOperationRead, + Update: resourceArmApiManagementApiOperationCreateUpdate, + Delete: resourceArmApiManagementApiOperationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "operation_id": azure.SchemaApiManagementChildName(), + + "api_name": azure.SchemaApiManagementChildName(), + + "api_management_name": azure.SchemaApiManagementName(), + + "resource_group_name": resourceGroupNameSchema(), + + "display_name": { + Type: schema.TypeString, + Required: true, + }, + + "method": { + Type: schema.TypeString, + Required: true, + }, + + "url_template": { + Type: schema.TypeString, + Required: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + }, + + "request": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Optional: true, + }, + + "header": azure.SchemaApiManagementOperationParameterContract(), + + "query_parameter": azure.SchemaApiManagementOperationParameterContract(), + + "representation": azure.SchemaApiManagementOperationRepresentation(), + }, + }, + }, + + "response": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status_code": { + Type: schema.TypeInt, + Required: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + }, + + "header": azure.SchemaApiManagementOperationParameterContract(), + + "representation": azure.SchemaApiManagementOperationRepresentation(), + }, + }, + }, + + "template_parameter": azure.SchemaApiManagementOperationParameterContract(), + }, + } +} + +func resourceArmApiManagementApiOperationCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).apiManagementApiOperationsClient + ctx := meta.(*ArmClient).StopContext + + resourceGroup := d.Get("resource_group_name").(string) + serviceName := d.Get("api_management_name").(string) + apiId := d.Get("api_name").(string) + operationId := d.Get("operation_id").(string) + + description := d.Get("description").(string) + displayName := d.Get("display_name").(string) + method := d.Get("method").(string) + urlTemplate := d.Get("url_template").(string) + + requestContractRaw := d.Get("request").([]interface{}) + requestContract, err := expandApiManagementOperationRequestContract(requestContractRaw) + if err != nil { + return err + } + + responseContractsRaw := d.Get("response").([]interface{}) + responseContracts, err := expandApiManagementOperationResponseContract(responseContractsRaw) + if err != nil { + return err + } + + templateParametersRaw := d.Get("template_parameter").([]interface{}) + templateParameters := azure.ExpandApiManagementOperationParameterContract(templateParametersRaw) + + parameters := apimanagement.OperationContract{ + OperationContractProperties: &apimanagement.OperationContractProperties{ + Description: utils.String(description), + DisplayName: utils.String(displayName), + Method: utils.String(method), + Request: requestContract, + Responses: responseContracts, + TemplateParameters: templateParameters, + URLTemplate: utils.String(urlTemplate), + }, + } + + if _, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, apiId, operationId, parameters, ""); err != nil { + return fmt.Errorf("Error creating/updating API Operation %q (API %q / API Management Service %q / Resource Group %q): %+v", operationId, apiId, serviceName, resourceGroup, err) + } + + resp, err := client.Get(ctx, resourceGroup, serviceName, apiId, operationId) + if err != nil { + return fmt.Errorf("Error retrieving API Operation %q (API %q / API Management Service %q / Resource Group %q): %+v", operationId, apiId, serviceName, resourceGroup, err) + } + + d.SetId(*resp.ID) + + return resourceArmApiManagementApiOperationRead(d, meta) +} + +func resourceArmApiManagementApiOperationRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).apiManagementApiOperationsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resourceGroup := id.ResourceGroup + serviceName := id.Path["service"] + apiId := id.Path["apis"] + operationId := id.Path["operations"] + + resp, err := client.Get(ctx, resourceGroup, serviceName, apiId, operationId) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] API Operation %q (API %q / API Management Service %q / Resource Group %q) was not found - removing from state!", operationId, apiId, serviceName, resourceGroup) + d.SetId("") + return nil + } + + return fmt.Errorf("Error retrieving API Operation %q (API %q / API Management Service %q / Resource Group %q): %+v", operationId, apiId, serviceName, resourceGroup, err) + } + + d.Set("operation_id", operationId) + d.Set("api_name", apiId) + d.Set("api_management_name", serviceName) + d.Set("resource_group_name", resourceGroup) + + if props := resp.OperationContractProperties; props != nil { + d.Set("description", props.Description) + d.Set("display_name", props.DisplayName) + d.Set("method", props.Method) + d.Set("url_template", props.URLTemplate) + + flattenedRequest := flattenApiManagementOperationRequestContract(props.Request) + if err := d.Set("request", flattenedRequest); err != nil { + return fmt.Errorf("Error flattening `request`: %+v", err) + } + + flattenedResponse := flattenApiManagementOperationResponseContract(props.Responses) + if err := d.Set("response", flattenedResponse); err != nil { + return fmt.Errorf("Error flattening `response`: %+v", err) + } + + flattenedTemplateParams := azure.FlattenApiManagementOperationParameterContract(props.TemplateParameters) + if err := d.Set("template_parameter", flattenedTemplateParams); err != nil { + return fmt.Errorf("Error flattening `template_parameter`: %+v", err) + } + } + + return nil +} + +func resourceArmApiManagementApiOperationDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).apiManagementApiOperationsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resourceGroup := id.ResourceGroup + serviceName := id.Path["service"] + apiId := id.Path["apis"] + operationId := id.Path["operations"] + + resp, err := client.Delete(ctx, resourceGroup, serviceName, apiId, operationId, "") + if err != nil { + if !utils.ResponseWasNotFound(resp) { + return fmt.Errorf("Error deleting API Operation %q (API %q / API Management Service %q / Resource Group %q): %+v", operationId, apiId, serviceName, resourceGroup, err) + } + } + + return nil +} + +func expandApiManagementOperationRequestContract(input []interface{}) (*apimanagement.RequestContract, error) { + if len(input) == 0 { + return nil, nil + } + + vs := input[0].(map[string]interface{}) + description := vs["description"].(string) + + headersRaw := vs["header"].([]interface{}) + headers := azure.ExpandApiManagementOperationParameterContract(headersRaw) + + queryParametersRaw := vs["query_parameter"].([]interface{}) + queryParameters := azure.ExpandApiManagementOperationParameterContract(queryParametersRaw) + + representationsRaw := vs["representation"].([]interface{}) + representations, err := azure.ExpandApiManagementOperationRepresentation(representationsRaw) + if err != nil { + return nil, err + } + + return &apimanagement.RequestContract{ + Description: utils.String(description), + Headers: headers, + QueryParameters: queryParameters, + Representations: representations, + }, nil +} + +func flattenApiManagementOperationRequestContract(input *apimanagement.RequestContract) []interface{} { + if input == nil { + return []interface{}{} + } + + output := make(map[string]interface{}) + + if input.Description != nil { + output["description"] = *input.Description + } + + output["header"] = azure.FlattenApiManagementOperationParameterContract(input.Headers) + output["query_parameter"] = azure.FlattenApiManagementOperationParameterContract(input.QueryParameters) + output["representation"] = azure.FlattenApiManagementOperationRepresentation(input.Representations) + + return []interface{}{output} +} + +func expandApiManagementOperationResponseContract(input []interface{}) (*[]apimanagement.ResponseContract, error) { + if len(input) == 0 { + return &[]apimanagement.ResponseContract{}, nil + } + + outputs := make([]apimanagement.ResponseContract, 0) + + for _, v := range input { + vs := v.(map[string]interface{}) + + description := vs["description"].(string) + statusCode := vs["status_code"].(int) + + headersRaw := vs["header"].([]interface{}) + headers := azure.ExpandApiManagementOperationParameterContract(headersRaw) + + representationsRaw := vs["representation"].([]interface{}) + representations, err := azure.ExpandApiManagementOperationRepresentation(representationsRaw) + if err != nil { + return nil, err + } + + output := apimanagement.ResponseContract{ + Description: utils.String(description), + Headers: headers, + Representations: representations, + StatusCode: utils.Int32(int32(statusCode)), + } + + outputs = append(outputs, output) + } + + return &outputs, nil +} + +func flattenApiManagementOperationResponseContract(input *[]apimanagement.ResponseContract) []interface{} { + if input == nil { + return []interface{}{} + } + + outputs := make([]interface{}, 0) + + for _, v := range *input { + output := make(map[string]interface{}) + + if v.Description != nil { + output["description"] = *v.Description + } + + if v.StatusCode != nil { + output["status_code"] = int(*v.StatusCode) + } + + output["header"] = azure.FlattenApiManagementOperationParameterContract(v.Headers) + output["representation"] = azure.FlattenApiManagementOperationRepresentation(v.Representations) + + outputs = append(outputs, output) + } + + return outputs +} diff --git a/azurerm/resource_arm_api_management_api_operation_test.go b/azurerm/resource_arm_api_management_api_operation_test.go new file mode 100644 index 000000000000..b43ff38f2b50 --- /dev/null +++ b/azurerm/resource_arm_api_management_api_operation_test.go @@ -0,0 +1,566 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMApiManagementApiOperation_basic(t *testing.T) { + resourceName := "azurerm_api_management_api_operation.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiOperationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApiOperation_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiOperationExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMApiManagementApiOperation_requiresImport(t *testing.T) { + if !requireResourcesToBeImported { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + resourceName := "azurerm_api_management_api_operation.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiOperationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApiOperation_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiOperationExists(resourceName), + ), + }, + { + Config: testAccAzureRMApiManagementApiOperation_requiresImport(ri, location), + ExpectError: testRequiresImportError("azurerm_api_management_api_operation"), + }, + }, + }) +} + +func TestAccAzureRMApiManagementApiOperation_customMethod(t *testing.T) { + resourceName := "azurerm_api_management_api_operation.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiOperationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApiOperation_customMethod(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiOperationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "method", "HAMMERTIME"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMApiManagementApiOperation_headers(t *testing.T) { + resourceName := "azurerm_api_management_api_operation.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiOperationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApiOperation_headers(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiOperationExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMApiManagementApiOperation_requestRepresentations(t *testing.T) { + resourceName := "azurerm_api_management_api_operation.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiOperationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApiOperation_requestRepresentation(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiOperationExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMApiManagementApiOperation_requestRepresentationUpdated(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiOperationExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMApiManagementApiOperation_representations(t *testing.T) { + // TODO: once `azurerm_api_management_schema` is supported add `request.0.representation.0.schema_id` + resourceName := "azurerm_api_management_api_operation.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiOperationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApiOperation_representation(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiOperationExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMApiManagementApiOperation_representationUpdated(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiOperationExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testCheckAzureRMApiManagementApiOperationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*ArmClient).apiManagementApiOperationsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_api_management_api_operation" { + continue + } + + operationId := rs.Primary.Attributes["operation_id"] + apiName := rs.Primary.Attributes["api_name"] + serviceName := rs.Primary.Attributes["api_management_name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := conn.Get(ctx, resourceGroup, serviceName, apiName, operationId) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + + return err + } + + return nil + } + + return nil +} + +func testCheckAzureRMApiManagementApiOperationExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + operationId := rs.Primary.Attributes["operation_id"] + apiName := rs.Primary.Attributes["api_name"] + serviceName := rs.Primary.Attributes["api_management_name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + conn := testAccProvider.Meta().(*ArmClient).apiManagementApiOperationsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := conn.Get(ctx, resourceGroup, serviceName, apiName, operationId) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: API Operation %q (API %q / API Management Service %q / Resource Group: %q) does not exist", operationId, apiName, serviceName, resourceGroup) + } + + return fmt.Errorf("Bad: Get on apiManagementApiOperationsClient: %+v", err) + } + + return nil + } +} + +func testAccAzureRMApiManagementApiOperation_basic(rInt int, location string) string { + template := testAccAzureRMApiManagementApiOperation_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api_operation" "test" { + operation_id = "acctest-operation" + api_name = "${azurerm_api_management_api.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + display_name = "DELETE Resource" + method = "DELETE" + url_template = "/resource" +} +`, template) +} + +func testAccAzureRMApiManagementApiOperation_customMethod(rInt int, location string) string { + template := testAccAzureRMApiManagementApiOperation_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api_operation" "test" { + operation_id = "acctest-operation" + api_name = "${azurerm_api_management_api.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + display_name = "HAMMERTIME Resource" + method = "HAMMERTIME" + url_template = "/resource" +} +`, template) +} + +func testAccAzureRMApiManagementApiOperation_requiresImport(rInt int, location string) string { + template := testAccAzureRMApiManagementApiOperation_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api_operation" "import" { + operation_id = "${azurerm_api_management_api_operation.test.operation_id}" + api_name = "${azurerm_api_management_api_operation.test.api_name}" + api_management_name = "${azurerm_api_management_api_operation.test.api_management_name}" + resource_group_name = "${azurerm_api_management_api_operation.test.resource_group_name}" + display_name = "${azurerm_api_management_api_operation.test.display_name}" + method = "${azurerm_api_management_api_operation.test.method}" + url_template = "${azurerm_api_management_api_operation.test.url_template}" +} +`, template) +} + +func testAccAzureRMApiManagementApiOperation_requestRepresentation(rInt int, location string) string { + template := testAccAzureRMApiManagementApiOperation_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api_operation" "test" { + operation_id = "acctest-operation" + api_name = "${azurerm_api_management_api.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + display_name = "Acceptance Test Operation" + method = "DELETE" + url_template = "/user1" + description = "This can only be done by the logged in user." + + request { + description = "Created user object" + + representation { + content_type = "application/json" + type_name = "User" + } + } +} + +`, template) +} + +func testAccAzureRMApiManagementApiOperation_requestRepresentationUpdated(rInt int, location string) string { + template := testAccAzureRMApiManagementApiOperation_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api_operation" "test" { + operation_id = "acctest-operation" + api_name = "${azurerm_api_management_api.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + display_name = "Acceptance Test Operation" + method = "DELETE" + url_template = "/user1" + description = "This can only be done by the logged in user." + + request { + description = "Created user object" + + representation { + content_type = "application/json" + type_name = "User" + } + } +} + +`, template) +} + +func testAccAzureRMApiManagementApiOperation_headers(rInt int, location string) string { + template := testAccAzureRMApiManagementApiOperation_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api_operation" "test" { + operation_id = "acctest-operation" + api_name = "${azurerm_api_management_api.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + display_name = "Acceptance Test Operation" + method = "DELETE" + url_template = "/user1" + description = "This can only be done by the logged in user." + + request { + description = "Created user object" + + header { + name = "X-Test-Operation" + required = true + type = "string" + } + + representation { + content_type = "application/json" + type_name = "User" + } + } + + response { + status_code = 200 + description = "successful operation" + + header { + name = "X-Test-Operation" + required = true + type = "string" + } + + representation { + content_type = "application/xml" + sample = < + + + + + + + +SAMPLE + } + } +} + +`, template) +} + +func testAccAzureRMApiManagementApiOperation_representation(rInt int, location string) string { + template := testAccAzureRMApiManagementApiOperation_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api_operation" "test" { + operation_id = "acctest-operation" + api_name = "${azurerm_api_management_api.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + display_name = "Acceptance Test Operation" + method = "DELETE" + url_template = "/user1" + description = "This can only be done by the logged in user." + + request { + description = "Created user object" + + representation { + content_type = "application/json" + type_name = "User" + } + } + + response { + status_code = 200 + description = "successful operation" + + representation { + content_type = "application/xml" + sample = < + + + + + + + +SAMPLE + } + } +} + +`, template) +} + +func testAccAzureRMApiManagementApiOperation_representationUpdated(rInt int, location string) string { + template := testAccAzureRMApiManagementApiOperation_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api_operation" "test" { + operation_id = "acctest-operation" + api_name = "${azurerm_api_management_api.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + display_name = "Acceptance Test Operation" + method = "DELETE" + url_template = "/user1" + description = "This can only be done by the logged in user." + + request { + description = "Created user object" + + representation { + content_type = "application/json" + type_name = "User" + } + } + + response { + status_code = 200 + description = "successful operation" + + representation { + content_type = "application/xml" + sample = < + + + + + + + +SAMPLE + } + + representation { + content_type = "application/json" + sample = <azurerm_api_management_api + > + azurerm_api_management_api_operation + + > azurerm_api_management_group diff --git a/website/docs/r/api_management_api_operation.html.markdown b/website/docs/r/api_management_api_operation.html.markdown new file mode 100644 index 000000000000..3ca27336c687 --- /dev/null +++ b/website/docs/r/api_management_api_operation.html.markdown @@ -0,0 +1,190 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_api_management_api_operation" +sidebar_current: "docs-azurerm-resource-api-management-api-operation" +description: |- + Manages an API Operation within an API Management Service. +--- + +# azurerm_api_management_api_operation + +Manages an API Operation within an API Management Service. + +## Example Usage + +```hcl +data "azurerm_api_management_api" "test" { + name = "search-api" + api_management_name = "search-api-management" + resource_group_name = "search-service" + revision = "2" +} + +resource "azurerm_api_management_api_operation" "example" { + operation_id = "user-delete" + api_name = "${data.azurerm_api_management_api.example.name}" + api_management_name = "${data.azurerm_api_management_api.example.api_management_name}" + resource_group_name = "${data.azurerm_api_management_api.example.resource_group_name}" + display_name = "Delete User Operation" + method = "DELETE" + url_template = "/users/{id}/delete" + description = "This can only be done by the logged in user." + + response { + status_code = 200 + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `operation_id` - (Required) A unique identifier for this API Operation. Changing this forces a new resource to be created. + +* `api_name` - (Required) The name of the API within the API Management Service where this API Operation should be created. Changing this forces a new resource to be created. + +* `api_management_name` - (Required) The Name of the API Management Service where the API exists. 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 exists. Changing this forces a new resource to be created. + +* `display_name` - (Required) The Display Name for this API Management Operation. + +* `method` - (Required) The HTTP Method used for this API Management Operation, like `GET`, `DELETE`, `PUT` or `POST` - but not limited to these values. + +* `url_template` - (Required) The relative URL Template identifying the target resource for this operation, which may include parameters. + +--- + +* `description` - (Optional) A description for this API Operation, which may include HTML formatting tags. + +* `request` - (Optional) A `request` block as defined below. + +* `response` - (Optional) One or more `response` blocks as defined below. + +* `template_parameter` - (Optional) One or more `template_parameter` blocks as defined below. + + +--- + +A `form_parameter` block supports the following: + +* `name` - (Required) The Name of this Form Parameter. + +* `required` - (Required) Is this Form Parameter Required? + +* `type` - (Required) The Type of this Form Parameter, such as a `string`. + +* `description` - (Optional) A description of this Form Parameter. + +* `default_value` - (Optional) The default value for this Form Parameter. + +* `values` - (Optional) One or more acceptable values for this Form Parameter. + +--- + +A `header` block supports the following: + +* `name` - (Required) The Name of this Header. + +* `required` - (Required) Is this Header Required? + +* `type` - (Required) The Type of this Header, such as a `string`. + +* `description` - (Optional) A description of this Header. + +* `default_value` - (Optional) The default value for this Header. + +* `values` - (Optional) One or more acceptable values for this Header. + +--- + +A `query_parameter` block supports the following: + +* `name` - (Required) The Name of this Query Parameter. + +* `required` - (Required) Is this Query Parameter Required? + +* `type` - (Required) The Type of this Query Parameter, such as a `string`. + +* `description` - (Optional) A description of this Query Parameter. + +* `default_value` - (Optional) The default value for this Query Parameter. + +* `values` - (Optional) One or more acceptable values for this Query Parameter. + +--- + +A `request` block supports the following: + +* `description` - (Required) A description of the HTTP Request, which may include HTML tags. + +* `header` - (Optional) One or more `header` blocks as defined above. + +* `query_parameter` - (Optional) One or more `query_parameter` blocks as defined above. + +* `representation` - (Optional) One or more `representation` blocks as defined below. + +--- + +A `representation` block supports the following: + +* `content_type` - (Required) The Content Type of this representation, such as `application/json`. + +* `form_parameter` - (Optional) One or more `form_parameter` block as defined above. + +-> **NOTE:** This is Required when `content_type` is set to `application/x-www-form-urlencoded` or `multipart/form-data`. + +* `sample` - (Optional) An example of this representation. + +* `schema_id` - (Optional) The ID of an API Management Schema which represents this Response. + +-> **NOTE:** This can only be specified when `content_type` is not set to `application/x-www-form-urlencoded` or `multipart/form-data`. + +* `type_name` - (Optional) The Type Name defined by the Schema. + +-> **NOTE:** This can only be specified when `content_type` is not set to `application/x-www-form-urlencoded` or `multipart/form-data`. + +--- + +A `response` block supports the following: + +* `status_code` - (Required) The HTTP Status Code. + +* `description` - (Required) A description of the HTTP Response, which may include HTML tags. + +* `header` - (Optional) One or more `header` blocks as defined above. + +* `representation` - (Optional) One or more `representation` blocks as defined below. + +--- + +A `template_parameter` block supports the following: + +* `name` - (Required) The Name of this Template Parameter. + +* `required` - (Required) Is this Template Parameter Required? + +* `type` - (Required) The Type of this Template Parameter, such as a `string`. + +* `description` - (Optional) A description of this Template Parameter. + +* `default_value` - (Optional) The default value for this Template Parameter. + +* `values` - (Optional) One or more acceptable values for this Template Parameter. + +--- + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the API Management API Operation. + +## Import + +API Management API Operation's can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_api_management_api_operation.test /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.ApiManagement/service/instance1/operations/operation1 +```