Skip to content

microsoftexpert/tf-mod-fabric-report

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“Š Microsoft Fabric Report Terraform Module

Manages a single Fabric Report (fabric_report) inside an existing Workspace β€” a Power BI report item bound to a Semantic Model by reference inside its definition payload (e.g. definition.pbir / report.json). Targets microsoft/fabric ~> 1.12.0.

Terraform Provider Module Type Resources Posture


🧩 Overview

  • πŸ“Š Manages one fabric_report β€” the Power BI report item that renders visuals against a bound Semantic Model, inside a Fabric Workspace.
  • 🧬 Models the provider's native definition Attributes Map (keyed by definition-part path) as a deeply-typed variables.tf schema, not a bare file path or positional list.
  • πŸ” Defaults processing_mode to "None" (no template substitution) regardless of the provider's own "GoTemplate" default β€” a caller must opt in explicitly to token/parameter substitution.
  • πŸ“ Defaults to workspace-root placement (folder_id = null); accepts an optional folder_id to nest under a governed folder hierarchy.
  • 🏷️ Wires the confirmed-live tags argument (a set of fabric_tag GUIDs) straight through.
  • πŸ”— Supports the documented JsonPathReplace/TextReplace parameter pattern for rewriting a Report's bound Semantic Model reference at deploy time.

πŸ’‘ Why it matters: a Report is only useful bound to real data β€” this module never creates a first-class Terraform reference to a Semantic Model (the provider's schema has none), but its definition[...].parameters/tokens accept plain strings, so a caller wires tf-mod-fabric-semantic-model's id/display_name output straight into the Report's $.datasetReference.byPath.path rewrite. Use a genuine module output reference (not a hardcoded literal) so Terraform's own dependency graph orders the Semantic Model apply before the Report apply.


❀️ Support this project

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

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


πŸ—ΊοΈ Where this fits

graph LR
 workspace["fabric_workspace<br/>tf-mod-fabric-workspace"]:::keystone
 folder["fabric_folder<br/>tf-mod-fabric-folder<br/>optional"]:::sibling
 semanticmodel["fabric_semantic_model<br/>tf-mod-fabric-semantic-model"]:::sibling
 report["fabric_report<br/>this module"]:::this

 workspace -->|"workspace_id"| folder
 workspace -->|"workspace_id"| semanticmodel
 workspace -->|"workspace_id"| report
 folder -.->|"folder_id (optional)"| report
 semanticmodel -->|"id (dataset reference)"| report

 classDef keystone fill:#143551,color:#ffffff,stroke:#143551;
 classDef this fill:#0F6CBD,color:#ffffff,stroke:#0F6CBD;
 classDef sibling fill:#E8E8E8,color:#111111,stroke:#B0B0B0;
Loading

(Validated via the Mermaid Chart MCP before embedding.)


🧬 What this builds

graph LR
 subgraph Inputs
 display_name
 workspace_id
 folder_id
 description
 format
 definition
 definition_update_enabled
 tags
 timeouts
 end

 this["fabric_report.this"]:::this

 subgraph Outputs
 id
 display_name_out["display_name"]
 format_out["format"]
 end

 display_name --> this
 workspace_id --> this
 folder_id --> this
 description --> this
 format --> this
 definition --> this
 definition_update_enabled --> this
 tags --> this
 timeouts --> this

 this --> id
 this --> display_name_out
 this --> format_out

 classDef this fill:#0F6CBD,color:#ffffff,stroke:#0F6CBD;
Loading

(Validated via the Mermaid Chart MCP before embedding.)

Resource inventory: 1 resource β€” fabric_report.this.


βœ… Provider / Versions

Requirement Value
Terraform >= 1.12.0
microsoft/fabric provider ~> 1.12.0
Provider block None β€” the caller configures provider "fabric" {} (auth, tenant) once at the root

Schema notes that bite:

  • definition is a provider-native Attributes Map keyed by the definition-part path (e.g. "definition.pbir", "definition/report.json", "report.json", "StaticResources/**") β€” a Terraform Plugin Framework Attributes Map, not a repeating Block. It is assigned directly with = in main.tf via a for expression over the caller's map β€” never a dynamic "definition" block.
  • The provider's own processing_mode default is "GoTemplate"; this module's variable default is "None" per this suite's Secure-by-default convention's "Item definition tokens" row. Set processing_mode to "GoTemplate" or "Parameters" explicitly on a per-part basis to opt in to substitution.
  • tags (Set of String, described by the provider as "the set of tag IDs") is confirmed present on the live v1.12.0 fabric_report schema and is wired through in this module β€” this is a deliberate, documented decision, not an oversight of an earlier (and since-corrected) claim in this suite's naming conventions that this provider "has no tags argument anywhere in its schema." That blanket claim was corrected during initial authoring once 34 of 62 live resources β€” every workspace-hosted item type, including this one β€” were confirmed to carry a genuine tags attribute (see this suite's naming conventions).
  • The accepted definition-part path keys differ by format:
  • PBIR β†’ StaticResources/**, definition.pbir, definition/**, semanticModelDiagramLayout.json
  • PBIR-Legacy β†’ StaticResources/**, definition.pbir, report.json, semanticModelDiagramLayout.json

This module does not cross-validate a definition map key against the chosen format β€” the provider performs no such check at the Terraform type level either. A caller who mixes part keys from the wrong format (e.g. supplying "definition/report.json" under format = "PBIR-Legacy") will plan cleanly and fail at apply. See Β§ Testing and Β§ Troubleshooting below.

  • There is no first-class Terraform reference between fabric_report and fabric_semantic_model β€” the binding lives entirely inside the Report's definition.pbir payload. Terraform cannot detect a stale reference if the target Semantic Model is later renamed or moved; use a genuine module.semantic_model.id/display_name reference (not a hardcoded literal) in tokens/parameters so Terraform's own dependency graph at least orders the applies correctly, even though it cannot track the binding's ongoing validity.
  • display_name's live schema docs pulled this session do not state an explicit maximum length for this resource (unlike fabric_workspace's confirmed 256-character limit or fabric_domain's 40-character limit) β€” this module validates only non-empty. Reconfirm against the live provider schema before assuming parity with another item type's length limit.
  • No delegated-auth exception applies β€” the provider's own docs state fabric_report "supports Service Principal authentication."

πŸ”‘ Required Fabric / Entra Permissions

  • Fabric workspace role: at least Contributor on the target workspace. Per Microsoft's Roles in workspaces in Power BI, Admin, Member, and Contributor (not Viewer) can create, edit, and delete workspace content, which covers Report creation β€” this corroborates the "Fabric Workspace Contributor" role supplied to this authoring session as sufficient and least-privilege.
  • Read/Build permission on the bound Semantic Model if it lives in a different workspace: per Microsoft's content-creator security planning guidance, a report creator needs Read and Build permission on the underlying Semantic Model, granted implicitly by workspace role when it's in the same workspace, or explicitly (per-item permission, or the tenant-level "Use semantic models across workspaces" setting) when it's elsewhere.
  • Entra / tenant: the calling Service Principal must be enabled under the tenant's "Service principals can use Fabric APIs" setting β€” this resource explicitly supports SPN authentication.
  • If tags is populated, the calling principal additionally needs whatever Fabric permission governs applying an existing fabric_tag to an item (not independently verified in this session).

Microsoft Fabric Prerequisites

  • The target workspace's assigned capacity must be Active (not paused) for Report create/update operations.
  • The tenant-level "Service principals can use Fabric APIs" setting must already be enabled in the Fabric Admin Portal β€” this is entirely outside Terraform's control and independent of this module.
  • If binding to a Semantic Model in a different workspace, the tenant's "Use semantic models across workspaces" setting must be enabled (or the model shared directly with the calling principal).
  • No additional Fabric trial/license prerequisite is documented for this resource beyond standard workspace/capacity access.

πŸ“ Module Structure

tf-mod-fabric-report/
β”œβ”€β”€ providers.tf # required_providers block, ~> 1.12.0 floor, no provider {} block
β”œβ”€β”€ variables.tf # display_name, workspace_id, folder_id, description, format, definition, tags, timeouts
β”œβ”€β”€ main.tf # fabric_report.this β€” the sole keystone
β”œβ”€β”€ outputs.tf # id, display_name, format
β”œβ”€β”€ README.md # this file
β”œβ”€β”€ SCOPE.md # lightweight cross-module contract
└── examples/
 β”œβ”€β”€ basic/ # bootstrap-only PBIR-Legacy report, no visuals
 └── complete/ # PBIR report with visuals, Parameters mode rewriting the dataset reference, folder placement, tags

βš™οΈ Quick Start

module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-claims-summary-dev"
  workspace_id = "00000000-0000-0000-0000-000000000000"
  format       = "PBIR-Legacy"

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source = "${path.module}/files/definition.pbir"
    }
  }
}

The caller configures the fabric provider (Service Principal auth, tenant ID) once at the root module β€” never inside this module.


πŸ”Œ Cross-Module Contract

Consumes:

Input Type Source module
workspace_id string tf-mod-fabric-workspace (id output)
folder_id string, optional tf-mod-fabric-folder (id output)
(informal, threaded into definition) string tf-mod-fabric-semantic-model (id/display_name outputs) β€” see Β§ Architecture Notes
tags set(string), optional tf-mod-fabric-tag (id outputs, once authored)

Emits:

Output Description Consumed by
id Report GUID β€” primary output Informational / downstream deployment pipelines, app publishing
display_name Report display name Informational / cross-referencing
format Report format (PBIR or PBIR-Legacy) Informational / cross-referencing

πŸ“š Example Library

1 Β· Bootstrap-only PBIR-Legacy (smallest legal call)

The format-mandatory PBIR-Legacy parts only β€” one token substitution for the Semantic Model id, no visuals beyond the baseline, no folder, no tags.

module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name              = "rpt-claims-summary-dev"
  workspace_id              = "00000000-0000-0000-0000-000000000000"
  format                    = "PBIR-Legacy"
  definition_update_enabled = false

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source          = "${path.module}/files/definition.pbir.tmpl"
      processing_mode = "GoTemplate"
      tokens = {
        "SemanticModelID" = "00000000-0000-0000-0000-000000000000"
      }
    }
    "StaticResources/SharedResources/BaseThemes/CY24SU10.json" = {
      source = "${path.module}/files/StaticResources/SharedResources/BaseThemes/CY24SU10.json"
    }
  }
}

ℹ️ definition_update_enabled = false means this is a true bootstrap β€” Terraform creates the report once and does not re-apply on subsequent source file changes.

2 Β· PBIR format with visuals
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-inventory-pbir-dev"
  workspace_id = "00000000-0000-0000-0000-000000000000"
  format       = "PBIR"

  definition = {
    "definition/report.json" = {
      source = "${path.module}/files/definition/report.json"
    }
    "definition/version.json" = {
      source = "${path.module}/files/definition/version.json"
    }
    "definition.pbir" = {
      source = "${path.module}/files/definition.pbir"
    }
    "definition/pages/pages.json" = {
      source = "${path.module}/files/definition/pages/pages.json"
    }
    "definition/pages/f0275333137c0ea79df2/page.json" = {
      source = "${path.module}/files/definition/pages/f0275333137c0ea79df2/page.json"
    }
    "definition/pages/f0275333137c0ea79df2/visuals/a3c8f5e1b79d42f0c6a1/visual.json" = {
      source = "${path.module}/files/definition/pages/f0275333137c0ea79df2/visuals/a3c8f5e1b79d42f0c6a1/visual.json"
    }
  }
}

⚠️ These part keys are only valid together under format = "PBIR" β€” the same keys under format = "PBIR-Legacy" would plan cleanly (this module does not cross-validate) and fail at apply.

3 Β· Custom tokens_delimiter
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-inventory-customdelim-dev"
  workspace_id = "00000000-0000-0000-0000-000000000000"
  format       = "PBIR-Legacy"

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source           = "${path.module}/files/definition.pbir.tmpl"
      processing_mode  = "GoTemplate"
      tokens_delimiter = "<<>>"
      tokens = {
        "SemanticModelID" = "00000000-0000-0000-0000-000000000000"
      }
    }
  }
}

ℹ️ With tokens_delimiter = "<<>>", the source file's placeholder syntax changes to <<SemanticModelID>> (not the dot-prefixed Go-template {{.SemanticModelID }} syntax, which is specific to the default "{{}}" delimiter).

4 Β· Parameters processing mode β€” rewriting the bound Semantic Model (JsonPathReplace)
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-inventory-parameters-dev"
  workspace_id = "00000000-0000-0000-0000-000000000000"
  format       = "PBIR-Legacy"

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source          = "${path.module}/files/definition.pbir"
      processing_mode = "Parameters"
      parameters = [
        {
          type  = "JsonPathReplace"
          find  = "$.datasetReference.byPath.path"
          value = "MyWorkspace/MySemanticModel.SemanticModel"
        }
      ]
    }
  }
}

πŸ”’ processing_mode defaults to "None" module-wide β€” this example opts in explicitly on the "definition.pbir" part only.

5 Β· Parameters processing mode β€” TextReplace combined with JsonPathReplace
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-inventory-parameters-combined-dev"
  workspace_id = "00000000-0000-0000-0000-000000000000"
  format       = "PBIR-Legacy"

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source          = "${path.module}/files/definition.pbir"
      processing_mode = "Parameters"
      parameters = [
        {
          type  = "JsonPathReplace"
          find  = "$.datasetReference.byPath.path"
          value = "MyWorkspace/MySemanticModel.SemanticModel"
        },
        {
          type  = "TextReplace"
          find  = "OldModelID"
          value = "NewModelID"
        }
      ]
    }
  }
}
6 Β· Explicit folder placement
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-claims-summary-prod"
  description  = "Curated-layer claims summary report β€” prod. Owner: Analytics."
  workspace_id = "00000000-0000-0000-0000-000000000000"
  folder_id    = "11111111-1111-1111-1111-111111111111"
  format       = "PBIR-Legacy"

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source = "${path.module}/files/definition.pbir"
    }
  }
}

πŸ’‘ folder_id defaults to null (workspace root) per this suite's Secure-by-default convention β€” this example opts in explicitly. Consume folder_id from tf-mod-fabric-folder's id output in a real composition.

7 Β· Tags assignment
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-claims-summary-prod"
  workspace_id = "00000000-0000-0000-0000-000000000000"
  format       = "PBIR-Legacy"

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source = "${path.module}/files/definition.pbir"
    }
  }

  tags = [
    "22222222-2222-2222-2222-222222222222",
    "33333333-3333-3333-3333-333333333333",
  ]
}

πŸ”’ tags is a set of fabric_tag GUIDs, not a free-form ARM-style key/value map β€” sourced from tf-mod-fabric-tag. Empty ([]) by default.

8 Β· Per-operation timeout overrides
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-claims-summary-dev"
  workspace_id = "00000000-0000-0000-0000-000000000000"
  format       = "PBIR-Legacy"

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source = "${path.module}/files/definition.pbir"
    }
  }

  timeouts = {
    create = "30m"
    update = "20m"
  }
}
9 Β· Multi-part PBIR definition with StaticResources theme
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-finance-multipart-dev"
  workspace_id = "00000000-0000-0000-0000-000000000000"
  format       = "PBIR"

  definition = {
    "definition/report.json" = {
      source = "${path.module}/files/definition/report.json"
    }
    "definition/version.json" = {
      source = "${path.module}/files/definition/version.json"
    }
    "definition.pbir" = {
      source = "${path.module}/files/definition.pbir"
    }
    "definition/pages/pages.json" = {
      source = "${path.module}/files/definition/pages/pages.json"
    }
    "StaticResources/SharedResources/BaseThemes/CY23SU10.json" = {
      source = "${path.module}/files/StaticResources/SharedResources/BaseThemes/CY23SU10.json"
    }
  }
}

ℹ️ PBIR's StaticResources/** and definition/** accepted-key entries each cover an arbitrary directory of files β€” this module's map(object({...})) typing accommodates any number of such nested paths as distinct map keys.

10 Β· Definition-update-disabled bootstrap with description
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name              = "rpt-archive-snapshot-prod"
  description               = "Frozen snapshot report β€” not re-applied on source change. Owner: Analytics."
  workspace_id              = "00000000-0000-0000-0000-000000000000"
  format                    = "PBIR-Legacy"
  definition_update_enabled = false

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source = "${path.module}/files/definition.pbir"
    }
  }
}
11 Β· PBIR-Legacy update semantics (source/tokens change re-applies)
module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-claims-summary-dev"
  workspace_id = "00000000-0000-0000-0000-000000000000"
  format       = "PBIR-Legacy"
  # definition_update_enabled left at the provider/module default (true)

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source          = "${path.module}/files/definition.pbir.tmpl"
      processing_mode = "GoTemplate"
      tokens = {
        "SemanticModelID" = "00000000-0000-0000-0000-000000000000"
      }
    }
  }
}
12 Β· PBIR with visuals, Parameters mode, folder placement, and tags together

The examples/complete/ reference implementation β€” combines several optional behaviors in one call.

module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-claims-summary-prod"
  description  = "Claims summary report, curated layer β€” prod. Owner: Analytics."
  workspace_id = "00000000-0000-0000-0000-000000000000"
  folder_id    = "11111111-1111-1111-1111-111111111111"
  format       = "PBIR"

  definition = {
    "definition/report.json" = {
      source = "${path.module}/files/definition/report.json"
    }
    "definition/version.json" = {
      source = "${path.module}/files/definition/version.json"
    }
    "definition.pbir" = {
      source          = "${path.module}/files/definition.pbir"
      processing_mode = "Parameters"
      parameters = [
        {
          type  = "JsonPathReplace"
          find  = "$.datasetReference.byPath.path"
          value = "ws-core-bronze-prod/sm-sales-forecast-prod.SemanticModel"
        }
      ]
    }
    "definition/pages/pages.json" = {
      source = "${path.module}/files/definition/pages/pages.json"
    }
    "definition/pages/f0275333137c0ea79df2/page.json" = {
      source = "${path.module}/files/definition/pages/f0275333137c0ea79df2/page.json"
    }
    "definition/pages/f0275333137c0ea79df2/visuals/a3c8f5e1b79d42f0c6a1/visual.json" = {
      source = "${path.module}/files/definition/pages/f0275333137c0ea79df2/visuals/a3c8f5e1b79d42f0c6a1/visual.json"
    }
    "StaticResources/SharedResources/BaseThemes/CY23SU10.json" = {
      source = "${path.module}/files/StaticResources/SharedResources/BaseThemes/CY23SU10.json"
    }
  }

  tags = ["22222222-2222-2222-2222-222222222222"]

  timeouts = {
    create = "30m"
  }
}
13 Β· πŸ—οΈ End-to-end composition β€” workspace + folder + semantic model + report

Wires tf-mod-fabric-workspace, tf-mod-fabric-folder, and tf-mod-fabric-semantic-model outputs into this module's inputs β€” using a genuine module.semantic_model.display_name reference (not a hardcoded literal) in the JsonPathReplace parameter, so Terraform's dependency graph orders the Semantic Model's apply before the Report's.

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

  display_name = "ws-core-bronze-prod"
  description  = "Bronze-layer medallion workspace, core domain β€” prod. Owner: Data Engineering."
}

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

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

module "semantic_model" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-semantic-model.git?ref=v1.0.0"

  display_name = "sm-sales-forecast-prod"
  description  = "Sales forecast semantic model, curated layer β€” prod. Owner: Data Engineering."
  workspace_id = module.workspace.id
  folder_id    = module.folder_curated.id
  format       = "TMSL"

  definition = {
    "model.bim" = {
      source = "${path.module}/files/model.bim"
    }
    "definition.pbism" = {
      source = "${path.module}/files/definition.pbism"
    }
  }
}

module "report" {
  source = "git::https://github.com/microsoftexpert/tf-mod-fabric-report.git?ref=v1.0.0"

  display_name = "rpt-sales-forecast-prod"
  description  = "Sales forecast report, curated layer β€” prod. Owner: Analytics."
  workspace_id = module.workspace.id
  folder_id    = module.folder_curated.id
  format       = "PBIR-Legacy"

  definition = {
    "report.json" = {
      source = "${path.module}/files/report.json"
    }
    "definition.pbir" = {
      source          = "${path.module}/files/definition.pbir"
      processing_mode = "Parameters"
      parameters = [
        {
          type  = "JsonPathReplace"
          find  = "$.datasetReference.byPath.path"
          value = "${module.workspace.display_name}/${module.semantic_model.display_name}.SemanticModel"
        }
      ]
    }
  }
}

output "report_id" {
  value = module.report.id
}

πŸ’‘ This continues directly from tf-mod-fabric-semantic-model's own end-to-end composition example β€” see that module's README Β§ Example Library, entry 13.


πŸ“₯ Inputs

Required: display_name, workspace_id, format, definition. Optional: description, folder_id, definition_update_enabled (default true), tags (default []), timeouts (default null).

Full object schemas
variable "display_name" {
  type = string
}

variable "workspace_id" {
  type = string
}

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

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

variable "format" {
  type = string # "PBIR" | "PBIR-Legacy"
}

variable "definition" {
  type = map(object({
    source           = string
    tokens           = optional(map(string), {})
    tokens_delimiter = optional(string)         # "<<>>" | "@{}@" | "____" | "{{}}"
    processing_mode  = optional(string, "None") # "GoTemplate" | "None" | "Parameters"
    parameters = optional(set(object({
      find  = string
      type  = string # "JsonPathReplace" | "TextReplace"
      value = string
    })), [])
  }))
  # required β€” no default
}

variable "definition_update_enabled" {
  type    = bool
  default = true
}

variable "tags" {
  type    = set(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 Report GUID β€” primary output No
display_name Report display name, echoed No
format Report format (PBIR or PBIR-Legacy), echoed No

Nothing sensitive or credential-shaped exists on this resource.


🧠 Architecture Notes

  • definition is rendered as a for expression over var.definition, mapping each caller-supplied part straight through to the resource's own Attributes Map shape β€” no dynamic block, since this is a Terraform Plugin Framework Attributes Map, not a repeating Block.
  • timeouts is passed through directly (timeouts = var.timeouts) rather than a ternary/try-wrapped construction β€” the variable's own type already matches the resource's expected shape (an object of optional duration strings), including the null case.
  • format vs. definition key coupling is a real, unenforced constraint: the accepted definition-part path keys differ between "PBIR" and "PBIR-Legacy", but this module does not (and the provider does not, at the Terraform type level) cross-validate a definition map key against the chosen format β€” a mismatch plans cleanly and only surfaces at apply.
  • The Semantic Model binding lives entirely inside definition.pbir's own JSON content (rewritten via tokens or parameters[*]) β€” there is no resource-level Terraform reference (no semantic_model_id argument on fabric_report). Use a genuine module output reference in tokens/parameters[*].value (not a hardcoded literal) so Terraform's dependency graph still orders the two applies correctly.
  • Sensitive handling: none required β€” no identity/credential-shaped attribute exists on fabric_report.

🧱 Design Principles

Concern Safe default (this module) Opt-out
Item definition tokens processing_mode = "None" per part (no template substitution) Set "GoTemplate" or "Parameters" explicitly on that part
Folder placement folder_id = null (workspace root) Supply folder_id from tf-mod-fabric-folder
Tags tags = [] (none assigned) Supply a set of fabric_tag GUIDs
Secrets in definition Never β€” sources are file paths; secrets belong in Key Vault/pipeline variables, injected via tokens/parameters at deploy time N/A

πŸš€ Runbook

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

Pin ?ref=v1.0.0 in every consuming root module β€” never a branch. This module is plan-only; a human applies from a reviewed, approved CI pipeline.


πŸ§ͺ Testing

What validate/fmt catch: malformed definition map shape (wrong nested field name/type), an invalid format/processing_mode/tokens_delimiter/parameters[*].type enum value, a missing required argument (display_name, workspace_id, format, definition).

What only a live plan/apply against a real tenant can exercise: whether the target capacity is Active; whether the calling principal actually holds Contributor-or-higher on the workspace (and Read/Build on the bound Semantic Model if it's cross-workspace); whether the tenant's "Service principals can use Fabric APIs" setting is enabled; and β€” notably β€” whether a definition part key is actually valid for the chosen format, and whether the Semantic Model reference rewritten via tokens/parameters actually resolves to a real, accessible Semantic Model. A PBIR-only key ("definition/report.json") supplied under format = "PBIR-Legacy" passes validate and plan cleanly (this module does not cross-validate keys against format) and only fails once the Fabric API rejects the definition at apply.


πŸ’¬ Example Output

report_id = "b2c3d4e5-f6a7-8901-bcde-f12345678901"

πŸ” Troubleshooting

Symptom Cause Fix
apply fails with a definition/format mismatch error A definition map key isn't valid for the chosen format (e.g. "definition/report.json" under format = "PBIR-Legacy") Re-check the accepted key list per format in Β§ Provider/Versions and correct the definition map's keys
Report renders with no data / "can't find dataset" error The Semantic Model reference inside definition.pbir doesn't resolve β€” either the token/parameter substitution didn't run (processing_mode left at "None") or the referenced Semantic Model was renamed/moved Confirm processing_mode is set to "GoTemplate"/"Parameters" on the relevant part, and that the substituted value matches the Semantic Model's current workspace/display_name
apply fails with an authorization/permission error despite Contributor access on the report's workspace The calling principal lacks Read/Build permission on a cross-workspace bound Semantic Model Grant Read+Build on the Semantic Model, or enable "Use semantic models across workspaces" tenant-wide
Terraform state appears to "lose track" of this Report between applies Backing capacity is paused rather than Active Resume the capacity before the next apply; see this suite's Region/Instance/Scope model convention
terraform validate rejects a tokens_delimiter/processing_mode/parameters[*].type value Value isn't in the closed enum this module validates Use one of the exact values listed in the variable's error_message

πŸ”— Related Docs

  • fabric_report provider docs
  • tf-mod-fabric-workspace β€” source of workspace_id
  • tf-mod-fabric-folder β€” source of optional folder_id
  • tf-mod-fabric-semantic-model β€” source of the Semantic Model identity threaded into this module's definition[...].tokens/parameters
  • This module's SCOPE.md

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

About

No description or website provided.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages