diff --git a/.gitignore b/.gitignore index 12e6978..ae1174b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ crash.log crash.*.log +buildkite-* # Exclude all .tfvars files, which are likely to contain sensitive data, such as # password, private keys, and other secrets. These should not be part of version # control as they are data points which are potentially sensitive and subject diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index efe2327..b718a9c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ default_stages: [commit] repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.83.3 + rev: v1.84.0 hooks: - id: terraform_fmt - id: terraform_validate @@ -22,7 +22,7 @@ repos: args: - --args=provider google -v "~> 4.0" - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer diff --git a/.tflint.hcl b/.tflint.hcl index d820d49..73a1fc9 100644 --- a/.tflint.hcl +++ b/.tflint.hcl @@ -1,6 +1,6 @@ plugin "google" { enabled = true - version = "0.25.0" + version = "0.26.0" source = "github.com/terraform-linters/tflint-ruleset-google" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 348f0b8..5342b21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +## 0.10.0 (Released) +FEATURES: +- Support for shared VPC + - Example `anyscale-v2-vpc-shared` created to demonstrate this. Please make sure to read the README in the example for additional requirements. + - Requires Anyscale CLI v0.5.163 or greater. + - Supports creating a Firewall in the Shared VPC Project if an existing firewall is not provided +- Update VPC Firewall to allow GCP Load Balancer Health Check CIDR ranges. + - This rule is required for Anyscale Services +- Minimal IAM Service Account Roles + - Project/Owner or Project/Editor are no longer required for the Anyscale Service Account. + +BUG FIXES: + +BREAKING CHANGES: +- Updates to output names for Service Accounts. +- Changes to IAM Service Account Terraform names + - This will replace existing IAM Service Accounts if upgrading. + - You will need to create new Anyscale Clouds. + +OTHER: +- TFLint Rules Update +- Cleanup of unused variables +- pre-commit update + ## 0.9.0 (Released) FEATURES: - Support for existing Workload Identify Federation pool and provider diff --git a/README.md b/README.md index 4e42ab4..292b834 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [Terraform] modules to manage cloud infrastructure for Anyscale. This builds the foundational cloud resources needed to run Anyscale in a cloud environment. This module and sub-modules support Google Cloud. -**THIS IS PROVIDED AS A STARTING POINT AND IS CONSIDERED BETA** +**THIS IS PROVIDED AS A STARTING POINT** **USE AT YOUR OWN RISK** @@ -86,7 +86,7 @@ None | Name | Version | |------|---------| | [google](#provider\_google) | 4.84.0 | -| [random](#provider\_random) | 3.5.1 | +| [random](#provider\_random) | 3.6.0 | ## Modules @@ -108,12 +108,14 @@ None | [random_id.common_name](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource | | [google_client_config.current](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/client_config) | data source | | [google_compute_subnetwork.existing_vpc_subnet](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_subnetwork) | data source | +| [google_compute_subnetwork.shared_vpc_subnet](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_subnetwork) | data source | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [allow\_ssh\_from\_google\_ui](#input\_allow\_ssh\_from\_google\_ui) | (Optional) Determines if SSH access is allowed from the Google UI.

ex:
allow_ssh_from_google_ui = true
| `bool` | `true` | no | +| [anyscale\_access\_role\_description](#input\_anyscale\_access\_role\_description) | (Optional) The description of the Anyscale IAM access role.

ex:
anyscale_access_role_description = "Anyscale Cross Account Access"
| `string` | `"Anyscale Cross Account Access Role"` | no | | [anyscale\_bucket\_cors\_rules](#input\_anyscale\_bucket\_cors\_rules) | (Optional) List of CORS rules to configure.

Format is the same as described in provider documentation https://www.terraform.io/docs/providers/google/r/storage_bucket.html#cors except max\_age\_seconds should be a number.

ex:
anyscale_bucket_cors_rules = [
{
origins = ["https://console.anyscale.com"]
methods = ["GET"]
response_headers = ["*"]
max_age_seconds = 3600
}
]
|
set(object({
# Object with keys:
# - origins - (Required) List of values, with wildcards, of the Origin header in the request that an incoming OPTIONS request will be matched against.
# - methods - (Required) Lilst of values, with wildcards, of the Access-Control-Request-Method header in the request that an incoming OPTIONS request will be matched against.
# - response_headers - (Required) List of values, with wildcards, of the Access-Control-Request-Headers header in the request that an incoming OPTIONS request will be matched against.
# - max_age_seconds - (Optional) The value, in seconds, to return in the Access-Control-Max-Age header used in preflight responses.
origins = list(string)
methods = list(string)
response_headers = list(string)
max_age_seconds = number
}))
|
[
{
"max_age_seconds": 3600,
"methods": [
"GET"
],
"origins": [
"https://console.anyscale.com"
],
"response_headers": [
"*"
]
}
]
| no | | [anyscale\_bucket\_lifecycle\_rules](#input\_anyscale\_bucket\_lifecycle\_rules) | (Optional) List of lifecycle rules to configure.

Format is the same as described in provider documentation https://www.terraform.io/docs/providers/google/r/storage_bucket.html#lifecycle_rule except condition.matches\_storage\_class should be a comma delimited string.

ex:
anyscale_bucket_lifecycle_rules = [
{
action = {
type = "Delete"
storage_class = "MULTI_REGIONAL"
}
condition = {
age = 30
}
}
]
|
set(object({
# Object with keys:
# - type - The type of the action of this Lifecycle Rule. Supported values: Delete and SetStorageClass.
# - storage_class - (Required if action type is SetStorageClass) The target Storage Class of objects affected by this Lifecycle Rule.
action = map(string)

# Object with keys:
# - age - (Optional) Minimum age of an object in days to satisfy this condition.
# - created_before - (Optional) Creation date of an object in RFC 3339 (e.g. 2017-06-13) to satisfy this condition.
# - with_state - (Optional) Match to live and/or archived objects. Supported values include: "LIVE", "ARCHIVED", "ANY".
# - matches_storage_class - (Optional) Comma delimited string for storage class of objects to satisfy this condition. Supported values include: MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, DURABLE_REDUCED_AVAILABILITY.
# - matches_prefix - (Optional) One or more matching name prefixes to satisfy this condition.
# - matches_suffix - (Optional) One or more matching name suffixes to satisfy this condition.
# - num_newer_versions - (Optional) Relevant only for versioned objects. The number of newer versions of an object to satisfy this condition.
# - custom_time_before - (Optional) A date in the RFC 3339 format YYYY-MM-DD. This condition is satisfied when the customTime metadata for the object is set to an earlier date than the date used in this lifecycle condition.
# - days_since_custom_time - (Optional) The number of days from the Custom-Time metadata attribute after which this condition becomes true.
# - days_since_noncurrent_time - (Optional) Relevant only for versioned objects. Number of days elapsed since the noncurrent timestamp of an object.
# - noncurrent_time_before - (Optional) Relevant only for versioned objects. The date in RFC 3339 (e.g. 2017-06-13) when the object became nonconcurrent.
condition = map(string)
}))
| `[]` | no | | [anyscale\_bucket\_location](#input\_anyscale\_bucket\_location) | (Optional) The location of the bucket.

ex:
anyscale_bucket_location = "US"
| `string` | `"US"` | no | @@ -121,9 +123,9 @@ None | [anyscale\_bucket\_prefix](#input\_anyscale\_bucket\_prefix) | (Optional - forces new resource) Cloudstorage bucket name prefix.

Creates a unique bucket name beginning with the specified prefix.
- If `anyscale_bucket_name` is provided, it will override this variable.
- The variable `general_prefix` is a fall-back prefix if this is not provided.
- Default is `null` but is set to `anyscale-` in a local variable.

ex:
anyscale_bucket_prefix = "anyscale-bucket-"
| `string` | `null` | no | | [anyscale\_bucket\_storage\_class](#input\_anyscale\_bucket\_storage\_class) | (Optional) Bucket storage class.

Must be one of: STANDARD, MULTI\_REGIONAL, REGIONAL, NEARLINE, COLDLINE, ARCHIVE

ex:
anyscale_bucket_storage_class = "STANDARD"
| `string` | `"STANDARD"` | no | | [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID.

This is the ID of the Anyscale Cloud. This is not the same as the GCP Project ID. Used in labels.

ex:
anyscale_cloud_id = "cld_1234567890"
| `string` | `null` | no | -| [anyscale\_cluster\_node\_role\_description](#input\_anyscale\_cluster\_node\_role\_description) | (Optional) The description of the IAM role that will be created for Anyscale access.

ex:
anyscale_cluster_node_role_description = "Anyscale Cluster Node"
| `string` | `null` | no | -| [anyscale\_cluster\_node\_role\_name](#input\_anyscale\_cluster\_node\_role\_name) | (Optional - forces new resource) IAM Cluster Node Role Name

The name of the IAM role that will be created for Anyscale cluster nodes.
- If left `null`, will default to anyscale\_cluster\_node\_role\_name\_prefix.
- If provided, overrides the anyscale\_cluster\_node\_role\_name\_prefix variable.
- It needs to be > 4 chars and < 28 chars.

ex:
anyscale_cluster_node_role_name = "anyscale-cluster-node"
| `string` | `null` | no | -| [anyscale\_cluster\_node\_role\_name\_prefix](#input\_anyscale\_cluster\_node\_role\_name\_prefix) | (Optional - forces new resource) IAM Cluster Node Role Name Prefix

Creates a unique IAM role name beginning with the specified prefix.
- If `anyscale_cluster_node_role_name` is provided, it will override this variable.
- The variable `general_prefix` is a fall-back prefix if this is not provided.
- Default is `null` but is set to `anyscale-cluster-` in a local variable.
- It needs to be > 4 chars and < 20 chars.

ex:
anyscale_cluster_node_role_name_prefix = "anyscale-cluster-"
| `string` | `null` | no | +| [anyscale\_cluster\_node\_service\_acct\_description](#input\_anyscale\_cluster\_node\_service\_acct\_description) | (Optional) The description of the IAM role that will be created for Anyscale access.

ex:
anyscale_cluster_node_service_acct_description = "Anyscale Cluster Node"
| `string` | `null` | no | +| [anyscale\_cluster\_node\_service\_acct\_name](#input\_anyscale\_cluster\_node\_service\_acct\_name) | (Optional - forces new resource) IAM Cluster Node Role Name

The name of the IAM role that will be created for Anyscale cluster nodes.
- If left `null`, will default to anyscale\_cluster\_node\_service\_acct\_name\_prefix.
- If provided, overrides the anyscale\_cluster\_node\_service\_acct\_name\_prefix variable.
- It needs to be > 4 chars and < 28 chars.

ex:
anyscale_cluster_node_service_acct_name = "anyscale-cluster-node"
| `string` | `null` | no | +| [anyscale\_cluster\_node\_service\_acct\_name\_prefix](#input\_anyscale\_cluster\_node\_service\_acct\_name\_prefix) | (Optional - forces new resource) IAM Cluster Node Role Name Prefix

Creates a unique IAM role name beginning with the specified prefix.
- If `anyscale_cluster_node_service_acct_name` is provided, it will override this variable.
- The variable `general_prefix` is a fall-back prefix if this is not provided.
- Default is `null` but is set to `anyscale-cluster-` in a local variable.
- It needs to be > 4 chars and < 20 chars.

ex:
anyscale_cluster_node_service_acct_name_prefix = "anyscale-cluster-"
| `string` | `null` | no | | [anyscale\_deploy\_env](#input\_anyscale\_deploy\_env) | (Optional) Anyscale deploy environment.

Used in resource names and tags.

ex:
anyscale_deploy_env = "production"
| `string` | `"production"` | no | | [anyscale\_filestore\_capacity\_gb](#input\_anyscale\_filestore\_capacity\_gb) | (Optional) The capacity of the fileshare in GB.
This must be at least 1024 GiB for the standard or enterprise tiers, or 2560 GiB for the premium tier.
Default is `1024`. | `number` | `1024` | no | | [anyscale\_filestore\_description](#input\_anyscale\_filestore\_description) | (Optional) The description of the filestore instance.

ex:
anyscale_filestore_description = "Anyscale Filestore Instance"
| `string` | `"Anyscale Filestore Instance"` | no | @@ -134,9 +136,11 @@ None | [anyscale\_filestore\_name\_prefix](#input\_anyscale\_filestore\_name\_prefix) | (Optional - forces new resource) Filestore instance name prefix.

Creates a unique filestore instance name beginning with the specified prefix.
- If `anyscale_filestore_name` is provided, it will override this variable.
- The variable `general_prefix` is a fall-back prefix if this is not provided.
- Default is `null` but is set to `anyscale-` in a local variable.

ex:
anyscale_filestore_name_prefix = "anyscale-filestore-"
| `string` | `null` | no | | [anyscale\_filestore\_network\_conect\_mode](#input\_anyscale\_filestore\_network\_conect\_mode) | (Optional) The network connect mode of the filestore instance.

Must be one of `DIRECT_PEERING` or `PRIVATE_SERVICE_ACCESS`. If using a Shared VPC, this must be set to `PRIVATE_SERVICE_ACCESS`.

ex:
anyscale_filestore_network_conect_mode = "DIRECT_PEERING"
| `string` | `"DIRECT_PEERING"` | no | | [anyscale\_filestore\_tier](#input\_anyscale\_filestore\_tier) | (Optional) The tier of the filestore to create.

Must be one of `STANDARD`, `BASIC_HDD`, `BASIC_SSD`, `HIGH_SCALE_SSD`, `ENTERPRISE` or `PREMIUM`.

ex:
anyscale_filestore_tier = "STANDARD"
| `string` | `"STANDARD"` | no | -| [anyscale\_iam\_access\_role\_description](#input\_anyscale\_iam\_access\_role\_description) | (Optional) The description of the IAM role that will be created for Anyscale access.

ex:
anyscale_iam_access_role_description = "Anyscale Cross Account Access"
| `string` | `null` | no | -| [anyscale\_iam\_access\_role\_name](#input\_anyscale\_iam\_access\_role\_name) | (Optional - forces new resource) IAM Access Role Name

The name of the IAM role that will be created for Anyscale access.
- If left `null`, will default to `anyscale_iam_access_role_name_prefix`.
- If provided, overrides the `anyscale_iam_access_role_name_prefix` variable.
- It needs to be > 4 chars and < 28 chars.

ex:
anyscale_iam_access_role_name = "anyscale-crossacct-access"
| `string` | `null` | no | -| [anyscale\_iam\_access\_role\_name\_prefix](#input\_anyscale\_iam\_access\_role\_name\_prefix) | (Optional - forces new resource) IAM Access Role Name Prefix

Creates a unique IAM role name beginning with the specified prefix.
- If `anyscale_iam_access_role_name` is provided, it will override this variable.
- The variable `general_prefix` is a fall-back prefix if this is not provided.
- Default is `null` but is set to `anyscale-crossacct-` in a local variable.
- It needs to be > 4 chars and < 20 chars.

ex:
anyscale_iam_access_role_name_prefix = "anyscale-crossacct-"
| `string` | `null` | no | +| [anyscale\_iam\_access\_role\_id](#input\_anyscale\_iam\_access\_role\_id) | (Optional, forces creation of new resource) The ID of the Anyscale IAM access role.

Overrides `anyscale_iam_access_role_id_prefix`.

ex:
anyscale_iam_access_role_id = "anyscale_access_role"
| `string` | `null` | no | +| [anyscale\_iam\_access\_role\_id\_prefix](#input\_anyscale\_iam\_access\_role\_id\_prefix) | (Optional, forces creation of new resource) The prefix of the Anyscale IAM access role.

If `anyscale_iam_access_role_id` is provided, it will override this variable.
If set to `null`, the prefix will be set to \"anyscale\_\" in a local variable.

ex:
anyscale_iam_access_role_id_prefix = "anyscale_crossacct_role_"
| `string` | `"anyscale_crossacct_role_"` | no | +| [anyscale\_iam\_access\_service\_acct\_description](#input\_anyscale\_iam\_access\_service\_acct\_description) | (Optional) The description of the IAM role that will be created for Anyscale access.

ex:
anyscale_iam_access_service_acct_description = "Anyscale Cross Account Access"
| `string` | `null` | no | +| [anyscale\_iam\_access\_service\_acct\_name](#input\_anyscale\_iam\_access\_service\_acct\_name) | (Optional - forces new resource) IAM Access Service Account Name

The name of the IAM role that will be created for Anyscale access.
- If left `null`, will default to `anyscale_iam_access_service_acct_name_prefix`.
- If provided, overrides the `anyscale_iam_access_service_acct_name_prefix` variable.
- It needs to be > 4 chars and < 28 chars.

ex:
anyscale_iam_access_service_acct_name = "anyscale-crossacct-access"
| `string` | `null` | no | +| [anyscale\_iam\_access\_service\_acct\_name\_prefix](#input\_anyscale\_iam\_access\_service\_acct\_name\_prefix) | (Optional - forces new resource) IAM Access Role Name Prefix

Creates a unique IAM Service Account name beginning with the specified prefix.
- If `anyscale_iam_access_service_acct_name` is provided, it will override this variable.
- The variable `general_prefix` is a fall-back prefix if this is not provided.
- Default is `null` but is set to `anyscale-crossacct-` in a local variable.
- It needs to be > 4 chars and < 20 chars.

ex:
anyscale_iam_access_service_acct_name_prefix = "anyscale-crossacct-"
| `string` | `null` | no | | [anyscale\_memorystore\_display\_name](#input\_anyscale\_memorystore\_display\_name) | (Optional) Memorystore Display Name

The display name of the Memorystore instance used for Anyscale Services Head Node HA.
Must start with a lowercase letter followed by up to 62 lowercase letters, numbers, or hyphens, and cannot end with a hyphen.

ex:
anyscale_memorystore_display_name = "Anyscale Memorystore"
| `string` | `null` | no | | [anyscale\_memorystore\_labels](#input\_anyscale\_memorystore\_labels) | (Optional) Memorystore Labels

A map of labels to be added to the Memorystore instance.
Duplicate labels in `labels` will be overwritten by labels in `anyscale_memorystore_labels`.

ex:
anyscale_memorystore_labels = {
application = "Anyscale",
environment = "prod"
}
| `map(string)` | `{}` | no | | [anyscale\_memorystore\_name](#input\_anyscale\_memorystore\_name) | (Optional - forces new resource) Memorystore Name

The name of the Memorystore instance used for Anyscale Services Head Node HA.

If left `null`, will default to `anyscale_memorystore_name_prefix`.
If provided, overrides the `anyscale_memorystore_name_prefix` variable.

ex:
anyscale_memorystore_name = "anyscale-memorystore"
| `string` | `null` | no | @@ -195,14 +199,14 @@ None | [filestore\_id](#output\_filestore\_id) | The Google Filestore id. | | [filestore\_location](#output\_filestore\_location) | The Google Filestore location. | | [filestore\_name](#output\_filestore\_name) | The Google Filestore name. | -| [iam\_anyscale\_access\_role\_email](#output\_iam\_anyscale\_access\_role\_email) | The Google IAM Anyscale Access Role email. | -| [iam\_anyscale\_access\_role\_id](#output\_iam\_anyscale\_access\_role\_id) | The Google IAM Anyscale Access Role id. | -| [iam\_anyscale\_access\_role\_name](#output\_iam\_anyscale\_access\_role\_name) | The Google IAM Anyscale Access Role name. | -| [iam\_anyscale\_access\_role\_unique\_id](#output\_iam\_anyscale\_access\_role\_unique\_id) | The Google IAM Anyscale Access Role unique id. | -| [iam\_anyscale\_cluster\_node\_role\_email](#output\_iam\_anyscale\_cluster\_node\_role\_email) | The Google IAM Anyscale Cluster Node Role email. | -| [iam\_anyscale\_cluster\_node\_role\_id](#output\_iam\_anyscale\_cluster\_node\_role\_id) | The Google IAM Anyscale Cluster Node Role id. | -| [iam\_anyscale\_cluster\_node\_role\_name](#output\_iam\_anyscale\_cluster\_node\_role\_name) | The Google IAM Anyscale Cluster Node Role name. | -| [iam\_anyscale\_cluster\_node\_role\_unique\_id](#output\_iam\_anyscale\_cluster\_node\_role\_unique\_id) | The Google IAM Anyscale Cluster Node Role unique id. | +| [iam\_anyscale\_access\_service\_acct\_email](#output\_iam\_anyscale\_access\_service\_acct\_email) | The Google IAM Anyscale Access Service Account email. | +| [iam\_anyscale\_access\_service\_acct\_id](#output\_iam\_anyscale\_access\_service\_acct\_id) | The Google IAM Anyscale Access Service Account ID. | +| [iam\_anyscale\_access\_service\_acct\_name](#output\_iam\_anyscale\_access\_service\_acct\_name) | The Google IAM Anyscale Access Service Account name. | +| [iam\_anyscale\_access\_service\_acct\_unique\_id](#output\_iam\_anyscale\_access\_service\_acct\_unique\_id) | The Google IAM Anyscale Access Service Account unique id. | +| [iam\_anyscale\_cluster\_node\_service\_acct\_email](#output\_iam\_anyscale\_cluster\_node\_service\_acct\_email) | The Google IAM Anyscale Cluster Node Service Account email. | +| [iam\_anyscale\_cluster\_node\_service\_acct\_id](#output\_iam\_anyscale\_cluster\_node\_service\_acct\_id) | The Google IAM Anyscale Cluster Node Service Account ID. | +| [iam\_anyscale\_cluster\_node\_service\_acct\_name](#output\_iam\_anyscale\_cluster\_node\_service\_acct\_name) | The Google IAM Anyscale Cluster Node Service Accpimt name. | +| [iam\_anyscale\_cluster\_node\_service\_acct\_unique\_id](#output\_iam\_anyscale\_cluster\_node\_service\_acct\_unique\_id) | The Google IAM Anyscale Cluster Node Service Account unique id. | | [iam\_workload\_identity\_pool\_id](#output\_iam\_workload\_identity\_pool\_id) | The Google IAM Anyscale Workload Identity Pool id. | | [iam\_workload\_identity\_pool\_name](#output\_iam\_workload\_identity\_pool\_name) | The Google IAM Anyscale Workload Identity Pool name. | | [iam\_workload\_identity\_provider\_id](#output\_iam\_workload\_identity\_provider\_id) | The Google IAM Anyscale Workload Identity Provider id. | diff --git a/data.tf b/data.tf index 9066068..c63484f 100644 --- a/data.tf +++ b/data.tf @@ -6,3 +6,10 @@ data "google_compute_subnetwork" "existing_vpc_subnet" { name = var.existing_vpc_subnet_name } + +data "google_compute_subnetwork" "shared_vpc_subnet" { + count = local.execute_vpc_firewall_sub_module && var.existing_vpc_subnet_name != null && var.existing_vpc_name != null && var.shared_vpc_project_id != null ? 1 : 0 + project = var.shared_vpc_project_id + + name = var.existing_vpc_subnet_name +} diff --git a/examples/anyscale-v2-commonname/README.md b/examples/anyscale-v2-commonname/README.md index b7e7f22..97b204e 100644 --- a/examples/anyscale-v2-commonname/README.md +++ b/examples/anyscale-v2-commonname/README.md @@ -53,17 +53,5 @@ No resources. | Name | Description | |------|-------------| -| [anyscale\_iam\_cluster\_node\_role\_email](#output\_anyscale\_iam\_cluster\_node\_role\_email) | The Anyscale cluster service account email. | -| [anyscale\_iam\_service\_account\_email](#output\_anyscale\_iam\_service\_account\_email) | The Anyscale service account email. | -| [anyscale\_iam\_workload\_identity\_provider\_id](#output\_anyscale\_iam\_workload\_identity\_provider\_id) | The Anyscale workload identity provider id. | -| [anyscale\_iam\_workload\_identity\_provider\_name](#output\_anyscale\_iam\_workload\_identity\_provider\_name) | The Anyscale workload identity provider name. | -| [cloudstorage\_bucket\_name](#output\_cloudstorage\_bucket\_name) | The Google Cloud Storage bucket name. | -| [filestore\_instance\_id](#output\_filestore\_instance\_id) | The Google Filestore instance id. | -| [filestore\_location](#output\_filestore\_location) | The Google Filestore location. | -| [firewall\_policy\_name](#output\_firewall\_policy\_name) | The Google VPC firewall policy name. | -| [project\_name](#output\_project\_name) | The Google Project name. | | [registration\_command](#output\_registration\_command) | The Anyscale registration command. | -| [subnet\_name](#output\_subnet\_name) | The Google VPC public subnet name. | -| [subnet\_region](#output\_subnet\_region) | The Google VPC public subnet region. | -| [vpc\_name](#output\_vpc\_name) | The Google VPC network name. | diff --git a/examples/anyscale-v2-commonname/outputs.tf b/examples/anyscale-v2-commonname/outputs.tf index d582434..4c88c1d 100644 --- a/examples/anyscale-v2-commonname/outputs.tf +++ b/examples/anyscale-v2-commonname/outputs.tf @@ -1,58 +1,3 @@ -output "vpc_name" { - description = "The Google VPC network name." - value = module.google_anyscale_v2_commonname.vpc_name -} -output "subnet_name" { - description = "The Google VPC public subnet name." - value = module.google_anyscale_v2_commonname.public_subnet_name -} -output "subnet_region" { - description = "The Google VPC public subnet region." - value = module.google_anyscale_v2_commonname.public_subnet_region -} - -output "firewall_policy_name" { - description = "The Google VPC firewall policy name." - value = module.google_anyscale_v2_commonname.vpc_firewall_policy_name -} -output "cloudstorage_bucket_name" { - description = "The Google Cloud Storage bucket name." - value = module.google_anyscale_v2_commonname.cloudstorage_bucket_name -} - -output "project_name" { - description = "The Google Project name." - value = module.google_anyscale_v2_commonname.project_name -} - -output "filestore_instance_id" { - description = "The Google Filestore instance id." - value = module.google_anyscale_v2_commonname.filestore_name -} -output "filestore_location" { - description = "The Google Filestore location." - value = module.google_anyscale_v2_commonname.filestore_location -} - -output "anyscale_iam_service_account_email" { - description = "The Anyscale service account email." - value = module.google_anyscale_v2_commonname.iam_anyscale_access_role_email -} - -output "anyscale_iam_cluster_node_role_email" { - description = "The Anyscale cluster service account email." - value = module.google_anyscale_v2_commonname.iam_anyscale_cluster_node_role_email -} - -output "anyscale_iam_workload_identity_provider_id" { - description = "The Anyscale workload identity provider id." - value = module.google_anyscale_v2_commonname.iam_workload_identity_provider_id -} -output "anyscale_iam_workload_identity_provider_name" { - description = "The Anyscale workload identity provider name." - value = module.google_anyscale_v2_commonname.iam_workload_identity_provider_name -} - output "registration_command" { description = "The Anyscale registration command." value = <<-EOT @@ -66,8 +11,8 @@ output "registration_command" { --cloud-storage-bucket-name ${module.google_anyscale_v2_commonname.cloudstorage_bucket_name} \ --filestore-instance-id ${module.google_anyscale_v2_commonname.filestore_name} \ --filestore-location ${module.google_anyscale_v2_commonname.filestore_location} \ - --anyscale-service-account-email ${module.google_anyscale_v2_commonname.iam_anyscale_access_role_email} \ - --instance-service-account-email ${module.google_anyscale_v2_commonname.iam_anyscale_cluster_node_role_email} \ + --anyscale-service-account-email ${module.google_anyscale_v2_commonname.iam_anyscale_access_service_acct_email} \ + --instance-service-account-email ${module.google_anyscale_v2_commonname.iam_anyscale_cluster_node_service_acct_email} \ --provider-name ${module.google_anyscale_v2_commonname.iam_workload_identity_provider_name} EOT } diff --git a/examples/anyscale-v2-existingidentityfederation/README.md b/examples/anyscale-v2-existingidentityfederation/README.md index acbc3c1..1fd680e 100644 --- a/examples/anyscale-v2-existingidentityfederation/README.md +++ b/examples/anyscale-v2-existingidentityfederation/README.md @@ -43,11 +43,10 @@ No resources. | [anyscale\_google\_region](#input\_anyscale\_google\_region) | (Required) Google region to deploy Anyscale resources. | `string` | n/a | yes | | [anyscale\_google\_zone](#input\_anyscale\_google\_zone) | (Required) Google zone to deploy Anyscale resources. | `string` | n/a | yes | | [anyscale\_org\_id](#input\_anyscale\_org\_id) | (Required) Anyscale Organization ID | `string` | n/a | yes | -| [billing\_account\_id](#input\_billing\_account\_id) | (Required) Google billing account ID to deploy Anyscale resources. | `string` | n/a | yes | | [customer\_ingress\_cidr\_ranges](#input\_customer\_ingress\_cidr\_ranges) | The IPv4 CIDR blocks that allows access Anyscale clusters.
These are added to the firewall and allows port 443 (https) and 22 (ssh) access.
ex: `52.1.1.23/32,10.1.0.0/16'
` | `string` | n/a | yes | +| [existing\_project\_id](#input\_existing\_project\_id) | (Required) Google project ID to deploy Anyscale resources. | `string` | n/a | yes | | [existing\_workload\_identity\_provider\_name](#input\_existing\_workload\_identity\_provider\_name) | (Optional) Existing Workload Identity Provider Name.

The name of an existing Workload Identity Provider that you'd like to use. This can be in a different project.

You can retrieve the name of an existing Workload Identity Provider by running the following command:
gcloud iam workload-identity-pools providers list --location global --workload-identity-pool anyscale-access-pool
ex:
existing_workload_identity_provider = "projects/1234567890/locations/global/workloadIdentityPools/anyscale-access-pool/providers/anyscale-access-provider"
| `string` | n/a | yes | | [labels](#input\_labels) | (Optional) A map of labels to all resources that accept labels. | `map(string)` |
{
"environment": "test",
"test": true
}
| no | -| [root\_folder\_number](#input\_root\_folder\_number) | (Required) Google Folder number to deploy Anyscale resources. Will create a new sub-project by default. | `string` | n/a | yes | ## Outputs diff --git a/examples/anyscale-v2-existingidentityfederation/main.tf b/examples/anyscale-v2-existingidentityfederation/main.tf index 7687d73..2928a61 100644 --- a/examples/anyscale-v2-existingidentityfederation/main.tf +++ b/examples/anyscale-v2-existingidentityfederation/main.tf @@ -31,8 +31,9 @@ module "google_anyscale_v2_existingidentityfederation" { use_common_name = true # Project Related - anyscale_project_billing_account = var.billing_account_id - anyscale_project_folder_id = var.root_folder_number + # anyscale_project_billing_account = var.billing_account_id + # anyscale_project_folder_id = var.root_folder_number + existing_project_id = var.existing_project_id # IAM Related existing_workload_identity_provider_name = var.existing_workload_identity_provider_name diff --git a/examples/anyscale-v2-existingidentityfederation/outputs.tf b/examples/anyscale-v2-existingidentityfederation/outputs.tf index 1cdb542..eee0765 100644 --- a/examples/anyscale-v2-existingidentityfederation/outputs.tf +++ b/examples/anyscale-v2-existingidentityfederation/outputs.tf @@ -3,7 +3,7 @@ output "registration_command" { value = <<-EOT anyscale cloud register --provider gcp \ --name \ - --project-id ${module.google_anyscale_v2_existingidentityfederation.project_name} \ + --project-id ${var.existing_project_id} \ --vpc-name ${module.google_anyscale_v2_existingidentityfederation.vpc_name} \ --subnet-names ${module.google_anyscale_v2_existingidentityfederation.public_subnet_name} \ --region ${module.google_anyscale_v2_existingidentityfederation.public_subnet_region} \ @@ -11,9 +11,8 @@ output "registration_command" { --cloud-storage-bucket-name ${module.google_anyscale_v2_existingidentityfederation.cloudstorage_bucket_name} \ --filestore-instance-id ${module.google_anyscale_v2_existingidentityfederation.filestore_name} \ --filestore-location ${module.google_anyscale_v2_existingidentityfederation.filestore_location} \ - --anyscale-service-account-email ${module.google_anyscale_v2_existingidentityfederation.iam_anyscale_access_role_email} \ - --instance-service-account-email ${module.google_anyscale_v2_existingidentityfederation.iam_anyscale_cluster_node_role_email} \ + --anyscale-service-account-email ${module.google_anyscale_v2_existingidentityfederation.iam_anyscale_access_service_acct_email} \ + --instance-service-account-email ${module.google_anyscale_v2_existingidentityfederation.iam_anyscale_cluster_node_service_acct_email} \ --provider-name ${var.existing_workload_identity_provider_name} EOT } -# diff --git a/examples/anyscale-v2-existingidentityfederation/variables.tf b/examples/anyscale-v2-existingidentityfederation/variables.tf index 194bf4b..77065ff 100644 --- a/examples/anyscale-v2-existingidentityfederation/variables.tf +++ b/examples/anyscale-v2-existingidentityfederation/variables.tf @@ -30,12 +30,8 @@ variable "anyscale_org_id" { } # Project Related Required Variables -variable "root_folder_number" { - description = "(Required) Google Folder number to deploy Anyscale resources. Will create a new sub-project by default." - type = string -} -variable "billing_account_id" { - description = "(Required) Google billing account ID to deploy Anyscale resources." +variable "existing_project_id" { + description = "(Required) Google project ID to deploy Anyscale resources." type = string } diff --git a/examples/anyscale-v2-existingproject/README.md b/examples/anyscale-v2-existingproject/README.md index a231fce..e09d059 100644 --- a/examples/anyscale-v2-existingproject/README.md +++ b/examples/anyscale-v2-existingproject/README.md @@ -51,17 +51,5 @@ No resources. | Name | Description | |------|-------------| -| [anyscale\_iam\_cluster\_node\_role\_email](#output\_anyscale\_iam\_cluster\_node\_role\_email) | The Anyscale cluster service account email. | -| [anyscale\_iam\_service\_account\_email](#output\_anyscale\_iam\_service\_account\_email) | The Anyscale service account email. | -| [anyscale\_iam\_workload\_identity\_provider\_id](#output\_anyscale\_iam\_workload\_identity\_provider\_id) | The Anyscale workload identity provider id. | -| [anyscale\_iam\_workload\_identity\_provider\_name](#output\_anyscale\_iam\_workload\_identity\_provider\_name) | The Anyscale workload identity provider name. | -| [cloudstorage\_bucket\_name](#output\_cloudstorage\_bucket\_name) | The Google Cloud Storage bucket name. | -| [filestore\_instance\_id](#output\_filestore\_instance\_id) | The Google Filestore instance id. | -| [filestore\_location](#output\_filestore\_location) | The Google Filestore location. | -| [firewall\_policy\_name](#output\_firewall\_policy\_name) | The Google VPC firewall policy name. | -| [project\_name](#output\_project\_name) | The Google Project name. | | [registration\_command](#output\_registration\_command) | The Anyscale registration command. | -| [subnet\_name](#output\_subnet\_name) | The Google VPC public subnet name. | -| [subnet\_region](#output\_subnet\_region) | The Google VPC public subnet region. | -| [vpc\_name](#output\_vpc\_name) | The Google VPC network name. | diff --git a/examples/anyscale-v2-existingproject/outputs.tf b/examples/anyscale-v2-existingproject/outputs.tf index 86fee37..f33d194 100644 --- a/examples/anyscale-v2-existingproject/outputs.tf +++ b/examples/anyscale-v2-existingproject/outputs.tf @@ -1,58 +1,3 @@ -output "vpc_name" { - description = "The Google VPC network name." - value = module.google_anyscale_v2_existingproject.vpc_name -} -output "subnet_name" { - description = "The Google VPC public subnet name." - value = module.google_anyscale_v2_existingproject.public_subnet_name -} -output "subnet_region" { - description = "The Google VPC public subnet region." - value = module.google_anyscale_v2_existingproject.public_subnet_region -} - -output "firewall_policy_name" { - description = "The Google VPC firewall policy name." - value = module.google_anyscale_v2_existingproject.vpc_firewall_policy_name -} -output "cloudstorage_bucket_name" { - description = "The Google Cloud Storage bucket name." - value = module.google_anyscale_v2_existingproject.cloudstorage_bucket_name -} - -output "project_name" { - description = "The Google Project name." - value = module.google_anyscale_v2_existingproject.project_name -} - -output "filestore_instance_id" { - description = "The Google Filestore instance id." - value = module.google_anyscale_v2_existingproject.filestore_name -} -output "filestore_location" { - description = "The Google Filestore location." - value = module.google_anyscale_v2_existingproject.filestore_location -} - -output "anyscale_iam_service_account_email" { - description = "The Anyscale service account email." - value = module.google_anyscale_v2_existingproject.iam_anyscale_access_role_email -} - -output "anyscale_iam_cluster_node_role_email" { - description = "The Anyscale cluster service account email." - value = module.google_anyscale_v2_existingproject.iam_anyscale_cluster_node_role_email -} - -output "anyscale_iam_workload_identity_provider_id" { - description = "The Anyscale workload identity provider id." - value = module.google_anyscale_v2_existingproject.iam_workload_identity_provider_id -} -output "anyscale_iam_workload_identity_provider_name" { - description = "The Anyscale workload identity provider name." - value = module.google_anyscale_v2_existingproject.iam_workload_identity_provider_name -} - output "registration_command" { description = "The Anyscale registration command." value = <<-EOT @@ -66,8 +11,8 @@ output "registration_command" { --cloud-storage-bucket-name ${module.google_anyscale_v2_existingproject.cloudstorage_bucket_name} \ --filestore-instance-id ${module.google_anyscale_v2_existingproject.filestore_name} \ --filestore-location ${module.google_anyscale_v2_existingproject.filestore_location} \ - --anyscale-service-account-email ${module.google_anyscale_v2_existingproject.iam_anyscale_access_role_email} \ - --instance-service-account-email ${module.google_anyscale_v2_existingproject.iam_anyscale_cluster_node_role_email} \ + --anyscale-service-account-email ${module.google_anyscale_v2_existingproject.iam_anyscale_access_service_acct_email} \ + --instance-service-account-email ${module.google_anyscale_v2_existingproject.iam_anyscale_cluster_node_service_acct_email} \ --provider-name ${module.google_anyscale_v2_existingproject.iam_workload_identity_provider_name} EOT } diff --git a/examples/anyscale-v2-kitchensink/main.tf b/examples/anyscale-v2-kitchensink/main.tf index 3dde5ae..01ad2b1 100644 --- a/examples/anyscale-v2-kitchensink/main.tf +++ b/examples/anyscale-v2-kitchensink/main.tf @@ -90,14 +90,14 @@ module "google_anyscale_v2_kitchensink" { # IAM Related enable_anyscale_iam = true - anyscale_iam_access_role_name_prefix = "anyscale-tf-ks-acct-" - anyscale_iam_access_role_description = "Anyscale Terraform KitchenSink IAM Access Role" + anyscale_iam_access_service_acct_name_prefix = "anyscale-tf-ks-acct-" + anyscale_iam_access_service_acct_description = "Anyscale Terraform KitchenSink IAM Access Role" anyscale_workload_identity_pool_name = "anyscale-tf-ks-workload-id-pool" anyscale_workload_identity_pool_display_name = "Anyscale TF KS Identity Pool" anyscale_workload_identity_pool_description = "Anyscale Terraform KitchenSink Workload Identity Pool" - anyscale_cluster_node_role_name = "anyscale-tf-ks-cluster" - anyscale_cluster_node_role_description = "Anyscale Terraform KitchenSink IAM Cluster Node Role" + anyscale_cluster_node_service_acct_name = "anyscale-tf-ks-cluster" + anyscale_cluster_node_service_acct_description = "Anyscale Terraform KitchenSink IAM Cluster Node Role" # Memorystore Related enable_anyscale_memorystore = true diff --git a/examples/anyscale-v2-kitchensink/outputs.tf b/examples/anyscale-v2-kitchensink/outputs.tf index bf7d639..e563cc0 100644 --- a/examples/anyscale-v2-kitchensink/outputs.tf +++ b/examples/anyscale-v2-kitchensink/outputs.tf @@ -11,8 +11,8 @@ output "registration_command" { --cloud-storage-bucket-name ${module.google_anyscale_v2_kitchensink.cloudstorage_bucket_name} \ --filestore-instance-id ${module.google_anyscale_v2_kitchensink.filestore_name} \ --filestore-location ${module.google_anyscale_v2_kitchensink.filestore_location} \ - --anyscale-service-account-email ${module.google_anyscale_v2_kitchensink.iam_anyscale_access_role_email} \ - --instance-service-account-email ${module.google_anyscale_v2_kitchensink.iam_anyscale_cluster_node_role_email} \ + --anyscale-service-account-email ${module.google_anyscale_v2_kitchensink.iam_anyscale_access_service_acct_email} \ + --instance-service-account-email ${module.google_anyscale_v2_kitchensink.iam_anyscale_cluster_node_service_acct_email} \ --provider-name ${module.google_anyscale_v2_kitchensink.iam_workload_identity_provider_name} \ --memorystore-instance-name ${module.google_anyscale_v2_kitchensink.memorystore_id} EOT diff --git a/examples/anyscale-v2-privatenetwork/README.md b/examples/anyscale-v2-privatenetwork/README.md index 2aafbdd..49e975d 100644 --- a/examples/anyscale-v2-privatenetwork/README.md +++ b/examples/anyscale-v2-privatenetwork/README.md @@ -57,18 +57,5 @@ No resources. | Name | Description | |------|-------------| -| [anyscale\_iam\_cluster\_node\_role\_email](#output\_anyscale\_iam\_cluster\_node\_role\_email) | The Anyscale cluster service account email. | -| [anyscale\_iam\_service\_account\_email](#output\_anyscale\_iam\_service\_account\_email) | The Anyscale service account email. | -| [anyscale\_iam\_workload\_identity\_provider\_id](#output\_anyscale\_iam\_workload\_identity\_provider\_id) | The Anyscale workload identity provider id. | -| [anyscale\_iam\_workload\_identity\_provider\_name](#output\_anyscale\_iam\_workload\_identity\_provider\_name) | The Anyscale workload identity provider name. | -| [cloudstorage\_bucket\_name](#output\_cloudstorage\_bucket\_name) | The Google Cloud Storage bucket name. | -| [filestore\_instance\_id](#output\_filestore\_instance\_id) | The Google Filestore instance id. | -| [filestore\_location](#output\_filestore\_location) | The Google Filestore location. | -| [firewall\_policy\_name](#output\_firewall\_policy\_name) | The Google VPC firewall policy name. | -| [memorystore\_id](#output\_memorystore\_id) | The memorystore instance ID. | -| [project\_name](#output\_project\_name) | The Google Project name. | | [registration\_command](#output\_registration\_command) | The Anyscale registration command. | -| [subnet\_name](#output\_subnet\_name) | The Google VPC public subnet name. | -| [subnet\_region](#output\_subnet\_region) | The Google VPC public subnet region. | -| [vpc\_name](#output\_vpc\_name) | The Google VPC network name. | diff --git a/examples/anyscale-v2-privatenetwork/main.tf b/examples/anyscale-v2-privatenetwork/main.tf index 7f9f4ce..41b8063 100644 --- a/examples/anyscale-v2-privatenetwork/main.tf +++ b/examples/anyscale-v2-privatenetwork/main.tf @@ -50,5 +50,5 @@ module "google_anyscale_v2_privatenetwork" { anyscale_bucket_location = "US" # Memorystore Related - # enable_anyscale_memorystore = true + enable_anyscale_memorystore = true } diff --git a/examples/anyscale-v2-privatenetwork/outputs.tf b/examples/anyscale-v2-privatenetwork/outputs.tf index bfcaf84..ade6f3e 100644 --- a/examples/anyscale-v2-privatenetwork/outputs.tf +++ b/examples/anyscale-v2-privatenetwork/outputs.tf @@ -1,63 +1,3 @@ -output "vpc_name" { - description = "The Google VPC network name." - value = module.google_anyscale_v2_privatenetwork.vpc_name -} -output "subnet_name" { - description = "The Google VPC public subnet name." - value = module.google_anyscale_v2_privatenetwork.private_subnet_name -} -output "subnet_region" { - description = "The Google VPC public subnet region." - value = module.google_anyscale_v2_privatenetwork.private_subnet_region -} - -output "firewall_policy_name" { - description = "The Google VPC firewall policy name." - value = module.google_anyscale_v2_privatenetwork.vpc_firewall_policy_name -} -output "cloudstorage_bucket_name" { - description = "The Google Cloud Storage bucket name." - value = module.google_anyscale_v2_privatenetwork.cloudstorage_bucket_name -} - -output "project_name" { - description = "The Google Project name." - value = module.google_anyscale_v2_privatenetwork.project_name -} - -output "filestore_instance_id" { - description = "The Google Filestore instance id." - value = module.google_anyscale_v2_privatenetwork.filestore_name -} -output "filestore_location" { - description = "The Google Filestore location." - value = module.google_anyscale_v2_privatenetwork.filestore_location -} - -output "anyscale_iam_service_account_email" { - description = "The Anyscale service account email." - value = module.google_anyscale_v2_privatenetwork.iam_anyscale_access_role_email -} - -output "anyscale_iam_cluster_node_role_email" { - description = "The Anyscale cluster service account email." - value = module.google_anyscale_v2_privatenetwork.iam_anyscale_cluster_node_role_email -} - -output "anyscale_iam_workload_identity_provider_id" { - description = "The Anyscale workload identity provider id." - value = module.google_anyscale_v2_privatenetwork.iam_workload_identity_provider_id -} -output "anyscale_iam_workload_identity_provider_name" { - description = "The Anyscale workload identity provider name." - value = module.google_anyscale_v2_privatenetwork.iam_workload_identity_provider_name -} - -output "memorystore_id" { - description = "The memorystore instance ID." - value = module.google_anyscale_v2_privatenetwork.memorystore_id -} - output "registration_command" { description = "The Anyscale registration command." value = <<-EOT @@ -71,11 +11,11 @@ output "registration_command" { --cloud-storage-bucket-name ${module.google_anyscale_v2_privatenetwork.cloudstorage_bucket_name} \ --filestore-instance-id ${module.google_anyscale_v2_privatenetwork.filestore_name} \ --filestore-location ${module.google_anyscale_v2_privatenetwork.filestore_location} \ - --anyscale-service-account-email ${module.google_anyscale_v2_privatenetwork.iam_anyscale_access_role_email} \ - --instance-service-account-email ${module.google_anyscale_v2_privatenetwork.iam_anyscale_cluster_node_role_email} \ + --anyscale-service-account-email ${module.google_anyscale_v2_privatenetwork.iam_anyscale_access_service_acct_email} \ + --instance-service-account-email ${module.google_anyscale_v2_privatenetwork.iam_anyscale_cluster_node_service_acct_email} \ --provider-name ${module.google_anyscale_v2_privatenetwork.iam_workload_identity_provider_name} \ --memorystore-instance-name ${module.google_anyscale_v2_privatenetwork.memorystore_id} \ - --private-network" + --private-network EOT } # diff --git a/examples/anyscale-v2-vpc-shared/README.md b/examples/anyscale-v2-vpc-shared/README.md new file mode 100644 index 0000000..cfdbc6c --- /dev/null +++ b/examples/anyscale-v2-vpc-shared/README.md @@ -0,0 +1,74 @@ +# anyscale-v2-vpc-shared example + +Builds the resources for Anyscale in a Google Cloud. +This will build all resources in an existing project. +It will use a Shared VPC from a different project to (optionally) create Firewall resources. +It will use an existing Project (with which the VPC has been shared with) +This will also build all the resources with the same name. + +Creates a stack including: +- Enabling Cloud APIs on the Project +- Cloud Storage Bucket - Standard +- IAM Roles +- VPC Firewall +- FileStore (Requires private service access to be enabled on the shared VPC. See the [Google Documentation](https://cloud.google.com/filestore/docs/shared-vpc#enable_private_service_access_on_the_network) for more information) + +Requirements: +- Source GCP Project + - VPC created + - Service Networking API enabled + - VPC shared with Second Project + - VPC Private Service Connection configured (following above Google Documentation) + - Allocated IP ranges configured + - Private Connections to Services enabled +- A second Anyscale GCP Project + - Service Netowrking API enabled + - The VPC created in the first GCP project should be shared with this Project + +Once the Anyscale Access Service Account has been created, additionally, the service account needs to be granted "Compute Network User" on the Source GCP Project. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [google](#requirement\_google) | ~> 4.0 | + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [google\_anyscale\_v2\_vpc\_shared](#module\_google\_anyscale\_v2\_vpc\_shared) | ../.. | n/a | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID. Default is `null`. | `string` | `null` | no | +| [anyscale\_deploy\_env](#input\_anyscale\_deploy\_env) | (Required) Anyscale deploy environment. Used in resource names and tags. | `string` | `"production"` | no | +| [anyscale\_google\_region](#input\_anyscale\_google\_region) | (Required) Google region to deploy Anyscale resources. | `string` | n/a | yes | +| [anyscale\_google\_zone](#input\_anyscale\_google\_zone) | (Required) Google zone to deploy Anyscale resources. | `string` | n/a | yes | +| [anyscale\_org\_id](#input\_anyscale\_org\_id) | (Required) Anyscale Organization ID | `string` | n/a | yes | +| [customer\_ingress\_cidr\_ranges](#input\_customer\_ingress\_cidr\_ranges) | The IPv4 CIDR blocks that allows access Anyscale clusters.
These are added to the firewall and allows port 443 (https) and 22 (ssh) access.
ex: `52.1.1.23/32,10.1.0.0/16'
` | `string` | n/a | yes | +| [enable\_anyscale\_vpc\_firewall](#input\_enable\_anyscale\_vpc\_firewall) | (Optional) Determines if the Anyscale VPC Firewall is created.

ex:
enable_anyscale_vpc_firewall = true
| `bool` | `true` | no | +| [existing\_project\_id](#input\_existing\_project\_id) | (Required) Google project ID to deploy Anyscale resources.

ex:
existing_project_id = "anyscale-project"
| `string` | n/a | yes | +| [existing\_vpc\_name](#input\_existing\_vpc\_name) | (Required) An existing VPC Name.

If provided, this module will skip creating a new VPC with the Anyscale VPC module.
An existing VPC Subnet Name (`existing_vpc_subnet_name`) is also required if this is provided.

ex:
existing_vpc_name = "anyscale-vpc"
| `string` | `null` | no | +| [existing\_vpc\_subnet\_name](#input\_existing\_vpc\_subnet\_name) | (Required) Existing subnet name to create Anyscale resources in.

If provided, this will skip creating resources with the Anyscale VPC module.
An existing VPC Name (`existing_vpc_name`) is also required if this is provided.

ex:
existing_vpc_subnet_name = "anyscale-subnet"
| `string` | `null` | no | +| [labels](#input\_labels) | (Optional) A map of labels to all resources that accept labels. | `map(string)` |
{
"environment": "test",
"test": true
}
| no | +| [shared\_vpc\_project\_id](#input\_shared\_vpc\_project\_id) | (Required) Google project ID for the Shared VPC.

If provided, the firewall resources will be created in the Shared VPC Project.

An existing VPC Name (`existing_vpc_name`) and existing Subnet Name (`existing_vpc_subnet_name`) are also required when this is provided.

ex:
shared_vpc_project_id = "anyscale-vpc"
| `string` | `null` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [registration\_command](#output\_registration\_command) | The Anyscale registration command. | + diff --git a/examples/anyscale-v2-vpc-shared/main.tf b/examples/anyscale-v2-vpc-shared/main.tf new file mode 100644 index 0000000..ea33ccc --- /dev/null +++ b/examples/anyscale-v2-vpc-shared/main.tf @@ -0,0 +1,51 @@ +# --------------------------------------------------------------------------------------------------------------------- +# Create core Anyscale v2 Stack resources in Google Cloud within an existing project +# Creates a v2 stack including +# - Enabling Cloud APIs on the Project +# - Cloud Storage Bucket +# - IAM Roles +# - VPC with public subnets +# - VPC Firewall +# - FileStore (Standard) +# This does NOT create a project. +# --------------------------------------------------------------------------------------------------------------------- +locals { + full_labels = merge(tomap({ + anyscale-cloud-id = var.anyscale_cloud_id, + anyscale-deploy-environment = var.anyscale_deploy_env + }), + var.labels + ) + +} + +module "google_anyscale_v2_vpc_shared" { + source = "../.." + labels = local.full_labels + + anyscale_deploy_env = var.anyscale_deploy_env + anyscale_cloud_id = var.anyscale_cloud_id + anyscale_organization_id = var.anyscale_org_id + + common_prefix = "tf-sharedvpc-" + use_common_name = true + + # Project Related + existing_project_id = var.existing_project_id + + # VPC Related + existing_vpc_name = var.existing_vpc_name + existing_vpc_subnet_name = var.existing_vpc_subnet_name + shared_vpc_project_id = var.shared_vpc_project_id + + # Firewall Related + enable_anyscale_vpc_firewall = var.enable_anyscale_vpc_firewall # determines if a new firewall is created + + anyscale_vpc_firewall_allow_access_from_cidrs = var.customer_ingress_cidr_ranges # determines what cidr ranges to allow access from + + # Cloud Storage (Bucket) Related + anyscale_bucket_location = "US" + + # Filestore Related + anyscale_filestore_network_conect_mode = "PRIVATE_SERVICE_ACCESS" +} diff --git a/examples/anyscale-v2-vpc-shared/outputs.tf b/examples/anyscale-v2-vpc-shared/outputs.tf new file mode 100644 index 0000000..6cfce65 --- /dev/null +++ b/examples/anyscale-v2-vpc-shared/outputs.tf @@ -0,0 +1,19 @@ +output "registration_command" { + description = "The Anyscale registration command." + value = <<-EOT + anyscale cloud register --provider gcp \ + --name \ + --project-id ${var.existing_project_id} \ + --vpc-name ${var.existing_vpc_name} \ + --subnet-names ${var.existing_vpc_subnet_name} \ + --region ${var.anyscale_google_region} \ + --firewall-policy-names ${module.google_anyscale_v2_vpc_shared.vpc_firewall_policy_name} \ + --cloud-storage-bucket-name ${module.google_anyscale_v2_vpc_shared.cloudstorage_bucket_name} \ + --filestore-instance-id ${module.google_anyscale_v2_vpc_shared.filestore_name} \ + --filestore-location ${module.google_anyscale_v2_vpc_shared.filestore_location} \ + --anyscale-service-account-email ${module.google_anyscale_v2_vpc_shared.iam_anyscale_access_service_acct_email} \ + --instance-service-account-email ${module.google_anyscale_v2_vpc_shared.iam_anyscale_cluster_node_service_acct_email} \ + --provider-name ${module.google_anyscale_v2_vpc_shared.iam_workload_identity_provider_name} \ + --host-project-id ${var.shared_vpc_project_id} + EOT +} diff --git a/examples/anyscale-v2-vpc-shared/variables.tf b/examples/anyscale-v2-vpc-shared/variables.tf new file mode 100644 index 0000000..15dff46 --- /dev/null +++ b/examples/anyscale-v2-vpc-shared/variables.tf @@ -0,0 +1,154 @@ +# --------------------------------------------------------------------------------------------------------------------- +# ENVIRONMENT VARIABLES +# Define these secrets as environment variables +# --------------------------------------------------------------------------------------------------------------------- + + +# --------------------------------------------------------------------------------------------------------------------- +# REQUIRED VARIABLES +# These variables must be set when using this module. +# --------------------------------------------------------------------------------------------------------------------- +variable "anyscale_google_region" { + description = "(Required) Google region to deploy Anyscale resources." + type = string +} +variable "anyscale_google_zone" { + description = "(Required) Google zone to deploy Anyscale resources." + type = string +} + +variable "anyscale_org_id" { + description = "(Required) Anyscale Organization ID" + type = string + validation { + condition = ( + length(var.anyscale_org_id) > 4 && + substr(var.anyscale_org_id, 0, 4) == "org_" + ) + error_message = "The anyscale_org_id value must start with \"org_\"." + } +} + +# Project Related Required Variables +variable "existing_project_id" { + description = <<-EOT + (Required) Google project ID to deploy Anyscale resources. + + ex: + ``` + existing_project_id = "anyscale-project" + ``` + EOT + type = string +} + +variable "existing_vpc_name" { + description = <<-EOT + (Required) An existing VPC Name. + + If provided, this module will skip creating a new VPC with the Anyscale VPC module. + An existing VPC Subnet Name (`existing_vpc_subnet_name`) is also required if this is provided. + + ex: + ``` + existing_vpc_name = "anyscale-vpc" + ``` + EOT + type = string + default = null +} + +variable "existing_vpc_subnet_name" { + description = <<-EOT + (Required) Existing subnet name to create Anyscale resources in. + + If provided, this will skip creating resources with the Anyscale VPC module. + An existing VPC Name (`existing_vpc_name`) is also required if this is provided. + + ex: + ``` + existing_vpc_subnet_name = "anyscale-subnet" + ``` + EOT + type = string + default = null +} + +variable "shared_vpc_project_id" { + description = <<-EOT + (Required) Google project ID for the Shared VPC. + + If provided, the firewall resources will be created in the Shared VPC Project. + + An existing VPC Name (`existing_vpc_name`) and existing Subnet Name (`existing_vpc_subnet_name`) are also required when this is provided. + + ex: + ``` + shared_vpc_project_id = "anyscale-vpc" + ``` + EOT + type = string + default = null +} + +variable "customer_ingress_cidr_ranges" { + description = <<-EOT + The IPv4 CIDR blocks that allows access Anyscale clusters. + These are added to the firewall and allows port 443 (https) and 22 (ssh) access. + ex: `52.1.1.23/32,10.1.0.0/16' + EOT + type = string +} + +# ------------------------------------------------------------------------------ +# OPTIONAL PARAMETERS +# These variables have defaults, but may be overridden. +# ------------------------------------------------------------------------------ +variable "anyscale_deploy_env" { + description = "(Required) Anyscale deploy environment. Used in resource names and tags." + type = string + validation { + condition = ( + var.anyscale_deploy_env == "production" || var.anyscale_deploy_env == "development" || var.anyscale_deploy_env == "test" + ) + error_message = "The anyscale_deploy_env only allows `production`, `test`, or `development`" + } + default = "production" +} + +variable "anyscale_cloud_id" { + description = "(Optional) Anyscale Cloud ID. Default is `null`." + type = string + default = null + validation { + condition = ( + var.anyscale_cloud_id == null ? true : ( + length(var.anyscale_cloud_id) > 4 && + substr(var.anyscale_cloud_id, 0, 4) == "cld_" + ) + ) + error_message = "The anyscale_cloud_id value must start with \"cld_\"." + } +} + +variable "labels" { + description = "(Optional) A map of labels to all resources that accept labels." + type = map(string) + default = { + "test" : true, + "environment" : "test" + } +} + +variable "enable_anyscale_vpc_firewall" { + description = <<-EOT + (Optional) Determines if the Anyscale VPC Firewall is created. + + ex: + ``` + enable_anyscale_vpc_firewall = true + ``` + EOT + type = bool + default = true +} diff --git a/examples/anyscale-v2-vpc-shared/versions.tf b/examples/anyscale-v2-vpc-shared/versions.tf new file mode 100644 index 0000000..763888a --- /dev/null +++ b/examples/anyscale-v2-vpc-shared/versions.tf @@ -0,0 +1,15 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + google = { + source = "hashicorp/google" + version = "~> 4.0" + } + } +} + +provider "google" { + region = var.anyscale_google_region + zone = var.anyscale_google_zone +} diff --git a/examples/anyscale-v2/README.md b/examples/anyscale-v2/README.md index c1224e6..36f52c2 100644 --- a/examples/anyscale-v2/README.md +++ b/examples/anyscale-v2/README.md @@ -51,7 +51,7 @@ No resources. | Name | Description | |------|-------------| -| [anyscale\_iam\_cluster\_node\_role\_email](#output\_anyscale\_iam\_cluster\_node\_role\_email) | The Anyscale cluster service account email. | +| [anyscale\_iam\_cluster\_node\_service\_account\_email](#output\_anyscale\_iam\_cluster\_node\_service\_account\_email) | The Anyscale cluster service account email. | | [anyscale\_iam\_service\_account\_email](#output\_anyscale\_iam\_service\_account\_email) | The Anyscale service account email. | | [anyscale\_iam\_workload\_identity\_provider\_id](#output\_anyscale\_iam\_workload\_identity\_provider\_id) | The Anyscale workload identity provider id. | | [anyscale\_iam\_workload\_identity\_provider\_name](#output\_anyscale\_iam\_workload\_identity\_provider\_name) | The Anyscale workload identity provider name. | diff --git a/examples/anyscale-v2/outputs.tf b/examples/anyscale-v2/outputs.tf index 6ba7c25..991bde0 100644 --- a/examples/anyscale-v2/outputs.tf +++ b/examples/anyscale-v2/outputs.tf @@ -36,12 +36,12 @@ output "filestore_location" { output "anyscale_iam_service_account_email" { description = "The Anyscale service account email." - value = module.google_anyscale_v2.iam_anyscale_access_role_email + value = module.google_anyscale_v2.iam_anyscale_access_service_acct_email } -output "anyscale_iam_cluster_node_role_email" { +output "anyscale_iam_cluster_node_service_account_email" { description = "The Anyscale cluster service account email." - value = module.google_anyscale_v2.iam_anyscale_cluster_node_role_email + value = module.google_anyscale_v2.iam_anyscale_cluster_node_service_acct_email } output "anyscale_iam_workload_identity_provider_id" { @@ -66,8 +66,8 @@ output "registration_command" { --cloud-storage-bucket-name ${module.google_anyscale_v2.cloudstorage_bucket_name} \ --filestore-instance-id ${module.google_anyscale_v2.filestore_name} \ --filestore-location ${module.google_anyscale_v2.filestore_location} \ - --anyscale-service-account-email ${module.google_anyscale_v2.iam_anyscale_access_role_email} \ - --instance-service-account-email ${module.google_anyscale_v2.iam_anyscale_cluster_node_role_email} \ + --anyscale-service-account-email ${module.google_anyscale_v2.iam_anyscale_access_service_acct_email} \ + --instance-service-account-email ${module.google_anyscale_v2.iam_anyscale_cluster_node_service_acct_email} \ --provider-name ${module.google_anyscale_v2.iam_workload_identity_provider_name} EOT } diff --git a/main.tf b/main.tf index f695f1b..4cc3a9d 100644 --- a/main.tf +++ b/main.tf @@ -118,6 +118,8 @@ module "google_anyscale_vpc" { locals { execute_vpc_firewall_sub_module = local.create_new_vpc || var.enable_anyscale_vpc_firewall ? true : false + firewall_policy_name = coalesce(var.anyscale_vpc_firewall_policy_name, var.existing_vpc_name, var.anyscale_vpc_name, local.common_name, "anyscale-firewall-policy") + vpc_project_id = coalesce(var.shared_vpc_project_id, var.existing_project_id, module.google_anyscale_project.project_id) google_ui_cidr = "35.235.240.0/20" @@ -138,7 +140,8 @@ locals { [ var.anyscale_vpc_public_subnet_cidr, var.anyscale_vpc_private_subnet_cidr, - try(data.google_compute_subnetwork.existing_vpc_subnet[0].ip_cidr_range, null) + try(data.google_compute_subnetwork.existing_vpc_subnet[0].ip_cidr_range, null), + try(data.google_compute_subnetwork.shared_vpc_subnet[0].ip_cidr_range, null) ] ) } @@ -153,7 +156,7 @@ module "google_anyscale_vpc_firewall_policy" { vpc_name = coalesce(var.existing_vpc_name, module.google_anyscale_vpc.vpc_name) - firewall_policy_name = var.anyscale_vpc_firewall_policy_name + firewall_policy_name = local.firewall_policy_name firewall_policy_description = var.anyscale_vpc_firewall_policy_description ingress_from_cidr_map = local.ingress_from_cidr_map @@ -218,11 +221,17 @@ module "google_anyscale_filestore" { locals { execute_iam_submodule = var.enable_anyscale_iam ? true : false - iam_access_role_name = var.anyscale_iam_access_role_name != null ? var.anyscale_iam_access_role_name : local.common_name != null ? "${local.common_name}-access" : null - iam_access_role_name_prefix = coalesce(var.anyscale_iam_access_role_name_prefix, var.common_prefix, "anyscale-crossacct-") + iam_access_service_acct_name = var.anyscale_iam_access_service_acct_name != null ? var.anyscale_iam_access_service_acct_name : local.common_name != null ? "${local.common_name}-access" : null + iam_access_service_acct_name_prefix = coalesce(var.anyscale_iam_access_service_acct_name_prefix, var.common_prefix, "anyscale-crossacct-") + + common_name_underscores = try(replace(local.common_name, "-", "_"), null) + common_prefix_underscores = try(replace(var.common_prefix, "-", "_"), null) - iam_cluster_node_role_name = var.anyscale_cluster_node_role_name != null ? var.anyscale_cluster_node_role_name : local.common_name != null ? "${local.common_name}-cluster" : null - iam_cluster_node_role_name_prefix = coalesce(var.anyscale_cluster_node_role_name_prefix, var.common_prefix, "anyscale-cluster-") + iam_access_role_id = var.anyscale_iam_access_role_id != null ? var.anyscale_iam_access_role_id : local.common_name_underscores != null ? "${local.common_name_underscores}_access" : null + iam_access_role_id_prefix = coalesce(var.anyscale_iam_access_role_id_prefix, local.common_prefix_underscores, "anyscale_crossacct_") + + iam_cluster_node_service_acct_name = var.anyscale_cluster_node_service_acct_name != null ? var.anyscale_cluster_node_service_acct_name : local.common_name != null ? "${local.common_name}-cluster" : null + iam_cluster_node_service_acct_name_prefix = coalesce(var.anyscale_cluster_node_service_acct_name_prefix, var.common_prefix, "anyscale-cluster-") } module "google_anyscale_iam" { source = "./modules/google-anyscale-iam" @@ -233,9 +242,13 @@ module "google_anyscale_iam" { enable_random_name_suffix = local.enable_module_random_name_suffix - anyscale_access_role_name = local.iam_access_role_name - anyscale_access_role_name_prefix = local.iam_access_role_name_prefix - anyscale_access_role_description = var.anyscale_iam_access_role_description + anyscale_access_service_acct_name = local.iam_access_service_acct_name + anyscale_access_service_acct_name_prefix = local.iam_access_service_acct_name_prefix + anyscale_access_service_acct_description = var.anyscale_iam_access_service_acct_description + + anyscale_access_role_id = local.iam_access_role_id + anyscale_access_role_id_prefix = local.iam_access_role_id_prefix + anyscale_access_role_description = var.anyscale_access_role_description existing_workload_identity_provider_name = var.existing_workload_identity_provider_name workload_identity_pool_name = var.anyscale_workload_identity_pool_name @@ -244,10 +257,10 @@ module "google_anyscale_iam" { workload_identity_pool_provider_name = var.anyscale_workload_identity_pool_provider_name workload_anyscale_aws_account_id = var.anyscale_workload_identity_account_id - anyscale_cluster_node_role_name = local.iam_cluster_node_role_name - anyscale_cluster_node_role_name_prefix = local.iam_cluster_node_role_name_prefix - anyscale_cluster_node_role_description = var.anyscale_cluster_node_role_description - enable_anyscale_cluster_logging_monitoring = local.enable_cloud_logging_monitoring + anyscale_cluster_node_service_acct_name = local.iam_cluster_node_service_acct_name + anyscale_cluster_node_service_acct_name_prefix = local.iam_cluster_node_service_acct_name_prefix + anyscale_cluster_node_service_acct_description = var.anyscale_cluster_node_service_acct_description + enable_anyscale_cluster_logging_monitoring = local.enable_cloud_logging_monitoring anyscale_cloud_id = var.anyscale_cloud_id } @@ -261,7 +274,7 @@ locals { bucket_name = var.anyscale_bucket_name != null ? var.anyscale_bucket_name : local.common_name bucket_prefix = coalesce(var.anyscale_bucket_prefix, var.common_prefix, "anyscale-") - bucket_iam_binding_members = local.execute_iam_submodule ? ["serviceAccount:${module.google_anyscale_iam.iam_anyscale_access_role_email}", "serviceAccount:${module.google_anyscale_iam.iam_anyscale_cluster_node_role_email}"] : [] + bucket_iam_binding_members = local.execute_iam_submodule ? ["serviceAccount:${module.google_anyscale_iam.iam_anyscale_access_service_acct_email}", "serviceAccount:${module.google_anyscale_iam.iam_anyscale_cluster_node_service_acct_email}"] : [] } module "google_anyscale_cloudstorage" { source = "./modules/google-anyscale-cloudstorage" diff --git a/modules/google-anyscale-cloudapis/README.md b/modules/google-anyscale-cloudapis/README.md index 3100733..9f32e5b 100644 --- a/modules/google-anyscale-cloudapis/README.md +++ b/modules/google-anyscale-cloudapis/README.md @@ -15,7 +15,7 @@ | Name | Version | |------|---------| -| [google](#provider\_google) | 4.82.0 | +| [google](#provider\_google) | 4.84.0 | ## Modules @@ -35,7 +35,6 @@ No modules. |------|-------------|------|---------|:--------:| | [anyscale\_activate\_optional\_apis](#input\_anyscale\_activate\_optional\_apis) | (Optional) Optional APIs to activate.

A list of optional apis to activate within the project.

ex:
anyscale_activate_optional_apis = [
"cloudkms.googleapis.com",
"containerregistry.googleapis.com",
"logging.googleapis.com",
"monitoring.googleapis.com",
"redis.googleapis.com",
]
| `list(string)` | `[]` | no | | [anyscale\_activate\_required\_apis](#input\_anyscale\_activate\_required\_apis) | (Optional) The list of apis to activate within the project.
Default enables APIs for compute, filestore, and storage. | `list(string)` |
[
"compute.googleapis.com",
"file.googleapis.com",
"storage-component.googleapis.com",
"storage.googleapis.com",
"certificatemanager.googleapis.com",
"cloudresourcemanager.googleapis.com",
"serviceusage.googleapis.com",
"deploymentmanager.googleapis.com"
]
| no | -| [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Required) Anyscale Cloud ID | `string` | `null` | no | | [anyscale\_project\_id](#input\_anyscale\_project\_id) | (Optional) The ID of the project to create the resource in. If not provided, the provider project is used. Default is `null`. | `string` | `null` | no | | [disable\_dependent\_services](#input\_disable\_dependent\_services) | (Optional) Determines if services that are enabled and which depend on this service should also be disabled when this service is destroyed.
More information in the [terraform documentation](https://www.terraform.io/docs/providers/google/r/google_project_service.html#disable_dependent_services). | `bool` | `true` | no | | [disable\_services\_on\_destroy](#input\_disable\_services\_on\_destroy) | (Optional) Determines if project services will be disabled when the resources are destroyed.
More information in the [terraform documentation](https://www.terraform.io/docs/providers/google/r/google_project_service.html#disable_on_destroy).
Default is `true`. | `bool` | `true` | no | diff --git a/modules/google-anyscale-cloudapis/examples/README.md b/modules/google-anyscale-cloudapis/examples/README.md index ce80a1c..fcb8a33 100644 --- a/modules/google-anyscale-cloudapis/examples/README.md +++ b/modules/google-anyscale-cloudapis/examples/README.md @@ -29,7 +29,6 @@ No resources. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [anyscale\_deploy\_env](#input\_anyscale\_deploy\_env) | (Required) Anyscale deploy environment. Used in resource names and tags. | `string` | n/a | yes | | [google\_project\_id](#input\_google\_project\_id) | ID of the Project to put these resources in | `string` | n/a | yes | | [google\_region](#input\_google\_region) | The Google region in which all resources will be created. | `string` | n/a | yes | diff --git a/modules/google-anyscale-cloudapis/examples/variables.tf b/modules/google-anyscale-cloudapis/examples/variables.tf index e40d591..e5d2edd 100644 --- a/modules/google-anyscale-cloudapis/examples/variables.tf +++ b/modules/google-anyscale-cloudapis/examples/variables.tf @@ -8,17 +8,6 @@ # REQUIRED VARIABLES # These variables must be set when using this module. # --------------------------------------------------------------------------------------------------------------------- -variable "anyscale_deploy_env" { - description = "(Required) Anyscale deploy environment. Used in resource names and tags." - type = string - validation { - condition = ( - var.anyscale_deploy_env == "production" || var.anyscale_deploy_env == "development" || var.anyscale_deploy_env == "test" - ) - error_message = "The anyscale_deploy_env only allows `production`, `test`, or `development`" - } -} - variable "google_region" { description = "The Google region in which all resources will be created." type = string diff --git a/modules/google-anyscale-cloudapis/variables.tf b/modules/google-anyscale-cloudapis/variables.tf index df49ab6..4ea7c50 100644 --- a/modules/google-anyscale-cloudapis/variables.tf +++ b/modules/google-anyscale-cloudapis/variables.tf @@ -7,21 +7,6 @@ # OPTIONAL PARAMETERS # These variables have defaults, but may be overridden. # ------------------------------------------------------------------------------ -variable "anyscale_cloud_id" { - description = "(Required) Anyscale Cloud ID" - type = string - default = null - validation { - condition = ( - var.anyscale_cloud_id == null ? true : ( - length(var.anyscale_cloud_id) > 4 && - substr(var.anyscale_cloud_id, 0, 4) == "cld_" - ) - ) - error_message = "The anyscale_cloud_id value must start with \"cld_\"." - } -} - variable "module_enabled" { description = "(Optional) Determines whether to create the resources inside this module. Default is `true`." type = bool diff --git a/modules/google-anyscale-cloudstorage/README.md b/modules/google-anyscale-cloudstorage/README.md index 11dca42..08a5a98 100644 --- a/modules/google-anyscale-cloudstorage/README.md +++ b/modules/google-anyscale-cloudstorage/README.md @@ -20,8 +20,8 @@ See the examples folder for how to use. | Name | Version | |------|---------| -| [google](#provider\_google) | 4.82.0 | -| [random](#provider\_random) | 3.5.1 | +| [google](#provider\_google) | 4.84.0 | +| [random](#provider\_random) | 3.6.0 | ## Modules @@ -41,7 +41,6 @@ No modules. |------|-------------|------|---------|:--------:| | [anyscale\_bucket\_name](#input\_anyscale\_bucket\_name) | (Optional - forces new resource)
The name of the bucket.
Changing this forces creating a new bucket.
This overrides the `anyscale_bucket_name_prefix` parameter.
Default is `null`. | `string` | `null` | no | | [anyscale\_bucket\_name\_prefix](#input\_anyscale\_bucket\_name\_prefix) | (Optional - forces new resource)
Creates a unique bucket name beginning with the specified prefix.
Changing this forces creating a new bucket.
If `anyscale_bucket_name` is provided, it overrides this parameter.
Default is `anyscale-`. | `string` | `"anyscale-"` | no | -| [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID. Default is `null`. | `string` | `null` | no | | [anyscale\_project\_id](#input\_anyscale\_project\_id) | (Optional) The ID of the project to create the resource in. If not provided, the provider project is used. Default is `null`. | `string` | `null` | no | | [bucket\_encryption\_key\_name](#input\_bucket\_encryption\_key\_name) | (Optional) The encryption key name that should be used to encrypt this bucket. Default is `null`. | `string` | `null` | no | | [bucket\_force\_destroy](#input\_bucket\_force\_destroy) | (Optional) Determines if the contents of the bucket will be deleted when a `terraform destroy` command is issued. Default is `false`. | `bool` | `false` | no | diff --git a/modules/google-anyscale-cloudstorage/variables.tf b/modules/google-anyscale-cloudstorage/variables.tf index 45b74d2..3001f82 100644 --- a/modules/google-anyscale-cloudstorage/variables.tf +++ b/modules/google-anyscale-cloudstorage/variables.tf @@ -8,21 +8,6 @@ # OPTIONAL PARAMETERS # These variables have defaults, but may be overridden. # ------------------------------------------------------------------------------ -variable "anyscale_cloud_id" { - description = "(Optional) Anyscale Cloud ID. Default is `null`." - type = string - default = null - validation { - condition = ( - var.anyscale_cloud_id == null ? true : ( - length(var.anyscale_cloud_id) > 4 && - substr(var.anyscale_cloud_id, 0, 4) == "cld_" - ) - ) - error_message = "The anyscale_cloud_id value must start with \"cld_\"." - } -} - variable "module_enabled" { description = "(Optional) Whether to create the resources inside this module. Default is `true`." type = bool diff --git a/modules/google-anyscale-filestore/README.md b/modules/google-anyscale-filestore/README.md index d916272..5d0591d 100644 --- a/modules/google-anyscale-filestore/README.md +++ b/modules/google-anyscale-filestore/README.md @@ -16,8 +16,8 @@ | Name | Version | |------|---------| -| [google](#provider\_google) | 4.82.0 | -| [random](#provider\_random) | 3.5.1 | +| [google](#provider\_google) | 4.84.0 | +| [random](#provider\_random) | 3.6.0 | ## Modules diff --git a/modules/google-anyscale-iam/README.md b/modules/google-anyscale-iam/README.md index 87c2f79..b8b5b3d 100644 --- a/modules/google-anyscale-iam/README.md +++ b/modules/google-anyscale-iam/README.md @@ -17,7 +17,7 @@ | Name | Version | |------|---------| | [google](#provider\_google) | 4.84.0 | -| [random](#provider\_random) | 3.5.1 | +| [random](#provider\_random) | 3.6.0 | ## Modules @@ -29,12 +29,14 @@ No modules. |------|------| | [google_iam_workload_identity_pool.anyscale_pool](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool) | resource | | [google_iam_workload_identity_pool_provider.anyscale_pool](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool_provider) | resource | -| [google_project_iam_binding.anyscale_cluster_node_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_binding) | resource | -| [google_project_iam_member.anyscale_access_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource | -| [google_service_account.anyscale_access_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource | -| [google_service_account.anyscale_cluster_node_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource | -| [google_service_account_iam_binding.anyscale_access_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_binding) | resource | +| [google_project_iam_binding.anyscale_cluster_node_service_acct](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_binding) | resource | +| [google_project_iam_custom_role.anyscale_access_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_custom_role) | resource | +| [google_project_iam_member.anyscale_access_service_acct](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource | +| [google_service_account.anyscale_access_service_acct](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource | +| [google_service_account.anyscale_cluster_node_service_acct](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource | +| [google_service_account_iam_binding.anyscale_access_service_acct](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_binding) | resource | | [google_service_account_iam_binding.anyscale_workload_identity_user](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_binding) | resource | +| [google_service_account_iam_member.anyscale_cluster_node_service_acct](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_member) | resource | | [random_id.random_char_suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource | ## Inputs @@ -42,22 +44,26 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [anyscale\_access\_aws\_account\_id](#input\_anyscale\_access\_aws\_account\_id) | (Optional) The AWS account ID to grant access to. This will be overridden by `workload_anyscale_aws_account_id`. Default is `525325868955`. | `string` | `"525325868955"` | no | -| [anyscale\_access\_role\_binding\_permissions](#input\_anyscale\_access\_role\_binding\_permissions) | (Optional) A list of permission roles to grant to the Anyscale IAM access role at the Service Account level.
Default is `["roles/iam.serviceAccountTokenCreator"]`. | `list(string)` |
[
"roles/iam.serviceAccountTokenCreator"
]
| no | -| [anyscale\_access\_role\_description](#input\_anyscale\_access\_role\_description) | (Optional) Anyscale IAM access role description. If this is `null` the description will be set to "Anyscale access role". Default is `null`. | `string` | `null` | no | -| [anyscale\_access\_role\_name](#input\_anyscale\_access\_role\_name) | (Optional, forces creation of new resource) The name of the Anyscale IAM access role. Conflicts with anyscale\_access\_role\_name\_prefix. Default is `null`. | `string` | `null` | no | -| [anyscale\_access\_role\_name\_prefix](#input\_anyscale\_access\_role\_name\_prefix) | (Optional, forces creation of new resource) The prefix of the Anyscale IAM access role. Conflicts with anyscale\_access\_role\_name. Default is `anyscale-iam-role-`. | `string` | `"anyscale-crossacct-role-"` | no | -| [anyscale\_access\_role\_project\_permissions](#input\_anyscale\_access\_role\_project\_permissions) | (Optional) A list of permission roles to grant to the Anyscale IAM access role at the project level.
Default is `["roles/owner"]`. | `list(string)` |
[
"roles/owner"
]
| no | +| [anyscale\_access\_role\_description](#input\_anyscale\_access\_role\_description) | (Optional) Anyscale IAM access role description.

ex:
anyscale_access_role_description = "Anyscale access role"
| `string` | `"Anyscale access role"` | no | +| [anyscale\_access\_role\_id](#input\_anyscale\_access\_role\_id) | (Optional, forces creation of new resource) The ID of the Anyscale IAM access role.

Overrides `anyscale_access_role_id_prefix`.

ex:
anyscale_access_role_id = "anyscale_access_role"
| `string` | `null` | no | +| [anyscale\_access\_role\_id\_prefix](#input\_anyscale\_access\_role\_id\_prefix) | (Optional, forces creation of new resource) The prefix of the Anyscale IAM access role.

If `anyscale_access_role_id` is provided, it will override this variable.
If set to `null`, the prefix will be set to \"anyscale\_\" in a local variable.

ex:
anyscale_access_role_id_prefix = "anyscale_crossacct_role_"
| `string` | `"anyscale_crossacct_role_"` | no | +| [anyscale\_access\_service\_acct\_binding\_permissions](#input\_anyscale\_access\_service\_acct\_binding\_permissions) | (Optional) A list of permission roles to grant to the Anyscale IAM access service account at the Service Account level.
Default is `["roles/iam.serviceAccountTokenCreator"]`. | `list(string)` |
[
"roles/iam.serviceAccountTokenCreator"
]
| no | +| [anyscale\_access\_service\_acct\_description](#input\_anyscale\_access\_service\_acct\_description) | (Optional) Anyscale IAM access service account description.

If this is `null` the description will be set to \"Anyscale access service account\" in a local variable.

ex:
anyscale_access_service_acct_description = "Anyscale access service account"
| `string` | `null` | no | +| [anyscale\_access\_service\_acct\_name](#input\_anyscale\_access\_service\_acct\_name) | (Optional, forces creation of new resource)
The name of the Anyscale IAM access service account.

Overrides `anyscale_access_service_acct_name_prefix`.

ex:
anyscale_access_service_acct_name = "anyscale-access-service-acct"
| `string` | `null` | no | +| [anyscale\_access\_service\_acct\_name\_prefix](#input\_anyscale\_access\_service\_acct\_name\_prefix) | (Optional, forces creation of new resource)
The prefix of the Anyscale IAM access service account.

Conflicts with anyscale\_access\_service\_acct\_name.

ex:
anyscale_access_service_acct_name_prefix = "anyscale-access-"
| `string` | `"anyscale-crossacct-"` | no | | [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID | `string` | `null` | no | -| [anyscale\_cluster\_node\_role\_description](#input\_anyscale\_cluster\_node\_role\_description) | (Optional) IAM cluster node role description.

If this is `null` the description will be set to `Anyscale cluster node role` in a local variable.

ex:
anyscale_cluster_node_role_description = "Anyscale cluster node role for cloud"
| `string` | `null` | no | -| [anyscale\_cluster\_node\_role\_name](#input\_anyscale\_cluster\_node\_role\_name) | (Optional, forces creation of new resource) The name of the Anyscale IAM cluster node role.

Overrides `anyscale_cluster_node_role_name_prefix`.

ex:
anyscale_cluster_node_role_name = "anyscale-cluster-node-role"
| `string` | `null` | no | -| [anyscale\_cluster\_node\_role\_name\_prefix](#input\_anyscale\_cluster\_node\_role\_name\_prefix) | (Optional, forces creation of new resource) The prefix of the Anyscale IAM access role.

If `anyscale_cluster_role_node_name` is provided, it will override this variable.

ex:
anyscale_cluster_node_role_name_prefix = "anyscale-cluster-"
| `string` | `"anyscale-cluster-"` | no | -| [anyscale\_cluster\_node\_role\_permissions](#input\_anyscale\_cluster\_node\_role\_permissions) | (Optional) A list of permission roles to grant to the Anyscale IAM cluster node role.

ex:
anyscale_cluster_node_role_permissions = ["roles/artifactregistry.reader"]
| `list(string)` |
[
"roles/artifactregistry.reader"
]
| no | +| [anyscale\_cluster\_node\_service\_acct\_description](#input\_anyscale\_cluster\_node\_service\_acct\_description) | (Optional) IAM cluster node service account description.

If this is `null` the description will be set to `Anyscale cluster node service account` in a local variable.

ex:
anyscale_cluster_node_service_acct_description = "Anyscale cluster node service account for cloud"
| `string` | `null` | no | +| [anyscale\_cluster\_node\_service\_acct\_name](#input\_anyscale\_cluster\_node\_service\_acct\_name) | (Optional, forces creation of new resource) The name of the Anyscale IAM cluster node service account.

Overrides `anyscale_cluster_node_service_acct_name_prefix`.

ex:
anyscale_cluster_node_service_acct_name = "anyscale-cluster-acct"
| `string` | `null` | no | +| [anyscale\_cluster\_node\_service\_acct\_name\_prefix](#input\_anyscale\_cluster\_node\_service\_acct\_name\_prefix) | (Optional, forces creation of new resource) The prefix of the Anyscale IAM cluster service account.

If `anyscale_cluster_node_service_acct_name` is provided, it will override this variable.

ex:
anyscale_cluster_node_service_acct_name_prefix = "anyscale-cluster-"
| `string` | `"anyscale-cluster-"` | no | +| [anyscale\_cluster\_node\_service\_acct\_permissions](#input\_anyscale\_cluster\_node\_service\_acct\_permissions) | (Optional) A list of permission roles to grant to the Anyscale IAM cluster node service account.

ex:
anyscale_cluster_node_service_acct_permissions = ["roles/artifactregistry.reader"]
| `list(string)` |
[
"roles/artifactregistry.reader"
]
| no | | [anyscale\_org\_id](#input\_anyscale\_org\_id) | (Required) Anyscale Organization ID | `string` | n/a | yes | | [anyscale\_project\_id](#input\_anyscale\_project\_id) | (Optional) The ID of the project to create the resource in. If not provided, the provider project is used. Default is `null`. | `string` | `null` | no | -| [create\_anyscale\_access\_role](#input\_create\_anyscale\_access\_role) | (Optional) Determines whether to create the Anyscale access role. Default is `true`. | `bool` | `true` | no | -| [create\_anyscale\_cluster\_node\_role](#input\_create\_anyscale\_cluster\_node\_role) | (Optional) Determines whether to create the Anyscale cluster role.

ex:
create_anyscale_cluster_node_role = true
| `bool` | `true` | no | +| [create\_anyscale\_access\_role](#input\_create\_anyscale\_access\_role) | (Optional) Determines whether to create the Anyscale access role.

ex:
create_anyscale_access_role = true
| `bool` | `true` | no | +| [create\_anyscale\_access\_service\_acct](#input\_create\_anyscale\_access\_service\_acct) | (Optional) Determines whether to create the Anyscale access service account. Default is `true`. | `bool` | `true` | no | +| [create\_anyscale\_cluster\_node\_service\_acct](#input\_create\_anyscale\_cluster\_node\_service\_acct) | (Optional) Determines whether to create the Anyscale cluster service account.

ex:
create_anyscale_cluster_node_service_acct = true
| `bool` | `true` | no | | [enable\_anyscale\_cluster\_logging\_monitoring](#input\_enable\_anyscale\_cluster\_logging\_monitoring) | (Optional) Determines whether to grant the Cluster Node access to the monitoring and logging.

ex:
enable_anyscale_cluster_logging_monitoring = true
| `bool` | `false` | no | | [enable\_random\_name\_suffix](#input\_enable\_random\_name\_suffix) | (Optional) Determines if a suffix of random characters will be added to the Anyscale resources.
Default is `true` | `bool` | `true` | no | +| [existing\_anyscale\_access\_role\_name](#input\_existing\_anyscale\_access\_role\_name) | (Optional) The name of an existing Anyscale IAM access role to use.

If provided, will skip creating the Anyscale access role.

ex:
existing_anyscale_access_role_name = "projects/1234567890/roles/anyscale_access_role"
| `string` | `null` | no | | [existing\_workload\_identity\_provider\_name](#input\_existing\_workload\_identity\_provider\_name) | (Optional) The name of an existing workload identity provider to use.

If provided, will skip creating the workload identity pool and provider.

You can retrieve the name of an existing Workload Identity Provider by running the following command:
gcloud iam workload-identity-pools providers list --location global --workload-identity-pool anyscale-access-pool
ex:
existing_workload_identity_provider_name = "projects/1234567890/locations/global/workloadIdentityPools/anyscale-access-pool/providers/anyscale-access-provider"
 | `string` | `null` | no |
 |  [google\_region](#input\_google\_region) | (Optional) The Google region in which all resources will be created. If it is not provided, the provider region is used. Default is `null`. | `string` | `null` | no |
 |  [module\_enabled](#input\_module\_enabled) | (Optional) Determines whether to create the resources inside this module. Default is `true`. | `bool` | `true` | no |
@@ -65,21 +71,21 @@ No modules.
 |  [workload\_anyscale\_aws\_account\_id](#input\_workload\_anyscale\_aws\_account\_id) | (Optional) The AWS account ID to grant access to. This will override the `anyscale_access_aws_account_id` which is the default account ID to use. Default is `null`. | `string` | `null` | no |
 |  [workload\_identity\_pool\_description](#input\_workload\_identity\_pool\_description) | (Optional) The description of the workload identity pool. Default is `Used to provide Anyscale access from AWS.`. | `string` | `"Used to provide Anyscale access from AWS."` | no |
 |  [workload\_identity\_pool\_display\_name](#input\_workload\_identity\_pool\_display\_name) | (Optional) The display name of the workload identity pool. Must be less than or equal to 32 chars. Default is `Anyscale Cross Account AWS Access`. | `string` | `"Anyscale Cross Account Access"` | no |
-|  [workload\_identity\_pool\_name](#input\_workload\_identity\_pool\_name) | (Optional) The name of the workload identity pool. If it is not provided, the Anyscale Access role name is used. Default is `null`. | `string` | `null` | no |
-|  [workload\_identity\_pool\_provider\_name](#input\_workload\_identity\_pool\_provider\_name) | (Optional) The name of the workload identity pool provider. If it is not provided, the Anyscale Access role name is used. Default is `null`. | `string` | `null` | no |
+|  [workload\_identity\_pool\_name](#input\_workload\_identity\_pool\_name) | (Optional) The name of the workload identity pool. If it is not provided, the Anyscale Access service account name is used. Default is `null`. | `string` | `null` | no |
+|  [workload\_identity\_pool\_provider\_name](#input\_workload\_identity\_pool\_provider\_name) | (Optional) The name of the workload identity pool provider. If it is not provided, the Anyscale Access service account name is used. Default is `null`. | `string` | `null` | no |
 
 ## Outputs
 
 | Name | Description |
 |------|-------------|
-|  [iam\_anyscale\_access\_role\_email](#output\_iam\_anyscale\_access\_role\_email) | Anyscale cross account access role email |
-|  [iam\_anyscale\_access\_role\_id](#output\_iam\_anyscale\_access\_role\_id) | Anyscale cross account access role ID |
-|  [iam\_anyscale\_access\_role\_name](#output\_iam\_anyscale\_access\_role\_name) | Anyscale cross account access role name |
-|  [iam\_anyscale\_access\_role\_unique\_id](#output\_iam\_anyscale\_access\_role\_unique\_id) | Anyscale cross account access role unique ID |
-|  [iam\_anyscale\_cluster\_node\_role\_email](#output\_iam\_anyscale\_cluster\_node\_role\_email) | Anyscale cross account cluster node role email |
-|  [iam\_anyscale\_cluster\_node\_role\_id](#output\_iam\_anyscale\_cluster\_node\_role\_id) | Anyscale cross account cluster node role ID |
-|  [iam\_anyscale\_cluster\_node\_role\_name](#output\_iam\_anyscale\_cluster\_node\_role\_name) | Anyscale cross account cluster node role name |
-|  [iam\_anyscale\_cluster\_node\_role\_unique\_id](#output\_iam\_anyscale\_cluster\_node\_role\_unique\_id) | Anyscale cross account cluster node role unique ID |
+|  [iam\_anyscale\_access\_service\_acct\_email](#output\_iam\_anyscale\_access\_service\_acct\_email) | Anyscale cross account access service account email |
+|  [iam\_anyscale\_access\_service\_acct\_id](#output\_iam\_anyscale\_access\_service\_acct\_id) | Anyscale cross account access service account ID |
+|  [iam\_anyscale\_access\_service\_acct\_name](#output\_iam\_anyscale\_access\_service\_acct\_name) | Anyscale cross account access service account name |
+|  [iam\_anyscale\_access\_service\_acct\_unique\_id](#output\_iam\_anyscale\_access\_service\_acct\_unique\_id) | Anyscale cross account access service account unique ID |
+|  [iam\_anyscale\_cluster\_node\_service\_acct\_email](#output\_iam\_anyscale\_cluster\_node\_service\_acct\_email) | Anyscale cross account cluster node service account email |
+|  [iam\_anyscale\_cluster\_node\_service\_acct\_id](#output\_iam\_anyscale\_cluster\_node\_service\_acct\_id) | Anyscale cross account cluster node service account ID |
+|  [iam\_anyscale\_cluster\_node\_service\_acct\_name](#output\_iam\_anyscale\_cluster\_node\_service\_acct\_name) | Anyscale cross account cluster node service account name |
+|  [iam\_anyscale\_cluster\_node\_service\_acct\_unique\_id](#output\_iam\_anyscale\_cluster\_node\_service\_acct\_unique\_id) | Anyscale cross account cluster node service account unique ID |
 |  [iam\_workload\_identity\_pool\_id](#output\_iam\_workload\_identity\_pool\_id) | Anyscale cross account workload identity pool ID |
 |  [iam\_workload\_identity\_pool\_name](#output\_iam\_workload\_identity\_pool\_name) | Anyscale cross account workload identity pool name |
 |  [iam\_workload\_identity\_provider\_id](#output\_iam\_workload\_identity\_provider\_id) | Anyscale cross account workload identity provider ID |
diff --git a/modules/google-anyscale-iam/examples/README.md b/modules/google-anyscale-iam/examples/README.md
index d5d08c3..9079c2f 100644
--- a/modules/google-anyscale-iam/examples/README.md
+++ b/modules/google-anyscale-iam/examples/README.md
@@ -29,7 +29,6 @@ No resources.
 
 | Name | Description | Type | Default | Required |
 |------|-------------|------|---------|:--------:|
-|  [anyscale\_deploy\_env](#input\_anyscale\_deploy\_env) | (Required) Anyscale deploy environment. Used in resource names and tags. | `string` | n/a | yes |
 |  [anyscale\_organization\_id](#input\_anyscale\_organization\_id) | (Required) Anyscale Organization ID | `string` | n/a | yes |
 |  [existing\_workload\_identity\_provider\_name](#input\_existing\_workload\_identity\_provider\_name) | (Optional) Existing Workload Identity Provider Name.

The name of an existing Workload Identity Provider that you'd like to use. This can be in a different project.
If provided, this will skip creating a new Workload Identity Provider with the Anyscale IAM module.

ex:
existing_workload_identity_provider_name = "projects/1234567890/locations/global/workloadIdentityPools/anyscale-existing-pool/providers/anyscale-existing-provider"
| `string` | `null` | no | | [google\_project\_id](#input\_google\_project\_id) | ID of the Project to put these resources in | `string` | n/a | yes | @@ -38,29 +37,29 @@ No resources. | Name | Description | |------|-------------| -| [all\_defaults\_access\_role\_email](#output\_all\_defaults\_access\_role\_email) | All Defaults - Anyscale cross account access role email | -| [all\_defaults\_access\_role\_id](#output\_all\_defaults\_access\_role\_id) | All Defaults - Anyscale cross account access role ID | -| [all\_defaults\_access\_role\_name](#output\_all\_defaults\_access\_role\_name) | All Defaults - Anyscale cross account access role name | -| [all\_defaults\_access\_role\_unique\_id](#output\_all\_defaults\_access\_role\_unique\_id) | All Defaults - Anyscale cross account access role unique ID | -| [all\_defaults\_cluster\_node\_role\_email](#output\_all\_defaults\_cluster\_node\_role\_email) | All Defaults - Anyscale cluster node role email | -| [all\_defaults\_cluster\_node\_role\_id](#output\_all\_defaults\_cluster\_node\_role\_id) | All Defaults - Anyscale cluster node role ID | -| [all\_defaults\_cluster\_node\_role\_name](#output\_all\_defaults\_cluster\_node\_role\_name) | All Defaults - Anyscale cluster node role name | -| [all\_defaults\_cluster\_node\_role\_unique\_id](#output\_all\_defaults\_cluster\_node\_role\_unique\_id) | All Defaults - Anyscale cluster node role unique ID | -| [iam\_cluster\_node\_only\_role\_access\_role\_email](#output\_iam\_cluster\_node\_only\_role\_access\_role\_email) | Cluster Node Only - Anyscale cross account access role email | -| [iam\_cluster\_node\_only\_role\_access\_role\_id](#output\_iam\_cluster\_node\_only\_role\_access\_role\_id) | Cluster Node Only - Anyscale cross account access role ID | -| [iam\_cluster\_node\_only\_role\_access\_role\_name](#output\_iam\_cluster\_node\_only\_role\_access\_role\_name) | Cluster Node Only - Anyscale cross account access role name | -| [iam\_cluster\_node\_only\_role\_access\_role\_unique\_id](#output\_iam\_cluster\_node\_only\_role\_access\_role\_unique\_id) | Cluster Node Only - Anyscale cross account access role unique ID | -| [iam\_cluster\_node\_only\_role\_cluster\_node\_role\_email](#output\_iam\_cluster\_node\_only\_role\_cluster\_node\_role\_email) | Cluster Node Only - Anyscale cluster node role email | -| [iam\_cluster\_node\_only\_role\_cluster\_node\_role\_id](#output\_iam\_cluster\_node\_only\_role\_cluster\_node\_role\_id) | Cluster Node Only - Anyscale cluster node role ID | -| [iam\_cluster\_node\_only\_role\_cluster\_node\_role\_name](#output\_iam\_cluster\_node\_only\_role\_cluster\_node\_role\_name) | Cluster Node Only - Anyscale cluster node role name | -| [iam\_cluster\_node\_only\_role\_cluster\_node\_role\_unique\_id](#output\_iam\_cluster\_node\_only\_role\_cluster\_node\_role\_unique\_id) | Cluster Node Only - Anyscale cluster node role unique ID | -| [kitchen\_sink\_access\_role\_email](#output\_kitchen\_sink\_access\_role\_email) | Kitchen Sink - Anyscale cross account access role email | -| [kitchen\_sink\_access\_role\_id](#output\_kitchen\_sink\_access\_role\_id) | Kitchen Sink - Anyscale cross account access role ID | -| [kitchen\_sink\_access\_role\_name](#output\_kitchen\_sink\_access\_role\_name) | Kitchen Sink - Anyscale cross account access role name | -| [kitchen\_sink\_access\_role\_unique\_id](#output\_kitchen\_sink\_access\_role\_unique\_id) | Kitchen Sink - Anyscale cross account access role unique ID | -| [kitchen\_sink\_cluster\_node\_role\_email](#output\_kitchen\_sink\_cluster\_node\_role\_email) | Kitchen Sink - Anyscale cluster node role email | -| [kitchen\_sink\_cluster\_node\_role\_id](#output\_kitchen\_sink\_cluster\_node\_role\_id) | Kitchen Sink - Anyscale cluster node role ID | -| [kitchen\_sink\_cluster\_node\_role\_name](#output\_kitchen\_sink\_cluster\_node\_role\_name) | Kitchen Sink - Anyscale cluster node role name | -| [kitchen\_sink\_cluster\_node\_role\_unique\_id](#output\_kitchen\_sink\_cluster\_node\_role\_unique\_id) | Kitchen Sink - Anyscale cluster node role unique ID | +| [all\_defaults\_access\_role\_email](#output\_all\_defaults\_access\_role\_email) | All Defaults - Anyscale cross account access Service Account email | +| [all\_defaults\_access\_role\_id](#output\_all\_defaults\_access\_role\_id) | All Defaults - Anyscale cross account access Service Account ID | +| [all\_defaults\_access\_role\_name](#output\_all\_defaults\_access\_role\_name) | All Defaults - Anyscale cross account access Service Account name | +| [all\_defaults\_access\_role\_unique\_id](#output\_all\_defaults\_access\_role\_unique\_id) | All Defaults - Anyscale cross account access Service Account unique ID | +| [all\_defaults\_cluster\_node\_service\_acct\_email](#output\_all\_defaults\_cluster\_node\_service\_acct\_email) | All Defaults - Anyscale cluster node Service Account email | +| [all\_defaults\_cluster\_node\_service\_acct\_id](#output\_all\_defaults\_cluster\_node\_service\_acct\_id) | All Defaults - Anyscale cluster node Service Account ID | +| [all\_defaults\_cluster\_node\_service\_acct\_name](#output\_all\_defaults\_cluster\_node\_service\_acct\_name) | All Defaults - Anyscale cluster node Service Account name | +| [all\_defaults\_cluster\_node\_service\_acct\_unique\_id](#output\_all\_defaults\_cluster\_node\_service\_acct\_unique\_id) | All Defaults - Anyscale cluster node Service Account unique ID | +| [iam\_cluster\_node\_only\_role\_access\_role\_email](#output\_iam\_cluster\_node\_only\_role\_access\_role\_email) | Cluster Node Only - Anyscale cross account access Service Account email | +| [iam\_cluster\_node\_only\_role\_access\_role\_id](#output\_iam\_cluster\_node\_only\_role\_access\_role\_id) | Cluster Node Only - Anyscale cross account access Service Account ID | +| [iam\_cluster\_node\_only\_role\_access\_role\_name](#output\_iam\_cluster\_node\_only\_role\_access\_role\_name) | Cluster Node Only - Anyscale cross account access Service Account name | +| [iam\_cluster\_node\_only\_role\_access\_role\_unique\_id](#output\_iam\_cluster\_node\_only\_role\_access\_role\_unique\_id) | Cluster Node Only - Anyscale cross account access Service Account unique ID | +| [iam\_cluster\_node\_only\_role\_cluster\_node\_service\_acct\_email](#output\_iam\_cluster\_node\_only\_role\_cluster\_node\_service\_acct\_email) | Cluster Node Only - Anyscale cluster node Service Account email | +| [iam\_cluster\_node\_only\_role\_cluster\_node\_service\_acct\_id](#output\_iam\_cluster\_node\_only\_role\_cluster\_node\_service\_acct\_id) | Cluster Node Only - Anyscale cluster node Service Account ID | +| [iam\_cluster\_node\_only\_role\_cluster\_node\_service\_acct\_name](#output\_iam\_cluster\_node\_only\_role\_cluster\_node\_service\_acct\_name) | Cluster Node Only - Anyscale cluster node Service Account name | +| [iam\_cluster\_node\_only\_role\_cluster\_node\_service\_acct\_unique\_id](#output\_iam\_cluster\_node\_only\_role\_cluster\_node\_service\_acct\_unique\_id) | Cluster Node Only - Anyscale cluster node Service Account unique ID | +| [kitchen\_sink\_access\_role\_email](#output\_kitchen\_sink\_access\_role\_email) | Kitchen Sink - Anyscale cross account access Service Account email | +| [kitchen\_sink\_access\_role\_id](#output\_kitchen\_sink\_access\_role\_id) | Kitchen Sink - Anyscale cross account access Service Account ID | +| [kitchen\_sink\_access\_role\_name](#output\_kitchen\_sink\_access\_role\_name) | Kitchen Sink - Anyscale cross account access Service Account name | +| [kitchen\_sink\_access\_role\_unique\_id](#output\_kitchen\_sink\_access\_role\_unique\_id) | Kitchen Sink - Anyscale cross account access Service Account unique ID | +| [kitchen\_sink\_cluster\_node\_service\_acct\_email](#output\_kitchen\_sink\_cluster\_node\_service\_acct\_email) | Kitchen Sink - Anyscale cluster node Service Account email | +| [kitchen\_sink\_cluster\_node\_service\_acct\_id](#output\_kitchen\_sink\_cluster\_node\_service\_acct\_id) | Kitchen Sink - Anyscale cluster node Service Account ID | +| [kitchen\_sink\_cluster\_node\_service\_acct\_name](#output\_kitchen\_sink\_cluster\_node\_service\_acct\_name) | Kitchen Sink - Anyscale cluster node Service Account name | +| [kitchen\_sink\_cluster\_node\_service\_acct\_unique\_id](#output\_kitchen\_sink\_cluster\_node\_service\_acct\_unique\_id) | Kitchen Sink - Anyscale cluster node Service Account unique ID | | [test\_no\_resources](#output\_test\_no\_resources) | The outputs of the no\_resource resource - should be empty | diff --git a/modules/google-anyscale-iam/examples/main.tf b/modules/google-anyscale-iam/examples/main.tf index 0c43891..2834f8a 100644 --- a/modules/google-anyscale-iam/examples/main.tf +++ b/modules/google-anyscale-iam/examples/main.tf @@ -20,11 +20,10 @@ module "iam_cluster_node_only_role" { source = "../" module_enabled = true - anyscale_org_id = var.anyscale_organization_id - anyscale_project_id = var.google_project_id - create_anyscale_access_role = false - create_anyscale_cluster_node_role = true - anyscale_cluster_node_role_name_prefix = "cluster-node-only-" + anyscale_org_id = var.anyscale_organization_id + anyscale_project_id = var.google_project_id + create_anyscale_access_role = false + anyscale_cluster_node_service_acct_name_prefix = "cluster-node-only-" random_char_length = 8 } @@ -41,11 +40,10 @@ module "kitchen_sink" { anyscale_org_id = var.anyscale_organization_id anyscale_project_id = var.google_project_id - enable_random_name_suffix = false - anyscale_access_role_name = "kitchen-sink-role" - anyscale_access_role_description = "Anyscale cross account access role for kitchen sink test" - anyscale_access_role_project_permissions = ["roles/editor"] - anyscale_access_role_binding_permissions = ["roles/iam.serviceAccountUser"] + enable_random_name_suffix = false + anyscale_access_service_acct_name = "kitchen-sink-role" + anyscale_access_service_acct_description = "Anyscale cross account access role for kitchen sink test" + anyscale_access_service_acct_binding_permissions = ["roles/iam.serviceAccountUser"] existing_workload_identity_provider_name = var.existing_workload_identity_provider_name # workload_identity_pool_name = "anyscale-kitchen-sink-pool" @@ -54,9 +52,9 @@ module "kitchen_sink" { # workload_identity_pool_provider_name = "anyscale-kitchen-sink-provider" # anyscale_access_aws_account_id = "623395924981" - anyscale_cluster_node_role_name = "kitchen-sink-cluster-node-role" - anyscale_cluster_node_role_description = "Anyscale cluster node role for kitchen sink test" - anyscale_cluster_node_role_permissions = ["roles/compute.instanceAdmin.v1"] + anyscale_cluster_node_service_acct_name = "kitchen-sink-cluster-node-role" + anyscale_cluster_node_service_acct_description = "Anyscale cluster node role for kitchen sink test" + anyscale_cluster_node_service_acct_permissions = ["roles/compute.instanceAdmin.v1"] enable_anyscale_cluster_logging_monitoring = true } diff --git a/modules/google-anyscale-iam/examples/outputs.tf b/modules/google-anyscale-iam/examples/outputs.tf index 461c47a..cec96bf 100644 --- a/modules/google-anyscale-iam/examples/outputs.tf +++ b/modules/google-anyscale-iam/examples/outputs.tf @@ -2,86 +2,86 @@ # All Defaults Test # ------------------------------------------- output "all_defaults_access_role_id" { - description = "All Defaults - Anyscale cross account access role ID" - value = module.all_defaults.iam_anyscale_access_role_id + description = "All Defaults - Anyscale cross account access Service Account ID" + value = module.all_defaults.iam_anyscale_access_service_acct_id } output "all_defaults_access_role_email" { - description = "All Defaults - Anyscale cross account access role email" - value = module.all_defaults.iam_anyscale_access_role_email + description = "All Defaults - Anyscale cross account access Service Account email" + value = module.all_defaults.iam_anyscale_access_service_acct_email } output "all_defaults_access_role_name" { - description = "All Defaults - Anyscale cross account access role name" - value = module.all_defaults.iam_anyscale_access_role_name + description = "All Defaults - Anyscale cross account access Service Account name" + value = module.all_defaults.iam_anyscale_access_service_acct_name } output "all_defaults_access_role_unique_id" { - description = "All Defaults - Anyscale cross account access role unique ID" - value = module.all_defaults.iam_anyscale_access_role_unique_id + description = "All Defaults - Anyscale cross account access Service Account unique ID" + value = module.all_defaults.iam_anyscale_access_service_acct_unique_id } -output "all_defaults_cluster_node_role_id" { - description = "All Defaults - Anyscale cluster node role ID" - value = module.all_defaults.iam_anyscale_cluster_node_role_id +output "all_defaults_cluster_node_service_acct_id" { + description = "All Defaults - Anyscale cluster node Service Account ID" + value = module.all_defaults.iam_anyscale_cluster_node_service_acct_id } -output "all_defaults_cluster_node_role_email" { - description = "All Defaults - Anyscale cluster node role email" - value = module.all_defaults.iam_anyscale_cluster_node_role_email +output "all_defaults_cluster_node_service_acct_email" { + description = "All Defaults - Anyscale cluster node Service Account email" + value = module.all_defaults.iam_anyscale_cluster_node_service_acct_email } -output "all_defaults_cluster_node_role_name" { - description = "All Defaults - Anyscale cluster node role name" - value = module.all_defaults.iam_anyscale_cluster_node_role_name +output "all_defaults_cluster_node_service_acct_name" { + description = "All Defaults - Anyscale cluster node Service Account name" + value = module.all_defaults.iam_anyscale_cluster_node_service_acct_name } -output "all_defaults_cluster_node_role_unique_id" { - description = "All Defaults - Anyscale cluster node role unique ID" - value = module.all_defaults.iam_anyscale_cluster_node_role_unique_id +output "all_defaults_cluster_node_service_acct_unique_id" { + description = "All Defaults - Anyscale cluster node Service Account unique ID" + value = module.all_defaults.iam_anyscale_cluster_node_service_acct_unique_id } # ------------------------------------------- # IAM Cluster Node Only Test # ------------------------------------------- output "iam_cluster_node_only_role_access_role_id" { - description = "Cluster Node Only - Anyscale cross account access role ID" - value = module.iam_cluster_node_only_role.iam_anyscale_access_role_id + description = "Cluster Node Only - Anyscale cross account access Service Account ID" + value = module.iam_cluster_node_only_role.iam_anyscale_access_service_acct_id } output "iam_cluster_node_only_role_access_role_email" { - description = "Cluster Node Only - Anyscale cross account access role email" - value = module.iam_cluster_node_only_role.iam_anyscale_access_role_email + description = "Cluster Node Only - Anyscale cross account access Service Account email" + value = module.iam_cluster_node_only_role.iam_anyscale_access_service_acct_email } output "iam_cluster_node_only_role_access_role_name" { - description = "Cluster Node Only - Anyscale cross account access role name" - value = module.iam_cluster_node_only_role.iam_anyscale_access_role_name + description = "Cluster Node Only - Anyscale cross account access Service Account name" + value = module.iam_cluster_node_only_role.iam_anyscale_access_service_acct_name } output "iam_cluster_node_only_role_access_role_unique_id" { - description = "Cluster Node Only - Anyscale cross account access role unique ID" - value = module.iam_cluster_node_only_role.iam_anyscale_access_role_unique_id + description = "Cluster Node Only - Anyscale cross account access Service Account unique ID" + value = module.iam_cluster_node_only_role.iam_anyscale_access_service_acct_unique_id } -output "iam_cluster_node_only_role_cluster_node_role_id" { - description = "Cluster Node Only - Anyscale cluster node role ID" - value = module.iam_cluster_node_only_role.iam_anyscale_cluster_node_role_id +output "iam_cluster_node_only_role_cluster_node_service_acct_id" { + description = "Cluster Node Only - Anyscale cluster node Service Account ID" + value = module.iam_cluster_node_only_role.iam_anyscale_cluster_node_service_acct_id } -output "iam_cluster_node_only_role_cluster_node_role_email" { - description = "Cluster Node Only - Anyscale cluster node role email" - value = module.iam_cluster_node_only_role.iam_anyscale_cluster_node_role_email +output "iam_cluster_node_only_role_cluster_node_service_acct_email" { + description = "Cluster Node Only - Anyscale cluster node Service Account email" + value = module.iam_cluster_node_only_role.iam_anyscale_cluster_node_service_acct_email } -output "iam_cluster_node_only_role_cluster_node_role_name" { - description = "Cluster Node Only - Anyscale cluster node role name" - value = module.iam_cluster_node_only_role.iam_anyscale_cluster_node_role_name +output "iam_cluster_node_only_role_cluster_node_service_acct_name" { + description = "Cluster Node Only - Anyscale cluster node Service Account name" + value = module.iam_cluster_node_only_role.iam_anyscale_cluster_node_service_acct_name } -output "iam_cluster_node_only_role_cluster_node_role_unique_id" { - description = "Cluster Node Only - Anyscale cluster node role unique ID" - value = module.iam_cluster_node_only_role.iam_anyscale_cluster_node_role_unique_id +output "iam_cluster_node_only_role_cluster_node_service_acct_unique_id" { + description = "Cluster Node Only - Anyscale cluster node Service Account unique ID" + value = module.iam_cluster_node_only_role.iam_anyscale_cluster_node_service_acct_unique_id } @@ -89,43 +89,43 @@ output "iam_cluster_node_only_role_cluster_node_role_unique_id" { # Kitchen Sink Test # ------------------------------------------- output "kitchen_sink_access_role_id" { - description = "Kitchen Sink - Anyscale cross account access role ID" - value = module.kitchen_sink.iam_anyscale_access_role_id + description = "Kitchen Sink - Anyscale cross account access Service Account ID" + value = module.kitchen_sink.iam_anyscale_access_service_acct_id } output "kitchen_sink_access_role_email" { - description = "Kitchen Sink - Anyscale cross account access role email" - value = module.kitchen_sink.iam_anyscale_access_role_email + description = "Kitchen Sink - Anyscale cross account access Service Account email" + value = module.kitchen_sink.iam_anyscale_access_service_acct_email } output "kitchen_sink_access_role_name" { - description = "Kitchen Sink - Anyscale cross account access role name" - value = module.kitchen_sink.iam_anyscale_access_role_name + description = "Kitchen Sink - Anyscale cross account access Service Account name" + value = module.kitchen_sink.iam_anyscale_access_service_acct_name } output "kitchen_sink_access_role_unique_id" { - description = "Kitchen Sink - Anyscale cross account access role unique ID" - value = module.kitchen_sink.iam_anyscale_access_role_unique_id + description = "Kitchen Sink - Anyscale cross account access Service Account unique ID" + value = module.kitchen_sink.iam_anyscale_access_service_acct_unique_id } -output "kitchen_sink_cluster_node_role_id" { - description = "Kitchen Sink - Anyscale cluster node role ID" - value = module.kitchen_sink.iam_anyscale_cluster_node_role_id +output "kitchen_sink_cluster_node_service_acct_id" { + description = "Kitchen Sink - Anyscale cluster node Service Account ID" + value = module.kitchen_sink.iam_anyscale_cluster_node_service_acct_id } -output "kitchen_sink_cluster_node_role_email" { - description = "Kitchen Sink - Anyscale cluster node role email" - value = module.kitchen_sink.iam_anyscale_cluster_node_role_email +output "kitchen_sink_cluster_node_service_acct_email" { + description = "Kitchen Sink - Anyscale cluster node Service Account email" + value = module.kitchen_sink.iam_anyscale_cluster_node_service_acct_email } -output "kitchen_sink_cluster_node_role_name" { - description = "Kitchen Sink - Anyscale cluster node role name" - value = module.kitchen_sink.iam_anyscale_cluster_node_role_name +output "kitchen_sink_cluster_node_service_acct_name" { + description = "Kitchen Sink - Anyscale cluster node Service Account name" + value = module.kitchen_sink.iam_anyscale_cluster_node_service_acct_name } -output "kitchen_sink_cluster_node_role_unique_id" { - description = "Kitchen Sink - Anyscale cluster node role unique ID" - value = module.kitchen_sink.iam_anyscale_cluster_node_role_unique_id +output "kitchen_sink_cluster_node_service_acct_unique_id" { + description = "Kitchen Sink - Anyscale cluster node Service Account unique ID" + value = module.kitchen_sink.iam_anyscale_cluster_node_service_acct_unique_id } # ----------------- diff --git a/modules/google-anyscale-iam/examples/variables.tf b/modules/google-anyscale-iam/examples/variables.tf index 4855075..7c0fa5e 100644 --- a/modules/google-anyscale-iam/examples/variables.tf +++ b/modules/google-anyscale-iam/examples/variables.tf @@ -8,17 +8,6 @@ # REQUIRED VARIABLES # These variables must be set when using this module. # --------------------------------------------------------------------------------------------------------------------- -variable "anyscale_deploy_env" { - description = "(Required) Anyscale deploy environment. Used in resource names and tags." - type = string - validation { - condition = ( - var.anyscale_deploy_env == "production" || var.anyscale_deploy_env == "development" || var.anyscale_deploy_env == "test" - ) - error_message = "The anyscale_deploy_env only allows `production`, `test`, or `development`" - } -} - variable "anyscale_organization_id" { description = "(Required) Anyscale Organization ID" type = string diff --git a/modules/google-anyscale-iam/main.tf b/modules/google-anyscale-iam/main.tf index c5aee89..e13b1cd 100644 --- a/modules/google-anyscale-iam/main.tf +++ b/modules/google-anyscale-iam/main.tf @@ -1,31 +1,31 @@ locals { random_char_length = var.random_char_length >= 4 && var.random_char_length % 2 == 0 ? var.random_char_length / 2 : 0 - anyscale_aws_account_id = var.workload_anyscale_aws_account_id != null ? var.workload_anyscale_aws_account_id : var.anyscale_access_aws_account_id - anyscale_access_role_enabled = var.module_enabled && var.create_anyscale_access_role ? true : false - - anyscale_access_role_desc_cloud = try("Anyscale access role for cloud ${var.anyscale_cloud_id} in region ${var.google_region}", "Anyscale access role for cloud ${var.anyscale_cloud_id}", null) - anyscale_access_role_desc = coalesce( - var.anyscale_access_role_description, - local.anyscale_access_role_desc_cloud, - "Anyscale access role" + anyscale_aws_account_id = var.workload_anyscale_aws_account_id != null ? var.workload_anyscale_aws_account_id : var.anyscale_access_aws_account_id + + anyscale_access_service_acct_enabled = var.module_enabled && var.create_anyscale_access_service_acct ? true : false + anyscale_access_service_acct_desc_cloud = var.anyscale_cloud_id != null ? "Anyscale access service account for cloud ${var.anyscale_cloud_id} in region ${var.google_region}" : null + anyscale_access_service_acct_desc = coalesce( + var.anyscale_access_service_acct_description, + local.anyscale_access_service_acct_desc_cloud, + "Anyscale access service account" ) - anyscale_access_role_name = coalesce(var.anyscale_access_role_name, var.anyscale_access_role_name_prefix, "anyscale-") - access_role_name_computed = var.enable_random_name_suffix ? format( + anyscale_access_service_acct_name = coalesce(var.anyscale_access_service_acct_name, var.anyscale_access_service_acct_name_prefix, "anyscale-") + access_acct_name_computed = var.enable_random_name_suffix ? format( "%s%s", - local.anyscale_access_role_name, + local.anyscale_access_service_acct_name, random_id.random_char_suffix.hex, - ) : local.anyscale_access_role_name + ) : local.anyscale_access_service_acct_name existing_provider_provided = var.existing_workload_identity_provider_name != null ? true : false - create_workload_identity_pool = local.anyscale_access_role_enabled && !local.existing_provider_provided ? true : false + create_workload_identity_pool = local.anyscale_access_service_acct_enabled && !local.existing_provider_provided ? true : false workload_identity_pool_crossacct_rolename = "gcp_if_${var.anyscale_org_id}" - workload_identity_pool_name_computed = coalesce(var.workload_identity_pool_name, local.access_role_name_computed) - workload_identity_pool_provider_name_computed = coalesce(var.workload_identity_pool_provider_name, local.access_role_name_computed) + workload_identity_pool_name_computed = coalesce(var.workload_identity_pool_name, local.access_acct_name_computed) + workload_identity_pool_provider_name_computed = coalesce(var.workload_identity_pool_provider_name, local.access_acct_name_computed) } # -------------------------------------------------------------- -# Random Strings for IAM Role Names +# Random Strings for IAM Names # -------------------------------------------------------------- resource "random_id" "random_char_suffix" { byte_length = local.random_char_length @@ -38,28 +38,34 @@ resource "random_id" "random_char_suffix" { # serviceAccountTokenCreator # workloadIdentityUser # -------------------------------------------------------------- -resource "google_service_account" "anyscale_access_role" { - count = local.anyscale_access_role_enabled ? 1 : 0 +resource "google_service_account" "anyscale_access_service_acct" { + count = local.anyscale_access_service_acct_enabled ? 1 : 0 - account_id = local.access_role_name_computed - description = local.anyscale_access_role_desc + account_id = local.access_acct_name_computed + description = local.anyscale_access_service_acct_desc project = var.anyscale_project_id } #tfsec:ignore:google-iam-no-project-level-service-account-impersonation -resource "google_project_iam_member" "anyscale_access_role" { - for_each = local.anyscale_access_role_enabled ? toset(var.anyscale_access_role_project_permissions) : [] - role = each.key - project = var.anyscale_project_id - member = "serviceAccount:${google_service_account.anyscale_access_role[0].email}" +# resource "google_project_iam_member" "anyscale_access_service_acct" { +# for_each = local.anyscale_access_service_acct_enabled ? toset(var.anyscale_access_service_acct_project_permissions) : [] +# role = each.key +# project = var.anyscale_project_id +# member = "serviceAccount:${google_service_account.anyscale_access_service_acct[0].email}" +# } +resource "google_project_iam_member" "anyscale_access_service_acct" { + count = local.anyscale_access_service_acct_enabled ? 1 : 0 + role = coalesce(google_project_iam_custom_role.anyscale_access_role[0].name, var.existing_anyscale_access_role_name) + project = var.anyscale_project_id + member = "serviceAccount:${google_service_account.anyscale_access_service_acct[0].email}" } #tfsec:ignore:google-iam-no-project-level-service-account-impersonation -resource "google_service_account_iam_binding" "anyscale_access_role" { - for_each = local.anyscale_access_role_enabled ? toset(var.anyscale_access_role_binding_permissions) : [] +resource "google_service_account_iam_binding" "anyscale_access_service_acct" { + for_each = local.anyscale_access_service_acct_enabled ? toset(var.anyscale_access_service_acct_binding_permissions) : [] role = each.key - service_account_id = google_service_account.anyscale_access_role[0].name - members = ["serviceAccount:${google_service_account.anyscale_access_role[0].email}"] + service_account_id = google_service_account.anyscale_access_service_acct[0].name + members = ["serviceAccount:${google_service_account.anyscale_access_service_acct[0].email}"] } # Identity Pool Resources @@ -101,9 +107,9 @@ locals { identity_pool_name = local.create_workload_identity_pool ? "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.anyscale_pool[0].name}/*" : local.existing_provider_provided ? "principalSet://iam.googleapis.com/${local.existing_workload_identity_pool_name}/*" : null } resource "google_service_account_iam_binding" "anyscale_workload_identity_user" { - count = local.anyscale_access_role_enabled ? 1 : 0 + count = local.anyscale_access_service_acct_enabled ? 1 : 0 - service_account_id = google_service_account.anyscale_access_role[0].name + service_account_id = google_service_account.anyscale_access_service_acct[0].name role = "roles/iam.workloadIdentityUser" members = [ local.identity_pool_name @@ -115,40 +121,47 @@ resource "google_service_account_iam_binding" "anyscale_workload_identity_user" # Permission: storage admin, artifact registry read # -------------------------------------------------------------- locals { - cluster_node_role_enabled = var.module_enabled && var.create_anyscale_cluster_node_role ? true : false + cluster_node_role_enabled = var.module_enabled && var.create_anyscale_cluster_node_service_acct ? true : false - anyscale_cluster_node_role_desc_cloud = try("Anyscale cluster node role for cloud ${var.anyscale_cloud_id} in region ${var.google_region}", "Anyscale cluster node role for cloud ${var.anyscale_cloud_id}", null) - anyscale_cluster_node_role_desc = coalesce( - var.anyscale_cluster_node_role_description, - local.anyscale_cluster_node_role_desc_cloud, + anyscale_cluster_node_service_acct_desc_cloud = var.anyscale_cloud_id != null ? "Anyscale cluster node role for cloud ${var.anyscale_cloud_id} in region ${var.google_region}" : null + anyscale_cluster_node_service_acct_desc = coalesce( + var.anyscale_cluster_node_service_acct_description, + local.anyscale_cluster_node_service_acct_desc_cloud, "Anyscale cluster node role" ) - anyscale_cluster_node_role_name = coalesce(var.anyscale_cluster_node_role_name, var.anyscale_cluster_node_role_name_prefix, "anyscale-") + anyscale_cluster_node_service_acct_name = coalesce(var.anyscale_cluster_node_service_acct_name, var.anyscale_cluster_node_service_acct_name_prefix, "anyscale-") cluster_node_role_name_computed = var.enable_random_name_suffix ? format( "%s%s", - local.anyscale_cluster_node_role_name, + local.anyscale_cluster_node_service_acct_name, random_id.random_char_suffix.hex, - ) : local.anyscale_cluster_node_role_name + ) : local.anyscale_cluster_node_service_acct_name cluster_node_logging_monitoring_enabled = var.module_enabled && var.enable_anyscale_cluster_logging_monitoring ? true : false cluster_node_roles = local.cluster_node_logging_monitoring_enabled ? concat([ "roles/logging.logWriter", "roles/monitoring.metricWriter", - ], var.anyscale_cluster_node_role_permissions) : var.anyscale_cluster_node_role_permissions + ], var.anyscale_cluster_node_service_acct_permissions) : var.anyscale_cluster_node_service_acct_permissions } -resource "google_service_account" "anyscale_cluster_node_role" { +resource "google_service_account" "anyscale_cluster_node_service_acct" { count = local.cluster_node_role_enabled ? 1 : 0 account_id = local.cluster_node_role_name_computed - description = local.anyscale_cluster_node_role_desc + description = local.anyscale_cluster_node_service_acct_desc project = var.anyscale_project_id } -resource "google_project_iam_binding" "anyscale_cluster_node_role" { +resource "google_project_iam_binding" "anyscale_cluster_node_service_acct" { for_each = local.cluster_node_role_enabled ? toset(local.cluster_node_roles) : [] role = each.key project = var.anyscale_project_id - # service_account_id = google_service_account.anyscale_cluster_node_role[0].name - members = ["serviceAccount:${google_service_account.anyscale_cluster_node_role[0].email}"] + # service_account_id = google_service_account.anyscale_cluster_node_service_acct[0].name + members = ["serviceAccount:${google_service_account.anyscale_cluster_node_service_acct[0].email}"] +} + +resource "google_service_account_iam_member" "anyscale_cluster_node_service_acct" { + count = local.cluster_node_role_enabled && local.anyscale_access_service_acct_enabled ? 1 : 0 + role = "roles/iam.serviceAccountUser" + service_account_id = google_service_account.anyscale_cluster_node_service_acct[0].name + member = "serviceAccount:${google_service_account.anyscale_access_service_acct[0].email}" } diff --git a/modules/google-anyscale-iam/outputs.tf b/modules/google-anyscale-iam/outputs.tf index 2ba2bd3..38747a6 100644 --- a/modules/google-anyscale-iam/outputs.tf +++ b/modules/google-anyscale-iam/outputs.tf @@ -1,24 +1,24 @@ -# ------------------------------------------- -# Anyscale Cross Account Access Role -# ------------------------------------------- -output "iam_anyscale_access_role_id" { - description = "Anyscale cross account access role ID" - value = try(google_service_account.anyscale_access_role[0].id, null) +# ---------------------------------------------- +# Anyscale Cross Account Access Service Account +# ---------------------------------------------- +output "iam_anyscale_access_service_acct_id" { + description = "Anyscale cross account access service account ID" + value = try(google_service_account.anyscale_access_service_acct[0].id, null) } -output "iam_anyscale_access_role_email" { - description = "Anyscale cross account access role email" - value = try(google_service_account.anyscale_access_role[0].email, null) +output "iam_anyscale_access_service_acct_email" { + description = "Anyscale cross account access service account email" + value = try(google_service_account.anyscale_access_service_acct[0].email, null) } -output "iam_anyscale_access_role_name" { - description = "Anyscale cross account access role name" - value = try(google_service_account.anyscale_access_role[0].name, null) +output "iam_anyscale_access_service_acct_name" { + description = "Anyscale cross account access service account name" + value = try(google_service_account.anyscale_access_service_acct[0].name, null) } -output "iam_anyscale_access_role_unique_id" { - description = "Anyscale cross account access role unique ID" - value = try(google_service_account.anyscale_access_role[0].unique_id, null) +output "iam_anyscale_access_service_acct_unique_id" { + description = "Anyscale cross account access service account unique ID" + value = try(google_service_account.anyscale_access_service_acct[0].unique_id, null) } # ------------------------------------------- @@ -47,24 +47,24 @@ output "iam_workload_identity_provider_name" { } # ------------------------------------------- -# Anyscale Cluster Node Role +# Anyscale Cluster Node Service Account # ------------------------------------------- -output "iam_anyscale_cluster_node_role_id" { - description = "Anyscale cross account cluster node role ID" - value = try(google_service_account.anyscale_cluster_node_role[0].id, null) +output "iam_anyscale_cluster_node_service_acct_id" { + description = "Anyscale cross account cluster node service account ID" + value = try(google_service_account.anyscale_cluster_node_service_acct[0].id, null) } -output "iam_anyscale_cluster_node_role_email" { - description = "Anyscale cross account cluster node role email" - value = try(google_service_account.anyscale_cluster_node_role[0].email, null) +output "iam_anyscale_cluster_node_service_acct_email" { + description = "Anyscale cross account cluster node service account email" + value = try(google_service_account.anyscale_cluster_node_service_acct[0].email, null) } -output "iam_anyscale_cluster_node_role_name" { - description = "Anyscale cross account cluster node role name" - value = try(google_service_account.anyscale_cluster_node_role[0].name, null) +output "iam_anyscale_cluster_node_service_acct_name" { + description = "Anyscale cross account cluster node service account name" + value = try(google_service_account.anyscale_cluster_node_service_acct[0].name, null) } -output "iam_anyscale_cluster_node_role_unique_id" { - description = "Anyscale cross account cluster node role unique ID" - value = try(google_service_account.anyscale_cluster_node_role[0].unique_id, null) +output "iam_anyscale_cluster_node_service_acct_unique_id" { + description = "Anyscale cross account cluster node service account unique ID" + value = try(google_service_account.anyscale_cluster_node_service_acct[0].unique_id, null) } diff --git a/modules/google-anyscale-iam/roles.tf b/modules/google-anyscale-iam/roles.tf new file mode 100644 index 0000000..084aff1 --- /dev/null +++ b/modules/google-anyscale-iam/roles.tf @@ -0,0 +1,156 @@ +locals { + anyscale_access_serviceacct_role_enabled = var.module_enabled && var.create_anyscale_access_role ? true : false + + anyscale_access_serviceacct_role_id = coalesce(var.anyscale_access_role_id, var.anyscale_access_role_id_prefix, "anyscale_") + access_acct_role_id_computed = var.enable_random_name_suffix ? format( + "%s%s", + local.anyscale_access_serviceacct_role_id, + random_id.random_char_suffix.hex, + ) : local.anyscale_access_serviceacct_role_id +} +resource "google_project_iam_custom_role" "anyscale_access_role" { + count = local.anyscale_access_serviceacct_role_enabled ? 1 : 0 + project = var.anyscale_project_id + role_id = local.access_acct_role_id_computed + title = local.access_acct_role_id_computed + description = var.anyscale_access_role_description + permissions = [ + "certificatemanager.certmapentries.create", + "certificatemanager.certmapentries.delete", + "certificatemanager.certmapentries.get", + "certificatemanager.certmaps.create", + "certificatemanager.certmaps.delete", + "certificatemanager.certmaps.get", + "certificatemanager.certmaps.list", + "certificatemanager.certmaps.use", + "certificatemanager.certs.create", + "certificatemanager.certs.delete", + "certificatemanager.certs.get", + "certificatemanager.certs.use", + "certificatemanager.dnsauthorizations.create", + "certificatemanager.dnsauthorizations.delete", + "certificatemanager.dnsauthorizations.get", + "certificatemanager.dnsauthorizations.use", + "certificatemanager.operations.get", + "compute.acceleratorTypes.list", + "compute.backendServices.create", + "compute.backendServices.delete", + "compute.backendServices.get", + "compute.backendServices.list", + "compute.backendServices.update", + "compute.backendServices.use", + "compute.disks.create", + "compute.disks.list", + "compute.firewalls.create", + "compute.firewalls.delete", + "compute.firewalls.list", + "compute.firewalls.update", + "compute.forwardingRules.create", + "compute.forwardingRules.delete", + "compute.forwardingRules.list", + "compute.forwardingRules.update", + "compute.globalForwardingRules.create", + "compute.globalForwardingRules.delete", + "compute.globalForwardingRules.list", + "compute.globalForwardingRules.update", + "compute.globalOperations.get", + "compute.healthChecks.create", + "compute.healthChecks.delete", + "compute.healthChecks.get", + "compute.healthChecks.list", + "compute.healthChecks.update", + "compute.healthChecks.use", + "compute.healthChecks.useReadOnly", + "compute.httpHealthChecks.create", + "compute.httpHealthChecks.delete", + "compute.httpHealthChecks.get", + "compute.httpHealthChecks.list", + "compute.httpHealthChecks.update", + "compute.httpHealthChecks.use", + "compute.httpsHealthChecks.create", + "compute.httpsHealthChecks.delete", + "compute.httpsHealthChecks.get", + "compute.httpsHealthChecks.list", + "compute.httpsHealthChecks.update", + "compute.httpsHealthChecks.use", + "compute.instanceGroups.create", + "compute.instanceGroups.delete", + "compute.instanceGroups.get", + "compute.instanceGroups.list", + "compute.instanceGroups.update", + "compute.instanceGroups.use", + "compute.instances.create", + "compute.instances.delete", + "compute.instances.get", + "compute.instances.list", + "compute.instances.setLabels", + "compute.instances.setMetadata", + "compute.instances.setServiceAccount", + "compute.instances.update", + "compute.instances.use", + "compute.machineTypes.list", + "compute.networks.updatePolicy", + "compute.regionBackendServices.create", + "compute.regionBackendServices.delete", + "compute.regionBackendServices.get", + "compute.regionBackendServices.list", + "compute.regionBackendServices.update", + "compute.regionBackendServices.use", + "compute.regionHealthChecks.create", + "compute.regionHealthChecks.delete", + "compute.regionHealthChecks.get", + "compute.regionHealthChecks.list", + "compute.regionHealthChecks.update", + "compute.regionHealthChecks.use", + "compute.regionHealthChecks.useReadOnly", + "compute.regionOperations.get", + "compute.regionSslCertificates.create", + "compute.regionSslCertificates.delete", + "compute.regionSslCertificates.get", + "compute.regionSslCertificates.list", + "compute.regionTargetHttpProxies.create", + "compute.regionTargetHttpProxies.delete", + "compute.regionTargetHttpProxies.get", + "compute.regionTargetHttpProxies.list", + "compute.regionTargetHttpProxies.update", + "compute.regionTargetHttpProxies.use", + "compute.regionTargetHttpsProxies.create", + "compute.regionTargetHttpsProxies.delete", + "compute.regionTargetHttpsProxies.get", + "compute.regionTargetHttpsProxies.list", + "compute.regionTargetHttpsProxies.update", + "compute.regionTargetHttpsProxies.use", + "compute.regionUrlMaps.create", + "compute.regionUrlMaps.delete", + "compute.regionUrlMaps.get", + "compute.regionUrlMaps.list", + "compute.regionUrlMaps.update", + "compute.regionUrlMaps.use", + "compute.regions.list", + "compute.reservations.list", + "compute.subnetworks.list", + "compute.subnetworks.use", + "compute.subnetworks.useExternalIp", + "compute.targetHttpProxies.create", + "compute.targetHttpProxies.delete", + "compute.targetHttpProxies.get", + "compute.targetHttpProxies.list", + "compute.targetHttpProxies.update", + "compute.targetHttpProxies.use", + "compute.targetHttpsProxies.create", + "compute.targetHttpsProxies.delete", + "compute.targetHttpsProxies.get", + "compute.targetHttpsProxies.list", + "compute.targetHttpsProxies.update", + "compute.targetHttpsProxies.use", + "compute.urlMaps.create", + "compute.urlMaps.delete", + "compute.urlMaps.get", + "compute.urlMaps.list", + "compute.urlMaps.update", + "compute.urlMaps.use", + "compute.zoneOperations.get", + "compute.zones.list", + "storage.buckets.get" + ] +} diff --git a/modules/google-anyscale-iam/variables.tf b/modules/google-anyscale-iam/variables.tf index ca635c7..99ed67f 100644 --- a/modules/google-anyscale-iam/variables.tf +++ b/modules/google-anyscale-iam/variables.tf @@ -73,63 +73,183 @@ variable "random_char_length" { } } # -------------------------------------------------------------- -# Anyscale Cross Acct Access Role +# Anyscale Cross Acct Access Service Account # -------------------------------------------------------------- -variable "create_anyscale_access_role" { - description = "(Optional) Determines whether to create the Anyscale access role. Default is `true`." +variable "create_anyscale_access_service_acct" { + description = "(Optional) Determines whether to create the Anyscale access service account. Default is `true`." type = bool default = true } -variable "anyscale_access_role_name" { - description = "(Optional, forces creation of new resource) The name of the Anyscale IAM access role. Conflicts with anyscale_access_role_name_prefix. Default is `null`." +variable "anyscale_access_service_acct_name" { + description = <<-EOT + (Optional, forces creation of new resource) + The name of the Anyscale IAM access service account. + + Overrides `anyscale_access_service_acct_name_prefix`. + + ex: + ``` + anyscale_access_service_acct_name = "anyscale-access-service-acct" + ``` + EOT type = string default = null validation { - condition = var.anyscale_access_role_name == null ? true : ( - can(regex("^[a-z](?:[-a-z0-9]{4,28}[a-z0-9])$", var.anyscale_access_role_name)) + condition = var.anyscale_access_service_acct_name == null ? true : ( + can(regex("^[a-z](?:[-a-z0-9]{4,28}[a-z0-9])$", var.anyscale_access_service_acct_name)) ) - error_message = "`anyscale_access_role_name` must match regex: ^[a-z](?:[-a-z0-9]{4,28}[a-z0-9])$." + error_message = "`anyscale_access_service_acct_name` must match regex: ^[a-z](?:[-a-z0-9]{4,28}[a-z0-9])$." } } -variable "anyscale_access_role_name_prefix" { - description = "(Optional, forces creation of new resource) The prefix of the Anyscale IAM access role. Conflicts with anyscale_access_role_name. Default is `anyscale-iam-role-`." +variable "anyscale_access_service_acct_name_prefix" { + description = <<-EOT + (Optional, forces creation of new resource) + The prefix of the Anyscale IAM access service account. + + Conflicts with anyscale_access_service_acct_name. + + ex: + ``` + anyscale_access_service_acct_name_prefix = "anyscale-access-" + ``` + EOT type = string - default = "anyscale-crossacct-role-" + default = "anyscale-crossacct-" validation { - condition = var.anyscale_access_role_name_prefix == null ? true : ( - can(regex("^[a-z](?:[-a-z0-9]{4,24})$", var.anyscale_access_role_name_prefix)) + condition = var.anyscale_access_service_acct_name_prefix == null ? true : ( + can(regex("^[a-z](?:[-a-z0-9]{4,24})$", var.anyscale_access_service_acct_name_prefix)) ) - error_message = "`anyscale_access_role_name_prefix` must match regex: ^[a-z](?:[-a-z0-9]{4,24})$." + error_message = "`anyscale_access_service_acct_name_prefix` must match regex: ^[a-z](?:[-a-z0-9]{4,24})$." } } -variable "anyscale_access_role_description" { - description = "(Optional) Anyscale IAM access role description. If this is `null` the description will be set to \"Anyscale access role\". Default is `null`." +variable "anyscale_access_service_acct_description" { + description = <<-EOT + (Optional) Anyscale IAM access service account description. + + If this is `null` the description will be set to \"Anyscale access service account\" in a local variable. + + ex: + ``` + anyscale_access_service_acct_description = "Anyscale access service account" + ``` + EOT type = string default = null } -variable "anyscale_access_role_project_permissions" { - description = <<-EOF - (Optional) A list of permission roles to grant to the Anyscale IAM access role at the project level. - Default is `["roles/owner"]`. - EOF - type = list(string) - default = ["roles/owner"] -} +# variable "anyscale_access_service_acct_project_permissions" { +# description = <<-EOT +# (Optional) A list of permission roles -variable "anyscale_access_role_binding_permissions" { - description = <<-EOF - (Optional) A list of permission roles to grant to the Anyscale IAM access role at the Service Account level. +# These permission roles will be granted to the service account at the project level. + +# ex: +# ``` +# anyscale_access_service_acct_project_permissions = ["roles/owner"] +# ``` +# EOT +# type = list(string) +# default = ["roles/owner"] +# } + +variable "anyscale_access_service_acct_binding_permissions" { + description = <<-EOT + (Optional) A list of permission roles to grant to the Anyscale IAM access service account at the Service Account level. Default is `["roles/iam.serviceAccountTokenCreator"]`. - EOF + EOT type = list(string) default = ["roles/iam.serviceAccountTokenCreator"] } +# - Role for Anyscale Cross Account Access +variable "create_anyscale_access_role" { + description = <<-EOT + (Optional) Determines whether to create the Anyscale access role. + + ex: + ``` + create_anyscale_access_role = true + ``` + EOT + type = bool + default = true +} + +variable "existing_anyscale_access_role_name" { + description = <<-EOT + (Optional) The name of an existing Anyscale IAM access role to use. + + If provided, will skip creating the Anyscale access role. + + ex: + ``` + existing_anyscale_access_role_name = "projects/1234567890/roles/anyscale_access_role" + ``` + EOT + type = string + default = null +} + +variable "anyscale_access_role_id" { + description = <<-EOT + (Optional, forces creation of new resource) The ID of the Anyscale IAM access role. + + Overrides `anyscale_access_role_id_prefix`. + + ex: + ``` + anyscale_access_role_id = "anyscale_access_role" + ``` + EOT + type = string + default = null + validation { + condition = var.anyscale_access_role_id == null ? true : ( + can(regex("^[a-zA-Z0-9_]{4,28}$", var.anyscale_access_role_id)) + ) + error_message = "`anyscale_access_role_name` must match regex: ^[a-zA-Z0-9_]{4,28}$." + } +} + +variable "anyscale_access_role_id_prefix" { + description = <<-EOT + (Optional, forces creation of new resource) The prefix of the Anyscale IAM access role. + + If `anyscale_access_role_id` is provided, it will override this variable. + If set to `null`, the prefix will be set to \"anyscale_\" in a local variable. + + ex: + ``` + anyscale_access_role_id_prefix = "anyscale_crossacct_role_" + ``` + EOT + type = string + default = "anyscale_crossacct_role_" + validation { + condition = var.anyscale_access_role_id_prefix == null ? true : ( + can(regex("^[a-zA-Z0-9_]{4,24}$", var.anyscale_access_role_id_prefix)) + ) + error_message = "`anyscale_access_role_id_prefix` must match regex: ^[a-zA-Z0-9_]{4,24}$." + } +} + +variable "anyscale_access_role_description" { + description = <<-EOT + (Optional) Anyscale IAM access role description. + + ex: + ``` + anyscale_access_role_description = "Anyscale access role" + ``` + EOT + type = string + default = "Anyscale access role" +} +# - Workload Identity Pool for Anyscale Cross Account Access variable "existing_workload_identity_provider_name" { description = <<-EOF (Optional) The name of an existing workload identity provider to use. @@ -151,7 +271,7 @@ variable "existing_workload_identity_provider_name" { default = null } variable "workload_identity_pool_name" { - description = "(Optional) The name of the workload identity pool. If it is not provided, the Anyscale Access role name is used. Default is `null`." + description = "(Optional) The name of the workload identity pool. If it is not provided, the Anyscale Access service account name is used. Default is `null`." type = string default = null } @@ -167,7 +287,7 @@ variable "workload_identity_pool_description" { } variable "workload_identity_pool_provider_name" { - description = "(Optional) The name of the workload identity pool provider. If it is not provided, the Anyscale Access role name is used. Default is `null`." + description = "(Optional) The name of the workload identity pool provider. If it is not provided, the Anyscale Access service account name is used. Default is `null`." type = string default = null } @@ -183,85 +303,89 @@ variable "workload_anyscale_aws_account_id" { } # -------------------------------------------------------------- -# Anyscale Cluster Node Role +# Anyscale Access Service Account Access Role +# -------------------------------------------------------------- + +# -------------------------------------------------------------- +# Anyscale Cluster Node Service Account # -------------------------------------------------------------- -variable "create_anyscale_cluster_node_role" { +variable "create_anyscale_cluster_node_service_acct" { description = <<-EOT - (Optional) Determines whether to create the Anyscale cluster role. + (Optional) Determines whether to create the Anyscale cluster service account. ex: ``` - create_anyscale_cluster_node_role = true + create_anyscale_cluster_node_service_acct = true ``` EOT type = bool default = true } -variable "anyscale_cluster_node_role_name" { +variable "anyscale_cluster_node_service_acct_name" { description = <<-EOT - (Optional, forces creation of new resource) The name of the Anyscale IAM cluster node role. + (Optional, forces creation of new resource) The name of the Anyscale IAM cluster node service account. - Overrides `anyscale_cluster_node_role_name_prefix`. + Overrides `anyscale_cluster_node_service_acct_name_prefix`. ex: ``` - anyscale_cluster_node_role_name = "anyscale-cluster-node-role" + anyscale_cluster_node_service_acct_name = "anyscale-cluster-acct" ``` EOT type = string default = null validation { - condition = var.anyscale_cluster_node_role_name == null ? true : ( - can(regex("^[a-z](?:[-a-z0-9]{4,28}[a-z0-9])$", var.anyscale_cluster_node_role_name)) + condition = var.anyscale_cluster_node_service_acct_name == null ? true : ( + can(regex("^[a-z](?:[-a-z0-9]{4,28}[a-z0-9])$", var.anyscale_cluster_node_service_acct_name)) ) - error_message = "`anyscale_cluster_node_role_name` must match regex: ^[a-z](?:[-a-z0-9]{4,28}[a-z0-9])$." + error_message = "`anyscale_cluster_node_service_acct_name` must match regex: ^[a-z](?:[-a-z0-9]{4,28}[a-z0-9])$." } } -variable "anyscale_cluster_node_role_name_prefix" { +variable "anyscale_cluster_node_service_acct_name_prefix" { description = <<-EOT - (Optional, forces creation of new resource) The prefix of the Anyscale IAM access role. + (Optional, forces creation of new resource) The prefix of the Anyscale IAM cluster service account. - If `anyscale_cluster_role_node_name` is provided, it will override this variable. + If `anyscale_cluster_node_service_acct_name` is provided, it will override this variable. ex: ``` - anyscale_cluster_node_role_name_prefix = "anyscale-cluster-" + anyscale_cluster_node_service_acct_name_prefix = "anyscale-cluster-" ``` EOT type = string default = "anyscale-cluster-" validation { - condition = var.anyscale_cluster_node_role_name_prefix == null ? true : ( - can(regex("^[a-z](?:[-a-z0-9]{4,24})$", var.anyscale_cluster_node_role_name_prefix)) + condition = var.anyscale_cluster_node_service_acct_name_prefix == null ? true : ( + can(regex("^[a-z](?:[-a-z0-9]{4,24})$", var.anyscale_cluster_node_service_acct_name_prefix)) ) - error_message = "`anyscale_cluster_node_role_name_prefix` must match regex: ^[a-z](?:[-a-z0-9]{4,24})$." + error_message = "`anyscale_cluster_node_service_acct_name_prefix` must match regex: ^[a-z](?:[-a-z0-9]{4,24})$." } } -variable "anyscale_cluster_node_role_description" { +variable "anyscale_cluster_node_service_acct_description" { description = <<-EOT - (Optional) IAM cluster node role description. + (Optional) IAM cluster node service account description. - If this is `null` the description will be set to `Anyscale cluster node role` in a local variable. + If this is `null` the description will be set to `Anyscale cluster node service account` in a local variable. ex: ``` - anyscale_cluster_node_role_description = "Anyscale cluster node role for cloud" + anyscale_cluster_node_service_acct_description = "Anyscale cluster node service account for cloud" ``` EOT type = string default = null } -variable "anyscale_cluster_node_role_permissions" { +variable "anyscale_cluster_node_service_acct_permissions" { description = <<-EOT - (Optional) A list of permission roles to grant to the Anyscale IAM cluster node role. + (Optional) A list of permission roles to grant to the Anyscale IAM cluster node service account. ex: ``` - anyscale_cluster_node_role_permissions = ["roles/artifactregistry.reader"] + anyscale_cluster_node_service_acct_permissions = ["roles/artifactregistry.reader"] ``` EOT type = list(string) diff --git a/modules/google-anyscale-memorystore/README.md b/modules/google-anyscale-memorystore/README.md index b1ab1be..b5e75e5 100644 --- a/modules/google-anyscale-memorystore/README.md +++ b/modules/google-anyscale-memorystore/README.md @@ -18,8 +18,8 @@ Optional sub-module that creates a Google Memorystore Redis DB. | Name | Version | |------|---------| -| [google](#provider\_google) | 4.82.0 | -| [random](#provider\_random) | 3.5.1 | +| [google](#provider\_google) | 4.84.0 | +| [random](#provider\_random) | 3.6.0 | ## Modules @@ -37,7 +37,6 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [alternative\_google\_zone](#input\_alternative\_google\_zone) | (Optional) Alternative Google Cloud Zone

The alternative Google zone in which resources will be created.

If `alternative_google_zone is also provided, it must be different from `google\_zone`.
If it is not provided, the service will choose two zones for the instances to be created in for protection against zonal failures.

ex:
`
alternative_google_zone = "us-central1-b"
| `string` | `null` | no | -| [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID

ex:
anyscale_cloud_id = "cld_1234567890"
| `string` | `null` | no | | [anyscale\_memorystore\_name](#input\_anyscale\_memorystore\_name) | (Optional) The name of the memorystore to create.

Conflicts with `anyscale_memorystore_name_prefix`.
Must start with a lowercase letter followed by up to 62 lowercase letters, numbers, or hyphens, and cannot end with a hyphen.

ex:
anyscale_memorystore_name = "anyscale-memorystore"
| `string` | `null` | no | | [anyscale\_memorystore\_name\_prefix](#input\_anyscale\_memorystore\_name\_prefix) | (Optional) The prefix of the memorystore to create.

Conflicts `with anyscale_memorystore_name`.
Must start with a lowercase letter followed by up to 48 lowercase letters, numbers, or hyphens.
Because it is the prefix, it can end in a hyphen as it will have a random suffix appended to it.

Default is `null` but set to `anyscale-memorystore-` in the module.

ex:
anyscale_memorystore_name_prefix = "anyscale-memorystore-"
| `string` | `null` | no | | [anyscale\_project\_id](#input\_anyscale\_project\_id) | (Optional) Google Project ID

ID of the project to create the resource in. If not provided, the provider project is used.

ex:
anyscale_project_id = "my-project"
| `string` | `null` | no | diff --git a/modules/google-anyscale-memorystore/variables.tf b/modules/google-anyscale-memorystore/variables.tf index ced0cc8..ee00a8d 100644 --- a/modules/google-anyscale-memorystore/variables.tf +++ b/modules/google-anyscale-memorystore/variables.tf @@ -20,28 +20,6 @@ variable "memorystore_vpc_name" { # OPTIONAL PARAMETERS # These variables have defaults, but may be overridden. # ------------------------------------------------------------------------------ -variable "anyscale_cloud_id" { - description = <<-EOT - (Optional) Anyscale Cloud ID - - ex: - ``` - anyscale_cloud_id = "cld_1234567890" - ``` - EOT - type = string - default = null - validation { - condition = ( - var.anyscale_cloud_id == null ? true : ( - length(var.anyscale_cloud_id) > 4 && - substr(var.anyscale_cloud_id, 0, 4) == "cld_" - ) - ) - error_message = "The anyscale_cloud_id value must start with \"cld_\"." - } -} - variable "module_enabled" { description = <<-EOT (Optional) Determines whether to create the resources inside this module. diff --git a/modules/google-anyscale-project/README.md b/modules/google-anyscale-project/README.md index 7b22cb4..84e5dcb 100644 --- a/modules/google-anyscale-project/README.md +++ b/modules/google-anyscale-project/README.md @@ -17,8 +17,8 @@ Creates a new Google Cloud Project for Anyscale Resources | Name | Version | |------|---------| -| [google](#provider\_google) | 4.82.0 | -| [random](#provider\_random) | 3.5.1 | +| [google](#provider\_google) | 4.84.0 | +| [random](#provider\_random) | 3.6.0 | ## Modules @@ -36,7 +36,6 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID. Default is `null`. | `string` | `null` | no | | [anyscale\_project\_id](#input\_anyscale\_project\_id) | (Optional) Google Cloud Project ID. If not provided, the `project_name_computed` local variable will be used. | `string` | `null` | no | | [anyscale\_project\_name](#input\_anyscale\_project\_name) | (Optional) Google Cloud Project name. Default is `null`. | `string` | `null` | no | | [anyscale\_project\_name\_prefix](#input\_anyscale\_project\_name\_prefix) | (Optional) Prefix to be used for the project name.
Conflicts with `anyscale_project_name`. If `anyscale_project_name` is provided, it will be used and `anyscale_project_name_prefix` will be ignored.
Default is `anyscale-project-`. | `string` | `"anyscale-project-"` | no | diff --git a/modules/google-anyscale-project/variables.tf b/modules/google-anyscale-project/variables.tf index 1b89e75..c890331 100644 --- a/modules/google-anyscale-project/variables.tf +++ b/modules/google-anyscale-project/variables.tf @@ -11,21 +11,6 @@ variable "billing_account_id" { # OPTIONAL PARAMETERS # These variables have defaults, but may be overridden. # ------------------------------------------------------------------------------ -variable "anyscale_cloud_id" { - description = "(Optional) Anyscale Cloud ID. Default is `null`." - type = string - default = null - validation { - condition = ( - var.anyscale_cloud_id == null ? true : ( - length(var.anyscale_cloud_id) > 4 && - substr(var.anyscale_cloud_id, 0, 4) == "cld_" - ) - ) - error_message = "The anyscale_cloud_id value must start with \"cld_\"." - } -} - variable "module_enabled" { description = "(Optional) Whether to create the resources inside this module. Default is `true`." type = bool diff --git a/modules/google-anyscale-vpc-firewall/README.md b/modules/google-anyscale-vpc-firewall/README.md index 5affaf0..86530b3 100644 --- a/modules/google-anyscale-vpc-firewall/README.md +++ b/modules/google-anyscale-vpc-firewall/README.md @@ -18,7 +18,7 @@ This sub-module builds Google VPC Firewalls that will work with Anyscale. | Name | Version | |------|---------| -| [google](#provider\_google) | 4.82.0 | +| [google](#provider\_google) | 4.84.0 | ## Modules @@ -31,6 +31,7 @@ No modules. | [google_compute_network_firewall_policy.anyscale_firewall_policy](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_network_firewall_policy) | resource | | [google_compute_network_firewall_policy_association.anyscale_firewall_policy](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_network_firewall_policy_association) | resource | | [google_compute_network_firewall_policy_rule.ingress_allow_from_cidr_blocks](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_network_firewall_policy_rule) | resource | +| [google_compute_network_firewall_policy_rule.ingress_allow_from_gcp_health_checks](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_network_firewall_policy_rule) | resource | | [google_compute_network_firewall_policy_rule.ingress_with_self](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_network_firewall_policy_rule) | resource | | [google_compute_network.anyscale_vpc](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_network) | data source | @@ -38,17 +39,17 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID.

ex:
anyscale_cloud_id = "cld_1234567890"
| `string` | `null` | no | | [anyscale\_project\_id](#input\_anyscale\_project\_id) | (Optional) The ID of the project to create the resource in.

If it is not provided, the provider project is used.

ex:
anyscale_project_id = "project-1234567890"
| `string` | `null` | no | | [default\_ingress\_cidr\_range](#input\_default\_ingress\_cidr\_range) | (Optional) List of IPv4 cidr ranges to default to if a specific mapping isn't provided.

ex:
default_ingress_cidr_range = ["32.0.10.0/24","32.32.10.9/32"]
| `list(string)` | `[]` | no | | [enable\_firewall\_rule\_logging](#input\_enable\_firewall\_rule\_logging) | (Optional) Determines whether to enable logging for firewall rules.

ex:
enable_firewall_rule_logging = true
| `bool` | `true` | no | | [firewall\_policy\_description](#input\_firewall\_policy\_description) | (Optional) The description of the firewall policy.

ex:
firewall_policy_description = "Anyscale VPC Firewall Policy"
| `string` | `"Anyscale VPC Firewall Policy"` | no | | [firewall\_policy\_name](#input\_firewall\_policy\_name) | (Optional) The name of the firewall policy.

If left `null`, the firewall name will default to the vpc name.

ex:
firewall_policy_name = "anyscale-vpc-firewall-policy"
| `string` | `null` | no | | [ingress\_from\_cidr\_map](#input\_ingress\_from\_cidr\_map) | (Optional) List of ingress rules to create with cidr ranges.
This can use rules from `predefined_firewall_rules` or custom rules.
ex:
ingress_from_cidr_map = [
{
rule = "https-443-tcp"
cidr_blocks = "10.100.10.10/32"
},
{ rule = "nfs-tcp" },
{
ports = "10-20"
protocol = "tcp"
description = "Service name is TEST"
cidr_blocks = "10.100.10.10/32"
}
]
Default is an empty list. | `list(map(string))` | `[]` | no | +| [ingress\_from\_gcp\_health\_checks](#input\_ingress\_from\_gcp\_health\_checks) | (Optional) List of ingress rules to create to allow GCP health check probes.

This only uses rules from `predefined_firewall_rules`.
More information on GCP health checks can be found here:
https://cloud.google.com/load-balancing/docs/health-check-concepts#ip-ranges

ex:
ingress_from_gcp_health_checks = [
{
rule = "health-checks"
cidr_blocks = "35.191.0.0/16, 130.211.0.0/22"
}
]
| `list(map(string))` |
[
{
"cidr_blocks": "35.191.0.0/16,130.211.0.0/22",
"rule": "health-checks"
}
]
| no | | [ingress\_with\_self\_cidr\_range](#input\_ingress\_with\_self\_cidr\_range) | (Optional) List of CIDR range to default to if a specific mapping isn't provided.

ex:
ingress_with_self_cidr_range = ["10.10.0.0/16","10.20.0.0/16"]
| `list(string)` | `[]` | no | | [ingress\_with\_self\_map](#input\_ingress\_with\_self\_map) | (Optional) List of ingress rules to create where 'self' is defined.

Default rule is `all-all` as this firewall rule is used for all Anyscale resources.

ex:
ingress_with_self_map = [
{
rule = "https-443-tcp"
},
{
rule = "http-80-tcp"
},
{
rule = "ssh-tcp"
},
{
rule = "nfs-tcp"
}
]
| `list(map(string))` |
[
{
"rule": "all-all"
}
]
| no | | [module\_enabled](#input\_module\_enabled) | (Optional) Determines whether to create the resources inside this module.

ex:
module_enabled = true
| `bool` | `true` | no | -| [predefined\_firewall\_rules](#input\_predefined\_firewall\_rules) | (Required) Map of predefined firewall rules. | `map(list(any))` |
{
"all-all": [
"",
"all",
"All protocols",
1000
],
"http-80-tcp": [
80,
"tcp",
"HTTP",
1001
],
"https-443-tcp": [
443,
"tcp",
"HTTPS",
1002
],
"nfs-tcp": [
2049,
"tcp",
"NFS/EFS",
1004
],
"ssh-tcp": [
22,
"tcp",
"SSH",
1003
]
}
| no | +| [predefined\_firewall\_rules](#input\_predefined\_firewall\_rules) | (Required) Map of predefined firewall rules. | `map(list(any))` |
{
"all-all": [
"",
"all",
"All protocols",
1000
],
"health-checks": [
8000,
"tcp",
"Health Checks",
1005
],
"http-80-tcp": [
80,
"tcp",
"HTTP",
1001
],
"https-443-tcp": [
443,
"tcp",
"HTTPS",
1002
],
"nfs-tcp": [
2049,
"tcp",
"NFS/EFS",
1004
],
"ssh-tcp": [
22,
"tcp",
"SSH",
1003
]
}
| no | | [vpc\_name](#input\_vpc\_name) | (Required) The name of the VPC to apply the Firewall Policy to.

ex:
vpc_name = "anyscale-vpc"
| `string` | n/a | yes | ## Outputs diff --git a/modules/google-anyscale-vpc-firewall/examples/README.md b/modules/google-anyscale-vpc-firewall/examples/README.md index c920eb5..2cae45f 100644 --- a/modules/google-anyscale-vpc-firewall/examples/README.md +++ b/modules/google-anyscale-vpc-firewall/examples/README.md @@ -56,8 +56,6 @@ No resources. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID | `string` | `null` | no | -| [anyscale\_deploy\_env](#input\_anyscale\_deploy\_env) | (Required) Anyscale deploy environment. Used in resource names and tags. | `string` | n/a | yes | | [default\_ingress\_cidr\_range](#input\_default\_ingress\_cidr\_range) | (Optional) Default ingress CIDR range. Default is `null`. | `string` | `null` | no | | [google\_project\_id](#input\_google\_project\_id) | ID of the Project to put these resources in | `string` | n/a | yes | | [google\_region](#input\_google\_region) | The Google region in which all resources will be created. | `string` | n/a | yes | diff --git a/modules/google-anyscale-vpc-firewall/examples/variables.tf b/modules/google-anyscale-vpc-firewall/examples/variables.tf index 814599d..42a1f2a 100644 --- a/modules/google-anyscale-vpc-firewall/examples/variables.tf +++ b/modules/google-anyscale-vpc-firewall/examples/variables.tf @@ -8,17 +8,6 @@ # REQUIRED VARIABLES # These variables must be set when using this module. # --------------------------------------------------------------------------------------------------------------------- -variable "anyscale_deploy_env" { - description = "(Required) Anyscale deploy environment. Used in resource names and tags." - type = string - validation { - condition = ( - var.anyscale_deploy_env == "production" || var.anyscale_deploy_env == "development" || var.anyscale_deploy_env == "test" - ) - error_message = "The anyscale_deploy_env only allows `production`, `test`, or `development`" - } -} - variable "google_region" { description = "The Google region in which all resources will be created." type = string @@ -33,32 +22,8 @@ variable "google_project_id" { # OPTIONAL PARAMETERS # These variables have defaults, but may be overridden. # ------------------------------------------------------------------------------ -variable "anyscale_cloud_id" { - description = "(Optional) Anyscale Cloud ID" - type = string - default = null - validation { - condition = ( - var.anyscale_cloud_id == null ? true : ( - length(var.anyscale_cloud_id) > 4 && - substr(var.anyscale_cloud_id, 0, 4) == "cld_" - ) - ) - error_message = "The anyscale_cloud_id value must start with \"cld_\"." - } -} - variable "default_ingress_cidr_range" { description = "(Optional) Default ingress CIDR range. Default is `null`." type = string default = null } - -# variable "labels" { -# description = "(Optional) A map of tags to all resources that accept tags." -# type = map(string) -# default = { -# "test" : true, -# "environment" : "test" -# } -# } diff --git a/modules/google-anyscale-vpc-firewall/main.tf b/modules/google-anyscale-vpc-firewall/main.tf index 745895f..6fd01c2 100644 --- a/modules/google-anyscale-vpc-firewall/main.tf +++ b/modules/google-anyscale-vpc-firewall/main.tf @@ -6,6 +6,7 @@ locals { ingress_with_self_enabled = var.module_enabled && length(var.ingress_with_self_map) > 0 && length(var.ingress_with_self_cidr_range) > 0 ? true : false ingress_from_cidr_blocks_enabled = var.module_enabled && var.ingress_from_cidr_map != null && length(var.ingress_from_cidr_map) > 0 ? true : false + ingress_from_gcp_health_checks = var.module_enabled && var.ingress_from_gcp_health_checks != null ? true : false } #------------------------------- @@ -141,3 +142,57 @@ resource "google_compute_network_firewall_policy_rule" "ingress_allow_from_cidr_ } } + +resource "google_compute_network_firewall_policy_rule" "ingress_allow_from_gcp_health_checks" { + count = local.ingress_from_gcp_health_checks ? length(var.ingress_from_gcp_health_checks) : 0 + project = var.anyscale_project_id + + # name = "${local.computed_anyscale_vpcname}-ingress-allow-from-cidr-blocks-${count.index}" + description = lookup(var.ingress_from_gcp_health_checks[count.index], "description", "Ingress Rule") + direction = "INGRESS" + action = "allow" + enable_logging = var.enable_firewall_rule_logging + firewall_policy = google_compute_network_firewall_policy.anyscale_firewall_policy[0].name + + priority = lookup( + var.ingress_from_gcp_health_checks[count.index], + "priority", + try( + var.predefined_firewall_rules[lookup(var.ingress_from_gcp_health_checks[count.index], "rule", "_")][3], + count.index + ) + ) + + match { + src_ip_ranges = split( + ",", + lookup( + var.ingress_from_gcp_health_checks[count.index], + "cidr_blocks", + join(",", var.default_ingress_cidr_range) + ) + ) + + layer4_configs { + ip_protocol = lookup( + var.ingress_from_gcp_health_checks[count.index], + "protocol", + try( + var.predefined_firewall_rules[lookup(var.ingress_from_gcp_health_checks[count.index], "rule", "_")][1], + "tcp" + ) + ) + ports = var.predefined_firewall_rules[lookup(var.ingress_from_gcp_health_checks[count.index], "rule", "_")][0] == "" ? null : tolist([ + lookup( + var.ingress_from_cidr_map[count.index], + "ports", + try( + var.predefined_firewall_rules[lookup(var.ingress_from_gcp_health_checks[count.index], "rule", "_")][0], + null + ) + ) + ]) + } + } + +} diff --git a/modules/google-anyscale-vpc-firewall/variables.tf b/modules/google-anyscale-vpc-firewall/variables.tf index cc2f2ae..39c0a15 100644 --- a/modules/google-anyscale-vpc-firewall/variables.tf +++ b/modules/google-anyscale-vpc-firewall/variables.tf @@ -18,27 +18,27 @@ variable "vpc_name" { # OPTIONAL PARAMETERS # These variables have defaults, but may be overridden. # ------------------------------------------------------------------------------ -variable "anyscale_cloud_id" { - description = <<-EOT - (Optional) Anyscale Cloud ID. +# variable "anyscale_cloud_id" { +# description = <<-EOT +# (Optional) Anyscale Cloud ID. - ex: - ``` - anyscale_cloud_id = "cld_1234567890" - ``` - EOT - type = string - default = null - validation { - condition = ( - var.anyscale_cloud_id == null ? true : ( - length(var.anyscale_cloud_id) > 4 && - substr(var.anyscale_cloud_id, 0, 4) == "cld_" - ) - ) - error_message = "The anyscale_cloud_id value must start with \"cld_\"." - } -} +# ex: +# ``` +# anyscale_cloud_id = "cld_1234567890" +# ``` +# EOT +# type = string +# default = null +# validation { +# condition = ( +# var.anyscale_cloud_id == null ? true : ( +# length(var.anyscale_cloud_id) > 4 && +# substr(var.anyscale_cloud_id, 0, 4) == "cld_" +# ) +# ) +# error_message = "The anyscale_cloud_id value must start with \"cld_\"." +# } +# } variable "module_enabled" { description = <<-EOT @@ -214,6 +214,33 @@ variable "ingress_from_cidr_map" { default = [] } +variable "ingress_from_gcp_health_checks" { + description = <<-EOT + (Optional) List of ingress rules to create to allow GCP health check probes. + + This only uses rules from `predefined_firewall_rules`. + More information on GCP health checks can be found here: + https://cloud.google.com/load-balancing/docs/health-check-concepts#ip-ranges + + ex: + ``` + ingress_from_gcp_health_checks = [ + { + rule = "health-checks" + cidr_blocks = "35.191.0.0/16, 130.211.0.0/22" + } + ] + ``` + EOT + type = list(map(string)) + default = [ + { + rule = "health-checks" + cidr_blocks = "35.191.0.0/16,130.211.0.0/22" + } + ] +} + # -------------------- # Pre-defined rules # These are reuqired @@ -233,5 +260,7 @@ variable "predefined_firewall_rules" { ssh-tcp = [22, "tcp", "SSH", 1003] # NFS nfs-tcp = [2049, "tcp", "NFS/EFS", 1004] + # Health Checks + health-checks = [8000, "tcp", "Health Checks", 1005] } } diff --git a/modules/google-anyscale-vpc/README.md b/modules/google-anyscale-vpc/README.md index 14b1c4e..63efa24 100644 --- a/modules/google-anyscale-vpc/README.md +++ b/modules/google-anyscale-vpc/README.md @@ -23,9 +23,9 @@ This includes: | Name | Version | |------|---------| -| [google](#provider\_google) | 4.82.0 | -| [random](#provider\_random) | 3.5.1 | -| [time](#provider\_time) | 0.9.1 | +| [google](#provider\_google) | 4.84.0 | +| [random](#provider\_random) | 3.6.0 | +| [time](#provider\_time) | 0.10.0 | ## Modules @@ -49,7 +49,6 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID.

ex:
anyscale_cloud_id = "cld_1234567890"
| `string` | `null` | no | | [anyscale\_project\_id](#input\_anyscale\_project\_id) | (Optional) The ID of the project to create the resource in.

If it is not provided, the provider project is used.

ex:
anyscale_project_id = "gcp_anyscale"
| `string` | `null` | no | | [anyscale\_vpc\_name](#input\_anyscale\_vpc\_name) | (Optional) The name of the VPC.

This overrides the `anyscale_vpc_prefix` parameter.

ex:
anyscale_vpc_name = "anyscale-vpc"
| `string` | `null` | no | | [anyscale\_vpc\_name\_prefix](#input\_anyscale\_vpc\_name\_prefix) | (Optional) The prefix of the VPC name.

Creates a unique VPC name beginning with the specified prefix.

ex:
anyscale_vpc_name_prefix = "anyscale-vpc"
| `string` | `"anyscale-"` | no | diff --git a/modules/google-anyscale-vpc/examples/README.md b/modules/google-anyscale-vpc/examples/README.md index 232f8c3..039c4c8 100644 --- a/modules/google-anyscale-vpc/examples/README.md +++ b/modules/google-anyscale-vpc/examples/README.md @@ -52,8 +52,6 @@ No resources. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [anyscale\_cloud\_id](#input\_anyscale\_cloud\_id) | (Optional) Anyscale Cloud ID | `string` | `null` | no | -| [anyscale\_deploy\_env](#input\_anyscale\_deploy\_env) | (Required) Anyscale deploy environment. Used in resource names and tags. | `string` | n/a | yes | | [google\_project\_id](#input\_google\_project\_id) | ID of the Project to put these resources in | `string` | n/a | yes | | [google\_region](#input\_google\_region) | The Google region in which all resources will be created. | `string` | n/a | yes | diff --git a/modules/google-anyscale-vpc/examples/variables.tf b/modules/google-anyscale-vpc/examples/variables.tf index ac08335..b78d711 100644 --- a/modules/google-anyscale-vpc/examples/variables.tf +++ b/modules/google-anyscale-vpc/examples/variables.tf @@ -8,16 +8,6 @@ # REQUIRED VARIABLES # These variables must be set when using this module. # --------------------------------------------------------------------------------------------------------------------- -variable "anyscale_deploy_env" { - description = "(Required) Anyscale deploy environment. Used in resource names and tags." - type = string - validation { - condition = ( - var.anyscale_deploy_env == "production" || var.anyscale_deploy_env == "development" || var.anyscale_deploy_env == "test" - ) - error_message = "The anyscale_deploy_env only allows `production`, `test`, or `development`" - } -} variable "google_region" { description = "The Google region in which all resources will be created." @@ -33,26 +23,3 @@ variable "google_project_id" { # OPTIONAL PARAMETERS # These variables have defaults, but may be overridden. # ------------------------------------------------------------------------------ -variable "anyscale_cloud_id" { - description = "(Optional) Anyscale Cloud ID" - type = string - default = null - validation { - condition = ( - var.anyscale_cloud_id == null ? true : ( - length(var.anyscale_cloud_id) > 4 && - substr(var.anyscale_cloud_id, 0, 4) == "cld_" - ) - ) - error_message = "The anyscale_cloud_id value must start with \"cld_\"." - } -} - -# variable "labels" { -# description = "(Optional) A map of tags to all resources that accept tags." -# type = map(string) -# default = { -# "test" : true, -# "environment" : "test" -# } -# } diff --git a/modules/google-anyscale-vpc/proxy-subnet.tf b/modules/google-anyscale-vpc/proxy-subnet.tf index 1828369..3037fdc 100644 --- a/modules/google-anyscale-vpc/proxy-subnet.tf +++ b/modules/google-anyscale-vpc/proxy-subnet.tf @@ -17,9 +17,10 @@ resource "google_compute_subnetwork" "anyscale_proxy_subnet" { #checkov:skip=CKV_GCP_26:VPC Flow Logs disabled for Proxy Subnets count = local.proxy_subnet_enabled ? 1 : 0 - name = local.proxy_subnet_name_computed - ip_cidr_range = var.proxy_subnet_cidr - region = var.google_region + name = local.proxy_subnet_name_computed + ip_cidr_range = var.proxy_subnet_cidr + ipv6_access_type = "INTERNAL" + region = var.google_region network = google_compute_network.anyscale_vpc[0].name project = var.anyscale_project_id diff --git a/modules/google-anyscale-vpc/variables.tf b/modules/google-anyscale-vpc/variables.tf index 9f9d83b..85e0240 100644 --- a/modules/google-anyscale-vpc/variables.tf +++ b/modules/google-anyscale-vpc/variables.tf @@ -8,28 +8,6 @@ # OPTIONAL PARAMETERS # These variables have defaults, but may be overridden. # ------------------------------------------------------------------------------ -variable "anyscale_cloud_id" { - description = <<-EOT - (Optional) Anyscale Cloud ID. - - ex: - ``` - anyscale_cloud_id = "cld_1234567890" - ``` - EOT - type = string - default = null - validation { - condition = ( - var.anyscale_cloud_id == null ? true : ( - length(var.anyscale_cloud_id) > 4 && - substr(var.anyscale_cloud_id, 0, 4) == "cld_" - ) - ) - error_message = "The anyscale_cloud_id value must start with \"cld_\"." - } -} - variable "module_enabled" { description = <<-EOT (Optional) Determines whether to create the resources inside this module. diff --git a/outputs.tf b/outputs.tf index ce9b3b6..a51bb8f 100644 --- a/outputs.tf +++ b/outputs.tf @@ -57,6 +57,7 @@ output "private_subnet_region" { description = "The Google VPC private subnet region." value = try(module.google_anyscale_vpc.private_subnet_region, "") } + # ------------------------------------ # VPC Firewall Policy Outputs # ------------------------------------ @@ -114,21 +115,21 @@ output "filestore_fileshare_name" { # ------------------------------------ # IAM Resource Outputs # ------------------------------------ -output "iam_anyscale_access_role_id" { - description = "The Google IAM Anyscale Access Role id." - value = try(module.google_anyscale_iam.iam_anyscale_access_role_id, "") +output "iam_anyscale_access_service_acct_id" { + description = "The Google IAM Anyscale Access Service Account ID." + value = try(module.google_anyscale_iam.iam_anyscale_access_service_acct_id, "") } -output "iam_anyscale_access_role_name" { - description = "The Google IAM Anyscale Access Role name." - value = try(module.google_anyscale_iam.iam_anyscale_access_role_name, "") +output "iam_anyscale_access_service_acct_name" { + description = "The Google IAM Anyscale Access Service Account name." + value = try(module.google_anyscale_iam.iam_anyscale_access_service_acct_name, "") } -output "iam_anyscale_access_role_email" { - description = "The Google IAM Anyscale Access Role email." - value = try(module.google_anyscale_iam.iam_anyscale_access_role_email, "") +output "iam_anyscale_access_service_acct_email" { + description = "The Google IAM Anyscale Access Service Account email." + value = try(module.google_anyscale_iam.iam_anyscale_access_service_acct_email, "") } -output "iam_anyscale_access_role_unique_id" { - description = "The Google IAM Anyscale Access Role unique id." - value = try(module.google_anyscale_iam.iam_anyscale_access_role_unique_id, "") +output "iam_anyscale_access_service_acct_unique_id" { + description = "The Google IAM Anyscale Access Service Account unique id." + value = try(module.google_anyscale_iam.iam_anyscale_access_service_acct_unique_id, "") } output "iam_workload_identity_pool_id" { @@ -148,21 +149,21 @@ output "iam_workload_identity_provider_name" { value = try(module.google_anyscale_iam.iam_workload_identity_provider_name, "") } -output "iam_anyscale_cluster_node_role_id" { - description = "The Google IAM Anyscale Cluster Node Role id." - value = try(module.google_anyscale_iam.iam_anyscale_cluster_node_role_id, "") +output "iam_anyscale_cluster_node_service_acct_id" { + description = "The Google IAM Anyscale Cluster Node Service Account ID." + value = try(module.google_anyscale_iam.iam_anyscale_cluster_node_service_acct_id, "") } -output "iam_anyscale_cluster_node_role_name" { - description = "The Google IAM Anyscale Cluster Node Role name." - value = try(module.google_anyscale_iam.iam_anyscale_cluster_node_role_name, "") +output "iam_anyscale_cluster_node_service_acct_name" { + description = "The Google IAM Anyscale Cluster Node Service Accpimt name." + value = try(module.google_anyscale_iam.iam_anyscale_cluster_node_service_acct_name, "") } -output "iam_anyscale_cluster_node_role_email" { - description = "The Google IAM Anyscale Cluster Node Role email." - value = try(module.google_anyscale_iam.iam_anyscale_cluster_node_role_email, "") +output "iam_anyscale_cluster_node_service_acct_email" { + description = "The Google IAM Anyscale Cluster Node Service Account email." + value = try(module.google_anyscale_iam.iam_anyscale_cluster_node_service_acct_email, "") } -output "iam_anyscale_cluster_node_role_unique_id" { - description = "The Google IAM Anyscale Cluster Node Role unique id." - value = try(module.google_anyscale_iam.iam_anyscale_cluster_node_role_unique_id, "") +output "iam_anyscale_cluster_node_service_acct_unique_id" { + description = "The Google IAM Anyscale Cluster Node Service Account unique id." + value = try(module.google_anyscale_iam.iam_anyscale_cluster_node_service_acct_unique_id, "") } # ------------------------------------ diff --git a/test/anyscale-v2-e2e-private-test/outputs.tf b/test/anyscale-v2-e2e-private-test/outputs.tf index aee08a2..9ba2a00 100644 --- a/test/anyscale-v2-e2e-private-test/outputs.tf +++ b/test/anyscale-v2-e2e-private-test/outputs.tf @@ -36,12 +36,12 @@ output "filestore_location" { output "anyscale_iam_service_account_email" { description = "The Anyscale service account email." - value = module.google_anyscale_v2_privatenetwork.iam_anyscale_access_role_email + value = module.google_anyscale_v2_privatenetwork.iam_anyscale_access_service_acct_email } -output "anyscale_iam_cluster_node_role_email" { +output "anyscale_iam_cluster_node_service_acct_email" { description = "The Anyscale cluster service account email." - value = module.google_anyscale_v2_privatenetwork.iam_anyscale_cluster_node_role_email + value = module.google_anyscale_v2_privatenetwork.iam_anyscale_cluster_node_service_acct_email } output "anyscale_iam_workload_identity_provider_id" { @@ -55,6 +55,6 @@ output "anyscale_iam_workload_identity_provider_name" { output "registration_command" { description = "The Anyscale registration command." - value = "anyscale cloud register --provider gcp \\\n--name \\\n--project-id ${module.google_anyscale_v2_privatenetwork.project_name} \\\n--vpc-name ${module.google_anyscale_v2_privatenetwork.vpc_name} \\\n--subnet-names ${module.google_anyscale_v2_privatenetwork.private_subnet_name} \\\n--region ${module.google_anyscale_v2_privatenetwork.private_subnet_region} \\\n--firewall-policy-names ${module.google_anyscale_v2_privatenetwork.vpc_firewall_policy_name} \\\n--cloud-storage-bucket-name ${module.google_anyscale_v2_privatenetwork.cloudstorage_bucket_name} \\\n--filestore-instance-id ${module.google_anyscale_v2_privatenetwork.filestore_name} \\\n--filestore-location ${module.google_anyscale_v2_privatenetwork.filestore_location} \\\n--anyscale-service-account-email ${module.google_anyscale_v2_privatenetwork.iam_anyscale_access_role_email} \\\n--instance-service-account-email ${module.google_anyscale_v2_privatenetwork.iam_anyscale_cluster_node_role_email} \\\n--provider-name ${module.google_anyscale_v2_privatenetwork.iam_workload_identity_provider_name} \\\n--private-network" + value = "anyscale cloud register --provider gcp \\\n--name \\\n--project-id ${module.google_anyscale_v2_privatenetwork.project_name} \\\n--vpc-name ${module.google_anyscale_v2_privatenetwork.vpc_name} \\\n--subnet-names ${module.google_anyscale_v2_privatenetwork.private_subnet_name} \\\n--region ${module.google_anyscale_v2_privatenetwork.private_subnet_region} \\\n--firewall-policy-names ${module.google_anyscale_v2_privatenetwork.vpc_firewall_policy_name} \\\n--cloud-storage-bucket-name ${module.google_anyscale_v2_privatenetwork.cloudstorage_bucket_name} \\\n--filestore-instance-id ${module.google_anyscale_v2_privatenetwork.filestore_name} \\\n--filestore-location ${module.google_anyscale_v2_privatenetwork.filestore_location} \\\n--anyscale-service-account-email ${module.google_anyscale_v2_privatenetwork.iam_anyscale_access_service_acct_email} \\\n--instance-service-account-email ${module.google_anyscale_v2_privatenetwork.iam_anyscale_cluster_node_service_acct_email} \\\n--provider-name ${module.google_anyscale_v2_privatenetwork.iam_workload_identity_provider_name} \\\n--private-network" } # diff --git a/test/anyscale-v2-e2e-public-test/outputs.tf b/test/anyscale-v2-e2e-public-test/outputs.tf index 939d23a..65f0d30 100644 --- a/test/anyscale-v2-e2e-public-test/outputs.tf +++ b/test/anyscale-v2-e2e-public-test/outputs.tf @@ -36,12 +36,12 @@ output "filestore_location" { output "anyscale_iam_service_account_email" { description = "The Anyscale service account email." - value = module.google_anyscale_v2_commonname.iam_anyscale_access_role_email + value = module.google_anyscale_v2_commonname.iam_anyscale_access_service_acct_email } -output "anyscale_iam_cluster_node_role_email" { +output "anyscale_iam_cluster_node_service_acct_email" { description = "The Anyscale cluster service account email." - value = module.google_anyscale_v2_commonname.iam_anyscale_cluster_node_role_email + value = module.google_anyscale_v2_commonname.iam_anyscale_cluster_node_service_acct_email } output "anyscale_iam_workload_identity_provider_id" { @@ -55,6 +55,6 @@ output "anyscale_iam_workload_identity_provider_name" { output "registration_command" { description = "The Anyscale registration command." - value = "anyscale cloud register --provider gcp \\\n--name \\\n--project-id ${module.google_anyscale_v2_commonname.project_name} \\\n--vpc-name ${module.google_anyscale_v2_commonname.vpc_name} \\\n--subnet-names ${module.google_anyscale_v2_commonname.public_subnet_name} \\\n--region ${module.google_anyscale_v2_commonname.public_subnet_region} \\\n--firewall-policy-names ${module.google_anyscale_v2_commonname.vpc_firewall_policy_name} \\\n--cloud-storage-bucket-name ${module.google_anyscale_v2_commonname.cloudstorage_bucket_name} \\\n--filestore-instance-id ${module.google_anyscale_v2_commonname.filestore_name} \\\n--filestore-location ${module.google_anyscale_v2_commonname.filestore_location} \\\n--anyscale-service-account-email ${module.google_anyscale_v2_commonname.iam_anyscale_access_role_email} \\\n--instance-service-account-email ${module.google_anyscale_v2_commonname.iam_anyscale_cluster_node_role_email} \\\n--provider-name ${module.google_anyscale_v2_commonname.iam_workload_identity_provider_name}" + value = "anyscale cloud register --provider gcp \\\n--name \\\n--project-id ${module.google_anyscale_v2_commonname.project_name} \\\n--vpc-name ${module.google_anyscale_v2_commonname.vpc_name} \\\n--subnet-names ${module.google_anyscale_v2_commonname.public_subnet_name} \\\n--region ${module.google_anyscale_v2_commonname.public_subnet_region} \\\n--firewall-policy-names ${module.google_anyscale_v2_commonname.vpc_firewall_policy_name} \\\n--cloud-storage-bucket-name ${module.google_anyscale_v2_commonname.cloudstorage_bucket_name} \\\n--filestore-instance-id ${module.google_anyscale_v2_commonname.filestore_name} \\\n--filestore-location ${module.google_anyscale_v2_commonname.filestore_location} \\\n--anyscale-service-account-email ${module.google_anyscale_v2_commonname.iam_anyscale_access_service_acct_email} \\\n--instance-service-account-email ${module.google_anyscale_v2_commonname.iam_anyscale_cluster_node_service_acct_email} \\\n--provider-name ${module.google_anyscale_v2_commonname.iam_workload_identity_provider_name}" } # diff --git a/test/test_cloud_register_manual.py b/test/test_cloud_register_manual.py index 14f18a6..5fc49ac 100644 --- a/test/test_cloud_register_manual.py +++ b/test/test_cloud_register_manual.py @@ -32,7 +32,18 @@ from anyscale.controllers.cloud_controller import CloudController from python_terraform import Terraform, IsFlagged, IsNotFlagged -logging.basicConfig(level=logging.INFO, format="%(message)s", handlers=[RichHandler()]) +logging.basicConfig( + level=logging.INFO, + format="%(message)s", + handlers=[ + RichHandler( + show_path=False, + enable_link_path=False, + rich_tracebacks=True, + tracebacks_suppress=[CloudController, Terraform], + ) + ], +) logger = logging.getLogger("rich") @@ -87,7 +98,14 @@ def _terraform_apply(tf: Terraform, expected_time: int, variables: dict): var=variables, ) - logger.info(" Succesfull: terraform apply") + if return_code == 0: + logger.info(" Succesfull: terraform apply") + else: + logger.error(" Failed: terraform apply") + logger.error(stdout) + logger.error(stderr) + + logger.debug(stdout) return return_code, stdout, stderr except Exception as e: logger.error(f"Terraform apply failed: {e}") @@ -105,13 +123,40 @@ def _terraform_destroy(tf: Terraform, variables: dict): var=variables, ) - logger.info(" Succesfull: terraform destroy") + if return_code == 0: + logger.info(" Succesfull: terraform destroy") + else: + logger.error(" Failed: terraform destroy") + logger.error(stdout) + logger.error(stderr) + + logger.debug(stdout) return return_code, stdout, stderr except Exception as e: logger.error(f"Error running terraform destroy: {e}") raise e +def _anyscale_cloud_verify(cloud_controller: CloudController, cloud_name: str): + """Run Functional Verify on the Anyscale Cloud.""" + logger.info("Starting: Anyscale functional test") + try: + cloud_controller.verify_cloud( + cloud_name=cloud_name, + cloud_id=None, + strict=True, + # Change functional_verify="workspace,service" once service is ready. + # Requires user confirmation to proceed or setting yes=True + functional_verify="workspace", + yes=True, + ) + logger.info(" Completed: Anyscale Cloud verified successfully") + return 0 + except Exception as e: + logger.error(f" Error verifying cloud: {e}") + return 1 + + def _anyscale_cloud_delete(cloud_controller: CloudController, cloud_name: str): """Delete the cloud from anyscale.""" logger.info("Running: anyscale cloud delete") @@ -152,7 +197,7 @@ def _parse_registration_command(input_string): return None registration_command = match.group(1) - logger.debug(registration_command) + logger.debug(f"registration_command: {registration_command}") return _parse_options(registration_command) @@ -199,8 +244,8 @@ def start_aws_test(branch_name: str, local_path: str): task_id = e2e_progress.add_task("", total=100) e2e_progress.update(task_id, description="Running: terraform init") - return_code, stdout, stderr = _terraform_init(tf) - if return_code != 0: + tf_init_return_code, stdout, stderr = _terraform_init(tf) + if tf_init_return_code != 0: raise RuntimeError(f"Error initializing terraform: {stderr}") e2e_progress.update( @@ -208,132 +253,125 @@ def start_aws_test(branch_name: str, local_path: str): description="Running: terraform apply", advance=20, ) - return_code, stdout, stderr = _terraform_apply( + tf_apply_return_code, stdout, stderr = _terraform_apply( tf, 5, _get_terraform_anyscale_v2_e2e_public_vars_aws(), ) - if return_code != 0: - logger.error("Error running: terraform apply") - logger.error(stderr) - logger.debug(stdout) - - logger.info("Applied AWS Terraform: anyscale_v2_e2e_public") - - ## Gather information for registration - cloud_name = ( - f"test_terraform_anyscale_v2_e2e_public_aws_{datetime.now().isoformat()}" - ) - stdout_dict = _parse_registration_command(stdout) - s3_bucket_id = stdout_dict.get("s3-bucket-id") ## Register the cloud. - e2e_progress.update( - task_id, - description="Registering Anyscale AWS cloud...", - advance=40, - ) - try: - cloud_controller = CloudController() - cloud_controller.register_aws_cloud( - region=stdout_dict.get("region"), - name=cloud_name, - vpc_id=stdout_dict.get("vpc-id"), - subnet_ids=stdout_dict.get("subnet-ids").split(","), - efs_id=stdout_dict.get("efs-id"), - anyscale_iam_role_id=stdout_dict.get("anyscale-iam-role-id"), - instance_iam_role_id=stdout_dict.get("instance-iam-role-id"), - security_group_ids=stdout_dict.get("security-group-ids").split(","), - s3_bucket_id=s3_bucket_id, - # Changed functional_verify to `None` to - # allow Anyscale resources time to be created. - functional_verify=None, - private_network=False, - cluster_management_stack_version="v2", - memorydb_cluster_id=None, - yes=True, + if tf_apply_return_code == 0: + logger.info("Applied Terraform: anyscale_v2_e2e_public") + + ## Gather information for registration + cloud_name = f"test_terraform_anyscale_v2_e2e_public_aws_{datetime.now().isoformat()}" # noqa: E501 + stdout_dict = _parse_registration_command(stdout) + s3_bucket_id = stdout_dict.get("s3-bucket-id") + logger.info(f"stdout_dict: {stdout_dict}") + + e2e_progress.update( + task_id, + description="Registering Anyscale AWS cloud...", + advance=40, + ) + try: + cloud_controller = CloudController() + cloud_controller.register_aws_cloud( + region=stdout_dict.get("region"), + name=cloud_name, + vpc_id=stdout_dict.get("vpc-id"), + subnet_ids=stdout_dict.get("subnet-ids").split(","), + efs_id=stdout_dict.get("efs-id"), + anyscale_iam_role_id=stdout_dict.get("anyscale-iam-role-id"), + instance_iam_role_id=stdout_dict.get("instance-iam-role-id"), + security_group_ids=stdout_dict.get("security-group-ids").split(","), + s3_bucket_id=s3_bucket_id, + # Changed functional_verify to `None` to + # allow Anyscale resources time to be created. + functional_verify=None, + private_network=False, + cluster_management_stack_version="v2", + memorydb_cluster_id=None, + yes=True, + ) + logger.info(" Cloud registered successfully") + register_cloud_return_code = 0 + except Exception as e: + logger.error(f"Error registering cloud: {e}") + register_cloud_return_code = 1 + + if register_cloud_return_code == 0: + e2e_progress.update( + task_id, + description="Sleeping: Waiting for Anyscale resources", + advance=30, + ) + # pause for 3 min to wait for Anyscale to be ready + _sleep_timer(60 * 3) + e2e_progress.update( + task_id, + description="Proceeding with Anyscale functional test", + completed=100, ) - logger.info(" Cloud registered successfully") - except Exception as e: - logger.error(f"Error registering cloud: {e}") + e2e_progress.stop_task(task_id) + wait_for_cloud_return_code = 0 - e2e_progress.update( - task_id, description="Sleeping: Waiting for Anyscale resources", advance=30 - ) - # pause for 3 min to wait for Anyscale to be ready - _sleep_timer(60 * 3) - e2e_progress.update( - task_id, - description="Proceeding with Anyscale functional test", - completed=100, - ) - e2e_progress.stop_task(task_id) - - logger.info("Starting: Anyscale functional test") - try: - cloud_controller.verify_cloud( - cloud_name=cloud_name, - cloud_id=None, - strict=True, - # Change functional_verify="workspace,service" once service is ready. - # Requires user confirmation to proceed or setting yes=True - functional_verify="workspace", - yes=True, - ) - logger.info(" Completed: AWS Cloud verified successfully") - except Exception as e: - logger.error(f"Error verifying aws cloud: {e}") + if wait_for_cloud_return_code == 0: + verify_cloud_return_code = _anyscale_cloud_verify(cloud_controller, cloud_name) with live: task_id = e2e_progress.add_task("", total=100) ## Delete the cloud. - e2e_progress.update(task_id, description="Deleting Anyscale AWS cloud...") - _anyscale_cloud_delete(cloud_controller, cloud_name) - - ## Emptying the bucket. - e2e_progress.update( - task_id, - description=f"Emptying bucket {s3_bucket_id}...", - advance=30, - ) - s3_client = boto3.client("s3") - object_response_paginator = s3_client.get_paginator("list_object_versions") - delete_marker_list = [] - version_list = [] - for object_response_itr in object_response_paginator.paginate( - Bucket=s3_bucket_id - ): - if "DeleteMarkers" in object_response_itr: - for delete_marker in object_response_itr["DeleteMarkers"]: - delete_marker_list.append( - { - "Key": delete_marker["Key"], - "VersionId": delete_marker["VersionId"], - } - ) - - if "Versions" in object_response_itr: - for version in object_response_itr["Versions"]: - version_list.append( - {"Key": version["Key"], "VersionId": version["VersionId"]} - ) - - for i in range(0, len(delete_marker_list), 1000): - response = s3_client.delete_objects( - Bucket=s3_bucket_id, - Delete={"Objects": delete_marker_list[i : i + 1000], "Quiet": True}, + if register_cloud_return_code == 0: + e2e_progress.update(task_id, description="Deleting Anyscale AWS cloud...") + delete_cloud_return_code = _anyscale_cloud_delete( + cloud_controller, cloud_name ) - logger.debug(response) - for i in range(0, len(version_list), 1000): - response = s3_client.delete_objects( - Bucket=s3_bucket_id, - Delete={"Objects": version_list[i : i + 1000], "Quiet": True}, + ## Emptying the bucket. + e2e_progress.update( + task_id, + description=f"Emptying bucket {s3_bucket_id}...", + advance=30, ) - logger.debug(response) - - logger.info(f"S3 bucket {s3_bucket_id} emptied successfully") + s3_client = boto3.client("s3") + object_response_paginator = s3_client.get_paginator("list_object_versions") + delete_marker_list = [] + version_list = [] + for object_response_itr in object_response_paginator.paginate( + Bucket=s3_bucket_id + ): + if "DeleteMarkers" in object_response_itr: + for delete_marker in object_response_itr["DeleteMarkers"]: + delete_marker_list.append( + { + "Key": delete_marker["Key"], + "VersionId": delete_marker["VersionId"], + } + ) + + if "Versions" in object_response_itr: + for version in object_response_itr["Versions"]: + version_list.append( + {"Key": version["Key"], "VersionId": version["VersionId"]} + ) + + for i in range(0, len(delete_marker_list), 1000): + response = s3_client.delete_objects( + Bucket=s3_bucket_id, + Delete={"Objects": delete_marker_list[i : i + 1000], "Quiet": True}, + ) + logger.debug(response) + + for i in range(0, len(version_list), 1000): + response = s3_client.delete_objects( + Bucket=s3_bucket_id, + Delete={"Objects": version_list[i : i + 1000], "Quiet": True}, + ) + logger.debug(response) + + logger.info(f"S3 bucket {s3_bucket_id} emptied successfully") ## Destroy the terraform. e2e_progress.update( @@ -341,18 +379,26 @@ def start_aws_test(branch_name: str, local_path: str): description="Running: terraform destroy", advance=40, ) - return_code, stdout, stderr = _terraform_destroy( + tf_destroy_return_code, stdout, stderr = _terraform_destroy( tf, variables=_get_terraform_anyscale_v2_e2e_public_vars_aws() ) - if return_code != 0: - logger.error("Error running: terraform destroy") - logger.error(stderr) - logger.info("Destroyed anyscale_v2_e2e_public aws terraform successfully") + if tf_destroy_return_code == 0: + logger.info("Destroyed anyscale_v2_e2e_public aws terraform successfully") logger.debug(stdout) e2e_progress.update(task_id, description="E2E test complete!", completed=100) + if ( + delete_cloud_return_code != 0 + or wait_for_cloud_return_code != 0 + or register_cloud_return_code != 0 + or verify_cloud_return_code != 0 + or tf_destroy_return_code != 0 + or tf_apply_return_code != 0 + ): # noqa: E501 + raise RuntimeError("E2E test failed") + def start_gcp_test( branch_name: str, @@ -381,8 +427,8 @@ def start_gcp_test( task_id = e2e_progress.add_task("", total=100) e2e_progress.update(task_id, description="Running: terraform init") - return_code, stdout, stderr = _terraform_init(tf) - if return_code != 0: + tf_init_return_code, stdout, stderr = _terraform_init(tf) + if tf_init_return_code != 0: raise RuntimeError(f"Error initializing terraform: {stderr}") e2e_progress.update( @@ -390,7 +436,7 @@ def start_gcp_test( description="Running: terraform apply", advance=20, ) - return_code, stdout, stderr = _terraform_apply( + tf_apply_return_code, stdout, stderr = _terraform_apply( tf, 10, _get_terraform_anyscale_v2_e2e_public_vars_gcp( @@ -399,123 +445,117 @@ def start_gcp_test( root_folder_number=root_folder_number, ), ) - if return_code != 0: - logger.error("Error running: terraform apply") - logger.error(stderr) - logger.info("Applied GCP Terraform: anyscale_v2_e2e_public") + if tf_apply_return_code == 0: + logger.info("Applied Terraform: anyscale_v2_e2e_public") - # pause for GCP to be ready - _sleep_timer(60) - e2e_progress.update( - task_id, - description="Registering Anyscale GCP cloud...", - completed=10, - ) - - ## Gather information for registration - cloud_name = ( - f"test_terraform_anyscale_v2_e2e_public_gcp_{datetime.now().isoformat()}" - ) - stdout_dict = _parse_registration_command(stdout) - logger.debug(f"Parsed stdout_dict: {stdout_dict}") - logger.info("Registering gcp cloud...") - bucket_name = stdout_dict.get("cloud-storage-bucket-name") - - try: - cloud_controller = CloudController() - cloud_controller.register_gcp_cloud( - region=stdout_dict.get("region"), - name=cloud_name, - project_id=stdout_dict.get("project-id"), - vpc_name=stdout_dict.get("vpc-name"), - subnet_names=stdout_dict.get("subnet-names").split(","), - filestore_instance_id=stdout_dict.get("filestore-instance-id"), - filestore_location=stdout_dict.get("filestore-location"), - anyscale_service_account_email=stdout_dict.get( - "anyscale-service-account-email" - ), - instance_service_account_email=stdout_dict.get( - "instance-service-account-email" - ), - provider_id=stdout_dict.get("provider-name"), - firewall_policy_names=stdout_dict.get("firewall-policy-names").split( - "," - ), - cloud_storage_bucket_name=bucket_name, - # Changed functional_verify=None to - # allow Anyscale Resources time to be created. - functional_verify=None, - private_network=False, - cluster_management_stack_version="v2", - memorystore_instance_name=None, - yes=True, + # pause for GCP to be ready + _sleep_timer(60) + e2e_progress.update( + task_id, + description="Registering Anyscale GCP cloud...", + completed=10, ) - logger.info("Cloud registered successfully") - except Exception as e: - logger.info(f"Error registering gcp cloud: {e}") - e2e_progress.update( - task_id, description="Sleeping: Waiting for Anyscale resources", advance=30 - ) - # pause for 3 min to wait for Anyscale to be ready - _sleep_timer(60 * 3) - e2e_progress.update( - task_id, - description="Proceeding with Anyscale functional test", - completed=100, - ) - e2e_progress.stop_task(task_id) + ## Gather information for registration + cloud_name = f"test_terraform_anyscale_v2_e2e_public_gcp_{datetime.now().isoformat()}" # noqa: E501 + stdout_dict = _parse_registration_command(stdout) + logger.debug(f"Parsed stdout_dict: {stdout_dict}") + logger.info("Registering gcp cloud...") + bucket_name = stdout_dict.get("cloud-storage-bucket-name") + try: + cloud_controller = CloudController() + cloud_controller.register_gcp_cloud( + region=stdout_dict.get("region"), + name=cloud_name, + project_id=stdout_dict.get("project-id"), + vpc_name=stdout_dict.get("vpc-name"), + subnet_names=stdout_dict.get("subnet-names").split(","), + filestore_instance_id=stdout_dict.get("filestore-instance-id"), + filestore_location=stdout_dict.get("filestore-location"), + anyscale_service_account_email=stdout_dict.get( + "anyscale-service-account-email" + ), + instance_service_account_email=stdout_dict.get( + "instance-service-account-email" + ), + provider_id=stdout_dict.get("provider-name"), + firewall_policy_names=stdout_dict.get( + "firewall-policy-names" + ).split(","), + cloud_storage_bucket_name=bucket_name, + # Changed functional_verify=None to + # allow Anyscale Resources time to be created. + functional_verify=None, + private_network=False, + cluster_management_stack_version="v2", + memorystore_instance_name=None, + yes=True, + ) + logger.info("Cloud registered successfully") + register_cloud_return_code = 0 + except Exception as e: + logger.info(f"Error registering gcp cloud: {e}") + register_cloud_return_code = 1 + + if register_cloud_return_code == 0: + e2e_progress.update( + task_id, + description="Sleeping: Waiting for Anyscale resources", + advance=30, + ) + # pause for 3 min to wait for Anyscale to be ready + _sleep_timer(60 * 3) + e2e_progress.update( + task_id, + description="Proceeding with Anyscale functional test", + completed=100, + ) + e2e_progress.stop_task(task_id) + wait_for_cloud_return_code = 0 ## Verify the cloud. - logger.info("Starting: Anyscale functional test") - try: - cloud_controller.verify_cloud( - cloud_name=cloud_name, - cloud_id=None, - strict=True, - functional_verify="workspace", - yes=True, - ) - logger.info("GCP Cloud verified successfully") - except Exception as e: - logger.info(f"Error verifying gcp cloud: {e}") + if wait_for_cloud_return_code == 0: + verify_cloud_return_code = _anyscale_cloud_verify(cloud_controller, cloud_name) with live: task_id = e2e_progress.add_task("", total=100) ## Delete the cloud. - e2e_progress.update(task_id, description="Deleting Anyscale AWS cloud...") - _anyscale_cloud_delete(cloud_controller, cloud_name) + if register_cloud_return_code == 0: + e2e_progress.update(task_id, description="Deleting Anyscale cloud...") + delete_cloud_return_code = _anyscale_cloud_delete( + cloud_controller, cloud_name + ) - # ## Emptying bucket - e2e_progress.update( - task_id, - description=f"Emptying bucket {bucket_name}...", - advance=30, - ) - try: - storage_client = storage.Client() - bucket = storage_client.bucket(bucket_name) + # Emptying bucket + e2e_progress.update( + task_id, + description=f"Emptying bucket {bucket_name}...", + advance=30, + ) + try: + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) - # get all objects and delete them - blobs = list(bucket.list_blobs()) - blobs_count = len(blobs) + # get all objects and delete them + blobs = list(bucket.list_blobs()) + blobs_count = len(blobs) - step_task_id = step_progress.add_task( - f"Emptying bucket: {bucket_name}", total=blobs_count - ) + step_task_id = step_progress.add_task( + f"Emptying bucket: {bucket_name}", total=blobs_count + ) - for blob in blobs: - blob.delete() - step_progress.update(step_task_id, advance=1) + for blob in blobs: + blob.delete() + step_progress.update(step_task_id, advance=1) - logger.info(f"Bucket {bucket_name} emptied successfully") - step_progress.stop_task(step_task_id) - step_progress.update(step_task_id, visible=False) + logger.info(f"Bucket {bucket_name} emptied successfully") + step_progress.stop_task(step_task_id) + step_progress.update(step_task_id, visible=False) - except Exception as e: - logger.info(f"Error emptying bucket {bucket_name}: {e}") + except Exception as e: + logger.info(f"Error emptying bucket {bucket_name}: {e}") # Destroy the terraform. e2e_progress.update( @@ -523,7 +563,7 @@ def start_gcp_test( description="Running: terraform destroy", advance=40, ) - return_code, stdout, stderr = _terraform_destroy( + tf_destroy_return_code, stdout, stderr = _terraform_destroy( tf, _get_terraform_anyscale_v2_e2e_public_vars_gcp( billing_account_id=gcp_billing_id, @@ -531,14 +571,22 @@ def start_gcp_test( root_folder_number=root_folder_number, ), ) - if return_code != 0: - raise RuntimeError(f"Error destroying terraform: {stderr}") - - logger.info("Destroyed anyscale_v2_e2e_public gcp terraform successfully") + if tf_destroy_return_code == 0: + logger.info("Destroyed anyscale_v2_e2e_public gcp terraform successfully") logger.debug(stdout) e2e_progress.update(task_id, description="E2E test complete!", completed=100) + if ( + delete_cloud_return_code != 0 + or wait_for_cloud_return_code != 0 + or register_cloud_return_code != 0 + or verify_cloud_return_code != 0 + or tf_destroy_return_code != 0 + or tf_apply_return_code != 0 + ): # noqa: E501 + raise RuntimeError("E2E test failed") + if __name__ == "__main__": parser = argparse.ArgumentParser() diff --git a/variables.tf b/variables.tf index a8157f6..a49eda5 100644 --- a/variables.tf +++ b/variables.tf @@ -1036,65 +1036,120 @@ variable "enable_anyscale_iam" { default = true } -variable "anyscale_iam_access_role_name" { +variable "anyscale_iam_access_service_acct_name" { description = <<-EOT - (Optional - forces new resource) IAM Access Role Name + (Optional - forces new resource) IAM Access Service Account Name The name of the IAM role that will be created for Anyscale access. - - If left `null`, will default to `anyscale_iam_access_role_name_prefix`. - - If provided, overrides the `anyscale_iam_access_role_name_prefix` variable. + - If left `null`, will default to `anyscale_iam_access_service_acct_name_prefix`. + - If provided, overrides the `anyscale_iam_access_service_acct_name_prefix` variable. - It needs to be > 4 chars and < 28 chars. ex: ``` - anyscale_iam_access_role_name = "anyscale-crossacct-access" + anyscale_iam_access_service_acct_name = "anyscale-crossacct-access" ``` EOT type = string default = null validation { - condition = var.anyscale_iam_access_role_name == null ? true : ( - can(regex("^(?:[a-z](?:[-a-z0-9]{4,28}[a-z0-9])?)$", var.anyscale_iam_access_role_name)) + condition = var.anyscale_iam_access_service_acct_name == null ? true : ( + can(regex("^(?:[a-z](?:[-a-z0-9]{4,28}[a-z0-9])?)$", var.anyscale_iam_access_service_acct_name)) ) - error_message = "`anyscale_iam_access_role_name` must start with a lowercase letter followed by up to 28 lowercase letters, numbers, or hyphens." + error_message = "`anyscale_iam_access_service_acct_name` must start with a lowercase letter followed by up to 28 lowercase letters, numbers, or hyphens." } } -variable "anyscale_iam_access_role_name_prefix" { +variable "anyscale_iam_access_service_acct_name_prefix" { description = <<-EOT (Optional - forces new resource) IAM Access Role Name Prefix - Creates a unique IAM role name beginning with the specified prefix. - - If `anyscale_iam_access_role_name` is provided, it will override this variable. + Creates a unique IAM Service Account name beginning with the specified prefix. + - If `anyscale_iam_access_service_acct_name` is provided, it will override this variable. - The variable `general_prefix` is a fall-back prefix if this is not provided. - Default is `null` but is set to `anyscale-crossacct-` in a local variable. - It needs to be > 4 chars and < 20 chars. ex: ``` - anyscale_iam_access_role_name_prefix = "anyscale-crossacct-" + anyscale_iam_access_service_acct_name_prefix = "anyscale-crossacct-" ``` EOT type = string default = null validation { - condition = var.anyscale_iam_access_role_name_prefix == null ? true : ( - can(regex("^(?:[a-z](?:[-a-z0-9]{4,20})?)$", var.anyscale_iam_access_role_name_prefix)) + condition = var.anyscale_iam_access_service_acct_name_prefix == null ? true : ( + can(regex("^(?:[a-z](?:[-a-z0-9]{4,20})?)$", var.anyscale_iam_access_service_acct_name_prefix)) ) - error_message = "`anyscale_iam_access_role_name_prefix` must start with a lowercase letter followed by up to 20 lowercase letters, numbers, or hyphens." + error_message = "`anyscale_iam_access_service_acct_name_prefix` must start with a lowercase letter followed by up to 20 lowercase letters, numbers, or hyphens." } } -variable "anyscale_iam_access_role_description" { +variable "anyscale_iam_access_service_acct_description" { description = <<-EOT (Optional) The description of the IAM role that will be created for Anyscale access. ex: ``` - anyscale_iam_access_role_description = "Anyscale Cross Account Access" + anyscale_iam_access_service_acct_description = "Anyscale Cross Account Access" + ``` + EOT + type = string + default = null +} + +variable "anyscale_iam_access_role_id" { + description = <<-EOT + (Optional, forces creation of new resource) The ID of the Anyscale IAM access role. + + Overrides `anyscale_iam_access_role_id_prefix`. + + ex: + ``` + anyscale_iam_access_role_id = "anyscale_access_role" ``` EOT type = string default = null + validation { + condition = var.anyscale_iam_access_role_id == null ? true : ( + can(regex("^[a-zA-Z0-9_]{4,28}$", var.anyscale_iam_access_role_id)) + ) + error_message = "`anyscale_iam_access_role_id` must match regex: ^[a-zA-Z0-9_]{4,28}$." + } +} +variable "anyscale_iam_access_role_id_prefix" { + description = <<-EOT + (Optional, forces creation of new resource) The prefix of the Anyscale IAM access role. + + If `anyscale_iam_access_role_id` is provided, it will override this variable. + If set to `null`, the prefix will be set to \"anyscale_\" in a local variable. + + ex: + ``` + anyscale_iam_access_role_id_prefix = "anyscale_crossacct_role_" + ``` + EOT + type = string + default = "anyscale_crossacct_role_" + validation { + condition = var.anyscale_iam_access_role_id_prefix == null ? true : ( + can(regex("^[a-zA-Z0-9_]{4,24}$", var.anyscale_iam_access_role_id_prefix)) + ) + error_message = "`anyscale_iam_access_role_id_prefix` must match regex: ^[a-zA-Z0-9_]{4,24}$." + } } +variable "anyscale_access_role_description" { + description = <<-EOT + (Optional) The description of the Anyscale IAM access role. + + ex: + ``` + anyscale_access_role_description = "Anyscale Cross Account Access" + ``` + EOT + type = string + default = "Anyscale Cross Account Access Role" +} + variable "existing_workload_identity_provider_name" { description = <<-EOF @@ -1190,61 +1245,61 @@ variable "anyscale_workload_identity_account_id" { default = null } -variable "anyscale_cluster_node_role_name" { +variable "anyscale_cluster_node_service_acct_name" { description = <<-EOT (Optional - forces new resource) IAM Cluster Node Role Name The name of the IAM role that will be created for Anyscale cluster nodes. - - If left `null`, will default to anyscale_cluster_node_role_name_prefix. - - If provided, overrides the anyscale_cluster_node_role_name_prefix variable. + - If left `null`, will default to anyscale_cluster_node_service_acct_name_prefix. + - If provided, overrides the anyscale_cluster_node_service_acct_name_prefix variable. - It needs to be > 4 chars and < 28 chars. ex: ``` - anyscale_cluster_node_role_name = "anyscale-cluster-node" + anyscale_cluster_node_service_acct_name = "anyscale-cluster-node" ``` EOT type = string default = null validation { - condition = var.anyscale_cluster_node_role_name == null ? true : ( - can(regex("^(?:[a-z](?:[-a-z0-9]{4,28}[a-z0-9])?)$", var.anyscale_cluster_node_role_name)) + condition = var.anyscale_cluster_node_service_acct_name == null ? true : ( + can(regex("^(?:[a-z](?:[-a-z0-9]{4,28}[a-z0-9])?)$", var.anyscale_cluster_node_service_acct_name)) ) - error_message = "`anyscale_cluster_node_role_name` must start with a lowercase letter followed by up to 28 lowercase letters, numbers, or hyphens." + error_message = "`anyscale_cluster_node_service_acct_name` must start with a lowercase letter followed by up to 28 lowercase letters, numbers, or hyphens." } } -variable "anyscale_cluster_node_role_name_prefix" { +variable "anyscale_cluster_node_service_acct_name_prefix" { description = <<-EOT (Optional - forces new resource) IAM Cluster Node Role Name Prefix Creates a unique IAM role name beginning with the specified prefix. - - If `anyscale_cluster_node_role_name` is provided, it will override this variable. + - If `anyscale_cluster_node_service_acct_name` is provided, it will override this variable. - The variable `general_prefix` is a fall-back prefix if this is not provided. - Default is `null` but is set to `anyscale-cluster-` in a local variable. - It needs to be > 4 chars and < 20 chars. ex: ``` - anyscale_cluster_node_role_name_prefix = "anyscale-cluster-" + anyscale_cluster_node_service_acct_name_prefix = "anyscale-cluster-" ``` EOT type = string default = null validation { - condition = var.anyscale_cluster_node_role_name_prefix == null ? true : ( - can(regex("^(?:[a-z](?:[-a-z0-9]{4,20})?)$", var.anyscale_cluster_node_role_name_prefix)) + condition = var.anyscale_cluster_node_service_acct_name_prefix == null ? true : ( + can(regex("^(?:[a-z](?:[-a-z0-9]{4,20})?)$", var.anyscale_cluster_node_service_acct_name_prefix)) ) - error_message = "`anyscale_cluster_node_role_name_prefix` must start with a lowercase letter followed by up to 20 lowercase letters, numbers, or hyphens." + error_message = "`anyscale_cluster_node_service_acct_name_prefix` must start with a lowercase letter followed by up to 20 lowercase letters, numbers, or hyphens." } } -variable "anyscale_cluster_node_role_description" { +variable "anyscale_cluster_node_service_acct_description" { description = <<-EOT (Optional) The description of the IAM role that will be created for Anyscale access. ex: ``` - anyscale_cluster_node_role_description = "Anyscale Cluster Node" + anyscale_cluster_node_service_acct_description = "Anyscale Cluster Node" ``` EOT type = string