Report (SSRS) Deployment
How eSHARS report definitions (.rdl), shared datasets, and data sources are deployed to the
SSRS report server during a release, and how to recover a failed publish.
This is the release-time report deploy path. For provisioning the report-server VM itself see Report Server (infrastructure). For local report authoring in Visual Studio see the dev-site Report Configuration guide.
Go-forward — GitHub Actions CD Deploy (HISD repo, PR #6478)
Source of truth: .github/workflows/cd-deploy.yml and .github/ops-scripts/deploy-reports.ps1
in the HISD repo, branch ci/tier-aware-deploys.
Reports are not a separate workflow — they are the deploy-reports job within the unified
tier-aware CD Deploy pipeline (alongside webui, eublob, jobscheduler, dbupgrader, tmhp,
reportviewer).
How a deploy is triggered
| Trigger | Result |
|---|---|
CI Build succeeds on develop | Auto-deploys to dev (nonprod) |
Manual workflow_dispatch | Promote to any slot: dev/qa/regression (nonprod tier) or uat/training/prod (prod tier) |
CD Deploy consumes the artifacts from a CI Build run (latest successful on develop, or a
specified ci_run_id). The resolve job derives the tier from the slot and resolves all
tier-specific infra names centrally (rebuilt CAF names), then reads the run’s
build-manifest.json so each component deploys only if it changed in that build
(changed_reports). If no manifest is present (older runs), it deploys all components.
How reports are published
The deploy-reports job runs on the self-hosted runner on the per-tier ops VM, then executes
deploy-reports.ps1 on the SSRS VM itself via a managed Run Command (ops-vm-run action) —
so publishing happens locally against http://localhost/ReportServer, never cross-VM HTTP. Flow:
- Stage to blob — the reports artifact is uploaded to the tier staging account
(
saeshars{tier}cus) →deploy-artifactscontainer →reports/<ci_run_id>/, guarded by a.stagedsentinel so re-runs skip re-upload. - Run on the SSRS VM — the VM pulls the staged blobs with its own managed identity
(
Connect-AzAccount -Identity) and runsdeploy-reports.ps1withReportingServicesTools.
What the script does (this is the important behaviour for HM-6163):
- Publishes the project manifest, not a glob. The file list comes from
Eshars.Report.rptproj(ItemGroup/Report+ItemGroup/DataSet), so the* - Backup.rdlworking files are never published. (PR #6478: 69 reports + 1 dataset.) - Catalog layout (per-environment, from the
REPORT_FOLDEREnvironment variable):- Reports →
REPORT_FOLDER - Datasets →
<REPORT_FOLDER>/../Datasets(sibling of the reports folder) - Data sources →
REPORT_DATASOURCE_FOLDER(documented default<REPORT_FOLDER>/Data Sources) - Missing report/dataset folders are created (
New-RsFolder).
- Reports →
- Data sources are CI-upserted from Key Vault —
HisdDbDataSource,HisdDbReportDataSource, andHistReportDbDataSource. On every deploy (wheneverKeyVaultNameis set, which the job always sets), the scriptNew-RsDataSource -Overwrites all three withCredentialRetrieval Storeand the SQL password pulled from the env’s Key Vault (SqlAdminPassword). CI then re-points each report’s data source reference at them (Set-RsDataSourceReference). They are not admin-managed — CI owns them. So the prerequisite per env is a correctSqlAdminPasswordin the KV plus correctDB_SERVER/SQL_USER/CORE_DB_NAMEvars, not hand-created data sources. - Per report:
Write-RsCatalogItem -Overwrite, then re-wire everyDataSourcereference to<DataSourceFolder>/<refName>.
Resolved infra (rebuilt CAF names)
resolve maps slot → tier → infra. The report/SSRS VM (component ssrs):
| Tier | Slots | SSRS VM | Staging account |
|---|---|---|---|
| nonprod | dev, qa, regression | vm-eshars-ssrs-nonprod-cus (10.22.1.6) | saesharsnonprodcus |
| prod | uat, training, prod | vm-eshars-ssrs-prod-cus (pending provision) | saesharsprodcus |
All tier VMs live in rg-eshars-compute-{tier}-cus. Per-env core DB is per-environment SQL
(sql-eshars-{env}-cus).
Per-environment configuration contract
GitHub Environment variables/secrets per slot (from PR #6478):
| Name | Kind | Purpose |
|---|---|---|
REPORT_FOLDER | var | SSRS catalog folder for this env’s reports |
REPORT_DATASOURCE_FOLDER | var (recommended) | Data-source catalog folder. Defaults to <REPORT_FOLDER>/../Data Sources; set explicitly to be unambiguous. |
SECURE_SETTINGS_KEYVAULT | var | Per-env Key Vault (kv-eshars-{env}); supplies the SQL password |
DB_SERVER, SQL_USER, CORE_DB_NAME | var | Data-source connection target |
SqlAdminPassword | KV secret | Read from SECURE_SETTINGS_KEYVAULT at deploy time |
Before running deploys for real
Outstanding items from PR #6478 (must be done before the GitHub path can deploy a given env):
- Confirm prod-tier resource names still marked
# TODO confirminresolve(SSRS VM / report server URL are*-001placeholders). - Create GitHub Environments for
uat/training/prodwithREPORT_FOLDERset and required-reviewer protection on prod. - Set
SECURE_SETTINGS_KEYVAULTon every environment, and ensure each env’s KV holds a correctSqlAdminPassword(CI stores it on the data sources). - Set
REPORT_DATASOURCE_FOLDERexplicitly per env (see the folder-default caution above). - Confirm
DB_SERVER/SQL_USER/CORE_DB_NAMEper env — CI builds the data-source connection from these. (Data sources are CI-upserted, not hand-created.) - Provision the prod SSRS VM (
vm-eshars-ssrs-prod-cus) and prod App Gateway ingress.
Legacy — Azure DevOps (runs until PR #6478 merges, then retired)
Step 10 of the hisd-deploy-stage ADO template (in this eshars-ops repo,
pipelines/templates/hisd-deploy-stage.yml)
runs E:\Build_Scripts\eSHARS\Build\Push-ReportDefinitions.ps1 on the self-hosted eSHARS-Agents
pool. It enumerates every *.rdl in eSHARS Build\eSHARS Reports and calls
CreateCatalogItem("Report", <name>, "/Reports", overwrite=$true, …) via ReportService2010.asmx.
Legacy targets (from pipelines/environments/*.yml):
| Env | Report server | Web service URL | reportServerEnvironment |
|---|---|---|---|
| Dev/QA/Reg/Stg/UAT | 40.113.238.4 (vm-sql16-np) | …/{Dev,QA,Reg,Stg,UAT}ReportServer | Devel/QA/REGRESSION/STG/UAT |
| Training | 40.122.54.1 (vm-sql16-1-np) | …/Reports | TRAIN |
| Production | 23.99.180.223 (vm-ssrs16-prod) | …/ReportServer | PROD |
Manual legacy publish (recovery only)
.\Push-ReportDefinitionsV2.ps1 ` -ReportServerUri "http://40.113.238.4/UATReportServer/ReportService2010.asmx?wsdl" ` -ReportServerEnvironment "UAT" ` -ReportSourceFolder "C:\path\to\eSHARS Build\eSHARS Reports" ` -ReportAdminUser "<ssrs-admin-user>" -ReportAdminPass "<ssrs-admin-password>"Credentials come from the ADO variable group / approved secret store — never hardcoded.
Report permissions (production)
After a production report deploy, ensure the report SQL login has EXECUTE on all report stored
procedures (a new report backed by a new proc fails to render otherwise).
Troubleshooting
| Symptom | Likely cause / action |
|---|---|
deploy-reports job: no staged blobs under reports/<run_id>/ | The reports artifact didn’t stage — check the CI build produced a reports artifact and the manifest had reports=true. |
| Run Command on SSRS VM fails to auth to blob/KV | The SSRS VM managed identity lacks Storage Blob Data Reader on the staging account or KV access — fix in Terraform, not by hand. |
| Report publishes but renders blank / data error | Data source pointing at the wrong DB, or references resolving to the wrong folder. CI upserts the data sources from KV — check DB_SERVER/SQL_USER/CORE_DB_NAME and SqlAdminPassword for the env. If references resolve to an empty folder, suspect the REPORT_DATASOURCE_FOLDER default mismatch (DataSources vs Data Sources). |
| Report renders but errors on a stored proc | Missing EXECUTE grant — see Report permissions. |
REPORT_FOLDER is not set | The slot’s GitHub Environment is missing the REPORT_FOLDER variable. |
| (Legacy) ADO step green but reports not updated | Pipeline ran the agent-local script, which may have drifted. Verify E:\Build_Scripts\eSHARS\Build\. |
For pipeline-level failures see Pipeline Failure.
Related
- HISD repo PR #6478 — ReportViewer Azure-readiness + tier-aware CI/CD pipelines (the go-forward CD pipeline)
- Release Process — the overall release; this runbook is the report substep
- Report Server (infrastructure) — provisioning the SSRS VM
- Report Performance monitoring
- Jira: HM-6163 — Create full documentation for reports server deployment