diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index aedc15bb..00000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.5.3 diff --git a/CHANGELOG.md b/CHANGELOG.md index bfbc4928..b880a9ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ and this project adheres to ## [Unreleased] +## [1.0.0] - 2019-08-14 + +### Changed + +- Upgraded for usage with terraform-0.12.x [#9] +- Added support for `force_destroy` attribute [#9] + ## [0.1.0] - 2019-05-22 ### Added diff --git a/Gemfile b/Gemfile index 4dbdea25..6dc7c95f 100644 --- a/Gemfile +++ b/Gemfile @@ -15,5 +15,5 @@ ruby '2.5.3' source 'https://rubygems.org/' do - gem 'kitchen-terraform', '~> 4.8' + gem 'kitchen-terraform', '~> 4.9' end diff --git a/Makefile b/Makefile index 7f127c0e..bd31e8ac 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ SHELL := /usr/bin/env bash # Docker build config variables CREDENTIALS_PATH ?= /cft/workdir/credentials.json DOCKER_ORG := gcr.io/cloud-foundation-cicd -DOCKER_TAG_BASE_KITCHEN_TERRAFORM ?= 1.0.1 +DOCKER_TAG_BASE_KITCHEN_TERRAFORM ?= 2.3.0 DOCKER_REPO_BASE_KITCHEN_TERRAFORM := ${DOCKER_ORG}/cft/kitchen-terraform:${DOCKER_TAG_BASE_KITCHEN_TERRAFORM} # All is the first target in the file so it will get picked up when you just run 'make' on its own @@ -30,7 +30,7 @@ all: check generate_docs # Run all available linters .PHONY: check -check: check_shell check_python check_golang check_terraform check_docker check_base_files test_check_headers check_headers check_trailing_whitespace +check: check_python check_golang check_terraform check_base_files test_check_headers check_headers check_trailing_whitespace # The .PHONY directive tells make that this isn't a real target and so # the presence of a file named 'check_shell' won't cause this target to stop @@ -93,9 +93,9 @@ docker_run: -e PROJECT_ID \ -e SERVICE_ACCOUNT_JSON \ -e GOOGLE_APPLICATION_CREDENTIALS=${CREDENTIALS_PATH} \ - -v "$(CURDIR)":/cft/workdir \ + -v $(CURDIR):/cft/workdir \ ${DOCKER_REPO_BASE_KITCHEN_TERRAFORM} \ - /bin/bash -c "source test/ci_integration.sh && setup_environment && exec /bin/bash" + /bin/bash -c "cd /cft/workdir && source test/ci_integration.sh && setup_environment && exec /bin/bash" .PHONY: docker_create docker_create: @@ -103,9 +103,9 @@ docker_create: -e PROJECT_ID \ -e SERVICE_ACCOUNT_JSON \ -e GOOGLE_APPLICATION_CREDENTIALS=${CREDENTIALS_PATH} \ - -v "$(CURDIR)":/cft/workdir \ + -v $(CURDIR):/cft/workdir \ ${DOCKER_REPO_BASE_KITCHEN_TERRAFORM} \ - /bin/bash -c "source test/ci_integration.sh && setup_environment && kitchen create" + /bin/bash -c "cd /cft/workdir && source test/ci_integration.sh && setup_environment && kitchen create" .PHONY: docker_converge docker_converge: @@ -113,9 +113,9 @@ docker_converge: -e PROJECT_ID \ -e SERVICE_ACCOUNT_JSON \ -e GOOGLE_APPLICATION_CREDENTIALS=${CREDENTIALS_PATH} \ - -v "$(CURDIR)":/cft/workdir \ + -v $(CURDIR):/cft/workdir \ ${DOCKER_REPO_BASE_KITCHEN_TERRAFORM} \ - /bin/bash -c "source test/ci_integration.sh && setup_environment && kitchen converge" + /bin/bash -c "cd /cft/workdir && source test/ci_integration.sh && setup_environment && kitchen converge" .PHONY: docker_verify docker_verify: @@ -123,9 +123,9 @@ docker_verify: -e PROJECT_ID \ -e SERVICE_ACCOUNT_JSON \ -e GOOGLE_APPLICATION_CREDENTIALS=${CREDENTIALS_PATH} \ - -v "$(CURDIR)":/cft/workdir \ + -v $(CURDIR):/cft/workdir \ ${DOCKER_REPO_BASE_KITCHEN_TERRAFORM} \ - /bin/bash -c "source test/ci_integration.sh && setup_environment && kitchen verify" + /bin/bash -c "cd /cft/workdir && source test/ci_integration.sh && setup_environment && kitchen verify" .PHONY: docker_destroy docker_destroy: @@ -133,9 +133,9 @@ docker_destroy: -e PROJECT_ID \ -e SERVICE_ACCOUNT_JSON \ -e GOOGLE_APPLICATION_CREDENTIALS=${CREDENTIALS_PATH} \ - -v "$(CURDIR)":/cft/workdir \ + -v $(CURDIR):/cft/workdir \ ${DOCKER_REPO_BASE_KITCHEN_TERRAFORM} \ - /bin/bash -c "source test/ci_integration.sh && setup_environment && kitchen destroy" + /bin/bash -c "cd /cft/workdir && source test/ci_integration.sh && setup_environment && kitchen destroy" .PHONY: test_integration_docker test_integration_docker: @@ -143,6 +143,6 @@ test_integration_docker: -e PROJECT_ID \ -e SERVICE_ACCOUNT_JSON \ -e GOOGLE_APPLICATION_CREDENTIALS=${CREDENTIALS_PATH} \ - -v "$(CURDIR)":/cft/workdir \ + -v $(CURDIR):/cft/workdir \ ${DOCKER_REPO_BASE_KITCHEN_TERRAFORM} \ - make test_integration + /bin/bash -c "cd /cft/workdir && source test/ci_integration.sh && setup_environment && make test_integration" diff --git a/README.md b/README.md index 3129e86c..b01e75a7 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,12 @@ The resources/services/activations/deletions that this module will create/trigge - One or more GCS buckets - Zero or more IAM bindings for those buckets +## Compatibility + + This module is meant for use with Terraform 0.12. If you haven't [upgraded](https://www.terraform.io/upgrade-guides/0-12.html) + and need a Terraform 0.11.x-compatible version of this module, the last released version intended for + Terraform 0.11.x is [0.1.0](https://registry.terraform.io/modules/terraform-google-modules/cloud-storage/google/0.1.0). + ## Usage Basic usage of this module is as follows: @@ -32,8 +38,7 @@ module "gcs_buckets" { Functional examples are included in the [examples](./examples/) directory. -[^]: (autogen_docs_start) - + ## Inputs | Name | Description | Type | Default | Required | @@ -44,9 +49,10 @@ Functional examples are included in the | bucket\_policy\_only | Disable ad-hoc ACLs on specified buckets. Defaults to true. Map of lowercase unprefixed name => boolean | map | `` | no | | bucket\_viewers | Map of lowercase unprefixed name => comma-delimited IAM-style bucket viewers. | map | `` | no | | creators | IAM-style members who will be granted roles/storage.objectCreators on all buckets. | list | `` | no | +| force\_destroy | Optional map of lowercase unprefixed name => boolean, defaults to false. | map | `` | no | | labels | Labels to be attached to the buckets | map | `` | no | | location | Bucket location. | string | `"EU"` | no | -| names | Bucket name suffixes. | list | n/a | yes | +| names | Bucket name suffixes. | list(string) | n/a | yes | | prefix | Prefix used to generate the bucket name. | string | n/a | yes | | project\_id | Bucket project id. | string | n/a | yes | | set\_admin\_roles | Grant roles/storage.objectAdmin role to admins and bucket_admins. | string | `"false"` | no | @@ -60,12 +66,16 @@ Functional examples are included in the | Name | Description | |------|-------------| -| name | Bucket name of the first bucket (for single-use cases). | -| names | Map of unprefixed names => bucket names. | -| url | URL of the first bucket (for single-use cases). | -| urls | Map of unprefixed names => bucket URLs. | +| bucket | Bucket resource (for single use). | +| buckets | Bucket resources. | +| name | Bucket name (for single use). | +| names | Bucket names. | +| names\_list | List of bucket names. | +| url | Bucket URL (for single use). | +| urls | Bucket URLs. | +| urls\_list | List of bucket URLs. | -[^]: (autogen_docs_end) + ## Requirements @@ -107,3 +117,4 @@ information on contributing to this module. [project-factory-module]: https://registry.terraform.io/modules/terraform-google-modules/project-factory/google [terraform-provider-gcp]: https://www.terraform.io/docs/providers/google/index.html [terraform]: https://www.terraform.io/downloads.html + diff --git a/examples/simple_example/README.md b/examples/simple_example/README.md index e88fafaa..ca6d4a35 100644 --- a/examples/simple_example/README.md +++ b/examples/simple_example/README.md @@ -2,14 +2,13 @@ This example illustrates how to use the `cloud-storage` module. -[^]: (autogen_docs_start) - + ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| bucket\_policy\_only | Disable ad-hoc ACLs on specified buckets. Defaults to true. Map of lowercase unprefixed name => boolean | map | n/a | yes | -| names | Names of the buckets to create. | list | n/a | yes | +| bucket\_policy\_only | Disable ad-hoc ACLs on specified buckets. Defaults to true. Map of lowercase unprefixed name => boolean | map(string) | n/a | yes | +| names | Names of the buckets to create. | list(string) | n/a | yes | | prefix | Prefix used to generate bueckt names. | string | n/a | yes | | project\_id | The ID of the project in which to provision resources. | string | n/a | yes | @@ -17,9 +16,10 @@ This example illustrates how to use the `cloud-storage` module. | Name | Description | |------|-------------| -| names | Names of the buckets created. | +| names | Bucket names. | +| names\_list | List of bucket names. | -[^]: (autogen_docs_end) + To provision this example, run the following from within this directory: - `terraform init` to get the plugins diff --git a/examples/simple_example/main.tf b/examples/simple_example/main.tf index 4737a024..540ec043 100644 --- a/examples/simple_example/main.tf +++ b/examples/simple_example/main.tf @@ -19,10 +19,10 @@ provider "google" { } module "cloud_storage" { - source = "../.." - - project_id = "${var.project_id}" - prefix = "${var.prefix}" - names = "${var.names}" - bucket_policy_only = "${var.bucket_policy_only}" + source = "../.." + project_id = var.project_id + prefix = var.prefix + names = var.names + bucket_policy_only = var.bucket_policy_only } + diff --git a/examples/simple_example/outputs.tf b/examples/simple_example/outputs.tf index d050853d..18a0211d 100644 --- a/examples/simple_example/outputs.tf +++ b/examples/simple_example/outputs.tf @@ -15,6 +15,11 @@ */ output "names" { - description = "Names of the buckets created." - value = "${values(module.cloud_storage.names)}" + description = "Bucket names." + value = module.cloud_storage.names +} + +output "names_list" { + description = "List of bucket names." + value = module.cloud_storage.names_list } diff --git a/examples/simple_example/variables.tf b/examples/simple_example/variables.tf index 40784e91..e6d05d54 100644 --- a/examples/simple_example/variables.tf +++ b/examples/simple_example/variables.tf @@ -16,20 +16,21 @@ variable "project_id" { description = "The ID of the project in which to provision resources." - type = "string" + type = string } variable "names" { description = "Names of the buckets to create." - type = "list" + type = list(string) } variable "prefix" { description = "Prefix used to generate bueckt names." - type = "string" + type = string } variable "bucket_policy_only" { description = "Disable ad-hoc ACLs on specified buckets. Defaults to true. Map of lowercase unprefixed name => boolean" - type = "map" + type = map(string) } + diff --git a/examples/simple_example/versions.tf b/examples/simple_example/versions.tf new file mode 100644 index 00000000..ac97c6ac --- /dev/null +++ b/examples/simple_example/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/kitchen.yml b/kitchen.yml index f3c9c354..8b65aa90 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -35,9 +35,4 @@ suites: - name: simple_example local backend: local controls: - - gcloud - gsutil - - name: simple_example gcp - backend: gcp - controls: - - gcp diff --git a/main.tf b/main.tf index 71a3b8db..dd9f8d71 100644 --- a/main.tf +++ b/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2018 Google LLC + * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,65 +14,77 @@ * limitations under the License. */ -terraform { - required_version = "~> 0.11.0" -} - locals { - prefix = "${var.prefix == "" ? "" : "${var.prefix}-"}${lower(var.location)}" + prefix = var.prefix == "" ? "" : join("-", list(var.prefix, lower(var.location), "")) } resource "google_storage_bucket" "buckets" { - count = "${length(var.names)}" - name = "${var.prefix}-${lower(element(var.names, count.index))}" - project = "${var.project_id}" - bucket_policy_only = "${lookup(var.bucket_policy_only, lower(element(var.names, count.index)), true)}" - location = "${var.location}" - storage_class = "${var.storage_class}" - labels = "${var.labels}" - + count = length(var.names) + name = "${local.prefix}${lower(element(var.names, count.index))}" + project = var.project_id + location = var.location + storage_class = var.storage_class + labels = var.labels + force_destroy = lookup( + var.force_destroy, + lower(element(var.names, count.index)), + false, + ) + bucket_policy_only = lookup( + var.bucket_policy_only, + lower(element(var.names, count.index)), + true, + ) versioning { - enabled = "${ - lookup(var.versioning, lower(element(var.names, count.index)), false) - }" + enabled = lookup( + var.versioning, + lower(element(var.names, count.index)), + false, + ) } } resource "google_storage_bucket_iam_binding" "admins" { - count = "${var.set_admin_roles ? length(var.names) : 0}" - bucket = "${element(google_storage_bucket.buckets.*.name, count.index)}" + count = var.set_admin_roles ? length(var.names) : 0 + bucket = element(google_storage_bucket.buckets.*.name, count.index) role = "roles/storage.objectAdmin" - - members = ["${compact(concat( - var.admins, - split(",", - lookup(var.bucket_admins, element(var.names, count.index), "") - ) - ))}"] + members = compact( + concat( + var.admins, + split( + ",", + lookup(var.bucket_admins, element(var.names, count.index), ""), + ), + ), + ) } resource "google_storage_bucket_iam_binding" "creators" { - count = "${var.set_creator_roles ? length(var.names) : 0}" - bucket = "${element(google_storage_bucket.buckets.*.name, count.index)}" + count = var.set_creator_roles ? length(var.names) : 0 + bucket = element(google_storage_bucket.buckets.*.name, count.index) role = "roles/storage.objectCreator" - - members = ["${compact(concat( - var.creators, - split(",", - lookup(var.bucket_creators, element(var.names, count.index), "") - ) - ))}"] + members = compact( + concat( + var.creators, + split( + ",", + lookup(var.bucket_creators, element(var.names, count.index), ""), + ), + ), + ) } resource "google_storage_bucket_iam_binding" "viewers" { - count = "${var.set_viewer_roles ? length(var.names) : 0}" - bucket = "${element(google_storage_bucket.buckets.*.name, count.index)}" + count = var.set_viewer_roles ? length(var.names) : 0 + bucket = element(google_storage_bucket.buckets.*.name, count.index) role = "roles/storage.objectViewer" - - members = ["${compact(concat( - var.viewers, - split(",", - lookup(var.bucket_viewers, element(var.names, count.index), "") - ) - ))}"] + members = compact( + concat( + var.viewers, + split( + ",", + lookup(var.bucket_viewers, element(var.names, count.index), ""), + ), + ), + ) } diff --git a/outputs.tf b/outputs.tf index 96a21b43..e548fbaf 100644 --- a/outputs.tf +++ b/outputs.tf @@ -14,22 +14,42 @@ * limitations under the License. */ +output "bucket" { + description = "Bucket resource (for single use)." + value = google_storage_bucket.buckets[0] +} + output "name" { - description = "Bucket name of the first bucket (for single-use cases)." - value = "${element(google_storage_bucket.buckets.*.name, 0)}" + description = "Bucket name (for single use)." + value = google_storage_bucket.buckets[0].name } output "url" { - description = "URL of the first bucket (for single-use cases)." - value = "${element(google_storage_bucket.buckets.*.url, 0)}" + description = "Bucket URL (for single use)." + value = google_storage_bucket.buckets[0].url +} + +output "buckets" { + description = "Bucket resources." + value = google_storage_bucket.buckets } output "names" { - description = "Map of unprefixed names => bucket names." - value = "${zipmap(var.names, google_storage_bucket.buckets.*.name)}" + description = "Bucket names." + value = zipmap(var.names, google_storage_bucket.buckets[*].name) } output "urls" { - description = "Map of unprefixed names => bucket URLs." - value = "${zipmap(var.names, google_storage_bucket.buckets.*.url)}" + description = "Bucket URLs." + value = zipmap(var.names, google_storage_bucket.buckets[*].url) +} + +output "names_list" { + description = "List of bucket names." + value = google_storage_bucket.buckets[*].name +} + +output "urls_list" { + description = "List of bucket URLs." + value = google_storage_bucket.buckets[*].url } diff --git a/test/boilerplate/boilerplate.Dockerfile.txt b/test/boilerplate/boilerplate.Dockerfile.txt index b0c7da3d..1b991897 100644 --- a/test/boilerplate/boilerplate.Dockerfile.txt +++ b/test/boilerplate/boilerplate.Dockerfile.txt @@ -1,4 +1,4 @@ -# Copyright 2018 Google LLC +# Copyright YEAR Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/test/boilerplate/boilerplate.Makefile.txt b/test/boilerplate/boilerplate.Makefile.txt index b0c7da3d..1b991897 100644 --- a/test/boilerplate/boilerplate.Makefile.txt +++ b/test/boilerplate/boilerplate.Makefile.txt @@ -1,4 +1,4 @@ -# Copyright 2018 Google LLC +# Copyright YEAR Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/test/boilerplate/boilerplate.go.txt b/test/boilerplate/boilerplate.go.txt index 557e16f0..1af96609 100644 --- a/test/boilerplate/boilerplate.go.txt +++ b/test/boilerplate/boilerplate.go.txt @@ -1,5 +1,5 @@ /* -Copyright 2018 Google LLC +Copyright YEAR Google LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/test/boilerplate/boilerplate.py.txt b/test/boilerplate/boilerplate.py.txt index b0c7da3d..1b991897 100644 --- a/test/boilerplate/boilerplate.py.txt +++ b/test/boilerplate/boilerplate.py.txt @@ -1,4 +1,4 @@ -# Copyright 2018 Google LLC +# Copyright YEAR Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/test/integration/simple_example/controls/gcp.rb b/test/boilerplate/boilerplate.rb.txt similarity index 66% rename from test/integration/simple_example/controls/gcp.rb rename to test/boilerplate/boilerplate.rb.txt index 95f2b763..1b991897 100644 --- a/test/integration/simple_example/controls/gcp.rb +++ b/test/boilerplate/boilerplate.rb.txt @@ -1,24 +1,13 @@ -# Copyright 2018 Google LLC +# Copyright YEAR 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 +# https://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. - -control "gcp" do - title "GCP Resources" - - attribute("names").each do |name| - describe google_storage_bucket(name: name) do - it { should exist } - end - end - -end diff --git a/test/boilerplate/boilerplate.sh.txt b/test/boilerplate/boilerplate.sh.txt index 2e94f3e5..9f9c9af5 100644 --- a/test/boilerplate/boilerplate.sh.txt +++ b/test/boilerplate/boilerplate.sh.txt @@ -1,4 +1,4 @@ -# Copyright 2018 Google LLC +# Copyright YEAR Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/test/boilerplate/boilerplate.tf.txt b/test/boilerplate/boilerplate.tf.txt index cfccff84..b8eae40e 100644 --- a/test/boilerplate/boilerplate.tf.txt +++ b/test/boilerplate/boilerplate.tf.txt @@ -1,5 +1,5 @@ /** - * Copyright 2018 Google LLC + * Copyright YEAR Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/test/boilerplate/boilerplate.xml.txt b/test/boilerplate/boilerplate.xml.txt index 3d98cdc6..00a2856a 100644 --- a/test/boilerplate/boilerplate.xml.txt +++ b/test/boilerplate/boilerplate.xml.txt @@ -1,5 +1,5 @@