From 4e8adc9c4317da7948de2a023ed2c6b9065ff6da Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Fri, 28 Jun 2024 19:52:25 +0200 Subject: [PATCH] Update `modules/artifact-registry` with newly-released features. (#2396) Fixes #2377 --- .../03-orchestration.tf | 3 +- .../data-solutions/vertex-mlops/ci-cd.tf | 3 +- blueprints/gke/autopilot/main.tf | 3 +- blueprints/gke/binauthz/main.tf | 3 +- .../gke/patterns/autopilot-cluster/main.tf | 3 +- modules/artifact-registry/README.md | 136 +++++++++++---- modules/artifact-registry/main.tf | 92 +++++++++-- modules/artifact-registry/outputs.tf | 17 +- modules/artifact-registry/variables.tf | 155 ++++++++++++++---- .../examples/other-formats.yaml | 134 +++++++++++++++ 10 files changed, 456 insertions(+), 93 deletions(-) create mode 100644 tests/modules/artifact_registry/examples/other-formats.yaml diff --git a/blueprints/data-solutions/data-platform-foundations/03-orchestration.tf b/blueprints/data-solutions/data-platform-foundations/03-orchestration.tf index 0f3ddb8cdd..57ffd10dc9 100644 --- a/blueprints/data-solutions/data-platform-foundations/03-orchestration.tf +++ b/blueprints/data-solutions/data-platform-foundations/03-orchestration.tf @@ -1,4 +1,4 @@ -# Copyright 2023 Google LLC +# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -155,6 +155,7 @@ module "orch-artifact-reg" { name = "${var.prefix}-app-images" location = var.region description = "Docker repository storing application images e.g. Dataflow, Cloud Run etc..." + format = { docker = { standard = {} } } } module "orch-cs-df-template" { diff --git a/blueprints/data-solutions/vertex-mlops/ci-cd.tf b/blueprints/data-solutions/vertex-mlops/ci-cd.tf index 28fb320bc1..1d07c26bb0 100644 --- a/blueprints/data-solutions/vertex-mlops/ci-cd.tf +++ b/blueprints/data-solutions/vertex-mlops/ci-cd.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,6 +43,7 @@ module "artifact_registry" { name = "docker-repo" project_id = module.project.project_id location = var.region + format = { docker = { standard = {} } } } module "service-account-github" { diff --git a/blueprints/gke/autopilot/main.tf b/blueprints/gke/autopilot/main.tf index 707f651656..84b7fe06e8 100644 --- a/blueprints/gke/autopilot/main.tf +++ b/blueprints/gke/autopilot/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,6 +59,7 @@ module "docker_artifact_registry" { project_id = module.project.project_id location = var.region name = "registry" + format = { docker = { standard = {} } } iam = { "roles/artifactregistry.reader" = [module.node_sa.iam_email] } diff --git a/blueprints/gke/binauthz/main.tf b/blueprints/gke/binauthz/main.tf index 09e502d793..521c6351bf 100644 --- a/blueprints/gke/binauthz/main.tf +++ b/blueprints/gke/binauthz/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -170,6 +170,7 @@ module "docker_artifact_registry" { project_id = module.project.project_id location = var.region name = "${var.prefix}-registry" + format = { docker = { standard = {} } } iam = { "roles/artifactregistry.writer" = [module.image_cb_sa.iam_email] "roles/artifactregistry.reader" = [module.cluster_nodepool.service_account_iam_email] diff --git a/blueprints/gke/patterns/autopilot-cluster/main.tf b/blueprints/gke/patterns/autopilot-cluster/main.tf index daea6e5c2f..9b4e164bd7 100644 --- a/blueprints/gke/patterns/autopilot-cluster/main.tf +++ b/blueprints/gke/patterns/autopilot-cluster/main.tf @@ -154,8 +154,7 @@ module "registry" { project_id = module.project.project_id location = var.region name = var.prefix - format = { docker = {} } - mode = { remote = true } + format = { docker = { remote = { public_repository = "DOCKER_HUB" } } } } module "nat" { diff --git a/modules/artifact-registry/README.md b/modules/artifact-registry/README.md index 59236a4b28..7e99a4e1b7 100644 --- a/modules/artifact-registry/README.md +++ b/modules/artifact-registry/README.md @@ -3,15 +3,16 @@ This module simplifies the creation of repositories using Google Cloud Artifact Registry. -- [Standard Repository](#standard-repository) +- [Simple Docker Repository](#simple-docker-repository) - [Remote and Virtual Repositories](#remote-and-virtual-repositories) - [Additional Docker and Maven Options](#additional-docker-and-maven-options) +- [Other Formats](#other-formats) - [Cleanup Policies](#cleanup-policies) - [Variables](#variables) - [Outputs](#outputs) -## Standard Repository +## Simple Docker Repository ```hcl module "docker_artifact_registry" { @@ -19,6 +20,7 @@ module "docker_artifact_registry" { project_id = "myproject" location = "europe-west1" name = "myregistry" + format = { docker = { standard = {} } } iam = { "roles/artifactregistry.admin" = ["group:cicd@example.com"] } @@ -35,7 +37,11 @@ module "registry-local" { project_id = var.project_id location = "europe-west1" name = "local" - format = { python = {} } + format = { + python = { + standard = true + } + } } module "registry-remote" { @@ -43,8 +49,13 @@ module "registry-remote" { project_id = var.project_id location = "europe-west1" name = "remote" - format = { python = {} } - mode = { remote = true } + format = { + python = { + remote = { + public_repository = "PYPI" + } + } + } } module "registry-virtual" { @@ -52,16 +63,17 @@ module "registry-virtual" { project_id = var.project_id location = "europe-west1" name = "virtual" - format = { python = {} } - mode = { - virtual = { - remote = { - repository = module.registry-remote.id - priority = 1 - } - local = { - repository = module.registry-local.id - priority = 10 + format = { + python = { + virtual = { + remote = { + repository = module.registry-remote.id + priority = 1 + } + local = { + repository = module.registry-local.id + priority = 10 + } } } } @@ -81,7 +93,9 @@ module "registry-docker" { name = "docker" format = { docker = { - immutable_tags = true + standard = { + immutable_tags = true + } } } } @@ -93,8 +107,10 @@ module "registry-maven" { name = "maven" format = { maven = { - allow_snapshot_overwrites = true - version_policy = "RELEASE" + standard = { + allow_snapshot_overwrites = true + version_policy = "RELEASE" + } } } } @@ -102,16 +118,77 @@ module "registry-maven" { # tftest modules=2 resources=2 ``` -## Cleanup Policies +## Other Formats ```hcl +module "apt-registry" { + source = "./fabric/modules/artifact-registry" + project_id = var.project_id + location = var.region + name = "apt-registry" + format = { apt = { standard = true } } +} + +module "generic-registry" { + source = "./fabric/modules/artifact-registry" + project_id = var.project_id + location = var.region + name = "generic-registry" + format = { generic = { standard = true } } +} + +module "go-registry" { + source = "./fabric/modules/artifact-registry" + project_id = var.project_id + location = var.region + name = "go-registry" + format = { go = { standard = true } } +} + +module "googet-registry" { + source = "./fabric/modules/artifact-registry" + project_id = var.project_id + location = var.region + name = "googet-registry" + format = { googet = { standard = true } } +} + +module "kfp-registry" { + source = "./fabric/modules/artifact-registry" + project_id = var.project_id + location = var.region + name = "kfp-registry" + format = { kfp = { standard = true } } +} + +module "npm-registry" { + source = "./fabric/modules/artifact-registry" + project_id = var.project_id + location = var.region + name = "npm-registry" + format = { npm = { standard = true } } +} + +module "yum-registry" { + source = "./fabric/modules/artifact-registry" + project_id = var.project_id + location = var.region + name = "yum-registry" + format = { yum = { standard = true } } +} + +# tftest modules=7 resources=7 inventory=other-formats.yaml +``` + +## Cleanup Policies +```hcl module "registry-docker" { source = "./fabric/modules/artifact-registry" project_id = var.project_id location = "europe-west1" name = "docker-cleanup-policies" - format = { docker = {} } + format = { docker = { standard = {} } } cleanup_policy_dry_run = false cleanup_policies = { keep-5-versions = { @@ -131,8 +208,6 @@ module "registry-docker" { } } } - - # tftest modules=1 resources=1 inventory=cleanup-policies.yaml ``` @@ -141,22 +216,21 @@ module "registry-docker" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| | [cleanup_policies](variables.tf#L17) | Object containing details about the cleanup policies for an Artifact Registry repository. | map(object({…default = null | ✓ | | -| [location](variables.tf#L95) | Registry location. Use `gcloud beta artifacts locations list' to get valid values. | string | ✓ | | -| [name](variables.tf#L120) | Registry name. | string | ✓ | | -| [project_id](variables.tf#L125) | Registry project id. | string | ✓ | | +| [format](variables.tf#L56) | Repository format. | object({…}) | ✓ | | +| [location](variables.tf#L208) | Registry location. Use `gcloud beta artifacts locations list' to get valid values. | string | ✓ | | +| [name](variables.tf#L213) | Registry name. | string | ✓ | | +| [project_id](variables.tf#L218) | Registry project id. | string | ✓ | | | [cleanup_policy_dry_run](variables.tf#L38) | If true, the cleanup pipeline is prevented from deleting versions in this repository. | bool | | null | | [description](variables.tf#L44) | An optional description for the repository. | string | | "Terraform-managed registry" | | [encryption_key](variables.tf#L50) | The KMS key name to use for encryption at rest. | string | | null | -| [format](variables.tf#L56) | Repository format. | object({…}) | | { docker = {} } | -| [iam](variables.tf#L83) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [labels](variables.tf#L89) | Labels to be attached to the registry. | map(string) | | {} | -| [mode](variables.tf#L100) | Repository mode. | object({…}) | | { standard = true } | +| [iam](variables.tf#L196) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [labels](variables.tf#L202) | Labels to be attached to the registry. | map(string) | | {} | ## Outputs | name | description | sensitive | |---|---|:---:| | [id](outputs.tf#L17) | Fully qualified repository id. | | -| [image_path](outputs.tf#L22) | Repository path for images. | | -| [name](outputs.tf#L32) | Repository name. | | +| [name](outputs.tf#L22) | Repository name. | | +| [repository](outputs.tf#L27) | Repository object. | | diff --git a/modules/artifact-registry/main.tf b/modules/artifact-registry/main.tf index e248900545..bef5c4f894 100644 --- a/modules/artifact-registry/main.tf +++ b/modules/artifact-registry/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,9 @@ */ locals { + format_obj = one([for k, v in var.format : v if v != null]) format_string = one([for k, v in var.format : k if v != null]) - mode_string = one([for k, v in var.mode : k if v != null && v != false]) + mode_string = one([for k, v in local.format_obj : k if v != null && v != false]) } resource "google_artifact_registry_repository" "registry" { @@ -62,48 +63,111 @@ resource "google_artifact_registry_repository" "registry" { dynamic "docker_config" { # TODO: open a bug on the provider for this permadiff for_each = ( - local.format_string == "docker" && try(var.format.docker.immutable_tags, null) == true - ? [""] - : [] + local.format_string == "docker" && try(local.format_obj.standard.immutable_tags, null) == true + ? [""] : [] ) content { - immutable_tags = var.format.docker.immutable_tags + immutable_tags = local.format_obj.standard.immutable_tags } } dynamic "maven_config" { for_each = local.format_string == "maven" ? [""] : [] content { - allow_snapshot_overwrites = var.format.maven.allow_snapshot_overwrites - version_policy = var.format.maven.version_policy + allow_snapshot_overwrites = try(local.format_obj.standard.allow_snapshot_overwrites, null) + version_policy = try(local.format_obj.standard.version_policy, null) } } dynamic "remote_repository_config" { for_each = local.mode_string == "remote" ? [""] : [] content { + disable_upstream_validation = local.format_obj.remote.disable_upstream_validation + dynamic "upstream_credentials" { + for_each = local.format_obj.remote.upstream_credentials != null ? [""] : [] + content { + username_password_credentials { + username = local.format_obj.remote.upstream_credentials.username + password_secret_version = local.format_obj.remote.upstream_credentials.password_secret_version + } + } + } + dynamic "apt_repository" { + for_each = local.format_string == "apt" ? [""] : [] + content { + public_repository { + repository_base = split(" ", local.format_obj.remote.public_repository)[0] + repository_path = split(" ", local.format_obj.remote.public_repository)[1] + } + # dynamic "custom_repository" { + # for_each = local.format_obj.remote.custom_repository != null ? [""] : [] + # content { + # uri = local.format_obj.remote.custom_repository + # } + # } + } + } dynamic "docker_repository" { for_each = local.format_string == "docker" ? [""] : [] content { - public_repository = "DOCKER_HUB" + public_repository = local.format_obj.remote.public_repository + dynamic "custom_repository" { + for_each = local.format_obj.remote.custom_repository != null ? [""] : [] + content { + uri = local.format_obj.remote.custom_repository + } + } } } dynamic "maven_repository" { for_each = local.format_string == "maven" ? [""] : [] content { - public_repository = "MAVEN_CENTRAL" + public_repository = local.format_obj.remote.public_repository + dynamic "custom_repository" { + for_each = local.format_obj.remote.custom_repository != null ? [""] : [] + content { + uri = local.format_obj.remote.custom_repository + } + } } } dynamic "npm_repository" { for_each = local.format_string == "npm" ? [""] : [] content { - public_repository = "NPMJS" + public_repository = local.format_obj.remote.public_repository + dynamic "custom_repository" { + for_each = local.format_obj.remote.custom_repository != null ? [""] : [] + content { + uri = local.format_obj.remote.custom_repository + } + } } } dynamic "python_repository" { for_each = local.format_string == "python" ? [""] : [] content { - public_repository = "PYPI" + public_repository = local.format_obj.remote.public_repository + dynamic "custom_repository" { + for_each = local.format_obj.remote.custom_repository != null ? [""] : [] + content { + uri = local.format_obj.remote.custom_repository + } + } + } + } + dynamic "yum_repository" { + for_each = local.format_string == "yum" ? [""] : [] + content { + public_repository { + repository_base = split(" ", local.format_obj.remote.public_repository)[0] + repository_path = split(" ", local.format_obj.remote.public_repository)[1] + } + # dynamic "custom_repository" { + # for_each = local.format_obj.remote.custom_repository != null ? [""] : [] + # content { + # uri = local.format_obj.remote.custom_repository + # } + # } } } } @@ -113,7 +177,7 @@ resource "google_artifact_registry_repository" "registry" { for_each = local.mode_string == "virtual" ? [""] : [] content { dynamic "upstream_policies" { - for_each = var.mode.virtual + for_each = local.format_obj.virtual content { id = upstream_policies.key repository = upstream_policies.value.repository @@ -126,7 +190,7 @@ resource "google_artifact_registry_repository" "registry" { lifecycle { precondition { condition = local.mode_string != "remote" || contains( - ["docker", "maven", "npm", "python"], local.format_string + ["apt", "docker", "maven", "npm", "python", "yum"], local.format_string ) error_message = "Invalid format for remote repository." } diff --git a/modules/artifact-registry/outputs.tf b/modules/artifact-registry/outputs.tf index b41faf82b4..29462e358f 100644 --- a/modules/artifact-registry/outputs.tf +++ b/modules/artifact-registry/outputs.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,17 +19,12 @@ output "id" { value = google_artifact_registry_repository.registry.id } -output "image_path" { - description = "Repository path for images." - value = join("/", [ - "${var.location}-${local.format_string}.pkg.dev", - var.project_id, - var.name - ]) - depends_on = [google_artifact_registry_repository.registry] -} - output "name" { description = "Repository name." value = google_artifact_registry_repository.registry.name } + +output "repository" { + description = "Repository object." + value = google_artifact_registry_repository.registry +} diff --git a/modules/artifact-registry/variables.tf b/modules/artifact-registry/variables.tf index d80ed3014b..4d46e4a991 100644 --- a/modules/artifact-registry/variables.tf +++ b/modules/artifact-registry/variables.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,28 +56,141 @@ variable "encryption_key" { variable "format" { description = "Repository format." type = object({ - apt = optional(object({})) + apt = optional(object({ + remote = optional(object({ + # custom_repository = optional(string) # still not available in provider + public_repository = string # "BASE path" + + disable_upstream_validation = optional(bool) + upstream_credentials = optional(object({ + username = string + password_secret_version = string + })) + })) + standard = optional(bool) + })) docker = optional(object({ - immutable_tags = optional(bool) + remote = optional(object({ + public_repository = optional(string) + custom_repository = optional(string) + + disable_upstream_validation = optional(bool) + upstream_credentials = optional(object({ + username = string + password_secret_version = string + })) + })) + standard = optional(object({ + immutable_tags = optional(bool) + })) + virtual = optional(map(object({ + repository = string + priority = number + }))) + })) + kfp = optional(object({ + standard = optional(bool) + })) + generic = optional(object({ + standard = optional(bool) + })) + go = optional(object({ + standard = optional(bool) + })) + googet = optional(object({ + standard = optional(bool) })) - kfp = optional(object({})) - go = optional(object({})) maven = optional(object({ - allow_snapshot_overwrites = optional(bool) - version_policy = optional(string) + remote = optional(object({ + public_repository = optional(string) + custom_repository = optional(string) + + disable_upstream_validation = optional(bool) + upstream_credentials = optional(object({ + username = string + password_secret_version = string + })) + })) + standard = optional(object({ + allow_snapshot_overwrites = optional(bool) + version_policy = optional(string) + })) + virtual = optional(map(object({ + repository = string + priority = number + }))) + })) + npm = optional(object({ + remote = optional(object({ + public_repository = optional(string) + custom_repository = optional(string) + + disable_upstream_validation = optional(bool) + upstream_credentials = optional(object({ + username = string + password_secret_version = string + })) + })) + standard = optional(bool) + virtual = optional(map(object({ + repository = string + priority = number + }))) + })) + python = optional(object({ + remote = optional(object({ + public_repository = optional(string) + custom_repository = optional(string) + + disable_upstream_validation = optional(bool) + upstream_credentials = optional(object({ + username = string + password_secret_version = string + })) + })) + standard = optional(bool) + virtual = optional(map(object({ + repository = string + priority = number + }))) + })) + yum = optional(object({ + remote = optional(object({ + # custom_repository = optional(string) # still not available in provider + public_repository = string # "BASE path" + + disable_upstream_validation = optional(bool) + upstream_credentials = optional(object({ + username = string + password_secret_version = string + })) + })) + standard = optional(bool) })) - npm = optional(object({})) - python = optional(object({})) - yum = optional(object({})) }) nullable = false - default = { docker = {} } validation { condition = ( length([for k, v in var.format : k if v != null]) == 1 ) error_message = "Multiple or zero formats are not supported." } + validation { + condition = alltrue([ + for k, v in var.format : + length([for kk, vv in v : k if vv != null]) == 1 + if v != null + ]) + error_message = "Repository can only be one of standard, remote or virtual." + } + validation { + condition = alltrue([ + for k, v in var.format : + (try(v.remote.public_repository, null) == null) != (try(v.remote.custom_repository, null) == null) + if try(v.remote, null) != null + ]) + error_message = "Remote repositories must specify exactly one of public_repository and custom_repository." + } } variable "iam" { @@ -97,26 +210,6 @@ variable "location" { type = string } -variable "mode" { - description = "Repository mode." - type = object({ - standard = optional(bool) - remote = optional(bool) - virtual = optional(map(object({ - repository = string - priority = number - }))) - }) - nullable = false - default = { standard = true } - validation { - condition = ( - length([for k, v in var.mode : k if v != null && v != false]) == 1 - ) - error_message = "Multiple or zero modes are not supported." - } -} - variable "name" { description = "Registry name." type = string diff --git a/tests/modules/artifact_registry/examples/other-formats.yaml b/tests/modules/artifact_registry/examples/other-formats.yaml new file mode 100644 index 0000000000..1af10cbf2f --- /dev/null +++ b/tests/modules/artifact_registry/examples/other-formats.yaml @@ -0,0 +1,134 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.apt-registry.google_artifact_registry_repository.registry: + cleanup_policies: [] + cleanup_policy_dry_run: null + description: Terraform-managed registry + docker_config: [] + format: APT + kms_key_name: null + labels: null + location: europe-west8 + maven_config: [] + mode: STANDARD_REPOSITORY + project: project-id + remote_repository_config: [] + repository_id: apt-registry + timeouts: null + virtual_repository_config: [] + module.generic-registry.google_artifact_registry_repository.registry: + cleanup_policies: [] + cleanup_policy_dry_run: null + description: Terraform-managed registry + docker_config: [] + format: GENERIC + kms_key_name: null + labels: null + location: europe-west8 + maven_config: [] + mode: STANDARD_REPOSITORY + project: project-id + remote_repository_config: [] + repository_id: generic-registry + timeouts: null + virtual_repository_config: [] + module.go-registry.google_artifact_registry_repository.registry: + cleanup_policies: [] + cleanup_policy_dry_run: null + description: Terraform-managed registry + docker_config: [] + format: GO + kms_key_name: null + labels: null + location: europe-west8 + maven_config: [] + mode: STANDARD_REPOSITORY + project: project-id + remote_repository_config: [] + repository_id: go-registry + timeouts: null + virtual_repository_config: [] + module.googet-registry.google_artifact_registry_repository.registry: + cleanup_policies: [] + cleanup_policy_dry_run: null + description: Terraform-managed registry + docker_config: [] + format: GOOGET + kms_key_name: null + labels: null + location: europe-west8 + maven_config: [] + mode: STANDARD_REPOSITORY + project: project-id + remote_repository_config: [] + repository_id: googet-registry + timeouts: null + virtual_repository_config: [] + module.kfp-registry.google_artifact_registry_repository.registry: + cleanup_policies: [] + cleanup_policy_dry_run: null + description: Terraform-managed registry + docker_config: [] + format: KFP + kms_key_name: null + labels: null + location: europe-west8 + maven_config: [] + mode: STANDARD_REPOSITORY + project: project-id + remote_repository_config: [] + repository_id: kfp-registry + timeouts: null + virtual_repository_config: [] + module.npm-registry.google_artifact_registry_repository.registry: + cleanup_policies: [] + cleanup_policy_dry_run: null + description: Terraform-managed registry + docker_config: [] + format: NPM + kms_key_name: null + labels: null + location: europe-west8 + maven_config: [] + mode: STANDARD_REPOSITORY + project: project-id + remote_repository_config: [] + repository_id: npm-registry + timeouts: null + virtual_repository_config: [] + module.yum-registry.google_artifact_registry_repository.registry: + cleanup_policies: [] + cleanup_policy_dry_run: null + description: Terraform-managed registry + docker_config: [] + format: YUM + kms_key_name: null + labels: null + location: europe-west8 + maven_config: [] + mode: STANDARD_REPOSITORY + project: project-id + remote_repository_config: [] + repository_id: yum-registry + timeouts: null + virtual_repository_config: [] + +counts: + google_artifact_registry_repository: 7 + modules: 7 + resources: 7 + +outputs: {}