错误:提供程序配置不存在 - 当providers.tf来自源模块时

问题描述 投票:0回答:1

使用以下代码创建了 rds_cluster,

module "rds_cluster_db" {
  source = "./private-terraform-aws-rds-cluster"

  name      = "my-user-db"    
  db_user       = "db_user"
  db_name       = "db_name"
  instance_type = "db.t4g.small"
}

要删除此资源,我只需删除模块块。但是,它失败并出现以下错误,因为

source
模块包含
providers.tf
文件。

错误:

│ Error: Provider configuration not present
│ 
│ To work with module.rds_cluster_db.postgresql_role.iam_user
│ (orphan) its original provider configuration at
│ module.rds_cluster_db.provider["registry.terraform.io/cyrilgdn/postgresql"]
│ 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.rds_cluster_db.postgresql_role.iam_user (orphan),
│ after which you can remove the provider configuration again.

./private-terraform-aws-rds-cluster/main.tf:

module "rds_cluster" {
  source  = "cloudposse/rds-cluster/aws"
  version = "1.9.0"

  zone_id                               = var.zone_id
  security_groups                       = var.security_groups
  vpc_id                                = var.vpc_id
  subnets                               = var.subnets
  instance_type                         = var.instance_type

  context = module.this.context
}

resource "postgresql_role" "iam_user" {
  name            = var.db_user
  login           = true
  roles           = ["rds_iam"]
  create_database = true
  create_role     = true
  inherit         = true

  depends_on = [
    module.rds_cluster
  ]
}

./private-terraform-aws-rds-cluster/providers.tf:

provider "postgresql" {
  host             = module.rds_cluster.endpoint
  port             = var.db_port
  database         = var.db_name
  username         = var.admin_user
  password         = var.admin_password
  superuser        = false
  expected_version = var.engine_version
}

terraform {
  required_version = ">= 0.13.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 3.56"
    }
    postgresql = {
      source  = "cyrilgdn/postgresql"
      version = ">= 1.16.0"
    }
  }
}

Terraform 版本:

Terraform v1.5.5
on darwin_arm64
+ provider registry.terraform.io/cyrilgdn/postgresql v1.22.0
+ provider registry.terraform.io/hashicorp/archive v2.4.2
+ provider registry.terraform.io/hashicorp/aws v5.42.0
+ provider registry.terraform.io/hashicorp/kubernetes v2.27.0
+ provider registry.terraform.io/hashicorp/null v3.2.2
+ provider registry.terraform.io/hashicorp/random v3.6.0
+ provider registry.terraform.io/hashicorp/tls v4.0.5

我见过一些带有类似错误的帖子,但不太确定如何仅删除 terraform 部分而不删除对提供程序的引用,因为删除模块

rds_cluster_db
将删除 terraform 和提供程序?

amazon-web-services terraform terraform-provider-aws
1个回答
0
投票

您在这里遇到的情况就是为什么 Terraform 文档建议不要在非根模块中声明提供程序配置,请参见 具有提供程序配置的旧共享模块

在 Terraform v0.10 及更早版本中,没有明确的方法可以在同一配置的不同模块中使用提供程序的不同配置,因此模块作者通常通过直接在模块内编写

provider
块来解决此问题,从而使模块有自己独立的提供程序配置,与根模块中声明的提供程序配置分开。

但是,该模式有一个显着的缺点:因为需要提供程序配置来销毁与资源实例关联的远程对象以及创建或更新它,所以提供程序配置必须始终在整个 Terraform 配置中保持存在的时间超过它管理的所有资源。如果特定模块同时包含资源和这些资源的提供程序配置,那么从其调用者中删除该模块将违反该约束:资源及其关联的提供程序实际上将同时删除。

[...]

摆脱这个“陷阱”的主要方法有两种,但都有点繁琐。

手动删除受影响的对象

如果子模块中只声明了少量资源,那么最简单的方法可能是告诉 Terraform 完全“忘记”这些对象(即,将它们从 Terraform 状态中删除,而不实际删除真实对象),然后删除在远程系统中手动操作。

如果您想采用这种方法,在 Terraform 中唯一的步骤是告诉它忘记受影响的资源实例:

  • terraform state rm module.rds_cluster_db.postgresql_role.iam_user

完成此操作后,您需要在 Postgres 服务器中手动查找相应的对象并使用 Postgres 命令将其删除。

如果您打算完全销毁服务器,此策略是最简单的,因为删除整个 Postgres 服务器将隐式删除其中创建的所有内容,因此您无需手动清理单个对象。

如果这似乎不适合您的情况,请参阅下一节。

用空模块替换该模块

这里的核心问题是,当您的模块同时包含

resource
块和它所属的
provider
块时,没有任何简单的方法可以在保留
resource
块的同时删除
provider
块,但是Terraform 需要
provider
块来知道要连接到哪个 Postgres 服务器才能删除此对象。

您可以通过临时更改配置以包含所需的提供程序配置来打破此冲突。

为此,请创建一个仅包含一个空

.tf
文件的目录。例如,您可以将其称为
empty.tf
。文件名并不重要,它只需要存在,以便 Terraform 能够理解您打算将此目录用作 Terraform 模块。举例来说,我将选择将此模块放置在名为
empty
的子目录中,因此空文件将位于相对于根模块的
empty/empty.tf
处。

设置空模块后,您可以更改根模块以调用空模块而不是真正的

rds_cluster_db
模块,并且还传递 postgres 提供程序的配置,以便 Terraform 可以知道与现有对象一起使用哪个提供程序配置跟踪状态:

terraform {
  required_version = ">= 0.13.0"

  required_providers {
    postgresql = {
      source  = "cyrilgdn/postgresql"
      version = ">= 1.16.0"
    }
  }
}

provider "postgres" {
  alias = "temp_cleanup"

  # (configure here whatever minimal configuration
  # is sufficient to connect to the Postgres server
  # to run the destroy actions.)
}

module "rds_cluster_db" {
  source = "./empty"

  providers = {
    postgresql = postgresql.temp_cleanup
  }
}

此配置通过将提供程序配置移至根模块,然后用空模块替换现有模块来解决冲突。现在,Terraform 可以看到有一个提供程序配置可供使用,并且所有资源都已被删除,因此需要使用该提供程序配置来销毁它们。 (Terraform 通过其包含的模块来跟踪嵌套对象,并且 module.rds_cluster_db 现在指的是空模块而不是原始模块。)

应用此配置后,之前声明模块的对象已被销毁,您可以删除临时提供程序配置和 

module "rds_cluster_db"

块。

    

© www.soinside.com 2019 - 2024. All rights reserved.