I had the following Terraform configuration for my backend that worked for a while,
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
}
}
backend "azurerm" {
resource_group_name = "my-rg"
storage_account_name = "my-sa"
####!!!!! BELOW USED TO WORK !!!!###
provider = azurerm.mysub
key = "terraform.tfstate"
}
}
provider "azurerm" {
skip_provider_registration = true
subscription_id = "xxxxxx-xxxxx-xxxxx-xxxxx"
alias = "mysub"
features {
}
}
However after an upgrade it said that provider was not allowed in this block (I dont recall teh exact error message). So instead I changed it as such,
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
}
}
backend "azurerm" {
resource_group_name = "my-rg"
storage_account_name = "my-sa"
###!!!! Direct Reference to Subscription ID !!!!###
subscription_id = "xxxxxx-xxxxx-xxxxx-xxxxx"
key = "terraform.tfstate"
}
}
However now it says,
│ Error: Backend initialization required, please run "terraform init"
│
│ Reason: Backend configuration changed for "azurerm"
│
│ The "backend" is the interface that Terraform uses to store state,
│ perform operations, etc. If this message is showing up, it means that the
│ Terraform configuration you're using is using a custom configuration for
│ the Terraform backend.
│
│ Changes to backend configurations require reinitialization. This allows
│ Terraform to set up the new configuration, copy existing state, etc. Please run
│ "terraform init" with either the "-reconfigure" or "-migrate-state" flags to
│ use the current configuration.
│
│ If the change reason above is incorrect, please verify your configuration
│ hasn't changed and try again. At this point, no changes to your existing
│ configuration or state have been made.
If I want it to remember the state so that it knows how to destroy the same later, what command should I use? I have already deployed several iteration of resources in this RG using terraform and want to keep that intact.
terraform init, OR,
terraform init -reconfigure, OR,
terraform init -migrate-state??
Since the backend location has not changed, I want to continue as is but just have it ignore the backend block update from using "provider" to using the "subscription_id". Which command do I use?
Thanks in advance!
The terraform init documentation says the following about this situation:
Re-running init with an already-initialized backend will update the working directory to use the new backend settings. Either -reconfigure or -migrate-state must be supplied to update the backend configuration.
The -migrate-state option will attempt to copy existing state to the new backend, and depending on what changed, may result in interactive prompts to confirm migration of workspace states. The -force-copy option suppresses these prompts and answers "yes" to the migration questions. This implies -migrate-state.
The -reconfigure option disregards any existing configuration, preventing migration of any existing state.
The decision point here is whether you want Terraform to take explicit action to try to copy the state to the new location (-migrate-state) or whether you want Terraform to just forget the old settings entirely and just use the new settings directly.
You said that the physical location is unchanged and instead you've just written the same information a different way, and so -reconfigure is the option that matches that situation: there's no need for any explicit migration here because the state is already available at the "new" location (which is functionally the same as the old location, but Terraform can't know that).
Note that it has never been valid to associate a backend configuration with a provider, so whatever you had working before wasn't working in the way you thought it was.
The azurerm backend has the behavior of looking for the ARM_SUBSCRIPTION_ID environment variable if you don't explicitly set subscription_id in its configuration, so I'd guess that you were previously running Terraform in a context where that environment variable was set and thus the backend was able to find the appropriate subscription ID to use even though you hadn't explicitly set it.
Why the backend wasn't rejecting the invalid argument provider is unclear to me. That suggests a bug in either Terraform or in the backend itself, which has since been fixed and thus Terraform is now correctly reporting that there is no argument provider declared in that backend's configuration schema.
I am not sure if this is the proper way to do this, but I was able to get this resolved without the initialization message coming up anymore by updated the local terraform.tfstate file.
Changed this line
"subscription_id": null,
to,
"subscription_id": "xxxx-xxxx-xxxx-xxxx",
Related
I am looking to pass in the provider_version into terragrunt.hcl as a variable to make upgrading / setting the version easier. However this is my current code:
terraform {
backend "s3" {}
required_version = "~> 0.12"
required_providers {
aws = {
source = "hashicorp/aws"
version = "${var.aws_provider_version}"
}
}
}
I am getting an error
61: version = "${var.aws_provider_version}" Variables may not be used here.
Is there a known workaround or is this not possible?
Terraform doesn't support variables in blocks that are inputs to terraform itself, like provider blocks or lifecycle attributes.
You may be able to use code generation to set up a small providers.tf file before running terraform if you need to update your provider version at build time.
Im trying to update terraform version from 0.12 to 0.13. While updating the terraform I came across on an issue during plan
Error: Provider configuration not present
To work with
aws_sns_topic_subscription.sns_s3_raw_parquet_sqs_user_cleansing_monet_service_subscription
its original provider configuration at provider["registry.terraform.io/-/aws"]
is required, but it has been removed. This occurs when a provider
configuration is removed while objects created by that provider still exist in
the state. Re-add the provider configuration to destroy
aws_sns_topic_subscription.sns_s3_raw_parquet_sqs_user_cleansing_monet_service_subscription,
after which you can remove the provider configuration again.
Could someone please help?
Most likely you have not proceeded with the migration to Terraform v.013 fully.
Make a backup of your current state with terraform state pull then try to execute the following:
terraform state replace-provider 'registry.terraform.io/-/aws' 'registry.terraform.io/hashicorp/aws'
This should amend your state to the newer Terraform version.
Most of the time you'll have a global.tf file in your directory that lists some things that might not actually be resources. This is where you'd normally have a block like this:
provider "aws" {
region = "REGION"
access_key = "my-access-key"
secret_key = "my-secret-key"
}
Looks like that block, whatever file it was in, got deleted. Add it back and then try again. Note you'll need to change REGION to whatever region you put your resources in. In lieu of access_key and secret_key, some people use a profile and put it in ~/.aws/credentials.
I have the exact same problem as here Terraform tries to load old defunct provider and the solution posted there does not work for me.
Problem is that i define in the terraform config:
required_providers {
postgresql = {
source = "cyrilgdn/postgresql"
version = ">=1.13.0"
}
}
But the terraform init process always tries to download hashicorp/postgresql and can not find it in the end.
My current terraform version is:
Terraform v1.0.6 on windows_amd64
I did try a lot and played around with the resource parameter "provider" to explicitly set the provider for all resources but even with that i did not find a way.
Can anybody help here again or post me a working example for this provider?
I got the solution! The problem what i had was my folder structure. I had a specific folder structure like:
environments like dev/int/prod and i had a config.tf in there with the required providers.
resources where i use the resources i want to add and what i missed there is the a copy of the config.tf file.
So this means i need a config.tf file in every subfolder which consists modules.
In a CI/CD context, I would like to define provider versions outside my terraform configuration using TF_VAR_ environment variables.
I'm trying to use input variable to set the version of helm provider in versions.tf (terraform 0.12) but it seems not allowed :
Error: Invalid provider_requirements syntax
on versions.tf line 3, in terraform:
3: helm = "${var.helm_version}"
provider_requirements entries must be strings or objects.
Error: Variables not allowed
on versions.tf line 3, in terraform:
3: helm = "${var.helm_version}"
Variables may not be used here.
How can I configure this ?
If it's not possible, how I can manage the terraform provider version outside my configuration ?
Cannot be done. I wish it could be done. terraform init resolves and downloads the providers, you won't have access to variables at that point.
Each terraform block can contain a number of settings related to
Terraform's behavior. Within a terraform block, only constant values
can be used; arguments may not refer to named objects such as
resources, input variables, etc, and may not use any of the Terraform
language built-in functions.
https://www.terraform.io/docs/configuration/terraform.html
As #thekbb says, it's not possible to get access to version variable during terraform init at least in 0.12.20. However, I've below workaround to manage providers outside your configuration.
You could use alias with provider configuration to achieve this. Let's assume you want 1.3.0 version of helm. Rather than passing it as a var, you could define it statically with an alias like below.
provider "helm" {
alias = "helm-stable"
version = "1.3.0" (the version you pass via TF_VAR_helm_version)
kubernetes {
host = "https://104.196.242.174"
username = "ClusterMaster"
password = "MindTheGap"
client_certificate = file("~/.kube/client-cert.pem")
client_key = file("~/.kube/client-key.pem")
cluster_ca_certificate = file("~/.kube/cluster-ca-cert.pem")
}
}
Then, in your resource or data providers, you could point to a particular provider like below::
data "some_ds" "example" {
name = "dummy"
provider = helm.helm-stable
}
For more details, refer to the below links::
providers
allow variable in provider field
Ok, so I have three .tf-files: main.tf where I state azure as provider, resources.tf where all the my resources are claimed, and variables.tf.
I use variables.tf to store keys used by resources.tf.
However, I want to use variables stored in my variable file to fill in the fields in the backend scope like this:
main.tf:
provider "azurerm" {
version = "=1.5.0"
}
terraform {
backend "azurerm" {
storage_account_name = "${var.sa_name}"
container_name = "${var.c_name}"
key = "${var.key}"
access_key = "${var.access_key}"
}
}
Variables stored in variables.tf like this:
variable "sa_name" {
default = "myStorageAccount"
}
variable "c_name" {
default = "tfstate"
}
variable "key" {
default = "codelab.microsoft.tfstate"
}
variable "access_key" {
default = "weoghwoep489ug40gu ... "
}
I got this when running terraform init:
terraform.backend: configuration cannot contain interpolations
The backend configuration is loaded by Terraform extremely early,
before the core of Terraform can be initialized. This is necessary
because the backend dictates the behavior of that core. The core is
what handles interpolation processing. Because of this, interpolations
cannot be used in backend configuration.
If you'd like to parameterize backend configuration, we recommend
using partial configuration with the "-backend-config" flag to
"terraform init".
Is there a way of solving this? I really want all my keys/secrets in the same file... and not one key in the main which I preferably want to push to git.
Terraform doesn't care much about filenames: it just loads all .tf files in the current directory and processes them. Names like main.tf, variables.tf, and outputs.tf are useful conventions to make it easier for developers to navigate the code, but they won't have much impact on Terraform's behavior.
The reason you're seeing the error is that you're trying to use variables in a backend configuration. Unfortunately, Terraform does not allow any interpolation (any ${...}) in backends. Quoting from the documentation:
Only one backend may be specified and the configuration may not contain interpolations. Terraform will validate this.
So, you have to either hard-code all the values in your backend, or provide a partial configuration and fill in the rest of the configuration via CLI params using an outside tool (e.g., Terragrunt).
There are some important limitations on backend configuration:
A configuration can only provide one backend block.
A backend block cannot refer to named values (like input variables, locals, or data source attributes).
Terraform backends configurations one can see at below link:
https://www.terraform.io/docs/configuration/backend.html