Support context and add configurations factory to workstation cluster module, add FAST project template (#3401)
* add context to workstation-cluster module * context test * workstations project template
This commit is contained in:
committed by
GitHub
parent
9cf67755de
commit
c996285b26
3
fast/project-templates/README.md
Normal file
3
fast/project-templates/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# FAST Project Templates
|
||||
|
||||
Each of the folders contained here is a separate Terraform configuration, that can be used to bring up specific sets of resources. All the configurations include a `project.yaml` file in project factory format, that can be directly used after some light edits to bring up a project with the required prerequisites. The project file can also be used as documentation to create a suitable project via other means, where a project factory is not available.
|
||||
97
fast/project-templates/gce-workstation-cluster/README.md
Normal file
97
fast/project-templates/gce-workstation-cluster/README.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Cloud Workstations Cluster
|
||||
|
||||
This simple setup allows creating and configuring one Cloud Workstation Cluster, and an arbitrary number of workstation configurations and workstations via a dedicated factory.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The [`project.yaml`](./project.yaml) file describes the project-level configuration needed in terms of API activation and IAM bindings.
|
||||
|
||||
If you are deploying this inside a FAST-enabled organization, the file can be lightly edited to match your configuration, and then used directly in the [project factory](../../stages/2-project-factory/).
|
||||
|
||||
This Terraform can of course be deployed using any pre-existing project. In that case use the YAML file to determine the configuration you need to set on the project:
|
||||
|
||||
- enable the APIs listed under `services`
|
||||
- grant the permissions listed under `iam` to the principal running Terraform, either machine (service account) or human
|
||||
|
||||
## VPC-SC Integration
|
||||
|
||||
This example assumes a private cluster is needed, and provisions a PSC Endpoint for private connectivity. For more details on private clusters and VPC-SC see [this documentation page](https://cloud.google.com/workstations/docs/configure-vpc-service-controls-private-clusters).
|
||||
|
||||
An additional egress policy is needed to allow monitoring traffic for the cluster to the tenant project on the Google side. The following snippet can be added to the egress policy factory in the VPC-SC stage, and editied so that project numbers match. It should of course also be enabled in the perimeter definition.
|
||||
|
||||
```yaml
|
||||
from:
|
||||
identities:
|
||||
- serviceAccount:service-1234567890@gcp-sa-workstations.iam.gserviceaccount.com
|
||||
resources:
|
||||
- projects/3456789012
|
||||
to:
|
||||
operations:
|
||||
- service_name: monitoring.googleapis.com
|
||||
method_selectors:
|
||||
- "*"
|
||||
resources:
|
||||
- projects/1234567890
|
||||
```
|
||||
|
||||
## Additional Configuration Steps
|
||||
|
||||
The workstations are accessible via the PSC Endpoint, once a DNS record for the cluster hostname has been configured. The cluster hostname is available from this example's outputs.
|
||||
|
||||
## Variable Configuration
|
||||
|
||||
This is an example of running this stage. Note that the `apt_remote_registries` has a default value that can be used when no IAM is needed at the registry level, and the default set of remotes is fine.
|
||||
|
||||
```hcl
|
||||
project_id = "my-project"
|
||||
location = "europe-west3"
|
||||
network_config = {
|
||||
network = "projects/ldj-prod-net-landing-0/global/networks/prod-landing-0"
|
||||
subnetwork = "projects/ldj-prod-net-landing-0/regions/europe-west8/subnetworks/ws"
|
||||
psc_endpoint_address = "10.0.18.10"
|
||||
}
|
||||
# tftest skip
|
||||
```
|
||||
<!-- BEGIN TFDOC -->
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [network_config](variables.tf#L72) | VPC and subnet for the cluster. | <code title="object({ network = string subnetwork = string psc_endpoint_address = optional(string) })">object({…})</code> | ✓ | |
|
||||
| [project_id](variables.tf#L92) | Project id where the cluster will be created. | <code>string</code> | ✓ | |
|
||||
| [annotations](variables.tf#L17) | Workstation cluster annotations. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [context](variables.tf#L23) | Context-specific interpolations. | <code title="object({ condition_vars = optional(map(map(string)), {}) custom_roles = optional(map(string), {}) iam_principals = optional(map(string), {}) locations = optional(map(string), {}) networks = optional(map(string), {}) project_ids = optional(map(string), {}) subnetworks = optional(map(string), {}) })">object({…})</code> | | <code>{}</code> |
|
||||
| [display_name](variables.tf#L38) | Display name. | <code>string</code> | | <code>null</code> |
|
||||
| [domain](variables.tf#L44) | Domain. | <code>string</code> | | <code>null</code> |
|
||||
| [factories_config](variables.tf#L50) | Path to folder with YAML resource description data files. | <code title="object({ workstation_configs = optional(string, "data/workstation-configs") })">object({…})</code> | | <code>{}</code> |
|
||||
| [id](variables.tf#L59) | Workstation cluster ID. | <code>string</code> | | <code>"ws-cluster-0"</code> |
|
||||
| [labels](variables.tf#L66) | Workstation cluster labels. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [private_cluster_config](variables.tf#L82) | Private cluster config. | <code title="object({ allowed_projects = optional(list(string)) enable_private_endpoint = optional(bool, true) })">object({…})</code> | | <code>{}</code> |
|
||||
| [service_accounts](variables.tf#L98) | Project factory managed service accounts to populate context. | <code title="map(object({ email = string }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [hostname](outputs.tf#L17) | Cluster hostname. | |
|
||||
<!-- END TFDOC -->
|
||||
## Test
|
||||
|
||||
```hcl
|
||||
module "test" {
|
||||
source = "./fabric/fast/project-templates/os-apt-registries"
|
||||
project_id = "my-project"
|
||||
location = "europe-west3"
|
||||
apt_remote_registries = [
|
||||
{ path = "DEBIAN debian/dists/bookworm" },
|
||||
{
|
||||
path = "DEBIAN debian-security/dists/bookworm-security"
|
||||
# grant specific access permissions to this registry
|
||||
writer_principals = [
|
||||
"serviceAccount:vm-default@prod-proj-0.iam.gserviceaccount.com"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
# tftest modules=3 resources=4
|
||||
```
|
||||
@@ -0,0 +1,34 @@
|
||||
# Copyright 2025 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.
|
||||
|
||||
# yaml-language-server: $schema=../../../../../modules/workstation-cluster/schemas/workstation-config.schema.json
|
||||
|
||||
display_name: Default configuration.
|
||||
container:
|
||||
image: us-central1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest
|
||||
gce_instance:
|
||||
disable_public_ip_addresses: true
|
||||
machine_type: e2-medium
|
||||
service_account: $iam_principals:service_accounts/prod-gce-ws-0/ws-default
|
||||
service_account_scopes:
|
||||
- https://www.googleapis.com/auth/cloud-platform
|
||||
persistent_directories:
|
||||
- mount_path: /home
|
||||
gce_pd:
|
||||
size_gb: 10
|
||||
fs_type: ext4
|
||||
disk_type: pd-balanced
|
||||
reclaim_policy: DELETE
|
||||
workstations:
|
||||
test-0: {}
|
||||
50
fast/project-templates/gce-workstation-cluster/main.tf
Normal file
50
fast/project-templates/gce-workstation-cluster/main.tf
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright 2025 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 {
|
||||
location = reverse(split("/", var.network_config.subnetwork))[2]
|
||||
}
|
||||
|
||||
module "cluster" {
|
||||
source = "../../../modules/workstation-cluster"
|
||||
project_id = var.project_id
|
||||
id = var.id
|
||||
location = local.location
|
||||
network_config = var.network_config
|
||||
private_cluster_config = var.private_cluster_config
|
||||
factories_config = var.factories_config
|
||||
context = merge(var.context, {
|
||||
iam_principals = merge(var.context.iam_principals, {
|
||||
for k, v in var.service_accounts : "service_accounts/${k}" => v.email
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module "ws-addresses" {
|
||||
source = "../../../modules/net-address"
|
||||
count = var.network_config.psc_endpoint_address != null ? 1 : 0
|
||||
project_id = var.project_id
|
||||
psc_addresses = {
|
||||
ws-cluster-0 = {
|
||||
address = var.network_config.psc_endpoint_address
|
||||
subnet_self_link = var.network_config.subnetwork
|
||||
region = local.location
|
||||
service_attachment = {
|
||||
psc_service_attachment_link = module.cluster.service_attachment_uri
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
fast/project-templates/gce-workstation-cluster/outputs.tf
Normal file
20
fast/project-templates/gce-workstation-cluster/outputs.tf
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright 2025 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 "hostname" {
|
||||
description = "Cluster hostname."
|
||||
value = module.cluster.cluster_hostname
|
||||
}
|
||||
69
fast/project-templates/gce-workstation-cluster/project.yaml
Normal file
69
fast/project-templates/gce-workstation-cluster/project.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
# Copyright 2025 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.
|
||||
|
||||
# yaml-language-server: $schema=../..//stages/2-project-factory/schemas/project.schema.json
|
||||
|
||||
# TODO: edit and uncomment the following line to create the project in a folder
|
||||
# parent: $folder_ids:shared
|
||||
services:
|
||||
- artifactregistry.googleapis.com
|
||||
- compute.googleapis.com
|
||||
- servicedirectory.googleapis.com
|
||||
- workstations.googleapis.com
|
||||
automation:
|
||||
# TODO: edit the automation project and optionally edit resource names
|
||||
project: $project_ids:iac-0
|
||||
service_accounts:
|
||||
rw:
|
||||
description: Read/write automation service account for workstations.
|
||||
bucket:
|
||||
# this reuses the existing stage state bucket and creates a folder in it
|
||||
name: iac-stage-state
|
||||
create: false
|
||||
managed_folders:
|
||||
gce-workstation-cluster:
|
||||
iam:
|
||||
roles/storage.objectCreator:
|
||||
# TODO: the project id in the service account ref matches this file name
|
||||
- $iam_principals:service_accounts/gce-workstation-cluster/automation/rw
|
||||
roles/storage.objectViewer:
|
||||
- $iam_principals:service_accounts/gce-workstation-cluster/automation/rw
|
||||
iam_by_principals:
|
||||
# TODO: the project id in the service account ref matches this file name
|
||||
$iam_principals:service_accounts/gce-workstation-cluster/automation/rw:
|
||||
- roles/compute.admin
|
||||
- roles/iam.serviceAccountUser
|
||||
- roles/servicedirectory.admin
|
||||
- roles/workstations.admin
|
||||
$iam_principals:service_accounts/gce-workstation-cluster/ws-default:
|
||||
- roles/logging.logWriter
|
||||
- roles/monitoring.metricWriter
|
||||
# org_policies:
|
||||
# compute.restrictSharedVpcSubnetworks:
|
||||
# rules:
|
||||
# - allow:
|
||||
# values:
|
||||
# - ${subnet_self_links["prod-landing/europe-west8/ws"]}
|
||||
service_accounts:
|
||||
ws-default:
|
||||
display_name: Workstations default service account.
|
||||
shared_vpc_service_config:
|
||||
# TODO: edit the host project
|
||||
host_project: $project_ids:prod-landing
|
||||
network_users:
|
||||
- $iam_principals:service_accounts/gce-workstation-cluster/automation/rw
|
||||
service_agent_iam:
|
||||
roles/compute.networkUser:
|
||||
- $service_agents:compute
|
||||
- $service_agents:workstations
|
||||
105
fast/project-templates/gce-workstation-cluster/variables.tf
Normal file
105
fast/project-templates/gce-workstation-cluster/variables.tf
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright 2025 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 "annotations" {
|
||||
description = "Workstation cluster annotations."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "context" {
|
||||
description = "Context-specific interpolations."
|
||||
type = object({
|
||||
condition_vars = optional(map(map(string)), {})
|
||||
custom_roles = optional(map(string), {})
|
||||
iam_principals = optional(map(string), {})
|
||||
locations = optional(map(string), {})
|
||||
networks = optional(map(string), {})
|
||||
project_ids = optional(map(string), {})
|
||||
subnetworks = optional(map(string), {})
|
||||
})
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "display_name" {
|
||||
description = "Display name."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "domain" {
|
||||
description = "Domain."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "factories_config" {
|
||||
description = "Path to folder with YAML resource description data files."
|
||||
type = object({
|
||||
workstation_configs = optional(string, "data/workstation-configs")
|
||||
})
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "id" {
|
||||
description = "Workstation cluster ID."
|
||||
type = string
|
||||
nullable = false
|
||||
default = "ws-cluster-0"
|
||||
}
|
||||
|
||||
variable "labels" {
|
||||
description = "Workstation cluster labels."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "network_config" {
|
||||
description = "VPC and subnet for the cluster."
|
||||
nullable = false
|
||||
type = object({
|
||||
network = string
|
||||
subnetwork = string
|
||||
psc_endpoint_address = optional(string)
|
||||
})
|
||||
}
|
||||
|
||||
variable "private_cluster_config" {
|
||||
description = "Private cluster config."
|
||||
type = object({
|
||||
allowed_projects = optional(list(string))
|
||||
enable_private_endpoint = optional(bool, true)
|
||||
})
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "Project id where the cluster will be created."
|
||||
type = string
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "service_accounts" {
|
||||
description = "Project factory managed service accounts to populate context."
|
||||
type = map(object({
|
||||
email = string
|
||||
}))
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ automation:
|
||||
rw:
|
||||
description: Read/write automation service account for apt registries.
|
||||
bucket:
|
||||
description: Terraform state bucket for apt registries.
|
||||
# this reuses the existing stage state bucket and creates a folder in it
|
||||
name: iac-stage-state
|
||||
create: false
|
||||
@@ -39,7 +38,7 @@ automation:
|
||||
os-apt:
|
||||
iam:
|
||||
roles/storage.objectCreator:
|
||||
# the project id in the service account ref matches this file name
|
||||
# TODO: the project id in the service account ref matches this file name
|
||||
- $iam_principals:service_accounts/os-apt-registries/automation/rw
|
||||
roles/storage.objectViewer:
|
||||
- $iam_principals:service_accounts/os-apt-registries/automation/rw
|
||||
|
||||
@@ -140,18 +140,15 @@ locals {
|
||||
)
|
||||
shared_vpc_service_config = ( # type: object({...})
|
||||
try(v.shared_vpc_service_config, null) != null
|
||||
? merge(
|
||||
{
|
||||
host_project = null
|
||||
iam_bindings_additive = {}
|
||||
network_users = []
|
||||
service_agent_iam = {}
|
||||
service_agent_subnet_iam = {}
|
||||
service_iam_grants = []
|
||||
network_subnet_users = {}
|
||||
},
|
||||
v.shared_vpc_service_config
|
||||
)
|
||||
? {
|
||||
host_project = try(v.shared_vpc_service_config.host_project, null)
|
||||
iam_bindings_additive = try(v.shared_vpc_service_config.iam_bindings_additive, {})
|
||||
network_users = try(v.shared_vpc_service_config.network_users, [])
|
||||
service_agent_iam = try(v.shared_vpc_service_config.service_agent_iam, {})
|
||||
service_agent_subnet_iam = try(v.shared_vpc_service_config.service_agent_subnet_iam, {})
|
||||
service_iam_grants = try(v.shared_vpc_service_config.service_iam_grants, [])
|
||||
network_subnet_users = try(v.shared_vpc_service_config.network_subnet_users, {})
|
||||
}
|
||||
: local.data_defaults.defaults.shared_vpc_service_config
|
||||
)
|
||||
tag_bindings = coalesce( # type: map(string)
|
||||
@@ -267,27 +264,15 @@ locals {
|
||||
)
|
||||
service_encryption_key_ids = {}
|
||||
services = []
|
||||
shared_vpc_service_config = merge(
|
||||
{
|
||||
host_project = null
|
||||
iam_bindings_additive = {}
|
||||
network_users = []
|
||||
service_agent_iam = {}
|
||||
service_agent_subnet_iam = {}
|
||||
service_iam_grants = []
|
||||
network_subnet_users = {}
|
||||
},
|
||||
try(local._data_defaults.defaults.shared_vpc_service_config, {
|
||||
host_project = null
|
||||
iam_bindings_additive = {}
|
||||
network_users = []
|
||||
service_agent_iam = {}
|
||||
service_agent_subnet_iam = {}
|
||||
service_iam_grants = []
|
||||
network_subnet_users = {}
|
||||
}
|
||||
)
|
||||
)
|
||||
shared_vpc_service_config = {
|
||||
host_project = try(local._data_defaults.defaults.shared_vpc_service_config.host_project, null)
|
||||
iam_bindings_additive = try(local._data_defaults.defaults.shared_vpc_service_config.iam_bindings_additive, {})
|
||||
network_users = try(local._data_defaults.defaults.shared_vpc_service_config.network_users, [])
|
||||
service_agent_iam = try(local._data_defaults.defaults.shared_vpc_service_config.service_agent_iam, {})
|
||||
service_agent_subnet_iam = try(local._data_defaults.defaults.shared_vpc_service_config.service_agent_subnet_iam, {})
|
||||
service_iam_grants = try(local._data_defaults.defaults.shared_vpc_service_config.service_iam_grants, [])
|
||||
network_subnet_users = try(local._data_defaults.defaults.shared_vpc_service_config.network_subnet_users, {})
|
||||
}
|
||||
tag_bindings = {}
|
||||
service_accounts = {}
|
||||
universe = null
|
||||
|
||||
@@ -172,16 +172,18 @@ module "workstation-cluster" {
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [id](variables.tf#L35) | Workstation cluster ID. | <code>string</code> | ✓ | |
|
||||
| [location](variables.tf#L46) | Location. | <code>string</code> | ✓ | |
|
||||
| [network_config](variables.tf#L51) | Network configuration. | <code title="object({ network = string subnetwork = string })">object({…})</code> | ✓ | |
|
||||
| [project_id](variables.tf#L69) | Cluster ID. | <code>string</code> | ✓ | |
|
||||
| [workstation_configs](variables.tf#L74) | Workstation configurations. | <code title="map(object({ annotations = optional(map(string)) container = optional(object({ image = optional(string) command = optional(list(string), []) args = optional(list(string), []) working_dir = optional(string) env = optional(map(string), {}) run_as_user = optional(string) })) display_name = optional(string) enable_audit_agent = optional(bool) encryption_key = optional(object({ kms_key = string kms_key_service_account = string })) gce_instance = optional(object({ machine_type = optional(string) service_account = optional(string) service_account_scopes = optional(list(string), []) pool_size = optional(number) boot_disk_size_gb = optional(number) tags = optional(list(string)) disable_public_ip_addresses = optional(bool, false) enable_nested_virtualization = optional(bool, false) shielded_instance_config = optional(object({ enable_secure_boot = optional(bool, false) enable_vtpm = optional(bool, false) enable_integrity_monitoring = optional(bool, false) })) enable_confidential_compute = optional(bool, false) accelerators = optional(list(object({ type = optional(string) count = optional(number) })), []) })) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ role = string members = list(string) })), {}) iam_bindings_additive = optional(map(object({ role = string member = string })), {}) labels = optional(map(string)) max_workstations = optional(number) persistent_directories = optional(list(object({ mount_path = optional(string) gce_pd = optional(object({ size_gb = optional(number) fs_type = optional(string) disk_type = optional(string) source_snapshot = optional(string) reclaim_policy = optional(string) })) })), []) replica_zones = optional(list(string)) timeouts = optional(object({ idle = optional(number) running = optional(number) }), {}) workstations = optional(map(object({ annotations = optional(map(string)) display_name = optional(string) env = optional(map(string)) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ role = string members = list(string) })), {}) iam_bindings_additive = optional(map(object({ role = string member = string })), {}) labels = optional(map(string)) })), {}) }))">map(object({…}))</code> | ✓ | |
|
||||
| [id](variables.tf#L59) | Workstation cluster ID. | <code>string</code> | ✓ | |
|
||||
| [location](variables.tf#L70) | Location. | <code>string</code> | ✓ | |
|
||||
| [network_config](variables.tf#L75) | Network configuration. | <code title="object({ network = string subnetwork = string })">object({…})</code> | ✓ | |
|
||||
| [project_id](variables.tf#L93) | Cluster ID. | <code>string</code> | ✓ | |
|
||||
| [annotations](variables.tf#L17) | Workstation cluster annotations. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [display_name](variables.tf#L23) | Display name. | <code>string</code> | | <code>null</code> |
|
||||
| [domain](variables.tf#L29) | Domain. | <code>string</code> | | <code>null</code> |
|
||||
| [labels](variables.tf#L40) | Workstation cluster labels. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [private_cluster_config](variables.tf#L59) | Private cluster config. | <code title="object({ enable_private_endpoint = optional(bool, false) allowed_projects = optional(list(string)) })">object({…})</code> | | <code>{}</code> |
|
||||
| [context](variables.tf#L23) | Context-specific interpolations. | <code title="object({ condition_vars = optional(map(map(string)), {}) custom_roles = optional(map(string), {}) iam_principals = optional(map(string), {}) locations = optional(map(string), {}) networks = optional(map(string), {}) project_ids = optional(map(string), {}) subnetworks = optional(map(string), {}) })">object({…})</code> | | <code>{}</code> |
|
||||
| [display_name](variables.tf#L38) | Display name. | <code>string</code> | | <code>null</code> |
|
||||
| [domain](variables.tf#L44) | Domain. | <code>string</code> | | <code>null</code> |
|
||||
| [factories_config](variables.tf#L50) | Path to folder with YAML resource description data files. | <code title="object({ workstation_configs = optional(string) })">object({…})</code> | | <code>{}</code> |
|
||||
| [labels](variables.tf#L64) | Workstation cluster labels. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [private_cluster_config](variables.tf#L83) | Private cluster config. | <code title="object({ enable_private_endpoint = optional(bool, false) allowed_projects = optional(list(string)) })">object({…})</code> | | <code>{}</code> |
|
||||
| [workstation_configs](variables.tf#L98) | Workstation configurations. | <code title="map(object({ annotations = optional(map(string)) display_name = optional(string) enable_audit_agent = optional(bool) labels = optional(map(string)) max_workstations = optional(number) replica_zones = optional(list(string)) container = optional(object({ args = optional(list(string), []) command = optional(list(string), []) env = optional(map(string), {}) image = optional(string) run_as_user = optional(string) working_dir = optional(string) })) encryption_key = optional(object({ kms_key = string kms_key_service_account = string })) gce_instance = optional(object({ boot_disk_size_gb = optional(number) disable_public_ip_addresses = optional(bool, false) enable_confidential_compute = optional(bool, false) enable_nested_virtualization = optional(bool, false) machine_type = optional(string) pool_size = optional(number) service_account = optional(string) service_account_scopes = optional(list(string), []) tags = optional(list(string)) accelerators = optional(list(object({ type = optional(string) count = optional(number) })), []) shielded_instance_config = optional(object({ enable_secure_boot = optional(bool, false) enable_vtpm = optional(bool, false) enable_integrity_monitoring = optional(bool, false) })) })) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ role = string members = list(string) })), {}) iam_bindings_additive = optional(map(object({ role = string member = string })), {}) persistent_directories = optional(list(object({ mount_path = optional(string) gce_pd = optional(object({ size_gb = optional(number) fs_type = optional(string) disk_type = optional(string) source_snapshot = optional(string) reclaim_policy = optional(string) })) })), []) timeouts = optional(object({ idle = optional(number) running = optional(number) }), {}) workstations = optional(map(object({ annotations = optional(map(string)) display_name = optional(string) env = optional(map(string)) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ role = string members = list(string) })), {}) iam_bindings_additive = optional(map(object({ role = string member = string })), {}) labels = optional(map(string)) })), {}) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
||||
107
modules/workstation-cluster/factory.tf
Normal file
107
modules/workstation-cluster/factory.tf
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright 2025 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 {
|
||||
_f_files = try(fileset(local._f_paths.workstation_configs, "*.yaml"), [])
|
||||
_f_paths = {
|
||||
for k, v in var.factories_config : k => v == null ? null : pathexpand(v)
|
||||
}
|
||||
_f_raw = {
|
||||
for f in local._f_files : trimsuffix(f, ".yaml") => yamldecode(file(
|
||||
"${local._f_paths.workstation_configs}/${f}"
|
||||
))
|
||||
}
|
||||
f_workstation_configs = {
|
||||
for k, v in local._f_raw : k => {
|
||||
annotations = try(v.annotations, null)
|
||||
display_name = try(v.display_name, null)
|
||||
enable_audit_agent = try(v.enable_audit_agent, null)
|
||||
iam = try(v.iam, {})
|
||||
iam_bindings = try(v.iam_bindings, {})
|
||||
iam_bindings_additive = try(v.iam_bindings_additive, {})
|
||||
labels = try(v.labels, null)
|
||||
max_workstations = try(v.max_workstations, null)
|
||||
replica_zones = try(v.replica_zones, null)
|
||||
timeouts = try(v.timeouts, {})
|
||||
container = (
|
||||
lookup(v, "container", null) == null ? null : {
|
||||
args = try(v.container.args, [])
|
||||
command = try(v.container.command, [])
|
||||
env = try(v.container.env, {})
|
||||
image = try(v.container.image, null)
|
||||
run_as_user = try(v.container.run_as_user, null)
|
||||
working_dir = try(v.container.working_dir, null)
|
||||
}
|
||||
)
|
||||
encryption_key = (
|
||||
lookup(v, "encryption_key", null) == null ? null : {
|
||||
kms_key = try(v.encryption_key.kms_key, null)
|
||||
kms_key_service_account = try(v.encryption_key.kms_key_service_account, null)
|
||||
}
|
||||
)
|
||||
gce_instance = (
|
||||
lookup(v, "gce_instance", null) == null ? null : {
|
||||
boot_disk_size_gb = try(v.gce_instance.boot_disk_size_gb, null)
|
||||
disable_public_ip_addresses = try(v.gce_instance.disable_public_ip_addresses, false)
|
||||
enable_confidential_compute = try(v.gce_instance.enable_confidential_compute, false)
|
||||
enable_nested_virtualization = try(v.gce_instance.enable_nested_virtualization, false)
|
||||
machine_type = try(v.gce_instance.machine_type, null)
|
||||
pool_size = try(v.gce_instance.pool_size, null)
|
||||
service_account = try(v.gce_instance.service_account, null)
|
||||
service_account_scopes = try(v.gce_instance.service_account_scopes, null)
|
||||
tags = try(v.gce_instance.tags, null)
|
||||
accelerators = try(v.gce_instance.accelerators, [])
|
||||
shielded_instance_config = (
|
||||
try(v.gce_instance.shielded_instance_config, null) == null ? null : {
|
||||
enable_secure_boot = try(
|
||||
v.gce_instance.shielded_instance_config.enable_secure_boot, false
|
||||
)
|
||||
enable_vtpm = try(
|
||||
v.gce_instance.shielded_instance_config.enable_vtpm, false
|
||||
)
|
||||
enable_integrity_monitoring = try(
|
||||
v.gce_instance.shielded_instance_config.enable_integrity_monitoring, false
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
persistent_directories = [
|
||||
for vv in try(v.persistent_directories, []) : {
|
||||
mount_path = try(vv.mount_path, null)
|
||||
gce_pd = try(vv.gce_pd, null) == null ? null : {
|
||||
size_gb = try(vv.gce_pd.size_gb, null)
|
||||
fs_type = try(vv.gce_pd.fs_type, null)
|
||||
disk_type = try(vv.gce_pd.disk_type, null)
|
||||
source_snapshot = try(vv.gce_pd.source_snapshot, null)
|
||||
reclaim_policy = try(vv.gce_pd.reclaim_policy, null)
|
||||
}
|
||||
}
|
||||
]
|
||||
workstations = {
|
||||
for kk, vv in try(v.workstations, {}) : kk => {
|
||||
annotations = try(vv.annotations, null)
|
||||
display_name = try(vv.display_name, null)
|
||||
env = try(vv.env, null)
|
||||
labels = try(vv.labels, null)
|
||||
iam = try(vv.iam, {})
|
||||
iam_bindings = try(vv.iam_bindings, {})
|
||||
iam_bindings_additive = try(vv.iam_bindings_additive, {})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,105 +17,143 @@
|
||||
# tfdoc:file:description IAM bindings
|
||||
|
||||
locals {
|
||||
workstation_config_iam = merge([for k1, v1 in var.workstation_configs : { for k2, v2 in v1.iam :
|
||||
"${k1}-${k2}" => {
|
||||
workstation_config_id = k1
|
||||
role = k2
|
||||
members = v2
|
||||
} }]...)
|
||||
workstation_config_iam_bindings = merge([for k1, v1 in var.workstation_configs : { for k2, v2 in v1.iam_bindings :
|
||||
"${k1}-${k2}" => merge(v2, {
|
||||
workstation_config_id = k1
|
||||
}) }]...)
|
||||
workstation_config_iam_bindings_additive = merge([for k1, v1 in var.workstation_configs : { for k2, v2 in v1.iam_bindings_additive :
|
||||
"${k1}-${k2}" => merge(v2, {
|
||||
workstation_config_id = k1
|
||||
}) }]...)
|
||||
workstation_iam = merge(flatten([for k1, v1 in var.workstation_configs : [for k2, v2 in v1.workstations :
|
||||
{ for k3, v3 in v2.iam : "${k1}-${k2}-${k3}" => {
|
||||
workstation_config_id = k1
|
||||
workstation_id = k2
|
||||
role = k3
|
||||
members = v3
|
||||
} }]])...)
|
||||
workstation_iam_bindings = merge(flatten([for k1, v1 in var.workstation_configs : [for k2, v2 in v1.workstations :
|
||||
{ for k3, v3 in v2.iam_bindings : "${k1}-${k2}-${k3}" => merge(v3, {
|
||||
workstation_config_id = k1
|
||||
workstation_id = k2
|
||||
}) }]])...)
|
||||
workstation_iam_bindings_additive = merge(flatten([for k1, v1 in var.workstation_configs : [for k2, v2 in v1.workstations :
|
||||
{ for k3, v3 in v2.iam_bindings_additive : "${k1}-${k2}-${k3}" => merge(v3, {
|
||||
workstation_config_id = k1
|
||||
workstation_id = k2
|
||||
}) }]])...)
|
||||
gwcc = google_workstations_workstation_config.configs
|
||||
gwcw = google_workstations_workstation.workstations
|
||||
workstation_config_iam = merge([
|
||||
for k1, v1 in local.workstation_configs : {
|
||||
for k2, v2 in v1.iam : "${k1}-${k2}" => {
|
||||
workstation_config_id = k1
|
||||
role = k2
|
||||
members = v2
|
||||
}
|
||||
}
|
||||
]...)
|
||||
workstation_config_iam_bindings = merge([
|
||||
for k1, v1 in local.workstation_configs : {
|
||||
for k2, v2 in v1.iam_bindings : "${k1}-${k2}" => merge(v2, {
|
||||
workstation_config_id = k1
|
||||
})
|
||||
}
|
||||
]...)
|
||||
workstation_config_iam_bindings_additive = merge([
|
||||
for k1, v1 in local.workstation_configs : {
|
||||
for k2, v2 in v1.iam_bindings_additive : "${k1}-${k2}" => merge(v2, {
|
||||
workstation_config_id = k1
|
||||
})
|
||||
}
|
||||
]...)
|
||||
workstation_iam = merge(flatten([
|
||||
for k1, v1 in local.workstation_configs : [
|
||||
for k2, v2 in v1.workstations : {
|
||||
for k3, v3 in v2.iam : "${k1}-${k2}-${k3}" => {
|
||||
workstation_config_id = k1
|
||||
workstation_id = k2
|
||||
role = k3
|
||||
members = v3
|
||||
}
|
||||
}
|
||||
]
|
||||
])...)
|
||||
workstation_iam_bindings = merge(flatten([
|
||||
for k1, v1 in local.workstation_configs : [
|
||||
for k2, v2 in v1.workstations : {
|
||||
for k3, v3 in v2.iam_bindings : "${k1}-${k2}-${k3}" => merge(v3, {
|
||||
workstation_config_id = k1
|
||||
workstation_id = k2
|
||||
})
|
||||
}
|
||||
]
|
||||
])...)
|
||||
workstation_iam_bindings_additive = merge(flatten([
|
||||
for k1, v1 in local.workstation_configs : [
|
||||
for k2, v2 in v1.workstations : {
|
||||
for k3, v3 in v2.iam_bindings_additive : "${k1}-${k2}-${k3}" => merge(v3, {
|
||||
workstation_config_id = k1
|
||||
workstation_id = k2
|
||||
})
|
||||
}
|
||||
]
|
||||
])...)
|
||||
}
|
||||
|
||||
resource "google_workstations_workstation_config_iam_binding" "authoritative" {
|
||||
provider = google-beta
|
||||
for_each = local.workstation_config_iam
|
||||
project = google_workstations_workstation_config.configs[each.value.workstation_config_id].project
|
||||
location = google_workstations_workstation_config.configs[each.value.workstation_config_id].location
|
||||
workstation_cluster_id = google_workstations_workstation_config.configs[each.value.workstation_config_id].workstation_cluster_id
|
||||
workstation_config_id = google_workstations_workstation_config.configs[each.value.workstation_config_id].workstation_config_id
|
||||
role = each.value.role
|
||||
members = each.value.members
|
||||
project = local.gwcc[each.value.workstation_config_id].project
|
||||
location = local.gwcc[each.value.workstation_config_id].location
|
||||
workstation_cluster_id = local.gwcc[each.value.workstation_config_id].workstation_cluster_id
|
||||
workstation_config_id = local.gwcc[each.value.workstation_config_id].workstation_config_id
|
||||
role = lookup(local.ctx.custom_roles, each.value.role, each.value.role)
|
||||
members = [
|
||||
for v in each.value.members : lookup(local.ctx.iam_principals, v, v)
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_workstations_workstation_config_iam_binding" "bindings" {
|
||||
provider = google-beta
|
||||
for_each = local.workstation_config_iam_bindings
|
||||
project = google_workstations_workstation_config.configs[each.value.workstation_config_id].project
|
||||
location = google_workstations_workstation_config.configs[each.value.workstation_config_id].location
|
||||
workstation_cluster_id = google_workstations_workstation_config.configs[each.value.workstation_config_id].workstation_cluster_id
|
||||
workstation_config_id = google_workstations_workstation_config.configs[each.value.workstation_config_id].workstation_config_id
|
||||
role = each.value.role
|
||||
members = each.value.members
|
||||
project = local.gwcc[each.value.workstation_config_id].project
|
||||
location = local.gwcc[each.value.workstation_config_id].location
|
||||
workstation_cluster_id = local.gwcc[each.value.workstation_config_id].workstation_cluster_id
|
||||
workstation_config_id = local.gwcc[each.value.workstation_config_id].workstation_config_id
|
||||
role = lookup(local.ctx.custom_roles, each.value.role, each.value.role)
|
||||
members = [
|
||||
for v in each.value.members : lookup(local.ctx.iam_principals, v, v)
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_workstations_workstation_config_iam_member" "bindings" {
|
||||
provider = google-beta
|
||||
for_each = local.workstation_config_iam_bindings_additive
|
||||
project = google_workstations_workstation_config.configs[each.value.workstation_config_id].project
|
||||
location = google_workstations_workstation_config.configs[each.value.workstation_config_id].location
|
||||
workstation_cluster_id = google_workstations_workstation_config.configs[each.value.workstation_config_id].workstation_cluster_id
|
||||
workstation_config_id = google_workstations_workstation_config.configs[each.value.workstation_config_id].workstation_config_id
|
||||
role = each.value.role
|
||||
member = each.value.member
|
||||
project = local.gwcc[each.value.workstation_config_id].project
|
||||
location = local.gwcc[each.value.workstation_config_id].location
|
||||
workstation_cluster_id = local.gwcc[each.value.workstation_config_id].workstation_cluster_id
|
||||
workstation_config_id = local.gwcc[each.value.workstation_config_id].workstation_config_id
|
||||
role = lookup(local.ctx.custom_roles, each.value.role, each.value.role)
|
||||
member = lookup(
|
||||
local.ctx.iam_principals, each.value.member, each.value.member
|
||||
)
|
||||
}
|
||||
|
||||
resource "google_workstations_workstation_iam_binding" "authoritative" {
|
||||
provider = google-beta
|
||||
for_each = local.workstation_iam
|
||||
project = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].project
|
||||
location = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].location
|
||||
workstation_cluster_id = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_cluster_id
|
||||
workstation_config_id = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_config_id
|
||||
workstation_id = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_id
|
||||
role = each.value.role
|
||||
members = each.value.members
|
||||
project = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].project
|
||||
location = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].location
|
||||
workstation_cluster_id = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_cluster_id
|
||||
workstation_config_id = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_config_id
|
||||
workstation_id = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_id
|
||||
role = lookup(local.ctx.custom_roles, each.value.role, each.value.role)
|
||||
members = [
|
||||
for v in each.value.members : lookup(local.ctx.iam_principals, v, v)
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_workstations_workstation_iam_binding" "bindings" {
|
||||
provider = google-beta
|
||||
for_each = local.workstation_iam_bindings
|
||||
project = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].project
|
||||
location = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].location
|
||||
workstation_cluster_id = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_cluster_id
|
||||
workstation_config_id = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_config_id
|
||||
workstation_id = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_id
|
||||
role = each.value.role
|
||||
members = each.value.members
|
||||
project = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].project
|
||||
location = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].location
|
||||
workstation_cluster_id = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_cluster_id
|
||||
workstation_config_id = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_config_id
|
||||
workstation_id = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_id
|
||||
role = lookup(local.ctx.custom_roles, each.value.role, each.value.role)
|
||||
members = [
|
||||
for v in each.value.members : lookup(local.ctx.iam_principals, v, v)
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_workstations_workstation_iam_member" "bindings" {
|
||||
provider = google-beta
|
||||
for_each = local.workstation_iam_bindings_additive
|
||||
project = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].project
|
||||
location = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].location
|
||||
workstation_cluster_id = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_cluster_id
|
||||
workstation_config_id = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_config_id
|
||||
workstation_id = google_workstations_workstation.workstations["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_id
|
||||
role = each.value.role
|
||||
member = each.value.member
|
||||
project = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].project
|
||||
location = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].location
|
||||
workstation_cluster_id = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_cluster_id
|
||||
workstation_config_id = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_config_id
|
||||
workstation_id = local.gwcw["${each.value.workstation_config_id}-${each.value.workstation_id}"].workstation_id
|
||||
role = lookup(local.ctx.custom_roles, each.value.role, each.value.role)
|
||||
member = lookup(
|
||||
local.ctx.iam_principals, each.value.member, each.value.member
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,24 +15,43 @@
|
||||
*/
|
||||
|
||||
locals {
|
||||
workstations = merge(flatten([for k1, v1 in var.workstation_configs :
|
||||
{ for k2, v2 in v1.workstations :
|
||||
"${k1}-${k2}" => merge({
|
||||
ctx = {
|
||||
for k, v in var.context : k => {
|
||||
for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv
|
||||
} if k != "condition_vars"
|
||||
}
|
||||
ctx_p = "$"
|
||||
workstation_configs = merge(
|
||||
var.workstation_configs, local.f_workstation_configs
|
||||
)
|
||||
workstations = merge(flatten([
|
||||
for k1, v1 in local.workstation_configs : {
|
||||
for k2, v2 in v1.workstations : "${k1}-${k2}" => merge({
|
||||
workstation_config_id = k1
|
||||
workstation_id = k2
|
||||
}, v2) }])...)
|
||||
}, v2)
|
||||
}
|
||||
])...)
|
||||
}
|
||||
|
||||
resource "google_workstations_workstation_cluster" "cluster" {
|
||||
provider = google-beta
|
||||
workstation_cluster_id = var.id
|
||||
project = var.project_id
|
||||
display_name = var.display_name
|
||||
network = var.network_config.network
|
||||
subnetwork = var.network_config.subnetwork
|
||||
location = var.location
|
||||
annotations = var.annotations
|
||||
labels = var.labels
|
||||
project = lookup(
|
||||
local.ctx.project_ids, var.project_id, var.project_id
|
||||
)
|
||||
display_name = var.display_name
|
||||
location = lookup(
|
||||
local.ctx.locations, var.location, var.location
|
||||
)
|
||||
network = lookup(
|
||||
local.ctx.networks, var.network_config.network, var.network_config.network
|
||||
)
|
||||
subnetwork = lookup(
|
||||
local.ctx.subnetworks, var.network_config.subnetwork, var.network_config.subnetwork
|
||||
)
|
||||
annotations = var.annotations
|
||||
labels = var.labels
|
||||
dynamic "private_cluster_config" {
|
||||
for_each = var.private_cluster_config == null ? [] : [""]
|
||||
content {
|
||||
@@ -49,29 +68,37 @@ resource "google_workstations_workstation_cluster" "cluster" {
|
||||
}
|
||||
|
||||
resource "google_workstations_workstation_config" "configs" {
|
||||
for_each = var.workstation_configs
|
||||
for_each = local.workstation_configs
|
||||
provider = google-beta
|
||||
project = google_workstations_workstation_cluster.cluster.project
|
||||
workstation_config_id = each.key
|
||||
workstation_cluster_id = google_workstations_workstation_cluster.cluster.workstation_cluster_id
|
||||
location = google_workstations_workstation_cluster.cluster.location
|
||||
workstation_cluster_id = google_workstations_workstation_cluster.cluster.workstation_cluster_id
|
||||
workstation_config_id = each.key
|
||||
annotations = each.value.annotations
|
||||
display_name = each.value.display_name
|
||||
labels = each.value.labels
|
||||
max_usable_workstations = each.value.max_workstations
|
||||
replica_zones = each.value.replica_zones
|
||||
idle_timeout = (
|
||||
each.value.timeouts.idle == null ? null : "${each.value.timeouts.idle}s"
|
||||
try(each.value.timeouts.idle, null) == null
|
||||
? null
|
||||
: "${each.value.timeouts.idle}s"
|
||||
)
|
||||
running_timeout = (
|
||||
each.value.timeouts.running == null ? null : "${each.value.timeouts.running}s"
|
||||
try(each.value.timeouts.running, null) == null
|
||||
? null :
|
||||
"${each.value.timeouts.running}s"
|
||||
)
|
||||
replica_zones = each.value.replica_zones
|
||||
annotations = each.value.annotations
|
||||
labels = each.value.labels
|
||||
dynamic "host" {
|
||||
for_each = each.value.gce_instance == null ? [] : [""]
|
||||
content {
|
||||
gce_instance {
|
||||
machine_type = each.value.gce_instance.machine_type
|
||||
service_account = each.value.gce_instance.service_account
|
||||
machine_type = each.value.gce_instance.machine_type
|
||||
service_account = each.value.gce_instance.service_account == null ? null : lookup(
|
||||
local.ctx.iam_principals,
|
||||
each.value.gce_instance.service_account,
|
||||
each.value.gce_instance.service_account
|
||||
)
|
||||
service_account_scopes = each.value.gce_instance.service_account_scopes
|
||||
pool_size = each.value.gce_instance.pool_size
|
||||
boot_disk_size_gb = each.value.gce_instance.boot_disk_size_gb
|
||||
@@ -116,8 +143,16 @@ resource "google_workstations_workstation_config" "configs" {
|
||||
dynamic "encryption_key" {
|
||||
for_each = each.value.encryption_key == null ? [] : [""]
|
||||
content {
|
||||
kms_key = each.value.encryption_key.kms_key
|
||||
kms_key_service_account = each.value.encryption_key.kms_key_service_account
|
||||
kms_key = each.value.encryption_key.kms_key
|
||||
kms_key_service_account = (
|
||||
each.value.encryption_key.kms_key_service_account == null
|
||||
? null
|
||||
: lookup(
|
||||
local.ctx.iam_principals,
|
||||
each.value.encryption_key.kms_key_service_account,
|
||||
each.value.encryption_key.kms_key_service_account
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
dynamic "persistent_directories" {
|
||||
|
||||
@@ -0,0 +1,409 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Workstation Config",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"annotations": {
|
||||
"type": "object",
|
||||
"description": "Annotations for the object (optional).",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"^[a-z0-9-]+$": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"container": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Container configuration (optional).",
|
||||
"properties": {
|
||||
"args": {
|
||||
"type": "array",
|
||||
"description": "Container arguments (optional, defaults to []).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"command": {
|
||||
"type": "array",
|
||||
"description": "Container command (optional, defaults to []).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"env": {
|
||||
"type": "object",
|
||||
"description": "Container environment variables (optional, defaults to {}).",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": {}
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"description": "Container image URL (optional)."
|
||||
},
|
||||
"run_as_user": {
|
||||
"type": "string",
|
||||
"description": "User to run the container as (optional)."
|
||||
},
|
||||
"working_dir": {
|
||||
"type": "string",
|
||||
"description": "Container working directory (optional)."
|
||||
}
|
||||
}
|
||||
},
|
||||
"display_name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable display name (optional)."
|
||||
},
|
||||
"enable_audit_agent": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable the audit agent (optional)."
|
||||
},
|
||||
"encryption_key": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Customer-managed encryption key configuration (optional).",
|
||||
"properties": {
|
||||
"kms_key": {
|
||||
"type": "string",
|
||||
"description": "The KMS key resource name (required)."
|
||||
},
|
||||
"kms_key_service_account": {
|
||||
"type": "string",
|
||||
"description": "The service account to use for the KMS key (required)."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kms_key",
|
||||
"kms_key_service_account"
|
||||
]
|
||||
},
|
||||
"gce_instance": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "GCE instance configuration (optional).",
|
||||
"properties": {
|
||||
"machine_type": {
|
||||
"type": "string",
|
||||
"description": "Machine type (optional)."
|
||||
},
|
||||
"service_account": {
|
||||
"type": "string",
|
||||
"description": "Service account for the GCE instance (optional)."
|
||||
},
|
||||
"service_account_scopes": {
|
||||
"type": "array",
|
||||
"description": "Service account scopes (optional, defaults to []).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"pool_size": {
|
||||
"type": "number",
|
||||
"description": "Size of the GCE instance pool (optional)."
|
||||
},
|
||||
"boot_disk_size_gb": {
|
||||
"type": "number",
|
||||
"description": "Boot disk size in GB (optional)."
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"description": "Network tags (optional).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"disable_public_ip_addresses": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to disable public IP addresses (optional, defaults to false).",
|
||||
"default": false
|
||||
},
|
||||
"enable_nested_virtualization": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable nested virtualization (optional, defaults to false).",
|
||||
"default": false
|
||||
},
|
||||
"shielded_instance_config": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Shielded instance configuration (optional).",
|
||||
"properties": {
|
||||
"enable_secure_boot": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable Secure Boot (optional, defaults to false).",
|
||||
"default": false
|
||||
},
|
||||
"enable_vtpm": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable vTPM (optional, defaults to false).",
|
||||
"default": false
|
||||
},
|
||||
"enable_integrity_monitoring": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable integrity monitoring (optional, defaults to false).",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"enable_confidential_compute": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable Confidential Compute (optional, defaults to false).",
|
||||
"default": false
|
||||
},
|
||||
"accelerators": {
|
||||
"type": "array",
|
||||
"description": "Accelerator configuration (optional, defaults to []).",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Accelerator type (optional)."
|
||||
},
|
||||
"count": {
|
||||
"type": "number",
|
||||
"description": "Number of accelerators (optional)."
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"iam": {
|
||||
"type": "object",
|
||||
"description": "IAM policy per role for the resource (optional, defaults to {}).",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"default": {}
|
||||
},
|
||||
"iam_bindings": {
|
||||
"type": "object",
|
||||
"description": "IAM bindings for the resource (optional, defaults to {}).",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "The role name (required)."
|
||||
},
|
||||
"members": {
|
||||
"type": "array",
|
||||
"description": "List of members (required).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"role",
|
||||
"members"
|
||||
]
|
||||
},
|
||||
"default": {}
|
||||
},
|
||||
"iam_bindings_additive": {
|
||||
"type": "object",
|
||||
"description": "Additive IAM bindings for the resource (optional, defaults to {}).",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "The role name (required)."
|
||||
},
|
||||
"member": {
|
||||
"type": "string",
|
||||
"description": "The member (required)."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"role",
|
||||
"member"
|
||||
]
|
||||
},
|
||||
"default": {}
|
||||
},
|
||||
"labels": {
|
||||
"type": "object",
|
||||
"description": "Labels for the object (optional).",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"max_workstations": {
|
||||
"type": "number",
|
||||
"description": "Maximum number of workstations (optional)."
|
||||
},
|
||||
"persistent_directories": {
|
||||
"type": "array",
|
||||
"description": "Persistent directory configurations (optional, defaults to []).",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"mount_path": {
|
||||
"type": "string",
|
||||
"description": "Mount path for the directory (optional)."
|
||||
},
|
||||
"gce_pd": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "GCE persistent disk configuration (optional).",
|
||||
"properties": {
|
||||
"size_gb": {
|
||||
"type": "number",
|
||||
"description": "Size of the persistent disk in GB (optional)."
|
||||
},
|
||||
"fs_type": {
|
||||
"type": "string",
|
||||
"description": "Filesystem type (optional)."
|
||||
},
|
||||
"disk_type": {
|
||||
"type": "string",
|
||||
"description": "Disk type (optional)."
|
||||
},
|
||||
"source_snapshot": {
|
||||
"type": "string",
|
||||
"description": "Source snapshot (optional)."
|
||||
},
|
||||
"reclaim_policy": {
|
||||
"type": "string",
|
||||
"description": "Reclaim policy (optional)."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"replica_zones": {
|
||||
"type": "array",
|
||||
"description": "Zones for replicas (optional).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"timeouts": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Timeout configuration (optional, defaults to {}).",
|
||||
"properties": {
|
||||
"idle": {
|
||||
"type": "number",
|
||||
"description": "Idle timeout in seconds (optional)."
|
||||
},
|
||||
"running": {
|
||||
"type": "number",
|
||||
"description": "Running timeout in seconds (optional)."
|
||||
}
|
||||
},
|
||||
"default": {}
|
||||
},
|
||||
"workstations": {
|
||||
"type": "object",
|
||||
"description": "Workstation configurations by name (optional, defaults to {}).",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"annotations": {
|
||||
"type": "object",
|
||||
"description": "Annotations for the workstation (optional).",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"display_name": {
|
||||
"type": "string",
|
||||
"description": "Workstation display name (optional)."
|
||||
},
|
||||
"env": {
|
||||
"type": "object",
|
||||
"description": "Environment variables (optional).",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"iam": {
|
||||
"type": "object",
|
||||
"description": "IAM policy per role for the workstation (optional, defaults to {}).",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"default": {}
|
||||
},
|
||||
"iam_bindings": {
|
||||
"type": "object",
|
||||
"description": "IAM bindings for the workstation (optional, defaults to {}).",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "The role name (required)."
|
||||
},
|
||||
"members": {
|
||||
"type": "array",
|
||||
"description": "List of members (required).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"role",
|
||||
"members"
|
||||
]
|
||||
},
|
||||
"default": {}
|
||||
},
|
||||
"iam_bindings_additive": {
|
||||
"type": "object",
|
||||
"description": "Additive IAM bindings for the workstation (optional, defaults to {}).",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "The role name (required)."
|
||||
},
|
||||
"member": {
|
||||
"type": "string",
|
||||
"description": "The member (required)."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"role",
|
||||
"member"
|
||||
]
|
||||
},
|
||||
"default": {}
|
||||
},
|
||||
"labels": {
|
||||
"type": "object",
|
||||
"description": "Labels for the workstation (optional).",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,21 @@ variable "annotations" {
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "context" {
|
||||
description = "Context-specific interpolations."
|
||||
type = object({
|
||||
condition_vars = optional(map(map(string)), {})
|
||||
custom_roles = optional(map(string), {})
|
||||
iam_principals = optional(map(string), {})
|
||||
locations = optional(map(string), {})
|
||||
networks = optional(map(string), {})
|
||||
project_ids = optional(map(string), {})
|
||||
subnetworks = optional(map(string), {})
|
||||
})
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "display_name" {
|
||||
description = "Display name."
|
||||
type = string
|
||||
@@ -32,6 +47,15 @@ variable "domain" {
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "factories_config" {
|
||||
description = "Path to folder with YAML resource description data files."
|
||||
type = object({
|
||||
workstation_configs = optional(string)
|
||||
})
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "id" {
|
||||
description = "Workstation cluster ID."
|
||||
type = string
|
||||
@@ -74,40 +98,43 @@ variable "project_id" {
|
||||
variable "workstation_configs" {
|
||||
description = "Workstation configurations."
|
||||
type = map(object({
|
||||
annotations = optional(map(string))
|
||||
container = optional(object({
|
||||
image = optional(string)
|
||||
command = optional(list(string), [])
|
||||
args = optional(list(string), [])
|
||||
working_dir = optional(string)
|
||||
env = optional(map(string), {})
|
||||
run_as_user = optional(string)
|
||||
}))
|
||||
annotations = optional(map(string))
|
||||
display_name = optional(string)
|
||||
enable_audit_agent = optional(bool)
|
||||
labels = optional(map(string))
|
||||
max_workstations = optional(number)
|
||||
replica_zones = optional(list(string))
|
||||
container = optional(object({
|
||||
args = optional(list(string), [])
|
||||
command = optional(list(string), [])
|
||||
env = optional(map(string), {})
|
||||
image = optional(string)
|
||||
run_as_user = optional(string)
|
||||
working_dir = optional(string)
|
||||
}))
|
||||
encryption_key = optional(object({
|
||||
kms_key = string
|
||||
kms_key_service_account = string
|
||||
}))
|
||||
gce_instance = optional(object({
|
||||
boot_disk_size_gb = optional(number)
|
||||
disable_public_ip_addresses = optional(bool, false)
|
||||
enable_confidential_compute = optional(bool, false)
|
||||
enable_nested_virtualization = optional(bool, false)
|
||||
machine_type = optional(string)
|
||||
pool_size = optional(number)
|
||||
service_account = optional(string)
|
||||
service_account_scopes = optional(list(string), [])
|
||||
pool_size = optional(number)
|
||||
boot_disk_size_gb = optional(number)
|
||||
tags = optional(list(string))
|
||||
disable_public_ip_addresses = optional(bool, false)
|
||||
enable_nested_virtualization = optional(bool, false)
|
||||
accelerators = optional(list(object({
|
||||
type = optional(string)
|
||||
count = optional(number)
|
||||
})), [])
|
||||
shielded_instance_config = optional(object({
|
||||
enable_secure_boot = optional(bool, false)
|
||||
enable_vtpm = optional(bool, false)
|
||||
enable_integrity_monitoring = optional(bool, false)
|
||||
}))
|
||||
enable_confidential_compute = optional(bool, false)
|
||||
accelerators = optional(list(object({
|
||||
type = optional(string)
|
||||
count = optional(number)
|
||||
})), [])
|
||||
}))
|
||||
iam = optional(map(list(string)), {})
|
||||
iam_bindings = optional(map(object({
|
||||
@@ -118,8 +145,6 @@ variable "workstation_configs" {
|
||||
role = string
|
||||
member = string
|
||||
})), {})
|
||||
labels = optional(map(string))
|
||||
max_workstations = optional(number)
|
||||
persistent_directories = optional(list(object({
|
||||
mount_path = optional(string)
|
||||
gce_pd = optional(object({
|
||||
@@ -130,7 +155,6 @@ variable "workstation_configs" {
|
||||
reclaim_policy = optional(string)
|
||||
}))
|
||||
})), [])
|
||||
replica_zones = optional(list(string))
|
||||
timeouts = optional(object({
|
||||
idle = optional(number)
|
||||
running = optional(number)
|
||||
@@ -151,4 +175,6 @@ variable "workstation_configs" {
|
||||
labels = optional(map(string))
|
||||
})), {})
|
||||
}))
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
71
tests/modules/workstation_cluster/context.tfvars
Normal file
71
tests/modules/workstation_cluster/context.tfvars
Normal file
@@ -0,0 +1,71 @@
|
||||
context = {
|
||||
condition_vars = {
|
||||
names = {
|
||||
my-id = "myid"
|
||||
}
|
||||
}
|
||||
custom_roles = {
|
||||
myrole = "organizations/366118655033/roles/myRoleOne"
|
||||
}
|
||||
iam_principals = {
|
||||
myuser = "user:test-user@example.com"
|
||||
myuser2 = "user:test-user2@example.com"
|
||||
}
|
||||
locations = {
|
||||
ew8 = "europe-west8"
|
||||
}
|
||||
networks = {
|
||||
"dev-spoke-0" : "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
|
||||
}
|
||||
subnetworks = {
|
||||
"default" : "projects/foo-dev-net-spoke-0/regions/europe-west8/subnetworks/default"
|
||||
}
|
||||
project_ids = {
|
||||
test = "dev-test-0"
|
||||
}
|
||||
}
|
||||
|
||||
project_id = "$project_ids:test"
|
||||
id = "test-0"
|
||||
location = "$locations:ew8"
|
||||
network_config = {
|
||||
network = "$networks:dev-spoke-0"
|
||||
subnetwork = "$subnetworks:default"
|
||||
}
|
||||
workstation_configs = {
|
||||
my-workstation-config = {
|
||||
workstations = {
|
||||
my-workstation = {
|
||||
labels = {
|
||||
team = "my-team"
|
||||
}
|
||||
iam = {
|
||||
"roles/workstations.user" = ["$iam_principals:myuser"]
|
||||
}
|
||||
}
|
||||
}
|
||||
iam = {
|
||||
"roles/viewer" = ["$iam_principals:myuser2"]
|
||||
}
|
||||
iam_bindings = {
|
||||
workstations-config-viewer = {
|
||||
role = "$custom_roles:myrole"
|
||||
members = ["$iam_principals:myuser"]
|
||||
condition = {
|
||||
title = "limited-access"
|
||||
expression = "resource.name.startsWith('my-')"
|
||||
}
|
||||
}
|
||||
}
|
||||
iam_bindings_additive = {
|
||||
workstations-config-editor = {
|
||||
role = "roles/editor"
|
||||
member = "group:group3@my-org.com"
|
||||
condition = {
|
||||
title = "limited-access"
|
||||
expression = "resource.name.startsWith('$${names.my-id}-')"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
tests/modules/workstation_cluster/context.yaml
Normal file
117
tests/modules/workstation_cluster/context.yaml
Normal file
@@ -0,0 +1,117 @@
|
||||
# Copyright 2025 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.
|
||||
|
||||
values:
|
||||
google_workstations_workstation.workstations["my-workstation-config-my-workstation"]:
|
||||
annotations: null
|
||||
display_name: null
|
||||
effective_labels:
|
||||
goog-terraform-provisioned: 'true'
|
||||
team: my-team
|
||||
env: null
|
||||
labels:
|
||||
team: my-team
|
||||
location: europe-west8
|
||||
project: dev-test-0
|
||||
source_workstation: null
|
||||
terraform_labels:
|
||||
goog-terraform-provisioned: 'true'
|
||||
team: my-team
|
||||
timeouts: null
|
||||
workstation_cluster_id: test-0
|
||||
workstation_config_id: my-workstation-config
|
||||
workstation_id: my-workstation
|
||||
google_workstations_workstation_cluster.cluster:
|
||||
annotations: null
|
||||
display_name: null
|
||||
domain_config: []
|
||||
effective_labels:
|
||||
goog-terraform-provisioned: 'true'
|
||||
labels: null
|
||||
location: europe-west8
|
||||
network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
|
||||
private_cluster_config:
|
||||
- enable_private_endpoint: false
|
||||
project: dev-test-0
|
||||
subnetwork: projects/foo-dev-net-spoke-0/regions/europe-west8/subnetworks/default
|
||||
tags: null
|
||||
terraform_labels:
|
||||
goog-terraform-provisioned: 'true'
|
||||
timeouts: null
|
||||
workstation_cluster_id: test-0
|
||||
google_workstations_workstation_config.configs["my-workstation-config"]:
|
||||
annotations: null
|
||||
disable_tcp_connections: null
|
||||
display_name: null
|
||||
effective_labels:
|
||||
goog-terraform-provisioned: 'true'
|
||||
enable_audit_agent: null
|
||||
encryption_key: []
|
||||
idle_timeout: 1200s
|
||||
labels: null
|
||||
location: europe-west8
|
||||
project: dev-test-0
|
||||
readiness_checks: []
|
||||
running_timeout: 43200s
|
||||
terraform_labels:
|
||||
goog-terraform-provisioned: 'true'
|
||||
timeouts: null
|
||||
workstation_cluster_id: test-0
|
||||
workstation_config_id: my-workstation-config
|
||||
google_workstations_workstation_config_iam_binding.authoritative["my-workstation-config-roles/viewer"]:
|
||||
condition: []
|
||||
location: europe-west8
|
||||
members:
|
||||
- user:test-user2@example.com
|
||||
project: dev-test-0
|
||||
role: roles/viewer
|
||||
workstation_cluster_id: test-0
|
||||
workstation_config_id: my-workstation-config
|
||||
google_workstations_workstation_config_iam_binding.bindings["my-workstation-config-workstations-config-viewer"]:
|
||||
condition: []
|
||||
location: europe-west8
|
||||
members:
|
||||
- user:test-user@example.com
|
||||
project: dev-test-0
|
||||
role: organizations/366118655033/roles/myRoleOne
|
||||
workstation_cluster_id: test-0
|
||||
workstation_config_id: my-workstation-config
|
||||
google_workstations_workstation_config_iam_member.bindings["my-workstation-config-workstations-config-editor"]:
|
||||
condition: []
|
||||
location: europe-west8
|
||||
member: group:group3@my-org.com
|
||||
project: dev-test-0
|
||||
role: roles/editor
|
||||
workstation_cluster_id: test-0
|
||||
workstation_config_id: my-workstation-config
|
||||
google_workstations_workstation_iam_binding.authoritative["my-workstation-config-my-workstation-roles/workstations.user"]:
|
||||
condition: []
|
||||
location: europe-west8
|
||||
members:
|
||||
- user:test-user@example.com
|
||||
project: dev-test-0
|
||||
role: roles/workstations.user
|
||||
workstation_cluster_id: test-0
|
||||
workstation_config_id: my-workstation-config
|
||||
workstation_id: my-workstation
|
||||
|
||||
counts:
|
||||
google_workstations_workstation: 1
|
||||
google_workstations_workstation_cluster: 1
|
||||
google_workstations_workstation_config: 1
|
||||
google_workstations_workstation_config_iam_binding: 2
|
||||
google_workstations_workstation_config_iam_member: 1
|
||||
google_workstations_workstation_iam_binding: 1
|
||||
modules: 0
|
||||
resources: 7
|
||||
17
tests/modules/workstation_cluster/tftest.yaml
Normal file
17
tests/modules/workstation_cluster/tftest.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2025 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: modules/workstation-cluster
|
||||
tests:
|
||||
context:
|
||||
Reference in New Issue
Block a user