Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📊 Microsoft Fabric Activator Terraform Module

Manages a Fabric Activator item (fabric_activator) — a no-code/low-code event-driven alerting and automation surface (formerly branded "Reflex") — targeting the microsoft/fabric provider ~> 1.12.0.

Terraform Provider Module Version Module Type Resources Posture


ℹ️ Newly discovered resource. fabric_activator was not in this module suite's original § Fabric module suite table — it surfaced only through this batch's Discovery-phase reconciliation against the live provider (terraform-registry MCP, the live provider schema, provider_doc_id 12766450). Every fact below was independently re-confirmed against the live schema this session.

Naming history: Microsoft has used both "Activator" and "Reflex" for this Real-Time Intelligence item across UI/documentation generations. The current provider resource name is fabric_activator (confirmed live — no fabric_reflex alias exists), but its definition-part file name is still ReflexEntities.json — a naming holdover from the feature's earlier "Reflex" branding, not a module error. Older Microsoft materials referring to "Reflex" describe this same item type.

🧩 Overview

  • Creates and manages exactly one Fabric Activator (fabric_activator.this).
  • Optionally carries a single Default-format definition part (ReflexEntities.json) — the event trigger/condition/action rule graph — modeled as a path-keyed Attributes Map.
  • Defaults to workspace-root placement (folder_id = null) and no predefined content (definition = {}).
  • Optionally assigns existing fabric_tag GUIDs via tags — confirmed present on this resource's live schema.
  • Emits the Activator id for cross-referencing by downstream orchestration outside Terraform's own reference graph.

💡 Why it matters: this is a preview resource — the caller's root provider configuration must explicitly opt into preview mode before this module resolves at all. Getting that surfaced loudly here, rather than discovered as a confusing "resource not found" error mid-apply, is the single most important thing this README does.


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


⚠️ Preview status and required provider opt-in

The live v1.12.0 schema (confirmed via terraform-registry MCP the live provider schema, provider_doc_id 12766450) states directly:

~> This resource is in preview. To access it, you must explicitly enable the preview mode in the provider level configuration.

Per this module suite's conventions § Code Standard and § What makes Fabric modules different (item 4), this is exclusively a caller-level provider concern — this module never adds a preview/enable_preview variable, and never will. The caller's root module must set:

provider "fabric" {
  #... auth fields...
  preview = true
}

Omitting preview = true produces a confusing, module-unrelated error (the provider effectively behaves as if this resource type doesn't exist) rather than a clear "preview required" message — see 🔍 Troubleshooting.


🗺️ Where this fits

flowchart TB
 Workspace["terraform-fabric-workspace"]:::keystone
 Folder["terraform-fabric-folder"]:::sibling
 Tag["terraform-fabric-tag"]:::sibling
 Activator["terraform-fabric-activator\n(this module)"]:::thisModule
 Downstream["Teams / Power Automate / Fabric item triggers\n(inside the definition payload, outside Terraform)"]:::sibling

 Workspace -->|"workspace_id"| Activator
 Folder -->|"folder_id (optional)"| Activator
 Tag -->|"tags (optional set of GUIDs)"| Activator
 Activator -->|"id"| Downstream

 classDef thisModule fill:#0F6CBD,color:#FFFFFF,stroke:#0F6CBD
 classDef keystone fill:#143551,color:#FFFFFF,stroke:#143551
 classDef sibling fill:#E8EAED,color:#1A1A1A,stroke:#B0B7BF
Loading

The live v1.12.0 schema does not expose a top-level reference to an upstream event source (e.g. an Eventstream) — any such trigger wiring is expressed entirely inside the definition JSON payload's own rule graph, confirmed against the live schema. There is deliberately no terraform-fabric-eventstream edge in the diagram above.


🧬 What this builds

flowchart TB
 subgraph Inputs["Inputs"]
 DisplayName["display_name"]
 Description["description"]
 WorkspaceId["workspace_id"]
 FolderId["folder_id"]
 Format["format"]
 Definition["definition (Attributes Map,\nReflexEntities.json)"]
 DefUpdate["definition_update_enabled"]
 Tags["tags"]
 Timeouts["timeouts"]
 end

 Keystone["fabric_activator.this\n(PREVIEW)"]:::thisModule

 DisplayName --> Keystone
 Description --> Keystone
 WorkspaceId --> Keystone
 FolderId --> Keystone
 Format --> Keystone
 Definition -->|"assigned with ="| Keystone
 DefUpdate --> Keystone
 Tags --> Keystone
 Timeouts -->|"assigned with ="| Keystone

 Keystone -->|"id"| OutId["id output"]
 Keystone -->|"display_name"| OutName["display_name output"]

 classDef thisModule fill:#0F6CBD,color:#FFFFFF,stroke:#0F6CBD
Loading

Resource inventory: 1 resource — fabric_activator.this (single instance, the sole keystone; this is a standalone module with no owned children).


✅ Provider / Versions

Requirement Value
Terraform >= 1.12.0
Provider microsoft/fabric ~> 1.12.0
Provider configuration None in this module — the caller configures provider "fabric" {} (auth, tenant, and preview = true) at the root
Preview gate Required — see ⚠️ callout above
Delegated-auth exception Not applicable — the live schema states "This resource supports Service Principal authentication"

Schema notes that bite (confirmed against the live v1.12.0 schema via the terraform-registry MCP, the live provider schema, provider_doc_id 12766450):

  • This resource is preview-gated — see the ⚠️ callout above. This is the single most important gotcha in this README.
  • definition is a Terraform Plugin Framework Attributes Map, not a Block — assigned directly with = in main.tf, never wrapped in a dynamic "definition" block. timeouts is likewise a single nested Attributes object, also assigned with =.
  • The schema currently accepts exactly one definition-part key, "ReflexEntities.json" (note the "Reflex" naming holdover), paired with format = "Default" — the only documented format value.
  • processing_mode's provider-native default is "GoTemplate"; this module overrides its own default to "None" per this module suite's secure-by-default convention.
  • No configuration argument exists on this resource — do not add one.
  • tags is a genuine Set of String on the live schema — confirmed present, wired straight through.
  • Preview status is a real state, not a formality (this module suite's Fabric-specific design conventions, item 4) — reconfirm this resource's GA-vs-preview posture at the start of every subsequent authoring session, since the provider ships roughly every two weeks and preview→GA transitions are common.

🔑 Required Fabric / Entra Permissions

(sourced from this module's SCOPE.md — do not let this drift independently)

  • Fabric workspace role: Admin, Member, or Contributor (inferred). Microsoft Learn's "Roles in workspaces in Microsoft Fabric" capability table does not explicitly name "Activator" by row (unlike Eventhouses/KQL Querysets/Real-Time Dashboards, which are named explicitly) — this floor is inferred from the generic Fabric Permission Model's "Create items"/"Write data" capability (Admin/Member/Contributor ✅, Viewer ❌), matching the Discovery-phase baseline (Workspace Contributor). ⚠️ Flagged as inferred, not resource-specific-table-confirmed.
  • Entra: the calling Service Principal (or Managed Identity) must be included in the tenant's allowed security group under the "Service principals can call Fabric public APIs" Developer setting.
  • If the Activator's definition includes action types that call out to external services on the caller's behalf (Teams notifications, Power Automate flows, triggering other Fabric items) — Microsoft Learn's Activator troubleshooting docs describe distinct failure modes (FabricItemExecutionNoPermissions, Entra-admin-blocked service principals for Teams/Reflex) that imply additional, action-specific Entra/ Teams-tenant permissions beyond the base Fabric workspace role. These are data-plane/runtime permissions (needed for the Activator's rules to actually fire), not Terraform apply-time permissions, and are out of this module's scope to enumerate exhaustively — reconfirm against Microsoft Learn for the specific action types a given deployment uses.
  • ⚠️ Because this resource is newly discovered for this catalog, do not assume the floor above is complete — reconfirm before relying on it for a production tenant rollout.

Microsoft Fabric Prerequisites

  • The caller's root provider "fabric" {} block must set preview = true — see ⚠️ callout above. This is a hard prerequisite distinct from every other prerequisite listed here.
  • The target capacity backing the workspace must be in Active state (not paused) for Activator create/read operations.
  • The tenant's "Service principals can call Fabric public APIs" Developer setting must already be enabled in the Fabric Admin Portal before any SPN/MSI auth call succeeds at all.
  • No Fabric trial/license prerequisite beyond an active, non-trial capacity was found specific to Activator, beyond the general preview-feature enablement above.

📁 Module Structure

terraform-fabric-activator/
├── providers.tf # required_providers (fabric ~> 1.12.0), no provider {} block
├── variables.tf # display_name, workspace_id, description, folder_id, format, definition,
│ # definition_update_enabled, tags, timeouts
├── main.tf # fabric_activator.this — the sole keystone
├── outputs.tf # id, display_name
├── README.md # this file
├── SCOPE.md # lightweight cross-module contract (standalone)
└── examples/
 ├── basic/ # empty Activator, no definition, workspace-root placement
 └── complete/ # Activator with a token-substituted definition, folder_id, tags

⚙️ Quick Start

# Caller's root module configures the provider — never this module. `preview = true` is REQUIRED.
provider "fabric" {
  tenant_id     = var.tenant_id
  client_id     = var.client_id
  client_secret = var.client_secret # sourced from Key Vault / pipeline secret, never literal
  preview       = true
}

module "activator" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-activator.git?ref=v1.0.0"

  display_name = "act-alerts-ops-prod"
  description  = "Production alerting rules. Owner: Observability."
  workspace_id = module.workspace.id
}

🔌 Cross-Module Contract

Consumes

Input Type Source module
workspace_id string (required) terraform-fabric-workspace id output
folder_id string (optional) terraform-fabric-folder id output
tags set(string) (optional) terraform-fabric-tag id outputs

Emits

Output Description Consumed by
id Activator GUID Downstream orchestration outside Terraform's reference graph
display_name Activator display name Informational / cross-referencing

📚 Example Library

1 · Safe empty call

⚠️ Requires provider "fabric" { preview = true } at the caller's root — see § Preview status above.

module "activator" {
  source = "../../"

  display_name = "act-sandbox-explore-dev"
  workspace_id = module.workspace.id
}
2 · Governance context via description
module "activator" {
  source = "../../"

  display_name = "act-claims-alerts-prod"
  description  = "Claims backlog threshold alerting. Owner: Claims Operations."
  workspace_id = module.workspace.id
}
3 · Explicit folder placement
module "activator" {
  source = "../../"

  display_name = "act-alerts-ops-prod"
  workspace_id = module.workspace.id
  folder_id    = module.folder_alerting.id
}
4 · Tagged with existing fabric_tag GUIDs
module "activator" {
  source = "../../"

  display_name = "act-alerts-ops-prod"
  workspace_id = module.workspace.id
  tags         = [fabric_tag.this["observability"].id]
}
5 · Bootstrap-only definition (no drift tracking)
module "activator" {
  source = "../../"

  display_name              = "act-alerts-ops-dev"
  workspace_id              = module.workspace.id
  definition_update_enabled = false
  format                    = "Default"

  definition = {
    "ReflexEntities.json" = {
      source = "${path.module}/files/ReflexEntities.json"
    }
  }
}
6 · Definition with drift tracking (default behavior)
module "activator" {
  source = "../../"

  display_name = "act-alerts-ops-prod"
  workspace_id = module.workspace.id
  format       = "Default"

  definition = {
    "ReflexEntities.json" = {
      source = "${path.module}/files/ReflexEntities.json"
    }
  }
}
7 · Token substitution with a custom delimiter
module "activator" {
  source = "../../"

  display_name = "act-alerts-ops-prod"
  workspace_id = module.workspace.id
  format       = "Default"

  definition = {
    "ReflexEntities.json" = {
      source           = "${path.module}/files/ReflexEntities.json.tmpl"
      tokens_delimiter = "@{}@"
      processing_mode  = "GoTemplate"
      tokens = {
        RuleName = "high-error-rate"
      }
    }
  }
}
8 · Explicit Parameters processing mode (JsonPathReplace)

🔒 processing_mode defaults to "None" at the module level (overriding the provider's own "GoTemplate" default) per this module suite's secure-by-default convention.

module "activator" {
  source = "../../"

  display_name = "act-alerts-ops-prod"
  workspace_id = module.workspace.id
  format       = "Default"

  definition = {
    "ReflexEntities.json" = {
      source          = "${path.module}/files/ReflexEntities.json.tmpl"
      processing_mode = "Parameters"
      parameters = [
        {
          type  = "JsonPathReplace"
          find  = "$.properties.name"
          value = "high-error-rate"
        }
      ]
    }
  }
}
9 · TextReplace parameter substitution
module "activator" {
  source = "../../"

  display_name = "act-alerts-ops-prod"
  workspace_id = module.workspace.id
  format       = "Default"

  definition = {
    "ReflexEntities.json" = {
      source          = "${path.module}/files/ReflexEntities.json.tmpl"
      processing_mode = "Parameters"
      parameters = [
        {
          type  = "TextReplace"
          find  = "__ENVIRONMENT__"
          value = "prod"
        }
      ]
    }
  }
}
10 · Custom timeouts
module "activator" {
  source = "../../"

  display_name = "act-alerts-ops-prod"
  workspace_id = module.workspace.id

  timeouts = {
    create = "20m"
  }
}
11 · for_each fan-out across a per-domain alerting set
locals {
  activators = {
    ops     = "act-ops-alerts-prod"
    claims  = "act-claims-alerts-prod"
    finance = "act-finance-alerts-prod"
  }
}

module "activator" {
  source   = "../../"
  for_each = local.activators

  display_name = each.value
  workspace_id = module.workspace.id
}
12 · Missing preview opt-in (failure mode illustration)

⚠️ Without provider "fabric" { preview = true } at the caller's root, this exact same configuration fails to resolve the resource type — see 🔍 Troubleshooting.

# provider "fabric" { } # preview NOT set — this configuration will fail

module "activator" {
  source = "../../"

  display_name = "act-will-fail-dev"
  workspace_id = module.workspace.id
}
13 · Governed folder nesting (raw/curated split)
module "activator" {
  source = "../../"

  display_name = "act-curated-alerts-prod"
  workspace_id = module.workspace.id
  folder_id    = module.folder_curated.id
}
14 · Explicit format without a definition (no-op)
module "activator" {
  source = "../../"

  display_name = "act-placeholder-dev"
  workspace_id = module.workspace.id
  format       = "Default"
}
15 · 🏗️ End-to-end composition

Wires a workspace, a folder, a tag, and this module together. Assumes the caller's root provider "fabric" { preview = true } is already configured.

module "workspace" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-workspace.git?ref=v1.0.0"

  display_name = "ws-observability-core-prod"
  description  = "Core observability workspace — prod. Owner: Observability."
}

module "folder_alerting" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-folder.git?ref=v1.0.0"

  workspace_id = module.workspace.id
  display_name = "alerting"
}

resource "fabric_tag" "observability" {
  display_name = "observability"
}

module "activator" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-activator.git?ref=v1.0.0"

  display_name = "act-alerts-ops-prod"
  description  = "Production alerting rules — Teams notification on threshold breach. Owner: Observability."
  workspace_id = module.workspace.id
  folder_id    = module.folder_alerting.id
  format       = "Default"

  definition = {
    "ReflexEntities.json" = {
      source          = "${path.module}/files/ReflexEntities.json.tmpl"
      processing_mode = "GoTemplate"
      tokens = {
        RuleName = "high-error-rate"
      }
    }
  }

  tags = [fabric_tag.observability.id]
}

📥 Inputs

Variable Type Default Notes
display_name string — (required) Non-empty
workspace_id string — (required) Non-empty
description string null
folder_id string null Workspace-root placement if omitted
format string null Only legal value: "Default"
definition map(object({...})) {} Keyed by "ReflexEntities.json" for format = "Default"
definition_update_enabled bool true Matches provider default
tags set(string) [] fabric_tag GUIDs
timeouts object({...}) null
Full object schemas
variable "definition" {
  type = map(object({
    source           = string
    tokens_delimiter = optional(string, "{{}}")
    tokens           = optional(map(string), {})
    processing_mode  = optional(string, "None")
    parameters = optional(set(object({
      find  = string
      type  = string
      value = string
    })), [])
  }))
  default = {}
}

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

🧾 Outputs

Output Description Sensitive
id Activator GUID
display_name Activator display name

🧠 Architecture Notes

  • definition and timeouts are assigned directly with = in main.tf — never a dynamic block — since the live v1.12.0 schema documents both as Terraform Plugin Framework Attributes types.
  • The live schema does not expose a top-level reference to an upstream event source (e.g. an Eventstream). Trigger wiring is expressed entirely inside the definition JSON payload.
  • definition currently accepts exactly one part key ("ReflexEntities.json" — a naming holdover from the feature's earlier "Reflex" branding), still modeled as a generic map(object(...)).
  • processing_mode's module-level default ("None") overrides the provider's own "GoTemplate" default per this module suite's secure-by-default convention.
  • This resource requires provider "fabric" { preview = true } — this is the single fact most likely to trip up a caller who copies this module's examples without also updating their root provider block.

🧱 Design Principles

Concern Safe default Opt-out
Folder placement folder_id = null — workspace root Caller supplies folder_id
Definition content definition = {} — no predefined content Caller supplies a definition part
Template substitution processing_mode = "None" (module default; provider default is "GoTemplate") Caller sets "GoTemplate" or "Parameters" explicitly
Tag assignment tags = [] Caller supplies fabric_tag GUIDs
Preview opt-in Never assumed by this module — always the caller's explicit root provider setting N/A — caller-level only

🚀 Runbook

cd C:\GitHubCode\newfabricmodules\terraform-fabric-activator
terraform init -backend=false
terraform validate
terraform fmt -check

Pin consumers to ?ref=v1.0.0 — never a branch. This module is plan-only; a human applies from a reviewed, approved CI pipeline whose root provider configuration already sets preview = true.


🧪 Testing

  • terraform validate catches: a malformed definition entry, an illegal format value, an empty display_name/workspace_id.
  • terraform fmt -check catches formatting drift without silently rewriting files.
  • Not caught offline: whether the caller's root provider has preview = true set (a plan/apply-time failure, not a validate-time one), whether the calling principal holds sufficient workspace role, whether the target capacity is Active, or whether the tenant's "Service principals can call Fabric public APIs" setting is enabled. These require a live plan/apply against a real tenant.

💬 Example Output

module.activator.id = "6c9d4e3f-1b5a-4c0d-d4a3-8e7f0a1b2c3d"
module.activator.display_name = "act-alerts-ops-prod"

🔍 Troubleshooting

Symptom Cause Fix
Resource fails to resolve / plan errors with a confusing "resource not found"-shaped message Caller's root provider "fabric" {} did not set preview = true Add preview = true to the root provider block
apply fails with a 403/permission error Calling principal lacks Contributor+ on the workspace Grant Admin, Member, or Contributor on the workspace
Entire module fails on every resource, every environment Tenant-level "Service principals can call Fabric public APIs" setting not enabled Have a Fabric administrator flip the Developer setting in the Fabric Admin Portal
definition silently doesn't update after changing the source file definition_update_enabled = false Set it to true (the default) if drift tracking is desired
Activator rule created but its Teams/Power Automate action never fires Data-plane/runtime permission gap (e.g. blocked Reflex service principal in Entra) — separate from Terraform apply-time permissions See Microsoft Learn's Activator troubleshooting docs for the specific action-error code

🔗 Related Docs

Releases

Packages

Contributors

Languages