Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Management - Cannot add a revision to an existing API #12720

Closed
Berbe opened this issue Jul 23, 2021 · 14 comments · Fixed by #23031
Closed

API Management - Cannot add a revision to an existing API #12720

Berbe opened this issue Jul 23, 2021 · 14 comments · Fixed by #23031

Comments

@Berbe
Copy link

Berbe commented Jul 23, 2021

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Terraform (and AzureRM Provider) Version

Terraform v1.0.3
on linux_amd64
+ provider registry.terraform.io/hashicorp/azurerm v2.69.0
+ provider registry.terraform.io/hashicorp/template v2.2.0

Affected Resource(s)

  • azurerm_api_management_api

Terraform Configuration Files

Based on an existing revision:

resource "azurerm_api_management_api" "example" {
  name                = "example"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  display_name        = "example"
  path                = "example"
  revision            = "1"
  protocols           = [
    "https",
  ]
  service_url         = "https://example.org"

  import {
    content_format = "openapi+json"
    content_value  = file("${path.module}/example.json")
  }
}

, create a new one:

resource "azurerm_api_management_api" "example_2" {
  name                = "example"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  display_name        = "example"
  path                = "example"
  revision            = "2"
  protocols           = [
    "https",
  ]
  service_url         = "https://example.org"

  import {
    content_format = "openapi+json"
    content_value  = file("${path.module}/example.json")
  }
}

Expected Behaviour

Revision 2 created alongside 1

Actual Behaviour

Error: waiting on creating/updating API Management API "example" (Resource Group "example"): Future#WaitForCompletion: the number of retries has been exceeded: StatusCode=400 -- Original Error: Code="ValidationError" Message="Can't change property Name for non-current revision "

Steps to Reproduce

  1. terraform apply

Additional information

If you try to create both at once, ie with:

resource "azurerm_api_management_api" "example" {
  name                = "example"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  display_name        = "example"
  path                = "example"
  revision            = "1"
  protocols           = [
    "https",
  ]
  service_url         = "https://example.org"

  import {
    content_format = "openapi+json"
    content_value  = file("${path.module}/example.json")
  }
}

resource "azurerm_api_management_api" "example_2" {
  name                = "example"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  display_name        = "example"
  path                = "example"
  revision            = "2"
  protocols           = [
    "https",
  ]
  service_url         = "https://example.org"

  import {
    content_format = "openapi+json"
    content_value  = file("${path.module}/example.json")
  }
}
}

, it works!
Revisions 1 & 2 are created.

@yupwei68
Copy link
Contributor

Hi @Berbe , thanks for opening this issue.
I think you could create a new revision from an existing revision like the example here https://github.com/terraform-providers/terraform-provider-azurerm/blob/master/azurerm/internal/services/apimanagement/api_management_api_resource_test.go#L664.

resource "azurerm_api_management_api" "revision" {
  name                 = "acctestRevision-%d"
  resource_group_name  = azurerm_resource_group.test.name
  api_management_name  = azurerm_api_management.test.name
  revision             = "18"
  source_api_id        = "${azurerm_api_management_api.test.id};rev=3"
  revision_description = "Creating a Revision of an existing API"
}

@Berbe
Copy link
Author

Berbe commented Jul 26, 2021

If I try the following:

resource "azurerm_api_management_api" "example_2" {
  name                = "example"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  revision            = "2"
  service_url         = "https://example.org"
  source_api_id       = "${azurerm_api_management_api.example.id};rev=1"

  import {
    content_format = "openapi+json"
    content_value  = file("${path.module}/example.json")
  }
}

I end up with:

Future#WaitForCompletion: the number of retries has been exceeded: StatusCode=400 -- Original Error: Code="ValidationError" Message="One or more fields contain incorrect values:" Details=[{"code":"ValidationError","message":"Cannot create API 'example' with the same Path '' as API '***'  unless it's a part of the same version set","target":"path"}

source_api_id hence does not replace the path property.

If I try:

resource "azurerm_api_management_api" "example_2" {
  name                = "example_2"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  revision            = "2"
  path                = "example"
  service_url         = "https://example.org"
  source_api_id       = "${azurerm_api_management_api.example.id};rev=1"

  import {
    content_format = "openapi+json"
    content_value  = file("${path.module}/example.json")
  }
}

I end up with:

Future#WaitForCompletion: the number of retries has been exceeded: StatusCode=400 -- Original Error: Code="ValidationError" Message="One or more fields contain incorrect values:" Details=[{"code":"ValidationError","message":"Cannot create API 'example_2' with the same Path 'example' as API 'example'  unless it's a part of the same version set","target":"path"}]

Of course, trying:

resource "azurerm_api_management_api" "example_2" {
  name                = "example"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  revision            = "2"
  path                = "example"
  service_url         = "https://example.org"
  source_api_id       = "${azurerm_api_management_api.example.id};rev=1"

  import {
    content_format = "openapi+json"
    content_value  = file("${path.module}/example.json")
  }
}

gives me the exact same error as the one provided in my original post:

Future#WaitForCompletion: the number of retries has been exceeded: StatusCode=400 -- Original Error: Code="ValidationError" Message="Can't change property Name for non-current revision "

source_api_id does not seem to be of any help here as I eventually fall back on the original error, and it is kind of a relief anyway, as it's an optional directive. As my tests show, this directive does not even seem to be self-sufficient to fully describe an API based on another one.
Maybe a bug report shall be filled for this defect, but this is beyond the scope of this particular issue. @yupwei68 If you're interested in it, I'll let you deal with it.

I am so confused...

Trying to sum up all that has been tried and advised goes down to this: defining revisions all-at-once or separately produce different results.
This feels wrong, as Terraform configuration is supposed to be deterministic, not contextually based: it should use its own state to decide what needs to be done in order to reach the aforementioned determined state.
Said otherwise, the same configuration applied to different contexts might involve different actions, but that's the deal with deterministic tools: they should handle variations themselves.

Going back to the original issue description, how come the same configuration applied to different contexts does not yield the same results?

@Berbe
Copy link
Author

Berbe commented Jul 28, 2021

OK I think I got a lead.

The problematic part was the import block.
Without it, I am able to create a revision:

resource "azurerm_api_management_api" "example_2" {
  name                = "example"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  revision            = "2"
  display_name        = "example"
  path                = "example"
  service_url         = "https://example"
  protocols           = [
    "https",
  ]

Of course, it also works with the alternative definition format, source_api_id merely replacing display_name & protocols:

resource "azurerm_api_management_api" "example_2" {
  name                = "example"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  revision            = "2"
  path                = "example"
  service_url         = "https://example.org"
  source_api_id       = "${azurerm_api_management_api.example.id};rev=1"
}

The problem here is that, depending on whether you are creating the first revision of an API or not, the configuration you shall provide needs to be different.
This hurts automated Terraform configuration generation.

Is there a way to enhance import blocks support to allow them to be defined in multiple azurerm_api_management_api for several revisions of the same API while actually only be tied to a single revision/applied once?

@axk511

This comment was marked as off-topic.

@axk511
Copy link

axk511 commented Sep 28, 2021

@yupwei68

Issue here is - revisions are supposed to help us add non-breaking changes to API's - like adding an operation to existing API.
Since the current version of terraform errors out when using below section, it does not allow us to add new open api spec and new policy to it.
This defeats the purpose of revisions

import {
content_format = "openapi+json"
content_value = file("${path.module}/example.json")
}

Here is the link to revisions from microsoft docs
https://docs.microsoft.com/en-us/azure/api-management/api-management-get-started-revise-api?tabs=azure-portal

@Firenza

This comment was marked as off-topic.

@aaronmottmac

This comment was marked as off-topic.

@ZeChArtiahSaher

This comment was marked as off-topic.

@Firenza

This comment was marked as off-topic.

@mnemcik-visma

This comment was marked as off-topic.

@taksan

This comment was marked as off-topic.

@Apostolos-Daniel
Copy link

What's the latest on this issue? I've reproduced the fact that revisions cannot be created (and updated to current). Are there plans to implement this?

See example code

@rcskosir
Copy link
Contributor

Updating PR linking for this issue - PR #22380 has been superseded by #23031.

Copy link

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 26, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.