Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot delete an instance of module in Terraform which contains a provider

I have a module which contains resources for:

  • azure postgres server
  • azure postgres database
  • postgres role (user)
  • postgres provider (for the server and used to create the role)

In one of my env directories I can have 0-N .tf files which is an instance of that module and each specify database name etc. So if I add another .tf file with a new name then a new database server with a database will be provisioned. All this works fine.

However, if I now delete an existing database module (one of the .tf files in my env directory) I run into issues. Terraform will now try to get the state of all the previously existing resources and since that specific provider (for that postgres server) now is gone terraform cannot get the state of the created postgres role, with the output a provider configuration block is required for all operations.

I understand why this happens but I cannot figure out how to solve this. I want to "dynamically" create (and remove) postgres servers with a database on them but this requires "dynamic" providers which then makes me get stuck on this.

Example of how it looks

resource "azurerm_postgresql_server" "postgresserver" {
  name                = "${var.db_name}-server"
  location            = "${var.location}"
  resource_group_name = "${var.resource_group}"

  sku = ["${var.vmSize}"]

  storage_profile = ["${var.storage}"]

  administrator_login = "psqladminun"
  administrator_login_password = "${random_string.db-password.result}"
  version = "${var.postgres_version}"
  ssl_enforcement = "Disabled"
}

provider "postgresql" {
  version         = "0.1.0"
  host            = "${azurerm_postgresql_server.postgresserver.fqdn}"
  port            = 5432
  database        = "postgres"
  username        = "${azurerm_postgresql_server.postgresserver.administrator_login}@${azurerm_postgresql_server.postgresserver.name}". 
  password        = "${azurerm_postgresql_server.postgresserver.administrator_login_password}"
 }

resource "azurerm_postgresql_database" "db" {
  name                = "${var.db_name}"
  resource_group_name = "${var.resource_group}"
  server_name         = "${azurerm_postgresql_server.postgresserver.name}"
  charset             = "UTF8"
  collation           = "English_United States.1252"
}

resource "postgresql_role" "role" {
  name             = "${random_string.user.result}"
  login            = true
  connection_limit = 100
  password         = "${random_string.pass.result}"
  create_role      = true
  create_database     = true

  depends_on = ["azurerm_postgresql_database.db"]
}

Above you see how we, in the module create a postgres server, postgres db and also a postgres role (where only the role utilizes the postgres provider). So if I now define an instance datadb.tf such as:

module "datadb" {
  source = "../../modules/postgres"
  db_name   = "datadb"
  resource_group = "${azurerm_resource_group.resource-group.name}"
  location = "${azurerm_resource_group.resource-group.location}"
}

then it will be provisioned successfully. The issue is if I later on delete that same file (datadb.tf) then the planning fails because it will try to get the state of the postgres role without having the postgres provider present. The postgres provider is only needed for the postgres role which will be destroyed as soon as the azure provider destroys the postgres db and postgres server, so the actual removal of that role is not necessary. Is there a way to tell terraform that "if this resource should be removed, you don't have to do anything because it will be removed dependent on being removed"? Or does anyone see any other solutions?

I hope my goal and issue is clear, thanks!

like image 785
poppe Avatar asked Jun 14 '18 11:06

poppe


People also ask

Is required but it has been removed this occurs when a provider?

env 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 module.network.

How do I pass a provider in module Terraform?

Provider configurations can be defined only in a root Terraform module. Providers can be passed down to descendent modules in two ways: either implicitly through inheritance, or explicitly via the providers argument within a module block.


1 Answers

I think the only solution is a two-step solution, but I think it's still clean enough. What I would do is have two files per database (name them how you want).

db-1-infra.tf
db-1-pgsql.tf

Put everything except your postgres resources in db-1-infra.tf

resource "azurerm_postgresql_server" "postgresserver" {
  name                = "${var.db_name}-server"
  location            = "${var.location}"
  resource_group_name = "${var.resource_group}"

  sku = ["${var.vmSize}"]

  storage_profile = ["${var.storage}"]

  administrator_login = "psqladminun"
  administrator_login_password = "${random_string.db-password.result}"
  version = "${var.postgres_version}"
  ssl_enforcement = "Disabled"
}

provider "postgresql" {
  version         = "0.1.0"
  host            = "${azurerm_postgresql_server.postgresserver.fqdn}"
  port            = 5432
  database        = "postgres"
  username        = "${azurerm_postgresql_server.postgresserver.administrator_login}@${azurerm_postgresql_server.postgresserver.name}". 
  password        = "${azurerm_postgresql_server.postgresserver.administrator_login_password}"
 }

resource "azurerm_postgresql_database" "db" {
  name                = "${var.db_name}"
  resource_group_name = "${var.resource_group}"
  server_name         = "${azurerm_postgresql_server.postgresserver.name}"
  charset             = "UTF8"
  collation           = "English_United States.1252"
}

Put your PostgreSQL resources in db-1-pgsql.tf

resource "postgresql_role" "role" {
    name             = "${random_string.user.result}"
    login            = true
    connection_limit = 100
    password         = "${random_string.pass.result}"
    create_role      = true
    create_database     = true

    depends_on = ["azurerm_postgresql_database.db"]

}

When you want to get rid of your database, first delete the file db-1-pgsql.tf and apply. Next, delete db-1-infra.tf and apply again.

The first step will destroy all postgres resources and free you up to run the second step, which will remove the postgres provider for that database.

like image 120
Sam Svenbjorgchristiensensen Avatar answered Nov 15 '22 05:11

Sam Svenbjorgchristiensensen