Fix support for credit types in billing module budgets (#3765)

* fix billing budgets

* tfdoc
This commit is contained in:
Ludovico Magnocavallo
2026-02-25 15:31:35 +01:00
committed by GitHub
parent 81b70695ac
commit 6494939348
8 changed files with 191 additions and 8 deletions

118
FACTORIES.md Normal file
View File

@@ -0,0 +1,118 @@
# Factories Overview
- [Modules](#modules)
- [FAST Stages](#fast-stages)
- [Maintenance Guide](#maintenance-guide)
## Modules
The following table provides a granular overview of modules that implement factory patterns. Each row represents a specific **factory configuration key** found within the `factories_config` variable.
* **Primary Module Resource**: The main resource the module is designed to manage (e.g., a Project for the `project` module, or an Access Policy for `vpc-sc`). "N/A" indicates the module is a "Pure Factory" designed primarily to create multiple top-level resources.
* **Factory Key**: The key in `factories_config` used to load external data.
* **Factory-Managed Resources**: The specific resources created by iterating over the loaded factory data.
* **Dependencies**: Module-level variables used by the factory resources (e.g., `project_id` injected into factory resources).
| Module | Primary Module Resource | Factory Key | Factory-Managed Resources | Dependencies (Module Variables) |
| :--- | :--- | :--- | :--- | :--- |
| **analytics-hub** | Analytics Hub Exchange | `listings` | Analytics Hub Listings | `project_id`, `region` |
| **billing-account** | Billing Account (Config) | `budgets_data_path` | Billing Budgets | `id` (Billing Account ID) |
| **data-catalog-policy-tag** | Data Catalog Taxonomy | `taxonomy` | Policy Tags | `project_id`, `location`, `name` (Taxonomy Name) |
| **data-catalog-tag** | N/A | `tags` | Data Catalog Tags | `tags` (Merged with factory data) |
| **data-catalog-tag-template** | N/A | `tag_templates` | Tag Templates | `project_id`, `region` |
| **dataplex-aspect-types** | N/A | `aspect_types` | Aspect Types | `project_id`, `location` |
| **dataplex-datascan** | DataScan | `data_quality_spec` | Data Quality Rules | `project_id`, `location` |
| **dns-response-policy** | DNS Response Policy | `rules` | Response Policy Rules | `project_id` |
| **folder** | Folder | `org_policies` | Organization Policies | `folder` (ID/Name) |
| **folder** | Folder | `pam_entitlements` | PAM Entitlements | `folder` (ID/Name) |
| **folder** | Folder | `scc_mute_configs` | SCC Mute Configs | `folder` (ID/Name) |
| **folder** | Folder | `scc_sha_custom_modules` | SCC SHA Custom Modules | `folder` (ID/Name) |
| **net-firewall-policy** | Firewall Policy | `egress_mirroring_rules_file_path` | Egress Packet Mirroring Rules | `name` (Policy Name) |
| **net-firewall-policy** | Firewall Policy | `egress_rules_file_path` | Egress Firewall Rules | `name` (Policy Name) |
| **net-firewall-policy** | Firewall Policy | `ingress_mirroring_rules_file_path` | Ingress Packet Mirroring Rules | `name` (Policy Name) |
| **net-firewall-policy** | Firewall Policy | `ingress_rules_file_path` | Ingress Firewall Rules | `name` (Policy Name) |
| **net-swp** | Secure Web Proxy | `policy_rules` | Proxy Policy Rules | `project_id`, `region` |
| **net-swp** | Secure Web Proxy | `url_lists` | Proxy URL Lists | `project_id`, `region` |
| **net-vpc** | VPC Network | `internal_ranges_folder` | Internal Ranges | `project_id`, `name` (Network Name) |
| **net-vpc** | VPC Network | `subnets_folder` | Subnets | `project_id`, `region` (Default), `name` (Network Name) |
| **net-vpc-factory** | N/A | `vpcs` | VPCs (and associated resources) | `context`, `data_defaults`, `data_overrides` |
| **net-vpc-firewall** | N/A | `rules_folder` | Firewall Rules | `project_id`, `network` |
| **organization** | Organization (Existing) | `custom_roles` | Custom IAM Roles | `organization_id` |
| **organization** | Organization (Existing) | `org_policies` | Organization Policies | `organization_id` |
| **organization** | Organization (Existing) | `org_policy_custom_constraints` | Org Policy Custom Constraints | `organization_id` |
| **organization** | Organization (Existing) | `pam_entitlements` | PAM Entitlements | `organization_id` |
| **organization** | Organization (Existing) | `scc_mute_configs` | SCC Mute Configs | `organization_id` |
| **organization** | Organization (Existing) | `scc_sha_custom_modules` | SCC SHA Custom Modules | `organization_id` |
| **organization** | Organization (Existing) | `tags` | ResourceManager Tags | `organization_id` |
| **project** | Project | `custom_roles` | Custom IAM Roles | `project.project_id` |
| **project** | Project | `observability` | Observability (Alerts, Metrics) | `project.project_id` |
| **project** | Project | `org_policies` | Organization Policies | `project.project_id` |
| **project** | Project | `pam_entitlements` | PAM Entitlements | `project.project_id` |
| **project** | Project | `quotas` | Service Quotas | `project.project_id` |
| **project** | Project | `scc_mute_configs` | SCC Mute Configs | `project.project_id` |
| **project** | Project | `scc_sha_custom_modules` | SCC SHA Custom Modules | `project.project_id` |
| **project** | Project | `tags` | ResourceManager Tags | `project.project_id` |
| **project-factory** | N/A | `budgets` | Budgets | `billing_account` (from defaults) |
| **project-factory** | N/A | `folders` | Folders | `context` (Folder IDs) |
| **project-factory** | N/A | `projects` | Projects | `context`, `data_defaults`, `data_overrides` |
| **secops-rules** | N/A | `reference_lists` | SecOps Reference Lists | `project_id`, `tenant_config` |
| **secops-rules** | N/A | `rules` | SecOps Detection Rules | `project_id`, `tenant_config` |
| **vpc-sc** | Access Policy | `access_levels` | Access Levels | `access_policy`, `context` (for Project Numbers) |
| **vpc-sc** | Access Policy | `egress_policies` | Egress Policies | `access_policy`, `context` |
| **vpc-sc** | Access Policy | `ingress_policies` | Ingress Policies | `access_policy`, `context` |
| **vpc-sc** | Access Policy | `perimeters` | Service Perimeters | `access_policy`, `context` |
| **workstation-cluster** | Workstation Cluster | `workstation_configs` | Workstation Configurations | `project_id`, `location`, `network_config` |
## FAST Stages
The following table details how FAST stages implement factory patterns.
* **Implementation Type**:
* `Module-Backed (Factory)`: The stage passes the `factories_config` path to a module which has internal logic to load and iterate over the data (e.g., `project-factory`).
* `Stage-Implemented (Module)`: The stage explicitly loads the YAML data (usually in `locals`) and iterates over a standard module (e.g., `dns` module).
* `Stage-Implemented (Resource)`: The stage explicitly loads the YAML data and iterates over raw Terraform resources.
* `Native (Complex)`: The stage implements complex factory logic combining multiple modules and resources.
| Stage | Factory (Key/Feature) | Implementation Type | Underlying Module/Resource |
| :--- | :--- | :--- | :--- |
| **0-org-setup** | `projects`, `folders`, `budgets` | Module-Backed (Factory) | `project-factory` |
| **1-vpcsc** | `access_levels`, `perimeters`, `policies` | Module-Backed (Factory) | `vpc-sc` |
| **2-networking** | `vpcs` | Module-Backed (Factory) | `net-vpc-factory` |
| **2-networking** | `projects` | Module-Backed (Factory) | `project-factory` |
| **2-networking** | `dns` (Zones) | Stage-Implemented (Module) | `dns` |
| **2-networking** | `dns_response_policies` | Stage-Implemented (Module) | `dns-response-policy` |
| **2-networking** | `firewall_policies` | Stage-Implemented (Module) | `net-firewall-policy` |
| **2-networking** | `vpns` | Stage-Implemented (Module) | `net-vpn-ha` |
| **2-networking** | `ncc_hubs` | Stage-Implemented (Resource) | `google_network_connectivity_hub` |
| **2-networking** | `ncc_groups` | Stage-Implemented (Resource) | `google_network_connectivity_group` |
| **2-networking** | `nvas` | Native (Complex) | `compute-vm`, `net-lb-int` |
| **2-project-factory** | `projects`, `folders`, `budgets` | Module-Backed (Factory) | `project-factory` |
| **2-project-factory** | `vpcs` | Module-Backed (Factory) | `net-vpc-factory` |
| **2-security** | `projects` | Module-Backed (Factory) | `project-factory` |
| **2-security** | `certificate_authorities` | Stage-Implemented (Module) | `certificate-authority-service` |
| **2-security** | `keyrings` (KMS) | Stage-Implemented (Module) | `kms` |
| **3-secops-dev** | `rules`, `reference_lists` | Module-Backed (Factory) | `secops-rules` |
## Maintenance Guide
This documentation is maintained to track factory patterns across the `modules` and `fast/stages` directories.
### To Update
#### 1. Modules Analysis
1. **Identify Configuration:** Search for `variable "factories_config"` in typically `modules/your-module/variables.tf`.
2. **Determine Keys:** Inspect the `factories_config` type (e.g., `object({ ... })`) to identify the keys like `rules`, `vpcs`, `projects`.
3. **Find Usage:** Search for `var.factories_config.KEY` in the module's `main.tf` or `factory.tf` to see how the data is used.
4. **Classify Resources:** Determine whether the factory logic creates module resources (e.g., `google_project`) or iterates a sub-module.
5. **List Dependencies:** Note any module-level variables (e.g., `project_id`, `name`) that are injected into the factory-created resources.
#### 2. FAST Stages Analysis
1. **Identify Configuration:** Search for `variable "factories_config"` in `fast/stages/your-stage/variables.tf`.
2. **Find Usage:** Search for `var.factories_config.KEY` in the stage's implementation (often in `factory*.tf`).
3. **Classify Implementation**:
* **Module-Backed (Factory)**: The `factories_config` path is passed directly to an underlying module (e.g., `project-factory`).
* **Stage-Implemented (Module)**: The stage explicitly loads the YAML/files and iterates over a standard module (e.g., `dns` module).
* **Stage-Implemented (Resource)**: The stage explicitly loads the YAML/files and iterates over raw Terraform resources (e.g., `google_network_connectivity_hub`).
* **Native (Complex)**: The stage implements complex logic combining multiple modules/resources (e.g., combining `compute-vm` and `net-lb-int` for NVAs).

View File

@@ -42,7 +42,17 @@
"include_specified": {
"type": "array",
"items": {
"type": "string"
"type": "string",
"enum": [
"COMMITTED_USAGE_DISCOUNT",
"COMMITTED_USAGE_DISCOUNT_DOLLAR_BASE",
"DISCOUNT",
"FREE_TIER",
"PROMOTION",
"RESELLER_MARGIN",
"SUBSCRIPTION_BENEFIT",
"SUSTAINED_USAGE_DISCOUNT"
]
}
}
}

View File

@@ -281,17 +281,17 @@ update_rules:
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [id](variables.tf#L148) | Billing account id. | <code>string</code> | ✓ | |
| [id](variables.tf#L165) | Billing account id. | <code>string</code> | ✓ | |
| [budget_notification_channels](variables.tf#L17) | Notification channels used by budget alerts. | <code title="map&#40;object&#40;&#123;&#10; project_id &#61; string&#10; type &#61; string&#10; description &#61; optional&#40;string&#41;&#10; display_name &#61; optional&#40;string&#41;&#10; enabled &#61; optional&#40;bool, true&#41;&#10; force_delete &#61; optional&#40;bool&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;&#41;&#10; sensitive_labels &#61; optional&#40;list&#40;object&#40;&#123;&#10; auth_token &#61; optional&#40;string&#41;&#10; password &#61; optional&#40;string&#41;&#10; service_key &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#41;&#10; user_labels &#61; optional&#40;map&#40;string&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [budgets](variables.tf#L47) | Billing budgets. Notification channels are either keys in corresponding variable, or external ids. | <code title="map&#40;object&#40;&#123;&#10; amount &#61; object&#40;&#123;&#10; currency_code &#61; optional&#40;string&#41;&#10; nanos &#61; optional&#40;number&#41;&#10; units &#61; optional&#40;number&#41;&#10; use_last_period &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#10; display_name &#61; optional&#40;string&#41;&#10; ownership_scope &#61; optional&#40;string&#41;&#10; filter &#61; optional&#40;object&#40;&#123;&#10; credit_types_treatment &#61; optional&#40;object&#40;&#123;&#10; exclude_all &#61; optional&#40;bool&#41;&#10; include_specified &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; label &#61; optional&#40;object&#40;&#123;&#10; key &#61; string&#10; value &#61; string&#10; &#125;&#41;&#41;&#10; period &#61; optional&#40;object&#40;&#123;&#10; calendar &#61; optional&#40;string&#41;&#10; custom &#61; optional&#40;object&#40;&#123;&#10; start_date &#61; object&#40;&#123;&#10; day &#61; number&#10; month &#61; number&#10; year &#61; number&#10; &#125;&#41;&#10; end_date &#61; optional&#40;object&#40;&#123;&#10; day &#61; number&#10; month &#61; number&#10; year &#61; number&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; projects &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; resource_ancestors &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; services &#61; optional&#40;list&#40;string&#41;&#41;&#10; subaccounts &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; threshold_rules &#61; optional&#40;list&#40;object&#40;&#123;&#10; percent &#61; number&#10; forecasted_spend &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; update_rules &#61; optional&#40;map&#40;object&#40;&#123;&#10; disable_default_iam_recipients &#61; optional&#40;bool&#41;&#10; monitoring_notification_channels &#61; optional&#40;list&#40;string&#41;&#41;&#10; pubsub_topic &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [context](variables.tf#L122) | Context-specific interpolations. | <code title="object&#40;&#123;&#10; custom_roles &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; folder_ids &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; folder_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_principals &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; notification_channels &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_ids &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; storage_buckets &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_numbers &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [factories_config](variables.tf#L139) | Path to folder containing budget alerts data files. | <code title="object&#40;&#123;&#10; budgets_data_path &#61; optional&#40;string, &#34;data&#47;billing-budgets&#34;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [context](variables.tf#L139) | Context-specific interpolations. | <code title="object&#40;&#123;&#10; custom_roles &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; folder_ids &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; folder_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_principals &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; notification_channels &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_ids &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; storage_buckets &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_numbers &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [factories_config](variables.tf#L156) | Path to folder containing budget alerts data files. | <code title="object&#40;&#123;&#10; budgets_data_path &#61; optional&#40;string, &#34;data&#47;billing-budgets&#34;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam](variables-iam.tf#L17) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | <code title="map&#40;object&#40;&#123;&#10; members &#61; list&#40;string&#41;&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_by_principals](variables-iam.tf#L54) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L153) | Logging sinks to create for the billing account. | <code title="map&#40;object&#40;&#123;&#10; destination &#61; string&#10; type &#61; string&#10; bq_partitioned_table &#61; optional&#40;bool, false&#41;&#10; description &#61; optional&#40;string&#41;&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;object&#40;&#123;&#10; filter &#61; string&#10; description &#61; optional&#40;string&#41;&#10; disabled &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; filter &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [projects](variables.tf#L186) | Projects associated with this billing account. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [logging_sinks](variables.tf#L170) | Logging sinks to create for the billing account. | <code title="map&#40;object&#40;&#123;&#10; destination &#61; string&#10; type &#61; string&#10; bq_partitioned_table &#61; optional&#40;bool, false&#41;&#10; description &#61; optional&#40;string&#41;&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;object&#40;&#123;&#10; filter &#61; string&#10; description &#61; optional&#40;string&#41;&#10; disabled &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; filter &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [projects](variables.tf#L203) | Projects associated with this billing account. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
## Outputs

View File

@@ -89,6 +89,7 @@ resource "google_billing_budget" "default" {
: "INCLUDE_ALL_CREDITS"
)
)
credit_types = try(each.value.filter.credit_types_treatment.include_specified, null)
labels = each.value.filter.label == null ? null : {
(each.value.filter.label.key) = each.value.filter.label.value
}

View File

@@ -102,4 +102,21 @@ check "factory_budgets" {
]))
error_message = "Notification rules need either a pubsub topic or monitoring channels defined."
}
assert {
condition = alltrue(flatten([
for k, v in local.factory_budgets : [
for c in try(v.filter.credit_types_treatment.include_specified, []) : contains([
"COMMITTED_USAGE_DISCOUNT",
"COMMITTED_USAGE_DISCOUNT_DOLLAR_BASE",
"DISCOUNT",
"FREE_TIER",
"PROMOTION",
"RESELLER_MARGIN",
"SUBSCRIPTION_BENEFIT",
"SUSTAINED_USAGE_DISCOUNT"
], c) if c != null
]
]))
error_message = "Budget filter credit types must be one of COMMITTED_USAGE_DISCOUNT, COMMITTED_USAGE_DISCOUNT_DOLLAR_BASE, DISCOUNT, FREE_TIER, PROMOTION, RESELLER_MARGIN, SUBSCRIPTION_BENEFIT, SUSTAINED_USAGE_DISCOUNT."
}
}

View File

@@ -42,7 +42,17 @@
"include_specified": {
"type": "array",
"items": {
"type": "string"
"type": "string",
"enum": [
"COMMITTED_USAGE_DISCOUNT",
"COMMITTED_USAGE_DISCOUNT_DOLLAR_BASE",
"DISCOUNT",
"FREE_TIER",
"PROMOTION",
"RESELLER_MARGIN",
"SUBSCRIPTION_BENEFIT",
"SUSTAINED_USAGE_DISCOUNT"
]
}
}
}

View File

@@ -117,6 +117,23 @@ variable "budgets" {
]))
error_message = "Budget notification rules need either a pubsub topic or monitoring channels defined."
}
validation {
condition = alltrue(flatten([
for k, v in var.budgets : [
for c in try(v.filter.credit_types_treatment.include_specified, []) : contains([
"COMMITTED_USAGE_DISCOUNT",
"COMMITTED_USAGE_DISCOUNT_DOLLAR_BASE",
"DISCOUNT",
"FREE_TIER",
"PROMOTION",
"RESELLER_MARGIN",
"SUBSCRIPTION_BENEFIT",
"SUSTAINED_USAGE_DISCOUNT"
], c) if c != null
]
]))
error_message = "Budget filter credit types must be one of COMMITTED_USAGE_DISCOUNT, COMMITTED_USAGE_DISCOUNT_DOLLAR_BASE, DISCOUNT, FREE_TIER, PROMOTION, RESELLER_MARGIN, SUBSCRIPTION_BENEFIT, SUSTAINED_USAGE_DISCOUNT."
}
}
variable "context" {

View File

@@ -42,7 +42,17 @@
"include_specified": {
"type": "array",
"items": {
"type": "string"
"type": "string",
"enum": [
"COMMITTED_USAGE_DISCOUNT",
"COMMITTED_USAGE_DISCOUNT_DOLLAR_BASE",
"DISCOUNT",
"FREE_TIER",
"PROMOTION",
"RESELLER_MARGIN",
"SUBSCRIPTION_BENEFIT",
"SUSTAINED_USAGE_DISCOUNT"
]
}
}
}