Вопрос или проблема
У меня есть модуль Terraform, который создает репозиторий на GitHub и ряд связанных ресурсов (используя github_repository
, github_issue_labels
и github_branch_protection
). Это локальный модуль, и репозитории должны быть созданы в определенной организации, поэтому modules/common_repository/main.tf
начинается с:
provider "github" {
owner = "example_org"
}
resource "github_repository" "repo" {
name = var.name
visibility = var.visibility
description = var.description
auto_init = true
has_issues = true
has_downloads = false
has_projects = false
has_wiki = false
}
# и т.д...
Я вызываю модуль следующим образом:
module "repo_sandbox" {
source = "./modules/common_repository"
name = "sandbox"
labels = local.common_labels
}
Я надеялся, что удаление этих ресурсов просто потребует удаления указанного блока module
, но это приводит к следующей ошибке:
│ Ошибка: Конфигурация провайдера отсутствует
│
│ Для работы с module.repo_sandbox.github_repository.repo (orphan) требуется его оригинальная
│ конфигурация провайдера в
│ module.repo_sandbox.provider["registry.opentofu.org/hashicorp/github"],
│ но она была удалена. Это происходит в случае удаления конфигурации провайдера
│ в то время как объекты, созданные этим провайдером, все еще существуют в состоянии. Добавьте
│ конфигурацию провайдера заново для уничтожения
│ module.repo_sandbox.github_repository.repo (orphan), после чего вы снова сможете удалить
│ конфигурацию провайдера.
Я прочитал этот пост на форуме от 2022 года, в котором говорится, что:
Использование блоков провайдера в некорневых модулях не рекомендуется, так как это создает подобные ситуации, но Terraform, к сожалению, должен продолжать их поддерживать для обратной совместимости.
Однако я не уверен, как еще можно это написать; модуль, кажется, игнорирует конфигурацию провайдера в организации верхнего уровня. Если я удалю блок провайдера из модуля, он попытается создать репозитории в моем персональном пространстве имен GitHub.
Я попробовал предложение из того же поста, а именно заменить модуль новым, который пуст за исключением конфигурации провайдера; я создал modules/common_repository_destroy
с main.tf
, содержащим только:
provider "github" {
owner = "example_org"
}
Затем я изменил вызывающий блок:
module "repo_sandbox" {
source = "./modules/common_repository_destroy"
}
Но это все равно приводит к тем же ошибкам.
Есть ли чистый способ (или любой способ) заставить это работать?
Ответ или решение
Чтобы решить проблему удаления ресурсов в модуле Terraform, в который включён блок провайдера, важно понимать теоретическую основу работы Terraform и оптимальные практики для управления провайдерами и состоянием инфраструктуры.
Теория:
Terraform — это инструмент управления инфраструктурой, который позволяет определять ресурсы через код и управлять ими в декларативной форме. Каждая конфигурация Terraform использует провайдеры, такие как github
, которые позволяют взаимодействовать с конкретными API для управления ресурсами — в вашем случае это репозитории GitHub.
Когда вы создаете ресурсы в Terraform, информация об этих ресурсах записывается в файл состояния. Это состояние необходимо для управления временем жизни ресурсов, включая их создание и удаление. Если вы просто удалите блок модуля из вашей конфигурации, Terraform потеряет связь с состоянием этих ресурсов, что приведет к ошибке, с которой вы столкнулись.
Пример:
В вашем случае проблема заключается в следующем: блок провайдера github
прописан внутри модуля common_repository
. Это не является хорошей практикой, так как провайдеры, определённые в модулях, создают жесткую связь между конфигурацией и схемой провайдера, что может осложнить управление инфраструктурой, особенно при удалении ресурсов.
Как вы сами отметили, документация Terraform и сообщество настоятельно рекомендуют не определять блоки провайдеров в модулях. Это связано с тем, что Terraform использует связь между состоянием и конфигурацией: если конфигурация провайдера удалена, Terraform теряет информацию, необходимую для взаимодействия с API.
Применение:
На практике, чтобы разрушить эти ресурсы, вам нужно временно вернуть привязку состояния. Для этого:
-
Верните первоначальный блок провайдеров: Начните с возврата конфигурации провайдера
github
в ваш модуль. Это нужно для того, чтобы обеспечить Terraform доступ к API GitHub через провайдер. -
Используйте команду terraforms: Запустите
terraform destroy -target=module.repo_sandbox
в корне вашей конфигурации. Эта команда удалит все ресурсы, созданные модулемrepo_sandbox
. -
Проверьте состояние: После выполнения команды убедитесь, что состояние удалено корректно. Вы можете использовать
terraform plan
для подтверждения, что больше нет ресурсов, связанных с модулем. -
Перенесите провайдер на уровень корня: Переместите блоки провайдеров из модуля на уровень корневой конфигурации. Это не только упростит управление состоянием в будущем, но и позволит использовать один провайдер для нескольких модулей.
Следуя этим шагам, вы сможете корректно удалить ресурсы и минимизировать риск дальнейших ошибок, связанных с отсутствием конфигурации провайдера. Это также приведет ваш код в соответствие с лучшими практиками Terraform, что облегчит управление инфраструктурой в будущем.