Ресурс Terraform for_each с вложенным блоком Dynami c продолжает повторять те же изменения - PullRequest
1 голос
/ 26 марта 2020

Итак, я создал модуль google_bigquery для создания наборов данных и настройки доступа.

Модуль перебирает карту списка карт. Он использует ключ each.key для создания наборов данных, затем перебирает список карт для создания динамического доступа c.

Модуль работает следующим образом:

  • Он не имеет ни ошибок, ни предупреждений
  • Он развертывает ресурсы
  • Заполняет соответствующий файл удаленного состояния.

Проблема в том, что каждый раз, когда я запускаю terraform, он хочет повторно применить одни и те же изменения, снова и снова.

Ясно, что что-то не так, но не уверен, что.

вот код

main.tf

locals {
  env           = basename(path.cwd)
  project       = basename(abspath("${path.cwd}/../.."))
  project_name  = coalesce(var.project_name, format("%s-%s", local.project, local.env))
}

data "google_compute_zones" "available" {
  project = local.project_name
  region  = var.region
}

provider "google" {
  project = local.project_name
  region  = var.region
  version = "~> 2.0" #until 3.0 goes out of beta
}

terraform {
  required_version = ">= 0.12.12"
}

resource "google_bigquery_dataset" "main" {
  for_each                   = var.datasets
  dataset_id                 = upper("${each.key}_${local.env}")
  location                   = var.region
  delete_contents_on_destroy = true

  dynamic "access" {
    for_each = flatten([ for k, v in var.datasets : [
                 for i in each.value : {
                   role           = i.role
                   user_by_email  = i.user_by_email
                   group_by_email = i.group_by_email
                   dataset_id     = i.dataset_id
                   project_id     = i.project_id
                   table_id       = i.table_id
    }]])
    content {
      role           = lookup(access.value,"role", "")
      user_by_email  = lookup(access.value,"user_by_email","")
      group_by_email = lookup(access.value,"group_by_email","")
      view {
        dataset_id   = lookup(access.value,"dataset_id","")
        project_id   = lookup(access.value,"project_id","")
        table_id     = lookup(access.value,"table_id", "")
        }
    }
  }



  access {
    role          = "READER"
    special_group = "projectReaders"
  }

  access {
    role           = "OWNER"
    group_by_email = "Group"
  }

  access {
    role           = "OWNER"
    user_by_email  = "ServiceAccount"
  }

  access {
    role          = "WRITER"
    special_group = "projectWriters"
  }

}

variables.tf

variable "region" {
  description = ""
  default     = ""
}

variable "env" {
  default = ""
}

variable "project_name" {
  default = ""
}

variable "owner_group" {
  description = ""
  default     = ""
}

variable "owner_sa" {
  description = ""
  default = ""
}

variable "datasets" {
  description = "A map of objects, including dataset_isd abd access"
  type = map(list(map(string)))
}

terraform.tfvars

datasets = {
  dataset01 = [
    {
      role           = "WRITER"
      user_by_email  = "email_address"
      group_by_email = ""
      dataset_id     = ""
      project_id     = ""
      table_id       = ""
    },
    {
      role           = ""
      user_by_email  = ""
      group_by_email = ""
      dataset_id     ="MY_OTHER_DATASET"
      project_id     ="my_other_project"
      table_id       ="my_test_view"
    }
  ]
  dataset02 = [
    {
      role           = "READER"
      user_by_email  = ""
      group_by_email = "group"
      dataset_id     = ""
      project_id     = ""
      table_id       = ""
    },
    {
      role           = ""
      user_by_email  = ""
      group_by_email = ""
      dataset_id     ="MY_OTHER_DATASET"
      project_id     ="my_other_project"
      table_id       ="my_test_view_2"
    }
  ]
}

Таким образом, проблема заключается в том, что Блок dynamici c (как я его написал) может генерировать этот вывод

      + access {
          + role          = "WRITER"
          + special_group = "projectWriters"

          + view {}
        }

это применено, без ошибок, но он захочет повторно применять его снова и снова

Кажется, проблема в том, что ответ API провайдера не содержит пустого view{}

Любого предложения о том, как я могу сделать блок view c условно, если значения не равны нулю?

1 Ответ

0 голосов
/ 01 апреля 2020

Я исправил проблему. Я немного изменил модуль и тип переменной.

Я разделил роли и представления на их собственные списки карт в родительской карте наборов данных.

В каждом блоке есть условия, поэтому блок dynamici c применяется только в том случае, если существуют роли или представления.

Также понял, что блок dynamici c выполняет итерацию на неправильном итераторе.

блок dynamici c перебирал var.datasets, что приводило к применению разрешений, назначенных каждому набору данных, ко всем наборам данных. Так что теперь он был изменен на итерацию для каждого значения (из ресурса for_each).

Вот новый код, который работает

MAIN.TF

resource "google_bigquery_dataset" "main" {
  for_each                   = var.datasets
  dataset_id                 = upper("${each.key}_${local.env}")
  location                   = var.region
  delete_contents_on_destroy = true

  dynamic "access" {
    for_each = flatten([for i in each.value : [
      for k, v in i : [
        for l in v :
        {
          role           = l.role
          user_by_email  = l.user_by_email
          group_by_email = l.group_by_email
          special_group  = l.special_group
      }]
      if k == "roles"
    ]])
    content {
      role           = access.value["role"]
      user_by_email  = access.value["user_by_email"]
      group_by_email = access.value["group_by_email"]
      special_group  = access.value["special_group"]
    }
  }

  dynamic "access" {
    for_each = flatten([for i in each.value : [
      for k, v in i : [
        for l in v :
        {
          dataset_id = l.dataset_id
          project_id = l.project_id
          table_id   = l.table_id
      }]
      if k == "views"
    ]])
    content {
      view {
        dataset_id = access.value["dataset_id"]
        project_id = access.value["project_id"]
        table_id   = access.value["table_id"]
      }
    }
  }
}

VARIABLES.TF

variable "datasets" {
  description = "A map of objects, including datasets IDs, roles and views"
  type        = map(list(map(list(map(string)))))
  default     = {}
}

continued....

Terraform.tfvars

datasets = {
  dataset01 = [
    {
      roles = [
        {
          role="WRITER"
          user_by_email="email_address"
          group_by_email=""
          special_group=""
        }
      ]
    views = [
        {
          dataset_id="MY_OTHER_DATASET"
          project_id="my_other_project"
          table_id="my_test_view"
        }
      ]
    }
  ]
  dataset02 = [
    {
      roles = [
        {
          role="READER"
          user_by_email=""
          group_by_email="group"
          special_group=""
        }
      ]
      views=[
        {
          dataset_id="MY_OTHER_DATASET"
          project_id="my_other_project"
          table_id="my_test_view_2"
        }
      ]
    }     
  ]
}
...