From 221f9d7716a6a7c51e1c5a1600910830a5330f44 Mon Sep 17 00:00:00 2001 From: Ivan Kornienko Date: Wed, 14 Aug 2019 16:00:25 +0300 Subject: [PATCH] Linters fail on master #32 - Removed outdated doc_generator - Added missing helper scripts - Removed outdated docker linter - Fixed flake8 errors reported in #32 - Fixed broken simlinks(fixes terraform fmt #32) - Updated shared tfvars - Updated README files - Fixed trailing white-space from master Migrate modules to 0.12 and make the rest of the code base 0.12-compatible #35 - Migrated modules to 0.12 syntax - Added variable types constraints - Updated README - Removed outdated check_docker make target - Added a temporary workgaround for #28 (skip not migrated files in `find_files`) Updating image inside the example doesn't cause container to restart #29 - Updated examples/simple_instance/main.tf by introducing local.instance_name and adding substring of contianer image hash into instance_name - Updated examples/simple_instance/outputs.tf by reflecting the change above - Updated examples/instance_with_attached_disk/main.tf by introducing local.instance_name and adding substring of contianer image hash into instance_name - Updated examples/instance_with_attached_disk/outputs.tf by reflecting the change above --- .gitignore | 4 +- Makefile | 11 +- README.md | 287 +++++++- .../instance_with_attached_disk/README.md | 38 +- examples/instance_with_attached_disk/main.tf | 10 +- .../instance_with_attached_disk/outputs.tf | 2 +- examples/managed_instance_group/README.md | 38 +- examples/simple_instance/README.md | 22 +- examples/simple_instance/main.tf | 6 +- examples/simple_instance/outputs.tf | 2 +- helpers/combine_docfiles.py | 55 -- helpers/map_to_yaml.rb | 0 helpers/terraform_docs | 694 ++++++++++++++++++ helpers/terraform_validate | 23 + modules/cos-coredns/README.md | 31 +- modules/cos-coredns/main.tf | 20 +- modules/cos-coredns/variables.tf | 22 +- modules/cos-generic/README.md | 31 +- modules/cos-generic/main.tf | 20 +- modules/cos-generic/variables.tf | 21 +- modules/cos-mysql/README.md | 40 +- modules/cos-mysql/main.tf | 22 +- modules/cos-mysql/variables.tf | 32 +- test/fixtures/shared/terraform.tfvars | 3 + test/fixtures/shared/terraform.tfvars.sample | 3 - test/make.sh | 13 +- test/verify_boilerplate.py | 18 +- variables.tf | 8 +- 28 files changed, 1210 insertions(+), 266 deletions(-) delete mode 100644 helpers/combine_docfiles.py mode change 100644 => 100755 helpers/map_to_yaml.rb create mode 100755 helpers/terraform_docs create mode 100755 helpers/terraform_validate create mode 100644 test/fixtures/shared/terraform.tfvars delete mode 100644 test/fixtures/shared/terraform.tfvars.sample diff --git a/.gitignore b/.gitignore index 4dbbeae..fefe6b8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ test/fixtures/**/.terraform test/fixtures/**/terraform.tfstate.d test/fixtures/**/ssh/key *.pyc -test/fixtures/shared/terraform.tfvars .idea .vscode +.terraform/ +modules/*/.terraform/ + diff --git a/Makefile b/Makefile index da49710..1e365e4 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ 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 -all: check_shell check_python check_golang check_terraform check_docker check_base_files test_check_headers check_headers check_trailing_whitespace generate_docs +all: check_shell check_python check_golang check_terraform check_base_files test_check_headers check_headers check_trailing_whitespace generate_docs # 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 @@ -43,10 +43,6 @@ check_golang: check_terraform: @source test/make.sh && check_terraform -.PHONY: check_docker -check_docker: - @source test/make.sh && docker - .PHONY: check_base_files check_base_files: @source test/make.sh && basefiles @@ -65,9 +61,8 @@ test_check_headers: @python test/test_verify_boilerplate.py .PHONY: check_headers -check_headers: - @echo "Checking file headers" - @python test/verify_boilerplate.py +check_headers: ## Check that source files have appropriate boilerplate + @source test/make.sh && check_headers # Integration tests .PHONY: test_integration diff --git a/README.md b/README.md index c1b0f6d..f635a06 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ module "gce-container" { value = "Hello World!" } ], - + # Declare volumes to be mounted. # This is similar to how docker volumes are declared. volumeMounts = [ @@ -69,31 +69,29 @@ Then perform the following commands on the root folder: - `terraform plan` to see the infrastructure plan - `terraform apply` to apply the infrastructure build - `terraform destroy` to destroy the built infrastructure -[^]: (autogen_docs_start) - - + ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| container | A description of the container to deploy | map | `` | no | -| restart_policy | The restart policy for a Docker container. Defaults to `OnFailure` | string | `OnFailure` | no | -| volumes | A set of Docker Volumes to configure | list | `` | no | +| container | A description of the container to deploy | any | `` | no | +| restart\_policy | The restart policy for a Docker container. Defaults to `OnFailure` | string | `"OnFailure"` | no | +| volumes | A set of Docker Volumes to configure | any | `` | no | ## Outputs | Name | Description | |------|-------------| | container | The container definition provided | -| metadata_key | The key to assign `metadata_value` to, so container information is attached to the instance | -| metadata_value | The generated container configuration | -| restart_policy | The restart policy provided | -| source_image | The COS image to use for the GCE instance | -| vm_container_label | The COS version to deploy to the instance. To be used as the value for the `vm_container_label_key` label key | -| vm_container_label_key | The label key for the COS version deployed to the instance | +| metadata\_key | The key to assign `metadata_value` to, so container information is attached to the instance | +| metadata\_value | The generated container configuration | +| restart\_policy | The restart policy provided | +| source\_image | The COS image to use for the GCE instance | +| vm\_container\_label | The COS version to deploy to the instance. To be used as the value for the `vm_container_label_key` label key | +| vm\_container\_label\_key | The label key for the COS version deployed to the instance | | volumes | The volume definition provided | -[^]: (autogen_docs_end) + ## Requirements ### Terraform plugins @@ -126,7 +124,6 @@ Be sure you have the correct Terraform version (0.10.x), you can choose the bina The project has the following folders and files: - /: root folder -- /build: Dockerfiles and other build manifests - /examples: Examples for using this module - /helpers: Scripts that the module invokes - /test: Folders with files for testing the module (see Testing section of this file) @@ -167,7 +164,7 @@ The tests will do the following: - Perform `kitchen destroy` command - Performs a `terraform destroy -force` -Before running integration tests, you need to configure `terraform.tfvars` for your particular environment by running `cp test/fixtures/shared/terraform.tfvars.sample test/fixtures/shared/terraform.tfvars` and editing `test/fixtures/shared/terraform.tfvars` to reflect your testing environment. +Before running integration tests, you need to configure `terraform.tfvars` for your particular environment editing `test/fixtures/shared/terraform.tfvars` to reflect your testing environment. You can then use the following command to run the integration test in the root folder @@ -175,7 +172,7 @@ You can then use the following command to run the integration test in the root f ### Linting The makefile in this project will lint or sometimes just format any shell, -Python, golang, Terraform, or Dockerfiles. The linters will only be run if +Python, golang, Terraform. The linters will only be run if the makefile finds files with the appropriate file extension. All of the linter checks are in the default make target, so you just have to @@ -185,32 +182,272 @@ run make -s ``` -The -s is for 'silent'. Successful output looks like this +The -s is for 'silent'. Successful output looks like below and exists with 0 exit code. ``` +[user@host:~/workspace/google/terraform-google-container-vm]$ make -s Running shellcheck Running flake8 Running go fmt and go vet -Running terraform validate Running terraform fmt -Running hadolint on Dockerfiles -Checking for required files +terraform fmt -diff -check=true -write=false . +terraform fmt -diff -check=true -write=false ./examples/instance_with_attached_disk +terraform fmt -diff -check=true -write=false ./examples/simple_instance +terraform fmt -diff -check=true -write=false ./modules/cos-coredns +terraform fmt -diff -check=true -write=false ./modules/cos-generic +terraform fmt -diff -check=true -write=false ./modules/cos-mysql +terraform fmt -diff -check=true -write=false ./test/fixtures/instance_with_attached_disk +terraform fmt -diff -check=true -write=false ./test/fixtures/shared +terraform fmt -diff -check=true -write=false ./test/fixtures/simple_instance +Running terraform validate +helpers/terraform_validate . + +Initializing provider plugins... + +The following providers do not have any version constraints in configuration, +so the latest version was installed. + +To prevent automatic upgrades to new major versions that may contain breaking +changes, it is recommended to add version = "..." constraints to the +corresponding provider blocks in configuration, with the constraint strings +suggested below. + +* provider.external: version = "~> 1.2" +* provider.google: version = "~> 2.12" + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. +Success! The configuration is valid. + +helpers/terraform_validate ./examples/instance_with_attached_disk +Initializing modules... + +Initializing provider plugins... + +The following providers do not have any version constraints in configuration, +so the latest version was installed. + +To prevent automatic upgrades to new major versions that may contain breaking +changes, it is recommended to add version = "..." constraints to the +corresponding provider blocks in configuration, with the constraint strings +suggested below. + +* provider.external: version = "~> 1.2" +* provider.google: version = "~> 2.12" + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. +Success! The configuration is valid. + +helpers/terraform_validate ./examples/simple_instance +Initializing modules... + +Initializing provider plugins... + +The following providers do not have any version constraints in configuration, +so the latest version was installed. + +To prevent automatic upgrades to new major versions that may contain breaking +changes, it is recommended to add version = "..." constraints to the +corresponding provider blocks in configuration, with the constraint strings +suggested below. + +* provider.external: version = "~> 1.2" +* provider.google: version = "~> 2.12" +* provider.random: version = "~> 2.2" + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. +Success! The configuration is valid. + +helpers/terraform_validate ./modules/cos-coredns + +Initializing provider plugins... + +The following providers do not have any version constraints in configuration, +so the latest version was installed. + +To prevent automatic upgrades to new major versions that may contain breaking +changes, it is recommended to add version = "..." constraints to the +corresponding provider blocks in configuration, with the constraint strings +suggested below. + +* provider.google: version = "~> 2.12" +* provider.template: version = "~> 2.1" + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. +Success! The configuration is valid. + +helpers/terraform_validate ./modules/cos-generic + +Initializing provider plugins... + +The following providers do not have any version constraints in configuration, +so the latest version was installed. + +To prevent automatic upgrades to new major versions that may contain breaking +changes, it is recommended to add version = "..." constraints to the +corresponding provider blocks in configuration, with the constraint strings +suggested below. + +* provider.google: version = "~> 2.12" +* provider.template: version = "~> 2.1" + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. +Success! The configuration is valid. + +helpers/terraform_validate ./modules/cos-mysql + +Initializing provider plugins... + +The following providers do not have any version constraints in configuration, +so the latest version was installed. + +To prevent automatic upgrades to new major versions that may contain breaking +changes, it is recommended to add version = "..." constraints to the +corresponding provider blocks in configuration, with the constraint strings +suggested below. + +* provider.google: version = "~> 2.12" +* provider.random: version = "~> 2.2" +* provider.template: version = "~> 2.1" + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. +Success! The configuration is valid. + +helpers/terraform_validate ./test/fixtures/instance_with_attached_disk +Initializing modules... + +Initializing provider plugins... + +The following providers do not have any version constraints in configuration, +so the latest version was installed. + +To prevent automatic upgrades to new major versions that may contain breaking +changes, it is recommended to add version = "..." constraints to the +corresponding provider blocks in configuration, with the constraint strings +suggested below. + +* provider.external: version = "~> 1.2" +* provider.google: version = "~> 2.12" +* provider.local: version = "~> 1.3" +* provider.random: version = "~> 2.2" +* provider.tls: version = "~> 2.0" + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. +Success! The configuration is valid. + +helpers/terraform_validate ./test/fixtures/simple_instance +Initializing modules... + +Initializing provider plugins... + +The following providers do not have any version constraints in configuration, +so the latest version was installed. + +To prevent automatic upgrades to new major versions that may contain breaking +changes, it is recommended to add version = "..." constraints to the +corresponding provider blocks in configuration, with the constraint strings +suggested below. + +* provider.external: version = "~> 1.2" +* provider.google: version = "~> 2.12" +* provider.random: version = "~> 2.2" + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. +Success! The configuration is valid. + +Checking for required files LICENSE README.md Testing the validity of the header check .. ---------------------------------------------------------------------- -Ran 2 tests in 0.024s +Ran 2 tests in 0.014s OK Checking file headers -The following lines have trailing whitespace +Checking for trailing whitespace Generating markdown docs with terraform-docs +Skipping ./test/fixtures/instance_with_attached_disk because README.md does not exist. +Skipping ./test/fixtures/shared because README.md does not exist. +Skipping ./test/fixtures/simple_instance because README.md does not exist. +[user@host:~/workspace/google/terraform-google-container-vm]$ echo $? +0 ``` The linters are as follows: * Shell - shellcheck. Can be found in homebrew * Python - flake8. Can be installed with 'pip install flake8' * Golang - gofmt. gofmt comes with the standard golang installation. golang is a compiled language so there is no standard linter. -* Terraform - terraform has a built-in linter in the 'terraform fmt' command. -* Dockerfiles - hadolint. Can be found in homebrew +* Terraform (built-in): + - `terraform fmt` + - `terraform validate`. +* File headers +* Trailing whitespaces + +## Known limitations +Managed instance group [example](examples/managed_instance_group/main.tf) is not migrated to Terraform 0.12 +This is tracked as issue [`#28`](https://github.com/terraform-google-modules/terraform-google-container-vm/issues/28) +Linters and integrations tests skip this example and associated tests for now. [0.3.0]: https://registry.terraform.io/modules/terraform-google-modules/container-vm/google/0.3.0 diff --git a/examples/instance_with_attached_disk/README.md b/examples/instance_with_attached_disk/README.md index bee49e3..94df4cb 100644 --- a/examples/instance_with_attached_disk/README.md +++ b/examples/instance_with_attached_disk/README.md @@ -2,40 +2,38 @@ This example illustrates how to deploy and expose a container to a Google Compute Engine instance in GCP, with an attached disk. Also includes SSH configuration, so a user can be provisioned on the fly for future logins. -[^]: (autogen_docs_start) - - + ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| additional_metadata | Additional metadata to attach to the instance | map | `` | no | -| image | The Docker image to deploy to GCE instances | string | - | yes | -| image_port | The port the image exposes for HTTP requests | string | - | yes | -| instance_name | The desired name to assign to the deployed instance | string | `disk-instance-vm-test` | no | -| machine_type | The GCP machine type to deploy | string | - | yes | -| project_id | The project ID to deploy resource into | string | - | yes | -| region | The GCP region to deploy instances into | string | - | yes | -| restart_policy | The desired Docker restart policy for the deployed image | string | - | yes | -| subnetwork | The name of the subnetwork to deploy instances into | string | - | yes | -| subnetwork_project | The project ID where the desired subnetwork is provisioned | string | - | yes | -| zone | The GCP zone to deploy instances into | string | - | yes | +| additional\_metadata | Additional metadata to attach to the instance | map | `` | no | +| image | The Docker image to deploy to GCE instances | string | n/a | yes | +| image\_port | The port the image exposes for HTTP requests | string | n/a | yes | +| instance\_name | The desired name to assign to the deployed instance | string | `"disk-instance-vm-test"` | no | +| machine\_type | The GCP machine type to deploy | string | n/a | yes | +| project\_id | The project ID to deploy resource into | string | n/a | yes | +| region | The GCP region to deploy instances into | string | n/a | yes | +| restart\_policy | The desired Docker restart policy for the deployed image | string | n/a | yes | +| subnetwork | The name of the subnetwork to deploy instances into | string | n/a | yes | +| subnetwork\_project | The project ID where the desired subnetwork is provisioned | string | n/a | yes | +| zone | The GCP zone to deploy instances into | string | n/a | yes | ## Outputs | Name | Description | |------|-------------| | container | The container metadata provided to the module | -| http_address | The IP address on which the HTTP service is exposed | -| http_port | The port on which the HTTP service is exposed | -| instance_name | The deployed instance name | +| http\_address | The IP address on which the HTTP service is exposed | +| http\_port | The port on which the HTTP service is exposed | +| instance\_name | The deployed instance name | | ipv4 | The public IP address of the deployed instance | -| project_id | The project ID resources were deployed into | -| vm_container_label | The instance label containing container configuration | +| project\_id | The project ID resources were deployed into | +| vm\_container\_label | The instance label containing container configuration | | volumes | The volume metadata provided to the module | | zone | The zone the GCE instance was deployed into | -[^]: (autogen_docs_end) + ## Running diff --git a/examples/instance_with_attached_disk/main.tf b/examples/instance_with_attached_disk/main.tf index a38dd34..00fb0d0 100644 --- a/examples/instance_with_attached_disk/main.tf +++ b/examples/instance_with_attached_disk/main.tf @@ -18,6 +18,10 @@ provider "google" { region = var.region } +locals { + instance_name = format("%s-%s", var.instance_name, substr(md5(module.gce-container.container.image), 0, 8)) +} + module "gce-container" { source = "../../" @@ -71,7 +75,7 @@ module "gce-container" { resource "google_compute_disk" "pd" { project = var.project_id - name = "${var.instance_name}-data-disk" + name = "${local.instance_name}-data-disk" type = "pd-ssd" zone = var.zone size = 10 @@ -79,7 +83,7 @@ resource "google_compute_disk" "pd" { resource "google_compute_instance" "vm" { project = var.project_id - name = var.instance_name + name = local.instance_name machine_type = var.machine_type zone = var.zone @@ -117,7 +121,7 @@ resource "google_compute_instance" "vm" { } resource "google_compute_firewall" "http-access" { - name = "${var.instance_name}-http" + name = "${local.instance_name}-http" project = var.project_id network = var.subnetwork diff --git a/examples/instance_with_attached_disk/outputs.tf b/examples/instance_with_attached_disk/outputs.tf index e9aeff9..86782ab 100644 --- a/examples/instance_with_attached_disk/outputs.tf +++ b/examples/instance_with_attached_disk/outputs.tf @@ -51,7 +51,7 @@ output "http_port" { output "instance_name" { description = "The deployed instance name" - value = var.instance_name + value = local.instance_name } output "ipv4" { diff --git a/examples/managed_instance_group/README.md b/examples/managed_instance_group/README.md index 07c65ec..6b44c16 100644 --- a/examples/managed_instance_group/README.md +++ b/examples/managed_instance_group/README.md @@ -6,39 +6,37 @@ This example illustrates how to deploy a container to a [managed instance group] This example requires that some python libraries be installed, as outlined in `requirements.txt`. Depending on your environment, you should be able to run `pip install -r requirements.txt` to satisfy these requirements. -[^]: (autogen_docs_start) - - + ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| additional_metadata | Additional metadata to attach to the instance | map | `` | no | -| image | The Docker image to deploy to GCE instances | string | - | yes | -| image_port | The port the image exposes for HTTP requests | string | - | yes | -| machine_type | The GCP machine type to deploy | string | - | yes | -| mig_instance_count | The number of instances to place in the managed instance group | string | `2` | no | -| mig_name | The desired name to assign to the deployed managed instance group | string | `mig-test` | no | -| project_id | The project ID to deploy resource into | string | - | yes | -| region | The GCP region to deploy instances into | string | - | yes | -| restart_policy | The desired Docker restart policy for the deployed image | string | - | yes | -| subnetwork | The name of the subnetwork to deploy instances into | string | - | yes | -| subnetwork_project | The project ID where the desired subnetwork is provisioned | string | - | yes | -| zone | The GCP zone to deploy instances into | string | - | yes | +| additional\_metadata | Additional metadata to attach to the instance | map | `` | no | +| image | The Docker image to deploy to GCE instances | string | n/a | yes | +| image\_port | The port the image exposes for HTTP requests | string | n/a | yes | +| machine\_type | The GCP machine type to deploy | string | n/a | yes | +| mig\_instance\_count | The number of instances to place in the managed instance group | string | `"2"` | no | +| mig\_name | The desired name to assign to the deployed managed instance group | string | `"mig-test"` | no | +| project\_id | The project ID to deploy resource into | string | n/a | yes | +| region | The GCP region to deploy instances into | string | n/a | yes | +| restart\_policy | The desired Docker restart policy for the deployed image | string | n/a | yes | +| subnetwork | The name of the subnetwork to deploy instances into | string | n/a | yes | +| subnetwork\_project | The project ID where the desired subnetwork is provisioned | string | n/a | yes | +| zone | The GCP zone to deploy instances into | string | n/a | yes | ## Outputs | Name | Description | |------|-------------| | container | The container metadata provided to the module | -| http_address | The IP address on which the HTTP service is exposed | -| http_port | The port on which the HTTP service is exposed | -| project_id | The project ID resources were deployed into | -| vm_container_label | The instance label containing container configuration | +| http\_address | The IP address on which the HTTP service is exposed | +| http\_port | The port on which the HTTP service is exposed | +| project\_id | The project ID resources were deployed into | +| vm\_container\_label | The instance label containing container configuration | | volumes | The volume metadata provided to the module | | zone | The zone the GCE instance was deployed into | -[^]: (autogen_docs_end) + ## Running diff --git a/examples/simple_instance/README.md b/examples/simple_instance/README.md index 061e11f..8b3f394 100644 --- a/examples/simple_instance/README.md +++ b/examples/simple_instance/README.md @@ -2,32 +2,30 @@ This example illustrates how to deploy a container to a Google Compute Engine instance in GCP. -[^]: (autogen_docs_start) - - + ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| instance_name | The desired name to assign to the deployed instance | string | `hello-world-container-vm` | no | -| project_id | The project ID to deploy resources into | string | - | yes | -| region | The GCP region to deploy instances into | string | - | yes | -| subnetwork | The name of the subnetwork to deploy instances into | string | - | yes | -| subnetwork_project | The project ID where the desired subnetwork is provisioned | string | - | yes | +| instance\_name | The desired name to assign to the deployed instance | string | `"hello-world-container-vm"` | no | +| project\_id | The project ID to deploy resources into | string | n/a | yes | +| region | The GCP region to deploy instances into | string | n/a | yes | +| subnetwork | The name of the subnetwork to deploy instances into | string | n/a | yes | +| subnetwork\_project | The project ID where the desired subnetwork is provisioned | string | n/a | yes | ## Outputs | Name | Description | |------|-------------| | container | The container metadata provided to the module | -| instance_name | The deployed instance name | +| instance\_name | The deployed instance name | | ipv4 | The public IP address of the deployed instance | -| project_id | The project ID resources were deployed into | -| vm_container_label | The instance label containing container configuration | +| project\_id | The project ID resources were deployed into | +| vm\_container\_label | The instance label containing container configuration | | volumes | The volume metadata provided to the module | | zone | The zone the GCE instance was deployed into | -[^]: (autogen_docs_end) + ## Running diff --git a/examples/simple_instance/main.tf b/examples/simple_instance/main.tf index c987df1..13090e5 100644 --- a/examples/simple_instance/main.tf +++ b/examples/simple_instance/main.tf @@ -18,6 +18,10 @@ provider "google" { region = var.region } +locals { + instance_name = format("%s-%s", var.instance_name, substr(md5(module.gce-container.container.image), 0, 8)) +} + data "google_compute_zones" "available" { project = var.project_id region = var.region @@ -65,7 +69,7 @@ module "gce-container" { resource "google_compute_instance" "vm" { project = var.project_id - name = var.instance_name + name = local.instance_name machine_type = "n1-standard-1" zone = random_shuffle.zone.result[0] diff --git a/examples/simple_instance/outputs.tf b/examples/simple_instance/outputs.tf index b2b68c1..7ae72b4 100644 --- a/examples/simple_instance/outputs.tf +++ b/examples/simple_instance/outputs.tf @@ -41,7 +41,7 @@ output "volumes" { output "instance_name" { description = "The deployed instance name" - value = var.instance_name + value = local.instance_name } output "ipv4" { diff --git a/helpers/combine_docfiles.py b/helpers/combine_docfiles.py deleted file mode 100644 index 16516cb..0000000 --- a/helpers/combine_docfiles.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2018 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 -# -# 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. - -''' Combine file from: - * script argument 1 - with content of file from: - * script argument 2 - using the beginning of line separators - hardcoded using regexes in this file: - - We exclude any text using the separate - regex specified here -''' - -import os -import re -import sys - -insert_separator_regex = '(.*?\[\^\]\:\ \(autogen_docs_start\))(.*?)(\n\[\^\]\:\ \(autogen_docs_end\).*?$)' # noqa: E501 -exclude_separator_regex = '(.*?)Copyright 20\d\d Google LLC.*?limitations under the License.(.*?)$' # noqa: E501 - -if len(sys.argv) != 3: - sys.exit(1) - -if not os.path.isfile(sys.argv[1]): - sys.exit(0) - -input = open(sys.argv[1], "r").read() -replace_content = open(sys.argv[2], "r").read() - -# Exclude the specified content from the replacement content -groups = re.match( - exclude_separator_regex, - replace_content, - re.DOTALL -).groups(0) -replace_content = groups[0] + groups[1] - -# Find where to put the replacement content, overwrite the input file -groups = re.match(insert_separator_regex, input, re.DOTALL).groups(0) -output = groups[0] + replace_content + groups[2] -open(sys.argv[1], "w").write(output) diff --git a/helpers/map_to_yaml.rb b/helpers/map_to_yaml.rb old mode 100644 new mode 100755 diff --git a/helpers/terraform_docs b/helpers/terraform_docs new file mode 100755 index 0000000..0935b69 --- /dev/null +++ b/helpers/terraform_docs @@ -0,0 +1,694 @@ +#!/usr/bin/env bash + +set -e + +main() { + declare argv + argv=$(getopt -o a: --long args: -- "$@") || return + eval "set -- $argv" + + declare args + declare files + + for argv; do + case $argv in + (-a|--args) + shift + args="$1" + shift + ;; + (--) + shift + files="$@" + break + ;; + esac + done + + local hack_terraform_docs=$(terraform version | head -1 | grep -c 0.12) + + if [[ "$hack_terraform_docs" == "1" ]]; then + which awk 2>&1 >/dev/null || ( echo "awk is required for terraform-docs hack to work with Terraform 0.12"; exit 1) + + tmp_file_awk=$(mktemp "${TMPDIR:-/tmp}/terraform-docs-XXXXXXXXXX") + terraform_docs_awk "$tmp_file_awk" + terraform_docs "$tmp_file_awk" "$args" "$files" + rm -f "$tmp_file_awk" + else + terraform_docs "0" "$args" "$files" + fi + +} + +terraform_docs() { + readonly terraform_docs_awk_file="$1" + readonly args="$2" + readonly files="$3" + + declare -a paths + declare -a tfvars_files + + index=0 + + for file_with_path in $files; do + file_with_path="${file_with_path// /__REPLACED__SPACE__}" + + paths[index]=$(dirname "$file_with_path") + + if [[ "$file_with_path" == *".tfvars" ]]; then + tfvars_files+=("$file_with_path") + fi + + ((index+=1)) + done + + readonly tmp_file=$(mktemp) + readonly text_file="README.md" + + for path_uniq in $(echo "${paths[*]}" | tr ' ' '\n' | sort -u); do + path_uniq="${path_uniq//__REPLACED__SPACE__/ }" + + pushd "$path_uniq" > /dev/null + + if [[ ! -f "$text_file" ]]; then + popd > /dev/null + continue + fi + + if [[ "$terraform_docs_awk_file" == "0" ]]; then + terraform-docs $args md ./ > "$tmp_file" + else + # Can't append extension for mktemp, so renaming instead + tmp_file_docs=$(mktemp "${TMPDIR:-/tmp}/terraform-docs-XXXXXXXXXX") + mv "$tmp_file_docs" "$tmp_file_docs.tf" + tmp_file_docs_tf="$tmp_file_docs.tf" + + awk -f "$terraform_docs_awk_file" ./*.tf > "$tmp_file_docs_tf" + terraform-docs $args md "$tmp_file_docs_tf" > "$tmp_file" + rm -f "$tmp_file_docs_tf" + fi + + # Replace content between markers with the placeholder - https://stackoverflow.com/questions/1212799/how-do-i-extract-lines-between-two-line-delimiters-in-perl#1212834 + perl -i -ne 'if (/BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK/../END OF PRE-COMMIT-TERRAFORM DOCS HOOK/) { print $_ if /BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK/; print "I_WANT_TO_BE_REPLACED\n$_" if /END OF PRE-COMMIT-TERRAFORM DOCS HOOK/;} else { print $_ }' "$text_file" + + # Replace placeholder with the content of the file + perl -i -e 'open(F, "'"$tmp_file"'"); $f = join "", ; while(<>){if (/I_WANT_TO_BE_REPLACED/) {print $f} else {print $_};}' "$text_file" + + rm -f "$tmp_file" + + popd > /dev/null + done +} + +terraform_docs_awk() { + readonly output_file=$1 + + cat <<"EOF" > $output_file +# This script converts Terraform 0.12 variables/outputs to something suitable for `terraform-docs` +# As of terraform-docs v0.6.0, HCL2 is not supported. This script is a *dirty hack* to get around it. +# https://github.com/segmentio/terraform-docs/ +# https://github.com/segmentio/terraform-docs/issues/62 + +# Script was originally found here: https://github.com/cloudposse/build-harness/blob/master/bin/terraform-docs.awk + +{ + if ( $0 ~ /\{/ ) { + braceCnt++ + } + + if ( $0 ~ /\}/ ) { + braceCnt-- + } + + # [START] variable or output block started + if ($0 ~ /^[[:space:]]*(variable|output)[[:space:]][[:space:]]*"(.*?)"/) { + # Normalize the braceCnt (should be 1 now) + braceCnt = 1 + # [CLOSE] "default" block + if (blockDefCnt > 0) { + blockDefCnt = 0 + } + blockCnt++ + print $0 + } + + # [START] multiline default statement started + if (blockCnt > 0) { + if ($0 ~ /^[[:space:]][[:space:]]*(default)[[:space:]][[:space:]]*=/) { + if ($3 ~ "null") { + print " default = \"null\"" + } else { + print $0 + blockDefCnt++ + blockDefStart=1 + } + } + } + + # [PRINT] single line "description" + if (blockCnt > 0) { + if (blockDefCnt == 0) { + if ($0 ~ /^[[:space:]][[:space:]]*description[[:space:]][[:space:]]*=/) { + # [CLOSE] "default" block + if (blockDefCnt > 0) { + blockDefCnt = 0 + } + print $0 + } + } + } + + # [PRINT] single line "type" + if (blockCnt > 0) { + if ($0 ~ /^[[:space:]][[:space:]]*type[[:space:]][[:space:]]*=/ ) { + # [CLOSE] "default" block + if (blockDefCnt > 0) { + blockDefCnt = 0 + } + type=$3 + if (type ~ "object") { + print " type = \"object\"" + } else { + # legacy quoted types: "string", "list", and "map" + if ($3 ~ /^[[:space:]]*"(.*?)"[[:space:]]*$/) { + print " type = " $3 + } else { + print " type = \"" $3 "\"" + } + } + } + } + + # [CLOSE] variable/output block + if (blockCnt > 0) { + if (braceCnt == 0 && blockCnt > 0) { + blockCnt-- + print $0 + } + } + + # [PRINT] Multiline "default" statement + if (blockCnt > 0 && blockDefCnt > 0) { + if (blockDefStart == 1) { + blockDefStart = 0 + } else { + print $0 + } + } +} +EOF + +} + +getopt() { + # pure-getopt, a drop-in replacement for GNU getopt in pure Bash. + # version 1.4.3 + # + # Copyright 2012-2018 Aron Griffis + # + # Permission is hereby granted, free of charge, to any person obtaining + # a copy of this software and associated documentation files (the + # "Software"), to deal in the Software without restriction, including + # without limitation the rights to use, copy, modify, merge, publish, + # distribute, sublicense, and/or sell copies of the Software, and to + # permit persons to whom the Software is furnished to do so, subject to + # the following conditions: + # + # The above copyright notice and this permission notice shall be included + # in all copies or substantial portions of the Software. + # + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + _getopt_main() { + # Returns one of the following statuses: + # 0 success + # 1 error parsing parameters + # 2 error in getopt invocation + # 3 internal error + # 4 reserved for -T + # + # For statuses 0 and 1, generates normalized and shell-quoted + # "options -- parameters" on stdout. + + declare parsed status + declare short long name flags + declare have_short=false + + # Synopsis from getopt man-page: + # + # getopt optstring parameters + # getopt [options] [--] optstring parameters + # getopt [options] -o|--options optstring [options] [--] parameters + # + # The first form can be normalized to the third form which + # _getopt_parse() understands. The second form can be recognized after + # first parse when $short hasn't been set. + + if [[ -n ${GETOPT_COMPATIBLE+isset} || $1 == [^-]* ]]; then + # Enable compatibility mode + flags=c$flags + # Normalize first to third synopsis form + set -- -o "$1" -- "${@:2}" + fi + + # First parse always uses flags=p since getopt always parses its own + # arguments effectively in this mode. + parsed=$(_getopt_parse getopt ahl:n:o:qQs:TuV \ + alternative,help,longoptions:,name:,options:,quiet,quiet-output,shell:,test,version \ + p "$@") + status=$? + if [[ $status != 0 ]]; then + if [[ $status == 1 ]]; then + echo "Try \`getopt --help' for more information." >&2 + # Since this is the first parse, convert status 1 to 2 + status=2 + fi + return $status + fi + eval "set -- $parsed" + + while [[ $# -gt 0 ]]; do + case $1 in + (-a|--alternative) + flags=a$flags ;; + + (-h|--help) + _getopt_help + return 2 # as does GNU getopt + ;; + + (-l|--longoptions) + long="$long${long:+,}$2" + shift ;; + + (-n|--name) + name=$2 + shift ;; + + (-o|--options) + short=$2 + have_short=true + shift ;; + + (-q|--quiet) + flags=q$flags ;; + + (-Q|--quiet-output) + flags=Q$flags ;; + + (-s|--shell) + case $2 in + (sh|bash) + flags=${flags//t/} ;; + (csh|tcsh) + flags=t$flags ;; + (*) + echo 'getopt: unknown shell after -s or --shell argument' >&2 + echo "Try \`getopt --help' for more information." >&2 + return 2 ;; + esac + shift ;; + + (-u|--unquoted) + flags=u$flags ;; + + (-T|--test) + return 4 ;; + + (-V|--version) + echo "pure-getopt 1.4.3" + return 0 ;; + + (--) + shift + break ;; + esac + + shift + done + + if ! $have_short; then + # $short was declared but never set, not even to an empty string. + # This implies the second form in the synopsis. + if [[ $# == 0 ]]; then + echo 'getopt: missing optstring argument' >&2 + echo "Try \`getopt --help' for more information." >&2 + return 2 + fi + short=$1 + have_short=true + shift + fi + + if [[ $short == -* ]]; then + # Leading dash means generate output in place rather than reordering, + # unless we're already in compatibility mode. + [[ $flags == *c* ]] || flags=i$flags + short=${short#?} + elif [[ $short == +* ]]; then + # Leading plus means POSIXLY_CORRECT, unless we're already in + # compatibility mode. + [[ $flags == *c* ]] || flags=p$flags + short=${short#?} + fi + + # This should fire if POSIXLY_CORRECT is in the environment, even if + # it's an empty string. That's the difference between :+ and + + flags=${POSIXLY_CORRECT+p}$flags + + _getopt_parse "${name:-getopt}" "$short" "$long" "$flags" "$@" + } + + _getopt_parse() { + # Inner getopt parser, used for both first parse and second parse. + # Returns 0 for success, 1 for error parsing, 3 for internal error. + # In the case of status 1, still generates stdout with whatever could + # be parsed. + # + # $flags is a string of characters with the following meanings: + # a - alternative parsing mode + # c - GETOPT_COMPATIBLE + # i - generate output in place rather than reordering + # p - POSIXLY_CORRECT + # q - disable error reporting + # Q - disable normal output + # t - quote for csh/tcsh + # u - unquoted output + + declare name="$1" short="$2" long="$3" flags="$4" + shift 4 + + # Split $long on commas, prepend double-dashes, strip colons; + # for use with _getopt_resolve_abbrev + declare -a longarr + _getopt_split longarr "$long" + longarr=( "${longarr[@]/#/--}" ) + longarr=( "${longarr[@]%:}" ) + longarr=( "${longarr[@]%:}" ) + + # Parse and collect options and parameters + declare -a opts params + declare o alt_recycled=false error=0 + + while [[ $# -gt 0 ]]; do + case $1 in + (--) + params=( "${params[@]}" "${@:2}" ) + break ;; + + (--*=*) + o=${1%%=*} + if ! o=$(_getopt_resolve_abbrev "$o" "${longarr[@]}"); then + error=1 + elif [[ ,"$long", == *,"${o#--}"::,* ]]; then + opts=( "${opts[@]}" "$o" "${1#*=}" ) + elif [[ ,"$long", == *,"${o#--}":,* ]]; then + opts=( "${opts[@]}" "$o" "${1#*=}" ) + elif [[ ,"$long", == *,"${o#--}",* ]]; then + if $alt_recycled; then o=${o#-}; fi + _getopt_err "$name: option '$o' doesn't allow an argument" + error=1 + else + echo "getopt: assertion failed (1)" >&2 + return 3 + fi + alt_recycled=false + ;; + + (--?*) + o=$1 + if ! o=$(_getopt_resolve_abbrev "$o" "${longarr[@]}"); then + error=1 + elif [[ ,"$long", == *,"${o#--}",* ]]; then + opts=( "${opts[@]}" "$o" ) + elif [[ ,"$long", == *,"${o#--}::",* ]]; then + opts=( "${opts[@]}" "$o" '' ) + elif [[ ,"$long", == *,"${o#--}:",* ]]; then + if [[ $# -ge 2 ]]; then + shift + opts=( "${opts[@]}" "$o" "$1" ) + else + if $alt_recycled; then o=${o#-}; fi + _getopt_err "$name: option '$o' requires an argument" + error=1 + fi + else + echo "getopt: assertion failed (2)" >&2 + return 3 + fi + alt_recycled=false + ;; + + (-*) + if [[ $flags == *a* ]]; then + # Alternative parsing mode! + # Try to handle as a long option if any of the following apply: + # 1. There's an equals sign in the mix -x=3 or -xy=3 + # 2. There's 2+ letters and an abbreviated long match -xy + # 3. There's a single letter and an exact long match + # 4. There's a single letter and no short match + o=${1::2} # temp for testing #4 + if [[ $1 == *=* || $1 == -?? || \ + ,$long, == *,"${1#-}"[:,]* || \ + ,$short, != *,"${o#-}"[:,]* ]]; then + o=$(_getopt_resolve_abbrev "${1%%=*}" "${longarr[@]}" 2>/dev/null) + case $? in + (0) + # Unambiguous match. Let the long options parser handle + # it, with a flag to get the right error message. + set -- "-$1" "${@:2}" + alt_recycled=true + continue ;; + (1) + # Ambiguous match, generate error and continue. + _getopt_resolve_abbrev "${1%%=*}" "${longarr[@]}" >/dev/null + error=1 + shift + continue ;; + (2) + # No match, fall through to single-character check. + true ;; + (*) + echo "getopt: assertion failed (3)" >&2 + return 3 ;; + esac + fi + fi + + o=${1::2} + if [[ "$short" == *"${o#-}"::* ]]; then + if [[ ${#1} -gt 2 ]]; then + opts=( "${opts[@]}" "$o" "${1:2}" ) + else + opts=( "${opts[@]}" "$o" '' ) + fi + elif [[ "$short" == *"${o#-}":* ]]; then + if [[ ${#1} -gt 2 ]]; then + opts=( "${opts[@]}" "$o" "${1:2}" ) + elif [[ $# -ge 2 ]]; then + shift + opts=( "${opts[@]}" "$o" "$1" ) + else + _getopt_err "$name: option requires an argument -- '${o#-}'" + error=1 + fi + elif [[ "$short" == *"${o#-}"* ]]; then + opts=( "${opts[@]}" "$o" ) + if [[ ${#1} -gt 2 ]]; then + set -- "$o" "-${1:2}" "${@:2}" + fi + else + if [[ $flags == *a* ]]; then + # Alternative parsing mode! Report on the entire failed + # option. GNU includes =value but we omit it for sanity with + # very long values. + _getopt_err "$name: unrecognized option '${1%%=*}'" + else + _getopt_err "$name: invalid option -- '${o#-}'" + if [[ ${#1} -gt 2 ]]; then + set -- "$o" "-${1:2}" "${@:2}" + fi + fi + error=1 + fi ;; + + (*) + # GNU getopt in-place mode (leading dash on short options) + # overrides POSIXLY_CORRECT + if [[ $flags == *i* ]]; then + opts=( "${opts[@]}" "$1" ) + elif [[ $flags == *p* ]]; then + params=( "${params[@]}" "$@" ) + break + else + params=( "${params[@]}" "$1" ) + fi + esac + + shift + done + + if [[ $flags == *Q* ]]; then + true # generate no output + else + echo -n ' ' + if [[ $flags == *[cu]* ]]; then + printf '%s -- %s' "${opts[*]}" "${params[*]}" + else + if [[ $flags == *t* ]]; then + _getopt_quote_csh "${opts[@]}" -- "${params[@]}" + else + _getopt_quote "${opts[@]}" -- "${params[@]}" + fi + fi + echo + fi + + return $error + } + + _getopt_err() { + if [[ $flags != *q* ]]; then + printf '%s\n' "$1" >&2 + fi + } + + _getopt_resolve_abbrev() { + # Resolves an abbrevation from a list of possibilities. + # If the abbreviation is unambiguous, echoes the expansion on stdout + # and returns 0. If the abbreviation is ambiguous, prints a message on + # stderr and returns 1. (For first parse this should convert to exit + # status 2.) If there is no match at all, prints a message on stderr + # and returns 2. + declare a q="$1" + declare -a matches + shift + for a; do + if [[ $q == "$a" ]]; then + # Exact match. Squash any other partial matches. + matches=( "$a" ) + break + elif [[ $flags == *a* && $q == -[^-]* && $a == -"$q" ]]; then + # Exact alternative match. Squash any other partial matches. + matches=( "$a" ) + break + elif [[ $a == "$q"* ]]; then + # Abbreviated match. + matches=( "${matches[@]}" "$a" ) + elif [[ $flags == *a* && $q == -[^-]* && $a == -"$q"* ]]; then + # Abbreviated alternative match. + matches=( "${matches[@]}" "${a#-}" ) + fi + done + case ${#matches[@]} in + (0) + [[ $flags == *q* ]] || \ + printf "$name: unrecognized option %s\\n" >&2 \ + "$(_getopt_quote "$q")" + return 2 ;; + (1) + printf '%s' "${matches[0]}"; return 0 ;; + (*) + [[ $flags == *q* ]] || \ + printf "$name: option %s is ambiguous; possibilities: %s\\n" >&2 \ + "$(_getopt_quote "$q")" "$(_getopt_quote "${matches[@]}")" + return 1 ;; + esac + } + + _getopt_split() { + # Splits $2 at commas to build array specified by $1 + declare IFS=, + eval "$1=( \$2 )" + } + + _getopt_quote() { + # Quotes arguments with single quotes, escaping inner single quotes + declare s space q=\' + for s; do + printf "$space'%s'" "${s//$q/$q\\$q$q}" + space=' ' + done + } + + _getopt_quote_csh() { + # Quotes arguments with single quotes, escaping inner single quotes, + # bangs, backslashes and newlines + declare s i c space + for s; do + echo -n "$space'" + for ((i=0; i<${#s}; i++)); do + c=${s:i:1} + case $c in + (\\|\'|!) + echo -n "'\\$c'" ;; + ($'\n') + echo -n "\\$c" ;; + (*) + echo -n "$c" ;; + esac + done + echo -n \' + space=' ' + done + } + + _getopt_help() { + cat <<-EOT >&2 + + Usage: + getopt + getopt [options] [--] + getopt [options] -o|--options [options] [--] + + Parse command options. + + Options: + -a, --alternative allow long options starting with single - + -l, --longoptions the long options to be recognized + -n, --name the name under which errors are reported + -o, --options the short options to be recognized + -q, --quiet disable error reporting by getopt(3) + -Q, --quiet-output no normal output + -s, --shell set quoting conventions to those of + -T, --test test for getopt(1) version + -u, --unquoted do not quote the output + + -h, --help display this help and exit + -V, --version output version information and exit + + For more details see getopt(1). + EOT + } + + _getopt_version_check() { + if [[ -z $BASH_VERSION ]]; then + echo "getopt: unknown version of bash might not be compatible" >&2 + return 1 + fi + + # This is a lexical comparison that should be sufficient forever. + if [[ $BASH_VERSION < 2.05b ]]; then + echo "getopt: bash $BASH_VERSION might not be compatible" >&2 + return 1 + fi + + return 0 + } + + _getopt_version_check + _getopt_main "$@" + declare status=$? + unset -f _getopt_main _getopt_err _getopt_parse _getopt_quote \ + _getopt_quote_csh _getopt_resolve_abbrev _getopt_split _getopt_help \ + _getopt_version_check + return $status +} + +[[ $BASH_SOURCE != "$0" ]] || main "$@" diff --git a/helpers/terraform_validate b/helpers/terraform_validate new file mode 100755 index 0000000..7f60982 --- /dev/null +++ b/helpers/terraform_validate @@ -0,0 +1,23 @@ +#! /bin/bash +# +# Copyright 2019 Google LLC. This software is provided as-is, without warranty +# or representation for any use or purpose. Your use of it is subject to your +# agreement with Google. +# +# This script initializes modules so that terraform validate as of 0.12 behaves +# as expected and does not issue errors such as: +# +# Error: Module not installed +# +# on test/fixtures/shared_vpc_no_subnets/main.tf line 37: +# 37: module "project-factory" { +# +# This module is not yet installed. Run "terraform init" to install all modules +# required by this configuration. + +# The first and only argument to this script is the directory containing *.tf +# files to validate. This directory is assumed to be a root module. + +cd "$1" +terraform init -backend=false +terraform validate diff --git a/modules/cos-coredns/README.md b/modules/cos-coredns/README.md index 66c2b99..10f5d7b 100644 --- a/modules/cos-coredns/README.md +++ b/modules/cos-coredns/README.md @@ -28,33 +28,32 @@ module "dns-service" { } ``` -[^]: (autogen_docs_start) - + ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| network | Self link of the VPC subnet to use for firewall rules. | string | n/a | yes | -| project\_id | Project id where the instances will be created. | string | n/a | yes | -| region | Region for external addresses. | string | n/a | yes | -| subnetwork | Self link of the VPC subnet to use for the internal interface. | string | n/a | yes | -| zone | Instance zone. | string | n/a | yes | -| boot\_disk\_size | Size of the boot disk. | string | `"10"` | no | -| client\_cidrs | Client IP CIDR ranges to set in the firewall rule. | list | `` | no | +| boot\_disk\_size | Size of the boot disk. | number | `"10"` | no | +| client\_cidrs | Client IP CIDR ranges to set in the firewall rule. | list(string) | `` | no | | container\_image | CoreDNS container version. | string | `"coredns/coredns"` | no | | corefile | Path to the CoreDNS configuration file to use. | string | `""` | no | -| create\_firewall\_rule | Create tag-based firewall rule. | string | `"false"` | no | -| instance\_count | Number of instances to create. | string | `"1"` | no | +| create\_firewall\_rule | Create tag-based firewall rule. | bool | `"false"` | no | +| instance\_count | Number of instances to create. | number | `"1"` | no | | instance\_type | Instance machine type. | string | `"g1-small"` | no | -| labels | Labels to be attached to the resources | map | `` | no | +| labels | Labels to be attached to the resources | map(string) | `` | no | | log\_driver | Docker log driver to use for CoreDNS. | string | `"gcplogs"` | no | +| network | Self link of the VPC subnet to use for firewall rules. | string | n/a | yes | | network\_tag | Network tag that identifies the instances. | string | `"coredns"` | no | | prefix | Prefix to prepend to resource names. | string | `""` | no | -| scopes | Instance scopes. | list | `` | no | +| project\_id | Project id where the instances will be created. | string | n/a | yes | +| region | Region for external addresses. | string | n/a | yes | +| scopes | Instance scopes. | list(string) | `` | no | | service\_account | Instance service account. | string | `""` | no | -| stackdriver\_logging | Enable the Stackdriver logging agent. | string | `"true"` | no | +| stackdriver\_logging | Enable the Stackdriver logging agent. | bool | `"true"` | no | | stackdriver\_monitoring | Enable the Stackdriver monitoring agent. | string | `"true"` | no | -| vm\_tags | Additional network tags for the instances. | list | `` | no | +| subnetwork | Self link of the VPC subnet to use for the internal interface. | string | n/a | yes | +| vm\_tags | Additional network tags for the instances. | list(string) | `` | no | +| zone | Instance zone. | string | n/a | yes | ## Outputs @@ -64,4 +63,4 @@ module "dns-service" { | internal\_addresses | List of instance internal addresses. | | names | List of instance names. | -[^]: (autogen_docs_end) + diff --git a/modules/cos-coredns/main.tf b/modules/cos-coredns/main.tf index 95f6a1b..ef64193 100644 --- a/modules/cos-coredns/main.tf +++ b/modules/cos-coredns/main.tf @@ -34,7 +34,7 @@ data "template_file" "cloud-config" { count = var.instance_count template = file("${path.module}/assets/cloud-config.yaml") - vars { + vars = { corefile = file( var.corefile != "" ? var.corefile : "${path.module}/assets/Corefile" ) @@ -42,7 +42,7 @@ data "template_file" "cloud-config" { image = var.container_image instance_id = count.index + 1 log_driver = var.log_driver - ip_address = element(google_compute_address.addresses.*.address, count.index) + ip_address = google_compute_address.addresses.*.address[count.index] } } @@ -50,7 +50,7 @@ resource "google_compute_instance" "default" { count = var.instance_count name = "${local.prefix}coredns-${count.index + 1}" description = "coreDNS with containers on CoS." - tags = [concat(list(var.network_tag), var.vm_tags)] + tags = concat(list(var.network_tag), var.vm_tags) labels = var.labels machine_type = var.instance_type project = var.project_id @@ -71,20 +71,20 @@ resource "google_compute_instance" "default" { } network_interface { - subnetwork = var.subnetwork - network_ip = element(google_compute_address.addresses.*.address, count.index) - access_config = {} + subnetwork = var.subnetwork + network_ip = google_compute_address.addresses.*.address[count.index] + access_config {} } service_account { email = var.service_account - scopes = [var.scopes] + scopes = var.scopes } - metadata { + metadata = { google-logging-enabled = var.stackdriver_logging google-monitoring-enabled = var.stackdriver_monitoring - user-data = element(data.template_file.cloud-config.*.rendered, count.index) + user-data = data.template_file.cloud-config.*.rendered[count.index] } } @@ -97,7 +97,7 @@ resource "google_compute_firewall" "allow-tag-coredns" { network = var.network project = var.project_id - source_ranges = [var.client_cidrs] + source_ranges = var.client_cidrs target_tags = ["coredns"] allow { diff --git a/modules/cos-coredns/variables.tf b/modules/cos-coredns/variables.tf index 9d20123..abd491d 100644 --- a/modules/cos-coredns/variables.tf +++ b/modules/cos-coredns/variables.tf @@ -16,47 +16,56 @@ variable "project_id" { description = "Project id where the instances will be created." + type = string } variable "region" { description = "Region for external addresses." + type = string } variable "zone" { description = "Instance zone." + type = string } variable "network" { description = "Self link of the VPC subnet to use for firewall rules." + type = string } variable "subnetwork" { description = "Self link of the VPC subnet to use for the internal interface." + type = string } variable "instance_count" { description = "Number of instances to create." + type = number default = 1 } variable "network_tag" { description = "Network tag that identifies the instances." + type = string default = "coredns" } variable "vm_tags" { description = "Additional network tags for the instances." + type = list(string) default = [] } variable "instance_type" { description = "Instance machine type." + type = string default = "g1-small" } variable "scopes" { description = "Instance scopes." - + type = list(string) default = [ "https://www.googleapis.com/auth/devstorage.read_only", "https://www.googleapis.com/auth/logging.write", @@ -70,36 +79,43 @@ variable "scopes" { variable "service_account" { description = "Instance service account." + type = string default = "" } variable "prefix" { description = "Prefix to prepend to resource names." + type = string default = "" } variable "create_firewall_rule" { description = "Create tag-based firewall rule." + type = bool default = false } variable "client_cidrs" { description = "Client IP CIDR ranges to set in the firewall rule." + type = list(string) default = [] } variable "boot_disk_size" { description = "Size of the boot disk." + type = number default = 10 } variable "container_image" { description = "CoreDNS container version." + type = string default = "coredns/coredns" } variable "corefile" { description = "Path to the CoreDNS configuration file to use." + type = string default = "" } @@ -110,6 +126,7 @@ variable "log_driver" { variable "stackdriver_logging" { description = "Enable the Stackdriver logging agent." + type = bool default = true } @@ -119,9 +136,8 @@ variable "stackdriver_monitoring" { } variable "labels" { - type = "map" description = "Labels to be attached to the resources" - + type = map(string) default = { service = "coredns" } diff --git a/modules/cos-generic/README.md b/modules/cos-generic/README.md index 83f0f94..9e35fde 100644 --- a/modules/cos-generic/README.md +++ b/modules/cos-generic/README.md @@ -79,30 +79,29 @@ runcmd: - systemctl enable gcs-sync.timer && systemctl start gcs-sync.timer ``` -[^]: (autogen_docs_start) - + ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| project\_id | Project id where the instances will be created. | string | n/a | yes | -| region | Region for external addresses. | string | n/a | yes | -| subnetwork | Self link of the VPC subnet to use for the internal interface. | string | n/a | yes | -| zone | Instance zone. | string | n/a | yes | -| allow\_stopping\_for\_update | Allow stopping the instance for specific Terraform changes. | string | `"false"` | no | -| boot\_disk\_size | Size of the boot disk. | string | `"10"` | no | +| allow\_stopping\_for\_update | Allow stopping the instance for specific Terraform changes. | bool | `"false"` | no | +| boot\_disk\_size | Size of the boot disk. | number | `"10"` | no | | cloud\_init | Path to a file that will be used for the cloud-config template. | string | `""` | no | | cloud\_init\_custom\_var | String passed in to the cloud-config template as custome variable. | string | `""` | no | -| instance\_count | Number of instances to create. | string | `"1"` | no | +| instance\_count | Number of instances to create. | number | `"1"` | no | | instance\_type | Instance machine type. | string | `"g1-small"` | no | -| labels | Labels to be attached to the resources | map | `` | no | +| labels | Labels to be attached to the resources | map(string) | `` | no | | prefix | Prefix to prepend to resource names. | string | `""` | no | -| reserve\_ip | Reserve an IP address for the instance instead of using an ephemeral address. | string | `"false"` | no | -| scopes | Instance scopes. | list | `` | no | +| project\_id | Project id where the instances will be created. | string | n/a | yes | +| region | Region for external addresses. | string | n/a | yes | +| reserve\_ip | Reserve an IP address for the instance instead of using an ephemeral address. | bool | `"false"` | no | +| scopes | Instance scopes. | list(string) | `` | no | | service\_account | Instance service account. | string | `""` | no | -| stackdriver\_logging | Enable the Stackdriver logging agent. | string | `"true"` | no | -| stackdriver\_monitoring | Enable the Stackdriver monitoring agent. | string | `"true"` | no | -| vm\_tags | Additional network tags for the instances. | list | `` | no | +| stackdriver\_logging | Enable the Stackdriver logging agent. | bool | `"true"` | no | +| stackdriver\_monitoring | Enable the Stackdriver monitoring agent. | bool | `"true"` | no | +| subnetwork | Self link of the VPC subnet to use for the internal interface. | string | n/a | yes | +| vm\_tags | Additional network tags for the instances. | list(string) | `` | no | +| zone | Instance zone. | string | n/a | yes | ## Outputs @@ -112,4 +111,4 @@ runcmd: | internal\_addresses | List of instance internal addresses. | | names | List of instance names. | -[^]: (autogen_docs_end) + diff --git a/modules/cos-generic/main.tf b/modules/cos-generic/main.tf index d58def8..0ea2542 100644 --- a/modules/cos-generic/main.tf +++ b/modules/cos-generic/main.tf @@ -33,13 +33,13 @@ resource "google_compute_address" "addresses" { data "template_file" "cloud-config" { count = var.instance_count - template = file("${local.cloud_init}") + template = file(local.cloud_init) - vars { + vars = { custom_var = var.cloud_init_custom_var instance_id = count.index + 1 instance_name = "${local.prefix}${count.index + 1}" - ip_address = var.reserve_ip ? element(google_compute_address.addresses.*.address, count.index) : "" + ip_address = var.reserve_ip ? google_compute_address.addresses.*.address[count.index] : "" } } @@ -47,7 +47,7 @@ resource "google_compute_instance" "default" { count = var.instance_count name = "${local.prefix}${count.index + 1}" description = "Terraform-managed." - tags = [var.vm_tags] + tags = var.vm_tags labels = var.labels machine_type = var.instance_type project = var.project_id @@ -68,20 +68,20 @@ resource "google_compute_instance" "default" { } network_interface { - subnetwork = var.subnetwork - network_ip = var.reserve_ip ? element(google_compute_address.addresses.*.address, count.index) : "" - access_config = {} + subnetwork = var.subnetwork + network_ip = var.reserve_ip ? google_compute_address.addresses.*.address[count.index] : "" + access_config {} } service_account { email = var.service_account - scopes = [var.scopes] + scopes = var.scopes } - metadata { + metadata = { google-logging-enabled = var.stackdriver_logging google-monitoring-enabled = var.stackdriver_monitoring - user-data = element(data.template_file.cloud-config.*.rendered, count.index) + user-data = data.template_file.cloud-config.*.rendered[count.index] } allow_stopping_for_update = var.allow_stopping_for_update diff --git a/modules/cos-generic/variables.tf b/modules/cos-generic/variables.tf index 673f5f3..2f3e87f 100644 --- a/modules/cos-generic/variables.tf +++ b/modules/cos-generic/variables.tf @@ -16,38 +16,45 @@ variable "project_id" { description = "Project id where the instances will be created." + type = string } variable "region" { description = "Region for external addresses." + type = string } variable "zone" { description = "Instance zone." + type = string } variable "subnetwork" { description = "Self link of the VPC subnet to use for the internal interface." + type = string } variable "instance_count" { description = "Number of instances to create." + type = number default = 1 } variable "vm_tags" { description = "Additional network tags for the instances." + type = list(string) default = [] } variable "instance_type" { description = "Instance machine type." + type = string default = "g1-small" } variable "scopes" { description = "Instance scopes." - + type = list(string) default = [ "https://www.googleapis.com/auth/devstorage.read_only", "https://www.googleapis.com/auth/logging.write", @@ -61,33 +68,37 @@ variable "scopes" { variable "service_account" { description = "Instance service account." + type = string default = "" } variable "prefix" { description = "Prefix to prepend to resource names." + type = string default = "" } variable "boot_disk_size" { description = "Size of the boot disk." + type = number default = 10 } variable "stackdriver_logging" { description = "Enable the Stackdriver logging agent." + type = bool default = true } variable "stackdriver_monitoring" { description = "Enable the Stackdriver monitoring agent." + type = bool default = true } variable "labels" { - type = "map" description = "Labels to be attached to the resources" - + type = map(string) default = { service = "coredns" } @@ -95,20 +106,24 @@ variable "labels" { variable "reserve_ip" { description = "Reserve an IP address for the instance instead of using an ephemeral address." + type = bool default = false } variable "cloud_init" { description = "Path to a file that will be used for the cloud-config template." + type = string default = "" } variable "cloud_init_custom_var" { description = "String passed in to the cloud-config template as custome variable." + type = string default = "" } variable "allow_stopping_for_update" { description = "Allow stopping the instance for specific Terraform changes." + type = bool default = false } diff --git a/modules/cos-mysql/README.md b/modules/cos-mysql/README.md index 730ebb4..808ab9b 100644 --- a/modules/cos-mysql/README.md +++ b/modules/cos-mysql/README.md @@ -42,38 +42,38 @@ module "mysql" { } ``` -[^]: (autogen_docs_start) - + ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| data\_disk\_size | Size of data disk. | string | n/a | yes | -| network | Self link of the VPC subnet to use for firewall rules. | string | n/a | yes | -| project\_id | Project id where the instances will be created. | string | n/a | yes | -| region | Region for internal addresses. | string | n/a | yes | -| subnetwork | Self link of the VPC subnet to use for the internal interface. | string | n/a | yes | -| zone | Instance zone. | string | n/a | yes | -| boot\_disk\_size | Size of boot disk. | string | `"40"` | no | -| client\_cidrs | Client IP CIDR ranges to set in the firewall rule. | list | `` | no | +| boot\_disk\_size | Size of boot disk. | number | `"40"` | no | +| client\_cidrs | Client IP CIDR ranges to set in the firewall rule. | list(string) | `` | no | | container\_image | MySQL container version. | string | `"mysql:5.7"` | no | -| create\_firewall\_rule | Create tag-based firewall rule. | string | `"false"` | no | +| create\_firewall\_rule | Create tag-based firewall rule. | bool | `"false"` | no | +| data\_disk\_size | Size of data disk. | number | n/a | yes | | data\_disk\_type | Type of data disk. | string | `"pd-ssd"` | no | | host\_project\_id | VPC host project id if the instance is in a service project. | string | `""` | no | -| instance\_count | Number of instances to create. | string | `"1"` | no | +| instance\_count | Number of instances to create. | number | `"1"` | no | | instance\_type | Instance machine type. | string | `"n1-standard-2"` | no | -| kms\_data | Map with KMS project_id, keyring, location and key if password is encrypted with KMS. | map | `` | no | -| labels | Labels to be attached to the resources | map | `` | no | +| kms\_data | Map with KMS project_id, keyring, location and key if password is encrypted with KMS. | object | `"null"` | no | +| labels | Labels to be attached to the resources | map(string) | `` | no | +| log\_driver | Docker log driver to use for CoreDNS. | string | `"gcplogs"` | no | | my\_cnf | Content of the my.cnf file that will be written on the instances. | string | `""` | no | -| mysql\_port | Port MySQL will listen on. | string | `"3306"` | no | +| mysql\_port | Port MySQL will listen on. | number | `"3306"` | no | +| network | Self link of the VPC subnet to use for firewall rules. | string | n/a | yes | | network\_tag | Network tag that identifies the instances. | string | `"mysql"` | no | | password | Provide a plain text on KMS-encrypted password instead of using the auto-generated one. | string | `""` | no | | prefix | Prefix to prepend to resource names. | string | `""` | no | -| scopes | Instance scopes. | list | `` | no | +| project\_id | Project id where the instances will be created. | string | n/a | yes | +| region | Region for internal addresses. | string | n/a | yes | +| scopes | Instance scopes. | list(string) | `` | no | | service\_account | Instance service account. | string | `""` | no | -| stackdriver\_logging | Enable the Stackdriver logging agent. | string | `"true"` | no | -| stackdriver\_monitoring | Enable the Stackdriver monitoring agent. | string | `"true"` | no | -| vm\_tags | Additional network tags for the instances. | list | `` | no | +| stackdriver\_logging | Enable the Stackdriver logging agent. | bool | `"true"` | no | +| stackdriver\_monitoring | Enable the Stackdriver monitoring agent. | bool | `"true"` | no | +| subnetwork | Self link of the VPC subnet to use for the internal interface. | string | n/a | yes | +| vm\_tags | Additional network tags for the instances. | list(string) | `` | no | +| zone | Instance zone. | string | n/a | yes | ## Outputs @@ -82,4 +82,4 @@ module "mysql" { | instances | Instance name => address map. | | password | Auto-generated password, if no password was set as a variable. | -[^]: (autogen_docs_end) + diff --git a/modules/cos-mysql/main.tf b/modules/cos-mysql/main.tf index 7d91094..96159c4 100644 --- a/modules/cos-mysql/main.tf +++ b/modules/cos-mysql/main.tf @@ -43,7 +43,7 @@ data "template_file" "cloud-config" { count = var.instance_count template = file("${path.module}/assets/cloud-config.yaml") - vars { + vars = { image = var.container_image instance_id = count.index + 1 ip_address = google_compute_address.addresses.*.address[count.index] @@ -74,7 +74,7 @@ resource "google_compute_instance" "default" { count = var.instance_count name = "${local.prefix}mysql-${count.index + 1}" description = "MySQL test with containers on CoS." - tags = [concat(list(var.network_tag), var.vm_tags)] + tags = concat(list(var.network_tag), var.vm_tags) labels = var.labels machine_type = var.instance_type project = var.project_id @@ -96,9 +96,9 @@ resource "google_compute_instance" "default" { } network_interface { - subnetwork = var.subnetwork - network_ip = google_compute_address.addresses.*.address[count.index] - access_config = {} + subnetwork = var.subnetwork + network_ip = google_compute_address.addresses.*.address[count.index] + access_config {} } attached_disk { @@ -109,14 +109,14 @@ resource "google_compute_instance" "default" { service_account { email = var.service_account - scopes = [compact(concat( + scopes = compact(concat( var.scopes, - list("${local.use_kms ? "https://www.googleapis.com/auth/cloudkms" : ""}") - ))] + list(local.use_kms ? "https://www.googleapis.com/auth/cloudkms" : "") + )) } - metadata { - user-data = element(data.template_file.cloud-config.*.rendered, count.index) + metadata = { + user-data = data.template_file.cloud-config.*.rendered[count.index] google-logging-enabled = var.stackdriver_logging google-monitoring-enabled = var.stackdriver_monitoring } @@ -131,7 +131,7 @@ resource "google_compute_firewall" "allow-tag-mysql" { network = var.network project = local.net_project_id - source_ranges = [var.client_cidrs] + source_ranges = var.client_cidrs target_tags = ["mysql"] allow { diff --git a/modules/cos-mysql/variables.tf b/modules/cos-mysql/variables.tf index 154550f..2e50b59 100644 --- a/modules/cos-mysql/variables.tf +++ b/modules/cos-mysql/variables.tf @@ -16,47 +16,56 @@ variable "project_id" { description = "Project id where the instances will be created." + type = string } variable "region" { description = "Region for internal addresses." + type = string } variable "zone" { description = "Instance zone." + type = string } variable "network" { description = "Self link of the VPC subnet to use for firewall rules." + type = string } variable "subnetwork" { description = "Self link of the VPC subnet to use for the internal interface." + type = string } variable "instance_count" { description = "Number of instances to create." + type = number default = 1 } variable "network_tag" { description = "Network tag that identifies the instances." + type = string default = "mysql" } variable "vm_tags" { description = "Additional network tags for the instances." + type = list(string) default = [] } variable "instance_type" { description = "Instance machine type." + type = string default = "n1-standard-2" } variable "scopes" { description = "Instance scopes." - + type = list(string) default = [ "https://www.googleapis.com/auth/devstorage.read_only", "https://www.googleapis.com/auth/logging.write", @@ -70,87 +79,102 @@ variable "scopes" { variable "service_account" { description = "Instance service account." + type = string default = "" } variable "prefix" { description = "Prefix to prepend to resource names." + type = string default = "" } variable "create_firewall_rule" { description = "Create tag-based firewall rule." + type = bool default = false } variable "host_project_id" { description = "VPC host project id if the instance is in a service project." + type = string default = "" } variable "my_cnf" { description = "Content of the my.cnf file that will be written on the instances." + type = string default = "" } variable "kms_data" { description = "Map with KMS project_id, keyring, location and key if password is encrypted with KMS." - default = {} + type = object({ key = string, keyring = string, location = string }) + default = null } variable "password" { description = "Provide a plain text on KMS-encrypted password instead of using the auto-generated one." + type = string default = "" } variable "client_cidrs" { description = "Client IP CIDR ranges to set in the firewall rule." + type = list(string) default = [] } variable "data_disk_size" { description = "Size of data disk." + type = number } variable "data_disk_type" { description = "Type of data disk." + type = string default = "pd-ssd" } variable "boot_disk_size" { description = "Size of boot disk." + type = number default = 40 } variable "container_image" { description = "MySQL container version." + type = string default = "mysql:5.7" } variable "log_driver" { description = "Docker log driver to use for CoreDNS." + type = string default = "gcplogs" } variable "stackdriver_logging" { description = "Enable the Stackdriver logging agent." + type = bool default = true } variable "stackdriver_monitoring" { description = "Enable the Stackdriver monitoring agent." + type = bool default = true } variable "mysql_port" { description = "Port MySQL will listen on." + type = number default = 3306 } variable "labels" { - type = "map" description = "Labels to be attached to the resources" - + type = map(string) default = { service = "mysql" } diff --git a/test/fixtures/shared/terraform.tfvars b/test/fixtures/shared/terraform.tfvars new file mode 100644 index 0000000..7839ce6 --- /dev/null +++ b/test/fixtures/shared/terraform.tfvars @@ -0,0 +1,3 @@ +project_id = "ci-container-vm" +region = "us-east4" +zone = "us-east4-b" diff --git a/test/fixtures/shared/terraform.tfvars.sample b/test/fixtures/shared/terraform.tfvars.sample deleted file mode 100644 index 9f4ba38..0000000 --- a/test/fixtures/shared/terraform.tfvars.sample +++ /dev/null @@ -1,3 +0,0 @@ -project_id="" -region="us-east4" -zone="us-east4-b" diff --git a/test/make.sh b/test/make.sh index ce1f627..64d553a 100755 --- a/test/make.sh +++ b/test/make.sh @@ -40,7 +40,10 @@ find_files() { -o -path '*/.terraform' \ -o -path '*/.kitchen' \ ')' \ - -prune -o -type f "$@" + -prune -o -type f \ + -not -path '*managed[_-]instance[_-]group*' "$@" + # `-not -path` above is a temporary workaround for issue + # https://github.com/terraform-google-modules/terraform-google-container-vm/issues/28 } # Compatibility with both GNU and BSD style xargs. @@ -71,14 +74,6 @@ function basefiles() { done } -# This function runs the hadolint linter on -# every file named 'Dockerfile' -function docker() { - echo "Running hadolint on Dockerfiles" - find_files . -name "Dockerfile" -print0 \ - | compat_xargs -0 hadolint -} - # This function runs 'terraform validate' and 'terraform fmt' # against all directory paths which contain *.tf files. function check_terraform() { diff --git a/test/verify_boilerplate.py b/test/verify_boilerplate.py index c27a7d8..d35e47e 100644 --- a/test/verify_boilerplate.py +++ b/test/verify_boilerplate.py @@ -63,7 +63,7 @@ def get_args(): return parser.parse_args() -def get_refs(ARGS): +def get_refs(args): """Converts the directory of boilerplate files into a map keyed by file extension. @@ -79,7 +79,7 @@ def get_refs(ARGS): # Find and iterate over the absolute path for each boilerplate template for path in glob.glob(os.path.join( - ARGS.boilerplate_dir, + args.boilerplate_dir, "boilerplate.*.txt")): extension = os.path.basename(path).split(".")[1] ref_file = open(path, 'r') @@ -188,11 +188,11 @@ def normalize_files(files): newfiles.append(pathname) for idx, pathname in enumerate(newfiles): if not os.path.isabs(pathname): - newfiles[idx] = os.path.join(ARGS.rootdir, pathname) + newfiles[idx] = os.path.join(args.rootdir, pathname) return newfiles -def get_files(extensions, ARGS): +def get_files(extensions, args): """Generates a list of paths whose boilerplate should be verified. If a list of file names has been provided on the command line, it will be @@ -211,10 +211,10 @@ def get_files(extensions, ARGS): A list of absolute file paths """ files = [] - if ARGS.filenames: - files = ARGS.filenames + if args.filenames: + files = args.filenames else: - for root, dirs, walkfiles in os.walk(ARGS.rootdir): + for root, dirs, walkfiles in os.walk(args.rootdir): # don't visit certain dirs. This is just a performance improvement # as we would prune these later in normalize_files(). But doing it # cuts down the amount of filesystem walking we do and cuts down @@ -289,5 +289,5 @@ def main(args): if __name__ == "__main__": - ARGS = get_args() - main(ARGS) + args = get_args() + main(args) diff --git a/variables.tf b/variables.tf index 19a1386..812872f 100644 --- a/variables.tf +++ b/variables.tf @@ -18,7 +18,6 @@ variable "container" { // This is necessary to work around a limitation in Terraform 0.12. If this is set to `map`, as intended, Terraform expects all values within the map to have the same type, which is not the case here. type = any description = "A description of the container to deploy" - default = { image = "gcr.io/google-containers/busybox" command = "ls" @@ -29,12 +28,11 @@ variable "volumes" { // This is necessary to work around a limitation in Terraform 0.12. If this is set to `map`, as intended, Terraform expects all values within the map to have the same type, which is not the case here. type = any description = "A set of Docker Volumes to configure" - - default = [] + default = [] } variable "restart_policy" { description = "The restart policy for a Docker container. Defaults to `OnFailure`" - - default = "OnFailure" + type = string + default = "OnFailure" }