Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,9 @@ crash.log

credentials.json

examples/automatic-labelling-folder/function_source.zip
examples/automatic-labelling-from-localhost/function_source.zip
examples/automatic-labelling-from-repository/function_source_copy

node_modules
yarn.lock
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,4 @@ following APIs enabled:
- 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.
provision projects with specific APIs activated.
3 changes: 0 additions & 3 deletions build/int.cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ steps:
- 'TF_VAR_org_id=$_ORG_ID'
- 'TF_VAR_folder_id=$_FOLDER_ID'
- 'TF_VAR_billing_account=$_BILLING_ACCOUNT'
- id: echo
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cat test/source.sh']
- 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']
Expand Down
69 changes: 69 additions & 0 deletions examples/automatic-labelling-folder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Automatic Labelling for folder projects

This example demonstrates how to use the
[root module][root-module] and the
[event-folder-log-entry submodule][event-folder-log-entry-submodule]
to configure a system
which responds to project creation events by labelling them with test label.

## 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

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|:----:|:-----:|:-----:|
| folder\_id | The ID of the folder to look for changes. | 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 |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

## 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-folder-log-entry submodule][event-folder-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.12.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`

- Default AppSpot user: `roles/owner`
- Your user: `roles/resourcemanager.projectCreator`

### 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`

[event-folder-log-entry-submodule-requirements]: ../../modules/event-folder-log-entry/README.md#requirements
[event-folder-log-entry-submodule]: ../../modules/event-folder-log-entry
[root-module-requirements]: ../../README.md#requirements
[root-module]: ../..
[terraform-site]: https://terraform.io/
139 changes: 139 additions & 0 deletions examples/automatic-labelling-folder/function_source/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* 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 crm = google.cloudresourcemanager("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 fields from a given project.
*
* @param {!Object} authClient An authenticated client for GCP.
* label.
* @param {!String} projectId The identity of the project to fetch fields for.
* @param {!Function} callback A callback function to signal completion.
*/
fetchFields = ({ authClient, projectId }, callback) => {
console.log("Fetching fields for " + projectId);
crm.projects.get(
{ auth: authClient, projectId }, (error, response) => {
if (error) {
console.error("Error while fetching fields");

return callback(error);
}

const fields = response.data || {};

console.log("Fetched labels:", fields);

return callback(null, fields);
});
};

/**
* Stores fields on a given project.
*
* @param {!Object} authClient An authenticated client for GCP.
* @param {!Object} fields Fields to be stored on the project.
* @param {!String} projectId The identity of the project to save fields to.
* @param {!Function} callback A callback function to signal completion.
*/
storeFields =
({ authClient, fields, projectId },
callback) => {
console.log("Storing fields for " + projectId);
crm.projects.update(
{
auth: authClient,
projectId,
resource: fields
},
error => {
if (error) {
console.error("Error while storing fields");

return callback(error);
}
console.log("Stored fields:", fields);

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 = (data, context, callback)=> {
const eventData =
JSON.parse(Buffer.from(data.data, "base64").toString());

console.log("Received event");
console.log(eventData);
authenticate((error, authClient) => {
if (error) {
return callback(error);
}

const projectId = eventData.resource.labels.project_id;

fetchFields(
{ authClient, projectId },
(error, fields, labelFingerprint) => {
if (error) {
return callback(error);
}

const labelKey = process.env.LABEL_KEY;
const labelValue = process.env.LABEL_VALUE;

storeFields(
{
authClient,
fields: {
name: fields.name,
parent: fields.parent,
labels:
Object.assign(fields.labels || {}, { [labelKey]: labelValue })
},
projectId
},
callback);
});
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "label-resource",
"version": "0.0.1",
"dependencies": {
"googleapis": "^36.0"
}
}
107 changes: 107 additions & 0 deletions examples/automatic-labelling-folder/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* 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.0"
}

provider "archive" {
version = "~> 1.0"
}

provider "google" {
version = "~> 2.1"
}

provider "random" {
version = "~> 2.0"
}

provider "null" {
version = "~> 2.1"
}

resource "random_pet" "main" {
length = 2
separator = "-"
}

module "event_folder_log_entry" {
source = "../../modules/event-folder-log-entry"

filter = <<EOF
resource.type="project" AND
protoPayload.serviceName="cloudresourcemanager.googleapis.com" AND
protoPayload.methodName="CreateProject"
EOF
name = random_pet.main.id
project_id = var.project_id
folder_id = var.folder_id
}

module "localhost_function" {
source = "../.."

description = "Labels resource with owner information."
entry_point = "labelResource"

environment_variables = {
FOLDER_ID = var.folder_id
LABEL_KEY = "test"
LABEL_VALUE = "foobar"
}

event_trigger = module.event_folder_log_entry.function_event_trigger
name = random_pet.main.id
project_id = var.project_id
region = var.region
source_directory = "${path.module}/function_source"
runtime = "nodejs8"
}

resource "null_resource" "wait_for_function" {
provisioner "local-exec" {
command = "sleep 60"
}

depends_on = [module.localhost_function]
}

resource "random_pet" "project_id" {
length = 1
separator = "-"
prefix = random_pet.main.id
}

resource "google_project" "test" {
name = random_pet.project_id.id
project_id = random_pet.project_id.id
folder_id = var.folder_id

lifecycle {
ignore_changes = [
labels,
]
}

depends_on = [null_resource.wait_for_function]
}

resource "google_project_iam_member" "test_project_iam" {
project = google_project.test.project_id
role = "roles/owner"
member = "serviceAccount:${var.project_id}@appspot.gserviceaccount.com"
}
30 changes: 30 additions & 0 deletions examples/automatic-labelling-folder/outputs.tf
Original file line number Diff line number Diff line change
@@ -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.
*/

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 "test_project_id" {
value = google_project.test.project_id
description = "The ID of the project to test."
}
Loading