hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.6k stars 4.65k forks source link

Setting dotnet_version to v6.0 (i.e. DotNet Core) results in unnecessary changes in future deployments #22239

Open Zhaph opened 1 year ago

Zhaph commented 1 year ago

Is there an existing issue for this?

Community Note

Terraform Version

1.5.1

AzureRM Provider Version

3.61.0

Affected Resource(s)/Data Source(s)

azurerm_windows_web_app

Terraform Configuration Files

Start with the following configuration, and apply it to Azure

# Resource Group
resource "azurerm_resource_group" "example" {
  name     = "rg-example"
  location = "westus2"
}

# App Service Plan
resource "azurerm_service_plan" "example" {
  name                = "asp-example"
  resource_group_name = azurerm_resource_group.example.name
  location            = azurerm_resource_group.example.location
  sku_name            = "B1"
  worker_count        = 2
  os_type             = "Windows"
}

# Create web app targeting DotNet Core 6
resource "azurerm_windows_web_app" "web_example" {
  name                      = "git-example-1" # Will need to update to unique value
  resource_group_name       = azurerm_resource_group.rg_example.name
  location                  = azurerm_resource_group.rg_example.location
  service_plan_id           = azurerm_service_plan.asp_example.id

  site_config {
    application_stack {
      current_stack  = "dotnetcore"
      dotnet_version = "v6.0"
      #dotnet_core_version = "v6.0" # will error here.
    }
  }
}

Then, update the web app configuration, for example:

# Create web app targeting DotNet Core 6
resource "azurerm_windows_web_app" "web_example" {
  name                      = "git-example-1" # Will need to update to unique value
  resource_group_name       = azurerm_resource_group.rg_example.name
  location                  = azurerm_resource_group.rg_example.location
  service_plan_id           = azurerm_service_plan.asp_example.id

  site_config {
    application_stack {
      current_stack  = "dotnetcore"
      dotnet_version = "v6.0"
      #dotnet_core_version = "v6.0" # will error here.
    }
    ftps_state          = "Disabled"
    http2_enabled       = true
    minimum_tls_version = "1.2"
  }
}

And plan the changes.

Debug Output/Panic Output

[33m~[0m[0m application_stack {
  [31m-[0m[0m dotnet_core_version          = "v6.0" [90m-> null[0m[0m
  [32m+[0m[0m dotnet_version               = "v6.0"
    [90m# (4 unchanged attributes hidden)[0m[0m
}

Expected Behaviour

The dotnet_version and dotnet_core_version shouldn't be changing as part of this update.

However, attempting to set the dotnet_core_version to v6.0 (either initially or as part of an update) results in the following error:

╷
│ Error: expected site_config.0.application_stack.0.dotnet_core_version to be one of [v4.0], got v6.0
│ 
│   with azurerm_windows_web_app.web_si,
│   on [webs.tf](https://bitbucket.org/intermountainhealthcare/tfp-ih-sitecore-tst/src/362e6eb8448358478c98981486210ac9ffda4718/webs.tf) line 52, in resource "azurerm_windows_web_app" "web_si":
│   52:       dotnet_core_version = "v6.0"
│ 
╵

I know that the doc's state that I should be setting this on dotnet_version however when I do that, subsequent runs (i.e. drift controls, updates to other resources in the config) result in the following statements in the plan:

          [33m~[0m[0m application_stack {
              [31m-[0m[0m dotnet_core_version          = "v6.0" [90m-> null[0m[0m
              [32m+[0m[0m dotnet_version               = "v6.0"
                [90m# (4 unchanged attributes hidden)[0m[0m
            }

I.e. the platform has moved the value from dotnet_version onto dotnet_core_version and Terraform will then attempt to set it back to null and reset the dotnet_version to v6.0

This configuration change will either cause an app restart during what should be a non-event, or be ignored by the platform, but the Terraform state is clearly out of step with reality.

Actual Behaviour

I have to create the web app with dotnet_version = "v4.0" however this results in changes during drift control and subsequent deployments to other areas within the configuration.

This will result in unnecessary changes being made, and potential application restarts if the configuration is actually changed.

Steps to Reproduce

  1. terraform apply

  2. terraform plan -out=plan.tfplan

Confirm that there are

Important Factoids

No response

References

No response

Zhaph commented 1 year ago

I've actually been able to reproduce, please see the updated notes above.

xiaxyi commented 1 year ago

Hi @Zhaph Thanks for raising this issue. The supported dotnet core version is v4.0 as mentioned in our official [documents] image

Dotnet core is deprecated since 12/13/2022, please use dotnet_version to set the 6.0 dotnet app stack.

Feel free to let me know if you have any questions.

Zhaph commented 1 year ago

The question is: why am I seeing a battle in the plan to move the version into and out of dotnetcoreversion?

ekasprzak commented 1 year ago

Dotnet core is deprecated since 12/13/2022, please use dotnet_version to set the 6.0 dotnet app stack.

Hi, maybe this should be added into docs? (It wasn't obvious for me until I found this issue).

Phiph commented 1 year ago

I've noticed this too, and my plans looking to change the values on each deployment.

fishfacemcgee commented 12 months ago

It seems like there's an issue with how the provider is parsing values from Azure's API. I imported a pre-existing Windows Web App, and the original values were:

            application_stack {
                current_stack                = "dotnetcore"
                docker_registry_password     = (sensitive value)
                dotnet_core_version          = "v6.0"
                java_embedded_server_enabled = false
                php_version                  = "5.6"
                python                       = false
            }

Which according to @xiaxyi is an invalid configuration due to dotnetcore being a deprecated value for current_stack and dotnet_core_version's only valid value being v4.0. And yet, those are the values that are imported. Not to mention php_version not being allowed to be anything other than 7.1, 7.4, or Off except being imported as 5.6.

It seems like there's a fundamental issue with how the provider is enforcing values compared to how it is also parsing and using said values.

fishfacemcgee commented 12 months ago

To be clear, this same Windows Web App from my previous comment imports without drama as a azurerm_app_service resource. I realize the app_service resource is deprecated, but that also makes this issue a notable regression.

miroslavgrozdanovski commented 7 months ago

I'm facing the same problem and there's definitely something wrong with dotnet_version and dotnet_core_version. Terraform forces me to use dotnet_version and set it to v8.0, but as soon as I manually deploy through Visual Studio and come back to run Plan in Terraform, it shows that there are pending changes and it wants to swap dotnet_core_version and dotnet_version.

@xiaxyi, not sure who we should ping, but can we at least agree that there's an issue here and plan a fix? Or you need more info to conclude that? Pending changes through Terraform trigger manual approvals in our deployment pipelines (even if it results in a no-op, but I'm not even sure that's the case), and I don't see a workaround for this issue.

jemcclin commented 7 months ago

Additionally, this problem was reported another issue ( #24206 ) - and although the original poster in that case was able to work around the situation by using ignore_changes, that unfortunately isn't a solution that works for my particular use case (or that of another commenter in that issue).

I can confirm that it doesn't seem to matter which version of .NET is used here - we were affected with .NET 4, . NET 6, and are still affected with .NET 8. To pull from a terraform plan from about ten minutes ago, run against AzureRM 3.97.1:

      ~ site_config {
            # (24 unchanged attributes hidden)

          ~ application_stack {
              - dotnet_core_version          = "v8.0" -> null
              + dotnet_version               = "v8.0"
                # (4 unchanged attributes hidden)
            }
        }

The Terraform declaration that is causing these plans looks like:

resource "azurerm_windows_web_app" "appsvc" {

[removed other configurations for clarity]

    application_stack {
      dotnet_version = "v8.0"
    }
}

We had never set dotnet_core_version through Terraform on any of our resources - we switched over from dotnet_framework_version in the now-deprecated azurerm_app_service to using dotnet_version, re-importing these web apps along the way. The vast majority of our azurerm_windows_web_app resources were imported into Terraform, and all of them are affected by dotnet_core_version and dotnet_version being constantly changed in every single plan.

That said, as far as I can tell this affects both newly-created and imported resources in our environment - will have to test further to see if this problem shows up before deploying an app to the resource, or if it's just after that happens that the problem occurs.

It's a lot of plan noise for something that doesn't change - I get a lot of questions about it from developers worried that this will cause issues for the applications running on those web app resources if they apply the plan. While it doesn't seem to have caused any downtime (yet), we would appreciate a solution for this. Thanks!

oWretch commented 2 months ago

After doing some local testing on this, the issue occurs if the Web App is configured in the back-end to be a .Net Core app, instead of just a .Net app. I'm assuming this is a legacy hangover from when the platform had a difference between Core and Windows .NET applications.

To solve the problem, add the current_stack property to the application_stack property, and set it to dotnet. This should solve the perpetual change.

resource "azurerm_windows_web_app" "this" {
  name                = "windows-web-app-432as"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  service_plan_id     = azurerm_service_plan.windows.id

  site_config {
    application_stack {
      current_stack  = "dotnet"
      dotnet_version = "v8.0"
    }
  }
}

I'll have a look at what we might be able to do in the provider - it seems to just be a cosmetic legacy hangover...

Zhaph commented 2 months ago

After doing some local testing on this, the issue occurs if the Web App is configured in the back-end to be a .Net Core app, instead of just a .Net app. I'm assuming this is a legacy hangover from when the platform had a difference between Core and Windows .NET applications.

To solve the problem, add the current_stack property to the application_stack property, and set it to dotnet. This should solve the perpetual change.

resource "azurerm_windows_web_app" "this" {
  name                = "windows-web-app-432as"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  service_plan_id     = azurerm_service_plan.windows.id

  site_config {
    application_stack {
      current_stack  = "dotnet"
      dotnet_version = "v8.0"
    }
  }
}

Thanks for looking into this @oWretch - we've rolled out this recommendation and can confirm that it resolves the issue on our drift control.