diff --git a/.gitignore b/.gitignore index 9cf6d0e..a04824e 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,5 @@ crash.log credentials.json -examples/automatic_labelling/function_source.zip +examples/automatic-labelling-from-localhost/function_source.zip +examples/automatic-labelling-from-repository/function_source_copy diff --git a/Makefile b/Makefile index 826ad8a..9f96284 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ SHELL := /usr/bin/env bash # Docker build config variables CREDENTIALS_PATH ?= /cft/workdir/credentials.json DOCKER_ORG := gcr.io/cloud-foundation-cicd -DOCKER_TAG_BASE_KITCHEN_TERRAFORM ?= 0.11.10_216.0.0_1.19.1_0.1.10 +DOCKER_TAG_BASE_KITCHEN_TERRAFORM ?= 1.0.0 DOCKER_REPO_BASE_KITCHEN_TERRAFORM := ${DOCKER_ORG}/cft/kitchen-terraform:${DOCKER_TAG_BASE_KITCHEN_TERRAFORM} all: check generate_docs diff --git a/README.md b/README.md index 5b8d075..4abe8f5 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,24 @@ -# terraform-google-event-function +# Event Function -This module configures a system which responds to filtered Stackdriver -Logging events by invoking a Cloud Functions function. +This module configures a system which responds to events by invoking a +Cloud Functions function. -A project-level Stackdriver Logging export uses a provided filter to -identify events of interest and publish them to a dedicated Pub/Sub -topic. A Cloud Functions function subscribes to the topic and uses -provided source code to process each event. The source code is -retrieved from an archive which is created locally and stored in a -Storage bucket. +The root module configures a function sourced from a directory on +localhost to respond to a given event trigger. The source directory is +compressed and uploaded as a Cloud Storage bucket object which will be +leveraged by the function. + +Alternatively, the +[repository-function submodule][repository-function-submodule] +configures a function sourced from a Cloud Source Repositories +repository. ## Usage -The [examples directory](examples) contains tested references of how to -use this module. +The +[automatic-labelling-from-localhost example][automatic-labelling-from-localhost-example] +is a tested reference of how to use the root module with the +[event-project-log-entry submodule][event-project-log-entry-submodule]. [^]: (autogen_docs_start) @@ -21,59 +26,58 @@ use this module. | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| function\_available\_memory\_mb | The amount of memory in megabytes allotted for the function to use. | string | `"256"` | no | -| function\_description | The description of the function. | string | `"Processes log export events provided through a Pub/Sub topic subscription."` | no | -| function\_entry\_point | The name of a method in the function source which will be invoked when the function is executed. | string | n/a | yes | -| function\_environment\_variables | A set of key/value environment variable pairs to assign to the function. | map | `` | no | -| function\_event\_trigger\_failure\_policy\_retry | A toggle to determine if the function should be retried on failure. | string | `"false"` | no | -| function\_labels | A set of key/value label pairs to assign to the function. | map | `` | no | -| function\_runtime | The runtime in which the function will be executed. | string | `"nodejs6"` | no | -| function\_source\_archive\_bucket\_labels | A set of key/value label pairs to assign to the function source archive bucket. | map | `` | no | -| function\_source\_directory | The contents of this directory will be archived and used as the function source. | string | n/a | yes | -| function\_timeout\_s | The amount of time in seconds allotted for the execution of the function. | string | `"60"` | no | -| log\_export\_filter | The filter to apply when exporting logs to the Pub/Sub topic. | string | n/a | yes | +| available\_memory\_mb | The amount of memory in megabytes allotted for the function to use. | string | `"256"` | no | +| description | The description of the function. | string | `"Processes events."` | no | +| entry\_point | The name of a method in the function source which will be invoked when the function is executed. | string | n/a | yes | +| environment\_variables | A set of key/value environment variable pairs to assign to the function. | map | `` | no | +| event\_trigger | A source that fires events in response to a condition in another service. | map | n/a | yes | +| labels | A set of key/value label pairs to assign to any lableable resources. | map | `` | no | | name | The name to apply to any nameable resources. | string | n/a | yes | | project\_id | The ID of the project to which resources will be applied. | string | n/a | yes | | region | The region in which resources will be applied. | string | n/a | yes | +| runtime | The runtime in which the function will be executed. | string | `"nodejs6"` | no | +| source\_directory | The pathname of the directory which contains the function source code. | string | n/a | yes | +| timeout\_s | The amount of time in seconds allotted for the execution of the function. | string | `"60"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| name | The name of the function. | [^]: (autogen_docs_end) ## Requirements -The following requirements must be met in order to invoke this module: - -1. [Software dependencies](#software-dependencies). -2. [IAM roles](#iam-roles). -3. [APIs](#apis). +The following sections describe the requirements which must be met in +order to invoke this module. ### Software Dependencies The following software dependencies must be installed on the system from which this module will be invoked: -- [Terraform][terraform-site] v0.11.x -- [Google Terraform provider][terraform-provider-google-site] v1.20.0 +- [Terraform][terraform-site] v0.11.Z +- [Terraform Provider for Archive][terraform-provider-archive-site] + v1.2.Z +- [Terraform Provider for Google Cloud Platform][terraform-provider-gcp-site] + v2.1.Z ### IAM Roles The Service Account which will be used to invoke this module must have the following IAM roles: -- Cloud Functions Developer -- Compute Viewer -- Logs Configuration Writer -- Pub/Sub Admin -- Service Account User -- Storage Admin +- Cloud Functions Developer: `roles/cloudfunctions.developer` +- Storage Admin: `roles/storage.admin` ### APIs The project against which this module will be invoked must have the following APIs enabled: -- Cloud Functions API -- Cloud Pub/Sub API -- Google Cloud Storage +- Cloud Functions API: `cloudfunctions.googleapis.com` +- Cloud Storage API: `storage-component.googleapis.com` The [Project Factory module][project-factory-module-site] can be used to provision projects with specific APIs activated. @@ -176,7 +180,10 @@ from which the documentation will be generated: Run `make generate_docs` to update the documentation. +[automatic-labelling-from-localhost-example]: examples/automatic-labelling-from-localhost [bundler-site]: https://bundler.io/ +[event-project-log-entry-submodule]: modules/event-project-log-entry +[repository-function-submodule]: modules/repository-function [flake8-site]: https://pypi.org/project/flake8/ [gofmt-site]: https://golang.org/cmd/gofmt/ [hadolint-site]: https://github.com/hadolint/hadolint/ @@ -188,6 +195,6 @@ Run `make generate_docs` to update the documentation. [sample-variable-file]: test/fixtures/shared/terraform.tfvars.sample [shellcheck-site]: https://www.shellcheck.net/ [terraform-docs-site]: https://github.com/segmentio/terraform-docs/releases/ -[terraform-provider-google-site]: https://github.com/terraform-providers/terraform-provider-google/ +[terraform-provider-gcp-site]: https://github.com/terraform-providers/terraform-provider-google/ [terraform-site]: https://www.terraform.io/ [terraform-validate-site]: https://www.terraform.io/docs/commands/validate.html diff --git a/examples/automatic-labelling-from-localhost/README.md b/examples/automatic-labelling-from-localhost/README.md new file mode 100644 index 0000000..7e31e65 --- /dev/null +++ b/examples/automatic-labelling-from-localhost/README.md @@ -0,0 +1,64 @@ +# Automatic Labelling from Localhost + +This example demonstrates how to use the +[root module][root-module] and the +[event-project-log-entry submodule][event-project-log-entry-submodule] +to configure a system +which responds to Compute VM creation events by labelling them with the +principal email address of the account responsible for causing the events. + +## Usage + +To provision this example, populate `terraform.tfvars` with the [required variables][#inputs] and run the following commands within +this directory: + +- `terraform init` to initialize the directory +- `terraform plan` to generate the execution plan +- `terraform apply` to apply the execution plan +- `terraform destroy` to destroy the infrastructure + +[^]: (autogen_docs_start) + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| project\_id | The ID of the project to which resources will be applied. | string | n/a | yes | +| region | The region in which resources will be applied. | string | n/a | yes | +| zone | The zone in which resources will be applied. | string | n/a | yes | + +[^]: (autogen_docs_end) + +## Requirements + +The following sections describe the requirements which must be met in +order to invoke this module. The requirements of the +[root module][root-module-requirements] and the +[event-project-log-entry submodule][event-project-log-entry-submodule-requirements] +must also be met. + +### Software Dependencies + +The following software dependencies must be installed on the system +from which this module will be invoked: + +- [Terraform][terraform-site] v0.11.Z + +### IAM Roles + +The Service Account which will be used to invoke this module must have +the following IAM roles: + +- Compute Instance Admin (v1): `roles/compute.instanceAdmin.v1` + +### APIs + +The project against which this module will be invoked must have the +following APIs enabled: + +- Compute Engine API: `compute.googleapis.com` + +[event-project-log-entry-submodule-requirements]: ../../modules/event-project-log-entry/README.md#requirements +[event-project-log-entry-submodule]: ../../modules/event-project-log-entry +[root-module-requirements]: ../../README.md#requirements +[root-module]: ../.. diff --git a/examples/automatic_labelling/function_source/index.js b/examples/automatic-labelling-from-localhost/function_source/index.js similarity index 100% rename from examples/automatic_labelling/function_source/index.js rename to examples/automatic-labelling-from-localhost/function_source/index.js diff --git a/examples/automatic_labelling/function_source/package.json b/examples/automatic-labelling-from-localhost/function_source/package.json similarity index 100% rename from examples/automatic_labelling/function_source/package.json rename to examples/automatic-labelling-from-localhost/function_source/package.json diff --git a/test/fixtures/automatic_labelling/main.tf b/examples/automatic-labelling-from-localhost/main.tf similarity index 52% rename from test/fixtures/automatic_labelling/main.tf rename to examples/automatic-labelling-from-localhost/main.tf index 06385d8..7d96f27 100644 --- a/test/fixtures/automatic_labelling/main.tf +++ b/examples/automatic-labelling-from-localhost/main.tf @@ -14,12 +14,16 @@ * limitations under the License. */ +terraform { + required_version = "~> 0.11.0" +} + provider "archive" { - version = "~> 1.1" + version = "~> 1.0" } provider "google" { - version = "~> 1.20" + version = "~> 2.1" } provider "random" { @@ -27,27 +31,44 @@ provider "random" { } provider "null" { - version = "~> 2.0" + version = "~> 1.0" } resource "random_pet" "main" { separator = "-" } -module "automatic_labelling" { - source = "../../../examples/automatic_labelling" +module "event_project_log_entry" { + source = "../../modules/event-project-log-entry" + filter = "protoPayload.@type=\"type.googleapis.com/google.cloud.audit.AuditLog\" protoPayload.methodName:insert operation.first=true" + name = "${random_pet.main.id}" project_id = "${var.project_id}" - name = "automatic-labelling-${random_pet.main.id}" - region = "${var.region}" } -resource "null_resource" "wait_for_cloud_functions_function" { +module "localhost_function" { + source = "../.." + + description = "Labels resource with owner information." + entry_point = "labelResource" + + environment_variables = { + LABEL_KEY = "principal-email" + } + + event_trigger = "${module.event_project_log_entry.function_event_trigger}" + name = "${random_pet.main.id}" + project_id = "${var.project_id}" + region = "${var.region}" + source_directory = "${path.module}/function_source" +} + +resource "null_resource" "wait_for_function" { provisioner "local-exec" { command = "sleep 60" } - depends_on = ["module.automatic_labelling"] + depends_on = ["module.localhost_function"] } resource "google_compute_instance" "main" { @@ -58,7 +79,7 @@ resource "google_compute_instance" "main" { } machine_type = "f1-micro" - name = "unlabelled" + name = "unlabelled-${random_pet.main.id}" zone = "${var.zone}" network_interface = { @@ -67,5 +88,5 @@ resource "google_compute_instance" "main" { project = "${var.project_id}" - depends_on = ["null_resource.wait_for_cloud_functions_function"] + depends_on = ["null_resource.wait_for_function"] } diff --git a/examples/automatic-labelling-from-localhost/outputs.tf b/examples/automatic-labelling-from-localhost/outputs.tf new file mode 100644 index 0000000..c92e2d5 --- /dev/null +++ b/examples/automatic-labelling-from-localhost/outputs.tf @@ -0,0 +1,20 @@ +/** + * 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 "compute_instance_name" { + value = "${google_compute_instance.main.name}" + description = "The name of the unlabelled Compute instance." +} diff --git a/test/fixtures/shared/variables.tf b/examples/automatic-labelling-from-localhost/variables.tf similarity index 100% rename from test/fixtures/shared/variables.tf rename to examples/automatic-labelling-from-localhost/variables.tf diff --git a/examples/automatic-labelling-from-repository/README.md b/examples/automatic-labelling-from-repository/README.md new file mode 100644 index 0000000..12b84a3 --- /dev/null +++ b/examples/automatic-labelling-from-repository/README.md @@ -0,0 +1,67 @@ +# Automatic Labelling from Repository + +This example demonstrates how to use the +[repository-function submodule][repository-function-submodule] and the +[event-project-log-entry submodule][event-project-log-entry-submodule] +to configure a system +which responds to Compute VM creation events by labelling them with the +principal email address of the account responsible for causing the events. + +## Usage + +To provision this example, populate `terraform.tfvars` with the [required variables][#inputs] and run the following commands within +this directory: + +- `terraform init` to initialize the directory +- `terraform plan` to generate the execution plan +- `terraform apply` to apply the execution plan +- `terraform destroy` to destroy the infrastructure + +[^]: (autogen_docs_start) + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| project\_id | The ID of the project to which resources will be applied. | string | n/a | yes | +| region | The region in which resources will be applied. | string | n/a | yes | +| zone | The zone in which resources will be applied. | string | n/a | yes | + +[^]: (autogen_docs_end) + +## Requirements + +The following sections describe the requirements which must be met in +order to invoke this module. The +[repository-function submodule requirements][repository-function-submodule-requirements] +and the +[event-project-log-entry submodule requirements][event-project-log-entry-submodule-requirements] +must also be met. + +### Software Dependencies + +The following software dependencies must be installed on the system +from which this module will be invoked: + +- [Terraform][terraform-site] v0.11.Z + +### IAM Roles + +The Service Account which will be used to invoke this module must have +the following IAM roles: + +- Compute Instance Admin (v1): `roles/compute.instanceAdmin.v1` +- Source Repository Admin: `roles/source.admin` + +### APIs + +The project against which this module will be invoked must have the +following APIs enabled: + +- Cloud Source Repositories API: `sourcerepo.googleapis.com` +- Compute Engine API: `compute.googleapis.com` + +[event-project-log-entry-submodule-requirements]: ../../modules/event-project-log-entry/README.md#requirements +[event-project-log-entry-submodule]: ../../modules/event-project-log-entry +[repository-function-submodule-requirements]: ../../modules/repository-function/README.md#requirements +[repository-function-submodule]: ../../modules/repository-function diff --git a/examples/automatic-labelling-from-repository/function_source/index.js b/examples/automatic-labelling-from-repository/function_source/index.js new file mode 100644 index 0000000..cb2b9bf --- /dev/null +++ b/examples/automatic-labelling-from-repository/function_source/index.js @@ -0,0 +1,153 @@ +/** + * Copyright 2019 Google Inc. + * + * 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. + */ + +const { google } = require("googleapis"); +const { auth } = google; +const compute = google.compute("v1"); + +/** + * Authenticates with Google Cloud Platform. + * + * @param {!Function} callback A callback function to signal completion. + */ +authenticate = callback => { + console.log("Authenticating"); + auth.getApplicationDefault((error, authClient) => { + if (error) { + console.error("Error while authenticating"); + + return callback(error); + } + console.log("Authenticated"); + + return callback(null, authClient); + }); +}; + +/** + * Fetches labels from a given Compute Engine instance. + * + * @param {!Object} authClient An authenticated client for GCP. + * @param {!String} instance The identity of the instance on which to store + * label. + * @param {!String} project The identity of the project in which the instance + * exists. + * @param {!String} zone The zone in which the instance exists. + * @param {!Function} callback A callback function to signal completion. + */ +fetchLabels = ({ authClient, instance, project, zone }, callback) => { + console.log("Fetching labels"); + compute.instances.get( + { auth: authClient, instance, project, zone }, (error, response) => { + if (error) { + console.error("Error while fetching labels"); + + return callback(error); + } + + const labels = response.data.labels || {}; + const labelFingerprint = response.data.labelFingerprint; + + console.log("Fetched labels:", labels, labelFingerprint); + + return callback(null, labels, labelFingerprint); + }); +}; + +/** + * Stores labels on a given Compute Engine instance. + * + * @param {!Object} authClient An authenticated client for GCP. + * @param {!String} instance The identity of the instance on which to store + * label. + * @param {!String} labelFingerprint The fingerprint of existing labels stored + * on the instance. + * @param {!Object} labels Labels to be stored on the instance. + * @param {!String} project The identity of the project in which the instance + * exists. + * @param {!String} zone The zone in which the instance exists. + * @param {!Function} callback A callback function to signal completion. + */ +storeLabels = + ({ authClient, instance, labelFingerprint, labels, project, zone }, + callback) => { + console.log("Storing labels"); + compute.instances.setLabels( + { + auth: authClient, + instance, + project, + resource: { labels: labels, labelFingerprint: labelFingerprint }, zone + }, + error => { + if (error) { + console.error("Error while storing labels"); + + return callback(error); + } + console.log("Stored labels:", labels); + + return callback(null); + }); + }; + +/** + * Triggered from a message on a Cloud Pub/Sub topic. + * + * @param {!Object} event Event payload and metadata. + * @param {!Function} callback Callback function to signal completion. + */ +exports.labelResource = (event, callback) => { + const eventData = + JSON.parse(Buffer.from(event.data.data, "base64").toString()); + + console.log("Received event"); + console.log(eventData); + authenticate((error, authClient) => { + if (error) { + return callback(error); + } + + const instance = eventData.resource.labels.instance_id; + const project = eventData.resource.labels.project_id; + const zone = eventData.resource.labels.zone; + + fetchLabels( + { authClient, instance, project, zone }, + (error, labels, labelFingerprint) => { + if (error) { + return callback(error); + } + + const labelKey = process.env.LABEL_KEY; + const principalEmail = + eventData.protoPayload.authenticationInfo.principalEmail.split( + "@")[0]; + + storeLabels( + { + authClient, + instance, + labelFingerprint, + labels: + Object.assign(labels, { [labelKey]: principalEmail }), + project, + zone + }, + callback); + }); + }); +}; diff --git a/examples/automatic-labelling-from-repository/function_source/package.json b/examples/automatic-labelling-from-repository/function_source/package.json new file mode 100644 index 0000000..a3edb7d --- /dev/null +++ b/examples/automatic-labelling-from-repository/function_source/package.json @@ -0,0 +1,7 @@ +{ + "name": "label-resource", + "version": "0.0.1", + "dependencies": { + "googleapis": "^36.0" + } +} \ No newline at end of file diff --git a/examples/automatic-labelling-from-repository/main.tf b/examples/automatic-labelling-from-repository/main.tf new file mode 100644 index 0000000..bc4c1be --- /dev/null +++ b/examples/automatic-labelling-from-repository/main.tf @@ -0,0 +1,121 @@ +/** + * 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.11.0" +} + +provider "archive" { + version = "~> 1.0" +} + +provider "google" { + version = "~> 2.1" +} + +provider "random" { + version = "~> 2.0" +} + +provider "null" { + version = "~> 1.0" +} + +resource "random_pet" "main" { + separator = "-" +} + +resource "google_sourcerepo_repository" "main" { + name = "${random_pet.main.id}" + project = "${var.project_id}" +} + +resource "null_resource" "configure_repository" { + triggers { + repository_url = "${google_sourcerepo_repository.main.url}" + } + + provisioner "local-exec" { + command = "${path.module}/scripts/configure_repository.sh" + + environment { + REMOTE_URL = "${google_sourcerepo_repository.main.url}" + REPOSITORY_DIRECTORY = "${path.module}/function_source" + REPOSITORY_COPY_DIRECTORY = "${path.module}/function_source_copy" + } + } +} + +data "null_data_source" "main" { + inputs = { + source_repository_url = "https://source.developers.google.com/projects/${var.project_id}/repos/${random_pet.main.id}/moveable-aliases/master/paths/" + } + + depends_on = ["null_resource.configure_repository"] +} + +module "event_project_log_entry" { + source = "../../modules/event-project-log-entry" + + filter = "protoPayload.@type=\"type.googleapis.com/google.cloud.audit.AuditLog\" protoPayload.methodName:insert operation.first=true" + name = "${random_pet.main.id}" + project_id = "${var.project_id}" +} + +module "repository_function" { + source = "../../modules/repository-function" + + description = "Labels resource with owner information." + entry_point = "labelResource" + + environment_variables = { + LABEL_KEY = "principal-email" + } + + event_trigger = "${module.event_project_log_entry.function_event_trigger}" + name = "${random_pet.main.id}" + project_id = "${var.project_id}" + region = "${var.region}" + source_repository_url = "${data.null_data_source.main.outputs["source_repository_url"]}" +} + +resource "null_resource" "wait_for_function" { + provisioner "local-exec" { + command = "sleep 60" + } + + depends_on = ["module.repository_function"] +} + +resource "google_compute_instance" "main" { + boot_disk = { + initialize_params = { + image = "debian-cloud/debian-9" + } + } + + machine_type = "f1-micro" + name = "unlabelled-${random_pet.main.id}" + zone = "${var.zone}" + + network_interface = { + network = "default" + } + + project = "${var.project_id}" + + depends_on = ["null_resource.wait_for_function"] +} diff --git a/examples/automatic-labelling-from-repository/outputs.tf b/examples/automatic-labelling-from-repository/outputs.tf new file mode 100644 index 0000000..c92e2d5 --- /dev/null +++ b/examples/automatic-labelling-from-repository/outputs.tf @@ -0,0 +1,20 @@ +/** + * 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 "compute_instance_name" { + value = "${google_compute_instance.main.name}" + description = "The name of the unlabelled Compute instance." +} diff --git a/examples/automatic-labelling-from-repository/scripts/configure_repository.sh b/examples/automatic-labelling-from-repository/scripts/configure_repository.sh new file mode 100755 index 0000000..228687c --- /dev/null +++ b/examples/automatic-labelling-from-repository/scripts/configure_repository.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# 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. + +set -e +set -x + +cp -R "$REPOSITORY_DIRECTORY" "$REPOSITORY_COPY_DIRECTORY" +cd "$REPOSITORY_COPY_DIRECTORY" +git init +git config user.name "Terraform" +git config user.email "terraform@example.com" +git config credential.'https://source.developers.google.com'.helper gcloud.sh +git remote add google "$REMOTE_URL" +git add -A +git commit -m "Initial commit" +git push -u google master diff --git a/examples/automatic_labelling/variables.tf b/examples/automatic-labelling-from-repository/variables.tf similarity index 91% rename from examples/automatic_labelling/variables.tf rename to examples/automatic-labelling-from-repository/variables.tf index b3102f9..2e75295 100644 --- a/examples/automatic_labelling/variables.tf +++ b/examples/automatic-labelling-from-repository/variables.tf @@ -14,11 +14,6 @@ * limitations under the License. */ -variable "name" { - type = "string" - description = "The name to apply to any nameable resources." -} - variable "project_id" { type = "string" description = "The ID of the project to which resources will be applied." @@ -28,3 +23,8 @@ variable "region" { type = "string" description = "The region in which resources will be applied." } + +variable "zone" { + type = "string" + description = "The zone in which resources will be applied." +} diff --git a/examples/automatic_labelling/README.md b/examples/automatic_labelling/README.md deleted file mode 100644 index ac9c13d..0000000 --- a/examples/automatic_labelling/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Automatic Labelling - -This example module invokes the [root module][root-module] to configure a system -which responds to Compute VM creation events by labelling them with the -principal email address of the account responsible for causing the events. - -## Usage - -To provision this example, run the following commands 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 - -## Requirements - -The following requirements must be met in order to invoke this module: - -1. [IAM roles](#iam-roles). -1. [APIs](#apis). -1. [Root module requirements][root-module-requirements]. - -### IAM Roles - -The Service Account which will be used to invoke this module requires no additional IAM roles. - -### APIs - -The project against which this module will be invoked requires no additional APIs enabled. - -[^]: (autogen_docs_start) - -## Inputs - -| Name | Description | Type | Default | Required | -|------|-------------|:----:|:-----:|:-----:| -| name | The name to apply to any nameable resources. | string | n/a | yes | -| project\_id | The ID of the project to which resources will be applied. | string | n/a | yes | -| region | The region in which resources will be applied. | string | n/a | yes | - -[^]: (autogen_docs_end) - -[root-module]: ../.. -[root-module-requirements]: ../../README.md#requirements diff --git a/kitchen.yml b/kitchen.yml index 775a603..4822946 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -23,14 +23,17 @@ verifier: name: terraform platforms: - - name: gcp + - name: from-localhost + driver: + root_module_directory: test/fixtures/automatic-labelling-from-localhost + - name: from-repository + driver: + root_module_directory: test/fixtures/automatic-labelling-from-repository suites: - - name: automatic_labelling - driver: - root_module_directory: test/fixtures/automatic_labelling + - name: automatic-labelling verifier: + color: false systems: - - name: automatic_labelling + - name: automatic-labelling backend: gcp - color: false diff --git a/main.tf b/main.tf index f429b34..47ed232 100644 --- a/main.tf +++ b/main.tf @@ -14,71 +14,46 @@ * limitations under the License. */ -resource "google_pubsub_topic" "main" { - name = "${var.name}" - project = "${var.project_id}" -} - -resource "google_logging_project_sink" "main" { - name = "${var.name}" - destination = "pubsub.googleapis.com/${google_pubsub_topic.main.id}" - filter = "${var.log_export_filter}" - project = "${var.project_id}" - unique_writer_identity = true -} - -resource "google_pubsub_topic_iam_member" "main" { - topic = "${google_pubsub_topic.main.name}" - role = "roles/pubsub.publisher" - member = "${google_logging_project_sink.main.writer_identity}" - project = "${var.project_id}" -} - -resource "google_cloudfunctions_function" "main" { - name = "${var.name}" - source_archive_bucket = "${google_storage_bucket.main.name}" - source_archive_object = "${google_storage_bucket_object.main.name}" - description = "${var.function_description}" - available_memory_mb = "${var.function_available_memory_mb}" - timeout = "${var.function_timeout_s}" - entry_point = "${var.function_entry_point}" - - event_trigger { - event_type = "google.pubsub.topic.publish" - resource = "${google_pubsub_topic.main.name}" - - failure_policy { - retry = "${var.function_event_trigger_failure_policy_retry}" - } - } - - labels = "${var.function_labels}" - runtime = "${var.function_runtime}" - environment_variables = "${var.function_environment_variables}" - project = "${var.project_id}" - region = "${var.region}" -} - data "archive_file" "main" { type = "zip" - output_path = "${pathexpand("${var.function_source_directory}.zip")}" - source_dir = "${pathexpand("${var.function_source_directory}")}" + output_path = "${pathexpand("${var.source_directory}.zip")}" + source_dir = "${pathexpand("${var.source_directory}")}" } resource "google_storage_bucket" "main" { name = "${var.name}" - force_destroy = "true" location = "${var.region}" project = "${var.project_id}" storage_class = "REGIONAL" - labels = "${var.function_source_archive_bucket_labels}" + labels = "${var.labels}" } resource "google_storage_bucket_object" "main" { - name = "event_function.zip" + name = "${basename(data.archive_file.main.output_path)}" bucket = "${google_storage_bucket.main.name}" source = "${data.archive_file.main.output_path}" content_disposition = "attachment" content_encoding = "gzip" content_type = "application/zip" } + +resource "google_cloudfunctions_function" "main" { + name = "${var.name}" + description = "${var.description}" + available_memory_mb = "${var.available_memory_mb}" + timeout = "${var.timeout_s}" + entry_point = "${var.entry_point}" + + event_trigger { + event_type = "${var.event_trigger["event_type"]}" + resource = "${var.event_trigger["resource"]}" + } + + labels = "${var.labels}" + runtime = "${var.runtime}" + environment_variables = "${var.environment_variables}" + source_archive_bucket = "${google_storage_bucket.main.name}" + source_archive_object = "${google_storage_bucket_object.main.name}" + project = "${var.project_id}" + region = "${var.region}" +} diff --git a/modules/event-project-log-entry/README.md b/modules/event-project-log-entry/README.md new file mode 100644 index 0000000..7840584 --- /dev/null +++ b/modules/event-project-log-entry/README.md @@ -0,0 +1,73 @@ +# Event Project Log Entry + +This submodule configures a project-level Stackdriver Logging export to +act as an event which will trigger a Cloud Functions function configured +by the [root module][root-module] or the +[repository-function submodule][repository-function]. + +The export uses a provided filter to identify events of interest and +publishes them to a dedicated Pub/Sub topic. The target function +must be configured to subscribe to the topic in order to process each +export event. + +## Usage + +The +[automatic-labelling-from-localhost example][a7c-l7g-from-l7t-example] +is a tested reference of how to use this submodule with the +[root module]. + +[^]: (autogen_docs_start) + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| filter | The filter to apply when exporting logs. | string | n/a | yes | +| labels | A set of key/value label pairs to assign to any labelable resources. | map | `` | no | +| name | The name to apply to any nameable resources. | string | n/a | yes | +| project\_id | The ID of the project to which resources will be applied. | string | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| function\_event\_trigger | The information used to trigger the function when a log entry is exported to the topic. | + +[^]: (autogen_docs_end) + +## Requirements + +The following sections describe the requirements which must be met in +order to invoke this module. + +### Software Dependencies + +The following software dependencies must be installed on the system +from which this module will be invoked: + +- [Terraform][terraform-site] v0.11.Z +- [Terraform Provider for Google Cloud Platform][t7m-provider-gcp-site] + v2.1.Z + +### IAM Roles + +The Service Account which will be used to invoke this module must have +the following IAM roles: + +- Logs Configuration Writer: `roles/logging.configWriter` +- Pub/Sub Admin: `roles/pubsub.admin` +- Service Account User: `roles/iam.serviceAccountUser` + +### APIs + +The project against which this module will be invoked must have the +following APIs enabled: + +- Cloud Pub/Sub API: `pubsub.googleapis.com` +- Stackdriver Logging API: `logging.googleapis.com` + +[automatic-labelling-example]: ../../examples/automatic_labelling +[repository-function]: ../repository-function +[root-module]: ../.. +[terraform-site]: https://www.terraform.io/ diff --git a/modules/event-project-log-entry/main.tf b/modules/event-project-log-entry/main.tf new file mode 100644 index 0000000..57df7b6 --- /dev/null +++ b/modules/event-project-log-entry/main.tf @@ -0,0 +1,36 @@ +/** + * 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. + */ + +resource "google_pubsub_topic" "main" { + name = "${var.name}" + labels = "${var.labels}" + project = "${var.project_id}" +} + +resource "google_logging_project_sink" "main" { + name = "${var.name}" + destination = "pubsub.googleapis.com/${google_pubsub_topic.main.id}" + filter = "${var.filter}" + project = "${var.project_id}" + unique_writer_identity = true +} + +resource "google_pubsub_topic_iam_member" "main" { + topic = "${google_pubsub_topic.main.name}" + project = "${google_logging_project_sink.main.project}" + member = "${google_logging_project_sink.main.writer_identity}" + role = "roles/pubsub.publisher" +} diff --git a/modules/event-project-log-entry/outputs.tf b/modules/event-project-log-entry/outputs.tf new file mode 100644 index 0000000..966a284 --- /dev/null +++ b/modules/event-project-log-entry/outputs.tf @@ -0,0 +1,20 @@ +/** + * 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 "function_event_trigger" { + description = "The information used to trigger the function when a log entry is exported to the topic." + value = "${map("event_type", "google.pubsub.topic.publish", "resource", "${google_pubsub_topic.main.name}")}" +} diff --git a/modules/event-project-log-entry/variables.tf b/modules/event-project-log-entry/variables.tf new file mode 100644 index 0000000..b1c5cf2 --- /dev/null +++ b/modules/event-project-log-entry/variables.tf @@ -0,0 +1,36 @@ +/** + * 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 "filter" { + type = "string" + description = "The filter to apply when exporting logs." +} + +variable "labels" { + type = "map" + default = {} + description = "A set of key/value label pairs to assign to any labelable resources." +} + +variable "name" { + type = "string" + description = "The name to apply to any nameable resources." +} + +variable "project_id" { + type = "string" + description = "The ID of the project to which resources will be applied." +} diff --git a/modules/repository-function/README.md b/modules/repository-function/README.md new file mode 100644 index 0000000..538491f --- /dev/null +++ b/modules/repository-function/README.md @@ -0,0 +1,73 @@ +# Repository Function + +This submodule configures a function sourced from a Cloud Source +Repositories repository to respond to a given event trigger. + +Alternatively, the [root module][root-module] configures a function +sourced from a directory on localhost. + +## Usage + +The +[automatic-labelling-from-repository example][automatic-labelling-from-repository-example] +is a tested reference of how to use this submodule with the +[event-project-log-entry submodule][event-project-log-entry-submodule]. + +[^]: (autogen_docs_start) + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| available\_memory\_mb | The amount of memory in megabytes allotted for the function to use. | string | `"256"` | no | +| description | The description of the function. | string | `"Processes events."` | no | +| entry\_point | The name of a method in the function source which will be invoked when the function is executed. | string | n/a | yes | +| environment\_variables | A set of key/value environment variable pairs to assign to the function. | map | `` | no | +| event\_trigger | A source that fires events in response to a condition in another service. | map | n/a | yes | +| labels | A set of key/value label pairs to assign to any lableable resources. | map | `` | no | +| name | The name to apply to any nameable resources. | string | n/a | yes | +| project\_id | The ID of the project to which resources will be applied. | string | n/a | yes | +| region | The region in which resources will be applied. | string | n/a | yes | +| runtime | The runtime in which the function will be executed. | string | `"nodejs6"` | no | +| source\_repository\_url | The URL of the repository which contains the function source code. | string | n/a | yes | +| timeout\_s | The amount of time in seconds allotted for the execution of the function. | string | `"60"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| name | The name of the function. | + +[^]: (autogen_docs_end) + +## Requirements + +The following sections describe the requirements which must be met in +order to invoke this module. + +### Software Dependencies + +The following software dependencies must be installed on the system +from which this module will be invoked: + +- [Terraform][terraform-site] v0.11.Z +- [Terraform Provider for Google Cloud Platform][t7m-provider-gcp-site] + v2.1.Z + +### IAM Roles + +The Service Account which will be used to invoke this module must have +the following IAM roles: + +- Cloud Functions Developer: `roles/cloudfunctions.developer` + +### APIs + +The project against which this module will be invoked must have the +following APIs enabled: + +- Cloud Functions API: `cloudfunctions.googleapis.com` + +[automatic-labelling-from-repository-example]: ../../examples/automatic-labelling-from-repository +[event-project-log-entry-submodule]: ../event-project-log-entry +[terraform-site]: https://www.terraform.io/ diff --git a/modules/repository-function/main.tf b/modules/repository-function/main.tf new file mode 100644 index 0000000..75e0b8e --- /dev/null +++ b/modules/repository-function/main.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. + */ + +resource "google_cloudfunctions_function" "main" { + name = "${var.name}" + description = "${var.description}" + available_memory_mb = "${var.available_memory_mb}" + timeout = "${var.timeout_s}" + entry_point = "${var.entry_point}" + + event_trigger { + event_type = "${var.event_trigger["event_type"]}" + resource = "${var.event_trigger["resource"]}" + } + + labels = "${var.labels}" + runtime = "${var.runtime}" + environment_variables = "${var.environment_variables}" + + source_repository { + url = "${var.source_repository_url}" + } + + project = "${var.project_id}" + region = "${var.region}" +} diff --git a/modules/repository-function/outputs.tf b/modules/repository-function/outputs.tf new file mode 100644 index 0000000..a3849d9 --- /dev/null +++ b/modules/repository-function/outputs.tf @@ -0,0 +1,20 @@ +/** + * 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 "name" { + description = "The name of the function." + value = "${google_cloudfunctions_function.main.name}" +} diff --git a/modules/repository-function/variables.tf b/modules/repository-function/variables.tf new file mode 100644 index 0000000..0b20a9d --- /dev/null +++ b/modules/repository-function/variables.tf @@ -0,0 +1,81 @@ +/** + * 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 "available_memory_mb" { + type = "string" + default = "256" + description = "The amount of memory in megabytes allotted for the function to use." +} + +variable "description" { + type = "string" + default = "Processes events." + description = "The description of the function." +} + +variable "entry_point" { + type = "string" + description = "The name of a method in the function source which will be invoked when the function is executed." +} + +variable "environment_variables" { + type = "map" + default = {} + description = "A set of key/value environment variable pairs to assign to the function." +} + +variable "event_trigger" { + type = "map" + description = "A source that fires events in response to a condition in another service." +} + +variable "labels" { + type = "map" + default = {} + description = "A set of key/value label pairs to assign to any lableable resources." +} + +variable "name" { + type = "string" + description = "The name to apply to any nameable resources." +} + +variable "project_id" { + type = "string" + description = "The ID of the project to which resources will be applied." +} + +variable "region" { + type = "string" + description = "The region in which resources will be applied." +} + +variable "runtime" { + type = "string" + default = "nodejs6" + description = "The runtime in which the function will be executed." +} + +variable "source_repository_url" { + type = "string" + description = "The URL of the repository which contains the function source code." +} + +variable "timeout_s" { + type = "string" + default = "60" + description = "The amount of time in seconds allotted for the execution of the function." +} diff --git a/outputs.tf b/outputs.tf index 437465a..a3849d9 100644 --- a/outputs.tf +++ b/outputs.tf @@ -14,3 +14,7 @@ * limitations under the License. */ +output "name" { + description = "The name of the function." + value = "${google_cloudfunctions_function.main.name}" +} diff --git a/examples/automatic_labelling/main.tf b/test/fixtures/automatic-labelling-from-localhost/main.tf similarity index 54% rename from examples/automatic_labelling/main.tf rename to test/fixtures/automatic-labelling-from-localhost/main.tf index 850c798..177d0ca 100644 --- a/examples/automatic_labelling/main.tf +++ b/test/fixtures/automatic-labelling-from-localhost/main.tf @@ -14,30 +14,10 @@ * limitations under the License. */ -module "event_function" { - source = "../../" +module "automatic_labelling_from_localhost" { + source = "../../../examples/automatic-labelling-from-localhost" - function_description = "Labels resource with owner information." - function_entry_point = "labelResource" - - function_environment_variables = { - LABEL_KEY = "principal-email" - } - - function_source_directory = "${path.module}/function_source" - - log_export_filter = "${ - join( - " AND ", - list( - "protoPayload.@type=\"type.googleapis.com/google.cloud.audit.AuditLog\"", - "protoPayload.methodName:insert", - "operation.first=true", - ) - ) - }" - - name = "${var.name}" project_id = "${var.project_id}" region = "${var.region}" + zone = "${var.zone}" } diff --git a/test/fixtures/shared/outputs.tf b/test/fixtures/automatic-labelling-from-localhost/outputs.tf similarity index 83% rename from test/fixtures/shared/outputs.tf rename to test/fixtures/automatic-labelling-from-localhost/outputs.tf index bd9d854..28b53a6 100644 --- a/test/fixtures/shared/outputs.tf +++ b/test/fixtures/automatic-labelling-from-localhost/outputs.tf @@ -14,6 +14,11 @@ * limitations under the License. */ +output "compute_instance_name" { + value = "${module.automatic_labelling_from_localhost.compute_instance_name}" + description = "The name of the unlabelled Compute instance." +} + output "project_id" { value = "${var.project_id}" description = "The ID of the project to which resources are applied." diff --git a/test/fixtures/automatic-labelling-from-localhost/variables.tf b/test/fixtures/automatic-labelling-from-localhost/variables.tf new file mode 100644 index 0000000..2e75295 --- /dev/null +++ b/test/fixtures/automatic-labelling-from-localhost/variables.tf @@ -0,0 +1,30 @@ +/** + * 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 "project_id" { + type = "string" + description = "The ID of the project to which resources will be applied." +} + +variable "region" { + type = "string" + description = "The region in which resources will be applied." +} + +variable "zone" { + type = "string" + description = "The zone in which resources will be applied." +} diff --git a/test/fixtures/automatic-labelling-from-repository/main.tf b/test/fixtures/automatic-labelling-from-repository/main.tf new file mode 100644 index 0000000..324889c --- /dev/null +++ b/test/fixtures/automatic-labelling-from-repository/main.tf @@ -0,0 +1,23 @@ +/** + * 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 "automatic_labelling_from_repository" { + source = "../../../examples/automatic-labelling-from-repository" + + project_id = "${var.project_id}" + region = "${var.region}" + zone = "${var.zone}" +} diff --git a/test/fixtures/automatic-labelling-from-repository/outputs.tf b/test/fixtures/automatic-labelling-from-repository/outputs.tf new file mode 100644 index 0000000..2bf734d --- /dev/null +++ b/test/fixtures/automatic-labelling-from-repository/outputs.tf @@ -0,0 +1,35 @@ +/** + * 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 "compute_instance_name" { + value = "${module.automatic_labelling_from_repository.compute_instance_name}" + description = "The name of the unlabelled Compute instance." +} + +output "project_id" { + value = "${var.project_id}" + description = "The ID of the project to which resources are applied." +} + +output "region" { + value = "${var.region}" + description = "The region in which resources are applied." +} + +output "zone" { + value = "${var.zone}" + description = "The zone in which resources are applied." +} diff --git a/test/fixtures/automatic-labelling-from-repository/variables.tf b/test/fixtures/automatic-labelling-from-repository/variables.tf new file mode 100644 index 0000000..2e75295 --- /dev/null +++ b/test/fixtures/automatic-labelling-from-repository/variables.tf @@ -0,0 +1,30 @@ +/** + * 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 "project_id" { + type = "string" + description = "The ID of the project to which resources will be applied." +} + +variable "region" { + type = "string" + description = "The region in which resources will be applied." +} + +variable "zone" { + type = "string" + description = "The zone in which resources will be applied." +} diff --git a/test/fixtures/automatic_labelling/README.md b/test/fixtures/automatic_labelling/README.md deleted file mode 100644 index 1e8c2fd..0000000 --- a/test/fixtures/automatic_labelling/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Automatic Labelling - -This test module invokes the -[Automatic Labelling example module][example-module] and -then creates an unlabelled Compute VM in order to test the automatic -labelling behaviour. - -[^]: (autogen_docs_start) - -## Inputs - -| Name | Description | Type | Default | Required | -|------|-------------|:----:|:-----:|:-----:| -| project\_id | The ID of the project to which resources will be applied. | string | n/a | yes | -| region | The region in which resources will be applied. | string | n/a | yes | -| zone | The zone in which resources will be applied. | string | n/a | yes | - -## Outputs - -| Name | Description | -|------|-------------| -| project\_id | The ID of the project to which resources are applied. | -| region | The region in which resources are applied. | -| zone | The zone in which resources are applied. | - -[^]: (autogen_docs_end) - -## Requirements - -The following requirements must be met in order to invoke this module: - -1. [IAM roles](#iam-roles). -1. [APIs](#apis). -1. [Example module requirements][example-module-requirements]. - -### IAM Roles - -The Service Account which will be used to invoke this module must have the -following IAM roles: - -- Compute Instance Admin - -### APIs - -The project against which this module will be invoked must have the following APIs enabled: - -- Compute Engine API - -The [Project Factory module][project-factory-module] can be used to provision projects with specific APIs activated. - -[example-module]: ../../../examples/automatic_labelling -[example-module-requirements]: ../../../examples/automatic_labelling/README.md#Requirements -[project-factory-module]: https://github.com/terraform-google-modules/terraform-google-project-factory diff --git a/test/fixtures/automatic_labelling/outputs.tf b/test/fixtures/automatic_labelling/outputs.tf deleted file mode 120000 index 726bdc7..0000000 --- a/test/fixtures/automatic_labelling/outputs.tf +++ /dev/null @@ -1 +0,0 @@ -../shared/outputs.tf \ No newline at end of file diff --git a/test/fixtures/automatic_labelling/variables.tf b/test/fixtures/automatic_labelling/variables.tf deleted file mode 120000 index c113c00..0000000 --- a/test/fixtures/automatic_labelling/variables.tf +++ /dev/null @@ -1 +0,0 @@ -../shared/variables.tf \ No newline at end of file diff --git a/test/integration/automatic_labelling/controls/automatically_labelled.rb b/test/integration/automatic-labelling/controls/automatically_labelled.rb similarity index 95% rename from test/integration/automatic_labelling/controls/automatically_labelled.rb rename to test/integration/automatic-labelling/controls/automatically_labelled.rb index c021af8..fdba818 100644 --- a/test/integration/automatic_labelling/controls/automatically_labelled.rb +++ b/test/integration/automatic-labelling/controls/automatically_labelled.rb @@ -20,7 +20,7 @@ describe google_compute_instance( project: attribute("project_id"), zone: attribute("zone"), - name: "unlabelled", + name: attribute("compute_instance_name"), ) do let :principal_email do JSON.parse(File.read(ENV.fetch("GOOGLE_APPLICATION_CREDENTIALS"))).fetch("client_email").split("@").first diff --git a/test/integration/automatic_labelling/inspec.yml b/test/integration/automatic-labelling/inspec.yml similarity index 86% rename from test/integration/automatic_labelling/inspec.yml rename to test/integration/automatic-labelling/inspec.yml index 91cdf9b..e27db83 100644 --- a/test/integration/automatic_labelling/inspec.yml +++ b/test/integration/automatic-labelling/inspec.yml @@ -18,8 +18,12 @@ version: 0.1.0 depends: - name: inspec-gcp git: https://github.com/inspec/inspec-gcp.git - version: ~> 0.9.0 + tag: v0.10.0 attributes: + - name: compute_instance_name + type: string + required: true + description: "The name of the unlabelled Compute instance." - name: project_id type: string required: true diff --git a/variables.tf b/variables.tf index 5e4e73f..4c5222f 100644 --- a/variables.tf +++ b/variables.tf @@ -14,80 +14,68 @@ * limitations under the License. */ -variable "function_available_memory_mb" { +variable "available_memory_mb" { type = "string" default = "256" description = "The amount of memory in megabytes allotted for the function to use." } -variable "function_description" { +variable "description" { type = "string" - default = "Processes log export events provided through a Pub/Sub topic subscription." + default = "Processes events." description = "The description of the function." } -variable "function_entry_point" { +variable "entry_point" { type = "string" description = "The name of a method in the function source which will be invoked when the function is executed." } -variable "function_environment_variables" { +variable "environment_variables" { type = "map" default = {} description = "A set of key/value environment variable pairs to assign to the function." } -variable "function_event_trigger_failure_policy_retry" { - type = "string" - default = "false" - description = "A toggle to determine if the function should be retried on failure." -} - -variable "function_labels" { +variable "event_trigger" { type = "map" - default = {} - description = "A set of key/value label pairs to assign to the function." -} - -variable "function_runtime" { - type = "string" - default = "nodejs6" - description = "The runtime in which the function will be executed." + description = "A source that fires events in response to a condition in another service." } -variable "function_source_archive_bucket_labels" { +variable "labels" { type = "map" default = {} - description = "A set of key/value label pairs to assign to the function source archive bucket." + description = "A set of key/value label pairs to assign to any lableable resources." } -variable "function_source_directory" { +variable "name" { type = "string" - description = "The contents of this directory will be archived and used as the function source." + description = "The name to apply to any nameable resources." } -variable "function_timeout_s" { +variable "project_id" { type = "string" - default = "60" - description = "The amount of time in seconds allotted for the execution of the function." + description = "The ID of the project to which resources will be applied." } -variable "log_export_filter" { +variable "region" { type = "string" - description = "The filter to apply when exporting logs to the Pub/Sub topic." + description = "The region in which resources will be applied." } -variable "name" { +variable "runtime" { type = "string" - description = "The name to apply to any nameable resources." + default = "nodejs6" + description = "The runtime in which the function will be executed." } -variable "project_id" { +variable "source_directory" { type = "string" - description = "The ID of the project to which resources will be applied." + description = "The pathname of the directory which contains the function source code." } -variable "region" { +variable "timeout_s" { type = "string" - description = "The region in which resources will be applied." + default = "60" + description = "The amount of time in seconds allotted for the execution of the function." }