Skip to content

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

❄️ Snowflake Resource Monitor Terraform Module

Manages a single Snowflake resource monitor (snowflake_resource_monitor) — credit-quota, reset-schedule, and notify/suspend threshold policy — against the snowflakedb/snowflake provider, pinned ~> 2.17.

Terraform Snowflake Provider Module Version Module Type Resources Posture


🧩 Overview

  • ❄️ Manages a single snowflake_resource_monitor object — one keystone resource, no children, no cross-object grants.
  • 🔑 Encodes both of Snowflake's provider-enforced create-time pairing/rejection rules as terraform validate-time validation {} blocks, so a malformed call fails before any API call rather than as an opaque error mid-apply.
  • 🧾 Emits fully_qualified_name as the safe cross-reference for attaching the monitor to a warehouse via the sibling terraform-snowflake-warehouse module.
  • ⚠️ Documents — but cannot validate offline — the lifecycle-level gotcha that unsetting every trigger on an existing monitor forces a destroy/recreate rather than an in-place update.

💡 Why it matters: an unbounded warehouse is an unbounded bill. A resource monitor is the only Snowflake-native guardrail that caps and alerts on credit spend per warehouse (or, outside this module's scope, per account) — modeling its create-time constraints as type-level validation means a malformed monitor definition never reaches a live Snowflake account in the first place.


❤️ 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

flowchart LR
 user["terraform-snowflake-user"]
 thismod["terraform-snowflake-resource-monitor"]
 keystone[["snowflake_resource_monitor.this"]]
 warehouse["terraform-snowflake-warehouse"]

 user -->|"fully_qualified_name feeds notify_users"| thismod
 thismod -->|"creates"| keystone
 keystone -->|"fully_qualified_name feeds resource_monitor_fully_qualified_name"| warehouse

 style thismod fill:#29B5E8,color:#ffffff
 style keystone fill:#11567F,color:#ffffff
 style user fill:#ECEFF1,color:#000000
 style warehouse fill:#ECEFF1,color:#000000
Loading

This module has a real sibling family, so the family DAG is not dropped: terraform-snowflake-user feeds this module's notify_users input by reference (its fully_qualified_name output), and this module in turn feeds terraform-snowflake-warehouse's resource_monitor_fully_qualified_name input with its own fully_qualified_name output. Neither sibling module is created or modified by this one — both relationships are consumed by reference, per this library's composite/aggregation split (this library's "Composite modules" convention).


🧬 What this builds

flowchart TB
 subgraph inputs["Inputs"]
 name["name (required)"]
 credit_quota["credit_quota"]
 frequency["frequency + start_timestamp (paired)"]
 end_timestamp["end_timestamp"]
 notify_triggers["notify_triggers"]
 suspend_trigger["suspend_trigger"]
 suspend_immediate_trigger["suspend_immediate_trigger"]
 notify_users["notify_users"]
 end

 keystone[["snowflake_resource_monitor.this"]]

 subgraph outputs["Outputs"]
 fqn["fully_qualified_name"]
 outname["name"]
 id["id"]
 end

 inputs -->|"renders"| keystone
 keystone -->|"emits"| outputs

 style keystone fill:#11567F,color:#ffffff
 style inputs fill:#ECEFF1,color:#000000
 style outputs fill:#ECEFF1,color:#000000
Loading

Resource inventory:

Resource Count Notes
snowflake_resource_monitor.this 1 (keystone) No for_each children — standalone module

✅ Provider / Versions

Requirement Value
Terraform >= 1.12.0
snowflakedb/snowflake provider ~> 2.17
Provider block Not present — the caller's root module configures the provider (account identifier, authentication) and passes any role alias in

Schema notes that bite:

  • No settable comment argument. Unlike most modules in this library, snowflake_resource_monitor does not expose an input comment argument — only a read-only comment field nested inside the computed show_output block (Snowflake's SHOW RESOURCE MONITORS output). This module carries no comment variable — a deliberate, schema-verified deviation from this library's usual "comment is the universal tail" rule, not an oversight.
  • frequency/start_timestamp pairing is validate-time enforced. Set one, and you must set the other — this module rejects the mismatched case before terraform validate ever calls the Snowflake API.
  • Triggers-only creation is validate-time rejected. Setting only notify_triggers, suspend_trigger, and/or suspend_immediate_trigger with nothing else fails at terraform validate — Snowflake requires at least one of credit_quota, frequency, start_timestamp, end_timestamp, or notify_users alongside any trigger.
  • ⚠️ Unsetting all triggers forces a recreate — live-apply-time only, not offline-validatable. Once at least one trigger has ever been applied, a later configuration that removes every trigger cannot be satisfied as an in-place update; the provider recreates the resource monitor instead. terraform validate only ever sees one configuration in isolation, so this behavior is invisible until a real plan/apply against existing state.
  • frequency/start_timestamp have no unset path. Removing either field from a caller's HCL does not clear the previously applied value on the Snowflake side — the provider preserves it, by its own documented design, rather than resetting to a default. Expect no corrective diff on the next plan after simply deleting the argument.
  • A nested timeouts block exists on the schema but is not modeled here. The live schema exposes an optional timeouts { create, read, update, delete } block — Terraform's standard per-resource operation-timeout customization meta-argument, not a business-data field. This library's stance is that no Snowflake module exposes a timeouts variable, since the provider does not otherwise expose a configurable operation- timeout schema; this module follows that stance and does not surface it.
  • Case sensitivity. name is passed through as-is; Snowflake case-folds an unquoted identifier to upper case. This is a common source of "already exists" false negatives on import if the caller assumes the name is stored verbatim.

🔑 Required Snowflake Privileges

  • CREATE RESOURCE MONITOR — the global, account-level privilege required to create the keystone snowflake_resource_monitor.this object. In practice this typically requires the ACCOUNTADMIN role: CREATE RESOURCE MONITOR is one of the few privileges Snowflake has historically reserved to ACCOUNTADMIN, and is only grantable to a custom role on accounts/ editions where Snowflake has enabled delegating it. Confirm the executing role's actual grant (via the caller's aliased provider configuration) before assuming a lesser-privileged role will succeed — a role without this privilege fails at apply time with a Snowflake authorization error, not at terraform validate time.
  • Subsequent updates (ALTER RESOURCE MONITOR) and drops require ownership of the object or an equivalent privileged role — normally satisfied automatically by whichever role's session created it.

Snowflake Prerequisites

  • No specific Snowflake account edition requirement — resource monitors are available on every edition.
  • No preview_features_enabled flag required — snowflake_resource_monitor is documented by the provider as Stable (GA), not preview-gated.
  • The executing role must already hold CREATE RESOURCE MONITOR (see above) — provisioned by the caller's root module/provider alias; this module cannot grant itself the privilege it needs to run.
  • If notify_users is populated, every referenced Snowflake user identifier must already exist in the account (typically created via terraform-snowflake-user) before this module applies — this module does not create, look up, or validate the referenced users' existence.
  • If the monitor is meant to govern a warehouse's compute spend, terraform-snowflake-warehouse must exist (or be applied in the same run) — attachment is that module's concern.

📁 Module Structure

terraform-snowflake-resource-monitor/
├── providers.tf # required_providers + required_version — no provider {} block
├── variables.tf # name, credit_quota, frequency/start/end_timestamp, triggers, notify_users
├── main.tf # the keystone snowflake_resource_monitor.this — no children
├── outputs.tf # fully_qualified_name, name, id
├── README.md # this file
├── SCOPE.md # lightweight standalone spec — privileges, prerequisites, gotchas
└── examples/ # runnable example call sites

⚙️ Quick Start

module "etl_budget_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name            = "RM_ETL_BUDGET"
  credit_quota    = 500
  suspend_trigger = 100
}

The caller's root module configures the snowflake provider (account identifier, authentication, and any role alias — see this library's Authentication model convention). This module never declares account_name, organization_name, user, role, or any credential-shaped variable.


🔌 Cross-Module Contract

Consumes:

Input Type Source module
notify_users (optional) set(string) terraform-snowflake-user's fully_qualified_name output, one entry per notified user — not a hard Terraform module dependency, just an accepted reference convention

Emits:

Output Description Consumed by
fully_qualified_name Fully qualified identifier of the resource monitor terraform-snowflake-warehouse's resource_monitor_fully_qualified_name input
name Bare name of the resource monitor, as passed to var.name Documentation/display only
id Terraform resource ID (the quoted identifier string used for terraform import) Documentation/display only

📚 Example Library

1 · Minimal monitor (name only)

ℹ️ Matches the provider's own "minimal" example usage: without credit_quota or any trigger, the monitor is created but performs no work until attached and configured further.

module "placeholder_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name = "RM_PLACEHOLDER"
}
2 · Minimal monitor with only credit_quota set

💡 credit_quota alone (no triggers) satisfies the "not triggers-only" rule trivially, since no trigger field is set at all — Snowflake tracks usage against the quota but takes no suspend action without a trigger.

module "reporting_quota_only" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name         = "RM_REPORTING_QUOTA_ONLY"
  credit_quota = 250
}
3 · Monthly monitor with start_timestamp = "IMMEDIATELY"

💡 frequency and start_timestamp are set together, satisfying the pairing validation in variables.tf. "IMMEDIATELY" is the provider-documented literal that resolves to the current date at apply time.

module "monthly_reset_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name            = "RM_MONTHLY_RESET"
  credit_quota    = 1000
  frequency       = "MONTHLY"
  start_timestamp = "IMMEDIATELY"
  suspend_trigger = 100
}
4 · Daily monitor with explicit start and end timestamps
module "seasonal_daily_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name            = "RM_SEASONAL_DAILY"
  credit_quota    = 300
  frequency       = "DAILY"
  start_timestamp = "2026-08-01 00:00"
  end_timestamp   = "2026-10-31 23:59"
  suspend_trigger = 90
}
5 · All three trigger types plus notify_users

🔑 notify_users consumes terraform-snowflake-user's fully_qualified_name output by reference — this module does not create or validate the referenced users.

module "finance_analyst" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-user.git?ref=v1.0.0"

  name = "SVC_FINANCE_ANALYST"
}

module "data_platform_lead" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-user.git?ref=v1.0.0"

  name = "SVC_DATA_PLATFORM_LEAD"
}

module "full_policy_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name         = "RM_FULL_POLICY"
  credit_quota = 1000

  frequency       = "DAILY"
  start_timestamp = "2030-12-07 00:00"
  end_timestamp   = "2035-12-07 00:00"

  notify_triggers           = [40, 50]
  suspend_trigger           = 50
  suspend_immediate_trigger = 90

  notify_users = [
    module.finance_analyst.fully_qualified_name,
    module.data_platform_lead.fully_qualified_name,
  ]
}
6 · Notify-only thresholds (no suspend action)

💡 notify_triggers alone plus credit_quota sends notifications at 60% and 80% but never suspends the assigned warehouse(s) — useful for a monitor that only wants visibility, not enforcement.

module "visibility_only_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name            = "RM_VISIBILITY_ONLY"
  credit_quota    = 400
  notify_triggers = [60, 80]
  notify_users    = [module.finance_analyst.fully_qualified_name]
}
7 · Suspend-only monitor (graceful suspend, no immediate cancel)
module "graceful_suspend_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name            = "RM_GRACEFUL_SUSPEND"
  credit_quota    = 600
  suspend_trigger = 100
}
8 · Suspend-immediate-only monitor

⚠️ suspend_immediate_trigger cancels running queries outright with no grace period — reserve this for cost-critical, non-production warehouses where an interrupted query is preferable to overspend.

module "hard_stop_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name                      = "RM_HARD_STOP"
  credit_quota              = 150
  suspend_immediate_trigger = 100
}
9 · YEARLY frequency with a real start_timestamp
module "annual_budget_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name            = "RM_ANNUAL_BUDGET"
  credit_quota    = 12000
  frequency       = "YEARLY"
  start_timestamp = "2026-01-01 00:00"
  suspend_trigger = 95
}
10 · NEVER frequency (credit usage never resets)

ℹ️ frequency = "NEVER" still requires a paired start_timestamp per the validation block — NEVER only changes whether usage resets, not whether the pairing rule applies.

module "lifetime_quota_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name            = "RM_LIFETIME_QUOTA"
  credit_quota    = 50000
  frequency       = "NEVER"
  start_timestamp = "IMMEDIATELY"
  suspend_trigger = 100
}
11 · WEEKLY frequency with a threshold over 100%

💡 The provider explicitly supports trigger values over 100 — useful for an early-warning notification well past nominal quota without suspending anything.

module "overage_alert_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name            = "RM_OVERAGE_ALERT"
  credit_quota    = 200
  frequency       = "WEEKLY"
  start_timestamp = "IMMEDIATELY"
  notify_triggers = [110, 150]
  notify_users    = [module.data_platform_lead.fully_qualified_name]
}
12 · Multiple monitors at scale via a caller-level for_each

ℹ️ This module itself has no children (standalone), but a caller can still apply for_each at the module block to stamp out one monitor per entry in a map — each instance is independently keyed, so adding or removing a team never disturbs its siblings.

variable "team_credit_quotas" {
  type = map(number)
  default = {
    analytics = 300
    ingestion = 500
    reporting = 200
  }
}

module "team_monitors" {
  source   = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"
  for_each = var.team_credit_quotas

  name            = "RM_TEAM_${upper(each.key)}"
  credit_quota    = each.value
  suspend_trigger = 100
}
13 · One monitor shared across two warehouses
module "shared_budget_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name            = "RM_SHARED_BUDGET"
  credit_quota    = 2000
  suspend_trigger = 95
}

module "warehouse_etl" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-warehouse.git?ref=v1.0.0"

  name                                  = "WH_ETL"
  resource_monitor_fully_qualified_name = module.shared_budget_monitor.fully_qualified_name
}

module "warehouse_reporting" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-warehouse.git?ref=v1.0.0"

  name                                  = "WH_REPORTING"
  resource_monitor_fully_qualified_name = module.shared_budget_monitor.fully_qualified_name
}
14 · ⚠️ Rejected shape — triggers set with nothing else

⚠️ This example is deliberately not runnable HCL. It illustrates the shape terraform validate rejects — a validation failure is not something that can be shown as a working example, so this block is prose plus the invalid call, commented out.

Snowflake rejects a resource monitor created with only trigger fields (notify_triggers/suspend_trigger/suspend_immediate_trigger) and nothing else:

# module "invalid_triggers_only" {
# source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"
#
# name = "RM_INVALID_TRIGGERS_ONLY"
# suspend_trigger = 100 # no credit_quota, frequency, start_timestamp, end_timestamp, or
# # notify_users set alongside it
# }

terraform validate fails this call site with:

Error: Invalid value for variable

 on variables.tf line 158, in variable "suspend_trigger":
 158: validation {

A resource monitor cannot be created with only trigger fields set (notify_triggers,
suspend_trigger, suspend_immediate_trigger). Set at least one of credit_quota, frequency,
start_timestamp, end_timestamp, or notify_users as well.

Adding any one of credit_quota, frequency (paired with start_timestamp), end_timestamp, or notify_users resolves the error — see Example 7 for the minimal fix (adding credit_quota).

15 · 🏗️ End-to-end composition — user, monitor, and warehouse

Wires terraform-snowflake-user's fully_qualified_name output into this module's notify_users input, and this module's fully_qualified_name output into terraform-snowflake-warehouse's resource_monitor_fully_qualified_name input — the full cross-module contract shown in §4.

module "casey_finance_notify_user" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-user.git?ref=v1.0.0"

  name = "SVC_casey_FINANCE_NOTIFY"
}

module "wh_etl_monitor" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-resource-monitor.git?ref=v1.0.0"

  name         = "RM_WH_ETL"
  credit_quota = 1500

  frequency       = "MONTHLY"
  start_timestamp = "IMMEDIATELY"

  notify_triggers           = [50, 75]
  suspend_trigger           = 90
  suspend_immediate_trigger = 100

  notify_users = [module.casey_finance_notify_user.fully_qualified_name]
}

module "wh_etl" {
  source = "git::https://github.com/microsoftexpert/terraform-snowflake-warehouse.git?ref=v1.0.0"

  name                                  = "WH_ETL"
  warehouse_size                        = "MEDIUM"
  resource_monitor_fully_qualified_name = module.wh_etl_monitor.fully_qualified_name
}

💡 The monitor and the warehouse are independently reusable: module.wh_etl_monitor could just as easily be attached to a second warehouse (see Example 13), and module.wh_etl could just as easily reference a different monitor — attachment is deliberately not owned by either module.


📥 Inputs

Variable Type Default Required
name string — Yes
credit_quota number null No
frequency string null No
start_timestamp string null No
end_timestamp string null No
notify_triggers set(number) [] No
suspend_trigger number null No
suspend_immediate_trigger number null No
notify_users set(string) [] No
Full variable schemas
variable "name" {
  type = string
  # Required. Unique within the account. Avoid `|`, `.`, `"` in the value. Passed through as-is —
  # expect Snowflake to case-fold an unquoted name to upper case.
}

variable "credit_quota" {
  type    = number
  default = null
  # Credits allocated per frequency interval. A monitor with no credit_quota and no triggers
  # performs no work.
}

variable "frequency" {
  type    = string
  default = null
  # One of: MONTHLY, DAILY, WEEKLY, YEARLY, NEVER.
  # validation: must be one of the five values above, or null.
  # validation: (frequency == null) == (start_timestamp == null) — must be set together.
}

variable "start_timestamp" {
  type    = string
  default = null
  # A real timestamp string, or the literal "IMMEDIATELY". Paired with frequency.
}

variable "end_timestamp" {
  type    = string
  default = null
  # A real timestamp string marking when the monitor suspends the assigned warehouse(s).
}

variable "notify_triggers" {
  type    = set(number)
  default = []
  # Percentage-of-credit_quota thresholds that send a notification only. Values over 100 allowed.
}

variable "suspend_trigger" {
  type    = number
  default = null
  # Percentage-of-credit_quota threshold that suspends the warehouse(s) gracefully.
  # validation: rejects a call where only notify_triggers/suspend_trigger/
  # suspend_immediate_trigger are set with none of credit_quota/frequency/start_timestamp/
  # end_timestamp/notify_users also set.
}

variable "suspend_immediate_trigger" {
  type    = number
  default = null
  # Percentage-of-credit_quota threshold that suspends the warehouse(s) immediately, canceling
  # running queries.
}

variable "notify_users" {
  type    = set(string)
  default = []
  # Set of Snowflake user identifiers (pass terraform-snowflake-user's fully_qualified_name output).
  # Not validated for existence — an invalid reference fails at apply time.
}

🧾 Outputs

Output Description Sensitive / Conditional
fully_qualified_name Fully qualified identifier of the resource monitor — the safe cross-reference for sibling modules Always present
name Bare name of the resource monitor, as passed to var.name Always present
id Terraform resource ID (import identifier) Always present

🧠 Architecture Notes

  • frequency/start_timestamp pairing is enforced in variables.tf. The validation block on frequency checks (var.frequency == null) == (var.start_timestamp == null) — both null, or both set. This is a cross-variable validation {} block (Terraform 1.9+, well within this module's >= 1.12.0 floor), so it fires regardless of which of the two variables a caller actually edited.
  • The "cannot create with only triggers set" rule is enforced in variables.tf. The validation block on suspend_trigger checks that if any of notify_triggers, suspend_trigger, or suspend_immediate_trigger is set, at least one of credit_quota, frequency, start_timestamp, end_timestamp, or notify_users is also set. It is intentionally a single validation block (not duplicated across all three trigger variables) to avoid redundant, identically-worded terraform validate errors for one underlying cause.
  • ⚠️ Unsetting all triggers forces a recreate — a live-apply-time concern this module cannot validate offline. Once a monitor has ever had a trigger applied, Snowflake has no supported path to fully unset every trigger again; the provider's only way to reconcile a configuration that removes them all is to destroy and recreate the resource monitor. terraform validate evaluates one configuration in isolation and has no visibility into prior state, so this behavior only ever shows up in a real plan/apply against an existing monitor — flag it to reviewers before applying a change that removes every trigger from a monitor already in use.
  • Account-level assignment is out of scope. Assigning a resource monitor at the ACCOUNT level (rather than per-warehouse) requires the ACCOUNTADMIN role and is not supported by the snowflake_resource_monitor resource itself — the provider's own docs point callers at snowflake_execute instead. Neither this module nor terraform-snowflake-warehouse supports account-level assignment; only warehouse-level assignment via the sibling warehouse module's resource_monitor_fully_qualified_name input is supported in this library.
  • No comment variable. See the "Schema notes that bite" callout above — the resource itself has no settable comment argument, so this module has none either, despite this library's usual universal-tail convention.
  • notify_users is a flat set(string), not a nested block. Confirmed against the live provider schema during Phase 1 grounding — no dynamic block is needed in main.tf to render it or notify_triggers.

🧱 Design Principles

Concern Secure default in this module Opt-out (caller must be explicit)
Object comment N/A — the resource has no settable comment argument (schema-verified deviation from the house universal tail) Not applicable
Credit quota null (unset) — the empty call creates a monitor that tracks nothing and takes no action Caller sets credit_quota explicitly
Reset schedule (frequency/start_timestamp) Both null (unset) — no forced reset schedule Caller sets both together explicitly
Notify thresholds [] (empty) — no notifications configured Caller populates notify_triggers explicitly
Suspend thresholds null for both suspend_trigger and suspend_immediate_trigger — no suspend action configured Caller sets either or both explicitly
Notification recipients [] (empty) — no implicit notification of any user Caller populates notify_users explicitly, referencing terraform-snowflake-user outputs

The empty call (name only) produces a resource monitor that exists but governs nothing — no credit tracking, no notifications, no suspension — consistent with this library's "the empty call must produce the safe resource" convention. A caller has to type every additional argument to make the monitor actually enforce a budget.


🚀 Runbook

cd C:\GitHubCode\newsnowflakemodules\terraform-snowflake-resource-monitor
terraform init -backend=false
terraform validate
terraform fmt -check

Pin the module source to ?ref=v1.0.0 — never a branch — in every caller. This is a plan-only authoring pipeline: no terraform plan or terraform apply is ever run as part of authoring this module. A human runs apply from a governed CI pipeline against a real Snowflake account.


🧪 Testing

terraform validate and terraform fmt -check are the offline proof gate this module ships with:

  • What they cover: type correctness (every variable's object/scalar/set shape), the frequency enum, the frequency/start_timestamp pairing rule, and the triggers-only rejection rule — all three validation {} blocks fire on terraform validate with no live Snowflake account required. HCL syntax and formatting are covered by fmt -check.
  • What only a real plan/apply exercises: whether the executing role actually holds CREATE RESOURCE MONITOR (privilege sufficiency), whether notify_users references existing Snowflake users (object-existence dependency this module deliberately does not check), and the destroy/recreate behavior triggered by unsetting every trigger on an existing monitor (a DESC/state-comparison-driven behavior invisible to a single-configuration validate pass).

💬 Example Output

$ terraform output

fully_qualified_name = "\"RM_WH_ETL\""
name = "RM_WH_ETL"
id = "\"RM_WH_ETL\""

🔍 Troubleshooting

Symptom Cause Fix
terraform validate fails with "A resource monitor cannot be created with only trigger fields set" Only notify_triggers/suspend_trigger/suspend_immediate_trigger were set, with none of credit_quota, frequency, start_timestamp, end_timestamp, or notify_users Set at least one non-trigger attribute alongside the trigger(s) — see Example 7
terraform validate fails with "frequency and start_timestamp must be set together" Only one of the pair was set Set both, or leave both null
Apply fails with a Snowflake authorization error on CREATE RESOURCE MONITOR Executing role lacks the privilege (commonly ACCOUNTADMIN-only) Grant CREATE RESOURCE MONITOR to the executing role, or apply through a provider alias configured for ACCOUNTADMIN
A plan that removes every trigger from an existing monitor shows a destroy/recreate instead of an in-place update Provider/Snowflake limitation — once triggers are set, they cannot be fully unset in place Expected behavior; review the destroy/recreate carefully before applying, since it is a real object recreation, not a cosmetic diff
Removing frequency or start_timestamp from HCL produces no diff on the next plan Provider has no unset support for these two parameters — the previously applied value is preserved on the Snowflake side Set the field to a different explicit value to change it; deleting the argument alone does not reset it
notify_users reference fails at apply with a Snowflake "user does not exist" error This module does not validate user existence at plan time Confirm the referenced terraform-snowflake-user module has already been applied, or the user identifier is correct
Import leaves frequency/start_timestamp blank in the generated configuration despite a value on the live object Known provider import gap for several resources (see this library's cross-cutting "Schema notes that bite" convention) Compare against terraform show / show_output after import and add the missing arguments manually before the next plan

🔗 Related Docs

Releases

Packages

Contributors

Languages