Manages a single Fabric Report (
fabric_report) inside an existing Workspace β a Power BI report item bound to a Semantic Model by reference inside itsdefinitionpayload (e.g.definition.pbir/report.json). Targetsmicrosoft/fabric~> 1.12.0.
- π 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
definitionAttributes Map (keyed by definition-part path) as a deeply-typedvariables.tfschema, not a bare file path or positional list. - π Defaults
processing_modeto"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 optionalfolder_idto nest under a governed folder hierarchy. - π·οΈ Wires the confirmed-live
tagsargument (a set offabric_tagGUIDs) straight through. - π Supports the documented
JsonPathReplace/TextReplaceparameter 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/tokensaccept plain strings, so a caller wirestf-mod-fabric-semantic-model'sid/display_nameoutput straight into the Report's$.datasetReference.byPath.pathrewrite. 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.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
- β Star this repository to help others discover this Terraform module.
- π€ Connect with me on LinkedIn: linkedin.com/in/microsoftexpert
- β Buy me a coffee: buymeacoffee.com/microsoftexpert
Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!
graph LR
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;
(Validated via the Mermaid Chart MCP before embedding.)
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;
(Validated via the Mermaid Chart MCP before embedding.)
Resource inventory: 1 resource β fabric_report.this.
| 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:
definitionis 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=inmain.tfvia aforexpression over the caller's map β never adynamic "definition"block.- The provider's own
processing_modedefault is"GoTemplate"; this module's variable default is"None"per this suite's Secure-by-default convention's "Item definition tokens" row. Setprocessing_modeto"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.0fabric_reportschema 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 notagsargument 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 genuinetagsattribute (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_reportandfabric_semantic_modelβ the binding lives entirely inside the Report'sdefinition.pbirpayload. Terraform cannot detect a stale reference if the target Semantic Model is later renamed or moved; use a genuinemodule.semantic_model.id/display_namereference (not a hardcoded literal) intokens/parametersso 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 (unlikefabric_workspace's confirmed 256-character limit orfabric_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."
- 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
tagsis populated, the calling principal additionally needs whatever Fabric permission governs applying an existingfabric_tagto an item (not independently verified in this session).
- 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.
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
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.
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 |
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 = falsemeans 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 underformat = "PBIR"β the same keys underformat = "PBIR-Legacy"wouldplancleanly (this module does not cross-validate) and fail atapply.
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_modedefaults 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_iddefaults tonull(workspace root) per this suite's Secure-by-default convention β this example opts in explicitly. Consumefolder_idfromtf-mod-fabric-folder'sidoutput 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",
]
}π
tagsis a set offabric_tagGUIDs, not a free-form ARM-style key/value map β sourced fromtf-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/**anddefinition/**accepted-key entries each cover an arbitrary directory of files β this module'smap(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.
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
}| 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.
definitionis rendered as aforexpression overvar.definition, mapping each caller-supplied part straight through to the resource's own Attributes Map shape β nodynamicblock, since this is a Terraform Plugin Framework Attributes Map, not a repeating Block.timeoutsis 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 thenullcase.formatvs.definitionkey 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 adefinitionmap key against the chosenformatβ a mismatch plans cleanly and only surfaces atapply.- The Semantic Model binding lives entirely inside
definition.pbir's own JSON content (rewritten viatokensorparameters[*]) β there is no resource-level Terraform reference (nosemantic_model_idargument onfabric_report). Use a genuine module output reference intokens/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.
| 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 |
cd C:\GitHubCode\newfabricmodules\tf-mod-fabric-report
terraform init -backend=false
terraform validate
terraform fmt -checkPin ?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.
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.
report_id = "b2c3d4e5-f6a7-8901-bcde-f12345678901"
| 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 |
fabric_reportprovider docstf-mod-fabric-workspaceβ source ofworkspace_idtf-mod-fabric-folderβ source of optionalfolder_idtf-mod-fabric-semantic-modelβ source of the Semantic Model identity threaded into this module'sdefinition[...].tokens/parameters- This module's
SCOPE.md
π "Infrastructure as Code should be standardized, consistent, and secure."