Skip to content

Commit 8ab26d4

Browse files
committed
feat: support optional tag binding
1 parent 37cda99 commit 8ab26d4

File tree

16 files changed

+220
-2
lines changed

16 files changed

+220
-2
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ determining that location is as follows:
158158
| sa\_role | A role to give the default Service Account for the project (defaults to none) | `string` | `""` | no |
159159
| shared\_vpc\_subnets | List of subnets fully qualified subnet IDs (ie. projects/$project\_id/regions/$region/subnetworks/$subnet\_id) | `list(string)` | `[]` | no |
160160
| svpc\_host\_project\_id | The ID of the host project which hosts the shared VPC | `string` | `""` | no |
161+
| tag\_binding\_values | Tag values to bind the project to. | `list(string)` | `[]` | no |
161162
| usage\_bucket\_name | Name of a GCS bucket to store GCE usage reports in (optional) | `string` | `""` | no |
162163
| usage\_bucket\_prefix | Prefix in the GCS bucket to store GCE usage reports in (optional) | `string` | `""` | no |
163164
| vpc\_service\_control\_attach\_enabled | Whether the project will be attached to a VPC Service Control Perimeter | `bool` | `false` | no |
@@ -185,6 +186,7 @@ determining that location is as follows:
185186
| service\_account\_id | The id of the default service account |
186187
| service\_account\_name | The fully-qualified name of the default service account |
187188
| service\_account\_unique\_id | The unique id of the default service account |
189+
| tag\_bindings | Tag bindings |
188190

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

examples/tags_project/README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Project with tags
2+
3+
This example illustrates how to create a project with a tag binding.
4+
5+
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
6+
## Inputs
7+
8+
| Name | Description | Type | Default | Required |
9+
|------|-------------|------|---------|:--------:|
10+
| billing\_account | The ID of the billing account to associate this project with | `any` | n/a | yes |
11+
| organization\_id | The organization id for the associated services | `string` | `"684124036889"` | no |
12+
| tag\_value | value | `string` | n/a | yes |
13+
14+
## Outputs
15+
16+
| Name | Description |
17+
|------|-------------|
18+
| project\_id | The ID of the created project |
19+
| project\_num | The number of the created project |
20+
21+
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

examples/tags_project/main.tf

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
module "project-factory" {
18+
source = "terraform-google-modules/project-factory/google"
19+
version = "~> 14.0"
20+
21+
random_project_id = true
22+
name = "simple-tag-project"
23+
org_id = var.organization_id
24+
billing_account = var.billing_account
25+
default_service_account = "deprivilege"
26+
tag_binding_values = [var.tag_value]
27+
}

examples/tags_project/outputs.tf

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
output "project_id" {
18+
value = module.project-factory.project_id
19+
description = "The ID of the created project"
20+
}
21+
22+
output "project_num" {
23+
value = module.project-factory.project_number
24+
description = "The number of the created project"
25+
}
26+

examples/tags_project/variables.tf

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
variable "organization_id" {
18+
description = "The organization id for the associated services"
19+
default = "684124036889"
20+
}
21+
22+
variable "billing_account" {
23+
description = "The ID of the billing account to associate this project with"
24+
}
25+
26+
variable "tag_value" {
27+
description = "value"
28+
type = string
29+
}

main.tf

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ module "project-factory" {
6868
vpc_service_control_perimeter_name = var.vpc_service_control_perimeter_name
6969
vpc_service_control_sleep_duration = var.vpc_service_control_sleep_duration
7070
default_network_tier = var.default_network_tier
71+
tag_binding_values = var.tag_binding_values
7172
}
7273

7374
/******************************************

modules/core_project_factory/main.tf

+6
Original file line numberDiff line numberDiff line change
@@ -371,3 +371,9 @@ resource "google_compute_project_default_network_tier" "default" {
371371
project = google_project.main.number
372372
network_tier = var.default_network_tier
373373
}
374+
375+
resource "google_tags_tag_binding" "bindings" {
376+
for_each = toset(var.tag_binding_values)
377+
parent = "//cloudresourcemanager.googleapis.com/projects/${google_project.main.number}"
378+
tag_value = "tagValues/${each.value}"
379+
}

modules/core_project_factory/outputs.tf

+5
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,8 @@ output "enabled_api_identities" {
9595
description = "Enabled API identities in the project"
9696
value = module.project_services.enabled_api_identities
9797
}
98+
99+
output "tag_bindings" {
100+
description = "Tag bindings"
101+
value = google_tags_tag_binding.bindings
102+
}

modules/core_project_factory/variables.tf

+6
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,9 @@ variable "grant_network_role" {
258258
type = bool
259259
default = true
260260
}
261+
262+
variable "tag_binding_values" {
263+
description = "Tag values to bind the project to."
264+
type = list(string)
265+
default = []
266+
}

modules/core_project_factory/versions.tf

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ terraform {
2020
required_providers {
2121
google = {
2222
source = "hashicorp/google"
23-
version = ">= 3.50, < 6"
23+
version = ">= 3.64, < 6"
2424
}
2525
google-beta = {
2626
source = "hashicorp/google-beta"
27-
version = ">= 3.50, < 6"
27+
version = ">= 3.64, < 6"
2828
}
2929
null = {
3030
source = "hashicorp/null"

outputs.tf

+5
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,8 @@ output "budget_name" {
9898
value = module.budget.name
9999
description = "The name of the budget if created"
100100
}
101+
102+
output "tag_bindings" {
103+
description = "Tag bindings"
104+
value = module.project-factory.tag_bindings
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package tags_project
16+
17+
import (
18+
"fmt"
19+
"testing"
20+
21+
"github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/gcloud"
22+
"github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft"
23+
"github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/utils"
24+
"github.com/stretchr/testify/assert"
25+
)
26+
27+
func TestTagsProject(t *testing.T) {
28+
tagsProjectT := tft.NewTFBlueprintTest(t)
29+
tagsProjectT.DefineVerify(func(assert *assert.Assertions) {
30+
tagsProjectT.DefaultVerify(assert)
31+
32+
projectNum := tagsProjectT.GetStringOutput("project_num")
33+
tagValue := tagsProjectT.GetTFSetupStringOutput("tag_value")
34+
35+
parent := fmt.Sprintf("//cloudresourcemanager.googleapis.com/projects/%s", projectNum)
36+
projBindings := gcloud.Runf(t, "resource-manager tags bindings list --parent=%s", parent).Array()
37+
assert.Len(projBindings, 1, "expected one binding")
38+
39+
binding := utils.GetFirstMatchResult(t, projBindings, "parent", parent)
40+
assert.Equalf(fmt.Sprintf("tagValues/%s", tagValue), binding.Get("tagValue").String(), "expected binding to %s", tagValue)
41+
})
42+
tagsProjectT.Test()
43+
}

test/setup/iam.tf

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ locals {
3737
int_required_org_roles = [
3838
"roles/accesscontextmanager.policyAdmin",
3939
"roles/resourcemanager.organizationViewer",
40+
# CRUD tags.
41+
"roles/resourcemanager.tagAdmin",
42+
# Binding tags to resources.
43+
"roles/resourcemanager.tagUser"
4044
]
4145
}
4246

test/setup/outputs.tf

+4
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,7 @@ output "group_name" {
5858
output "service_account_email" {
5959
value = google_service_account.int_test.email
6060
}
61+
62+
output "tag_value" {
63+
value = google_tags_tag_value.value.name
64+
}

test/setup/tags.tf

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
resource "random_string" "key_suffix" {
18+
length = 7
19+
special = false
20+
upper = false
21+
}
22+
23+
resource "google_tags_tag_key" "key" {
24+
parent = "organizations/${var.org_id}"
25+
short_name = "pf-key-${random_string.key_suffix.result}"
26+
description = "Sample tag key"
27+
}
28+
29+
resource "google_tags_tag_value" "value" {
30+
parent = "tagKeys/${google_tags_tag_key.key.name}"
31+
short_name = "sample-val"
32+
description = "Sample val"
33+
}

variables.tf

+6
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,9 @@ variable "language_tag" {
347347
type = string
348348
default = "en-US"
349349
}
350+
351+
variable "tag_binding_values" {
352+
description = "Tag values to bind the project to."
353+
type = list(string)
354+
default = []
355+
}

0 commit comments

Comments
 (0)