From 86f7705d90c981a43711f0352f09f1c361284cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Tue, 9 Oct 2018 11:24:50 +0200 Subject: [PATCH 01/38] Added basic support for API Management API --- azurerm/config.go | 5 + azurerm/data_source_api_management_api.go | 69 +++ azurerm/provider.go | 59 ++- azurerm/resource_arm_api_management_api.go | 484 +++++++++++++++++++++ 4 files changed, 584 insertions(+), 33 deletions(-) create mode 100644 azurerm/data_source_api_management_api.go create mode 100644 azurerm/resource_arm_api_management_api.go diff --git a/azurerm/config.go b/azurerm/config.go index afd6610e62a4..59a8249435aa 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -127,6 +127,7 @@ type ArmClient struct { redisPatchSchedulesClient redis.PatchSchedulesClient // API Management + apiManagementApiClient apimanagement.APIClient apiManagementGroupClient apimanagement.GroupClient apiManagementGroupUsersClient apimanagement.GroupUserClient apiManagementProductsClient apimanagement.ProductClient @@ -521,6 +522,10 @@ func (c *ArmClient) registerApiManagementServiceClients(endpoint, subscriptionId usersClient := apimanagement.NewUserClientWithBaseURI(endpoint, subscriptionId) c.configureClient(&usersClient.Client, auth) c.apiManagementUsersClient = usersClient + + api := apimanagement.NewAPIClientWithBaseURI(endpoint, subscriptionId) + c.configureClient(&api.Client, auth) + c.apiManagementApiClient = api } func (c *ArmClient) registerAppInsightsClients(endpoint, subscriptionId string, auth autorest.Authorizer) { diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go new file mode 100644 index 000000000000..b82b3f9eb501 --- /dev/null +++ b/azurerm/data_source_api_management_api.go @@ -0,0 +1,69 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceApiManagementApi() *schema.Resource { + return &schema.Resource{ + Read: dataSourceApiManagementApiRead, + + Schema: map[string]*schema.Schema{ + "service_name": { + Type: schema.TypeString, + Required: true, + }, + + "name": { + Type: schema.TypeString, + Required: true, + }, + + "resource_group_name": resourceGroupNameForDataSourceSchema(), + + "location": locationForDataSourceSchema(), + + // "tags": tagsForDataSourceSchema(), + }, + } +} + +func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).apiManagementApiClient + ctx := meta.(*ArmClient).StopContext + + resGroup := d.Get("resource_group_name").(string) + serviceName := d.Get("service_name").(string) + apiId := d.Get("name").(string) + + resp, err := client.Get(ctx, resGroup, serviceName, apiId) + + log.Printf("Response:") + log.Printf("%+v\n", resp) + + if err != nil { + return fmt.Errorf("Error making Read request on API Management Service %q (Resource Group %q): %+v", serviceName, resGroup, err) + } + + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error: API Management Service %q (Resource Group %q) was not found", serviceName, resGroup) + } + + d.SetId(*resp.ID) + + d.Set("service_name", serviceName) + d.Set("resource_group_name", resGroup) + d.Set("name", apiId) + + // if location := resp.Location(); location != nil { + // d.Set("location", azureRMNormalizeLocation(*location)) + // } + + // flattenAndSetTags(d, resp.tag) + + return nil +} diff --git a/azurerm/provider.go b/azurerm/provider.go index c3d8a11f9d55..4da420882a05 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -99,6 +99,7 @@ func Provider() terraform.ResourceProvider { DataSourcesMap: map[string]*schema.Resource{ "azurerm_api_management": dataSourceApiManagementService(), + "azurerm_api_management_api": dataSourceApiManagementApi(), "azurerm_api_management_group": dataSourceApiManagementGroup(), "azurerm_api_management_product": dataSourceApiManagementProduct(), "azurerm_api_management_user": dataSourceArmApiManagementUser(), @@ -167,7 +168,11 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ + "azurerm_azuread_application": resourceArmActiveDirectoryApplication(), + "azurerm_azuread_service_principal": resourceArmActiveDirectoryServicePrincipal(), + "azurerm_azuread_service_principal_password": resourceArmActiveDirectoryServicePrincipalPassword(), "azurerm_api_management": resourceArmApiManagementService(), + "azurerm_api_management_api": resourceArmApiManagementApi(), "azurerm_api_management_group": resourceArmApiManagementGroup(), "azurerm_api_management_group_user": resourceArmApiManagementGroupUser(), "azurerm_api_management_product": resourceArmApiManagementProduct(), @@ -180,9 +185,13 @@ func Provider() terraform.ResourceProvider { "azurerm_app_service_slot": resourceArmAppServiceSlot(), "azurerm_app_service": resourceArmAppService(), "azurerm_application_gateway": resourceArmApplicationGateway(), - "azurerm_application_insights_api_key": resourceArmApplicationInsightsAPIKey(), "azurerm_application_insights": resourceArmApplicationInsights(), "azurerm_application_security_group": resourceArmApplicationSecurityGroup(), + "azurerm_app_service": resourceArmAppService(), + "azurerm_app_service_plan": resourceArmAppServicePlan(), + "azurerm_app_service_active_slot": resourceArmAppServiceActiveSlot(), + "azurerm_app_service_custom_hostname_binding": resourceArmAppServiceCustomHostnameBinding(), + "azurerm_app_service_slot": resourceArmAppServiceSlot(), "azurerm_automation_account": resourceArmAutomationAccount(), "azurerm_automation_credential": resourceArmAutomationCredential(), "azurerm_automation_dsc_configuration": resourceArmAutomationDscConfiguration(), @@ -192,32 +201,25 @@ func Provider() terraform.ResourceProvider { "azurerm_automation_schedule": resourceArmAutomationSchedule(), "azurerm_autoscale_setting": resourceArmAutoScaleSetting(), "azurerm_availability_set": resourceArmAvailabilitySet(), - "azurerm_azuread_application": resourceArmActiveDirectoryApplication(), - "azurerm_azuread_service_principal_password": resourceArmActiveDirectoryServicePrincipalPassword(), - "azurerm_azuread_service_principal": resourceArmActiveDirectoryServicePrincipal(), - "azurerm_batch_account": resourceArmBatchAccount(), - "azurerm_batch_pool": resourceArmBatchPool(), "azurerm_cdn_endpoint": resourceArmCdnEndpoint(), "azurerm_cdn_profile": resourceArmCdnProfile(), "azurerm_cognitive_account": resourceArmCognitiveAccount(), - "azurerm_connection_monitor": resourceArmConnectionMonitor(), - "azurerm_container_group": resourceArmContainerGroup(), "azurerm_container_registry": resourceArmContainerRegistry(), "azurerm_container_service": resourceArmContainerService(), + "azurerm_container_group": resourceArmContainerGroup(), "azurerm_cosmosdb_account": resourceArmCosmosDBAccount(), + "azurerm_databricks_workspace": resourceArmDatabricksWorkspace(), "azurerm_data_lake_analytics_account": resourceArmDataLakeAnalyticsAccount(), "azurerm_data_lake_analytics_firewall_rule": resourceArmDataLakeAnalyticsFirewallRule(), + "azurerm_data_lake_store": resourceArmDataLakeStore(), "azurerm_data_lake_store_file": resourceArmDataLakeStoreFile(), "azurerm_data_lake_store_firewall_rule": resourceArmDataLakeStoreFirewallRule(), - "azurerm_data_lake_store": resourceArmDataLakeStore(), - "azurerm_databricks_workspace": resourceArmDatabricksWorkspace(), - "azurerm_ddos_protection_plan": resourceArmDDoSProtectionPlan(), + "azurerm_devspace_controller": resourceArmDevSpaceController(), "azurerm_dev_test_lab": resourceArmDevTestLab(), - "azurerm_dev_test_linux_virtual_machine": resourceArmDevTestLinuxVirtualMachine(), "azurerm_dev_test_policy": resourceArmDevTestPolicy(), + "azurerm_dev_test_linux_virtual_machine": resourceArmDevTestLinuxVirtualMachine(), "azurerm_dev_test_virtual_network": resourceArmDevTestVirtualNetwork(), "azurerm_dev_test_windows_virtual_machine": resourceArmDevTestWindowsVirtualMachine(), - "azurerm_devspace_controller": resourceArmDevSpaceController(), "azurerm_dns_a_record": resourceArmDnsARecord(), "azurerm_dns_aaaa_record": resourceArmDnsAAAARecord(), "azurerm_dns_caa_record": resourceArmDnsCaaRecord(), @@ -231,39 +233,36 @@ func Provider() terraform.ResourceProvider { "azurerm_eventgrid_domain": resourceArmEventGridDomain(), "azurerm_eventgrid_event_subscription": resourceArmEventGridEventSubscription(), "azurerm_eventgrid_topic": resourceArmEventGridTopic(), + "azurerm_eventhub": resourceArmEventHub(), "azurerm_eventhub_authorization_rule": resourceArmEventHubAuthorizationRule(), "azurerm_eventhub_consumer_group": resourceArmEventHubConsumerGroup(), - "azurerm_eventhub_namespace_authorization_rule": resourceArmEventHubNamespaceAuthorizationRule(), "azurerm_eventhub_namespace": resourceArmEventHubNamespace(), - "azurerm_eventhub": resourceArmEventHub(), + "azurerm_eventhub_namespace_authorization_rule": resourceArmEventHubNamespaceAuthorizationRule(), + "azurerm_express_route_circuit": resourceArmExpressRouteCircuit(), "azurerm_express_route_circuit_authorization": resourceArmExpressRouteCircuitAuthorization(), "azurerm_express_route_circuit_peering": resourceArmExpressRouteCircuitPeering(), - "azurerm_express_route_circuit": resourceArmExpressRouteCircuit(), - "azurerm_firewall_application_rule_collection": resourceArmFirewallApplicationRuleCollection(), - "azurerm_firewall_network_rule_collection": resourceArmFirewallNetworkRuleCollection(), "azurerm_firewall": resourceArmFirewall(), + "azurerm_firewall_network_rule_collection": resourceArmFirewallNetworkRuleCollection(), "azurerm_function_app": resourceArmFunctionApp(), "azurerm_image": resourceArmImage(), - "azurerm_iothub_consumer_group": resourceArmIotHubConsumerGroup(), "azurerm_iothub": resourceArmIotHub(), + "azurerm_iothub_consumer_group": resourceArmIotHubConsumerGroup(), + "azurerm_key_vault": resourceArmKeyVault(), "azurerm_key_vault_access_policy": resourceArmKeyVaultAccessPolicy(), "azurerm_key_vault_certificate": resourceArmKeyVaultCertificate(), "azurerm_key_vault_key": resourceArmKeyVaultKey(), "azurerm_key_vault_secret": resourceArmKeyVaultSecret(), - "azurerm_key_vault": resourceArmKeyVault(), "azurerm_kubernetes_cluster": resourceArmKubernetesCluster(), + "azurerm_lb": resourceArmLoadBalancer(), "azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(), - "azurerm_lb_nat_pool": resourceArmLoadBalancerNatPool(), "azurerm_lb_nat_rule": resourceArmLoadBalancerNatRule(), + "azurerm_lb_nat_pool": resourceArmLoadBalancerNatPool(), "azurerm_lb_probe": resourceArmLoadBalancerProbe(), - "azurerm_lb_outbound_rule": resourceArmLoadBalancerOutboundRule(), "azurerm_lb_rule": resourceArmLoadBalancerRule(), - "azurerm_lb": resourceArmLoadBalancer(), "azurerm_local_network_gateway": resourceArmLocalNetworkGateway(), "azurerm_log_analytics_solution": resourceArmLogAnalyticsSolution(), - "azurerm_log_analytics_linked_service": resourceArmLogAnalyticsLinkedService(), - "azurerm_log_analytics_workspace_linked_service": resourceArmLogAnalyticsWorkspaceLinkedService(), "azurerm_log_analytics_workspace": resourceArmLogAnalyticsWorkspace(), + "azurerm_log_analytics_workspace_linked_service": resourceArmLogAnalyticsWorkspaceLinkedService(), "azurerm_logic_app_action_custom": resourceArmLogicAppActionCustom(), "azurerm_logic_app_action_http": resourceArmLogicAppActionHTTP(), "azurerm_logic_app_trigger_custom": resourceArmLogicAppTriggerCustom(), @@ -271,30 +270,24 @@ func Provider() terraform.ResourceProvider { "azurerm_logic_app_trigger_recurrence": resourceArmLogicAppTriggerRecurrence(), "azurerm_logic_app_workflow": resourceArmLogicAppWorkflow(), "azurerm_managed_disk": resourceArmManagedDisk(), - "azurerm_management_group": resourceArmManagementGroup(), "azurerm_management_lock": resourceArmManagementLock(), - "azurerm_mariadb_database": resourceArmMariaDbDatabase(), - "azurerm_mariadb_server": resourceArmMariaDbServer(), - "azurerm_media_services_account": resourceArmMediaServicesAccount(), + "azurerm_management_group": resourceArmManagementGroup(), "azurerm_metric_alertrule": resourceArmMetricAlertRule(), - "azurerm_monitor_autoscale_setting": resourceArmMonitorAutoScaleSetting(), "azurerm_monitor_action_group": resourceArmMonitorActionGroup(), "azurerm_monitor_activity_log_alert": resourceArmMonitorActivityLogAlert(), "azurerm_monitor_diagnostic_setting": resourceArmMonitorDiagnosticSetting(), "azurerm_monitor_log_profile": resourceArmMonitorLogProfile(), "azurerm_monitor_metric_alert": resourceArmMonitorMetricAlert(), - "azurerm_monitor_metric_alertrule": resourceArmMonitorMetricAlertRule(), - "azurerm_mssql_elasticpool": resourceArmMsSqlElasticPool(), "azurerm_mysql_configuration": resourceArmMySQLConfiguration(), "azurerm_mysql_database": resourceArmMySqlDatabase(), "azurerm_mysql_firewall_rule": resourceArmMySqlFirewallRule(), "azurerm_mysql_server": resourceArmMySqlServer(), "azurerm_mysql_virtual_network_rule": resourceArmMySqlVirtualNetworkRule(), + "azurerm_network_interface": resourceArmNetworkInterface(), "azurerm_network_interface_application_gateway_backend_address_pool_association": resourceArmNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation(), "azurerm_network_interface_application_security_group_association": resourceArmNetworkInterfaceApplicationSecurityGroupAssociation(), "azurerm_network_interface_backend_address_pool_association": resourceArmNetworkInterfaceBackendAddressPoolAssociation(), "azurerm_network_interface_nat_rule_association": resourceArmNetworkInterfaceNatRuleAssociation(), - "azurerm_network_interface": resourceArmNetworkInterface(), "azurerm_network_security_group": resourceArmNetworkSecurityGroup(), "azurerm_network_security_rule": resourceArmNetworkSecurityRule(), "azurerm_network_watcher": resourceArmNetworkWatcher(), diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go new file mode 100644 index 000000000000..644ff87fb619 --- /dev/null +++ b/azurerm/resource_arm_api_management_api.go @@ -0,0 +1,484 @@ +package azurerm + +import ( + "fmt" + "log" + "strings" + + "github.com/Azure/azure-sdk-for-go/services/preview/apimanagement/mgmt/2018-06-01-preview/apimanagement" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmApiManagementApi() *schema.Resource { + return &schema.Resource{ + Create: resourceArmApiManagementApiCreateUpdate, + Read: resourceArmApiManagementApiRead, + Update: resourceArmApiManagementApiCreateUpdate, + Delete: resourceArmApiManagementApiDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + // ValidateFunc: azure.ValidateApiManagementApiName, + }, + + "service_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": resourceGroupNameSchema(), + + "location": locationSchema(), + + "path": { + Type: schema.TypeString, + Required: true, + }, + + "service_url": { + Type: schema.TypeString, + Optional: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + }, + + "import": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "content_value": { + Type: schema.TypeString, + Required: true, + }, + "content_format": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.SwaggerJSON), + string(apimanagement.SwaggerLinkJSON), + string(apimanagement.WadlLinkJSON), + string(apimanagement.WadlXML), + string(apimanagement.Wsdl), + string(apimanagement.WsdlLink), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + + "wsdl_selector": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_name": { + Type: schema.TypeString, + Required: true, + }, + + "endpoint_name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + + "protocols": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.ProtocolHTTP), + string(apimanagement.ProtocolHTTPS), + }, true), + }, + Optional: true, + }, + + "oauth": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorization_server_id": { + Type: schema.TypeString, + Required: true, + }, + "scope": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + + "subscription_key": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "header": { + Type: schema.TypeString, + Optional: true, + }, + "query": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "soap_api_type": { + Type: schema.TypeString, + Default: "", + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.HTTP), + string(apimanagement.Soap), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + Optional: true, + }, + + "revision": { + Type: schema.TypeInt, + Default: 1, + Optional: true, + }, + + "version": { + Type: schema.TypeString, + Optional: true, + }, + + "version_set": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "scheme": { + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.VersioningSchemeQuery), + string(apimanagement.VersioningSchemeHeader), + string(apimanagement.VersioningSchemeSegment), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + Required: true, + }, + "query_name": { + Type: schema.TypeString, + Optional: true, + }, + "header_name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "version_set_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "is_current": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "is_online": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + }, + } +} + +func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).apiManagementApiClient + ctx := meta.(*ArmClient).StopContext + + log.Printf("[INFO] preparing arguments for AzureRM API Management API creation.") + + resGroup := d.Get("resource_group_name").(string) + serviceName := d.Get("service_name").(string) + name := d.Get("name").(string) + revision := int32(d.Get("revision").(int)) + + apiId := fmt.Sprintf("%s;rev=%d", name, revision) + + var properties *apimanagement.APICreateOrUpdateProperties + var updateProperties *apimanagement.APIContractUpdateProperties + + _, isImport := d.GetOk("import") + + if isImport { + properties = expandApiManagementImportProperties(d) + updateProperties = expandApiManagementApiUpdateProperties(d) + } else { + properties = expandApiManagementApiProperties(d) + } + + apiParams := apimanagement.APICreateOrUpdateParameter{ + APICreateOrUpdateProperties: properties, + } + + log.Printf("[DEBUG] Calling api with resource group %q, service name %q, api id %q", resGroup, serviceName, apiId) + log.Printf("[DEBUG] Listing api params:") + log.Printf("%+v\n", apiParams.APICreateOrUpdateProperties) + + apiContract, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, apiParams, "") + if err != nil { + return err + } + + if isImport { + updateParams := apimanagement.APIUpdateContract{ + APIContractUpdateProperties: updateProperties, + } + + _, err := client.Update(ctx, resGroup, serviceName, apiId, updateParams, "") + + if err != nil { + return fmt.Errorf("Failed to update after import: %+v", err) + } + } + + d.SetId(*apiContract.ID) + + return resourceArmApiManagementApiRead(d, meta) +} + +func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient) + apiManagementApiClient := meta.(*ArmClient).apiManagementApiClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resGroup := id.ResourceGroup + serviceName := id.Path["service"] + apiid := id.Path["apis"] + + ctx := client.StopContext + resp, err := apiManagementApiClient.Get(ctx, resGroup, serviceName, apiid) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error making Read request on API Management API %q on service %q (Resource Group %q): %+v", apiid, serviceName, resGroup, err) + } + + log.Printf("%+v\n", resp) + return nil +} + +func resourceArmApiManagementApiDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).apiManagementApiClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resGroup := id.ResourceGroup + serviceName := id.Path["service"] + apiid := id.Path["apis"] + + log.Printf("[DEBUG] Deleting api management api %s: %s", resGroup, apiid) + + resp, err := client.Delete(ctx, resGroup, serviceName, apiid, "*", utils.Bool(true)) + + if err != nil { + if utils.ResponseWasNotFound(resp) { + return nil + } + + return err + } + + return nil +} + +func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { + revision := d.Get("revision").(string) + displayName := d.Get("name").(string) + path := d.Get("path").(string) + serviceUrl := d.Get("service_url").(string) + description := d.Get("description").(string) + soapApiTypeConfig := d.Get("soap_api_type").(string) + version := d.Get("version").(string) + versionSetId := d.Get("version_set_id").(string) + isCurrent := d.Get("is_current").(bool) + isOnline := d.Get("is_online").(bool) + + soapApiType := apimanagement.APIType(soapApiTypeConfig) + + protos := make([]apimanagement.Protocol, 0) + if p, ok := d.GetOk("protocols.0"); ok { + protocolsConfig := p.([]interface{}) + for _, v := range protocolsConfig { + protos = append(protos, apimanagement.Protocol(v.(string))) + } + } + if len(protos) == 0 { + protos = append(protos, apimanagement.ProtocolHTTPS) + } + + // versionSetId := d.Get("api_version_set_id").(string) + + // var oAuth *apimanagement.OAuth2AuthenticationSettingsContract + // if oauthConfig := d.Get("oauth").([]interface{}); oauthConfig != nil && len(oauthConfig) > 0 { + // oAuth = expandApiManagementApiOAuth(oauthConfig) + // } + + return &apimanagement.APICreateOrUpdateProperties{ + APIRevision: &revision, + APIType: soapApiType, + APIVersion: &version, + // APIVersionSet: nil, + APIVersionSetID: &versionSetId, + // AuthenticationSettings: &apimanagement.AuthenticationSettingsContract{ + // OAuth2: oAuth, + // }, + Description: &description, + DisplayName: &displayName, + IsCurrent: &isCurrent, + IsOnline: &isOnline, + Path: &path, + Protocols: &protos, + ServiceURL: &serviceUrl, + // SubscriptionKeyParameterNames: nil, + } +} + +func expandApiManagementApiUpdateProperties(d *schema.ResourceData) *apimanagement.APIContractUpdateProperties { + name := d.Get("name").(string) + path := d.Get("path").(string) + serviceUrl := d.Get("service_url").(string) + description := d.Get("description").(string) + soapApiTypeConfig := d.Get("soap_api_type").(string) + // revisionDescription := d.Get("revision_description").(string) + + protos := make([]apimanagement.Protocol, 0) + + if p, ok := d.GetOk("protocols.0"); ok { + protocolsConfig := p.([]interface{}) + for _, v := range protocolsConfig { + protos = append(protos, apimanagement.Protocol(v.(string))) + } + } + + if len(protos) == 0 { + protos = append(protos, apimanagement.ProtocolHTTPS) + } + + var soapApiType apimanagement.APIType + + switch s := strings.ToLower(soapApiTypeConfig); s { + case "http": + soapApiType = apimanagement.HTTP + case "soap": + soapApiType = apimanagement.Soap + } + + // versionSetId := d.Get("api_version_set_id").(string) + + // var oAuth *apimanagement.OAuth2AuthenticationSettingsContract + // if oauthConfig := d.Get("oauth").([]interface{}); oauthConfig != nil && len(oauthConfig) > 0 { + // oAuth = expandApiManagementApiOAuth(oauthConfig) + // } + + log.Printf("ServiceURL: %s", &serviceUrl) + + return &apimanagement.APIContractUpdateProperties{ + // APIRevision: nil, + APIType: soapApiType, + // APIVersion: nil, + // APIVersionSetID: nil, + // AuthenticationSettings: nil, + Description: &description, + DisplayName: &name, + // IsCurrent: nil, + // IsOnline: nil, + Path: &path, + Protocols: &protos, + ServiceURL: &serviceUrl, + // SubscriptionKeyParameterNames: nil, + } +} + +func expandApiManagementImportProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { + path := d.Get("path").(string) + + var contentFormat apimanagement.ContentFormat + if v, ok := d.GetOk("import.0.content_format"); ok { + contentFormat = apimanagement.ContentFormat(v.(string)) + } + + var contentValue string + if v, ok := d.GetOk("import.0.content_value"); ok { + contentValue = v.(string) + } + + return &apimanagement.APICreateOrUpdateProperties{ + Path: &path, + ContentFormat: contentFormat, + ContentValue: &contentValue, + } +} + +func expandApiManagementApiOAuth(oauth []interface{}) *apimanagement.OAuth2AuthenticationSettingsContract { + config := oauth[0].(map[string]interface{}) + + authorization_server_id := config["authorization_server_id"].(string) + scope := config["scope"].(string) + + return &apimanagement.OAuth2AuthenticationSettingsContract{ + AuthorizationServerID: &authorization_server_id, + Scope: &scope, + } +} + +func flattenApiManagementApiContract(apiContract apimanagement.APIContract) error { + return nil +} From e97cb7d9da369a9b9c3465e5319e4be6486619dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Fri, 12 Oct 2018 00:17:09 +0200 Subject: [PATCH 02/38] Cleaned up unused schema elements of API Management API --- azurerm/resource_arm_api_management_api.go | 157 +++++++-------------- 1 file changed, 51 insertions(+), 106 deletions(-) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 644ff87fb619..8a378539fd79 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -22,7 +22,7 @@ func resourceArmApiManagementApi() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { + "name": { // DisplayName Type: schema.TypeString, Optional: true, ForceNew: true, @@ -111,6 +111,7 @@ func resourceArmApiManagementApi() *schema.Resource { }, true), }, Optional: true, + Computed: true, // Azure API sets protocols to https by default }, "oauth": { @@ -162,66 +163,26 @@ func resourceArmApiManagementApi() *schema.Resource { "revision": { Type: schema.TypeInt, - Default: 1, - Optional: true, + Computed: true, }, "version": { Type: schema.TypeString, - Optional: true, - }, - - "version_set": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "description": { - Type: schema.TypeString, - Optional: true, - }, - "scheme": { - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - string(apimanagement.VersioningSchemeQuery), - string(apimanagement.VersioningSchemeHeader), - string(apimanagement.VersioningSchemeSegment), - }, true), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - Required: true, - }, - "query_name": { - Type: schema.TypeString, - Optional: true, - }, - "header_name": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, + Computed: true, }, "version_set_id": { Type: schema.TypeString, - Optional: true, Computed: true, }, "is_current": { Type: schema.TypeBool, - Optional: true, Computed: true, }, "is_online": { Type: schema.TypeBool, - Optional: true, Computed: true, }, }, @@ -237,9 +198,9 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf resGroup := d.Get("resource_group_name").(string) serviceName := d.Get("service_name").(string) name := d.Get("name").(string) - revision := int32(d.Get("revision").(int)) - apiId := fmt.Sprintf("%s;rev=%d", name, revision) + //Currently we don't support revisions, so we use 1 as default + apiId := fmt.Sprintf("%s;rev=%d", name, 1) var properties *apimanagement.APICreateOrUpdateProperties var updateProperties *apimanagement.APIContractUpdateProperties @@ -258,9 +219,6 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf } log.Printf("[DEBUG] Calling api with resource group %q, service name %q, api id %q", resGroup, serviceName, apiId) - log.Printf("[DEBUG] Listing api params:") - log.Printf("%+v\n", apiParams.APICreateOrUpdateProperties) - apiContract, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, apiParams, "") if err != nil { return err @@ -296,6 +254,11 @@ func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) e serviceName := id.Path["service"] apiid := id.Path["apis"] + name := apiid + if strings.Contains(apiid, ";") { + name = strings.Split(apiid, ";")[0] + } + ctx := client.StopContext resp, err := apiManagementApiClient.Get(ctx, resGroup, serviceName, apiid) @@ -307,6 +270,22 @@ func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error making Read request on API Management API %q on service %q (Resource Group %q): %+v", apiid, serviceName, resGroup, err) } + d.Set("name", name) + d.Set("resource_group_name", resGroup) + d.Set("service_name", serviceName) + + if props := resp.APIContractProperties; props != nil { + d.Set("path", props.Path) + d.Set("description", props.Description) + d.Set("soap_api_type", props.APIType) + d.Set("revision", props.APIRevision) + d.Set("version", props.APIVersion) + d.Set("version_set_id", props.APIVersionSetID) + d.Set("is_current", props.IsCurrent) + d.Set("is_online", props.IsOnline) + d.Set("protocols", props.Protocols) + } + log.Printf("%+v\n", resp) return nil } @@ -340,30 +319,13 @@ func resourceArmApiManagementApiDelete(d *schema.ResourceData, meta interface{}) } func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { - revision := d.Get("revision").(string) displayName := d.Get("name").(string) path := d.Get("path").(string) serviceUrl := d.Get("service_url").(string) description := d.Get("description").(string) soapApiTypeConfig := d.Get("soap_api_type").(string) - version := d.Get("version").(string) - versionSetId := d.Get("version_set_id").(string) - isCurrent := d.Get("is_current").(bool) - isOnline := d.Get("is_online").(bool) - soapApiType := apimanagement.APIType(soapApiTypeConfig) - protos := make([]apimanagement.Protocol, 0) - if p, ok := d.GetOk("protocols.0"); ok { - protocolsConfig := p.([]interface{}) - for _, v := range protocolsConfig { - protos = append(protos, apimanagement.Protocol(v.(string))) - } - } - if len(protos) == 0 { - protos = append(protos, apimanagement.ProtocolHTTPS) - } - // versionSetId := d.Get("api_version_set_id").(string) // var oAuth *apimanagement.OAuth2AuthenticationSettingsContract @@ -372,45 +334,38 @@ func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.API // } return &apimanagement.APICreateOrUpdateProperties{ - APIRevision: &revision, - APIType: soapApiType, - APIVersion: &version, - // APIVersionSet: nil, - APIVersionSetID: &versionSetId, + APIType: soapApiType, // AuthenticationSettings: &apimanagement.AuthenticationSettingsContract{ // OAuth2: oAuth, // }, Description: &description, DisplayName: &displayName, - IsCurrent: &isCurrent, - IsOnline: &isOnline, Path: &path, - Protocols: &protos, + Protocols: expandApiManagementApiProtocols(d), ServiceURL: &serviceUrl, // SubscriptionKeyParameterNames: nil, } } -func expandApiManagementApiUpdateProperties(d *schema.ResourceData) *apimanagement.APIContractUpdateProperties { - name := d.Get("name").(string) - path := d.Get("path").(string) - serviceUrl := d.Get("service_url").(string) - description := d.Get("description").(string) - soapApiTypeConfig := d.Get("soap_api_type").(string) - // revisionDescription := d.Get("revision_description").(string) - +func expandApiManagementApiProtocols(d *schema.ResourceData) *[]apimanagement.Protocol { protos := make([]apimanagement.Protocol, 0) - if p, ok := d.GetOk("protocols.0"); ok { + if p, ok := d.GetOk("protocols"); ok { protocolsConfig := p.([]interface{}) for _, v := range protocolsConfig { protos = append(protos, apimanagement.Protocol(v.(string))) } } - if len(protos) == 0 { - protos = append(protos, apimanagement.ProtocolHTTPS) - } + return &protos +} + +func expandApiManagementApiUpdateProperties(d *schema.ResourceData) *apimanagement.APIContractUpdateProperties { + name := d.Get("name").(string) + path := d.Get("path").(string) + serviceUrl := d.Get("service_url").(string) + description := d.Get("description").(string) + soapApiTypeConfig := d.Get("soap_api_type").(string) var soapApiType apimanagement.APIType @@ -431,18 +386,13 @@ func expandApiManagementApiUpdateProperties(d *schema.ResourceData) *apimanageme log.Printf("ServiceURL: %s", &serviceUrl) return &apimanagement.APIContractUpdateProperties{ - // APIRevision: nil, APIType: soapApiType, - // APIVersion: nil, - // APIVersionSetID: nil, // AuthenticationSettings: nil, Description: &description, DisplayName: &name, - // IsCurrent: nil, - // IsOnline: nil, - Path: &path, - Protocols: &protos, - ServiceURL: &serviceUrl, + Path: &path, + Protocols: expandApiManagementApiProtocols(d), + ServiceURL: &serviceUrl, // SubscriptionKeyParameterNames: nil, } } @@ -450,21 +400,20 @@ func expandApiManagementApiUpdateProperties(d *schema.ResourceData) *apimanageme func expandApiManagementImportProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { path := d.Get("path").(string) - var contentFormat apimanagement.ContentFormat + props := &apimanagement.APICreateOrUpdateProperties{ + Path: &path, + } + if v, ok := d.GetOk("import.0.content_format"); ok { - contentFormat = apimanagement.ContentFormat(v.(string)) + props.ContentFormat = apimanagement.ContentFormat(v.(string)) } - var contentValue string if v, ok := d.GetOk("import.0.content_value"); ok { - contentValue = v.(string) + content_val := v.(string) + props.ContentValue = &content_val } - return &apimanagement.APICreateOrUpdateProperties{ - Path: &path, - ContentFormat: contentFormat, - ContentValue: &contentValue, - } + return props } func expandApiManagementApiOAuth(oauth []interface{}) *apimanagement.OAuth2AuthenticationSettingsContract { @@ -478,7 +427,3 @@ func expandApiManagementApiOAuth(oauth []interface{}) *apimanagement.OAuth2Authe Scope: &scope, } } - -func flattenApiManagementApiContract(apiContract apimanagement.APIContract) error { - return nil -} From 14eba357af2381ff43945b091c165146c1e43083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Fri, 12 Oct 2018 14:53:37 +0200 Subject: [PATCH 03/38] Added docs for api_management_api resource --- .../docs/r/api_management_api.html.markdown | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 website/docs/r/api_management_api.html.markdown diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown new file mode 100644 index 000000000000..5a38d551d4d3 --- /dev/null +++ b/website/docs/r/api_management_api.html.markdown @@ -0,0 +1,129 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_api_management_api" +sidebar_current: "docs-azurerm-resource-api-management-api-x" +description: |- + Create a API Management API. +--- + +# azurerm_api_management_api + +Create a API Management API component. + +## Example Usage (import from Open API spec) + +```hcl +resource "azurerm_resource_group" "test" { + name = "api-rg-dev" + location = "West Europe" +} + +resource "azurerm_api_management" "test" { + name = "api-mngmnt-dev" + publisher_name = "My Company" + publisher_email = "company@terraform.io" + sku { + name = "Developer" + } + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_api_management_api" "test" { + name = "conferenceapi" + service_name = "${azurerm_api_management.test.name}" + path = "/conference" + import { + content_format = "swagger-link-json" + content_value = "http://conferenceapi.azurewebsites.net/?format=json" + } + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the API Management API. + +* `resource_group_name` - (Required) The Name of the Resource Group where the API Management API exists. + +* `location` - (Required) The Azure location where the API Management API exists. + +* `service_name` - (Required) The Name of the API Management Service where the API Management API exists + +* `path` - (Required) Relative URL uniquely identifying this API and all of its resource paths within the API Management service instance. It is appended to the API endpoint base URL specified during the service instance creation to form a public URL for this API. + +--- + +* `service_url` - (Optional) Absolute URL of the backend service implementing this API. + +* `description` - (Optional) Description of the API. May include HTML formatting tags. + +* `protocols` - (Optional) A list of protocols the operations in this API can be invoked. Supported values are `http` and `https`. Default is `https`. + +* `revision` - (Optional) The revision number of the API. + +* `revision_description` - (Optional) Description of current revision. + +-> **Note:** Setting revision using this resource is supported, but revision are more of a deployment concept than infrastructure, so we recommend finding other means to manage revisions. + +* `import` - (Optional) A `import` block as documented below. + +* `oauth` - (Optional) A `oauth` block as documented below. + +* `subscription_key` - (Optional) A `subscription_key` block as documented below. + +* `soap_api_type` - (Optional) Type of Soap API. Possible values include: 'http' or 'soap'. `http` creates a SOAP to REST API. `soap` creates a SOAP pass-through API. Default behavior when not set is REST API to REST API. + +--- + +`import` block supports the following: + +* `content_format` - (Required) Format of the Content in which the API is getting imported. Possible values include: 'swagger-json', 'swagger-link-json', 'wadl-link-json', 'wadl-xml', 'wsdl', 'wsdl-link'. + +* `content_value` - (Required) Content value when Importing an API. When a `*-link-*` `content_format` is used, the `content_value` must be a URL. If not, `content_value` is defined inline. + +* `wsdl_selector` - (Optional) Criteria to limit import of WSDL to a subset of the document. Only applicable to content with format `wsdl` or `wsdl-link`. The `wsdl_selector` block is documented below. + +--- + +`wsdl_selector` block supports the following: + +* `service_name` - (Required) Name of service to import from WSDL. + +* `endpoint_name` - (Required) Name of endpoint(port) to import from WSDL. + +--- + +`oauth` block supports the following: + +* `authorization_server_id` - (Required) OAuth authorization server identifier. + +* `scope` - (Required) Operations scope. + +--- + +`subscription_key` block supports the following: + +* `header` - (Optional) Subscription key header name. + +* `query` - (Optional) Subscription key query string parameter name. + +-> **Note:** Set both `header` and `query` to support using subscription key in both, or one of `header` or `query` to support one of them. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the API Management API component. + +## Import + +Api Management API can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_api_management_api.test /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.ApiManagement/service/instance1/apis/api1 +``` From 8ab94d1b3b87a45ea51a4df848e0b92485dafce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 01:03:56 +0200 Subject: [PATCH 04/38] Added missing fields to schema --- azurerm/data_source_api_management_api.go | 117 +++++++++++++++++++--- 1 file changed, 101 insertions(+), 16 deletions(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index b82b3f9eb501..4150207d24db 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -2,7 +2,6 @@ package azurerm import ( "fmt" - "log" "github.com/hashicorp/terraform/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" @@ -27,7 +26,81 @@ func dataSourceApiManagementApi() *schema.Resource { "location": locationForDataSourceSchema(), - // "tags": tagsForDataSourceSchema(), + "display_name": { + Type: schema.TypeString, + Computed: true, + }, + + "path": { + Type: schema.TypeString, + Computed: true, + }, + + "service_url": { + Type: schema.TypeString, + Computed: true, + }, + + "description": { + Type: schema.TypeString, + Computed: true, + }, + + "protocols": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Computed: true, + }, + + "subscription_key_parameter_names": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "header": { + Type: schema.TypeString, + Computed: true, + }, + "query": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "soap_api_type": { + Type: schema.TypeString, + Computed: true, + }, + + "revision": { + Type: schema.TypeInt, + Computed: true, + }, + + "version": { + Type: schema.TypeString, + Computed: true, + }, + + "version_set_id": { + Type: schema.TypeString, + Computed: true, + }, + + "is_current": { + Type: schema.TypeBool, + Computed: true, + }, + + "is_online": { + Type: schema.TypeBool, + Computed: true, + }, }, } } @@ -38,32 +111,44 @@ func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) er resGroup := d.Get("resource_group_name").(string) serviceName := d.Get("service_name").(string) - apiId := d.Get("name").(string) + name := d.Get("name").(string) - resp, err := client.Get(ctx, resGroup, serviceName, apiId) + //Currently we don't support revisions, so we use 1 as default + apiId := fmt.Sprintf("%s;rev=%d", name, 1) - log.Printf("Response:") - log.Printf("%+v\n", resp) + resp, err := client.Get(ctx, resGroup, serviceName, apiId) if err != nil { - return fmt.Errorf("Error making Read request on API Management Service %q (Resource Group %q): %+v", serviceName, resGroup, err) - } + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("API Management API %q (Resource Group %q) was not found", name, resGroup) + } - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Error: API Management Service %q (Resource Group %q) was not found", serviceName, resGroup) + return fmt.Errorf("Error retrieving API Management API %q (Resource Group %q): %+v", name, resGroup, err) } d.SetId(*resp.ID) + d.Set("name", apiId) d.Set("service_name", serviceName) d.Set("resource_group_name", resGroup) - d.Set("name", apiId) - // if location := resp.Location(); location != nil { - // d.Set("location", azureRMNormalizeLocation(*location)) - // } - - // flattenAndSetTags(d, resp.tag) + if props := resp.APIContractProperties; props != nil { + d.Set("display_name", props.DisplayName) + d.Set("service_url", props.ServiceURL) + d.Set("path", props.Path) + d.Set("description", props.Description) + d.Set("soap_api_type", props.APIType) + d.Set("revision", props.APIRevision) + d.Set("version", props.APIVersion) + d.Set("version_set_id", props.APIVersionSetID) + d.Set("is_current", props.IsCurrent) + d.Set("is_online", props.IsOnline) + d.Set("protocols", props.Protocols) + + if err := d.Set("subscription_key_parameter_names", flattenApiManagementApiSubscriptionKeyParamNames(props.SubscriptionKeyParameterNames)); err != nil { + return fmt.Errorf("Error setting `subscription_key_parameter_names`: %+v", err) + } + } return nil } From 308f7d30c2ff9554c60538105d8968c1a0d2a38a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 01:06:13 +0200 Subject: [PATCH 05/38] Cleaned up, tested and added data to schema fields --- azurerm/resource_arm_api_management_api.go | 171 ++++++++++----------- 1 file changed, 82 insertions(+), 89 deletions(-) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 8a378539fd79..20c2402749c2 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -22,7 +22,7 @@ func resourceArmApiManagementApi() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { // DisplayName + "name": { Type: schema.TypeString, Optional: true, ForceNew: true, @@ -44,6 +44,11 @@ func resourceArmApiManagementApi() *schema.Resource { Required: true, }, + "display_name": { + Type: schema.TypeString, + Optional: true, + }, + "service_url": { Type: schema.TypeString, Optional: true, @@ -114,37 +119,22 @@ func resourceArmApiManagementApi() *schema.Resource { Computed: true, // Azure API sets protocols to https by default }, - "oauth": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "authorization_server_id": { - Type: schema.TypeString, - Required: true, - }, - "scope": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - - "subscription_key": { + "subscription_key_parameter_names": { Type: schema.TypeList, Optional: true, + Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "header": { Type: schema.TypeString, Optional: true, + Computed: true, }, "query": { Type: schema.TypeString, Optional: true, + Computed: true, }, }, }, @@ -203,13 +193,13 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf apiId := fmt.Sprintf("%s;rev=%d", name, 1) var properties *apimanagement.APICreateOrUpdateProperties - var updateProperties *apimanagement.APIContractUpdateProperties - _, isImport := d.GetOk("import") + _, hasImport := d.GetOk("import") - if isImport { + // If import is used, we need to send properties to Azure API in two operations. + // First we execute import and then updated the other props. + if hasImport { properties = expandApiManagementImportProperties(d) - updateProperties = expandApiManagementApiUpdateProperties(d) } else { properties = expandApiManagementApiProperties(d) } @@ -224,12 +214,13 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf return err } - if isImport { - updateParams := apimanagement.APIUpdateContract{ - APIContractUpdateProperties: updateProperties, + if hasImport { + // Update with aditional properties not possible to send to Azure API during import + updateParams := apimanagement.APICreateOrUpdateParameter{ + APICreateOrUpdateProperties: expandApiManagementApiProperties(d), } - _, err := client.Update(ctx, resGroup, serviceName, apiId, updateParams, "") + _, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, updateParams, "") if err != nil { return fmt.Errorf("Failed to update after import: %+v", err) @@ -275,6 +266,8 @@ func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) e d.Set("service_name", serviceName) if props := resp.APIContractProperties; props != nil { + d.Set("display_name", props.DisplayName) + d.Set("service_url", props.ServiceURL) d.Set("path", props.Path) d.Set("description", props.Description) d.Set("soap_api_type", props.APIType) @@ -284,6 +277,10 @@ func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) e d.Set("is_current", props.IsCurrent) d.Set("is_online", props.IsOnline) d.Set("protocols", props.Protocols) + + if err := d.Set("subscription_key_parameter_names", flattenApiManagementApiSubscriptionKeyParamNames(props.SubscriptionKeyParameterNames)); err != nil { + return fmt.Errorf("Error setting `subscription_key_parameter_names`: %+v", err) + } } log.Printf("%+v\n", resp) @@ -319,32 +316,42 @@ func resourceArmApiManagementApiDelete(d *schema.ResourceData, meta interface{}) } func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { - displayName := d.Get("name").(string) + displayName := d.Get("display_name").(string) path := d.Get("path").(string) serviceUrl := d.Get("service_url").(string) description := d.Get("description").(string) soapApiTypeConfig := d.Get("soap_api_type").(string) soapApiType := apimanagement.APIType(soapApiTypeConfig) - // versionSetId := d.Get("api_version_set_id").(string) + return &apimanagement.APICreateOrUpdateProperties{ + APIType: soapApiType, + Description: &description, + DisplayName: &displayName, + Path: &path, + Protocols: expandApiManagementApiProtocols(d), + ServiceURL: &serviceUrl, + SubscriptionKeyParameterNames: expandApiManagementApiSubscriptionKeyParamNames(d), + } +} - // var oAuth *apimanagement.OAuth2AuthenticationSettingsContract - // if oauthConfig := d.Get("oauth").([]interface{}); oauthConfig != nil && len(oauthConfig) > 0 { - // oAuth = expandApiManagementApiOAuth(oauthConfig) - // } +func expandApiManagementApiSubscriptionKeyParamNames(d *schema.ResourceData) *apimanagement.SubscriptionKeyParameterNamesContract { + var contract apimanagement.SubscriptionKeyParameterNamesContract - return &apimanagement.APICreateOrUpdateProperties{ - APIType: soapApiType, - // AuthenticationSettings: &apimanagement.AuthenticationSettingsContract{ - // OAuth2: oAuth, - // }, - Description: &description, - DisplayName: &displayName, - Path: &path, - Protocols: expandApiManagementApiProtocols(d), - ServiceURL: &serviceUrl, - // SubscriptionKeyParameterNames: nil, + if v, ok := d.GetOk("subscription_key_parameter_names.0.header"); ok { + header := v.(string) + contract.Header = &header } + + if v, ok := d.GetOk("subscription_key_parameter_names.0.query"); ok { + query := v.(string) + contract.Query = &query + } + + if contract.Header == nil && contract.Query == nil { + return nil + } + + return &contract } func expandApiManagementApiProtocols(d *schema.ResourceData) *[]apimanagement.Protocol { @@ -355,48 +362,14 @@ func expandApiManagementApiProtocols(d *schema.ResourceData) *[]apimanagement.Pr for _, v := range protocolsConfig { protos = append(protos, apimanagement.Protocol(v.(string))) } + } else { + // If not specified, set default to https + protos = append(protos, apimanagement.ProtocolHTTPS) } return &protos } -func expandApiManagementApiUpdateProperties(d *schema.ResourceData) *apimanagement.APIContractUpdateProperties { - name := d.Get("name").(string) - path := d.Get("path").(string) - serviceUrl := d.Get("service_url").(string) - description := d.Get("description").(string) - soapApiTypeConfig := d.Get("soap_api_type").(string) - - var soapApiType apimanagement.APIType - - switch s := strings.ToLower(soapApiTypeConfig); s { - case "http": - soapApiType = apimanagement.HTTP - case "soap": - soapApiType = apimanagement.Soap - } - - // versionSetId := d.Get("api_version_set_id").(string) - - // var oAuth *apimanagement.OAuth2AuthenticationSettingsContract - // if oauthConfig := d.Get("oauth").([]interface{}); oauthConfig != nil && len(oauthConfig) > 0 { - // oAuth = expandApiManagementApiOAuth(oauthConfig) - // } - - log.Printf("ServiceURL: %s", &serviceUrl) - - return &apimanagement.APIContractUpdateProperties{ - APIType: soapApiType, - // AuthenticationSettings: nil, - Description: &description, - DisplayName: &name, - Path: &path, - Protocols: expandApiManagementApiProtocols(d), - ServiceURL: &serviceUrl, - // SubscriptionKeyParameterNames: nil, - } -} - func expandApiManagementImportProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { path := d.Get("path").(string) @@ -413,17 +386,37 @@ func expandApiManagementImportProperties(d *schema.ResourceData) *apimanagement. props.ContentValue = &content_val } + if _, selectorUsed := d.GetOk("import.0.wsdl_selector"); selectorUsed { + props.WsdlSelector = &apimanagement.APICreateOrUpdatePropertiesWsdlSelector{} + + if v, ok := d.GetOk("import.0.wsdl_selector.0.service_name"); ok { + serviceName := v.(string) + props.WsdlSelector.WsdlServiceName = &serviceName + } + + if v, ok := d.GetOk("import.0.wsdl_selector.0.endpoint_name"); ok { + endpointName := v.(string) + props.WsdlSelector.WsdlEndpointName = &endpointName + } + } + return props } -func expandApiManagementApiOAuth(oauth []interface{}) *apimanagement.OAuth2AuthenticationSettingsContract { - config := oauth[0].(map[string]interface{}) +func flattenApiManagementApiSubscriptionKeyParamNames(paramNames *apimanagement.SubscriptionKeyParameterNamesContract) []interface{} { + if paramNames == nil { + return make([]interface{}, 0) + } - authorization_server_id := config["authorization_server_id"].(string) - scope := config["scope"].(string) + result := make(map[string]interface{}) - return &apimanagement.OAuth2AuthenticationSettingsContract{ - AuthorizationServerID: &authorization_server_id, - Scope: &scope, + if paramNames.Header != nil { + result["header"] = *paramNames.Header } + + if paramNames.Query != nil { + result["query"] = *paramNames.Query + } + + return []interface{}{result} } From 5e0b3bc0660e0befe265776f3ae5a872c592c8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 12:27:29 +0200 Subject: [PATCH 06/38] Cleanup: * Replaced soap_api_type with bool soap_pass_through * Added validation for api path and name * Added validation tests for api path and name --- azurerm/data_source_api_management_api.go | 7 +- azurerm/helpers/validate/api_management.go | 20 +++++ .../helpers/validate/api_management_test.go | 84 +++++++++++++++++++ azurerm/resource_arm_api_management_api.go | 54 +++++++----- 4 files changed, 139 insertions(+), 26 deletions(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index 4150207d24db..3253202da1fd 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -3,6 +3,7 @@ package azurerm import ( "fmt" + "github.com/Azure/azure-sdk-for-go/services/preview/apimanagement/mgmt/2018-06-01-preview/apimanagement" "github.com/hashicorp/terraform/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -72,8 +73,8 @@ func dataSourceApiManagementApi() *schema.Resource { }, }, - "soap_api_type": { - Type: schema.TypeString, + "soap_pass_through": { + Type: schema.TypeBool, Computed: true, }, @@ -137,13 +138,13 @@ func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) er d.Set("service_url", props.ServiceURL) d.Set("path", props.Path) d.Set("description", props.Description) - d.Set("soap_api_type", props.APIType) d.Set("revision", props.APIRevision) d.Set("version", props.APIVersion) d.Set("version_set_id", props.APIVersionSetID) d.Set("is_current", props.IsCurrent) d.Set("is_online", props.IsOnline) d.Set("protocols", props.Protocols) + d.Set("soap_pass_through", string(props.APIType) == string(apimanagement.SoapPassThrough)) if err := d.Set("subscription_key_parameter_names", flattenApiManagementApiSubscriptionKeyParamNames(props.SubscriptionKeyParameterNames)); err != nil { return fmt.Errorf("Error setting `subscription_key_parameter_names`: %+v", err) diff --git a/azurerm/helpers/validate/api_management.go b/azurerm/helpers/validate/api_management.go index d75d4208133a..bdbb90583c79 100644 --- a/azurerm/helpers/validate/api_management.go +++ b/azurerm/helpers/validate/api_management.go @@ -58,3 +58,23 @@ func ApiManagementServicePublisherEmail(v interface{}, k string) (warnings []str return warnings, errors } + +func ApiManagementApiName(v interface{}, k string) (ws []string, es []error) { + value := v.(string) + + if matched := regexp.MustCompile(`^[^*#&+]{1,256}$`).Match([]byte(value)); !matched { + es = append(es, fmt.Errorf("%q may only be up to 256 characters in length and not include the characters `*`, `#`, `&` or `+`", k)) + } + + return +} + +func ApiManagementApiPath(v interface{}, k string) (ws []string, es []error) { + value := v.(string) + + if matched := regexp.MustCompile(`^[\w][\w-/.]+[\w-]$`).Match([]byte(value)); !matched { + es = append(es, fmt.Errorf("%q may only be up to 256 characters in length, not start or end with `/` and only contain valid url characters", k)) + } + + return +} diff --git a/azurerm/helpers/validate/api_management_test.go b/azurerm/helpers/validate/api_management_test.go index 3c7e3554b647..62ea30a3cdd8 100644 --- a/azurerm/helpers/validate/api_management_test.go +++ b/azurerm/helpers/validate/api_management_test.go @@ -95,3 +95,87 @@ func TestAzureRMApiManagementPublisherName_validation(t *testing.T) { } } } + +func TestAzureRMApiManagementApiPath_validation(t *testing.T) { + cases := []struct { + Value string + ErrCount int + }{ + { + Value: "", + ErrCount: 1, + }, + { + Value: "/", + ErrCount: 1, + }, + { + Value: "/abc", + ErrCount: 1, + }, + { + Value: "api1", + ErrCount: 0, + }, + { + Value: "api1/", + ErrCount: 1, + }, + { + Value: "api1/sub", + ErrCount: 0, + }, + } + + for _, tc := range cases { + _, errors := ApiManagementApiPath(tc.Value, "azurerm_api_management_api") + + if len(errors) != tc.ErrCount { + t.Fatalf("Expected the Api Management Api Path to trigger a validation error for '%s'", tc.Value) + } + } +} + +func TestAzureRMApiManagementApiName_validation(t *testing.T) { + cases := []struct { + Value string + ErrCount int + }{ + { + Value: "", + ErrCount: 1, + }, + { + Value: "asdf+", + ErrCount: 1, + }, + { + Value: "adsf&", + ErrCount: 1, + }, + { + Value: "asdfasdf#", + ErrCount: 1, + }, + { + Value: "asdf*", + ErrCount: 1, + }, + { + Value: "alksdjl asdlfj laskdjflkjasdlfj lasdf", + ErrCount: 0, + }, + { + Value: "ddlfj laskdjflkjasdlfj lasdf alksdjflka sdlfjalsdjflajdsflkjasd alsdkjflaksjd flajksdl fjasldkjf lasjdflkajs dfljas ldfjj aljds fljasldkf jalsdjf lakjsdf ljasldkfjalskdjf lakjsd flkajs dlfkja lsdkjf laksdjf lkasjdf lkajsdlfk jasldkfj asldkjfal ksdjf laksjdf", + ErrCount: 1, + }, + } + + for _, tc := range cases { + _, errors := ApiManagementApiName(tc.Value, "azurerm_api_management_api") + + if len(errors) != tc.ErrCount { + t.Fatalf("Expected the Api Management Api Name to trigger a validation error for '%s'", tc.Value) + } + } +} diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 20c2402749c2..3befb03e7dd6 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -8,6 +8,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/preview/apimanagement/mgmt/2018-06-01-preview/apimanagement" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -23,16 +24,17 @@ func resourceArmApiManagementApi() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - // ValidateFunc: azure.ValidateApiManagementApiName, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validate.ApiManagementApiName, }, "service_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ApiManagementServiceName, }, "resource_group_name": resourceGroupNameSchema(), @@ -40,8 +42,14 @@ func resourceArmApiManagementApi() *schema.Resource { "location": locationSchema(), "path": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ApiManagementApiPath, + }, + + "api_id": { Type: schema.TypeString, - Required: true, + Computed: true, }, "display_name": { @@ -140,15 +148,10 @@ func resourceArmApiManagementApi() *schema.Resource { }, }, - "soap_api_type": { - Type: schema.TypeString, - Default: "", - ValidateFunc: validation.StringInSlice([]string{ - string(apimanagement.HTTP), - string(apimanagement.Soap), - }, true), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - Optional: true, + "soap_pass_through": { + Type: schema.TypeBool, + Default: false, + Optional: true, }, "revision": { @@ -191,6 +194,7 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf //Currently we don't support revisions, so we use 1 as default apiId := fmt.Sprintf("%s;rev=%d", name, 1) + d.Set("api_id", apiId) var properties *apimanagement.APICreateOrUpdateProperties @@ -261,6 +265,7 @@ func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error making Read request on API Management API %q on service %q (Resource Group %q): %+v", apiid, serviceName, resGroup, err) } + d.Set("api_id", apiid) d.Set("name", name) d.Set("resource_group_name", resGroup) d.Set("service_name", serviceName) @@ -270,20 +275,19 @@ func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) e d.Set("service_url", props.ServiceURL) d.Set("path", props.Path) d.Set("description", props.Description) - d.Set("soap_api_type", props.APIType) d.Set("revision", props.APIRevision) d.Set("version", props.APIVersion) d.Set("version_set_id", props.APIVersionSetID) d.Set("is_current", props.IsCurrent) d.Set("is_online", props.IsOnline) d.Set("protocols", props.Protocols) + d.Set("soap_pass_through", string(props.APIType) == string(apimanagement.SoapPassThrough)) if err := d.Set("subscription_key_parameter_names", flattenApiManagementApiSubscriptionKeyParamNames(props.SubscriptionKeyParameterNames)); err != nil { return fmt.Errorf("Error setting `subscription_key_parameter_names`: %+v", err) } } - log.Printf("%+v\n", resp) return nil } @@ -320,11 +324,9 @@ func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.API path := d.Get("path").(string) serviceUrl := d.Get("service_url").(string) description := d.Get("description").(string) - soapApiTypeConfig := d.Get("soap_api_type").(string) - soapApiType := apimanagement.APIType(soapApiTypeConfig) + soapPassThrough := d.Get("soap_pass_through").(bool) - return &apimanagement.APICreateOrUpdateProperties{ - APIType: soapApiType, + props := &apimanagement.APICreateOrUpdateProperties{ Description: &description, DisplayName: &displayName, Path: &path, @@ -332,6 +334,12 @@ func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.API ServiceURL: &serviceUrl, SubscriptionKeyParameterNames: expandApiManagementApiSubscriptionKeyParamNames(d), } + + if soapPassThrough { + props.APIType = apimanagement.APIType(apimanagement.SoapPassThrough) + } + + return props } func expandApiManagementApiSubscriptionKeyParamNames(d *schema.ResourceData) *apimanagement.SubscriptionKeyParameterNamesContract { From 7e60e9e25ee71212e6c1ec71a477664d8e821aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 13:11:49 +0200 Subject: [PATCH 07/38] Updated docs for API Management API resource and data to reflect recent changes --- website/azurerm.erb | 8 +++ .../docs/d/api_management_api.html.markdown | 69 +++++++++++++++++++ .../docs/r/api_management_api.html.markdown | 43 ++++++------ 3 files changed, 97 insertions(+), 23 deletions(-) create mode 100644 website/docs/d/api_management_api.html.markdown diff --git a/website/azurerm.erb b/website/azurerm.erb index acedd3ca1a41..23cd33666c19 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -63,6 +63,10 @@ azurerm_api_management + > + azurerm_api_management_api + + > azurerm_api_management_group @@ -334,6 +338,10 @@ azurerm_api_management + > + azurerm_api_management_api + + > azurerm_api_management_group diff --git a/website/docs/d/api_management_api.html.markdown b/website/docs/d/api_management_api.html.markdown new file mode 100644 index 000000000000..c0387fecff44 --- /dev/null +++ b/website/docs/d/api_management_api.html.markdown @@ -0,0 +1,69 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_api_management_api" +sidebar_current: "docs-azurerm-datasource-api-management_api-x" +description: |- + Gets information about an existing API Management API. +--- + +# Data Source: azurerm_api_management_api + +Use this data source to access information about an existing API Management API. + +## Example Usage + +```hcl +data "azurerm_api_management_api" "test" { + name = "search-api" + service_name = "search-api-management" + resource_group_name = "search-service" +} + +output "api_management_api_id" { + value = "${data.azurerm_api_management_api.test.id}" +} +``` + +## Argument Reference + +* `name` - (Required) The name of the API Management API. + +* `service_name` - (Required) The name of the API Management service which the API Management API belongs to. + +* `resource_group_name` - (Required) The Name of the Resource Group in which the API Management API exists. + +## Attributes Reference + +* `id` - The ID of the API Management API. + +* `display_name` - API name + +* `path` - Relative URL uniquely identifying this API and all of its resource paths within the API Management service instance. It is appended to the API endpoint base URL specified during the service instance creation to form a public URL for this API. The path cannot start or end with `/`. + +* `service_url` - Absolute URL of the backend service implementing this API. + +* `description` - Description of the API. May include HTML formatting tags. + +* `protocols` - Describes on which protocols the operations in this API can be invoked. + +* `subscription_key_parameter_names` - Describes the names of the header and query parameter names used to send in the subscription key. The `subscription_key_parameter_names` block is defined below. + +* `soap_pass_through` - Make API Management expose a SOAP front end, instead of a HTTP front end. + +* `revision` - Describes the Revision of the Api. + +* `version` - Indicates the Version identifier of the API if the API is versioned. + +* `version_set_id` - A resource identifier for the related ApiVersionSet. + +* `is_current` - Indicates if API revision is current api revision. + +* `is_online` - Indicates if API revision is accessible via the gateway. + +--- + +A `subscription_key_parameter_names` block exports the following: + +* `header` - Subscription key header name. Default is `Ocp-Apim-Subscription-Key`. + +* `query` - Subscription key query string parameter name. Default is `subscription-key`. diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index 5a38d551d4d3..716fbd91ab9f 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -23,7 +23,8 @@ resource "azurerm_api_management" "test" { publisher_name = "My Company" publisher_email = "company@terraform.io" sku { - name = "Developer" + name = "Developer" + capacity = 1 } location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" @@ -32,7 +33,7 @@ resource "azurerm_api_management" "test" { resource "azurerm_api_management_api" "test" { name = "conferenceapi" service_name = "${azurerm_api_management.test.name}" - path = "/conference" + path = "conference" import { content_format = "swagger-link-json" content_value = "http://conferenceapi.azurewebsites.net/?format=json" @@ -58,25 +59,27 @@ The following arguments are supported: --- +* `display_name` - (Optional) API name + * `service_url` - (Optional) Absolute URL of the backend service implementing this API. * `description` - (Optional) Description of the API. May include HTML formatting tags. * `protocols` - (Optional) A list of protocols the operations in this API can be invoked. Supported values are `http` and `https`. Default is `https`. -* `revision` - (Optional) The revision number of the API. +* `subscription_key_parameter_names` - (Optional) A `subscription_key` block as documented below. -* `revision_description` - (Optional) Description of current revision. +* `import` - (Optional) A `import` block as documented below. --> **Note:** Setting revision using this resource is supported, but revision are more of a deployment concept than infrastructure, so we recommend finding other means to manage revisions. +* `soap_pass_through` - Make API Management expose a SOAP front end, instead of a HTTP front end. -* `import` - (Optional) A `import` block as documented below. +--- -* `oauth` - (Optional) A `oauth` block as documented below. +A `subscription_key_parameter_names` block exports the following: -* `subscription_key` - (Optional) A `subscription_key` block as documented below. +* `header` - (Optional) Subscription key header name. Default is `Ocp-Apim-Subscription-Key`. -* `soap_api_type` - (Optional) Type of Soap API. Possible values include: 'http' or 'soap'. `http` creates a SOAP to REST API. `soap` creates a SOAP pass-through API. Default behavior when not set is REST API to REST API. +* `query` - (Optional) Subscription key query string parameter name. Default is `subscription-key`. --- @@ -98,27 +101,21 @@ The following arguments are supported: --- -`oauth` block supports the following: - -* `authorization_server_id` - (Required) OAuth authorization server identifier. - -* `scope` - (Required) Operations scope. - ---- +## Attributes Reference -`subscription_key` block supports the following: +In addition to all arguments above, the following attributes are exported: -* `header` - (Optional) Subscription key header name. +* `id` - The ID of the API Management API component. -* `query` - (Optional) Subscription key query string parameter name. +* `revision` - Describes the Revision of the Api. --> **Note:** Set both `header` and `query` to support using subscription key in both, or one of `header` or `query` to support one of them. +* `version` - Indicates the Version identifier of the API if the API is versioned. -## Attributes Reference +* `version_set_id` - A resource identifier for the related ApiVersionSet. -The following attributes are exported: +* `is_current` - Indicates if API revision is current api revision. -* `id` - The ID of the API Management API component. +* `is_online` - Indicates if API revision is accessible via the gateway. ## Import From 8ccd016bda2543cd8b0d69ba5f621eaf1275a1d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 13:23:40 +0200 Subject: [PATCH 08/38] Fixed sidebar issues in doc --- website/azurerm.erb | 2 +- website/docs/d/api_management_api.html.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/azurerm.erb b/website/azurerm.erb index 23cd33666c19..22128d776626 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -63,7 +63,7 @@ azurerm_api_management - > + > azurerm_api_management_api diff --git a/website/docs/d/api_management_api.html.markdown b/website/docs/d/api_management_api.html.markdown index c0387fecff44..817d9b617ce2 100644 --- a/website/docs/d/api_management_api.html.markdown +++ b/website/docs/d/api_management_api.html.markdown @@ -1,7 +1,7 @@ --- layout: "azurerm" page_title: "Azure Resource Manager: azurerm_api_management_api" -sidebar_current: "docs-azurerm-datasource-api-management_api-x" +sidebar_current: "docs-azurerm-datasource-azurerm-api-management-api-x" description: |- Gets information about an existing API Management API. --- From 4b2f6bff07872ce15dd82ce97c84e556b734ddbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 16:05:13 +0200 Subject: [PATCH 09/38] Removed display_name option - name works for both --- azurerm/data_source_api_management_api.go | 8 +------- azurerm/resource_arm_api_management_api.go | 9 ++------- website/docs/d/api_management_api.html.markdown | 2 -- website/docs/r/api_management_api.html.markdown | 2 -- 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index 3253202da1fd..9c5330703a33 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -27,11 +27,6 @@ func dataSourceApiManagementApi() *schema.Resource { "location": locationForDataSourceSchema(), - "display_name": { - Type: schema.TypeString, - Computed: true, - }, - "path": { Type: schema.TypeString, Computed: true, @@ -129,12 +124,11 @@ func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) er d.SetId(*resp.ID) - d.Set("name", apiId) + d.Set("name", name) d.Set("service_name", serviceName) d.Set("resource_group_name", resGroup) if props := resp.APIContractProperties; props != nil { - d.Set("display_name", props.DisplayName) d.Set("service_url", props.ServiceURL) d.Set("path", props.Path) d.Set("description", props.Description) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 3befb03e7dd6..bf939b2a1f07 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -25,7 +25,7 @@ func resourceArmApiManagementApi() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, - Optional: true, + Required: true, ForceNew: true, ValidateFunc: validate.ApiManagementApiName, }, @@ -52,11 +52,6 @@ func resourceArmApiManagementApi() *schema.Resource { Computed: true, }, - "display_name": { - Type: schema.TypeString, - Optional: true, - }, - "service_url": { Type: schema.TypeString, Optional: true, @@ -320,7 +315,7 @@ func resourceArmApiManagementApiDelete(d *schema.ResourceData, meta interface{}) } func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { - displayName := d.Get("display_name").(string) + displayName := d.Get("name").(string) path := d.Get("path").(string) serviceUrl := d.Get("service_url").(string) description := d.Get("description").(string) diff --git a/website/docs/d/api_management_api.html.markdown b/website/docs/d/api_management_api.html.markdown index 817d9b617ce2..92781e71bd29 100644 --- a/website/docs/d/api_management_api.html.markdown +++ b/website/docs/d/api_management_api.html.markdown @@ -36,8 +36,6 @@ output "api_management_api_id" { * `id` - The ID of the API Management API. -* `display_name` - API name - * `path` - Relative URL uniquely identifying this API and all of its resource paths within the API Management service instance. It is appended to the API endpoint base URL specified during the service instance creation to form a public URL for this API. The path cannot start or end with `/`. * `service_url` - Absolute URL of the backend service implementing this API. diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index 716fbd91ab9f..3b7d37de93c2 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -59,8 +59,6 @@ The following arguments are supported: --- -* `display_name` - (Optional) API name - * `service_url` - (Optional) Absolute URL of the backend service implementing this API. * `description` - (Optional) Description of the API. May include HTML formatting tags. From e9de296234ea44341d579a696088831943186b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 16:05:53 +0200 Subject: [PATCH 10/38] Add simple test for data source --- .../data_source_api_management_api_test.go | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 azurerm/data_source_api_management_api_test.go diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go new file mode 100644 index 000000000000..c7cfd7f88a8c --- /dev/null +++ b/azurerm/data_source_api_management_api_test.go @@ -0,0 +1,73 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccDataSourceAzureRMApiManagementApi_basic(t *testing.T) { + dataSourceName := "data.azurerm_api_management_api.test" + rInt := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceApiManagementApi_basic(rInt, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "revision", "1"), + resource.TestCheckResourceAttr(dataSourceName, "is_current", "true"), + resource.TestCheckResourceAttr(dataSourceName, "path", "api1"), + ), + }, + }, + }) +} + +func testAccDataSourceApiManagementApi_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "amtestRG-%d" + location = "%s" +} + +resource "azurerm_api_management" "test" { + name = "acctestAM-%d" + publisher_name = "pub1" + publisher_email = "pub1@email.com" + + sku { + name = "Developer" + capacity = 1 + } + + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_api_management_api" "test" { + name = "acctestAMA-%d" + service_name = "${azurerm_api_management.test.name}" + path = "api1" + + import { + content_value = "https://api.swaggerhub.com/apis/sparebanken-vest/tf-simple/1.0.2" + content_format = "swagger-link-json" + } + + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +data "azurerm_api_management_api" "test" { + name = "${azurerm_api_management_api.test.name}" + service_name = "${azurerm_api_management.test.name}" + resource_group_name = "${azurerm_api_management_api.test.resource_group_name}" +} +`, rInt, location, rInt, rInt) +} From 3c8b3341138516c4b82f35cfee6cedc993686fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 16:20:13 +0200 Subject: [PATCH 11/38] Add simple test for API Management API --- .../data_source_api_management_api_test.go | 2 +- .../resource_arm_api_management_api_test.go | 134 ++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 azurerm/resource_arm_api_management_api_test.go diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index c7cfd7f88a8c..9dd2d70c0b0f 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -56,7 +56,7 @@ resource "azurerm_api_management_api" "test" { path = "api1" import { - content_value = "https://api.swaggerhub.com/apis/sparebanken-vest/tf-simple/1.0.2" + content_value = "https://api.swaggerhub.com/apis/sparebanken-vest/tf-simple/1.0.2" content_format = "swagger-link-json" } diff --git a/azurerm/resource_arm_api_management_api_test.go b/azurerm/resource_arm_api_management_api_test.go new file mode 100644 index 000000000000..dad51b84d28d --- /dev/null +++ b/azurerm/resource_arm_api_management_api_test.go @@ -0,0 +1,134 @@ +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 TestAccAzureRMApiManagementApi_basic(t *testing.T) { + resourceName := "azurerm_api_management_api.test" + ri := acctest.RandInt() + config := testAccAzureRMApiManagementApi_basic(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testCheckAzureRMApiManagementApiDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*ArmClient).apiManagementApiClient + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_api_management_api" { + continue + } + + name := rs.Primary.Attributes["name"] + serviceName := rs.Primary.Attributes["service_name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + ctx := testAccProvider.Meta().(*ArmClient).StopContext + apiId := fmt.Sprintf("%s;rev=%d", name, 1) + + resp, err := conn.Get(ctx, resourceGroup, serviceName, apiId) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + + return err + } + + return nil + } + + return nil +} + +func testCheckAzureRMApiManagementApiExists(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) + } + + name := rs.Primary.Attributes["name"] + serviceName := rs.Primary.Attributes["service_name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for API Management API: %s", name) + } + + conn := testAccProvider.Meta().(*ArmClient).apiManagementApiClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + apiId := fmt.Sprintf("%s;rev=%d", name, 1) + resp, err := conn.Get(ctx, resourceGroup, serviceName, apiId) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: API Management API %q (resource group: %q) does not exist", name, resourceGroup) + } + + return fmt.Errorf("Bad: Get on apiManagementClient: %+v", err) + } + + return nil + } +} + +func testAccAzureRMApiManagementApi_basic(rInt int, location string) string { + return fmt.Sprintf(` +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 = "Developer" + capacity = 1 + } +} + +resource "azurerm_api_management_api" "test" { + name = "acctestAMA-%d" + service_name = "${azurerm_api_management.test.name}" + path = "api1" + + import { + content_value = "https://api.swaggerhub.com/apis/sparebanken-vest/tf-simple/1.0.2" + content_format = "swagger-link-json" + } + + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, rInt, location, rInt, rInt) +} From 046e7f35df29ee92f63ab8f86ef1546d93327d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 16:47:27 +0200 Subject: [PATCH 12/38] Testing: * Fixed basic data test and include more props to check * Replaced test data with files instead of pointing to urls * Add complete test for API Management API --- .../data_source_api_management_api_test.go | 16 +- .../resource_arm_api_management_api_test.go | 79 +++++++- .../testdata/api_management_api_swagger.json | 168 ++++++++++++++++++ azurerm/testdata/api_management_api_wsdl.xml | 91 ++++++++++ 4 files changed, 351 insertions(+), 3 deletions(-) create mode 100644 azurerm/testdata/api_management_api_swagger.json create mode 100644 azurerm/testdata/api_management_api_wsdl.xml diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index 9dd2d70c0b0f..816cf7940ae5 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -20,9 +20,23 @@ func TestAccDataSourceAzureRMApiManagementApi_basic(t *testing.T) { { Config: testAccDataSourceApiManagementApi_basic(rInt, location), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(dataSourceName, "revision", "1"), + resource.TestCheckResourceAttr(dataSourceName, "api_id", "api1"), + resource.TestCheckResourceAttr(dataSourceName, "import.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "import.0.content_format", "swagger-json"), + resource.TestCheckResourceAttr(dataSourceName, "import.0.wsdl_selector.#", "0"), resource.TestCheckResourceAttr(dataSourceName, "is_current", "true"), + resource.TestCheckResourceAttr(dataSourceName, "is_online", "false"), + resource.TestCheckResourceAttr(dataSourceName, "name", "api1"), resource.TestCheckResourceAttr(dataSourceName, "path", "api1"), + resource.TestCheckResourceAttr(dataSourceName, "protocols.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "protocols.0", "https"), + resource.TestCheckResourceAttr(dataSourceName, "service_name", fmt.Sprintf("acctestAM-%d", rInt)), + resource.TestCheckResourceAttr(dataSourceName, "soap_pass_through", "false"), + resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.0.header", "Ocp-Apim-Subscription-Key"), + resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.0.query", "subscription-key"), + resource.TestCheckResourceAttr(dataSourceName, "version", ""), + resource.TestCheckResourceAttr(dataSourceName, "version_set_id", ""), ), }, }, diff --git a/azurerm/resource_arm_api_management_api_test.go b/azurerm/resource_arm_api_management_api_test.go index dad51b84d28d..b8db2494400f 100644 --- a/azurerm/resource_arm_api_management_api_test.go +++ b/azurerm/resource_arm_api_management_api_test.go @@ -35,6 +35,31 @@ func TestAccAzureRMApiManagementApi_basic(t *testing.T) { }) } +func TestAccAzureRMApiManagementApi_complete(t *testing.T) { + resourceName := "azurerm_api_management_api.test" + ri := acctest.RandInt() + config := testAccAzureRMApiManagementApi_complete(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testCheckAzureRMApiManagementApiDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*ArmClient).apiManagementApiClient @@ -123,8 +148,8 @@ resource "azurerm_api_management_api" "test" { path = "api1" import { - content_value = "https://api.swaggerhub.com/apis/sparebanken-vest/tf-simple/1.0.2" - content_format = "swagger-link-json" + content_value = "${file("testdata/api_management_api_swagger.json")}" + content_format = "swagger-json" } location = "${azurerm_resource_group.test.location}" @@ -132,3 +157,53 @@ resource "azurerm_api_management_api" "test" { } `, rInt, location, rInt, rInt) } + +func testAccAzureRMApiManagementApi_complete(rInt int, location string) string { + return fmt.Sprintf(` +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 = "Developer" + capacity = 1 + } +} + +resource "azurerm_api_management_api" "test" { + name = "acctestAMA-%d" + service_name = "${azurerm_api_management.test.name}" + path = "api1" + + import { + content_value = "${file("testdata/api_management_api_wsdl.xml")}" + content_format = "wsdl" + + wsdl_selector { + service_name = "Calculator" + endpoint_name = "CalculatorHttpsSoap11Endpoint" + } + } + + soap_pass_through = true + + subscription_key_parameter_names { + header = "test1" + query = "test2" + } + + protocols = ["http", "https"] + + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, rInt, location, rInt, rInt) +} diff --git a/azurerm/testdata/api_management_api_swagger.json b/azurerm/testdata/api_management_api_swagger.json new file mode 100644 index 000000000000..6a44e5a5b33d --- /dev/null +++ b/azurerm/testdata/api_management_api_swagger.json @@ -0,0 +1,168 @@ +{ + "swagger": "2.0", + "info": { + "description": "This is a simple API", + "version": "1.0.2", + "title": "tftest2", + "contact": { + "email": "you@your-company.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "tags": [ + { + "name": "admins", + "description": "Secured Admin-only calls" + }, + { + "name": "developers", + "description": "Operations available to regular developers" + } + ], + "paths": { + "/inventory": { + "get": { + "tags": [ + "developers" + ], + "summary": "searches inventory", + "operationId": "searchInventory", + "description": "By passing in the appropriate options, you can search for\navailable inventory in the system\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "in": "query", + "name": "searchString", + "description": "pass an optional search string for looking up inventory", + "required": false, + "type": "string" + }, + { + "in": "query", + "name": "skip", + "description": "number of records to skip for pagination", + "type": "integer", + "format": "int32", + "minimum": 0 + }, + { + "in": "query", + "name": "limit", + "description": "maximum number of records to return", + "type": "integer", + "format": "int32", + "minimum": 0, + "maximum": 50 + } + ], + "responses": { + "200": { + "description": "search results matching criteria", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/InventoryItem" + } + } + }, + "400": { + "description": "bad input parameter" + } + } + }, + "post": { + "tags": [ + "admins" + ], + "summary": "adds an inventory item", + "operationId": "addInventory", + "description": "Adds an item to the system", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "inventoryItem", + "description": "Inventory item to add", + "schema": { + "$ref": "#/definitions/InventoryItem" + } + } + ], + "responses": { + "201": { + "description": "item created" + }, + "400": { + "description": "invalid input, object invalid" + }, + "409": { + "description": "an existing item already exists" + } + } + } + } + }, + "definitions": { + "InventoryItem": { + "type": "object", + "required": [ + "id", + "name", + "manufacturer", + "releaseDate" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "example": "d290f1ee-6c54-4b01-90e6-d701748f0851" + }, + "name": { + "type": "string", + "example": "Widget Adapter" + }, + "releaseDate": { + "type": "string", + "format": "int32", + "example": "2016-08-29T09:12:33.001Z" + }, + "manufacturer": { + "$ref": "#/definitions/Manufacturer" + } + } + }, + "Manufacturer": { + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "example": "ACME Corporation" + }, + "homePage": { + "type": "string", + "format": "url", + "example": "https://www.acme-corp.com" + }, + "phone": { + "type": "string", + "example": "408-867-5309" + } + } + } + }, + "schemes": [ + "https" + ] +} diff --git a/azurerm/testdata/api_management_api_wsdl.xml b/azurerm/testdata/api_management_api_wsdl.xml new file mode 100644 index 000000000000..4bbf8a7d2774 --- /dev/null +++ b/azurerm/testdata/api_management_api_wsdl.xml @@ -0,0 +1,91 @@ + + + Calculator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 93cd651d73aca4517d87b6dc0b2f1b44f42221b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 22:07:31 +0200 Subject: [PATCH 13/38] Fixed error found in integration tests: * Ignore import, since state is only persisted in Terraform * Removed location from schema * Add seperate get after creating resource to get ID --- azurerm/data_source_api_management_api_test.go | 5 ----- azurerm/resource_arm_api_management_api.go | 17 ++++++++++++----- .../resource_arm_api_management_api_test.go | 18 ++++++++++++++++-- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index 816cf7940ae5..8761a1e82bee 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -20,10 +20,6 @@ func TestAccDataSourceAzureRMApiManagementApi_basic(t *testing.T) { { Config: testAccDataSourceApiManagementApi_basic(rInt, location), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(dataSourceName, "api_id", "api1"), - resource.TestCheckResourceAttr(dataSourceName, "import.#", "1"), - resource.TestCheckResourceAttr(dataSourceName, "import.0.content_format", "swagger-json"), - resource.TestCheckResourceAttr(dataSourceName, "import.0.wsdl_selector.#", "0"), resource.TestCheckResourceAttr(dataSourceName, "is_current", "true"), resource.TestCheckResourceAttr(dataSourceName, "is_online", "false"), resource.TestCheckResourceAttr(dataSourceName, "name", "api1"), @@ -74,7 +70,6 @@ resource "azurerm_api_management_api" "test" { content_format = "swagger-link-json" } - location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" } diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index bf939b2a1f07..b4033ddcc4de 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -39,8 +39,6 @@ func resourceArmApiManagementApi() *schema.Resource { "resource_group_name": resourceGroupNameSchema(), - "location": locationSchema(), - "path": { Type: schema.TypeString, Required: true, @@ -208,9 +206,9 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf } log.Printf("[DEBUG] Calling api with resource group %q, service name %q, api id %q", resGroup, serviceName, apiId) - apiContract, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, apiParams, "") + _, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, apiParams, "") if err != nil { - return err + return fmt.Errorf("Error creating/updating API Management API %q (Resource Group %q): %+v", name, resGroup, err) } if hasImport { @@ -226,7 +224,16 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf } } - d.SetId(*apiContract.ID) + read, err := client.Get(ctx, resGroup, serviceName, apiId) + if err != nil { + return fmt.Errorf("Error retrieving API Management API %q (Resource Group %q): %+v", name, resGroup, err) + } + + if read.ID == nil { + return fmt.Errorf("Cannot read ID for API Management API %q (Resource Group %q)", name, resGroup) + } + + d.SetId(*read.ID) return resourceArmApiManagementApiRead(d, meta) } diff --git a/azurerm/resource_arm_api_management_api_test.go b/azurerm/resource_arm_api_management_api_test.go index b8db2494400f..98839a05d83f 100644 --- a/azurerm/resource_arm_api_management_api_test.go +++ b/azurerm/resource_arm_api_management_api_test.go @@ -30,6 +30,13 @@ func TestAccAzureRMApiManagementApi_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + // Ignore state that is only persisted in Terraform and not on Azure side + ImportStateVerifyIgnore: []string{ + "import.#", + "import.0.content_format", + "import.0.content_value", + "import.0.wsdl_selector.#", + }, }, }, }) @@ -55,6 +62,15 @@ func TestAccAzureRMApiManagementApi_complete(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + // Ignore state that is only persisted in Terraform and not on Azure side + ImportStateVerifyIgnore: []string{ + "import.#", + "import.0.content_format", + "import.0.content_value", + "import.0.wsdl_selector.#", + "import.0.wsdl_selector.0.service_name", + "import.0.wsdl_selector.0.endpoint_name", + }, }, }, }) @@ -152,7 +168,6 @@ resource "azurerm_api_management_api" "test" { content_format = "swagger-json" } - location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" } `, rInt, location, rInt, rInt) @@ -202,7 +217,6 @@ resource "azurerm_api_management_api" "test" { protocols = ["http", "https"] - location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" } `, rInt, location, rInt, rInt) From b3857dc38819657e9f4f1880597fa5904147726a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Sat, 13 Oct 2018 23:53:24 +0200 Subject: [PATCH 14/38] Check for generated name in test. Use local swagger file instead of url. --- azurerm/data_source_api_management_api_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index 8761a1e82bee..d31f269af116 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -22,7 +22,7 @@ func TestAccDataSourceAzureRMApiManagementApi_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(dataSourceName, "is_current", "true"), resource.TestCheckResourceAttr(dataSourceName, "is_online", "false"), - resource.TestCheckResourceAttr(dataSourceName, "name", "api1"), + resource.TestCheckResourceAttr(dataSourceName, "name", fmt.Sprintf("acctestAMA-%d", rInt)), resource.TestCheckResourceAttr(dataSourceName, "path", "api1"), resource.TestCheckResourceAttr(dataSourceName, "protocols.#", "1"), resource.TestCheckResourceAttr(dataSourceName, "protocols.0", "https"), @@ -66,8 +66,8 @@ resource "azurerm_api_management_api" "test" { path = "api1" import { - content_value = "https://api.swaggerhub.com/apis/sparebanken-vest/tf-simple/1.0.2" - content_format = "swagger-link-json" + content_value = "${file("testdata/api_management_api_swagger.json")}" + content_format = "swagger-json" } resource_group_name = "${azurerm_resource_group.test.name}" From faba325d573e43f6785474cfe25bda0a38c96055 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Tue, 23 Oct 2018 14:15:12 +0200 Subject: [PATCH 15/38] Output APIM Service name on error Co-Authored-By: torresdal --- azurerm/data_source_api_management_api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index 9c5330703a33..a45d7c4d79fc 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -116,7 +116,7 @@ func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) er if err != nil { if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("API Management API %q (Resource Group %q) was not found", name, resGroup) + return fmt.Errorf("API Management API %q (Service %q / Resource Group %q) was not found", name, serviceName, resGroup) } return fmt.Errorf("Error retrieving API Management API %q (Resource Group %q): %+v", name, resGroup, err) From 2f4992a6105ff6d1226baefcee15407b4a50ed65 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Tue, 23 Oct 2018 14:15:38 +0200 Subject: [PATCH 16/38] Output APIM Service name on error Co-Authored-By: torresdal --- azurerm/data_source_api_management_api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index a45d7c4d79fc..a6483378101a 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -119,7 +119,7 @@ func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("API Management API %q (Service %q / Resource Group %q) was not found", name, serviceName, resGroup) } - return fmt.Errorf("Error retrieving API Management API %q (Resource Group %q): %+v", name, resGroup, err) + return fmt.Errorf("Error retrieving API Management API %q (Service %q / Resource Group %q): %+v", name, serviceName, resGroup, err) } d.SetId(*resp.ID) From 7f0d5f20b76e25fb42d24f7e8f19712fc8dc2631 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Tue, 23 Oct 2018 14:18:46 +0200 Subject: [PATCH 17/38] Added debug line when APIM API does not exist Co-Authored-By: torresdal --- azurerm/resource_arm_api_management_api.go | 1 + 1 file changed, 1 insertion(+) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index b4033ddcc4de..530d6bab05ca 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -261,6 +261,7 @@ func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) e if err != nil { if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] API Management API %q (Service %q / Resource Group %q) does not exist - removing from state!", name, serviceName, resGroup) d.SetId("") return nil } From d1c50e92c81b9bbc5a2147bc1d1b9977ed8fba76 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Tue, 23 Oct 2018 14:20:33 +0200 Subject: [PATCH 18/38] Grammar improvement Co-Authored-By: torresdal --- website/docs/r/api_management_api.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index 3b7d37de93c2..458db5bd5f60 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -91,7 +91,7 @@ A `subscription_key_parameter_names` block exports the following: --- -`wsdl_selector` block supports the following: +A `wsdl_selector` block supports the following: * `service_name` - (Required) Name of service to import from WSDL. From 2ca63a59b99f33ac8888d763acbcaad20fb9d984 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Tue, 23 Oct 2018 14:20:53 +0200 Subject: [PATCH 19/38] Grammar improvement Co-Authored-By: torresdal --- website/docs/r/api_management_api.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index 458db5bd5f60..b69efe506f2e 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -81,7 +81,7 @@ A `subscription_key_parameter_names` block exports the following: --- -`import` block supports the following: +A `import` block supports the following: * `content_format` - (Required) Format of the Content in which the API is getting imported. Possible values include: 'swagger-json', 'swagger-link-json', 'wadl-link-json', 'wadl-xml', 'wsdl', 'wsdl-link'. From 530929a00fd0bd63a33c1d2eeb1fa5f0c0fd03e3 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Tue, 23 Oct 2018 14:21:04 +0200 Subject: [PATCH 20/38] Grammar improvement Co-Authored-By: torresdal --- website/docs/r/api_management_api.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index b69efe506f2e..91e05ab3edcb 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -73,7 +73,7 @@ The following arguments are supported: --- -A `subscription_key_parameter_names` block exports the following: +A `subscription_key_parameter_names` block supports the following: * `header` - (Optional) Subscription key header name. Default is `Ocp-Apim-Subscription-Key`. From 4134a352b8726a228004edefd2ce98d3a8ff4974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Thu, 25 Oct 2018 11:34:15 +0200 Subject: [PATCH 21/38] Fixed and made changes according to review --- azurerm/data_source_api_management_api.go | 14 ++- .../data_source_api_management_api_test.go | 12 +- azurerm/resource_arm_api_management_api.go | 107 ++++++++++-------- .../resource_arm_api_management_api_test.go | 44 +++---- azurerm/testdata/api_management_api_wsdl.xml | 6 +- .../docs/d/api_management_api.html.markdown | 8 +- .../docs/r/api_management_api.html.markdown | 13 +-- 7 files changed, 101 insertions(+), 103 deletions(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index a6483378101a..25037b35565d 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -75,15 +75,17 @@ func dataSourceApiManagementApi() *schema.Resource { "revision": { Type: schema.TypeInt, + Optional: true, + Default: 1, Computed: true, }, - "version": { + "api_version": { Type: schema.TypeString, Computed: true, }, - "version_set_id": { + "api_version_set_id": { Type: schema.TypeString, Computed: true, }, @@ -108,9 +110,9 @@ func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) er resGroup := d.Get("resource_group_name").(string) serviceName := d.Get("service_name").(string) name := d.Get("name").(string) + revision := int32(d.Get("revision").(int)) - //Currently we don't support revisions, so we use 1 as default - apiId := fmt.Sprintf("%s;rev=%d", name, 1) + apiId := fmt.Sprintf("%s;rev=%d", name, revision) resp, err := client.Get(ctx, resGroup, serviceName, apiId) @@ -133,8 +135,8 @@ func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) er d.Set("path", props.Path) d.Set("description", props.Description) d.Set("revision", props.APIRevision) - d.Set("version", props.APIVersion) - d.Set("version_set_id", props.APIVersionSetID) + d.Set("api_version", props.APIVersion) + d.Set("api_version_set_id", props.APIVersionSetID) d.Set("is_current", props.IsCurrent) d.Set("is_online", props.IsOnline) d.Set("protocols", props.Protocols) diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index d31f269af116..2c8257adfad0 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -61,12 +61,12 @@ resource "azurerm_api_management" "test" { } resource "azurerm_api_management_api" "test" { - name = "acctestAMA-%d" - service_name = "${azurerm_api_management.test.name}" - path = "api1" + name = "acctestAMA-%d" + service_name = "${azurerm_api_management.test.name}" + path = "api1" - import { - content_value = "${file("testdata/api_management_api_swagger.json")}" + import { + content_value = "${file("testdata/api_management_api_swagger.json")}" content_format = "swagger-json" } @@ -75,7 +75,7 @@ resource "azurerm_api_management_api" "test" { data "azurerm_api_management_api" "test" { name = "${azurerm_api_management_api.test.name}" - service_name = "${azurerm_api_management.test.name}" + service_name = "${azurerm_api_management.test.name}" resource_group_name = "${azurerm_api_management_api.test.resource_group_name}" } `, rInt, location, rInt, rInt) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 530d6bab05ca..23a19e20b40b 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -45,6 +45,18 @@ func resourceArmApiManagementApi() *schema.Resource { ValidateFunc: validate.ApiManagementApiPath, }, + "protocols": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.ProtocolHTTP), + string(apimanagement.ProtocolHTTPS), + }, false), + }, + Required: true, + }, + "api_id": { Type: schema.TypeString, Computed: true, @@ -80,8 +92,7 @@ func resourceArmApiManagementApi() *schema.Resource { string(apimanagement.WadlXML), string(apimanagement.Wsdl), string(apimanagement.WsdlLink), - }, true), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, false), }, "wsdl_selector": { @@ -106,20 +117,6 @@ func resourceArmApiManagementApi() *schema.Resource { }, }, - "protocols": { - Type: schema.TypeList, - Elem: &schema.Schema{ - Type: schema.TypeString, - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - ValidateFunc: validation.StringInSlice([]string{ - string(apimanagement.ProtocolHTTP), - string(apimanagement.ProtocolHTTPS), - }, true), - }, - Optional: true, - Computed: true, // Azure API sets protocols to https by default - }, - "subscription_key_parameter_names": { Type: schema.TypeList, Optional: true, @@ -149,7 +146,8 @@ func resourceArmApiManagementApi() *schema.Resource { "revision": { Type: schema.TypeInt, - Computed: true, + Optional: true, + Default: 1, }, "version": { @@ -184,9 +182,9 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf resGroup := d.Get("resource_group_name").(string) serviceName := d.Get("service_name").(string) name := d.Get("name").(string) + revision := int32(d.Get("revision").(int)) - //Currently we don't support revisions, so we use 1 as default - apiId := fmt.Sprintf("%s;rev=%d", name, 1) + apiId := fmt.Sprintf("%s;rev=%d", name, revision) d.Set("api_id", apiId) var properties *apimanagement.APICreateOrUpdateProperties @@ -327,7 +325,6 @@ func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.API path := d.Get("path").(string) serviceUrl := d.Get("service_url").(string) description := d.Get("description").(string) - soapPassThrough := d.Get("soap_pass_through").(bool) props := &apimanagement.APICreateOrUpdateProperties{ Description: &description, @@ -338,31 +335,43 @@ func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.API SubscriptionKeyParameterNames: expandApiManagementApiSubscriptionKeyParamNames(d), } - if soapPassThrough { - props.APIType = apimanagement.APIType(apimanagement.SoapPassThrough) + if v, ok := d.GetOk("soap_pass_through"); ok { + soapPassThrough := v.(bool) + + if soapPassThrough { + props.APIType = apimanagement.APIType(apimanagement.SoapPassThrough) + } else { + props.APIType = apimanagement.APIType(apimanagement.SoapToRest) + } } return props } func expandApiManagementApiSubscriptionKeyParamNames(d *schema.ResourceData) *apimanagement.SubscriptionKeyParameterNamesContract { - var contract apimanagement.SubscriptionKeyParameterNamesContract + vs := d.Get("subscription_key_parameter_names").([]interface{}) - if v, ok := d.GetOk("subscription_key_parameter_names.0.header"); ok { - header := v.(string) - contract.Header = &header - } + if len(vs) > 0 { + v := vs[0].(map[string]interface{}) + contract := apimanagement.SubscriptionKeyParameterNamesContract{} - if v, ok := d.GetOk("subscription_key_parameter_names.0.query"); ok { - query := v.(string) - contract.Query = &query - } + query := v["query"].(string) + header := v["header"].(string) + + if query != "" { + contract.Query = utils.String(query) + } + + if header != "" { + contract.Header = utils.String(header) + } - if contract.Header == nil && contract.Query == nil { - return nil + if query != "" || header != "" { + return &contract + } } - return &contract + return nil } func expandApiManagementApiProtocols(d *schema.ResourceData) *[]apimanagement.Protocol { @@ -388,27 +397,25 @@ func expandApiManagementImportProperties(d *schema.ResourceData) *apimanagement. Path: &path, } - if v, ok := d.GetOk("import.0.content_format"); ok { - props.ContentFormat = apimanagement.ContentFormat(v.(string)) - } + importVs := d.Get("import").([]interface{}) + importV := importVs[0].(map[string]interface{}) - if v, ok := d.GetOk("import.0.content_value"); ok { - content_val := v.(string) - props.ContentValue = &content_val - } + props.ContentFormat = apimanagement.ContentFormat(importV["content_format"].(string)) - if _, selectorUsed := d.GetOk("import.0.wsdl_selector"); selectorUsed { + cVal := importV["content_value"].(string) + props.ContentValue = &cVal + + wsdlSelectorVs := importV["wsdl_selector"].([]interface{}) + + if len(wsdlSelectorVs) > 0 { + wsdlSelectorV := wsdlSelectorVs[0].(map[string]interface{}) props.WsdlSelector = &apimanagement.APICreateOrUpdatePropertiesWsdlSelector{} - if v, ok := d.GetOk("import.0.wsdl_selector.0.service_name"); ok { - serviceName := v.(string) - props.WsdlSelector.WsdlServiceName = &serviceName - } + wSvcName := wsdlSelectorV["service_name"].(string) + wEndpName := wsdlSelectorV["endpoint_name"].(string) - if v, ok := d.GetOk("import.0.wsdl_selector.0.endpoint_name"); ok { - endpointName := v.(string) - props.WsdlSelector.WsdlEndpointName = &endpointName - } + props.WsdlSelector.WsdlServiceName = &wSvcName + props.WsdlSelector.WsdlEndpointName = &wEndpName } return props diff --git a/azurerm/resource_arm_api_management_api_test.go b/azurerm/resource_arm_api_management_api_test.go index 98839a05d83f..c52d4bbc8337 100644 --- a/azurerm/resource_arm_api_management_api_test.go +++ b/azurerm/resource_arm_api_management_api_test.go @@ -32,10 +32,7 @@ func TestAccAzureRMApiManagementApi_basic(t *testing.T) { ImportStateVerify: true, // Ignore state that is only persisted in Terraform and not on Azure side ImportStateVerifyIgnore: []string{ - "import.#", - "import.0.content_format", - "import.0.content_value", - "import.0.wsdl_selector.#", + "import", }, }, }, @@ -64,12 +61,7 @@ func TestAccAzureRMApiManagementApi_complete(t *testing.T) { ImportStateVerify: true, // Ignore state that is only persisted in Terraform and not on Azure side ImportStateVerifyIgnore: []string{ - "import.#", - "import.0.content_format", - "import.0.content_value", - "import.0.wsdl_selector.#", - "import.0.wsdl_selector.0.service_name", - "import.0.wsdl_selector.0.endpoint_name", + "import", }, }, }, @@ -124,7 +116,7 @@ func testCheckAzureRMApiManagementApiExists(name string) resource.TestCheckFunc conn := testAccProvider.Meta().(*ArmClient).apiManagementApiClient ctx := testAccProvider.Meta().(*ArmClient).StopContext - apiId := fmt.Sprintf("%s;rev=%d", name, 1) + apiId := fmt.Sprintf("%s;rev=%s", name, rs.Primary.Attributes["revision"]) resp, err := conn.Get(ctx, resourceGroup, serviceName, apiId) if err != nil { if utils.ResponseWasNotFound(resp.Response) { @@ -159,11 +151,11 @@ resource "azurerm_api_management" "test" { } resource "azurerm_api_management_api" "test" { - name = "acctestAMA-%d" - service_name = "${azurerm_api_management.test.name}" - path = "api1" + name = "acctestAMA-%d" + service_name = "${azurerm_api_management.test.name}" + path = "api1" - import { + import { content_value = "${file("testdata/api_management_api_swagger.json")}" content_format = "swagger-json" } @@ -194,12 +186,12 @@ resource "azurerm_api_management" "test" { } resource "azurerm_api_management_api" "test" { - name = "acctestAMA-%d" - service_name = "${azurerm_api_management.test.name}" - path = "api1" + name = "acctestAMA-%d" + service_name = "${azurerm_api_management.test.name}" + path = "api1" - import { - content_value = "${file("testdata/api_management_api_wsdl.xml")}" + import { + content_value = "${file("testdata/api_management_api_wsdl.xml")}" content_format = "wsdl" wsdl_selector { @@ -208,14 +200,14 @@ resource "azurerm_api_management_api" "test" { } } - soap_pass_through = true + soap_pass_through = true - subscription_key_parameter_names { - header = "test1" - query = "test2" - } + subscription_key_parameter_names { + header = "test1" + query = "test2" + } - protocols = ["http", "https"] + protocols = ["http", "https"] resource_group_name = "${azurerm_resource_group.test.name}" } diff --git a/azurerm/testdata/api_management_api_wsdl.xml b/azurerm/testdata/api_management_api_wsdl.xml index 4bbf8a7d2774..f4afcba1c641 100644 --- a/azurerm/testdata/api_management_api_wsdl.xml +++ b/azurerm/testdata/api_management_api_wsdl.xml @@ -70,7 +70,7 @@ - + @@ -79,10 +79,10 @@ - + - + diff --git a/website/docs/d/api_management_api.html.markdown b/website/docs/d/api_management_api.html.markdown index 92781e71bd29..694234bcf5d8 100644 --- a/website/docs/d/api_management_api.html.markdown +++ b/website/docs/d/api_management_api.html.markdown @@ -54,14 +54,14 @@ output "api_management_api_id" { * `version_set_id` - A resource identifier for the related ApiVersionSet. -* `is_current` - Indicates if API revision is current api revision. +* `is_current` - Indicates if the API revision is current api revision. -* `is_online` - Indicates if API revision is accessible via the gateway. +* `is_online` - Indicates if the API revision is accessible via the gateway. --- A `subscription_key_parameter_names` block exports the following: -* `header` - Subscription key header name. Default is `Ocp-Apim-Subscription-Key`. +* `header` - Subscription key header name. -* `query` - Subscription key query string parameter name. Default is `subscription-key`. +* `query` - Subscription key query string parameter name. diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index 91e05ab3edcb..c35ab49b3d1b 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -38,7 +38,6 @@ resource "azurerm_api_management_api" "test" { content_format = "swagger-link-json" content_value = "http://conferenceapi.azurewebsites.net/?format=json" } - location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" } ``` @@ -47,13 +46,11 @@ resource "azurerm_api_management_api" "test" { The following arguments are supported: -* `name` - (Required) The name of the API Management API. - -* `resource_group_name` - (Required) The Name of the Resource Group where the API Management API exists. +* `name` - (Required) The name of the API Management API. Changing this forces a new resource to be created. -* `location` - (Required) The Azure location where the API Management API exists. +* `resource_group_name` - (Required) The Name of the Resource Group where the API Management API exists. Changing this forces a new resource to be created. -* `service_name` - (Required) The Name of the API Management Service where the API Management API exists +* `service_name` - (Required) The Name of the API Management Service where the API Management API exists. Changing this forces a new resource to be created. * `path` - (Required) Relative URL uniquely identifying this API and all of its resource paths within the API Management service instance. It is appended to the API endpoint base URL specified during the service instance creation to form a public URL for this API. @@ -111,9 +108,9 @@ In addition to all arguments above, the following attributes are exported: * `version_set_id` - A resource identifier for the related ApiVersionSet. -* `is_current` - Indicates if API revision is current api revision. +* `is_current` - Indicates if the API revision is current api revision. -* `is_online` - Indicates if API revision is accessible via the gateway. +* `is_online` - Indicates if the API revision is accessible via the gateway. ## Import From 28daf664312df58862400fa561939f490e6cf670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Thu, 25 Oct 2018 11:52:06 +0200 Subject: [PATCH 22/38] Fixed failing test by removing Computed on revision for api-management-api data source --- azurerm/data_source_api_management_api.go | 1 - 1 file changed, 1 deletion(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index 25037b35565d..3817603ad5fc 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -77,7 +77,6 @@ func dataSourceApiManagementApi() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 1, - Computed: true, }, "api_version": { From f83994a2bb96cd1a7d3817e13065687f8fc2df38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Thu, 25 Oct 2018 12:27:39 +0200 Subject: [PATCH 23/38] Replaced ip's with int.test url in example wsdl using for int.test --- azurerm/testdata/api_management_api_wsdl.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azurerm/testdata/api_management_api_wsdl.xml b/azurerm/testdata/api_management_api_wsdl.xml index f4afcba1c641..714659cfacb9 100644 --- a/azurerm/testdata/api_management_api_wsdl.xml +++ b/azurerm/testdata/api_management_api_wsdl.xml @@ -73,10 +73,10 @@ - + - + @@ -85,7 +85,7 @@ - + From 13119aca385e6f59c49537cdd7650297f5ac9e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Fri, 26 Oct 2018 20:55:56 +0200 Subject: [PATCH 24/38] Fixed issues after running int.tests. --- azurerm/data_source_api_management_api.go | 3 ++- azurerm/data_source_api_management_api_test.go | 5 +++-- azurerm/resource_arm_api_management_api.go | 3 ++- azurerm/resource_arm_api_management_api_test.go | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index 3817603ad5fc..00f3b461a8a5 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -76,7 +76,8 @@ func dataSourceApiManagementApi() *schema.Resource { "revision": { Type: schema.TypeInt, Optional: true, - Default: 1, + Default: nil, + Computed: true, }, "api_version": { diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index 2c8257adfad0..6032c264e083 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -31,8 +31,8 @@ func TestAccDataSourceAzureRMApiManagementApi_basic(t *testing.T) { resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.#", "1"), resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.0.header", "Ocp-Apim-Subscription-Key"), resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.0.query", "subscription-key"), - resource.TestCheckResourceAttr(dataSourceName, "version", ""), - resource.TestCheckResourceAttr(dataSourceName, "version_set_id", ""), + resource.TestCheckResourceAttr(dataSourceName, "api_version", ""), + resource.TestCheckResourceAttr(dataSourceName, "api_version_set_id", ""), ), }, }, @@ -64,6 +64,7 @@ resource "azurerm_api_management_api" "test" { name = "acctestAMA-%d" service_name = "${azurerm_api_management.test.name}" path = "api1" + protocols = ["https"] import { content_value = "${file("testdata/api_management_api_swagger.json")}" diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 23a19e20b40b..c4fd9d78052a 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -147,7 +147,8 @@ func resourceArmApiManagementApi() *schema.Resource { "revision": { Type: schema.TypeInt, Optional: true, - Default: 1, + Computed: true, + Default: nil, }, "version": { diff --git a/azurerm/resource_arm_api_management_api_test.go b/azurerm/resource_arm_api_management_api_test.go index c52d4bbc8337..47d2b475a4ca 100644 --- a/azurerm/resource_arm_api_management_api_test.go +++ b/azurerm/resource_arm_api_management_api_test.go @@ -154,6 +154,7 @@ resource "azurerm_api_management_api" "test" { name = "acctestAMA-%d" service_name = "${azurerm_api_management.test.name}" path = "api1" + protocols = ["https"] import { content_value = "${file("testdata/api_management_api_swagger.json")}" @@ -189,6 +190,7 @@ resource "azurerm_api_management_api" "test" { name = "acctestAMA-%d" service_name = "${azurerm_api_management.test.name}" path = "api1" + protocols = ["http", "https"] import { content_value = "${file("testdata/api_management_api_wsdl.xml")}" @@ -207,8 +209,6 @@ resource "azurerm_api_management_api" "test" { query = "test2" } - protocols = ["http", "https"] - resource_group_name = "${azurerm_resource_group.test.name}" } `, rInt, location, rInt, rInt) From 0c75f2fb2c99c4a6b035e9c36098c88eae68503b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Thu, 22 Nov 2018 13:28:08 +0100 Subject: [PATCH 25/38] Don't mix name and display_name, seperate them as in azure api --- azurerm/resource_arm_api_management_api.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index c4fd9d78052a..32cda6262e7f 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -62,6 +62,11 @@ func resourceArmApiManagementApi() *schema.Resource { Computed: true, }, + "display_name": { + Type: schema.TypeString, + Optional: true, + }, + "service_url": { Type: schema.TypeString, Optional: true, @@ -322,7 +327,7 @@ func resourceArmApiManagementApiDelete(d *schema.ResourceData, meta interface{}) } func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { - displayName := d.Get("name").(string) + displayName := d.Get("display_name").(string) path := d.Get("path").(string) serviceUrl := d.Get("service_url").(string) description := d.Get("description").(string) From 4d8f6f3e89b0f47339866256c66fd65f9662e3c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Thu, 22 Nov 2018 13:54:37 +0100 Subject: [PATCH 26/38] Simplyfied create/update with/without import api --- azurerm/resource_arm_api_management_api.go | 35 +++++++++++----------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 32cda6262e7f..b6f833fbc7b4 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -201,33 +201,32 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf // First we execute import and then updated the other props. if hasImport { properties = expandApiManagementImportProperties(d) - } else { - properties = expandApiManagementApiProperties(d) + log.Printf("[DEBUG] Importing API Management API %q of type %q", name, properties.ContentFormat) + + apiParams := apimanagement.APICreateOrUpdateParameter{ + APICreateOrUpdateProperties: properties, + } + + log.Printf("[DEBUG] Calling api with resource group %q, service name %q, api id %q", resGroup, serviceName, apiId) + _, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, apiParams, "") + if err != nil { + return fmt.Errorf("Error creating/updating API Management API %q (Resource Group %q): %+v", name, resGroup, err) + } } - apiParams := apimanagement.APICreateOrUpdateParameter{ - APICreateOrUpdateProperties: properties, + properties = expandApiManagementApiProperties(d) + + updateParams := apimanagement.APICreateOrUpdateParameter{ + APICreateOrUpdateProperties: expandApiManagementApiProperties(d), } log.Printf("[DEBUG] Calling api with resource group %q, service name %q, api id %q", resGroup, serviceName, apiId) - _, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, apiParams, "") + _, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, updateParams, "") + if err != nil { return fmt.Errorf("Error creating/updating API Management API %q (Resource Group %q): %+v", name, resGroup, err) } - if hasImport { - // Update with aditional properties not possible to send to Azure API during import - updateParams := apimanagement.APICreateOrUpdateParameter{ - APICreateOrUpdateProperties: expandApiManagementApiProperties(d), - } - - _, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, updateParams, "") - - if err != nil { - return fmt.Errorf("Failed to update after import: %+v", err) - } - } - read, err := client.Get(ctx, resGroup, serviceName, apiId) if err != nil { return fmt.Errorf("Error retrieving API Management API %q (Resource Group %q): %+v", name, resGroup, err) From 2fad08db031936f926a2d0f5fbe7a6175e022723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Thu, 22 Nov 2018 14:02:42 +0100 Subject: [PATCH 27/38] Documented display name. Removed defaults for header and query --- website/docs/r/api_management_api.html.markdown | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index c35ab49b3d1b..635da666eedf 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -56,6 +56,8 @@ The following arguments are supported: --- +* `display_name` - (Optional) The display name of the API. + * `service_url` - (Optional) Absolute URL of the backend service implementing this API. * `description` - (Optional) Description of the API. May include HTML formatting tags. @@ -72,9 +74,9 @@ The following arguments are supported: A `subscription_key_parameter_names` block supports the following: -* `header` - (Optional) Subscription key header name. Default is `Ocp-Apim-Subscription-Key`. +* `header` - (Optional) Subscription key header name. -* `query` - (Optional) Subscription key query string parameter name. Default is `subscription-key`. +* `query` - (Optional) Subscription key query string parameter name. --- From 2460dda943fdafed4e7532035571225b860ef5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Thu, 22 Nov 2018 15:14:33 +0100 Subject: [PATCH 28/38] Fixed empty return statements --- azurerm/helpers/validate/api_management.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/azurerm/helpers/validate/api_management.go b/azurerm/helpers/validate/api_management.go index bdbb90583c79..d3d2867a821d 100644 --- a/azurerm/helpers/validate/api_management.go +++ b/azurerm/helpers/validate/api_management.go @@ -65,8 +65,7 @@ func ApiManagementApiName(v interface{}, k string) (ws []string, es []error) { if matched := regexp.MustCompile(`^[^*#&+]{1,256}$`).Match([]byte(value)); !matched { es = append(es, fmt.Errorf("%q may only be up to 256 characters in length and not include the characters `*`, `#`, `&` or `+`", k)) } - - return + return ws, es } func ApiManagementApiPath(v interface{}, k string) (ws []string, es []error) { @@ -75,6 +74,5 @@ func ApiManagementApiPath(v interface{}, k string) (ws []string, es []error) { if matched := regexp.MustCompile(`^[\w][\w-/.]+[\w-]$`).Match([]byte(value)); !matched { es = append(es, fmt.Errorf("%q may only be up to 256 characters in length, not start or end with `/` and only contain valid url characters", k)) } - - return + return ws, es } From d4a2981c84a78f41b6938da6703b255aa4305eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Thu, 22 Nov 2018 15:15:12 +0100 Subject: [PATCH 29/38] Removed unused props var --- azurerm/resource_arm_api_management_api.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index b6f833fbc7b4..1c033743517b 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -214,8 +214,6 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf } } - properties = expandApiManagementApiProperties(d) - updateParams := apimanagement.APICreateOrUpdateParameter{ APICreateOrUpdateProperties: expandApiManagementApiProperties(d), } From af6606c8fcd0006de309db84f41e2c386edc6a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Fri, 23 Nov 2018 11:10:48 +0100 Subject: [PATCH 30/38] Fixed issue where display_name is a mandatory value for the Azure API --- azurerm/resource_arm_api_management_api.go | 10 +++++----- website/docs/r/api_management_api.html.markdown | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 1c033743517b..65e1a4c63f77 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -30,6 +30,11 @@ func resourceArmApiManagementApi() *schema.Resource { ValidateFunc: validate.ApiManagementApiName, }, + "display_name": { + Type: schema.TypeString, + Required: true, + }, + "service_name": { Type: schema.TypeString, Required: true, @@ -62,11 +67,6 @@ func resourceArmApiManagementApi() *schema.Resource { Computed: true, }, - "display_name": { - Type: schema.TypeString, - Optional: true, - }, - "service_url": { Type: schema.TypeString, Optional: true, diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index 635da666eedf..69ba3800ca45 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -48,15 +48,15 @@ The following arguments are supported: * `name` - (Required) The name of the API Management API. Changing this forces a new resource to be created. -* `resource_group_name` - (Required) The Name of the Resource Group where the API Management API exists. Changing this forces a new resource to be created. +* `display_name` - (Required) The display name of the API. * `service_name` - (Required) The Name of the API Management Service where the API Management API exists. Changing this forces a new resource to be created. * `path` - (Required) Relative URL uniquely identifying this API and all of its resource paths within the API Management service instance. It is appended to the API endpoint base URL specified during the service instance creation to form a public URL for this API. ---- +* `resource_group_name` - (Required) The Name of the Resource Group where the API Management API exists. Changing this forces a new resource to be created. -* `display_name` - (Optional) The display name of the API. +--- * `service_url` - (Optional) Absolute URL of the backend service implementing this API. From ef0d91865791b8e520a9ce2c5ef02348ea5fafa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Arild=20T=C3=B8rresdal?= Date: Fri, 23 Nov 2018 11:19:22 +0100 Subject: [PATCH 31/38] Added missing display_name to int. tests --- azurerm/data_source_api_management_api_test.go | 1 + azurerm/resource_arm_api_management_api_test.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index 6032c264e083..0cff4534297b 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -62,6 +62,7 @@ resource "azurerm_api_management" "test" { resource "azurerm_api_management_api" "test" { name = "acctestAMA-%d" + display_name = "api1" service_name = "${azurerm_api_management.test.name}" path = "api1" protocols = ["https"] diff --git a/azurerm/resource_arm_api_management_api_test.go b/azurerm/resource_arm_api_management_api_test.go index 47d2b475a4ca..74441f18e2a9 100644 --- a/azurerm/resource_arm_api_management_api_test.go +++ b/azurerm/resource_arm_api_management_api_test.go @@ -152,6 +152,7 @@ resource "azurerm_api_management" "test" { resource "azurerm_api_management_api" "test" { name = "acctestAMA-%d" + display_name = "api1" service_name = "${azurerm_api_management.test.name}" path = "api1" protocols = ["https"] @@ -188,6 +189,7 @@ resource "azurerm_api_management" "test" { resource "azurerm_api_management_api" "test" { name = "acctestAMA-%d" + display_name = "api1" service_name = "${azurerm_api_management.test.name}" path = "api1" protocols = ["http", "https"] From 425d7ddb497bffe7663368a13a8408e719e58882 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 1 Mar 2019 17:12:24 +0100 Subject: [PATCH 32/38] fixing the build --- azurerm/data_source_api_management_api.go | 2 +- azurerm/resource_arm_api_management_api.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index 00f3b461a8a5..3a782023be4e 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -3,7 +3,7 @@ package azurerm import ( "fmt" - "github.com/Azure/azure-sdk-for-go/services/preview/apimanagement/mgmt/2018-06-01-preview/apimanagement" + "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/utils" ) diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 65e1a4c63f77..b636c6664689 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -5,7 +5,7 @@ import ( "log" "strings" - "github.com/Azure/azure-sdk-for-go/services/preview/apimanagement/mgmt/2018-06-01-preview/apimanagement" + "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2018-01-01/apimanagement" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" From 710b3f83bb87b8f081c424db8cb2514d8973b25f Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 1 Mar 2019 17:12:30 +0100 Subject: [PATCH 33/38] refactoring --- azurerm/config.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azurerm/config.go b/azurerm/config.go index 59a8249435aa..1388f59cb5c2 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -495,6 +495,10 @@ func getArmClient(c *authentication.Config, skipProviderRegistration bool, partn } func (c *ArmClient) registerApiManagementServiceClients(endpoint, subscriptionId string, auth autorest.Authorizer) { + apisClient := apimanagement.NewAPIClientWithBaseURI(endpoint, subscriptionId) + c.configureClient(&apisClient.Client, auth) + c.apiManagementApiClient = apisClient + groupsClient := apimanagement.NewGroupClientWithBaseURI(endpoint, subscriptionId) c.configureClient(&groupsClient.Client, auth) c.apiManagementGroupClient = groupsClient @@ -522,10 +526,6 @@ func (c *ArmClient) registerApiManagementServiceClients(endpoint, subscriptionId usersClient := apimanagement.NewUserClientWithBaseURI(endpoint, subscriptionId) c.configureClient(&usersClient.Client, auth) c.apiManagementUsersClient = usersClient - - api := apimanagement.NewAPIClientWithBaseURI(endpoint, subscriptionId) - c.configureClient(&api.Client, auth) - c.apiManagementApiClient = api } func (c *ArmClient) registerAppInsightsClients(endpoint, subscriptionId string, auth autorest.Authorizer) { From 3d86e683df49373390d4ebea2470ba326f83cbbc Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 4 Mar 2019 16:24:10 +0100 Subject: [PATCH 34/38] fixing a bad merge conflict --- azurerm/provider.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/azurerm/provider.go b/azurerm/provider.go index 4da420882a05..45f8c48292b2 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -187,11 +187,6 @@ func Provider() terraform.ResourceProvider { "azurerm_application_gateway": resourceArmApplicationGateway(), "azurerm_application_insights": resourceArmApplicationInsights(), "azurerm_application_security_group": resourceArmApplicationSecurityGroup(), - "azurerm_app_service": resourceArmAppService(), - "azurerm_app_service_plan": resourceArmAppServicePlan(), - "azurerm_app_service_active_slot": resourceArmAppServiceActiveSlot(), - "azurerm_app_service_custom_hostname_binding": resourceArmAppServiceCustomHostnameBinding(), - "azurerm_app_service_slot": resourceArmAppServiceSlot(), "azurerm_automation_account": resourceArmAutomationAccount(), "azurerm_automation_credential": resourceArmAutomationCredential(), "azurerm_automation_dsc_configuration": resourceArmAutomationDscConfiguration(), From 90931f8b559ffaf3941bd57f35f06fe3d3bab0f9 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 6 Mar 2019 15:01:09 +0100 Subject: [PATCH 35/38] Refactoring `azurerm_api_management_api` --- azurerm/data_source_api_management_api.go | 153 +++++--- .../data_source_api_management_api_test.go | 90 ++--- azurerm/resource_arm_api_management_api.go | 338 +++++++++--------- .../resource_arm_api_management_api_test.go | 336 +++++++++++++---- .../docs/d/api_management_api.html.markdown | 43 ++- .../docs/r/api_management_api.html.markdown | 85 ++--- 6 files changed, 653 insertions(+), 392 deletions(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index 3a782023be4e..cdd7a10f2f6a 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -2,9 +2,12 @@ package azurerm import ( "fmt" + "strconv" "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/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -13,47 +16,67 @@ func dataSourceApiManagementApi() *schema.Resource { Read: dataSourceApiManagementApiRead, Schema: map[string]*schema.Schema{ - "service_name": { - Type: schema.TypeString, - Required: true, - }, - "name": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ApiManagementApiName, }, + "api_management_name": azure.SchemaApiManagementDataSourceName(), + "resource_group_name": resourceGroupNameForDataSourceSchema(), - "location": locationForDataSourceSchema(), + "revision": { + Type: schema.TypeInt, + Required: true, + }, - "path": { + "description": { Type: schema.TypeString, Computed: true, }, - "service_url": { + "display_name": { Type: schema.TypeString, Computed: true, }, - "description": { + "is_current": { + Type: schema.TypeBool, + Computed: true, + }, + + "is_online": { + Type: schema.TypeBool, + Computed: true, + }, + + "path": { Type: schema.TypeString, Computed: true, }, "protocols": { - Type: schema.TypeList, + Type: schema.TypeList, + Computed: true, Elem: &schema.Schema{ Type: schema.TypeString, }, + }, + + "service_url": { + Type: schema.TypeString, + Computed: true, + }, + + "soap_pass_through": { + Type: schema.TypeBool, Computed: true, }, "subscription_key_parameter_names": { Type: schema.TypeList, - Optional: true, - MaxItems: 1, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "header": { @@ -68,84 +91,102 @@ func dataSourceApiManagementApi() *schema.Resource { }, }, - "soap_pass_through": { - Type: schema.TypeBool, - Computed: true, - }, - - "revision": { - Type: schema.TypeInt, - Optional: true, - Default: nil, - Computed: true, - }, - - "api_version": { + "version": { Type: schema.TypeString, Computed: true, }, - "api_version_set_id": { + "version_set_id": { Type: schema.TypeString, Computed: true, }, - - "is_current": { - Type: schema.TypeBool, - Computed: true, - }, - - "is_online": { - Type: schema.TypeBool, - Computed: true, - }, }, } } func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ArmClient).apiManagementApiClient ctx := meta.(*ArmClient).StopContext + client := meta.(*ArmClient).apiManagementApiClient - resGroup := d.Get("resource_group_name").(string) - serviceName := d.Get("service_name").(string) + resourceGroup := d.Get("resource_group_name").(string) + serviceName := d.Get("api_management_name").(string) name := d.Get("name").(string) - revision := int32(d.Get("revision").(int)) + revision := d.Get("revision").(int) apiId := fmt.Sprintf("%s;rev=%d", name, revision) - - resp, err := client.Get(ctx, resGroup, serviceName, apiId) - + resp, err := client.Get(ctx, resourceGroup, serviceName, apiId) if err != nil { if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("API Management API %q (Service %q / Resource Group %q) was not found", name, serviceName, resGroup) + return fmt.Errorf("API %q Revision %q (API Management Service %q / Resource Group %q) does not exist!", name, revision, serviceName, resourceGroup) } - return fmt.Errorf("Error retrieving API Management API %q (Service %q / Resource Group %q): %+v", name, serviceName, resGroup, err) + return fmt.Errorf("Error retrieving API %q / Revision %q (API Management Service %q / Resource Group %q): %+v", name, revision, serviceName, resourceGroup, err) } d.SetId(*resp.ID) + d.Set("api_management_name", serviceName) d.Set("name", name) - d.Set("service_name", serviceName) - d.Set("resource_group_name", resGroup) + d.Set("resource_group_name", resourceGroup) if props := resp.APIContractProperties; props != nil { - d.Set("service_url", props.ServiceURL) - d.Set("path", props.Path) d.Set("description", props.Description) - d.Set("revision", props.APIRevision) - d.Set("api_version", props.APIVersion) - d.Set("api_version_set_id", props.APIVersionSetID) + d.Set("display_name", props.DisplayName) d.Set("is_current", props.IsCurrent) d.Set("is_online", props.IsOnline) - d.Set("protocols", props.Protocols) + d.Set("path", props.Path) + d.Set("service_url", props.ServiceURL) d.Set("soap_pass_through", string(props.APIType) == string(apimanagement.SoapPassThrough)) + d.Set("version", props.APIVersion) + d.Set("version_set_id", props.APIVersionSetID) + + if apiR := props.APIRevision; apiR != nil { + i, err := strconv.Atoi(*apiR) + if err != nil { + return fmt.Errorf("Error casting %q to an integer: %s", *apiR, err) + } - if err := d.Set("subscription_key_parameter_names", flattenApiManagementApiSubscriptionKeyParamNames(props.SubscriptionKeyParameterNames)); err != nil { + d.Set("revision", i) + } + + if err := d.Set("protocols", flattenApiManagementApiDataSourceProtocols(props.Protocols)); err != nil { + return fmt.Errorf("Error setting `protocols`: %s", err) + } + + if err := d.Set("subscription_key_parameter_names", flattenApiManagementApiDataSourceSubscriptionKeyParamNames(props.SubscriptionKeyParameterNames)); err != nil { return fmt.Errorf("Error setting `subscription_key_parameter_names`: %+v", err) } } return nil } + +func flattenApiManagementApiDataSourceProtocols(input *[]apimanagement.Protocol) []string { + if input == nil { + return []string{} + } + + results := make([]string, 0) + for _, v := range *input { + results = append(results, string(v)) + } + + return results +} +func flattenApiManagementApiDataSourceSubscriptionKeyParamNames(paramNames *apimanagement.SubscriptionKeyParameterNamesContract) []interface{} { + if paramNames == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + if paramNames.Header != nil { + result["header"] = *paramNames.Header + } + + if paramNames.Query != nil { + result["query"] = *paramNames.Query + } + + return []interface{}{result} +} diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index 0cff4534297b..77ccf3e2541a 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -20,19 +20,41 @@ func TestAccDataSourceAzureRMApiManagementApi_basic(t *testing.T) { { Config: testAccDataSourceApiManagementApi_basic(rInt, location), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(dataSourceName, "is_current", "true"), - resource.TestCheckResourceAttr(dataSourceName, "is_online", "false"), - resource.TestCheckResourceAttr(dataSourceName, "name", fmt.Sprintf("acctestAMA-%d", rInt)), + resource.TestCheckResourceAttr(dataSourceName, "display_name", "api1"), resource.TestCheckResourceAttr(dataSourceName, "path", "api1"), - resource.TestCheckResourceAttr(dataSourceName, "protocols.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "protocols.%", "1"), resource.TestCheckResourceAttr(dataSourceName, "protocols.0", "https"), - resource.TestCheckResourceAttr(dataSourceName, "service_name", fmt.Sprintf("acctestAM-%d", rInt)), + resource.TestCheckResourceAttr(dataSourceName, "soap_pass_through", "true"), + resource.TestCheckResourceAttr(dataSourceName, "is_current", "true"), + resource.TestCheckResourceAttr(dataSourceName, "is_online", "false"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMApiManagementApi_complete(t *testing.T) { + dataSourceName := "data.azurerm_api_management_api.test" + rInt := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceApiManagementApi_complete(rInt, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "display_name", "Butter Parser"), + resource.TestCheckResourceAttr(dataSourceName, "path", "butter-parser"), + resource.TestCheckResourceAttr(dataSourceName, "protocols.#", "2"), + resource.TestCheckResourceAttr(dataSourceName, "description", "What is my purpose? You pass butter."), + resource.TestCheckResourceAttr(dataSourceName, "service_url", "https://example.com/foo/bar"), resource.TestCheckResourceAttr(dataSourceName, "soap_pass_through", "false"), - resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.#", "1"), - resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.0.header", "Ocp-Apim-Subscription-Key"), - resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.0.query", "subscription-key"), - resource.TestCheckResourceAttr(dataSourceName, "api_version", ""), - resource.TestCheckResourceAttr(dataSourceName, "api_version_set_id", ""), + resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.0.header", "X-Butter-Robot-API-Key"), + resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.0.query", "location"), + resource.TestCheckResourceAttr(dataSourceName, "is_current", "true"), + resource.TestCheckResourceAttr(dataSourceName, "is_online", "false"), ), }, }, @@ -40,45 +62,29 @@ func TestAccDataSourceAzureRMApiManagementApi_basic(t *testing.T) { } func testAccDataSourceApiManagementApi_basic(rInt int, location string) string { + template := testAccAzureRMApiManagementApi_basic(rInt, location) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "amtestRG-%d" - location = "%s" -} - -resource "azurerm_api_management" "test" { - name = "acctestAM-%d" - publisher_name = "pub1" - publisher_email = "pub1@email.com" - - sku { - name = "Developer" - capacity = 1 - } +%s - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" +data "azurerm_api_management_api" "test" { + name = "${azurerm_api_management_api.test.name}" + api_management_name = "${azurerm_api_management_api.test.api_management_name}" + resource_group_name = "${azurerm_api_management_api.test.resource_group_name}" + revision = "${azurerm_api_management_api.test.revision}" } - -resource "azurerm_api_management_api" "test" { - name = "acctestAMA-%d" - display_name = "api1" - service_name = "${azurerm_api_management.test.name}" - path = "api1" - protocols = ["https"] - - import { - content_value = "${file("testdata/api_management_api_swagger.json")}" - content_format = "swagger-json" - } - - resource_group_name = "${azurerm_resource_group.test.name}" +`, template) } +func testAccDataSourceApiManagementApi_complete(rInt int, location string) string { + template := testAccAzureRMApiManagementApi_complete(rInt, location) + return fmt.Sprintf(` +%s + data "azurerm_api_management_api" "test" { name = "${azurerm_api_management_api.test.name}" - service_name = "${azurerm_api_management.test.name}" + api_management_name = "${azurerm_api_management_api.test.api_management_name}" resource_group_name = "${azurerm_api_management_api.test.resource_group_name}" + revision = "${azurerm_api_management_api.test.revision}" } -`, rInt, location, rInt, rInt) +`, template) } diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index b636c6664689..94afcba2a6c1 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -3,11 +3,14 @@ package azurerm import ( "fmt" "log" + "strconv" "strings" "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2018-01-01/apimanagement" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -30,20 +33,15 @@ func resourceArmApiManagementApi() *schema.Resource { ValidateFunc: validate.ApiManagementApiName, }, + "api_management_name": azure.SchemaApiManagementName(), + + "resource_group_name": resourceGroupNameSchema(), + "display_name": { Type: schema.TypeString, Required: true, }, - "service_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validate.ApiManagementServiceName, - }, - - "resource_group_name": resourceGroupNameSchema(), - "path": { Type: schema.TypeString, Required: true, @@ -51,7 +49,8 @@ func resourceArmApiManagementApi() *schema.Resource { }, "protocols": { - Type: schema.TypeList, + Type: schema.TypeSet, + Required: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringInSlice([]string{ @@ -59,19 +58,15 @@ func resourceArmApiManagementApi() *schema.Resource { string(apimanagement.ProtocolHTTPS), }, false), }, - Required: true, - }, - - "api_id": { - Type: schema.TypeString, - Computed: true, }, - "service_url": { - Type: schema.TypeString, - Optional: true, + "revision": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, }, + // Optional "description": { Type: schema.TypeString, Optional: true, @@ -122,6 +117,12 @@ func resourceArmApiManagementApi() *schema.Resource { }, }, + "service_url": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "subscription_key_parameter_names": { Type: schema.TypeList, Optional: true, @@ -131,13 +132,11 @@ func resourceArmApiManagementApi() *schema.Resource { Schema: map[string]*schema.Schema{ "header": { Type: schema.TypeString, - Optional: true, - Computed: true, + Required: true, }, "query": { Type: schema.TypeString, - Optional: true, - Computed: true, + Required: true, }, }, }, @@ -149,30 +148,24 @@ func resourceArmApiManagementApi() *schema.Resource { Optional: true, }, - "revision": { - Type: schema.TypeInt, - Optional: true, + // Computed + "is_current": { + Type: schema.TypeBool, Computed: true, - Default: nil, }, - "version": { - Type: schema.TypeString, + "is_online": { + Type: schema.TypeBool, Computed: true, }, - "version_set_id": { + "version": { Type: schema.TypeString, Computed: true, }, - "is_current": { - Type: schema.TypeBool, - Computed: true, - }, - - "is_online": { - Type: schema.TypeBool, + "version_set_id": { + Type: schema.TypeString, Computed: true, }, }, @@ -183,109 +176,165 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf client := meta.(*ArmClient).apiManagementApiClient ctx := meta.(*ArmClient).StopContext - log.Printf("[INFO] preparing arguments for AzureRM API Management API creation.") - - resGroup := d.Get("resource_group_name").(string) - serviceName := d.Get("service_name").(string) + resourceGroup := d.Get("resource_group_name").(string) + serviceName := d.Get("api_management_name").(string) name := d.Get("name").(string) revision := int32(d.Get("revision").(int)) - + path := d.Get("path").(string) apiId := fmt.Sprintf("%s;rev=%d", name, revision) - d.Set("api_id", apiId) - var properties *apimanagement.APICreateOrUpdateProperties + if requireResourcesToBeImported && d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, serviceName, apiId) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing API %q (API Management Service %q / Resource Group %q): %s", name, serviceName, resourceGroup, err) + } + } - _, hasImport := d.GetOk("import") + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_api_management_api", *existing.ID) + } + } // If import is used, we need to send properties to Azure API in two operations. // First we execute import and then updated the other props. - if hasImport { - properties = expandApiManagementImportProperties(d) - log.Printf("[DEBUG] Importing API Management API %q of type %q", name, properties.ContentFormat) + if vs, hasImport := d.GetOk("import"); hasImport { + importVs := vs.([]interface{}) + importV := importVs[0].(map[string]interface{}) + contentFormat := importV["content_format"].(string) + contentValue := importV["content_value"].(string) + log.Printf("[DEBUG] Importing API Management API %q of type %q", name, contentFormat) apiParams := apimanagement.APICreateOrUpdateParameter{ - APICreateOrUpdateProperties: properties, + APICreateOrUpdateProperties: &apimanagement.APICreateOrUpdateProperties{ + ContentFormat: apimanagement.ContentFormat(contentFormat), + ContentValue: utils.String(contentValue), + Path: utils.String(path), + }, + } + wsdlSelectorVs := importV["wsdl_selector"].([]interface{}) + if len(wsdlSelectorVs) > 0 { + wsdlSelectorV := wsdlSelectorVs[0].(map[string]interface{}) + wSvcName := wsdlSelectorV["service_name"].(string) + wEndpName := wsdlSelectorV["endpoint_name"].(string) + + apiParams.APICreateOrUpdateProperties.WsdlSelector = &apimanagement.APICreateOrUpdatePropertiesWsdlSelector{ + WsdlServiceName: utils.String(wSvcName), + WsdlEndpointName: utils.String(wEndpName), + } } - log.Printf("[DEBUG] Calling api with resource group %q, service name %q, api id %q", resGroup, serviceName, apiId) - _, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, apiParams, "") - if err != nil { - return fmt.Errorf("Error creating/updating API Management API %q (Resource Group %q): %+v", name, resGroup, err) + if _, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, apiId, apiParams, ""); err != nil { + return fmt.Errorf("Error creating/updating API Management API %q (Resource Group %q): %+v", name, resourceGroup, err) } } - updateParams := apimanagement.APICreateOrUpdateParameter{ - APICreateOrUpdateProperties: expandApiManagementApiProperties(d), + description := d.Get("description").(string) + displayName := d.Get("display_name").(string) + serviceUrl := d.Get("service_url").(string) + + protocolsRaw := d.Get("protocols").(*schema.Set).List() + protocols := expandApiManagementApiProtocols(protocolsRaw) + + subscriptionKeyParameterNamesRaw := d.Get("subscription_key_parameter_names").([]interface{}) + subscriptionKeyParameterNames := expandApiManagementApiSubscriptionKeyParamNames(subscriptionKeyParameterNamesRaw) + + var apiType apimanagement.APIType + soapPassThrough := d.Get("soap_pass_through").(bool) + if soapPassThrough { + apiType = apimanagement.APIType(apimanagement.SoapPassThrough) + } else { + apiType = apimanagement.APIType(apimanagement.SoapToRest) } - log.Printf("[DEBUG] Calling api with resource group %q, service name %q, api id %q", resGroup, serviceName, apiId) - _, err := client.CreateOrUpdate(ctx, resGroup, serviceName, apiId, updateParams, "") + params := apimanagement.APICreateOrUpdateParameter{ + APICreateOrUpdateProperties: &apimanagement.APICreateOrUpdateProperties{ + APIType: apiType, + Description: utils.String(description), + DisplayName: utils.String(displayName), + Path: utils.String(path), + Protocols: protocols, + ServiceURL: utils.String(serviceUrl), + SubscriptionKeyParameterNames: subscriptionKeyParameterNames, + }, + } - if err != nil { - return fmt.Errorf("Error creating/updating API Management API %q (Resource Group %q): %+v", name, resGroup, err) + revisionStr := strconv.Itoa(int(revision)) + if _, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, apiId, params, ""); err != nil { + return fmt.Errorf("Error creating/updating API %q / Revision %q (API Management Service %q / Resource Group %q): %+v", name, revisionStr, serviceName, resourceGroup, err) } - read, err := client.Get(ctx, resGroup, serviceName, apiId) + read, err := client.Get(ctx, resourceGroup, serviceName, apiId) if err != nil { - return fmt.Errorf("Error retrieving API Management API %q (Resource Group %q): %+v", name, resGroup, err) + return fmt.Errorf("Error retrieving API %q / Revision %q (API Management Service %q / Resource Group %q): %+v", name, revisionStr, serviceName, resourceGroup, err) } if read.ID == nil { - return fmt.Errorf("Cannot read ID for API Management API %q (Resource Group %q)", name, resGroup) + return fmt.Errorf("Cannot read ID for API %q / Revision %q (API Management Service %q / Resource Group %q)", name, revisionStr, serviceName, resourceGroup) } d.SetId(*read.ID) - return resourceArmApiManagementApiRead(d, meta) } func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ArmClient) - apiManagementApiClient := meta.(*ArmClient).apiManagementApiClient + ctx := meta.(*ArmClient).StopContext + client := meta.(*ArmClient).apiManagementApiClient id, err := parseAzureResourceID(d.Id()) if err != nil { return err } - resGroup := id.ResourceGroup + resourceGroup := id.ResourceGroup serviceName := id.Path["service"] apiid := id.Path["apis"] name := apiid + revision := "" if strings.Contains(apiid, ";") { name = strings.Split(apiid, ";")[0] + revision = strings.Split(apiid, "=")[1] } - ctx := client.StopContext - resp, err := apiManagementApiClient.Get(ctx, resGroup, serviceName, apiid) - + resp, err := client.Get(ctx, resourceGroup, serviceName, apiid) if err != nil { if utils.ResponseWasNotFound(resp.Response) { - log.Printf("[DEBUG] API Management API %q (Service %q / Resource Group %q) does not exist - removing from state!", name, serviceName, resGroup) + log.Printf("[DEBUG] API %q Revision %q (API Management Service %q / Resource Group %q) does not exist - removing from state!", name, revision, serviceName, resourceGroup) d.SetId("") return nil } - return fmt.Errorf("Error making Read request on API Management API %q on service %q (Resource Group %q): %+v", apiid, serviceName, resGroup, err) + + return fmt.Errorf("Error retrieving API %q / Revision %q (API Management Service %q / Resource Group %q): %+v", name, revision, serviceName, resourceGroup, err) } - d.Set("api_id", apiid) + d.Set("api_management_name", serviceName) d.Set("name", name) - d.Set("resource_group_name", resGroup) - d.Set("service_name", serviceName) + d.Set("resource_group_name", resourceGroup) if props := resp.APIContractProperties; props != nil { - d.Set("display_name", props.DisplayName) - d.Set("service_url", props.ServiceURL) - d.Set("path", props.Path) d.Set("description", props.Description) - d.Set("revision", props.APIRevision) - d.Set("version", props.APIVersion) - d.Set("version_set_id", props.APIVersionSetID) + d.Set("display_name", props.DisplayName) d.Set("is_current", props.IsCurrent) d.Set("is_online", props.IsOnline) - d.Set("protocols", props.Protocols) + d.Set("path", props.Path) + d.Set("service_url", props.ServiceURL) d.Set("soap_pass_through", string(props.APIType) == string(apimanagement.SoapPassThrough)) + d.Set("version", props.APIVersion) + d.Set("version_set_id", props.APIVersionSetID) + + if apiR := props.APIRevision; apiR != nil { + i, err := strconv.Atoi(*apiR) + if err != nil { + return fmt.Errorf("Error casting %q to an integer: %s", *apiR, err) + } + + d.Set("revision", i) + } + + if err := d.Set("protocols", flattenApiManagementApiProtocols(props.Protocols)); err != nil { + return fmt.Errorf("Error setting `protocols`: %s", err) + } if err := d.Set("subscription_key_parameter_names", flattenApiManagementApiSubscriptionKeyParamNames(props.SubscriptionKeyParameterNames)); err != nil { return fmt.Errorf("Error setting `subscription_key_parameter_names`: %+v", err) @@ -304,124 +353,63 @@ func resourceArmApiManagementApiDelete(d *schema.ResourceData, meta interface{}) return err } - resGroup := id.ResourceGroup + resourceGroup := id.ResourceGroup serviceName := id.Path["service"] apiid := id.Path["apis"] - log.Printf("[DEBUG] Deleting api management api %s: %s", resGroup, apiid) - - resp, err := client.Delete(ctx, resGroup, serviceName, apiid, "*", utils.Bool(true)) + name := apiid + revision := "" + if strings.Contains(apiid, ";") { + name = strings.Split(apiid, ";")[0] + revision = strings.Split(apiid, "=")[1] + } - if err != nil { - if utils.ResponseWasNotFound(resp) { - return nil + deleteRevisions := utils.Bool(true) + if resp, err := client.Delete(ctx, resourceGroup, serviceName, name, "", deleteRevisions); err != nil { + if !utils.ResponseWasNotFound(resp) { + return fmt.Errorf("Error deleting API %q / Revision %q (API Management Service %q / Resource Group %q): %s", name, revision, serviceName, resourceGroup, err) } - - return err } return nil } -func expandApiManagementApiProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { - displayName := d.Get("display_name").(string) - path := d.Get("path").(string) - serviceUrl := d.Get("service_url").(string) - description := d.Get("description").(string) +func expandApiManagementApiProtocols(input []interface{}) *[]apimanagement.Protocol { + results := make([]apimanagement.Protocol, 0) - props := &apimanagement.APICreateOrUpdateProperties{ - Description: &description, - DisplayName: &displayName, - Path: &path, - Protocols: expandApiManagementApiProtocols(d), - ServiceURL: &serviceUrl, - SubscriptionKeyParameterNames: expandApiManagementApiSubscriptionKeyParamNames(d), + for _, v := range input { + results = append(results, apimanagement.Protocol(v.(string))) } - if v, ok := d.GetOk("soap_pass_through"); ok { - soapPassThrough := v.(bool) - - if soapPassThrough { - props.APIType = apimanagement.APIType(apimanagement.SoapPassThrough) - } else { - props.APIType = apimanagement.APIType(apimanagement.SoapToRest) - } - } - - return props + return &results } -func expandApiManagementApiSubscriptionKeyParamNames(d *schema.ResourceData) *apimanagement.SubscriptionKeyParameterNamesContract { - vs := d.Get("subscription_key_parameter_names").([]interface{}) - - if len(vs) > 0 { - v := vs[0].(map[string]interface{}) - contract := apimanagement.SubscriptionKeyParameterNamesContract{} - - query := v["query"].(string) - header := v["header"].(string) - - if query != "" { - contract.Query = utils.String(query) - } - - if header != "" { - contract.Header = utils.String(header) - } - - if query != "" || header != "" { - return &contract - } +func flattenApiManagementApiProtocols(input *[]apimanagement.Protocol) []string { + if input == nil { + return []string{} } - return nil -} - -func expandApiManagementApiProtocols(d *schema.ResourceData) *[]apimanagement.Protocol { - protos := make([]apimanagement.Protocol, 0) - - if p, ok := d.GetOk("protocols"); ok { - protocolsConfig := p.([]interface{}) - for _, v := range protocolsConfig { - protos = append(protos, apimanagement.Protocol(v.(string))) - } - } else { - // If not specified, set default to https - protos = append(protos, apimanagement.ProtocolHTTPS) + results := make([]string, 0) + for _, v := range *input { + results = append(results, string(v)) } - return &protos + return results } -func expandApiManagementImportProperties(d *schema.ResourceData) *apimanagement.APICreateOrUpdateProperties { - path := d.Get("path").(string) - - props := &apimanagement.APICreateOrUpdateProperties{ - Path: &path, +func expandApiManagementApiSubscriptionKeyParamNames(input []interface{}) *apimanagement.SubscriptionKeyParameterNamesContract { + if len(input) == 0 { + return nil } - importVs := d.Get("import").([]interface{}) - importV := importVs[0].(map[string]interface{}) - - props.ContentFormat = apimanagement.ContentFormat(importV["content_format"].(string)) - - cVal := importV["content_value"].(string) - props.ContentValue = &cVal - - wsdlSelectorVs := importV["wsdl_selector"].([]interface{}) - - if len(wsdlSelectorVs) > 0 { - wsdlSelectorV := wsdlSelectorVs[0].(map[string]interface{}) - props.WsdlSelector = &apimanagement.APICreateOrUpdatePropertiesWsdlSelector{} - - wSvcName := wsdlSelectorV["service_name"].(string) - wEndpName := wsdlSelectorV["endpoint_name"].(string) - - props.WsdlSelector.WsdlServiceName = &wSvcName - props.WsdlSelector.WsdlEndpointName = &wEndpName + v := input[0].(map[string]interface{}) + query := v["query"].(string) + header := v["header"].(string) + contract := apimanagement.SubscriptionKeyParameterNamesContract{ + Query: utils.String(query), + Header: utils.String(header), } - - return props + return &contract } func flattenApiManagementApiSubscriptionKeyParamNames(paramNames *apimanagement.SubscriptionKeyParameterNamesContract) []interface{} { diff --git a/azurerm/resource_arm_api_management_api_test.go b/azurerm/resource_arm_api_management_api_test.go index 74441f18e2a9..3654d27fdcd1 100644 --- a/azurerm/resource_arm_api_management_api_test.go +++ b/azurerm/resource_arm_api_management_api_test.go @@ -13,7 +13,7 @@ import ( func TestAccAzureRMApiManagementApi_basic(t *testing.T) { resourceName := "azurerm_api_management_api.test" ri := acctest.RandInt() - config := testAccAzureRMApiManagementApi_basic(ri, testLocation()) + location := testLocation() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -21,7 +21,89 @@ func TestAccAzureRMApiManagementApi_basic(t *testing.T) { CheckDestroy: testCheckAzureRMApiManagementApiDestroy, Steps: []resource.TestStep{ { - Config: config, + Config: testAccAzureRMApiManagementApi_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "soap_pass_through", "false"), + resource.TestCheckResourceAttr(resourceName, "is_current", "true"), + resource.TestCheckResourceAttr(resourceName, "is_online", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMApiManagementApi_requiresImport(t *testing.T) { + if !requireResourcesToBeImported { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + resourceName := "azurerm_api_management_api.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApi_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiExists(resourceName), + ), + }, + { + Config: testAccAzureRMApiManagementApi_requiresImport(ri, location), + ExpectError: testRequiresImportError("azurerm_api_management_api"), + }, + }, + }) +} + +func TestAccAzureRMApiManagementApi_soapPassthrough(t *testing.T) { + resourceName := "azurerm_api_management_api.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApi_soapPassthrough(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMApiManagementApi_importSwagger(t *testing.T) { + resourceName := "azurerm_api_management_api.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApi_importSwagger(ri, location), Check: resource.ComposeTestCheckFunc( testCheckAzureRMApiManagementApiExists(resourceName), ), @@ -30,8 +112,8 @@ func TestAccAzureRMApiManagementApi_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - // Ignore state that is only persisted in Terraform and not on Azure side ImportStateVerifyIgnore: []string{ + // not returned from the API "import", }, }, @@ -39,10 +121,39 @@ func TestAccAzureRMApiManagementApi_basic(t *testing.T) { }) } -func TestAccAzureRMApiManagementApi_complete(t *testing.T) { +func TestAccAzureRMApiManagementApi_importWsdl(t *testing.T) { + resourceName := "azurerm_api_management_api.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApi_importWsdl(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + // not returned from the API + "import", + }, + }, + }, + }) +} + +func TestAccAzureRMApiManagementApi_importUpdate(t *testing.T) { resourceName := "azurerm_api_management_api.test" ri := acctest.RandInt() - config := testAccAzureRMApiManagementApi_complete(ri, testLocation()) + location := testLocation() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -50,7 +161,22 @@ func TestAccAzureRMApiManagementApi_complete(t *testing.T) { CheckDestroy: testCheckAzureRMApiManagementApiDestroy, Steps: []resource.TestStep{ { - Config: config, + Config: testAccAzureRMApiManagementApi_importWsdl(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + // not returned from the API + "import", + }, + }, + { + Config: testAccAzureRMApiManagementApi_importSwagger(ri, location), Check: resource.ComposeTestCheckFunc( testCheckAzureRMApiManagementApiExists(resourceName), ), @@ -59,8 +185,8 @@ func TestAccAzureRMApiManagementApi_complete(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - // Ignore state that is only persisted in Terraform and not on Azure side ImportStateVerifyIgnore: []string{ + // not returned from the API "import", }, }, @@ -68,6 +194,31 @@ func TestAccAzureRMApiManagementApi_complete(t *testing.T) { }) } +func TestAccAzureRMApiManagementApi_complete(t *testing.T) { + resourceName := "azurerm_api_management_api.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApi_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testCheckAzureRMApiManagementApiDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*ArmClient).apiManagementApiClient @@ -77,13 +228,13 @@ func testCheckAzureRMApiManagementApiDestroy(s *terraform.State) error { } name := rs.Primary.Attributes["name"] - serviceName := rs.Primary.Attributes["service_name"] + serviceName := rs.Primary.Attributes["api_management_name"] resourceGroup := rs.Primary.Attributes["resource_group_name"] + revision := rs.Primary.Attributes["revision"] ctx := testAccProvider.Meta().(*ArmClient).StopContext - apiId := fmt.Sprintf("%s;rev=%d", name, 1) + apiId := fmt.Sprintf("%s;rev=%s", name, revision) resp, err := conn.Get(ctx, resourceGroup, serviceName, apiId) - if err != nil { if utils.ResponseWasNotFound(resp.Response) { return nil @@ -107,20 +258,18 @@ func testCheckAzureRMApiManagementApiExists(name string) resource.TestCheckFunc } name := rs.Primary.Attributes["name"] - serviceName := rs.Primary.Attributes["service_name"] - resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] - if !hasResourceGroup { - return fmt.Errorf("Bad: no resource group found in state for API Management API: %s", name) - } + serviceName := rs.Primary.Attributes["api_management_name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + revision := rs.Primary.Attributes["revision"] conn := testAccProvider.Meta().(*ArmClient).apiManagementApiClient ctx := testAccProvider.Meta().(*ArmClient).StopContext - apiId := fmt.Sprintf("%s;rev=%s", name, rs.Primary.Attributes["revision"]) + apiId := fmt.Sprintf("%s;rev=%s", name, revision) resp, err := conn.Get(ctx, resourceGroup, serviceName, apiId) if err != nil { if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: API Management API %q (resource group: %q) does not exist", name, resourceGroup) + return fmt.Errorf("Bad: API %q Revision %q (API Management Service %q / Resource Group: %q) does not exist", name, revision, serviceName, resourceGroup) } return fmt.Errorf("Bad: Get on apiManagementClient: %+v", err) @@ -131,43 +280,131 @@ func testCheckAzureRMApiManagementApiExists(name string) resource.TestCheckFunc } func testAccAzureRMApiManagementApi_basic(rInt int, location string) string { + template := testAccAzureRMApiManagementApi_template(rInt, location) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestrg-%d" - location = "%s" +%s + +resource "azurerm_api_management_api" "test" { + name = "acctestapi-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + display_name = "api1" + path = "api1" + protocols = ["https"] + revision = 1 +} +`, template, rInt) } -resource "azurerm_api_management" "test" { - name = "acctestAM-%d" - location = "${azurerm_resource_group.test.location}" +func testAccAzureRMApiManagementApi_soapPassthrough(rInt int, location string) string { + template := testAccAzureRMApiManagementApi_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api" "test" { + name = "acctestapi-%d" resource_group_name = "${azurerm_resource_group.test.name}" - publisher_name = "pub1" - publisher_email = "pub1@email.com" + api_management_name = "${azurerm_api_management.test.name}" + display_name = "api1" + path = "api1" + protocols = ["https"] + revision = 1 + soap_pass_through = true +} +`, template, rInt) +} - sku { - name = "Developer" - capacity = 1 - } +func testAccAzureRMApiManagementApi_requiresImport(rInt int, location string) string { + template := testAccAzureRMApiManagementApi_basic(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api" "import" { + name = "${azurerm_api_management_api.test.name}" + resource_group_name = "${azurerm_api_management_api.test.resource_group_name}" + api_management_name = "${azurerm_api_management_api.test.api_management_name}" + display_name = "${azurerm_api_management_api.test.display_name}" + path = "${azurerm_api_management_api.test.path}" + protocols = "${azurerm_api_management_api.test.protocols}" + revision = "${azurerm_api_management_api.test.revision}" +} +`, template) } +func testAccAzureRMApiManagementApi_importSwagger(rInt int, location string) string { + template := testAccAzureRMApiManagementApi_template(rInt, location) + return fmt.Sprintf(` +%s + resource "azurerm_api_management_api" "test" { - name = "acctestAMA-%d" - display_name = "api1" - service_name = "${azurerm_api_management.test.name}" - path = "api1" - protocols = ["https"] + name = "acctestapi-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + display_name = "api1" + path = "api1" + protocols = ["https"] + revision = 1 import { content_value = "${file("testdata/api_management_api_swagger.json")}" content_format = "swagger-json" } +} +`, template, rInt) +} + +func testAccAzureRMApiManagementApi_importWsdl(rInt int, location string) string { + template := testAccAzureRMApiManagementApi_template(rInt, location) + return fmt.Sprintf(` +%s +resource "azurerm_api_management_api" "test" { + name = "acctestapi-%d" resource_group_name = "${azurerm_resource_group.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + display_name = "api1" + path = "api1" + protocols = ["https"] + revision = 1 + + import { + content_value = "${file("testdata/api_management_api_wsdl.xml")}" + content_format = "wsdl" + + wsdl_selector { + service_name = "Calculator" + endpoint_name = "CalculatorHttpsSoap11Endpoint" + } + } } -`, rInt, location, rInt, rInt) +`, template, rInt) } func testAccAzureRMApiManagementApi_complete(rInt int, location string) string { + template := testAccAzureRMApiManagementApi_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api" "test" { + name = "acctestapi-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + display_name = "Butter Parser" + path = "butter-parser" + protocols = ["https", "http"] + revision = 3 + description = "What is my purpose? You pass butter." + service_url = "https://example.com/foo/bar" + + subscription_key_parameter_names { + header = "X-Butter-Robot-API-Key" + query = "location" + } +} +`, template, rInt) +} + +func testAccAzureRMApiManagementApi_template(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestrg-%d" @@ -186,32 +423,5 @@ resource "azurerm_api_management" "test" { capacity = 1 } } - -resource "azurerm_api_management_api" "test" { - name = "acctestAMA-%d" - display_name = "api1" - service_name = "${azurerm_api_management.test.name}" - path = "api1" - protocols = ["http", "https"] - - import { - content_value = "${file("testdata/api_management_api_wsdl.xml")}" - content_format = "wsdl" - - wsdl_selector { - service_name = "Calculator" - endpoint_name = "CalculatorHttpsSoap11Endpoint" - } - } - - soap_pass_through = true - - subscription_key_parameter_names { - header = "test1" - query = "test2" - } - - resource_group_name = "${azurerm_resource_group.test.name}" -} -`, rInt, location, rInt, rInt) +`, rInt, location, rInt) } diff --git a/website/docs/d/api_management_api.html.markdown b/website/docs/d/api_management_api.html.markdown index 694234bcf5d8..98652f34d5c4 100644 --- a/website/docs/d/api_management_api.html.markdown +++ b/website/docs/d/api_management_api.html.markdown @@ -15,8 +15,9 @@ Use this data source to access information about an existing API Management API. ```hcl data "azurerm_api_management_api" "test" { name = "search-api" - service_name = "search-api-management" + api_management_name = "search-api-management" resource_group_name = "search-service" + revision = 2 } output "api_management_api_id" { @@ -28,40 +29,50 @@ output "api_management_api_id" { * `name` - (Required) The name of the API Management API. -* `service_name` - (Required) The name of the API Management service which the API Management API belongs to. +* `api_management_name` - (Required) The name of the API Management Service in which the API Management API exists. -* `resource_group_name` - (Required) The Name of the Resource Group in which the API Management API exists. +* `resource_group_name` - (Required) The Name of the Resource Group in which the API Management Service exists. + +* `revision` - (Required) The Revision number of the API Management API. ## Attributes Reference * `id` - The ID of the API Management API. -* `path` - Relative URL uniquely identifying this API and all of its resource paths within the API Management service instance. It is appended to the API endpoint base URL specified during the service instance creation to form a public URL for this API. The path cannot start or end with `/`. +* `description` - A description of the API Management API, which may include HTML formatting tags. -* `service_url` - Absolute URL of the backend service implementing this API. +* `display_name` - The display name of the API. -* `description` - Description of the API. May include HTML formatting tags. +* `is_current` - Is this the current API Revision? -* `protocols` - Describes on which protocols the operations in this API can be invoked. +* `is_online` - Is this API Revision online/accessible via the Gateway? -* `subscription_key_parameter_names` - Describes the names of the header and query parameter names used to send in the subscription key. The `subscription_key_parameter_names` block is defined below. +* `path` - The Path for this API Management API. -* `soap_pass_through` - Make API Management expose a SOAP front end, instead of a HTTP front end. +* `protocols` - A list of protocols the operations in this API can be invoked. -* `revision` - Describes the Revision of the Api. +* `service_url` - Absolute URL of the backend service implementing this API. -* `version` - Indicates the Version identifier of the API if the API is versioned. +* `soap_pass_through` - Should this API expose a SOAP frontend, rather than a HTTP frontend? -* `version_set_id` - A resource identifier for the related ApiVersionSet. +* `subscription_key_parameter_names` - A `subscription_key_parameter_names` block as documented below. -* `is_current` - Indicates if the API revision is current api revision. +* `version` - The Version number of this API, if this API is versioned. -* `is_online` - Indicates if the API revision is accessible via the gateway. +* `version_set_id` - The ID of the Version Set which this API is associated with. --- A `subscription_key_parameter_names` block exports the following: -* `header` - Subscription key header name. +* `header` - The name of the HTTP Header which should be used for the Subscription Key. + +* `query` - The name of the QueryString parameter which should be used for the Subscription Key. + +--- + +A `wsdl_selector` block exports the following: + +* `service_name` - The name of service to import from WSDL. -* `query` - Subscription key query string parameter name. +* `endpoint_name` - The name of endpoint (port) to import from WSDL. diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index 69ba3800ca45..80347ae3b40a 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -3,42 +3,47 @@ layout: "azurerm" page_title: "Azure Resource Manager: azurerm_api_management_api" sidebar_current: "docs-azurerm-resource-api-management-api-x" description: |- - Create a API Management API. + Manages an API within an API Management Service. --- # azurerm_api_management_api -Create a API Management API component. +Manages an API within an API Management Service. -## Example Usage (import from Open API spec) +## Example Usage ```hcl resource "azurerm_resource_group" "test" { - name = "api-rg-dev" + name = "example-resources" location = "West Europe" } resource "azurerm_api_management" "test" { - name = "api-mngmnt-dev" + name = "example-apim" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" publisher_name = "My Company" publisher_email = "company@terraform.io" + sku { name = "Developer" capacity = 1 } - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" } resource "azurerm_api_management_api" "test" { - name = "conferenceapi" - service_name = "${azurerm_api_management.test.name}" - path = "conference" + name = "example-api" + resource_group_name = "${azurerm_resource_group.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + revision = 1 + display_name = "Example API" + path = "example" + protocols = ["https"] + import { content_format = "swagger-link-json" content_value = "http://conferenceapi.azurewebsites.net/?format=json" } - resource_group_name = "${azurerm_resource_group.test.name}" } ``` @@ -48,53 +53,55 @@ The following arguments are supported: * `name` - (Required) The name of the API Management API. Changing this forces a new resource to be created. -* `display_name` - (Required) The display name of the API. - -* `service_name` - (Required) The Name of the API Management Service where the API Management API exists. Changing this forces a new resource to be created. - -* `path` - (Required) Relative URL uniquely identifying this API and all of its resource paths within the API Management service instance. It is appended to the API endpoint base URL specified during the service instance creation to form a public URL for this API. +* `api_management_name` - (Required) The Name of the API Management Service where this API should be created. Changing this forces a new resource to be created. * `resource_group_name` - (Required) The Name of the Resource Group where the API Management API exists. Changing this forces a new resource to be created. ---- +* `revision` - (Required) The Revision number used for this API. -* `service_url` - (Optional) Absolute URL of the backend service implementing this API. +* `display_name` - (Required) The display name of the API. + +* `path` - (Required) The Path for this API Management API, which is a relative URL which uniquely identifies this API and all of it's resource paths within the API Management Service. -* `description` - (Optional) Description of the API. May include HTML formatting tags. +* `protocols` - (Required) A list of protocols the operations in this API can be invoked. Possible values are `http` and `https`. -* `protocols` - (Optional) A list of protocols the operations in this API can be invoked. Supported values are `http` and `https`. Default is `https`. +--- -* `subscription_key_parameter_names` - (Optional) A `subscription_key` block as documented below. +* `description` - (Optional) A description of the API Management API, which may include HTML formatting tags. * `import` - (Optional) A `import` block as documented below. -* `soap_pass_through` - Make API Management expose a SOAP front end, instead of a HTTP front end. +* `service_url` - (Optional) Absolute URL of the backend service implementing this API. + +* `soap_pass_through` - (Optional) Should this API expose a SOAP frontend, rather than a HTTP frontend? Defaults to `false`. + +* `subscription_key_parameter_names` - (Optional) A `subscription_key_parameter_names` block as documented below. --- -A `subscription_key_parameter_names` block supports the following: +A `import` block supports the following: -* `header` - (Optional) Subscription key header name. +* `content_format` - (Required) The format of the content from which the API Definition should be imported. Possible values are: `swagger-json`, `swagger-link-json`, `wadl-link-json`, `wadl-xml`, `wsdl` and `wsdl-link`. -* `query` - (Optional) Subscription key query string parameter name. +* `content_value` - (Required) The Content from which the API Definition should be imported. When a `content_format` of `*-link-*` is specified this must be a URL, otherwise this must be defined inline. ---- +* `wsdl_selector` - (Optional) A `wsdl_selector` block as defined below, which allows you to limit the import of a WSDL to only a subset of the document. This can only be specified when `content_format` is `wsdl` or `wsdl-link`. -A `import` block supports the following: +--- -* `content_format` - (Required) Format of the Content in which the API is getting imported. Possible values include: 'swagger-json', 'swagger-link-json', 'wadl-link-json', 'wadl-xml', 'wsdl', 'wsdl-link'. +A `subscription_key_parameter_names` block supports the following: -* `content_value` - (Required) Content value when Importing an API. When a `*-link-*` `content_format` is used, the `content_value` must be a URL. If not, `content_value` is defined inline. +* `header` - (Required) The name of the HTTP Header which should be used for the Subscription Key. -* `wsdl_selector` - (Optional) Criteria to limit import of WSDL to a subset of the document. Only applicable to content with format `wsdl` or `wsdl-link`. The `wsdl_selector` block is documented below. +* `query` - (Required) The name of the QueryString parameter which should be used for the Subscription Key. --- A `wsdl_selector` block supports the following: -* `service_name` - (Required) Name of service to import from WSDL. +* `service_name` - (Required) The name of service to import from WSDL. -* `endpoint_name` - (Required) Name of endpoint(port) to import from WSDL. +* `endpoint_name` - (Required) The name of endpoint (port) to import from WSDL. --- @@ -102,21 +109,19 @@ A `wsdl_selector` block supports the following: In addition to all arguments above, the following attributes are exported: -* `id` - The ID of the API Management API component. - -* `revision` - Describes the Revision of the Api. +* `id` - The ID of the API Management API. -* `version` - Indicates the Version identifier of the API if the API is versioned. +* `is_current` - Is this the current API Revision? -* `version_set_id` - A resource identifier for the related ApiVersionSet. +* `is_online` - Is this API Revision online/accessible via the Gateway? -* `is_current` - Indicates if the API revision is current api revision. +* `version` - The Version number of this API, if this API is versioned. -* `is_online` - Indicates if the API revision is accessible via the gateway. +* `version_set_id` - The ID of the Version Set which this API is associated with. ## Import -Api Management API can be imported using the `resource id`, e.g. +API Management API's can be imported using the `resource id`, e.g. ```shell terraform import azurerm_api_management_api.test /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.ApiManagement/service/instance1/apis/api1 From 2c0011906f213d62eea4cae7dbee3ea755efa341 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 6 Mar 2019 15:18:00 +0100 Subject: [PATCH 36/38] Adding back in the resources missing from a bad merge conflict with master --- azurerm/provider.go | 52 ++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/azurerm/provider.go b/azurerm/provider.go index 45f8c48292b2..9cb5d178f50a 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -168,9 +168,6 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "azurerm_azuread_application": resourceArmActiveDirectoryApplication(), - "azurerm_azuread_service_principal": resourceArmActiveDirectoryServicePrincipal(), - "azurerm_azuread_service_principal_password": resourceArmActiveDirectoryServicePrincipalPassword(), "azurerm_api_management": resourceArmApiManagementService(), "azurerm_api_management_api": resourceArmApiManagementApi(), "azurerm_api_management_group": resourceArmApiManagementGroup(), @@ -185,6 +182,7 @@ func Provider() terraform.ResourceProvider { "azurerm_app_service_slot": resourceArmAppServiceSlot(), "azurerm_app_service": resourceArmAppService(), "azurerm_application_gateway": resourceArmApplicationGateway(), + "azurerm_application_insights_api_key": resourceArmApplicationInsightsAPIKey(), "azurerm_application_insights": resourceArmApplicationInsights(), "azurerm_application_security_group": resourceArmApplicationSecurityGroup(), "azurerm_automation_account": resourceArmAutomationAccount(), @@ -196,25 +194,32 @@ func Provider() terraform.ResourceProvider { "azurerm_automation_schedule": resourceArmAutomationSchedule(), "azurerm_autoscale_setting": resourceArmAutoScaleSetting(), "azurerm_availability_set": resourceArmAvailabilitySet(), + "azurerm_azuread_application": resourceArmActiveDirectoryApplication(), + "azurerm_azuread_service_principal_password": resourceArmActiveDirectoryServicePrincipalPassword(), + "azurerm_azuread_service_principal": resourceArmActiveDirectoryServicePrincipal(), + "azurerm_batch_account": resourceArmBatchAccount(), + "azurerm_batch_pool": resourceArmBatchPool(), "azurerm_cdn_endpoint": resourceArmCdnEndpoint(), "azurerm_cdn_profile": resourceArmCdnProfile(), "azurerm_cognitive_account": resourceArmCognitiveAccount(), + "azurerm_connection_monitor": resourceArmConnectionMonitor(), + "azurerm_container_group": resourceArmContainerGroup(), "azurerm_container_registry": resourceArmContainerRegistry(), "azurerm_container_service": resourceArmContainerService(), - "azurerm_container_group": resourceArmContainerGroup(), "azurerm_cosmosdb_account": resourceArmCosmosDBAccount(), - "azurerm_databricks_workspace": resourceArmDatabricksWorkspace(), "azurerm_data_lake_analytics_account": resourceArmDataLakeAnalyticsAccount(), "azurerm_data_lake_analytics_firewall_rule": resourceArmDataLakeAnalyticsFirewallRule(), - "azurerm_data_lake_store": resourceArmDataLakeStore(), "azurerm_data_lake_store_file": resourceArmDataLakeStoreFile(), "azurerm_data_lake_store_firewall_rule": resourceArmDataLakeStoreFirewallRule(), - "azurerm_devspace_controller": resourceArmDevSpaceController(), + "azurerm_data_lake_store": resourceArmDataLakeStore(), + "azurerm_databricks_workspace": resourceArmDatabricksWorkspace(), + "azurerm_ddos_protection_plan": resourceArmDDoSProtectionPlan(), "azurerm_dev_test_lab": resourceArmDevTestLab(), - "azurerm_dev_test_policy": resourceArmDevTestPolicy(), "azurerm_dev_test_linux_virtual_machine": resourceArmDevTestLinuxVirtualMachine(), + "azurerm_dev_test_policy": resourceArmDevTestPolicy(), "azurerm_dev_test_virtual_network": resourceArmDevTestVirtualNetwork(), "azurerm_dev_test_windows_virtual_machine": resourceArmDevTestWindowsVirtualMachine(), + "azurerm_devspace_controller": resourceArmDevSpaceController(), "azurerm_dns_a_record": resourceArmDnsARecord(), "azurerm_dns_aaaa_record": resourceArmDnsAAAARecord(), "azurerm_dns_caa_record": resourceArmDnsCaaRecord(), @@ -228,36 +233,39 @@ func Provider() terraform.ResourceProvider { "azurerm_eventgrid_domain": resourceArmEventGridDomain(), "azurerm_eventgrid_event_subscription": resourceArmEventGridEventSubscription(), "azurerm_eventgrid_topic": resourceArmEventGridTopic(), - "azurerm_eventhub": resourceArmEventHub(), "azurerm_eventhub_authorization_rule": resourceArmEventHubAuthorizationRule(), "azurerm_eventhub_consumer_group": resourceArmEventHubConsumerGroup(), - "azurerm_eventhub_namespace": resourceArmEventHubNamespace(), "azurerm_eventhub_namespace_authorization_rule": resourceArmEventHubNamespaceAuthorizationRule(), - "azurerm_express_route_circuit": resourceArmExpressRouteCircuit(), + "azurerm_eventhub_namespace": resourceArmEventHubNamespace(), + "azurerm_eventhub": resourceArmEventHub(), "azurerm_express_route_circuit_authorization": resourceArmExpressRouteCircuitAuthorization(), "azurerm_express_route_circuit_peering": resourceArmExpressRouteCircuitPeering(), - "azurerm_firewall": resourceArmFirewall(), + "azurerm_express_route_circuit": resourceArmExpressRouteCircuit(), + "azurerm_firewall_application_rule_collection": resourceArmFirewallApplicationRuleCollection(), "azurerm_firewall_network_rule_collection": resourceArmFirewallNetworkRuleCollection(), + "azurerm_firewall": resourceArmFirewall(), "azurerm_function_app": resourceArmFunctionApp(), "azurerm_image": resourceArmImage(), - "azurerm_iothub": resourceArmIotHub(), "azurerm_iothub_consumer_group": resourceArmIotHubConsumerGroup(), - "azurerm_key_vault": resourceArmKeyVault(), + "azurerm_iothub": resourceArmIotHub(), "azurerm_key_vault_access_policy": resourceArmKeyVaultAccessPolicy(), "azurerm_key_vault_certificate": resourceArmKeyVaultCertificate(), "azurerm_key_vault_key": resourceArmKeyVaultKey(), "azurerm_key_vault_secret": resourceArmKeyVaultSecret(), + "azurerm_key_vault": resourceArmKeyVault(), "azurerm_kubernetes_cluster": resourceArmKubernetesCluster(), - "azurerm_lb": resourceArmLoadBalancer(), "azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(), - "azurerm_lb_nat_rule": resourceArmLoadBalancerNatRule(), "azurerm_lb_nat_pool": resourceArmLoadBalancerNatPool(), + "azurerm_lb_nat_rule": resourceArmLoadBalancerNatRule(), "azurerm_lb_probe": resourceArmLoadBalancerProbe(), + "azurerm_lb_outbound_rule": resourceArmLoadBalancerOutboundRule(), "azurerm_lb_rule": resourceArmLoadBalancerRule(), + "azurerm_lb": resourceArmLoadBalancer(), "azurerm_local_network_gateway": resourceArmLocalNetworkGateway(), "azurerm_log_analytics_solution": resourceArmLogAnalyticsSolution(), - "azurerm_log_analytics_workspace": resourceArmLogAnalyticsWorkspace(), + "azurerm_log_analytics_linked_service": resourceArmLogAnalyticsLinkedService(), "azurerm_log_analytics_workspace_linked_service": resourceArmLogAnalyticsWorkspaceLinkedService(), + "azurerm_log_analytics_workspace": resourceArmLogAnalyticsWorkspace(), "azurerm_logic_app_action_custom": resourceArmLogicAppActionCustom(), "azurerm_logic_app_action_http": resourceArmLogicAppActionHTTP(), "azurerm_logic_app_trigger_custom": resourceArmLogicAppTriggerCustom(), @@ -265,24 +273,30 @@ func Provider() terraform.ResourceProvider { "azurerm_logic_app_trigger_recurrence": resourceArmLogicAppTriggerRecurrence(), "azurerm_logic_app_workflow": resourceArmLogicAppWorkflow(), "azurerm_managed_disk": resourceArmManagedDisk(), - "azurerm_management_lock": resourceArmManagementLock(), "azurerm_management_group": resourceArmManagementGroup(), + "azurerm_management_lock": resourceArmManagementLock(), + "azurerm_mariadb_database": resourceArmMariaDbDatabase(), + "azurerm_mariadb_server": resourceArmMariaDbServer(), + "azurerm_media_services_account": resourceArmMediaServicesAccount(), "azurerm_metric_alertrule": resourceArmMetricAlertRule(), + "azurerm_monitor_autoscale_setting": resourceArmMonitorAutoScaleSetting(), "azurerm_monitor_action_group": resourceArmMonitorActionGroup(), "azurerm_monitor_activity_log_alert": resourceArmMonitorActivityLogAlert(), "azurerm_monitor_diagnostic_setting": resourceArmMonitorDiagnosticSetting(), "azurerm_monitor_log_profile": resourceArmMonitorLogProfile(), "azurerm_monitor_metric_alert": resourceArmMonitorMetricAlert(), + "azurerm_monitor_metric_alertrule": resourceArmMonitorMetricAlertRule(), + "azurerm_mssql_elasticpool": resourceArmMsSqlElasticPool(), "azurerm_mysql_configuration": resourceArmMySQLConfiguration(), "azurerm_mysql_database": resourceArmMySqlDatabase(), "azurerm_mysql_firewall_rule": resourceArmMySqlFirewallRule(), "azurerm_mysql_server": resourceArmMySqlServer(), "azurerm_mysql_virtual_network_rule": resourceArmMySqlVirtualNetworkRule(), - "azurerm_network_interface": resourceArmNetworkInterface(), "azurerm_network_interface_application_gateway_backend_address_pool_association": resourceArmNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation(), "azurerm_network_interface_application_security_group_association": resourceArmNetworkInterfaceApplicationSecurityGroupAssociation(), "azurerm_network_interface_backend_address_pool_association": resourceArmNetworkInterfaceBackendAddressPoolAssociation(), "azurerm_network_interface_nat_rule_association": resourceArmNetworkInterfaceNatRuleAssociation(), + "azurerm_network_interface": resourceArmNetworkInterface(), "azurerm_network_security_group": resourceArmNetworkSecurityGroup(), "azurerm_network_security_rule": resourceArmNetworkSecurityRule(), "azurerm_network_watcher": resourceArmNetworkWatcher(), From d4f836dc7aa78cfc46751b3431a785a384781c23 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 6 Mar 2019 16:17:48 +0100 Subject: [PATCH 37/38] Fixing the failing test --- azurerm/data_source_api_management_api_test.go | 4 ++-- azurerm/resource_arm_api_management_api.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index 77ccf3e2541a..8d825d71c661 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -22,9 +22,9 @@ func TestAccDataSourceAzureRMApiManagementApi_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(dataSourceName, "display_name", "api1"), resource.TestCheckResourceAttr(dataSourceName, "path", "api1"), - resource.TestCheckResourceAttr(dataSourceName, "protocols.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "protocols.#", "1"), resource.TestCheckResourceAttr(dataSourceName, "protocols.0", "https"), - resource.TestCheckResourceAttr(dataSourceName, "soap_pass_through", "true"), + resource.TestCheckResourceAttr(dataSourceName, "soap_pass_through", "false"), resource.TestCheckResourceAttr(dataSourceName, "is_current", "true"), resource.TestCheckResourceAttr(dataSourceName, "is_online", "false"), ), diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index 94afcba2a6c1..a31bb1a22493 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -144,8 +144,8 @@ func resourceArmApiManagementApi() *schema.Resource { "soap_pass_through": { Type: schema.TypeBool, - Default: false, Optional: true, + Default: false, }, // Computed From bee4eca35d8022f32647130549b4f94b36aff37e Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 15 Mar 2019 16:26:01 +0100 Subject: [PATCH 38/38] r/api_management_api: additional validation / making revision a string --- azurerm/data_source_api_management_api.go | 20 ++----- .../data_source_api_management_api_test.go | 2 +- azurerm/resource_arm_api_management_api.go | 60 +++++++++---------- .../resource_arm_api_management_api_test.go | 55 +++++++++++++++-- .../docs/d/api_management_api.html.markdown | 2 +- .../docs/r/api_management_api.html.markdown | 4 +- 6 files changed, 88 insertions(+), 55 deletions(-) diff --git a/azurerm/data_source_api_management_api.go b/azurerm/data_source_api_management_api.go index cdd7a10f2f6a..22697e8fd255 100644 --- a/azurerm/data_source_api_management_api.go +++ b/azurerm/data_source_api_management_api.go @@ -2,7 +2,6 @@ package azurerm import ( "fmt" - "strconv" "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2018-01-01/apimanagement" "github.com/hashicorp/terraform/helper/schema" @@ -27,8 +26,9 @@ func dataSourceApiManagementApi() *schema.Resource { "resource_group_name": resourceGroupNameForDataSourceSchema(), "revision": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, }, "description": { @@ -111,9 +111,9 @@ func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) er resourceGroup := d.Get("resource_group_name").(string) serviceName := d.Get("api_management_name").(string) name := d.Get("name").(string) - revision := d.Get("revision").(int) + revision := d.Get("revision").(string) - apiId := fmt.Sprintf("%s;rev=%d", name, revision) + apiId := fmt.Sprintf("%s;rev=%s", name, revision) resp, err := client.Get(ctx, resourceGroup, serviceName, apiId) if err != nil { if utils.ResponseWasNotFound(resp.Response) { @@ -135,20 +135,12 @@ func dataSourceApiManagementApiRead(d *schema.ResourceData, meta interface{}) er d.Set("is_current", props.IsCurrent) d.Set("is_online", props.IsOnline) d.Set("path", props.Path) + d.Set("revision", props.APIRevision) d.Set("service_url", props.ServiceURL) d.Set("soap_pass_through", string(props.APIType) == string(apimanagement.SoapPassThrough)) d.Set("version", props.APIVersion) d.Set("version_set_id", props.APIVersionSetID) - if apiR := props.APIRevision; apiR != nil { - i, err := strconv.Atoi(*apiR) - if err != nil { - return fmt.Errorf("Error casting %q to an integer: %s", *apiR, err) - } - - d.Set("revision", i) - } - if err := d.Set("protocols", flattenApiManagementApiDataSourceProtocols(props.Protocols)); err != nil { return fmt.Errorf("Error setting `protocols`: %s", err) } diff --git a/azurerm/data_source_api_management_api_test.go b/azurerm/data_source_api_management_api_test.go index 8d825d71c661..c139e058108a 100644 --- a/azurerm/data_source_api_management_api_test.go +++ b/azurerm/data_source_api_management_api_test.go @@ -48,7 +48,7 @@ func TestAccDataSourceAzureRMApiManagementApi_complete(t *testing.T) { resource.TestCheckResourceAttr(dataSourceName, "display_name", "Butter Parser"), resource.TestCheckResourceAttr(dataSourceName, "path", "butter-parser"), resource.TestCheckResourceAttr(dataSourceName, "protocols.#", "2"), - resource.TestCheckResourceAttr(dataSourceName, "description", "What is my purpose? You pass butter."), + resource.TestCheckResourceAttr(dataSourceName, "description", "What is my purpose? You parse butter."), resource.TestCheckResourceAttr(dataSourceName, "service_url", "https://example.com/foo/bar"), resource.TestCheckResourceAttr(dataSourceName, "soap_pass_through", "false"), resource.TestCheckResourceAttr(dataSourceName, "subscription_key_parameter_names.0.header", "X-Butter-Robot-API-Key"), diff --git a/azurerm/resource_arm_api_management_api.go b/azurerm/resource_arm_api_management_api.go index a31bb1a22493..d7a1347084b5 100644 --- a/azurerm/resource_arm_api_management_api.go +++ b/azurerm/resource_arm_api_management_api.go @@ -3,7 +3,6 @@ package azurerm import ( "fmt" "log" - "strconv" "strings" "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2018-01-01/apimanagement" @@ -38,8 +37,9 @@ func resourceArmApiManagementApi() *schema.Resource { "resource_group_name": resourceGroupNameSchema(), "display_name": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, }, "path": { @@ -61,9 +61,10 @@ func resourceArmApiManagementApi() *schema.Resource { }, "revision": { - Type: schema.TypeInt, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, }, // Optional @@ -79,9 +80,11 @@ func resourceArmApiManagementApi() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "content_value": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, }, + "content_format": { Type: schema.TypeString, Required: true, @@ -102,13 +105,15 @@ func resourceArmApiManagementApi() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "service_name": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, }, "endpoint_name": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, }, }, }, @@ -131,12 +136,14 @@ func resourceArmApiManagementApi() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "header": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, }, "query": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, }, }, }, @@ -179,9 +186,9 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf resourceGroup := d.Get("resource_group_name").(string) serviceName := d.Get("api_management_name").(string) name := d.Get("name").(string) - revision := int32(d.Get("revision").(int)) + revision := d.Get("revision").(string) path := d.Get("path").(string) - apiId := fmt.Sprintf("%s;rev=%d", name, revision) + apiId := fmt.Sprintf("%s;rev=%s", name, revision) if requireResourcesToBeImported && d.IsNewResource() { existing, err := client.Get(ctx, resourceGroup, serviceName, apiId) @@ -259,18 +266,17 @@ func resourceArmApiManagementApiCreateUpdate(d *schema.ResourceData, meta interf }, } - revisionStr := strconv.Itoa(int(revision)) if _, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, apiId, params, ""); err != nil { - return fmt.Errorf("Error creating/updating API %q / Revision %q (API Management Service %q / Resource Group %q): %+v", name, revisionStr, serviceName, resourceGroup, err) + return fmt.Errorf("Error creating/updating API %q / Revision %q (API Management Service %q / Resource Group %q): %+v", name, revision, serviceName, resourceGroup, err) } read, err := client.Get(ctx, resourceGroup, serviceName, apiId) if err != nil { - return fmt.Errorf("Error retrieving API %q / Revision %q (API Management Service %q / Resource Group %q): %+v", name, revisionStr, serviceName, resourceGroup, err) + return fmt.Errorf("Error retrieving API %q / Revision %q (API Management Service %q / Resource Group %q): %+v", name, revision, serviceName, resourceGroup, err) } if read.ID == nil { - return fmt.Errorf("Cannot read ID for API %q / Revision %q (API Management Service %q / Resource Group %q)", name, revisionStr, serviceName, resourceGroup) + return fmt.Errorf("Cannot read ID for API %q / Revision %q (API Management Service %q / Resource Group %q)", name, revision, serviceName, resourceGroup) } d.SetId(*read.ID) @@ -319,19 +325,11 @@ func resourceArmApiManagementApiRead(d *schema.ResourceData, meta interface{}) e d.Set("is_online", props.IsOnline) d.Set("path", props.Path) d.Set("service_url", props.ServiceURL) + d.Set("revision", props.APIRevision) d.Set("soap_pass_through", string(props.APIType) == string(apimanagement.SoapPassThrough)) d.Set("version", props.APIVersion) d.Set("version_set_id", props.APIVersionSetID) - if apiR := props.APIRevision; apiR != nil { - i, err := strconv.Atoi(*apiR) - if err != nil { - return fmt.Errorf("Error casting %q to an integer: %s", *apiR, err) - } - - d.Set("revision", i) - } - if err := d.Set("protocols", flattenApiManagementApiProtocols(props.Protocols)); err != nil { return fmt.Errorf("Error setting `protocols`: %s", err) } diff --git a/azurerm/resource_arm_api_management_api_test.go b/azurerm/resource_arm_api_management_api_test.go index 3654d27fdcd1..02072c3f670a 100644 --- a/azurerm/resource_arm_api_management_api_test.go +++ b/azurerm/resource_arm_api_management_api_test.go @@ -38,6 +38,32 @@ func TestAccAzureRMApiManagementApi_basic(t *testing.T) { }) } +func TestAccAzureRMApiManagementApi_wordRevision(t *testing.T) { + resourceName := "azurerm_api_management_api.test" + ri := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApiManagementApiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagementApi_wordRevision(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementApiExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "revision", "one-point-oh"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAzureRMApiManagementApi_requiresImport(t *testing.T) { if !requireResourcesToBeImported { t.Skip("Skipping since resources aren't required to be imported") @@ -291,7 +317,24 @@ resource "azurerm_api_management_api" "test" { display_name = "api1" path = "api1" protocols = ["https"] - revision = 1 + revision = "1" +} +`, template, rInt) +} + +func testAccAzureRMApiManagementApi_wordRevision(rInt int, location string) string { + template := testAccAzureRMApiManagementApi_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_api" "test" { + name = "acctestapi-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + display_name = "api1" + path = "api1" + protocols = ["https"] + revision = "one-point-oh" } `, template, rInt) } @@ -308,7 +351,7 @@ resource "azurerm_api_management_api" "test" { display_name = "api1" path = "api1" protocols = ["https"] - revision = 1 + revision = "1" soap_pass_through = true } `, template, rInt) @@ -343,7 +386,7 @@ resource "azurerm_api_management_api" "test" { display_name = "api1" path = "api1" protocols = ["https"] - revision = 1 + revision = "1" import { content_value = "${file("testdata/api_management_api_swagger.json")}" @@ -365,7 +408,7 @@ resource "azurerm_api_management_api" "test" { display_name = "api1" path = "api1" protocols = ["https"] - revision = 1 + revision = "1" import { content_value = "${file("testdata/api_management_api_wsdl.xml")}" @@ -392,8 +435,8 @@ resource "azurerm_api_management_api" "test" { display_name = "Butter Parser" path = "butter-parser" protocols = ["https", "http"] - revision = 3 - description = "What is my purpose? You pass butter." + revision = "3" + description = "What is my purpose? You parse butter." service_url = "https://example.com/foo/bar" subscription_key_parameter_names { diff --git a/website/docs/d/api_management_api.html.markdown b/website/docs/d/api_management_api.html.markdown index 98652f34d5c4..71ba63306ee6 100644 --- a/website/docs/d/api_management_api.html.markdown +++ b/website/docs/d/api_management_api.html.markdown @@ -33,7 +33,7 @@ output "api_management_api_id" { * `resource_group_name` - (Required) The Name of the Resource Group in which the API Management Service exists. -* `revision` - (Required) The Revision number of the API Management API. +* `revision` - (Required) The Revision of the API Management API. ## Attributes Reference diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index 80347ae3b40a..c54c81aa4dd0 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -35,7 +35,7 @@ resource "azurerm_api_management_api" "test" { name = "example-api" resource_group_name = "${azurerm_resource_group.test.name}" api_management_name = "${azurerm_api_management.test.name}" - revision = 1 + revision = "1" display_name = "Example API" path = "example" protocols = ["https"] @@ -57,7 +57,7 @@ The following arguments are supported: * `resource_group_name` - (Required) The Name of the Resource Group where the API Management API exists. Changing this forces a new resource to be created. -* `revision` - (Required) The Revision number used for this API. +* `revision` - (Required) The Revision which used for this API. * `display_name` - (Required) The display name of the API.