Error: Inconsistent dependency lock file when extract resource into a module - terraform

I am new to terraform and as I extracted one of the resources into a module I got this:
Error: Inconsistent dependency lock file
│
│ The following dependency selections recorded in the lock file are inconsistent with the current
│ configuration:
│ - provider registry.terraform.io/hashicorp/heroku: required by this configuration but no version is selected
│
│ To update the locked dependency selections to match a changed configuration, run:
│ terraform init -upgrade
How I did?
First I had this:
provider "heroku" {}
resource "heroku_app" "example" {
name = "learn-terraform-heroku-ob"
region = "us"
}
resource "heroku_addon" "redis" {
app = heroku_app.example.id
plan = "rediscloud:30"
}
after that terraform init was runing without error also terraform plan was successfull.
Then I extracted the redis resource declaration into a module:
provider "heroku" {}
resource "heroku_app" "example" {
name = "learn-terraform-heroku-ob"
region = "us"
}
module "key-value-store" {
source = "./modules/key-value-store"
app = heroku_app.example.id
plan = "30"
}
And the content of modules/key-value-store/main.tf is this:
terraform {
required_providers {
mycloud = {
source = "heroku/heroku"
version = "~> 4.6"
}
}
}
resource "heroku_addon" "redis" {
app = var.app
plan = "rediscloud:${var.plan}"
}
terraform get went well. but terraform plan showed me the above error!

For this code to work, you have to have the required_providers blocks in both the root and child modules. So, the following needs to happen:
Add the required_providers block to the root module (this is what you have already)
Add the required_providers block to the child module and name it properly (currently you have set it to mycloud, and provider "heroku" {} block is missing)
The code that needs to be added in the root module is:
terraform {
required_providers {
heroku = {
source = "heroku/heroku"
version = "~> 4.6"
}
}
}
provider "heroku" {}
resource "heroku_app" "example" {
name = "learn-terraform-heroku-ob"
region = "us"
}
module "key-value-store" {
source = "./modules/key-value-store"
app = heroku_app.example.id
plan = "30"
}
In the child module (i.e., ./modules/key-value-store) the following needs to be present:
terraform {
required_providers {
heroku = { ### not mycloud
source = "heroku/heroku"
version = "~> 4.6"
}
}
}
provider "heroku" {} ### this was missing as well
resource "heroku_addon" "redis" {
app = var.app
plan = "rediscloud:${var.plan}"
}
This stopped working when the second resource was moved to the module as Heroku is not an official Terraform provider hence the provider settings are not propagated to the modules. For the unofficial providers (e.g., marked with verified), corresponding blocks of required_providers and provider <name> {} have to be defined. Also, make sure to remove the .terraform directory and re-run terraform init.

Related

Terraform: Failed to query available provider packages (Azapi)

I try to use the Azure/Azapi Provider within my Terraform project but after I add the provider and run terraform init, I get the following error:
Error: Failed to query available provider packages
Could not retrieve the list of available versions for provider hashicorp/azapi: provider registry registry.terraform.io does not have a provider named registry.terraform.io/hashicorp/azapi
This is how my providers.tf looks like:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=3.16.0"
}
azapi = {
source = "azure/azapi"
version = "=0.4.0"
}
}
required_version = "=1.2.6"
}
provider "azurerm" {
features {}
}
provider "azapi" {
}
When I run terraform providers, I can see that the provider has a wrong registry URL within my module:
├── module.az-aca-env
│ └── provider[registry.terraform.io/hashicorp/azapi]
I would expect something like registry.terraform.io/azure/azapi.
Any ideas?
Okay, I found a workaround. I have to add a providers.tf inside my module directory (/modules/az-aca-env) with the following content:
terraform {
required_providers {
azapi = {
source = "Azure/azapi"
version = "=0.4.0"
}
}
}
After adding it, the terraform init works ✅.
You have a typo in the provider name, it is Azure/azapi as per documentation [1]:
terraform {
required_providers {
azapi = {
source = "Azure/azapi"
version = "0.4.0"
}
}
}
provider "azapi" {
# Configuration options
}
You can always see how to use the provider if you click on the big purple button in the top right-hand corner saying USE PROVIDER.
[1] https://registry.terraform.io/providers/azure/azapi/latest/docs

Terraform Cloud Run Service URL

I create a cloud run service like so
terraform {
required_version = ">= 1.1.2"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 4.1.0"
}
google-beta = {
source = "hashicorp/google-beta"
version = "~> 4.2.0"
}
}
}
provider "google" {
project = "main_project"
region = "us-central-1"
credentials = "<my-key-path>"
}
resource "google_cloud_run_service" "default" {
name = "cloudrun-srv"
location = "us-central1"
template {
spec {
containers {
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
}
traffic {
percent = 100
latest_revision = true
}
}
I want to save the value of the service url that is created - https://default-hml2qtrgfq-uw.a.run.app using an output variable. something like
output "cloud_run_instance_url" {
value = google_cloud_run_service.default.url
}
This gives me an error:
terraform plan
╷
│ Error: Unsupported attribute
│
│ on main.tf line 40, in output "cloud_run_instance_url":
│ 40: value = google_cloud_run_service.default.url
│
│ This object has no argument, nested block, or exported attribute named "url".
╵
How do I get this output value and assign it to a variable so that other services like cloud scheduler can point to it?
If you declare an output for the url resource attribute like:
output "cloud_run_instance_url" {
value = google_cloud_run_service.default.status.0.url
}
then it will be available for resolution (such as for inputs to other modules) at the scope where the module is declared in the namespace module.<declared module name>.cloud_run_instance_url. For example, if this module is declared in the root module config, then it can be resolved at that namespace elsewhere in the root module config.

terraform azure insufficient blocks

Here is my terraform plan
terraform {
required_providers {
azure = {
source = "hashicorp/azurerm"
version = "=3.5.0"
}
}
backend "s3" {
encrypt = true
bucket = "terraform"
region = "us-east-1"
key = "aws/tgw_peer/us-east-1/terraform.tfstate"
}
}
provider "azurerm" {
features {}
}
data "azurerm_virtual_network" "vnet" {
resource_group_name = var.resource_group_name
name = var.vnet_name
}
When I execute terraform plan I get the following error:
╷
│ Error: Insufficient features blocks
│
│ on <empty> line 0:
│ (source code not available)
│
│ At least 1 "features" blocks are required.
╵
There is clearly a features block in the azurerm provider block. However, the fact that the error doesn't specify the file name tells me that maybe the problem is somewhere else.
What am I doing wrong?
Terraform version 1.1.6
The name of the provider in the required_providers block is wrong, you have set it to azure while it should be azurerm. Example of how to configure the provider:
terraform {
required_providers {
azurerm = { # <--- Note that it is azurerm
source = "hashicorp/azurerm"
version = "3.5.0"
}
}
}
provider "azurerm" {
# Configuration options
}

Unable to create azurerm_cosmosdb_sql_container with indexing_policy block

According to the documentation on Terraform.io for azurerm_cosmosdb_sql_container, it says I can include an indexing_policy block. However, when I run terraform plan I get errors:
Error: Unsupported block type
on main.tf line 912, in resource "azurerm_cosmosdb_sql_container"
"AccountActivity": 912: indexing_policy {
Blocks of type "indexing_policy" are not expected here.
main.tf
resource "azurerm_cosmosdb_sql_container" "AccountActivity" {
name = "AccountActivity"
resource_group_name = azurerm_resource_group.backendResourceGroup.name
account_name = azurerm_cosmosdb_account.AzureCosmosAccount.name
database_name = azurerm_cosmosdb_sql_database.AzureCosmosDbCache.name
default_ttl = 2592000
throughput = 2500
indexing_policy {
indexing_mode = "Consistent"
included_path {
path = "/*"
}
excluded_path {
path = "/\"_etag\"/?"
}
}
}
Here is my terraform version output:
terraform version
Terraform v0.13.4
+ provider registry.terraform.io/-/azurerm v2.30.0
+ provider registry.terraform.io/hashicorp/azurerm v2.20.0
+ provider registry.terraform.io/hashicorp/random v2.3.0
After searching GitHub, I finally found that support for the indexing_policy block was added in this commit 26 days ago. The documentation doesn't mention this, nor does the release notes for azurerm v2.31.1. After updating my main.tf file with the latest version for azurerm and running terraform init the terraform plan command worked without issue.
provider "azurerm" {
version = "~>2.31.1"
features {}
}

How to create provide modules that support multiple AWS regions?

We are trying to create Terraform modules for below activities in AWS, so that we can use them where ever that is required.
VPC creation
Subnets creation
Instance creation etc.
But while creating these modules we have to define the provider in all above listed modules. So we decided to create one more module for provider so that we can call that provider module in other modules (VPC, Subnet, etc.).
Issue in above approach is that it is not taking provider value, and asking for the user input for region.
Terraform configuration is as follow:
$HOME/modules/providers/main.tf
provider "aws" {
region = "${var.region}"
}
$HOME/modules/providers/variables.tf
variable "region" {}
$HOME/modules/vpc/main.tf
module "provider" {
source = "../../modules/providers"
region = "${var.region}"
}
resource "aws_vpc" "vpc" {
cidr_block = "${var.vpc_cidr}"
tags = {
"name" = "${var.environment}_McD_VPC"
}
}
$HOME/modules/vpc/variables.tf
variable "vpc_cidr" {}
variable "environment" {}
variable "region" {}
$HOME/main.tf
module "dev_vpc" {
source = "modules/vpc"
vpc_cidr = "${var.vpc_cidr}"
environment = "${var.environment}"
region = "${var.region}"
}
$HOME/variables.tf
variable "vpc_cidr" {
default = "192.168.0.0/16"
}
variable "environment" {
default = "dev"
}
variable "region" {
default = "ap-south-1"
}
Then when running terraform plan command at $HOME/ location it is not taking provider value and instead asking for the user input for region.
I need help from the Terraform experts, what approach we should follow to address below concerns:
Wrap provider in a Terraform module
Handle multiple region use case using provider module or any other way.
I knew a long time back that it wasn't possible to do this because Terraform built a graph that required a provider for any resource before it included any dependencies and it didn't used to be possible to force a dependency on a module.
However since Terraform 0.8 it is now possible to set a dependency on modules with the following syntax:
module "network" {
# ...
}
resource "aws_instance" "foo" {
# ...
depends_on = ["module.network"]
}
However, if I try that with your setup by changing modules/vpc/main.tf to look something like this:
module "aws_provider" {
source = "../../modules/providers"
region = "${var.region}"
}
resource "aws_vpc" "vpc" {
cidr_block = "${var.vpc_cidr}"
tags = {
"name" = "${var.environment}_McD_VPC"
}
depends_on = ["module.aws_provider"]
}
And run terraform graph | dot -Tpng > graph.png against it it looks like the graph doesn't change at all from when the explicit dependency isn't there.
This seems like it might be a potential bug in the graph building stage in Terraform that should probably be raised as an issue but I don't know the core code base well enough to spot where the change needs to be.
For our usage we use symlinks heavily in our Terraform code base, some of which is historic from before Terraform supported other ways of doing things but could work for you here.
We simply define the provider in a single .tf file (such as environment.tf) along with any other generic config needed for every place you would ever run Terraform (ie not at a module level) and then symlink this into each location. That allows us to define the provider in a single place with overridable variables if necessary.
Step 1
Add region alias in the main.tf file where you gonna execute the terraform plan.
provider "aws" {
region = "eu-west-1"
alias = "main"
}
provider "aws" {
region = "us-east-1"
alias = "useast1"
}
Step 2
Add providers block inside your module definition block
module "lambda_edge_rule" {
providers = {
aws = aws.useast1
}
source = "../../../terraform_modules/lambda"
tags = var.tags
}
Step 3
Define "aws" as providers inside your module. ( source = ../../../terraform_modules/lambda")
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
}
}
}
resource "aws_lambda_function" "lambda" {
function_name = "blablabla"
.
.
.
.
.
.
.
}
Note: Terraform version v1.0.5 as of now.

Resources