Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

☁️ Google Cloud Monitoring Group Terraform Module

Provisions a single Cloud Monitoring Group (google_monitoring_group) β€” a dynamic, filter-based collection of monitored resources used to scope dashboards, alerting, and uptime checks to a logical group (e.g. "all production web servers") rather than one resource at a time. Targets hashicorp/google ~> 7.0, Terraform >= 1.12.0.

Terraform Google Provider Module Version Module Type Resources Posture


🧩 Overview

  • 🎯 Closes the last remaining piece of the monitoring family's original Tier 2 gap list (CATALOG_COVERAGE.md: "all three remaining monitoring gaps from Tier 2's notes now closed except groups/google_monitoring_group").
  • πŸ†” NO CALLER-SUPPLIED NAME/GROUP_ID INPUT EXISTS. Unlike almost every other module in this catalog, this resource's identity is entirely server-assigned β€” the only identity-adjacent input is display_name, a mutable, non-authoritative, display-only label. There is deliberately no name/group_id variable in this module.
  • πŸ”— id and name are literally the same value for this resource β€” the live schema confirms id's format is {{name}}, not a distinct composed string the way id/self_link differ elsewhere in this catalog. Both are emitted; both will always match.
  • βœ… Corrected cross-module relationship: the real, documented consumer of this module's name output is terraform-google-monitoring-uptime-check's resource_group.group_id input β€” that module's own "KNOWN CATALOG GAP" comment names this exact producer. NOT terraform-google-monitoring-alert-policy, which has no resource_group argument anywhere in its schema (independently re-verified during authoring).
  • 🌳 Nested group hierarchy β€” parent_name accepts another instance of this same module's name output, mirroring the live schema's own "Monitoring Group Subgroup" Example Usage block.
  • ⚠️ Silent zero-match risk β€” a syntactically valid filter that matches zero monitored resources plans and applies successfully, producing an empty group with no error anywhere.
  • 🏷️ No labels and no self_link exist on this resource β€” both confirmed, schema-driven omissions predating GCP's common labels convention.

πŸ’‘ Why it matters: a Monitoring Group's value is entirely a function of its filter actually matching the intended resources β€” a typo'd label key, an over-narrowed AND chain, or a resource type that no longer exists in the project all produce a group that creates successfully with zero members, silently defeating whatever uptime check or dashboard scopes to it.


❀️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!


πŸ—ΊοΈ Where this fits

graph LR
 PS["terraform-google-project-services"]:::external
 THIS["terraform-google-monitoring-group"]:::thisModule
 UC["terraform-google-monitoring-uptime-check"]:::keystoneSibling
 AP["terraform-google-monitoring-alert-policy (no resource_group field exists)"]:::noEdge
 SUB["second terraform-google-monitoring-group instance (nested subgroup)"]:::thisModule

 PS -. "enables monitoring.googleapis.com (informal prerequisite)".-> THIS
 THIS -- "name output -> resource_group.group_id, CLOSES known catalog gap" --> UC
 THIS -- "name output -> parent_name, nested group hierarchy" --> SUB

 classDef thisModule fill:#4285F4,color:#ffffff,stroke:#174EA6,stroke-width:1px;
 classDef keystoneSibling fill:#174EA6,color:#ffffff,stroke:#174EA6,stroke-width:1px;
 classDef external fill:#E8EAED,color:#202124,stroke:#9AA0A6,stroke-width:1px,stroke-dasharray: 3 3;
 classDef noEdge fill:#E8EAED,color:#202124,stroke:#EA4335,stroke-width:1px,stroke-dasharray: 3 3;
Loading

(Validated via the Mermaid Chart MCP β€” valid: true, diagramType: flowchart.) The solid edge into terraform-google-monitoring-uptime-check is the real, documented consumer relationship: this module's name output is exactly the string that module's resource_group.group_id input expects β€” that module's own variables.tf carries a "KNOWN CATALOG GAP β€” resource_group.group_id... google_monitoring_group is NOT yet a module in the catalog" comment that this module's authoring closes. terraform-google-monitoring-alert-policy is drawn deliberately, with no edge, and captioned "does not consume a monitoring group (no resource_group field exists on this resource)" β€” the scaffolding brief that seeded this module's authoring incorrectly assumed that relationship; it was independently re-verified this session to be false (that resource's conditions blocks support condition_absent, condition_monitoring_query_language, condition_threshold, condition_matched_log, condition_prometheus_query_language, condition_sql β€” none reference a Monitoring Group by id; its only "group"-adjacent field, aggregations.group_by_fields, groups time series by label during aggregation, an unrelated concept). The self-referential edge into a second instance of this same module illustrates the parent_name nested-group-hierarchy composition pattern. terraform-google-project-services (dashed) must have already enabled monitoring.googleapis.com.


🧬 What this builds

A single keystone resource, no children β€” every argument is a flat scalar; the only optional nested block is the universal timeouts guard.

graph TD
 subgraph Inputs
 A["var.display_name"]
 B["var.filter"]
 C["var.parent_name"]
 D["var.is_cluster"]
 E["var.deletion_policy"]
 F["var.timeouts"]
 end

 R["google_monitoring_group.this"]:::thisModule

 A --> R
 B --> R
 C -.->|"optional, nested subgroup hierarchy"| R
 D --> R
 E --> R
 F -.->|"dynamic timeouts"| R

 R --> O1["output: id"]
 R --> O2["output: name"]

 O1 -. "id == name, always identical".- O2

 classDef thisModule fill:#4285F4,color:#ffffff,stroke:#174EA6,stroke-width:1px;
Loading

(Validated via the Mermaid Chart MCP β€” valid: true, diagramType: flowchart.) id and name are drawn as two outputs joined by a dotted "always identical" edge rather than as independent values, since the live schema confirms id's format is literally {{name}}.

Resource inventory:

Resource Cardinality Notes
google_monitoring_group.this Exactly 1 Keystone; no for_each children β€” standalone module

βœ… Provider / Versions

Requirement Value
Terraform >= 1.12.0
hashicorp/google provider ~> 7.0 (verified against v7.39.0 live schema, provider_doc_id 12683937)
Provider block None β€” the caller configures google (project, region/zone, auth)

Schema notes that bite (verified against the live v7.39.0 Argument/Attributes Reference via terraform-registry):

  • No name/group_id argument exists anywhere in the Argument Reference. The full set is display_name, filter, parent_name, is_cluster, project (skipped per house rule), deletion_policy β€” nothing that lets a caller choose the resource's own identity. The group_id portion of name is entirely server-assigned.
  • id and name are the same value. The Attributes Reference states id β€” "an identifier for the resource with format {{name}}" β€” verbatim; name is "A unique identifier for this group. The format is projects/{project_id_or_number}/groups/{group_id}." No other module in this catalog has this property.
  • No self_link attribute. Only id and name are exported β€” the Monitoring Groups API has no distinct URL-form resource identity.
  • No labels argument. Confirmed absent from the full Argument Reference β€” Cloud Monitoring Groups predate GCP's common labels convention and were never retrofitted (the same class of omission as terraform-google-compute-target-pool and terraform-google-compute-http-health-check, for a different underlying reason).
  • filter has no plan-time validity check beyond non-empty. A syntactically valid filter that matches zero monitored resources plans and applies successfully β€” the group is created with zero members, not an error.
  • is_cluster's documented interaction with filter is thin. The live docs state only "the system can perform additional analysis on groups that are clusters" β€” nothing further is confirmed, and this module does not invent an additional constraint.
  • No deletion_protection boolean. deletion_policy (DELETE/ABANDON/PREVENT, provider default DELETE) is the only Terraform-side destroy guard this resource exposes.
  • timeouts fully supported. create/update/delete each default to 20 minutes β€” the full universal-tail triad, no exceptions.

πŸ”‘ Required IAM Roles

  • roles/monitoring.editor β€” this module's seeded candidate: create, update, and delete Cloud Monitoring Groups (broader than group-scoped; it also covers other Monitoring resources). Unlike this module's four Monitoring siblings (terraform-google-monitoring-alert-policy, terraform-google-monitoring-dashboard, terraform-google-monitoring-uptime-check, terraform-google-monitoring-notification-channel, each of which found a dedicated, resource-specific predefined role), no dedicated groupsEditor-style role could be confirmed to exist through this pipeline's tooling (Google's predefined-role catalog is not part of the terraform-registry MCP or the provider schema). Reconfirm against Google's own IAM predefined-roles reference before granting broadly in a production project.

☁️ GCP Prerequisites

  • monitoring.googleapis.com enabled on the target project (via terraform-google-project-services, applied before this module).

πŸ“ Module Structure

terraform-google-monitoring-group/
β”œβ”€β”€ providers.tf # required_providers (hashicorp/google ~> 7.0) + required_version β€” no provider {} block
β”œβ”€β”€ variables.tf # display_name, filter, parent_name, is_cluster, deletion_policy, timeouts (no labels)
β”œβ”€β”€ main.tf # google_monitoring_group.this
β”œβ”€β”€ outputs.tf # id, name (confirmed identical values; no self_link)
β”œβ”€β”€ README.md # this file
β”œβ”€β”€ SCOPE.md # lightweight cross-module contract
└── examples/ # runnable example matching the Quick Start below

βš™οΈ Quick Start

module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "Production web servers"
  filter       = "resource.type=\"gce_instance\" AND metadata.user_labels.\"env\"=\"prod\""
}

The caller's root module configures the google provider (project, region/zone, and authentication via ADC, Workload Identity Federation, or a service account key supplied out-of-band) β€” this module accepts none of those as variables.


πŸ”Œ Cross-Module Contract

Consumes

Input Type Source module
parent_name (optional) string Another instance of this same module (name output) β€” nested group hierarchy composition
(all other inputs) No upstream Terraform dependency in the current catalog

Emits

Output Description Consumed by
id Terraform-internal resource id, format {{name}} β€” confirmed IDENTICAL to name Primary output β€” any consumer needing the Terraform reference
name Fully-qualified resource name, format projects/{project_id_or_number}/groups/{group_id} β€” confirmed IDENTICAL to id terraform-google-monitoring-uptime-check's resource_group.group_id β€” the real, already-documented consumer (corrects the scaffolding brief's mistaken reference to terraform-google-monitoring-alert-policy, which has no resource_group field of any kind); also a second instance of this same module's parent_name for nested hierarchies

πŸ“š Example Library

1 Β· Minimal filter-based group
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "All production web servers"
  filter       = "resource.type=\"gce_instance\" AND metadata.user_labels.\"env\"=\"prod\""
}

πŸ’‘ The simplest valid shape: display_name + filter. Every other argument has a provider or module default.

2 Β· Region-scoped filter
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "EU-region resources"
  filter       = "resource.metadata.region=\"europe-west2\""
}

ℹ️ Mirrors the live schema's own "Monitoring Group Basic" Example Usage block verbatim.

3 Β· Explicit single-resource membership via exact filter
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "Primary database host (pinned)"
  filter       = "resource.type=\"gce_instance\" AND resource.labels.instance_id=\"1234567890123456789\""
}

πŸ’‘ There is no separate "static membership" mode on this resource β€” every group is filter-based. A filter narrowed to an exact instance_id produces effectively-static, single-resource membership without a distinct API concept for it.

4 Β· AWS EC2 cross-cloud filter
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "AWS EC2 fleet under Cloud Monitoring"
  filter       = "resource.type=\"aws_ec2_instance\" AND metadata.user_labels.\"env\"=\"prod\""
}

ℹ️ Cloud Monitoring Groups can scope non-GCP monitored resource types (e.g. aws_ec2_instance) exactly like GCP-native ones, as long as the resource is already reporting into the same Monitoring Workspace.

5 Β· ℹ️ is_cluster = true
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "GKE node pool cluster"
  filter       = "resource.type=\"k8s_node\" AND resource.labels.cluster_name=\"prod-gke\""
  is_cluster   = true
}

ℹ️ The live docs state only "the system can perform additional analysis on groups that are clusters" β€” nothing further is documented about what that analysis is or how it interacts with filter. This module does not invent an additional constraint or validation connecting the two; treat is_cluster as an honest, thin passthrough of exactly what Google documents.

6 · 🌳 parent_name nested subgroup composition
module "parent_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "All production resources"
  filter       = "metadata.user_labels.\"env\"=\"prod\""
}

module "web_subgroup" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "Production web tier (subgroup)"
  filter       = "resource.type=\"gce_instance\" AND metadata.user_labels.\"tier\"=\"web\""

  # Nested group hierarchy: wires the parent's own `name` output into this module's
  # `parent_name` input, mirroring the live schema's own "Monitoring Group Subgroup" Example
  # Usage block verbatim.
  parent_name = module.parent_group.name
}

πŸ’‘ A subgroup's own filter still determines its independent membership β€” parent_name only establishes the hierarchy relationship for display/organization purposes, it does not further restrict or union the subgroup's own filter against the parent's.

7 Β· deletion_policy = PREVENT
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name    = "Production uptime-check target group β€” protected"
  filter          = "resource.type=\"gce_instance\" AND metadata.user_labels.\"env\"=\"prod\""
  deletion_policy = "PREVENT"
}

πŸ”’ Set this explicitly for any group a production terraform-google-monitoring-uptime-check resource_group depends on β€” destroying the group would not break the Terraform graph (that module references it by a plain string today) but would silently break the check's targeting at the API level.

8 Β· deletion_policy = ABANDON
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name    = "Deprecated staging group (being decommissioned out-of-band)"
  filter          = "metadata.user_labels.\"env\"=\"staging\""
  deletion_policy = "ABANDON"
}

ℹ️ ABANDON removes the resource from Terraform state without calling the delete API β€” use when ownership of the group is being handed to a manual/Console-managed process.

9 Β· Custom timeouts
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "Large fleet group β€” extended apply window"
  filter       = "resource.type=\"gce_instance\""

  timeouts = {
    create = "10m"
    update = "10m"
    delete = "10m"
  }
}

ℹ️ The provider default for all three operations is 20 minutes β€” shortening them here is a deliberate choice to fail fast in CI rather than an indication this resource is normally slow.

10 Β· ⚠️ Zero-match filter β€” silent misconfiguration
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "Production web servers (typo'd label)"
  # Typo: "evn" instead of "env" β€” this string is syntactically valid Cloud Monitoring filter
  # syntax, so validate/plan/apply all succeed. The resulting group has zero members.
  filter = "resource.type=\"gce_instance\" AND metadata.user_labels.\"evn\"=\"prod\""
}

⚠️ MANDATORY GOTCHA: a syntactically valid filter that matches zero monitored resources plans and applies successfully β€” the group is created with zero members, not an error. This mirrors the identical class of risk already documented on terraform-google-log-based-metric, terraform-google-scc-notification-config, and terraform-google-log-view for their own filter-shaped arguments. Verify actual group membership with gcloud monitoring groups list or the Console after every apply that changes a filter.

11 Β· Kubernetes-scoped filter (k8s_container)
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "GKE production namespace containers"
  filter       = "resource.type=\"k8s_container\" AND resource.labels.namespace_name=\"prod\""
}

πŸ’‘ Filters compose across the full MonitoredResourceDescriptor label set for the chosen resource.type β€” verify the exact label keys for a given type against the live MonitoredResourceDescriptor reference if a filter unexpectedly matches nothing.

12 Β· Cloud SQL-scoped filter
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "Production Cloud SQL instances"
  filter       = "resource.type=\"cloudsql_database\" AND metadata.user_labels.\"env\"=\"prod\""
}

ℹ️ A group's filter can target any monitored resource type Cloud Monitoring recognizes, not only compute resources.

13 Β· Multi-condition AND filter
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "Production us-central1 web tier"
  filter = join(" AND ", [
    "resource.type=\"gce_instance\"",
    "resource.metadata.zone=starts_with(\"us-central1\")",
    "metadata.user_labels.\"tier\"=\"web\"",
    "metadata.user_labels.\"env\"=\"prod\"",
  ])
}

πŸ’‘ Each additional AND clause narrows membership further β€” the more clauses, the higher the risk of the zero-match gotcha (example 10). Verify membership after any filter change involving 3+ clauses.

14 Β· display_name-only rename (identity is unaffected)
module "monitoring_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name = "Production web servers (renamed for clarity)"
  filter       = "resource.type=\"gce_instance\" AND metadata.user_labels.\"env\"=\"prod\""
}

πŸ’‘ Changing display_name alone is a plain in-place update β€” it does not affect this module's id/name outputs, since neither is derived from display_name. Any downstream composition referencing module.monitoring_group.name (e.g. an uptime check's resource_group.group_id) is unaffected by a display_name rename.

15 Β· πŸ—οΈ End-to-end composition
module "project_services" {
  source = "git::https://github.com/microsoftexpert/terraform-google-project-services.git?ref=v1.0.0"

  # Enables monitoring.googleapis.com β€” applied before every other module in this composition.
}

module "production_web_group" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-group.git?ref=v1.0.0"

  display_name    = "Production web fleet"
  filter          = "resource.type=\"gce_instance\" AND metadata.user_labels.\"tier\"=\"web\" AND metadata.user_labels.\"env\"=\"prod\""
  deletion_policy = "PREVENT" # a production uptime check depends on this group's targeting

  depends_on = [module.project_services]
}

module "production_web_uptime_check" {
  source = "git::https://github.com/microsoftexpert/terraform-google-monitoring-uptime-check.git?ref=v1.0.0"

  display_name = "Production web fleet reachability"
  timeout      = "10s"

  tcp_check = {
    port = 443
  }

  # Real, confirmed cross-module composition: this module's own `name` output is exactly the
  # string terraform-google-monitoring-uptime-check's `resource_group.group_id` expects β€” CLOSING that
  # sibling module's own documented "KNOWN CATALOG GAP β€” resource_group.group_id" comment.
  resource_group = {
    resource_type = "INSTANCE"
    group_id      = module.production_web_group.name
  }

  depends_on = [module.production_web_group]
}

ℹ️ This is the one fully-real, two-module composition this module's authoring closes: terraform-google-monitoring-group creates the group β†’ its name output wires directly into terraform-google-monitoring-uptime-check's resource_group.group_id β€” a structural Terraform reference, not a plain out-of-band string the way that module's own README previously had to document it (its "KNOWN CATALOG GAP" comment is now closed by this module's existence). terraform-google-monitoring-alert-policy is deliberately NOT part of this composition β€” it has no resource_group field to consume a group through.


πŸ“₯ Inputs

Variable Type Required Default Notes
display_name string Yes β€” Display-only; NOT this resource's identity, NOT force-new
filter string Yes β€” A zero-match filter is a silent, valid misconfiguration β€” see example 10
parent_name string No null Set to another instance's name output for a nested group hierarchy
is_cluster bool No false Documented by Google only in prose; no additional constraint invented
deletion_policy string No "DELETE" DELETE | ABANDON | PREVENT β€” see Design Principles for the judgment call
timeouts object({ create, update, delete = optional(string) }) No null All three supported, 20 min provider default each

No name/group_id variable exists β€” the group's identity is entirely server-assigned. No labels variable exists β€” confirmed absent from this resource's live schema.

Full variable schemas
variable "display_name" {
  type = string
  # must be non-empty, enforced via validation {}
}

variable "filter" {
  type = string
  # must be non-empty, enforced via validation {}
  # zero-match risk is NOT enforceable β€” documented only
}

variable "parent_name" {
  type    = string
  default = null
}

variable "is_cluster" {
  type    = bool
  default = false
}

variable "deletion_policy" {
  type    = string
  default = "DELETE"
  # DELETE | ABANDON | PREVENT, enforced via validation {}
}

variable "timeouts" {
  type = object({
    create = optional(string)
    update = optional(string)
    delete = optional(string)
  })
  default = null
}

🧾 Outputs

Output Description
id Terraform-internal resource id, format {{name}} β€” confirmed IDENTICAL to name
name Fully-qualified resource name, format projects/{project_id_or_number}/groups/{group_id} β€” confirmed IDENTICAL to id; the value terraform-google-monitoring-uptime-check's resource_group.group_id expects

No self_link row β€” confirmed absent from this resource's live schema. No output is secret-bearing.


🧠 Architecture Notes

  • No caller-supplied name/group_id input β€” its own clearly-labeled finding. The group's identity (both id and name) is generated entirely by the API at creation time. This is a genuinely unusual shape relative to almost every other module in this catalog, where a caller chooses (or at least influences) the resource's own name. Any composition that needs a stable reference to this group must consume this module's name output β€” it cannot be predicted or hardcoded before the first apply.
  • id and name are the same value for this resource. The live schema's Attributes Reference confirms id's format is literally {{name}}. Both outputs are provided for house-convention consistency; either can be used interchangeably.
  • No labels and no self_link exist on this resource β€” both confirmed, schema-driven omissions. Cloud Monitoring Groups predate GCP's common labels convention and were never retrofitted; the Monitoring Groups API has no distinct URL-form resource identity.
  • The corrected consumer relationship with terraform-google-monitoring-uptime-check. The scaffolding brief that originally seeded this module's authoring incorrectly assumed terraform-google-monitoring-alert-policy consumed a group via a resource_group field β€” independently re-verified this session to be false. The real, already-documented consumer is terraform-google-monitoring-uptime-check's resource_group.group_id, whose own variables.tf carries an explicit "KNOWN CATALOG GAP" comment naming this exact producer.
  • filter zero-match risk. A syntactically valid filter matching zero monitored resources plans and applies successfully β€” the group is created with zero members, not an error. Consistent with the established house precedent on terraform-google-log-based-metric, terraform-google-scc-notification-config, and terraform-google-log-view. Cannot be caught by validate/plan/apply in this plan-only library.
  • is_cluster/filter documentation-boundary honesty note. Google documents only "the system can perform additional analysis on groups that are clusters" for is_cluster β€” nothing further. This module deliberately does not invent an additional constraint or cross-field validation connecting is_cluster to filter beyond what is literally stated.
  • deletion_policy judgment call. Left at the provider's own "DELETE" default β€” this resource has no separate deletion_protection boolean, mirroring terraform-google-service-networking-connection/terraform-google-managed-instance-group's reasoning rather than terraform-google-compute-target-pool's "PREVENT"-by-default precedent (that resource sits directly on a live traffic-routing path; a monitoring group does not). See Design Principles for the full rationale.
  • IAM propagation lag. roles/monitoring.editor grants made immediately before this module applies can take up to ~60 seconds to propagate, per the house-wide note.

🧱 Design Principles

Concern Secure default Opt-out (explicit)
Group deletion guard (deletion_policy) "DELETE" β€” the provider's own default; this resource has no separate deletion_protection boolean, so deletion_policy alone is not defaulted to "PREVENT" (mirrors terraform-google-service-networking-connection/terraform-google-managed-instance-group's precedent, not terraform-google-compute-target-pool's) Caller sets "PREVENT" explicitly for any group a production terraform-google-monitoring-uptime-check's resource_group depends on, or "ABANDON" to drop from state without an API call
Cluster analysis (is_cluster) false β€” the provider's own default Caller sets true when GCP's additional cluster-level analysis applies, per the (thin) documentation available
filter correctness Enforced only as a non-empty string at plan time β€” GCP filter syntax and zero-match risk are entirely unenforceable from a plan-only library Caller verifies actual group membership via gcloud monitoring groups list or the Console after every apply that changes filter
IAM role scope (roles/monitoring.editor) Broadest confirmable predefined role β€” no narrower, group-specific role could be independently verified through this pipeline's tooling Caller substitutes a narrower custom IAM role if one is defined in the target project, after independently reconfirming against Google's own IAM predefined-roles reference

πŸš€ Runbook

cd terraform-google-monitoring-group
terraform init -backend=false
terraform validate
terraform fmt -check

Pin the module source to ?ref=v1.0.0 β€” never a branch. This library is plan-only from an authoring session; a human applies from CI with valid Workload Identity Federation or ADC credentials.


πŸ§ͺ Testing

terraform validate confirms internal type and reference consistency (the deletion_policy closed-enum validation {} block, display_name/filter non-empty checks, correct resource/output wiring). terraform fmt -check confirms canonical formatting. Neither β€” nor any plan run from this authoring session β€” can catch:

  • A filter that syntactically validates but matches zero monitored resources β€” the single most important limitation of this module's testing. Only a real apply against a live Monitoring Workspace, followed by a membership check (gcloud monitoring groups list-members or the Console), proves a group's filter actually matches the intended resources.
  • A parent_name string that does not correspond to any real, existing group (if supplied as a plain string rather than via module.<name>.name) β€” rejected only by the API at apply time.
  • Quota or org-policy rejections (e.g. a project-level Monitoring Group quota limit).

Only a real apply/plan against a live project β€” out of this library's plan-only scope β€” proves a group's membership is what the caller intended.


πŸ’¬ Example Output

$ terraform output

id = "projects/casey-prod-web/groups/0123456789012345"
name = "projects/casey-prod-web/groups/0123456789012345"

πŸ” Troubleshooting

Symptom Cause Fix
Group exists but appears to have no members filter is syntactically valid but matches zero monitored resources β€” a silent, valid outcome Verify the exact label keys/values and resource type against the live MonitoredResourceDescriptor; re-check with gcloud monitoring groups list-members
Tried to set a name/group_id variable and got an "argument not expected" error This module has no name/group_id input β€” the group's identity is entirely server-assigned Set display_name instead (display-only, not the identity); read this module's name output after apply for the real identifier
Expected this module's output to feed terraform-google-monitoring-alert-policy That module has no resource_group field of any kind β€” a mistaken assumption from an earlier scaffolding brief Wire this module's name output into terraform-google-monitoring-uptime-check's resource_group.group_id instead β€” the real, documented consumer
destroy fails with a deletion-prevented error deletion_policy = "PREVENT" is set Set deletion_policy = "DELETE" explicitly and re-apply before the subsequent destroy will succeed
A nested subgroup's parent_name reference fails at apply parent_name was supplied as a raw string that does not match any existing group's name, or the parent group has not yet been created Wire parent_name = module.<parent>.name (a structural Terraform reference) rather than a hand-typed string, and confirm the parent module applies first
is_cluster = true produced no visible behavior change Google documents only "additional analysis" with no further detail β€” there is nothing else to configure or troubleshoot here Nothing to fix; this module faithfully passes through exactly what the schema documents, no more
Renaming display_name unexpectedly broke a downstream reference A caller wired a downstream input from display_name instead of this module's name/id output display_name is mutable and non-authoritative β€” always reference name/id for cross-module composition, never display_name

πŸ”— Related Docs

  • google_monitoring_group provider resource reference
  • terraform-google-project-services (must enable monitoring.googleapis.com before this module applies)
  • terraform-google-monitoring-uptime-check (the real, confirmed consumer of this module's name output via resource_group.group_id β€” see πŸ”Œ Cross-Module Contract and example 15; this module's authoring closes that module's own documented "KNOWN CATALOG GAP")
  • terraform-google-monitoring-alert-policy (does not consume a monitoring group β€” no resource_group field exists on this resource; drawn in the family DAG above with no edge, for context only)
  • terraform-google-log-based-metric, terraform-google-scc-notification-config, terraform-google-log-view (the sibling modules whose filter-shaped arguments document the identical zero-match silent-misconfiguration risk this module's own filter shares)
  • terraform-google-service-networking-connection, terraform-google-managed-instance-group (the deletion_policy = "DELETE"-by-default precedent this module follows)
  • terraform-google-compute-target-pool, terraform-google-server-tls-policy, terraform-google-client-tls-policy (the deletion_policy = "PREVENT"-by-default precedent this module deliberately does NOT follow, and why)
  • This module's SCOPE.md

Releases

Packages

Contributors

Languages