diff --git a/internal/services/apimanagement/api_management_api_release.go b/internal/services/apimanagement/api_management_api_release.go index 2a4a67f79bc9..8c393b0ac4cf 100644 --- a/internal/services/apimanagement/api_management_api_release.go +++ b/internal/services/apimanagement/api_management_api_release.go @@ -75,9 +75,7 @@ func resourceApiManagementApiReleaseCreateUpdate(d *pluginsdk.ResourceData, meta return err } - apiName := getApiName(apiId.ApiId) - - id := apirelease.NewReleaseID(subscriptionId, apiId.ResourceGroupName, apiId.ServiceName, apiName, name) + id := apirelease.NewReleaseID(subscriptionId, apiId.ResourceGroupName, apiId.ServiceName, apiId.ApiId, name) ifMatch := "*" if d.IsNewResource() { @@ -131,8 +129,7 @@ func resourceApiManagementApiReleaseRead(d *pluginsdk.ResourceData, meta interfa d.Set("name", id.ReleaseId) if model := resp.Model; model != nil { if props := model.Properties; props != nil { - apiName := getApiName(id.ApiId) - d.Set("api_id", api.NewApiID(subscriptionId, id.ResourceGroupName, id.ServiceName, apiName).ID()) + d.Set("api_id", api.NewApiID(subscriptionId, id.ResourceGroupName, id.ServiceName, id.ApiId).ID()) d.Set("notes", pointer.From(props.Notes)) } } diff --git a/internal/services/apimanagement/api_management_api_resource.go b/internal/services/apimanagement/api_management_api_resource.go index d89657647d8c..ae2c89efe320 100644 --- a/internal/services/apimanagement/api_management_api_resource.go +++ b/internal/services/apimanagement/api_management_api_resource.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/features" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/schemaz" "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -41,6 +42,11 @@ func resourceApiManagementApi() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(30 * time.Minute), }, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.ApiV0ToV1{}, + }), + Schema: map[string]*pluginsdk.Schema{ "name": schemaz.SchemaApiManagementApiName(), @@ -351,8 +357,6 @@ func resourceApiManagementApiCreateUpdate(d *pluginsdk.ResourceData, meta interf ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id := api.NewApiID(subscriptionId, d.Get("resource_group_name").(string), d.Get("api_management_name").(string), d.Get("name").(string)) - revision := d.Get("revision").(string) path := d.Get("path").(string) apiId := fmt.Sprintf("%s;rev=%s", d.Get("name").(string), revision) @@ -363,6 +367,8 @@ func resourceApiManagementApiCreateUpdate(d *pluginsdk.ResourceData, meta interf protocols := expandApiManagementApiProtocols(protocolsRaw) sourceApiId := d.Get("source_api_id").(string) + id := api.NewApiID(subscriptionId, d.Get("resource_group_name").(string), d.Get("api_management_name").(string), apiId) + if version != "" && versionSetId == "" { return fmt.Errorf("setting `version` without the required `version_set_id`") } @@ -412,12 +418,11 @@ func resourceApiManagementApiCreateUpdate(d *pluginsdk.ResourceData, meta interf log.Printf("[DEBUG] Importing API Management API %q of type %q", id.ApiId, contentFormat) apiParams := api.ApiCreateOrUpdateParameter{ Properties: &api.ApiCreateOrUpdateProperties{ - Type: pointer.To(apiType), - ApiType: pointer.To(soapApiType), - Format: pointer.To(api.ContentFormat(contentFormat)), - Value: pointer.To(contentValue), - Path: path, - ApiVersion: pointer.To(version), + Type: pointer.To(apiType), + ApiType: pointer.To(soapApiType), + Format: pointer.To(api.ContentFormat(contentFormat)), + Value: pointer.To(contentValue), + Path: path, }, } wsdlSelectorVs := importV["wsdl_selector"].([]interface{}) @@ -433,6 +438,10 @@ func resourceApiManagementApiCreateUpdate(d *pluginsdk.ResourceData, meta interf } } + if version != "" { + apiParams.Properties.ApiVersion = pointer.To(version) + } + if versionSetId != "" { apiParams.Properties.ApiVersionSetId = pointer.To(versionSetId) } @@ -474,7 +483,6 @@ func resourceApiManagementApiCreateUpdate(d *pluginsdk.ResourceData, meta interf Protocols: protocols, ServiceUrl: pointer.To(serviceUrl), SubscriptionKeyParameterNames: subscriptionKeyParameterNames, - ApiVersion: pointer.To(version), SubscriptionRequired: &subscriptionRequired, AuthenticationSettings: authenticationSettings, ApiRevisionDescription: pointer.To(d.Get("revision_description").(string)), @@ -490,6 +498,11 @@ func resourceApiManagementApiCreateUpdate(d *pluginsdk.ResourceData, meta interf if displayName != "" { params.Properties.DisplayName = pointer.To(displayName) } + + if version != "" { + params.Properties.ApiVersion = pointer.To(version) + } + if versionSetId != "" { params.Properties.ApiVersionSetId = pointer.To(versionSetId) } @@ -516,21 +529,19 @@ func resourceApiManagementApiRead(d *pluginsdk.ResourceData, meta interface{}) e return err } - name := getApiName(id.ApiId) - newId := api.NewApiID(id.SubscriptionId, id.ResourceGroupName, id.ServiceName, name) - resp, err := client.Get(ctx, newId) + resp, err := client.Get(ctx, *id) if err != nil { if response.WasNotFound(resp.HttpResponse) { - log.Printf("[INFO] %s does not exist - removing from state", newId) + log.Printf("[INFO] %s does not exist - removing from state", id) d.SetId("") return nil } - return fmt.Errorf("retrieving %s: %+v", newId, err) + return fmt.Errorf("retrieving %s: %+v", id, err) } d.Set("api_management_name", id.ServiceName) - d.Set("name", name) + d.Set("name", getApiName(id.ApiId)) d.Set("resource_group_name", id.ResourceGroupName) if model := resp.Model; model != nil { @@ -595,12 +606,9 @@ func resourceApiManagementApiDelete(d *pluginsdk.ResourceData, meta interface{}) return err } - name := getApiName(id.ApiId) - - newId := api.NewApiID(id.SubscriptionId, id.ResourceGroupName, id.ServiceName, name) - if resp, err := client.Delete(ctx, newId, api.DeleteOperationOptions{DeleteRevisions: pointer.To(true)}); err != nil { + if resp, err := client.Delete(ctx, *id, api.DefaultDeleteOperationOptions()); err != nil { if !response.WasNotFound(resp.HttpResponse) { - return fmt.Errorf("deleting %s: %+v", newId, err) + return fmt.Errorf("deleting %s: %+v", id, err) } } diff --git a/internal/services/apimanagement/migration/api_v0_to_v1.go b/internal/services/apimanagement/migration/api_v0_to_v1.go new file mode 100644 index 000000000000..d9910a1faf9e --- /dev/null +++ b/internal/services/apimanagement/migration/api_v0_to_v1.go @@ -0,0 +1,279 @@ +package migration + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/schemaz" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +var _ pluginsdk.StateUpgrade = ApiV0ToV1{} + +type ApiV0ToV1 struct{} + +func (ApiV0ToV1) Schema() map[string]*pluginsdk.Schema { + schema := map[string]*pluginsdk.Schema{ + "name": schemaz.SchemaApiManagementApiName(), + + "api_management_name": schemaz.SchemaApiManagementName(), + + "resource_group_name": commonschema.ResourceGroupName(), + + "display_name": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + }, + + "path": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + }, + + "protocols": { + Type: pluginsdk.TypeSet, + Optional: true, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "revision": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "revision_description": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + // Optional + "api_type": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + }, + + "contact": { + Type: pluginsdk.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "email": { + Type: pluginsdk.TypeString, + Optional: true, + }, + "name": { + Type: pluginsdk.TypeString, + Optional: true, + }, + "url": { + Type: pluginsdk.TypeString, + Optional: true, + }, + }, + }, + }, + + "description": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "import": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "content_value": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "content_format": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "wsdl_selector": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "service_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "endpoint_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + + "license": { + Type: pluginsdk.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Optional: true, + }, + "url": { + Type: pluginsdk.TypeString, + Optional: true, + }, + }, + }, + }, + + "service_url": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + }, + + "subscription_key_parameter_names": { + Type: pluginsdk.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "header": { + Type: pluginsdk.TypeString, + Required: true, + }, + "query": { + Type: pluginsdk.TypeString, + Required: true, + }, + }, + }, + }, + + "subscription_required": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + + "terms_of_service_url": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "source_api_id": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "oauth2_authorization": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "authorization_server_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + "scope": { + Type: pluginsdk.TypeString, + Optional: true, + }, + }, + }, + }, + + "openid_authentication": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "openid_provider_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + "bearer_token_sending_methods": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + }, + }, + }, + + // Computed + "is_current": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "is_online": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "soap_pass_through": { + Type: pluginsdk.TypeBool, + Computed: true, + Optional: true, + }, + + "version": { + Type: pluginsdk.TypeString, + Computed: true, + Optional: true, + }, + + "version_description": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "version_set_id": { + Type: pluginsdk.TypeString, + Computed: true, + Optional: true, + }, + } + + return schema +} + +func (ApiV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + apiId := fmt.Sprintf("%s;rev=%s", rawState["name"].(string), rawState["revision"].(string)) + oldId, err := parse.ApiID(rawState["id"].(string)) + if err != nil { + return rawState, err + } + newId := parse.NewApiID(oldId.SubscriptionId, oldId.ResourceGroup, oldId.ServiceName, apiId).ID() + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + rawState["id"] = newId + return rawState, nil + } +} diff --git a/website/docs/r/api_management_api.html.markdown b/website/docs/r/api_management_api.html.markdown index 3575c8f9d406..221d0f22236b 100644 --- a/website/docs/r/api_management_api.html.markdown +++ b/website/docs/r/api_management_api.html.markdown @@ -192,5 +192,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l API Management API's can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_api_management_api.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.ApiManagement/service/instance1/apis/api1 +terraform import azurerm_api_management_api.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.ApiManagement/service/instance1/apis/api1;rev=1 ```