Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

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

Repository files navigation

πŸ”· Dynatrace VictorOps Notification Terraform Module

Manages a single Splunk On-Call (VictorOps) problem-notification integration (dynatrace_victor_ops_notification) against the dynatrace-oss/dynatrace ~> 1.98 provider β€” a standalone primitive with one keystone resource and no owned children.

Terraform Dynatrace Provider Module Version Module Type Resources Posture


🧩 Overview

  • πŸ“Ÿ Renders exactly one resource β€” dynatrace_victor_ops_notification.this β€” a Splunk On-Call (VictorOps) notification channel that pages an on-call group when a problem matching an associated Dynatrace alerting profile opens.
  • πŸ”— Attaches to a pre-existing alerting profile by ID (profile); does not create, own, or validate that profile β€” see terraform-dynatrace-alerting-profile.
  • πŸ”’ Treats both api_key and routing_key as sensitive, caller-supplied secrets β€” never a literal default, never re-exported as an output.
  • 🧱 No nested block_types in the live schema β€” every attribute is flat, so main.tf is an unconditional, total 1:1 mapping from variables.tf with no dynamic blocks required.
  • 🚫 Ships disabled by default (active = false) β€” a newly-applied integration cannot page anyone until the caller explicitly reviews and activates it.

πŸ’‘ Why it matters: a VictorOps/Splunk On-Call integration that silently lacks a working API key, a message body, or an explicit activation decision is worse than no integration at all β€” it looks configured in the Dynatrace UI while quietly never paging anyone (or, if misconfigured the other direction, paging immediately on apply before anyone has reviewed it). This module's type contract (required api_key/message, secure-by-default active) makes both failure modes visible at plan time instead of discoverable only during a real incident.


❀️ 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
 AP["terraform-dynatrace-alerting-profile"]:::sibling
 TM["terraform-dynatrace-victorops-notification"]:::this
 KR["dynatrace_victor_ops_notification"]:::keystone
 VO["Splunk On-Call / VictorOps"]:::external

 AP -- "id to profile" --> TM
 TM -- "manages" --> KR
 KR -- "pages via routing_key" --> VO

 classDef this fill:#1496FF,color:#FFFFFF,stroke:#0B5FA5,stroke-width:1px;
 classDef keystone fill:#0A2540,color:#FFFFFF,stroke:#08182b,stroke-width:1px;
 classDef sibling fill:#E8EAED,color:#1A1A1A,stroke:#B0B4BA,stroke-width:1px;
 classDef external fill:#F5F5F5,color:#1A1A1A,stroke:#B0B4BA,stroke-width:1px,stroke-dasharray: 3 3;
Loading

This module sits downstream of terraform-dynatrace-alerting-profile (which owns the alerting profile's severity rules and event filters) and upstream of nothing in this catalog β€” no sibling module consumes a VictorOps notification's id today. Validated via the Mermaid Chart MCP before embedding (valid: true).


🧬 What this builds

flowchart TB
 subgraph Inputs["Module Inputs"]
 name["name: string (required)"]
 profile["profile: string (required)"]
 api_key["api_key: string (required, sensitive)"]
 routing_key["routing_key: string (required, sensitive)"]
 message["message: string (required)"]
 active["active: bool (optional, default false)"]
 end

 R["dynatrace_victor_ops_notification.this"]:::keystone

 name -- "renders" --> R
 profile -- "renders" --> R
 api_key -- "renders, never logged" --> R
 routing_key -- "renders, never logged" --> R
 message -- "renders" --> R
 active -- "renders" --> R

 R -- "exposes" --> out_id["output: id"]
 R -- "exposes" --> out_name["output: name"]

 classDef keystone fill:#0A2540,color:#FFFFFF,stroke:#08182b,stroke-width:1px;
Loading

Validated via the Mermaid Chart MCP before embedding (valid: true).

Resource inventory:

Resource Count Role
dynatrace_victor_ops_notification.this 1 Keystone β€” the only resource this module manages

βœ… Provider / Versions

Item Value
Terraform >= 1.12.0
Provider dynatrace-oss/dynatrace, ~> 1.98
provider {} block None β€” the caller configures auth and dt_env_url outside this module

Schema notes that bite (confirmed against the live provider schema, provider v1.100.0):

  • api_key is the only attribute the provider itself flags sensitive = true. This module marks the corresponding variable sensitive = true and additionally elevates it from provider-optional to module-required β€” the provider would let apply succeed with no API key at all, producing an integration that looks configured but can never authenticate to Splunk On-Call.
  • routing_key is not flagged sensitive by the provider schema, but this module marks it sensitive = true anyway β€” a deliberate house judgment call beyond the raw schema. A routing key is credential-adjacent (it directs alert traffic into a specific escalation group), so it gets the same "never print in plan/apply CLI output" treatment even though Dynatrace's own schema doesn't require it.
  • Neither api_key nor routing_key is ever emitted as a module output β€” outputs.tf exposes only id and name, by design, regardless of the sensitive flag on either variable.
  • message is provider-required with no documented default (confirmed "required": true in the live schema) β€” this module requires it explicitly rather than inventing a plausible-sounding default for a free-text field.
  • active is provider-required with no server-side default β€” this module supplies a concrete module-level default of false (never null) so the rendered argument is always populated. This is also the secure-by-default choice: a newly-applied VictorOps integration is created disabled and cannot page anyone until the caller explicitly sets active = true.
  • legacy_id is a computed, read-only attribute (the classic REST API v1 cross-reference ID) present in the live schema but not modeled as a module input or output β€” there is no documented consumer for it in this catalog.
  • No nested block_types on this resource β€” every attribute is flat, so main.tf needs no dynamic blocks and no try(x, null) guards (every variable that reaches the resource block is already guaranteed non-null: five variables are required with no default, and active carries a concrete default).

πŸ”‘ Required OAuth Scopes / API Token Permissions

dynatrace_victor_ops_notification is Settings 2.0-backed (schema ID builtin:problem.notifications) and accepts either OAuth client credentials/platform token or a legacy API token. This is not an IAM/Account Management or Platform/Automation resource, so no account-idm-* or automation:* scopes are needed.

  • OAuth (recommended) or platform token: settings:objects:read, settings:objects:write.
  • API token (fallback): the resource's own documentation states explicitly β€” "This resource requires the API token scopes Read settings (settings.read) and Write settings (settings.write)" β€” confirmed directly against the live v1.100.0 schema doc.
  • This module does not touch IAM, Automation, or classic-Config-API-only resources.

Dynatrace Prerequisites

  • An OAuth client (or platform token, or legacy API token) provisioned with the scopes/permissions above, already bound via an IAM policy (OAuth/platform token path) or token permission grant (API token path).
  • A pre-existing Dynatrace alerting profile β€” created by a terraform-dynatrace-alerting-profile instance in the same or a prior plan β€” whose id output is passed into this module's profile input. This module does not create or validate the alerting profile.
  • A Splunk On-Call (VictorOps) account with a REST endpoint integration configured for Dynatrace, yielding the api_key and routing_key values (Settings -> Integrations -> Rest Endpoint -> Dynatrace, within Splunk On-Call). Source both from your own secrets manager β€” never as literal values in .tf or .tfvars committed to version control.

πŸ“ Module Structure

terraform-dynatrace-victorops-notification/
β”œβ”€β”€ providers.tf # required_version, required_providers pin β€” no provider {} block
β”œβ”€β”€ variables.tf # name, profile, api_key, routing_key, message, active β€” the full contract
β”œβ”€β”€ main.tf # dynatrace_victor_ops_notification.this β€” thin, total renderer
β”œβ”€β”€ outputs.tf # id, name (api_key/routing_key never output)
β”œβ”€β”€ SCOPE.md # lightweight standalone-module scope (this module's cross-module contract)
β”œβ”€β”€ README.md # this file
└── examples/
 └── quickstart/
 └── main.tf # standalone, directly-runnable Quick Start snippet

βš™οΈ Quick Start

module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-primary-oncall"
  profile     = module.alerting_profile.id # terraform-dynatrace-alerting-profile's `id` output
  api_key     = var.victorops_api_key      # sourced from your own secrets manager
  routing_key = var.victorops_routing_key  # sourced from your own secrets manager
  message     = "{ProblemTitle} - {ProblemImpact} - {ProblemSeverity} - {ProblemURL}"
  # active intentionally omitted β€” defaults to false (secure-by-default)
}

The caller configures the dynatrace provider (auth and dt_env_url) themselves, outside this module. This module never declares a provider {} block or an auth-related variable.


πŸ”Œ Cross-Module Contract

Consumes

Input Type Source module
profile string, required terraform-dynatrace-alerting-profile (its id output)

Emits

Output Description Consumed by
id The Dynatrace object ID of this VictorOps (Splunk On-Call) notification configuration No in-catalog consumer today; exposed for reference/import
name The display name of this VictorOps (Splunk On-Call) notification configuration Documentation/reference only

πŸ“š Example Library

1 Β· Minimal inactive integration (secure-by-default)
module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-staging-check"
  profile     = module.alerting_profile.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key
  message     = "{ProblemTitle} - {ProblemURL}"
}

πŸ”’ active is omitted, so it defaults to false. This integration renders in Dynatrace but pages no one until a caller explicitly sets active = true β€” the secure-by-default posture this module follows for notification integrations.

2 Β· Activating a reviewed integration
module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-primary-oncall"
  profile     = module.alerting_profile.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key
  message     = "{ProblemTitle} - {ProblemImpact} - {ProblemSeverity} - {ProblemURL}"
  active      = true
}

⚠️ Set active = true only after the routing key, alerting-profile scope, and message content have all been reviewed β€” this is the explicit opt-out the secure default requires.

3 Β· Custom message using the full placeholder set
module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-detailed-message"
  profile     = module.alerting_profile.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key
  message     = <<-EOT
 [{State}] {ProblemTitle}
 Impact: {ProblemImpact} | Severity: {ProblemSeverity}
 Entities: {NamesOfImpactedEntities}
 Details: {ProblemDetailsText}
 Link: {ProblemURL}
 EOT
  active      = true
}

ℹ️ Placeholders are resolved server-side by Dynatrace at notification-send time; this module renders the literal message string unmodified β€” it does not interpret or validate placeholder syntax.

4 Β· Referencing a pre-existing alerting profile by literal ID
module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-legacy-profile-link"
  profile     = "b6a8a1b2-9c3d-4e2f-8a1b-1234567890ab" # pre-existing profile, not managed by Terraform
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key
  message     = "{ProblemTitle} - {ProblemURL}"
}

⚠️ Prefer wiring profile = module.alerting_profile.id wherever the profile is also managed by this Terraform library β€” a literal ID here means Terraform cannot order the profile's creation before this notification and cannot detect if the profile is later destroyed out-of-band.

5 Β· Sourcing secrets from Terraform Cloud/Enterprise workspace variables
variable "victorops_api_key" {
  type      = string
  sensitive = true
}

variable "victorops_routing_key" {
  type      = string
  sensitive = true
}

module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-tfc-sourced"
  profile     = module.alerting_profile.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key
  message     = "{ProblemTitle} - {ProblemURL}"
}

πŸ”’ Populate victorops_api_key / victorops_routing_key as sensitive workspace variables in HCP Terraform/Enterprise β€” never as plain .tfvars committed to version control.

6 Β· Sourcing secrets from an external secrets-manager data source
data "azurerm_key_vault_secret" "victorops_api_key" {
  name         = "victorops-dynatrace-api-key"
  key_vault_id = data.azurerm_key_vault.this.id
}

data "azurerm_key_vault_secret" "victorops_routing_key" {
  name         = "victorops-dynatrace-routing-key"
  key_vault_id = data.azurerm_key_vault.this.id
}

module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-keyvault-sourced"
  profile     = module.alerting_profile.id
  api_key     = data.azurerm_key_vault_secret.victorops_api_key.value
  routing_key = data.azurerm_key_vault_secret.victorops_routing_key.value
  message     = "{ProblemTitle} - {ProblemURL}"
}

πŸ”’ This is the standard pattern this module follows for credential-bearing inputs: secret material is provisioned out of band, from the caller's own secrets manager, never as a module default.

7 Β· Minimal message referencing only title and URL
module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-terse-message"
  profile     = module.alerting_profile.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key
  message     = "{ProblemTitle} β€” {ProblemURL}"
  active      = true
}

πŸ’‘ message is required with no invented default (see Β§ Schema notes that bite) β€” even a minimal, two-placeholder message must be supplied explicitly.

8 Β· Multiple routing destinations via caller-layer for_each
locals {
  victorops_teams = {
    platform = {
      routing_key = var.victorops_routing_key_platform
      name        = "victorops-platform-team"
    }
    database = {
      routing_key = var.victorops_routing_key_database
      name        = "victorops-database-team"
    }
  }
}

module "victorops_notification" {
  source   = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"
  for_each = local.victorops_teams

  name        = each.value.name
  profile     = module.alerting_profile.id
  api_key     = var.victorops_api_key
  routing_key = each.value.routing_key
  message     = "{ProblemTitle} - {ProblemImpact} - {ProblemURL}"
  active      = true
}

ℹ️ This module itself has no owned for_each children (it is a single-resource standalone primitive) β€” breadth at scale is achieved by the caller wrapping the module call in for_each, keyed by a caller-chosen map key, never a list index.

9 Β· Environment-conditional activation (dev vs. prod)
module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-${var.environment}"
  profile     = module.alerting_profile.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key
  message     = "[${upper(var.environment)}] {ProblemTitle} - {ProblemURL}"
  active      = var.environment == "prod"
}

⚠️ Making active a computed expression is a legitimate pattern, but it moves the secure-by-default decision into caller-controlled logic β€” verify var.environment == "prod" evaluates as expected in every workspace before relying on it in production.

10 Β· Pairing with a narrowly-scoped (management-zone) alerting profile
module "management_zone" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-management-zone.git?ref=v1.0.0"

  name = "payments-processing"
}

module "alerting_profile" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-alerting-profile.git?ref=v1.0.0"

  name               = "payments-processing-availability"
  management_zone_id = module.management_zone.id

  rules = {
    availability-payments = {
      severity_level   = "AVAILABILITY"
      include_mode     = "NONE"
      delay_in_minutes = 5
    }
  }
}

module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-payments-processing"
  profile     = module.alerting_profile.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key_payments
  message     = "{ProblemTitle} - {ImpactedEntityNames} - {ProblemURL}"
  active      = true
}

πŸ’‘ Scoping the upstream alerting profile to a management zone (rather than leaving it environment-wide) is this module's narrowest-matching-scope default for alerting profiles β€” this VictorOps integration only ever pages for problems within that zone.

11 Β· Per-severity routing via multiple module instances
module "victorops_notification_critical" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-critical-escalation"
  profile     = module.alerting_profile_critical.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key_critical
  message     = "CRITICAL: {ProblemTitle} - {ProblemURL}"
  active      = true
}

module "victorops_notification_warning" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-warning-escalation"
  profile     = module.alerting_profile_warning.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key_warning
  message     = "WARNING: {ProblemTitle} - {ProblemURL}"
  active      = true
}

ℹ️ Each severity tier gets its own alerting profile (with its own rules) and its own VictorOps module instance with a distinct routing_key β€” this module has no built-in severity branching, so distinct routing per severity is achieved by composing multiple profile/notification pairs.

12 Β· Importing an existing VictorOps integration
module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-preexisting"
  profile     = module.alerting_profile.id
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key
  message     = "{ProblemTitle} - {ProblemURL}"
  active      = true
}
terraform import 'module.victorops_notification.dynatrace_victor_ops_notification.this' <existing-notification-settings-object-id>

⚠️ After import, run terraform plan and confirm no unexpected diff before the next apply β€” api_key cannot be read back from the Dynatrace API (it is provider-marked sensitive/write-only in practice), so the imported state's api_key will not reflect the real value until the caller supplies it explicitly via this module's variable.

13 Β· Consuming this module's id output for documentation/inventory
output "victorops_integration_ids" {
  description = "Map of VictorOps notification names to their Dynatrace object IDs, for change-management documentation."
  value = {
    for k, m in module.victorops_notification : k => m.id
  }
}

ℹ️ No sibling module in this catalog consumes a VictorOps notification's id today β€” this output is exposed for reference, terraform import, and inventory/documentation tooling.

14 Β· πŸ—οΈ End-to-end composition β€” alerting profile through VictorOps notification
module "alerting_profile" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-alerting-profile.git?ref=v1.0.0"

  name = "production-availability-critical"

  rules = {
    availability-all-entities = {
      severity_level   = "AVAILABILITY"
      include_mode     = "NONE"
      delay_in_minutes = 5
    }
    errors-tagged-services = {
      severity_level   = "ERRORS"
      include_mode     = "INCLUDE_ANY"
      delay_in_minutes = 10
      tags             = ["env:production", "tier:critical"]
    }
  }
}

module "victorops_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-victorops-notification.git?ref=v1.0.0"

  name        = "victorops-production-critical"
  profile     = module.alerting_profile.id # wires the sibling module's `id` output into `profile`
  api_key     = var.victorops_api_key
  routing_key = var.victorops_routing_key
  message     = "{ProblemTitle} - {ProblemImpact} - {ProblemSeverity} - {ProblemURL}"
  active      = true
}

output "alerting_profile_id" {
  value       = module.alerting_profile.id
  description = "The alerting profile created and consumed by the VictorOps notification below."
}

output "victorops_notification_id" {
  value       = module.victorops_notification.id
  description = "The VictorOps notification configuration wired to the alerting profile above."
}

πŸ’‘ This is the mandatory end-to-end wiring: terraform-dynatrace-alerting-profile's id output flows directly into this module's profile input, giving Terraform an implicit reference that orders the profile's creation before the notification β€” no depends_on required.


πŸ“₯ Inputs

Variable Type Required Default Notes
name string Yes β€” Display name in the Dynatrace UI notification list
profile string Yes β€” Alerting-profile ID; pass terraform-dynatrace-alerting-profile's id output
api_key string Yes β€” sensitive = true; source from your own secrets manager
routing_key string Yes β€” sensitive = true (house judgment call, not provider-mandated)
message string Yes β€” No non-arbitrary default exists for a free-text field
active bool No false Secure-by-default β€” set true explicitly to activate
Full variable schemas
variable "name" {
  type = string
}

variable "profile" {
  type = string
}

variable "api_key" {
  type      = string
  sensitive = true
}

variable "routing_key" {
  type      = string
  sensitive = true
}

variable "message" {
  type = string
}

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

All six variables are flat scalars β€” there are no nested object schemas in this module, since the underlying dynatrace_victor_ops_notification resource has no nested block_types. See each variable's full description heredoc in variables.tf for the complete schema provenance, including the documented deviations from the raw provider schema (api_key and message elevated to required; routing_key elevated to sensitive).


🧾 Outputs

Output Description Sensitive?
id The Dynatrace object ID of this VictorOps (Splunk On-Call) notification configuration No
name The display name of this VictorOps (Splunk On-Call) notification configuration No

api_key and routing_key are never output, regardless of their sensitive = true status at the variable layer β€” this module omits them from outputs.tf entirely rather than outputting them marked sensitive.


🧠 Architecture Notes

  • Total, unconditional renderer. main.tf maps all six variables directly onto dynatrace_victor_ops_notification.this with no try(x, null) guards anywhere. This is possible (and correct, following this module's "thin, total renderer" convention) because five of the six variables have no default β€” Terraform refuses to plan without a caller-supplied value β€” and the sixth (active) always carries a concrete, non-null default of false. Nothing reaching the resource block can ever be null.
  • Two schema deviations, both documented in variables.tf, both intentional:
  • api_key is provider-optional but this module makes it module-required. An apply with no API key would succeed while producing an integration that can never authenticate to Splunk On-Call β€” an inert, silently-broken channel. Requiring it surfaces that dependency at plan time.
  • message is provider-required with no documented default; the module simply passes that requirement through rather than inventing a plausible-sounding default string for free-text content.
  • One sensitivity deviation, also intentional: routing_key is not provider-flagged sensitive, but this module marks it sensitive = true anyway, since it is credential-adjacent (it directs alert traffic to a specific escalation group) even though it cannot itself authenticate to an API the way api_key can.
  • Implicit reference, not depends_on. profile is wired via module.alerting_profile.id in every example that composes with the sibling module β€” this gives Terraform a real reference that orders resource creation, consistent with this module suite's convention to respect record ordering via implicit references. No example in this README uses depends_on as a substitute.
  • No environment-vs-account-scope split to document. Unlike IAM/Account Management resources, this resource is entirely environment-scoped (Settings 2.0 object against a single Dynatrace environment) β€” there is no dual-provider-config concern here.
  • legacy_id is intentionally invisible. It exists on the live schema as a computed, read-only classic-API cross-reference, but this module does not expose it as an output β€” no consumer in this catalog needs the REST API v1 equivalent ID.

🧱 Design Principles

Concern Safe default Opt-out (caller must set explicitly)
Notification activation active defaults to false β€” a newly-applied integration cannot page anyone Explicit active = true, only after reviewing routing key, alerting-profile scope, and message content
api_key handling No literal default permitted; sensitive = true; never re-exported as an output N/A β€” non-negotiable, not a default to opt out of
routing_key handling Treated as sensitive = true even though the provider schema doesn't require it; never re-exported as an output N/A β€” non-negotiable house judgment call
message content No invented default β€” caller must supply real message text, surfacing the dependency at plan time rather than shipping a generic placeholder string N/A β€” required field, no opt-out
Alerting-profile scope This module does not choose or narrow scope itself β€” it inherits whatever scope the referenced terraform-dynatrace-alerting-profile instance defines Caller controls scope entirely via the upstream profile module

πŸš€ Runbook

terraform init -backend=false
terraform validate
terraform fmt -check

Pin the module source at ?ref=v1.0.0 β€” never an unpinned branch. This library is plan-only: no terraform apply is performed as part of authoring or CI validation; a human applies from a controlled pipeline after reviewing the plan.


πŸ§ͺ Testing

  • Covered by init -backend=false / validate / fmt -check: type-contract correctness (every required variable enforced at parse time, sensitive flags present, no malformed HCL), provider version constraint satisfiability, and formatting conventions. This is the offline proof gate β€” it runs with no Dynatrace credentials and touches no live environment.
  • Only exercised by a real terraform plan against a configured environment: whether the supplied profile ID actually resolves to an existing alerting profile, whether the supplied api_key / routing_key are accepted by Splunk On-Call at the API level, and whether the caller's OAuth scopes/API token permissions are sufficient. None of this is verifiable offline β€” this module's static analysis proves the shape of the request, not that Dynatrace or Splunk On-Call will accept it.

πŸ’¬ Example Output

$ terraform output

id = "vu9U3hXd3q0AAAABABlidWlsdGluOnByb2JsZW0ubm90aWZpY2F0aW9ucwAGdGVuYW50AAZ0ZW5hbnQAJGNhOTk4YTA3LTVh"
name = "victorops-production-critical"

api_key and routing_key never appear in terraform output β€” they are omitted from outputs.tf entirely.


πŸ” Troubleshooting

Symptom Cause Fix
apply fails with an authentication/authorization error, but the OAuth client or API token has the documented settings:objects:* / settings.* scopes The provider is configured for one auth mechanism (e.g. API token) while DYNATRACE_HTTP_OAUTH_PREFERENCE or the credential environment variables point at a different one Confirm which of DT_CLIENT_ID/DT_CLIENT_SECRET, DYNATRACE_PLATFORM_TOKEN, or DYNATRACE_API_TOKEN is actually set in the calling environment, and that DYNATRACE_HTTP_OAUTH_PREFERENCE matches the intended mechanism β€” this is a provider-config concern, not something this module can detect
VictorOps never receives a page even though active = true and apply succeeded routing_key does not match a configured routing rule in Splunk On-Call, or the profile's rules/filters never actually match the triggering problem Verify the routing key against Splunk On-Call's own configuration, and confirm the upstream terraform-dynatrace-alerting-profile instance has at least one non-inert rule scoped to match the entities in question
plan shows profile changing on every run profile is wired to a literal string ID rather than module.alerting_profile.id, and the literal ID doesn't exactly match the live object's ID format Reference the sibling module's id output directly instead of a hardcoded literal (see Example 4's caveat)
terraform import succeeds but the next plan shows a diff on api_key api_key cannot be read back from the Dynatrace API after import; imported state does not know the real value until the caller supplies it Supply the real api_key value via the module variable (sourced from your secrets manager) before the first post-import apply
A CI pipeline's validate step fails on this module specifically, while siblings pass message or api_key left unset β€” both are module-required with no default, unlike some sibling notification modules where the equivalent field may be optional Confirm the calling code supplies both explicitly; check this module's variables.tf rather than assuming parity with a sibling notification module's schema

πŸ”— Related Docs

  • Provider resource reference: dynatrace_victor_ops_notification β€” Dynatrace Terraform provider docs (dynatrace-oss/dynatrace, subcategory "Notifications").
  • Sibling module: terraform-dynatrace-alerting-profile (profile input's source module).
  • This module's SCOPE.md (cross-module contract, permissions, prerequisites).

πŸ’™ "Infrastructure as Code should be standardized, consistent, and secure."

About

Terraform module: terraform-dynatrace-victorops-notification

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages