|
| 1 | +# Promote a Gateway VM from Pre-Prod to Prod |
| 2 | + |
| 3 | +> **When to use**: A hospital VM currently running the **pre-prod** gateway needs to become the **prod** gateway (same infrastructure, different environment). |
| 4 | +> **Related**: [Onboard Hospital VM](./onboard-hospital-vm.md) | [Cleanup](./cleanup.md) | [Deployment Pipeline](../deployment-pipeline.md) |
| 5 | +
|
| 6 | +--- |
| 7 | + |
| 8 | +## Why this is not just "re-point the gateway" |
| 9 | + |
| 10 | +Pre-prod and prod are separate Azure subscriptions, with separate Arc resource groups, relay namespaces (`relay-manbrs-<env>`), web-API service principals (`spn-manbrs-web-api-<env>`) and ADO pipelines. An Arc-connected machine belongs to **exactly one** subscription, and the gateway services authenticate using that machine's managed identity. A pre-prod machine identity holds the `Gateway.Access` role on the **pre-prod** API and cannot talk to prod. |
| 11 | + |
| 12 | +So you cannot promote by editing `.env`. The machine must be **disconnected from the pre-prod subscription and re-onboarded into the prod subscription** — effectively the [onboarding runbook](./onboard-hospital-vm.md) run for prod, preceded by a clean decommission of the pre-prod gateway. |
| 13 | + |
| 14 | +> One box hosts one gateway. After this procedure there is **no pre-prod gateway at this site**. If pre-prod is still needed at the site, use a different VM. |
| 15 | +
|
| 16 | +--- |
| 17 | + |
| 18 | +## Before the day (do these in advance) |
| 19 | + |
| 20 | +- [ ] **`GATEWAY_RINGS` is set for prod.** `infrastructure/environments/prod/variables.sh` must set `GATEWAY_RINGS` to include the ring the site is tagged with (for initial production installs this will typically be `ring1`). If it is unset it defaults to `ring0` and the prod deploy pipeline **silently skips** the machine. |
| 21 | +- [ ] **Prod infrastructure exists.** Confirm the prod relay namespace, `spn-manbrs-web-api-prod`, Log Analytics workspace and the prod ADO pipelines are provisioned and have had a successful infra deploy. |
| 22 | +- [ ] **Prod Manage (Rubie) is seeded.** The prod Rubie instance has the site's clinic/setting, a `Relay` record pointing at `relay-manbrs-prod` and the prod gateway, the `gateway_images` feature flag enabled, and a test appointment for the end-to-end check. |
| 23 | +- [ ] **DHCP reservation confirmed** for the VM, so the IP the modality targets cannot change between decommission and go-live. |
| 24 | +- [ ] **Modality engineer briefed** that the gateway **AE titles change** (see [Step 5](#step-5--reconfigure-the-modality-on-site)) and the modality must be reconfigured and re-tested on the day. |
| 25 | +- [ ] **Fresh prod Arc onboarding SPN secret** generated with 1-day expiry (`arc-onboarding-spn-client-secret`), shared with hospital IT before the onboarding call. |
| 26 | + |
| 27 | +--- |
| 28 | + |
| 29 | +## Step 1 — Decommission the pre-prod gateway (on the VM) |
| 30 | + |
| 31 | +Run from an **elevated PowerShell session** on the VM. First confirm you are on the right machine: |
| 32 | + |
| 33 | +```powershell |
| 34 | +hostname |
| 35 | +Get-Service Gateway-* | Format-Table Name, Status |
| 36 | +``` |
| 37 | + |
| 38 | +Then run the cleanup script, which stops and removes the services and **removes the installation directory including all pre-prod data** (`worklist.db`, `pacs.db`, `data\storage`): |
| 39 | + |
| 40 | +```powershell |
| 41 | +.\scripts\powershell\cleanup.ps1 |
| 42 | +``` |
| 43 | + |
| 44 | +**Verify**: no `Gateway-*` services remain and `C:\Program Files\NHS\ManageBreastScreeningGateway` is gone (see [Cleanup runbook — Verify](./cleanup.md)). |
| 45 | + |
| 46 | +## Step 2 — Disconnect from the pre-prod Arc subscription |
| 47 | + |
| 48 | +Still on the VM, elevated: |
| 49 | + |
| 50 | +```powershell |
| 51 | +azcmagent disconnect |
| 52 | +``` |
| 53 | + |
| 54 | +This removes the machine's registration from the pre-prod resource group. The Arc **agent stays installed** — only the registration is removed, so re-onboarding in Step 3 skips the agent install. |
| 55 | + |
| 56 | +**Verify**: `azcmagent show` reports the agent as **Disconnected**. |
| 57 | + |
| 58 | +## Step 3 — Re-onboard into prod |
| 59 | + |
| 60 | +This is [Onboarding runbook Step 2](./onboard-hospital-vm.md#step-2--run-arc-onboarding-script-on-the-gateway-vm) with **prod parameters**. The site parameters (`SiteName`, `ODSCode`, `Instance`) are unchanged, so the Arc resource name is identical — but it is now created in the prod resource group. |
| 61 | + |
| 62 | +```powershell |
| 63 | +.\arc-setup.ps1 ` |
| 64 | + -SubscriptionId "<prod-spoke-subscription-id>" ` |
| 65 | + -TenantId "<tenant-id>" ` |
| 66 | + -ResourceGroup "rg-mbsgw-prod-uks-arc-enabled-servers" ` |
| 67 | + -Location "uksouth" ` |
| 68 | + -ServicePrincipalId "<arc-onboarding-spn-client-id>" ` |
| 69 | + -ServicePrincipalSecret "<prod-arc-onboarding-spn-client-secret>" ` |
| 70 | + -SiteName "Hull-University-Teaching-Hospitals-NHS-Trust" ` |
| 71 | + -ODSCode "RWA" ` |
| 72 | + -Instance "01" ` |
| 73 | + -NHSRegion "neyh" ` |
| 74 | + -SiteType "static" ` |
| 75 | + -DeploymentRing "ring1" |
| 76 | +``` |
| 77 | + |
| 78 | +**Verify**: in the Azure portal, `rg-mbsgw-prod-uks-arc-enabled-servers` → Azure Arc machines → `gw-<...>-rwa-01` is **Connected**. |
| 79 | + |
| 80 | +## Step 4 — Provision prod and deploy the prod gateway |
| 81 | + |
| 82 | +From here, follow the onboarding runbook against **prod**: |
| 83 | + |
| 84 | +1. **Grant API access** — `make prod assign-arc-app-roles` ([Step 3](./onboard-hospital-vm.md#step-3--grant-api-access)). This assigns `Gateway.Access` on `spn-manbrs-web-api-prod` to the machine's new prod managed identity. The old pre-prod assignment is irrelevant (different identity) and is cleaned up in Step 6. |
| 85 | +2. **Provision the Hybrid Connection** — run **Deploy Arc Infrastructure - prod** ([Step 4](./onboard-hospital-vm.md#step-4--trigger-terraform-to-provision-the-hybrid-connection)). Creates `hc-gw-<...>-rwa-01` in `relay-manbrs-prod`. |
| 86 | +3. **Deploy the application** — run **Deploy Gateway - prod** with a **released** `releaseTag` (not a pre-prod build) ([Step 5](./onboard-hospital-vm.md#step-5--deploy-the-gateway-application)). This writes a fresh prod `.env` (prod relay namespace, `CLOUD_API_HOSTNAME=manage-breast-screening.nhs.uk`, prod AE titles), fully replacing the pre-prod `.env`. |
| 87 | + |
| 88 | +**Verify** (smoke test): all four services Running, and an initial heartbeat in the prod Log Analytics workspace within 5 minutes. |
| 89 | + |
| 90 | +```powershell |
| 91 | +Get-Service Gateway-PACS, Gateway-MWL, Gateway-Upload, Gateway-Relay | Select-Object Name, Status |
| 92 | +``` |
| 93 | + |
| 94 | +## Step 5 — Reconfigure the modality |
| 95 | + |
| 96 | +The gateway AE titles are environment-specific: the `.env` builder sets `MWL_AET=RUBIE_MWL_<ENV>` / `PACS_AET=RUBIE_PACS_<ENV>`, where the environment is uppercased and truncated to 3 characters if longer than 4. |
| 97 | + |
| 98 | +| Environment | MWL AE title | PACS AE title | |
| 99 | +|-------------|--------------|---------------| |
| 100 | +| pre-prod (`PREPROD` → `PRE`) | `RUBIE_MWL_PRE` | `RUBIE_PACS_PRE` | |
| 101 | +| prod (`PROD`) | `RUBIE_MWL_PROD` | `RUBIE_PACS_PROD` | |
| 102 | + |
| 103 | +The modality is currently configured to send to the **pre-prod** AE titles. The modality's MWL and PACS destinations must be updated to the **prod** AE titles. The VM IP and ports (`104` / `11112`) will typically be unchanged. |
| 104 | + |
| 105 | +**Verify**: a C-ECHO from the modality to each prod AE title succeeds. (A C-ECHO to the old `..._PRE` titles will now fail — expected.) |
| 106 | + |
| 107 | +## Step 6 — Clean up the pre-prod side (Azure) |
| 108 | + |
| 109 | +Disconnecting the machine in Step 2 leaves orphaned pre-prod resources: a disconnected Arc machine, a dangling Hybrid Connection (`hc-gw-<...>-rwa-01` in `relay-manbrs-preprod`), and a stale `Gateway.Access` role assignment. |
| 110 | + |
| 111 | +- [ ] Run **Deploy Arc Infrastructure - preprod** (Terraform) so it destroys the now-orphaned Hybrid Connection. |
| 112 | +- [ ] Remove the disconnected Arc machine resource from `rg-mbsgw-preprod-uks-arc-enabled-servers` if Terraform/Arc has not already. |
| 113 | +- [ ] Confirm the stale pre-prod app-role assignment is removed (re-running `make preprod assign-arc-app-roles` reconciles, or remove it via the portal). |
| 114 | + |
| 115 | +--- |
| 116 | + |
| 117 | +## End-to-end check |
| 118 | + |
| 119 | +With the modality reconfigured and prod Rubie seeded: |
| 120 | + |
| 121 | +1. Start the seeded test appointment in **prod** Rubie → a worklist item reaches the prod gateway. |
| 122 | +2. Query the worklist from the modality → the item appears. |
| 123 | +3. Acquire and send images → they arrive in the prod gateway PACS and are forwarded to prod Rubie. |
| 124 | +4. Confirm the images appear against the appointment in prod Rubie. |
| 125 | + |
| 126 | +--- |
| 127 | + |
| 128 | +## Gotchas |
| 129 | + |
| 130 | +| Symptom | Cause | Fix | |
| 131 | +|---------|-------|-----| |
| 132 | +| **Deploy Gateway - prod** reports "No machines found for ring1 — skipping" | `GATEWAY_RINGS` not set for prod, defaulting to `ring0` | Set `GATEWAY_RINGS="ring1"` in `prod/variables.sh` and redeploy | |
| 133 | +| Services start but fail to authenticate against the cloud API | `Gateway.Access` not assigned to the **prod** managed identity | Run `make prod assign-arc-app-roles` | |
| 134 | +| Modality C-ECHO fails after promotion | Modality still targeting `..._PRE` AE titles | Reconfigure modality to `..._PROD` (Step 5) | |
| 135 | +| Hybrid Connection not created by Terraform | Arc machine not yet **Connected** in the prod RG | Confirm Step 3 verify, then re-run the infra pipeline | |
| 136 | +| Pre-prod relay still shows connection attempts | Orphaned pre-prod HC / registration | Complete Step 6 | |
0 commit comments