diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..20265c2f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.git +.terraform +.terraform.d +.kitchen +terraform.tfstate.d +test/fixtures/*/.terraform +test/fixtures/*/terraform.tfstate.d +examples/.kitchen +examples/*/.terraform +examples/*/terraform.tfstate.d diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1c2e86dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# OSX leaves these everywhere on SMB shares +._* + +# OSX trash +.DS_Store + +# Python +*.pyc + +# Emacs save files +*~ +\#*\# +.\#* + +# Vim-related files +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist + +### https://raw.github.com/github/gitignore/90f149de451a5433aebd94d02d11b0e28843a1af/Terraform.gitignore + +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# Kitchen files +**/inspec.lock +**/.kitchen +**/kitchen.local.yml +**/Gemfile.lock + +# Ignore any .tfvars files that are generated automatically for each Terraform run. Most +# .tfvars files are managed as part of configuration and so should be included in +# version control. +**/*.tfvars + +google-cloud-sdk/ +google-cloud-sdk.staging/ +credentials.json diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..91ddc9e1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on +[Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0] - 20XX-YY-ZZ + +### Added + +- Initial release + +[Unreleased]: https://github.com/terraform-google-modules/terraform-google-gcloud/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/terraform-google-modules/terraform-google-gcloud/releases/tag/v0.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..a350db59 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,99 @@ +# Contributing + +This document provides guidelines for contributing to the module. + +## Dependencies + +The following dependencies must be installed on the development system: + +- [Docker Engine][docker-engine] +- [Google Cloud SDK][google-cloud-sdk] +- [make] + +## Generating Documentation for Inputs and Outputs + +The Inputs and Outputs tables in the READMEs of the root module, +submodules, and example modules are automatically generated based on +the `variables` and `outputs` of the respective modules. These tables +must be refreshed if the module interfaces are changed. + +### Execution + +Run `make generate_docs` to generate new Inputs and Outputs tables. + +## Integration Testing + +Integration tests are used to verify the behaviour of the root module, +submodules, and example modules. Additions, changes, and fixes should +be accompanied with tests. + +The integration tests are run using [Kitchen][kitchen], +[Kitchen-Terraform][kitchen-terraform], and [InSpec][inspec]. These +tools are packaged within a Docker image for convenience. + +The general strategy for these tests is to verify the behaviour of the +[example modules](./examples/), thus ensuring that the root module, +submodules, and example modules are all functionally correct. + +### Test Environment +The easiest way to test the module is in an isolated test project. The setup for such a project is defined in [test/setup](./test/setup/) directory. + +To use this setup, you need a service account with Project Creator access on a folder. Export the Service Account credentials to your environment like so: + +``` +export SERVICE_ACCOUNT_JSON=$(< credentials.json) +``` + +You will also need to set a few environment variables: +``` +export TF_VAR_org_id="your_org_id" +export TF_VAR_folder_id="your_folder_id" +export TF_VAR_billing_account="your_billing_account_id" +``` + +With these settings in place, you can prepare a test project using Docker: +``` +make docker_test_prepare +``` + +### Noninteractive Execution + +Run `make docker_test_integration` to test all of the example modules +noninteractively, using the prepared test project. + +### Interactive Execution + +1. Run `make docker_run` to start the testing Docker container in + interactive mode. + +1. Run `kitchen_do create ` to initialize the working + directory for an example module. + +1. Run `kitchen_do converge ` to apply the example module. + +1. Run `kitchen_do verify ` to test the example module. + +1. Run `kitchen_do destroy ` to destroy the example module + state. + +## Linting and Formatting + +Many of the files in the repository can be linted or formatted to +maintain a standard of quality. + +### Execution + +Run `make docker_test_lint`. + +[docker-engine]: https://www.docker.com/products/docker-engine +[flake8]: http://flake8.pycqa.org/en/latest/ +[gofmt]: https://golang.org/cmd/gofmt/ +[google-cloud-sdk]: https://cloud.google.com/sdk/install +[hadolint]: https://github.com/hadolint/hadolint +[inspec]: https://inspec.io/ +[kitchen-terraform]: https://github.com/newcontext-oss/kitchen-terraform +[kitchen]: https://kitchen.ci/ +[make]: https://en.wikipedia.org/wiki/Make_(software) +[shellcheck]: https://www.shellcheck.net/ +[terraform-docs]: https://github.com/segmentio/terraform-docs +[terraform]: https://terraform.io/ diff --git a/LICENSE b/LICENSE index 261eeb9e..d6456956 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,4 @@ + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..0e67c7e6 --- /dev/null +++ b/Makefile @@ -0,0 +1,117 @@ +# 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. +# 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. + +# Please note that this file was generated from [terraform-google-module-template](https://github.com/terraform-google-modules/terraform-google-module-template). +# Please make sure to contribute relevant changes upstream! + +# Make will use bash instead of sh +SHELL := /usr/bin/env bash + +GCLOUD_SDK_VERSION:=268.0.0 +DOCKER_TAG_VERSION_DEVELOPER_TOOLS := 0.4.6 +DOCKER_IMAGE_DEVELOPER_TOOLS := cft/developer-tools +REGISTRY_URL := gcr.io/cloud-foundation-cicd + +# Enter docker container for local development +.PHONY: docker_run +docker_run: + docker run --rm -it \ + -e SERVICE_ACCOUNT_JSON \ + -v "$(CURDIR)":/workspace \ + $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ + /bin/bash + +# Execute prepare tests within the docker container +.PHONY: docker_test_prepare +docker_test_prepare: + docker run --rm -it \ + -e SERVICE_ACCOUNT_JSON \ + -e TF_VAR_org_id \ + -e TF_VAR_folder_id \ + -e TF_VAR_billing_account \ + -v "$(CURDIR)":/workspace \ + $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ + /usr/local/bin/execute_with_credentials.sh prepare_environment + +# Clean up test environment within the docker container +.PHONY: docker_test_cleanup +docker_test_cleanup: + docker run --rm -it \ + -e SERVICE_ACCOUNT_JSON \ + -e TF_VAR_org_id \ + -e TF_VAR_folder_id \ + -e TF_VAR_billing_account \ + -v "$(CURDIR)":/workspace \ + $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ + /usr/local/bin/execute_with_credentials.sh cleanup_environment + +# Execute integration tests within the docker container +.PHONY: docker_test_integration +docker_test_integration: + docker run --rm -it \ + -e SERVICE_ACCOUNT_JSON \ + -v "$(CURDIR)":/workspace \ + $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ + /usr/local/bin/test_integration.sh + +# Execute lint tests within the docker container +.PHONY: docker_test_lint +docker_test_lint: + docker run --rm -it \ + -v "$(CURDIR)":/workspace \ + $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ + /usr/local/bin/test_lint.sh + +# Generate documentation +.PHONY: docker_generate_docs +docker_generate_docs: + docker run --rm -it \ + -v "$(CURDIR)":/workspace \ + $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ + /bin/bash -c 'source /usr/local/bin/task_helper_functions.sh && generate_docs' + +# Alias for backwards compatibility +.PHONY: generate_docs +generate_docs: docker_generate_docs + +.PHONY: all +all: reset +all: + $(MAKE) gcloud.darwin + $(MAKE) gcloud.linux + +.PHONY: gcloud.darwin +gcloud.darwin: OS_ARCH=darwin +gcloud.darwin: gcloud.download + +.PHONY: gcloud.linux +gcloud.linux: OS_ARCH=linux +gcloud.linux: gcloud.download + +.PHONY: gcloud.download +gcloud.download: + mkdir -p cache/${OS_ARCH}/ + cd cache/${OS_ARCH}/ && \ + curl -sL -o google-cloud-sdk.tar.gz https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${GCLOUD_SDK_VERSION}-${OS_ARCH}-x86_64.tar.gz + +.PHONY: clean +clean: ## Clean caches of decompressed SDKs + rm -rf cache/darwin/google-cloud-sdk/ + rm -rf cache/linux/google-cloud-sdk/ + rm -rf cache/darwin/google-cloud-sdk.staging/ + rm -rf cache/linux/google-cloud-sdk.staging/ + +.PHONY: reset +reset: + rm -rf cache diff --git a/README.md b/README.md index 3fbc0108..15a02020 100644 --- a/README.md +++ b/README.md @@ -1 +1,87 @@ -# terraform-google-gcloud \ No newline at end of file +# terraform-google-gcloud + +This module allows you to use gcloud, gsutil, and any gcloud component in Terraform. Sometimes, there isn't Terraform GCP support for a particular feature, or you'd like to do something each time Terraform runs (ie: upload a file to a Kubernetes pod) that lacks Terraform support. + +This module *does not* create any resources on GCP itself, rather exposes the GCP SDK to you for usage in null resources & external data resources. + +## Usage + +Basic usage of this module is as follows: + +```hcl +module "gcloud" { + source = "terraform-google-modules/gcloud/google" + version = "~> 0.1" + + platform = "linux" + additional_components = ["kubectl", "beta"] + + create_cmd_entrypoint = "gcloud" + create_cmd_body = "version" + destroy_cmd_entrypoint = "gcloud" + destroy_cmd_body = "version" +} +``` + +Functional examples are included in the +[examples](./examples/) directory. + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| additional\_components | Additional gcloud CLI components to install. Defaults to none. Valid value are components listed in `gcloud components list` | list | `` | no | +| create\_cmd\_body | On create, the command body you'd like to run with your entrypoint. | string | `"info"` | no | +| create\_cmd\_entrypoint | On create, the command entrypoint you'd like to use. | string | `"gcloud"` | no | +| destroy\_cmd\_body | On destroy, the command body you'd like to run with your entrypoint. | string | `"info"` | no | +| destroy\_cmd\_entrypoint | On destroy, the command entrypoint you'd like to use. | string | `"gcloud"` | no | +| enabled | Flag to optionally disable usage of this module. | bool | `"true"` | no | +| platform | Platform CLI will run on. Defaults to linux. Valid values: linux, darwin | string | `"linux"` | no | +| service\_account\_key\_file | Path to service account key file to run `gcloud auth activate-service-account` with. Optional. | string | `""` | no | +| use\_tf\_google\_credentials\_env\_var | Use GOOGLE_CREDENTIALS environment variable to run `gcloud auth activate-service-account` with. Optional. | string | `"false"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| create\_cmd\_bin | The full bin path & command used on create | +| destroy\_cmd\_bin | The full bin path & command used on destroy | + + + +## Requirements + +These sections describe requirements for using this module. + +### Software + +The following dependencies must be available: + +- [Terraform][terraform] v0.12 +- [Terraform Provider for GCP][terraform-provider-gcp] plugin v2.0 + +### Service Account + +A service account must be created, along with a key, to use this module. +The service account must have the proper IAM roles for whatever +commands you're running with this module. + +### APIs + +A project is not required to host resources of this module, since +this module does not create any resources. + +However you will likely need a project for your service account +and any resources you'd like to interact with while using this module. + +## Contributing + +Refer to the [contribution guidelines](./CONTRIBUTING.md) for +information on contributing to this module. + +[iam-module]: https://registry.terraform.io/modules/terraform-google-modules/iam/google +[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/build/int.cloudbuild.yaml b/build/int.cloudbuild.yaml new file mode 100644 index 00000000..ff44db3c --- /dev/null +++ b/build/int.cloudbuild.yaml @@ -0,0 +1,41 @@ +# 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. +# 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. + +timeout: 3600s +steps: +- id: prepare + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && prepare_environment'] + env: + - 'TF_VAR_org_id=$_ORG_ID' + - 'TF_VAR_folder_id=$_FOLDER_ID' + - 'TF_VAR_billing_account=$_BILLING_ACCOUNT' +- id: create + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do create'] +- id: converge + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do converge'] +- id: verify + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do verify'] +- id: destroy + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do destroy'] +tags: +- 'ci' +- 'integration' +substitutions: + _DOCKER_IMAGE_DEVELOPER_TOOLS: 'cft/developer-tools' + _DOCKER_TAG_VERSION_DEVELOPER_TOOLS: '0.4.6' diff --git a/build/lint.cloudbuild.yaml b/build/lint.cloudbuild.yaml new file mode 100644 index 00000000..7e3559f6 --- /dev/null +++ b/build/lint.cloudbuild.yaml @@ -0,0 +1,24 @@ +# 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. +# 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. + +steps: +- name: 'gcr.io/cloud-foundation-cicd/cft/developer-tools:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + id: 'lint' + args: ['/usr/local/bin/test_lint.sh'] +tags: +- 'ci' +- 'lint' +substitutions: + _DOCKER_IMAGE_DEVELOPER_TOOLS: 'cft/developer-tools' + _DOCKER_TAG_VERSION_DEVELOPER_TOOLS: '0.4.6' diff --git a/cache/darwin/google-cloud-sdk.tar.gz b/cache/darwin/google-cloud-sdk.tar.gz new file mode 100644 index 00000000..8c9828a7 Binary files /dev/null and b/cache/darwin/google-cloud-sdk.tar.gz differ diff --git a/cache/linux/google-cloud-sdk.tar.gz b/cache/linux/google-cloud-sdk.tar.gz new file mode 100644 index 00000000..c5f94c7c Binary files /dev/null and b/cache/linux/google-cloud-sdk.tar.gz differ diff --git a/examples/simple_example/README.md b/examples/simple_example/README.md new file mode 100644 index 00000000..f9e6cad3 --- /dev/null +++ b/examples/simple_example/README.md @@ -0,0 +1,18 @@ +# Simple Example + +This example illustrates how to use the `gcloud` module. + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| project\_id | The ID of the project in which to provision resources. | string | n/a | yes | + + + +To provision this example, run the following from within this directory: +- `terraform init` to get the plugins +- `terraform plan` to see the infrastructure plan +- `terraform apply` to apply the infrastructure build +- `terraform destroy` to destroy the built infrastructure diff --git a/examples/simple_example/main.tf b/examples/simple_example/main.tf new file mode 100644 index 00000000..468fe68c --- /dev/null +++ b/examples/simple_example/main.tf @@ -0,0 +1,29 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +provider "google" { + version = "~> 2.0" +} + +module "cli" { + source = "../.." + + platform = "linux" + additional_components = ["kubectl", "beta"] + + create_cmd_body = "services enable youtube.googleapis.com --project ${var.project_id}" + destroy_cmd_body = "services disable youtube.googleapis.com --project ${var.project_id}" +} diff --git a/examples/simple_example/outputs.tf b/examples/simple_example/outputs.tf new file mode 100644 index 00000000..cfccff84 --- /dev/null +++ b/examples/simple_example/outputs.tf @@ -0,0 +1,15 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/examples/simple_example/variables.tf b/examples/simple_example/variables.tf new file mode 100644 index 00000000..c1a5c773 --- /dev/null +++ b/examples/simple_example/variables.tf @@ -0,0 +1,20 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "project_id" { + description = "The ID of the project in which to provision resources." + type = string +} diff --git a/examples/simple_example/versions.tf b/examples/simple_example/versions.tf new file mode 100644 index 00000000..832ec1df --- /dev/null +++ b/examples/simple_example/versions.tf @@ -0,0 +1,19 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +terraform { + required_version = ">= 0.12" +} diff --git a/kitchen.yml b/kitchen.yml new file mode 100644 index 00000000..43e82623 --- /dev/null +++ b/kitchen.yml @@ -0,0 +1,39 @@ +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +driver: + name: terraform + +provisioner: + name: terraform + +verifier: + name: terraform + +platforms: + - name: default + +suites: + - name: simple_example + driver: + command_timeout: 1800 + root_module_directory: test/fixtures/simple_example/ + verifier: + color: false + systems: + - name: simple_example local + backend: local + controls: + - gcloud diff --git a/main.tf b/main.tf new file mode 100644 index 00000000..77a802cc --- /dev/null +++ b/main.tf @@ -0,0 +1,129 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +locals { + tmp_credentials_path = "${path.module}/terraform-google-credentials.json" + cache_path = "${path.module}/cache/${var.platform}" + gcloud_tar_path = "${local.cache_path}/google-cloud-sdk.tar.gz" + gcloud_bin_path = "${local.cache_path}/google-cloud-sdk/bin" + components = join(" ", var.additional_components) + + gcloud = "${local.gcloud_bin_path}/gcloud" + gsutil = "${local.gcloud_bin_path}/gsutil" + bq = "${local.gcloud_bin_path}/bq" + kubectl = "${local.gcloud_bin_path}/kubectl" + + create_cmd_bin = "${local.gcloud_bin_path}/${var.create_cmd_entrypoint}" + destroy_cmd_bin = "${local.gcloud_bin_path}/${var.destroy_cmd_entrypoint}" + + wait = length(null_resource.additional_components.*.triggers) + length( + null_resource.gcloud_auth_service_account_key_file.*.triggers, + ) + length(null_resource.gcloud_auth_google_credentials.*.triggers) +} + +resource "null_resource" "decompress" { + count = var.enabled ? 1 : 0 + + triggers = { + always = uuid() + } + + provisioner "local-exec" { + when = create + command = "tar -xzf ${local.gcloud_tar_path} -C ${local.cache_path}" + } +} + +resource "null_resource" "upgrade" { + count = var.enabled ? 1 : 0 + + depends_on = [null_resource.decompress] + + triggers = { + always = uuid() + } + + provisioner "local-exec" { + when = create + command = "${local.gcloud} components update --quiet" + } +} + +resource "null_resource" "additional_components" { + count = var.enabled && length(var.additional_components) > 1 ? 1 : 0 + depends_on = [null_resource.upgrade] + + triggers = { + always = uuid() + } + + provisioner "local-exec" { + when = create + command = "${local.gcloud} components install ${local.components} --quiet" + } +} + +resource "null_resource" "gcloud_auth_service_account_key_file" { + count = var.enabled && length(var.service_account_key_file) > 0 ? 1 : 0 + depends_on = [null_resource.upgrade] + + triggers = { + always = uuid() + } + + provisioner "local-exec" { + when = create + command = "${local.gcloud} auth activate-service-account --key-file ${var.service_account_key_file}" + } +} + +resource "null_resource" "gcloud_auth_google_credentials" { + count = var.enabled && var.use_tf_google_credentials_env_var ? 1 : 0 + depends_on = [null_resource.upgrade] + + triggers = { + always = uuid() + } + + provisioner "local-exec" { + when = create + command = < ${local.tmp_credentials_path} && +${local.gcloud} auth activate-service-account --key-file ${local.tmp_credentials_path} +EOF + } +} + +resource "null_resource" "run_command" { + count = var.enabled ? 1 : 0 + + depends_on = [ + null_resource.decompress, + null_resource.additional_components, + null_resource.gcloud_auth_google_credentials, + null_resource.gcloud_auth_service_account_key_file + ] + + provisioner "local-exec" { + when = create + command = "${local.create_cmd_bin} ${var.create_cmd_body}" + } + + provisioner "local-exec" { + when = destroy + command = "${local.destroy_cmd_bin} ${var.destroy_cmd_body}" + } +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 00000000..8d32da27 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,25 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +output "create_cmd_bin" { + description = "The full bin path & command used on create" + value = local.create_cmd_bin +} + +output "destroy_cmd_bin" { + description = "The full bin path & command used on destroy" + value = local.destroy_cmd_bin +} diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 00000000..d69ba0d4 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +source.sh diff --git a/test/fixtures/simple_example/main.tf b/test/fixtures/simple_example/main.tf new file mode 100644 index 00000000..7a988c14 --- /dev/null +++ b/test/fixtures/simple_example/main.tf @@ -0,0 +1,21 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module "example" { + source = "../../../examples/simple_example" + + project_id = var.project_id +} diff --git a/test/fixtures/simple_example/outputs.tf b/test/fixtures/simple_example/outputs.tf new file mode 100644 index 00000000..9d63e3c4 --- /dev/null +++ b/test/fixtures/simple_example/outputs.tf @@ -0,0 +1,20 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +output "project_id" { + description = "The ID of the project in which resources are provisioned." + value = var.project_id +} diff --git a/test/fixtures/simple_example/variables.tf b/test/fixtures/simple_example/variables.tf new file mode 100644 index 00000000..c1a5c773 --- /dev/null +++ b/test/fixtures/simple_example/variables.tf @@ -0,0 +1,20 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "project_id" { + description = "The ID of the project in which to provision resources." + type = string +} diff --git a/test/fixtures/simple_example/versions.tf b/test/fixtures/simple_example/versions.tf new file mode 100644 index 00000000..832ec1df --- /dev/null +++ b/test/fixtures/simple_example/versions.tf @@ -0,0 +1,19 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +terraform { + required_version = ">= 0.12" +} diff --git a/test/integration/simple_example/controls/gcloud.rb b/test/integration/simple_example/controls/gcloud.rb new file mode 100644 index 00000000..e91895ab --- /dev/null +++ b/test/integration/simple_example/controls/gcloud.rb @@ -0,0 +1,23 @@ +# 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. + +control "gcloud" do + title "gcloud" + + describe command("gcloud --project=#{attribute("project_id")} services list --enabled") do + its(:exit_status) { should eq 0 } + its(:stderr) { should eq "" } + its(:stdout) { should match "youtube.googleapis.com" } + end +end diff --git a/test/integration/simple_example/inspec.yml b/test/integration/simple_example/inspec.yml new file mode 100644 index 00000000..11666610 --- /dev/null +++ b/test/integration/simple_example/inspec.yml @@ -0,0 +1,9 @@ +name: simple_example +depends: + - name: inspec-gcp + git: https://github.com/inspec/inspec-gcp.git + tag: v0.10.0 +attributes: + - name: project_id + required: true + type: string diff --git a/test/setup/.gitignore b/test/setup/.gitignore new file mode 100644 index 00000000..0e515f83 --- /dev/null +++ b/test/setup/.gitignore @@ -0,0 +1,2 @@ +terraform.tfvars +source.sh diff --git a/test/setup/iam.tf b/test/setup/iam.tf new file mode 100644 index 00000000..9255735b --- /dev/null +++ b/test/setup/iam.tf @@ -0,0 +1,39 @@ +/** + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +locals { + int_required_roles = [ + "roles/owner" + ] +} + +resource "google_service_account" "int_test" { + project = module.project.project_id + account_id = "ci-account" + display_name = "ci-account" +} + +resource "google_project_iam_member" "int_test" { + count = length(local.int_required_roles) + + project = module.project.project_id + role = local.int_required_roles[count.index] + member = "serviceAccount:${google_service_account.int_test.email}" +} + +resource "google_service_account_key" "int_test" { + service_account_id = google_service_account.int_test.id +} diff --git a/test/setup/main.tf b/test/setup/main.tf new file mode 100644 index 00000000..42f4a409 --- /dev/null +++ b/test/setup/main.tf @@ -0,0 +1,31 @@ +/** + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module "project" { + source = "terraform-google-modules/project-factory/google" + version = "~> 3.0" + + name = "ci-gcloud" + random_project_id = "true" + org_id = var.org_id + folder_id = var.folder_id + billing_account = var.billing_account + + activate_apis = [ + "cloudresourcemanager.googleapis.com", + "serviceusage.googleapis.com", + ] +} diff --git a/test/setup/make_source.sh b/test/setup/make_source.sh new file mode 100755 index 00000000..ffdc48e1 --- /dev/null +++ b/test/setup/make_source.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +echo "#!/usr/bin/env bash" > ../source.sh + +project_id=$(terraform output project_id) +echo "export TF_VAR_project_id='$project_id'" >> ../source.sh + +sa_json=$(terraform output sa_key) +# shellcheck disable=SC2086 +echo "export SERVICE_ACCOUNT_JSON='$(echo $sa_json | base64 --decode)'" >> ../source.sh diff --git a/test/setup/outputs.tf b/test/setup/outputs.tf new file mode 100644 index 00000000..357bb1e4 --- /dev/null +++ b/test/setup/outputs.tf @@ -0,0 +1,24 @@ +/** + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +output "project_id" { + value = module.project.project_id +} + +output "sa_key" { + value = google_service_account_key.int_test.private_key + sensitive = true +} diff --git a/test/setup/variables.tf b/test/setup/variables.tf new file mode 100644 index 00000000..6d80b898 --- /dev/null +++ b/test/setup/variables.tf @@ -0,0 +1,26 @@ +/** + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +variable "org_id" { + description = "The numeric organization id" +} + +variable "folder_id" { + description = "The folder to deploy in" +} + +variable "billing_account" { + description = "The billing account id associated with the project, e.g. XXXXXX-YYYYYY-ZZZZZZ" +} diff --git a/test/setup/versions.tf b/test/setup/versions.tf new file mode 100644 index 00000000..efbd8ea5 --- /dev/null +++ b/test/setup/versions.tf @@ -0,0 +1,27 @@ +/** + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +terraform { + required_version = ">= 0.12" +} + +provider "google" { + version = "~> 2.13.0" +} + +provider "google-beta" { + version = "~> 2.13.0" +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 00000000..b5dea810 --- /dev/null +++ b/variables.tf @@ -0,0 +1,61 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "enabled" { + description = "Flag to optionally disable usage of this module." + type = bool + default = true +} + +variable "create_cmd_entrypoint" { + description = "On create, the command entrypoint you'd like to use." + default = "gcloud" +} + +variable "create_cmd_body" { + description = "On create, the command body you'd like to run with your entrypoint." + default = "info" +} + +variable "destroy_cmd_entrypoint" { + description = "On destroy, the command entrypoint you'd like to use." + default = "gcloud" +} + +variable "destroy_cmd_body" { + description = "On destroy, the command body you'd like to run with your entrypoint." + default = "info" +} + +variable "additional_components" { + description = "Additional gcloud CLI components to install. Defaults to none. Valid value are components listed in `gcloud components list`" + default = [] +} + +variable "platform" { + description = "Platform CLI will run on. Defaults to linux. Valid values: linux, darwin" + default = "linux" +} + +variable "service_account_key_file" { + description = "Path to service account key file to run `gcloud auth activate-service-account` with. Optional." + default = "" +} + +variable "use_tf_google_credentials_env_var" { + description = "Use GOOGLE_CREDENTIALS environment variable to run `gcloud auth activate-service-account` with. Optional." + default = false +} diff --git a/versions.tf b/versions.tf new file mode 100644 index 00000000..832ec1df --- /dev/null +++ b/versions.tf @@ -0,0 +1,19 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +terraform { + required_version = ">= 0.12" +}