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. Targetshashicorp/google ~> 7.0, Terraform>= 1.12.0.
- π― Closes the last remaining piece of the
monitoringfamily'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 noname/group_idvariable in this module. - π
idandnameare literally the same value for this resource β the live schema confirmsid's format is{{name}}, not a distinct composed string the wayid/self_linkdiffer elsewhere in this catalog. Both are emitted; both will always match. - β
Corrected cross-module relationship: the real, documented consumer of this module's
nameoutput isterraform-google-monitoring-uptime-check'sresource_group.group_idinput β that module's own "KNOWN CATALOG GAP" comment names this exact producer. NOTterraform-google-monitoring-alert-policy, which has noresource_groupargument anywhere in its schema (independently re-verified during authoring). - π³ Nested group hierarchy β
parent_nameaccepts another instance of this same module'snameoutput, mirroring the live schema's own "Monitoring Group Subgroup" Example Usage block. β οΈ Silent zero-match risk β a syntactically validfilterthat matches zero monitored resources plans and applies successfully, producing an empty group with no error anywhere.- π·οΈ No
labelsand noself_linkexist 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
filteractually 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.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
- β Star this repository to help others discover this Terraform module.
- π€ Connect with me on LinkedIn: linkedin.com/in/microsoftexpert
- β Buy me a coffee: buymeacoffee.com/microsoftexpert
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!
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;
(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.
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;
(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 |
| 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_idargument exists anywhere in the Argument Reference. The full set isdisplay_name,filter,parent_name,is_cluster,project(skipped per house rule),deletion_policyβ nothing that lets a caller choose the resource's own identity. Thegroup_idportion ofnameis entirely server-assigned. idandnameare the same value. The Attributes Reference statesidβ "an identifier for the resource with format{{name}}" β verbatim;nameis "A unique identifier for this group. The format isprojects/{project_id_or_number}/groups/{group_id}." No other module in this catalog has this property.- No
self_linkattribute. Onlyidandnameare exported β the Monitoring Groups API has no distinct URL-form resource identity. - No
labelsargument. 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 asterraform-google-compute-target-poolandterraform-google-compute-http-health-check, for a different underlying reason). filterhas 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 withfilteris 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_protectionboolean.deletion_policy(DELETE/ABANDON/PREVENT, provider defaultDELETE) is the only Terraform-side destroy guard this resource exposes. timeoutsfully supported.create/update/deleteeach default to 20 minutes β the full universal-tail triad, no exceptions.
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 dedicatedgroupsEditor-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.
monitoring.googleapis.comenabled on the target project (viaterraform-google-project-services, applied before this module).
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
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.
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 |
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_idproduces 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; treatis_clusteras 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
filterstill determines its independent membership βparent_nameonly 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-checkresource_groupdepends 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"
}βΉοΈ
ABANDONremoves 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 validfilterthat 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 onterraform-google-log-based-metric,terraform-google-scc-notification-config, andterraform-google-log-viewfor their own filter-shaped arguments. Verify actual group membership withgcloud monitoring groups listor the Console after every apply that changes afilter.
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
MonitoredResourceDescriptorlabel set for the chosenresource.typeβ verify the exact label keys for a given type against the liveMonitoredResourceDescriptorreference 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
filtercan 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
ANDclause 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_namealone is a plain in-place update β it does not affect this module'sid/nameoutputs, since neither is derived fromdisplay_name. Any downstream composition referencingmodule.monitoring_group.name(e.g. an uptime check'sresource_group.group_id) is unaffected by adisplay_namerename.
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-groupcreates the group β itsnameoutput wires directly intoterraform-google-monitoring-uptime-check'sresource_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-policyis deliberately NOT part of this composition β it has noresource_groupfield to consume a group through.
| 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
}| 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.
- No caller-supplied name/group_id input β its own clearly-labeled finding. The group's
identity (both
idandname) 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'snameoutput β it cannot be predicted or hardcoded before the firstapply. idandnameare the same value for this resource. The live schema's Attributes Reference confirmsid's format is literally{{name}}. Both outputs are provided for house-convention consistency; either can be used interchangeably.- No
labelsand noself_linkexist 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 assumedterraform-google-monitoring-alert-policyconsumed a group via aresource_groupfield β independently re-verified this session to be false. The real, already-documented consumer isterraform-google-monitoring-uptime-check'sresource_group.group_id, whose own variables.tf carries an explicit "KNOWN CATALOG GAP" comment naming this exact producer. filterzero-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 onterraform-google-log-based-metric,terraform-google-scc-notification-config, andterraform-google-log-view. Cannot be caught byvalidate/plan/applyin this plan-only library.is_cluster/filterdocumentation-boundary honesty note. Google documents only "the system can perform additional analysis on groups that are clusters" foris_clusterβ nothing further. This module deliberately does not invent an additional constraint or cross-field validation connectingis_clustertofilterbeyond what is literally stated.deletion_policyjudgment call. Left at the provider's own"DELETE"default β this resource has no separatedeletion_protectionboolean, mirroringterraform-google-service-networking-connection/terraform-google-managed-instance-group's reasoning rather thanterraform-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.editorgrants made immediately before this module applies can take up to ~60 seconds to propagate, per the house-wide note.
| 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 |
cd terraform-google-monitoring-group
terraform init -backend=false
terraform validate
terraform fmt -checkPin 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.
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
filterthat syntactically validates but matches zero monitored resources β the single most important limitation of this module's testing. Only a realapplyagainst a live Monitoring Workspace, followed by a membership check (gcloud monitoring groups list-membersor the Console), proves a group'sfilteractually matches the intended resources. - A
parent_namestring that does not correspond to any real, existing group (if supplied as a plain string rather than viamodule.<name>.name) β rejected only by the API atapplytime. - 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.
$ terraform output
id = "projects/casey-prod-web/groups/0123456789012345"
name = "projects/casey-prod-web/groups/0123456789012345"
| 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 |
google_monitoring_groupprovider resource referenceterraform-google-project-services(must enablemonitoring.googleapis.combefore this module applies)terraform-google-monitoring-uptime-check(the real, confirmed consumer of this module'snameoutput viaresource_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 β noresource_groupfield 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 ownfiltershares)terraform-google-service-networking-connection,terraform-google-managed-instance-group(thedeletion_policy = "DELETE"-by-default precedent this module follows)terraform-google-compute-target-pool,terraform-google-server-tls-policy,terraform-google-client-tls-policy(thedeletion_policy = "PREVENT"-by-default precedent this module deliberately does NOT follow, and why)- This module's
SCOPE.md