如果模块中声明了提供程序,如何删除Terraform模块引用?

4

我正在尝试删除一个模块,其中包含以下提供程序块,指定了一个非HashiCorp提供程序。据我所知,非HashiCorp提供程序不会被继承,因为在运行Terraform时,它会明确地抱怨找不到“hashicorp/azuredevops”提供程序。

# Defined in module
terraform {
  required_version = ">= 0.13"

  required_providers {
    azuredevops = {
      source = "microsoft/azuredevops"
      version = ">= 0.1.0"
    }
  }
}

我的根配置包含一个类似于以下内容的提供商块:

# Defined in root
terraform {
  required_version = ">= 0.13"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.19.1"
    }
    azuredevops = {
      source  = "microsoft/azuredevops"
      version = ">= 0.1.0"
    }
  }
}

我可以成功创建一个模块:

module "example" {
  source           = "../modules/example/"
  application_name = "example"
  location         = var.location
  environment      = var.environment
}

但是当我尝试通过注释来删除它时,我会收到帖子开头提到的错误。

我该如何让模块从根继承微软提供程序,以便成功删除此特定模块引用?

 Error: Failed to query available provider packages
 
 Could not retrieve the list of available versions for provider
 hashicorp/azuredevops: provider registry registry.terraform.io does not
 have a provider named registry.terraform.io/hashicorp/azuredevops

编辑:

terraform providers 中的提供者

Providers required by configuration:
.
├── provider[registry.terraform.io/hashicorp/azurerm]
└── module.example
    ├── provider[registry.terraform.io/hashicorp/azuredevops]

Providers required by state:

    provider[registry.terraform.io/microsoft/azuredevops]

    provider[registry.terraform.io/hashicorp/azurerm]

1
如果你运行 terraform providers 命令,Terraform 应该会解释每个 provider 的要求来自何处,而这些 provider 是 terraform init 将尝试安装的。 你能运行此命令后编辑你的问题并包含输出吗? - Martin Atkins
1
如果您已经删除了 module "example" 块,那么我不会在输出中看到 module.example 的提及。您能否确认在运行此命令之前已删除该块(或等效地将其注释掉)? - Martin Atkins
1
很抱歉,我不太确定您的问题是什么。您似乎已经有了一个正确声明module.example依赖于hashicorp/azurermmicrosoft/azuredevops的配置。这里没有需要更改的内容:您的配置已经是正确的。 - Martin Atkins
1
哦,好的...你遇到的问题与你所问的问题是不同的。子模块通常不应包含provider块,因为如你所见,这样做将无法在单个步骤中删除该模块。Terraform的文档建议不要这样做,但Terraform仍然允许它,因为有现有的配置依赖于这种能力,只要没有人尝试删除子模块就可以正常工作。 - Martin Atkins
1
这与子模块中的 required_providers 块无关。问题出在 provider "azuredevops" 块上,但由于您没有在问题中包含它,我无法猜到。 - Martin Atkins
显示剩余6条评论
1个回答

1
这涉及到子模块内的provider块,它是必需的,但一旦模块被注释掉就无法找到。请参考hashicorp中的评论:

因此,在删除配置中的提供程序配置块之前,您必须确保所有属于特定提供程序配置的资源都已销毁。如果Terraform在状态中找到一个资源实例,但其提供程序配置块不再可用,则在计划过程中会返回错误,并提示您重新引入提供程序配置。

还可以在here中看到一个两步骤的解决方案。

更好的定义提供程序的方法是从任何模块中删除任何provider块,只在模块内部保留一个required_providers

这样,您可以将提供程序从根目录传递到子模块中,如下所示:

module "test" {
  source       = "./module/working"
  project_name = local.project_name
  env_name     = local.env_name1
  providers = {
    azuredevops = azuredevops.test
  }
}

如果你在这个模块调用中注释掉providers参数,当尝试销毁该模块时会得到与之前相同的错误。请注意,在实施此操作时,请确保删除所有使用旧提供程序配置的资源,否则将再次出现相同的错误。
一个完整的示例:

enter image description here

根目录下的main.tf文件:
locals {
  azuredevops_pat = <your PAT>
  org_service_url = <url of project, e.g. https://dev.azure.com/some_name>
  project_name    = <name of azdo project>
  env_name1       = "Example Environment 1"
  env_name2       = "Example Environment 2"
}

terraform {
  required_version = ">= 0.13"

  required_providers {
    azuredevops = {
      source  = "microsoft/azuredevops"
      version = ">= 0.1.0"
    }
  }
}

provider "azuredevops" {
  personal_access_token = local.azuredevops_pat
  org_service_url       = local.org_service_url
  alias                 = "test"
}

module "test" {
  source       = "./module/working"
  project_name = local.project_name
  env_name     = local.env_name1
  providers = {
    azuredevops = azuredevops.test
  }
}

module "test2" {
  source       = "./module/failing"
  project_name = local.project_name
  env_name     = local.env_name2
}


在module/working中的main.tf文件:
terraform {
    required_providers {
        azuredevops = {
        source = "microsoft/azuredevops"
        }
    }
}

variable "project_name" {
  type = string
}
variable "env_name" {
  type = string
}

data "azuredevops_project" "example" {
    name = var.project_name
}

resource "azuredevops_environment" "example" {
    project_id = data.azuredevops_project.example.id
    name       = var.env_name
}


在模块/失败中的main.tf文件。
locals {
  azuredevops_pat = <pat>
  org_service_url = <url>
}

provider "azuredevops" {
  personal_access_token = local.azuredevops_pat
  org_service_url       = local.org_service_url
}

terraform {
    required_providers {
        azuredevops = {
        source = "microsoft/azuredevops"
        }
    }
}

variable "project_name" {
  type = string
}
variable "env_name" {
  type = string
}

data "azuredevops_project" "example" {
    name = var.project_name
}

resource "azuredevops_environment" "example" {
    project_id = data.azuredevops_project.example.id
    name       = var.env_name
}


1
非常感谢您提供的详细示例。这非常有道理! - Kevys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接