feat(managementservice): MgmtDeployArea — Deployer-only, scoped by the area's owning site (fail-closed on an unknown area), long-running like MgmtDeploySite (Gitea #40)
This commit is contained in:
@@ -124,6 +124,7 @@ The whole folder surface is reachable from the CLI as `template folder list|crea
|
||||
- **CreateInstance**: Create a new instance from a template.
|
||||
- **UpdateInstanceOverrides** (`SetInstanceOverrides`): Set attribute overrides on an instance. Every requested attribute is validated against the instance's template up front (unknown or locked ⇒ the whole batch is rejected before any write), then the batch is applied as **one bulk read of the existing override rows plus one commit** (WP2.5). It previously ran K independent read-modify-commit cycles — each re-reading the instance, the template's attributes and the existing overrides, then committing and writing its own audit row — so the all-or-nothing promise was only as good as the pre-validation. It is now a real single-transaction apply, with one audit row summarising the batch.
|
||||
- **MgmtDeploySite** (`SiteId`, WP2.5): Bulk-deploy every deployable instance at one site. Site scope is enforced on the SITE (the command's target); every instance the batch touches belongs to that site by construction. Same `Deployer` authority as `MgmtDeployInstance` — it is N of those, not a new class of privilege — and registered as a long-running command so the caller does not time out mid-batch. Semantics, phasing and failure policy: see `Component-DeploymentManager.md` → Bulk site deployment.
|
||||
- **MgmtDeployArea** (`AreaId`, `Force`, Gitea #40): Bulk-deploy every deployable instance in one area **subtree** (the area plus all descendant areas) with the site deploy's rules — Disabled always skipped, up-to-date skipped unless `Force`, not all-or-nothing — answering with the same `SiteDeploymentSummary`. Site scope is enforced on the area's owning site; an area that does not resolve is denied for a site-scoped caller exactly like an out-of-scope one (no existence oracle) and is a plain "not found" error for a system-wide caller. `Deployer`-only, long-running with the same overall deadline, `BULK_DEPLOY_TIMEOUT` mapping and +1 min Ask grace as `MgmtDeploySite`. See `Component-DeploymentManager.md` → Area-subtree deployment.
|
||||
- **SetInstanceAlarmOverride** / **DeleteInstanceAlarmOverride** / **ListInstanceAlarmOverrides**: Manage per-instance computed-alarm overrides.
|
||||
- **SetInstanceNativeAlarmSourceOverride** / **DeleteInstanceNativeAlarmSourceOverride**: Retarget or clear a per-instance native alarm source binding, keyed by `SourceCanonicalName` — `ConnectionNameOverride` / `SourceReferenceOverride` / `ConditionFilterOverride` each apply only when non-null. Gated to the **Deployment** role.
|
||||
- **ListInstanceNativeAlarmSourceOverrides** (`InstanceId`): List an instance's native alarm source overrides (read-only).
|
||||
@@ -151,6 +152,7 @@ The whole folder surface is reachable from the CLI as `template folder list|crea
|
||||
- **DeployInstance**: Deploy configuration to a specific instance (includes pre-deployment validation).
|
||||
- **DeployArtifacts**: Deploy system-wide artifacts (shared scripts, external system definitions, DB connections, data connections) to all sites or a specific site. The command's `SiteId` is honored (arch-review C2): a value routes to the single-site deploy path (`ArtifactDeploymentService.DeployToSiteAsync`), while `null` deploys fleet-wide (`DeployToAllSitesAsync`). Site scope is enforced — a site-scoped (non-Administrator) Deployer may only target a site within its `PermittedSiteIds`, and may **not** deploy fleet-wide (`SiteId is null` is rejected with `SiteScopeViolationException` → `ManagementUnauthorized`, since `EnforceSiteScope(null)` is a deliberate no-op); fleet-wide deployment requires a system-wide Deployer or Administrator.
|
||||
- **DeploySite** (`MgmtDeploySite`, WP2.5): Bulk-deploy every deployable instance at one site — see the Instances section above and `Component-DeploymentManager.md`.
|
||||
- **DeployArea** (`MgmtDeployArea`, Gitea #40): Bulk-deploy every deployable instance in one area subtree — see the Instances section above.
|
||||
- **GetDeploymentStatus**: Query deployment status.
|
||||
- **QueryDeployments** (`InstanceId?`, `Status?`, `Page`, `PageSize`): List deployment records. **All four arguments are honoured DB-side (WP2.5)** and the result is a `DeploymentQueryResult` envelope — `{ deployments, totalCount, page, pageSize }` over `DeploymentListRow`. The handler previously ignored `Status`, `Page` and `PageSize` entirely (the CLI had been sending them all along) and loaded the whole insert-only `DeploymentRecords` table; for a site-scoped user it additionally loaded every instance and intersected the two sets in memory. This read path also drives the opportunistic, rate-limited terminal-record retention sweep described in `Component-DeploymentManager.md`.
|
||||
|
||||
@@ -303,7 +305,7 @@ The ManagementActor receives the following services and repositories via DI (inj
|
||||
| Section | Options Class | Contents |
|
||||
|---------|--------------|----------|
|
||||
| `ScadaBridge:ManagementService` | `ManagementServiceOptions` | `CommandTimeout` (`TimeSpan`, default 30 s) — Ask timeout the HTTP endpoint applies when forwarding to the `ManagementActor`. A non-positive configured value falls back to the 30 s default. |
|
||||
| | | `LongRunningCommandTimeout` (`TimeSpan`, default 5 min) — Ask timeout applied to long-running commands (`ImportBundle`, `PreviewBundle`, `ExportBundle`, `MgmtDeployArtifacts`, `MgmtDeployInstance`, `MgmtDeploySite`); all other commands use `CommandTimeout`. A non-positive configured value falls back to the 5 min default. |
|
||||
| | | `LongRunningCommandTimeout` (`TimeSpan`, default 5 min) — Ask timeout applied to long-running commands (`ImportBundle`, `PreviewBundle`, `ExportBundle`, `MgmtDeployArtifacts`, `MgmtDeployInstance`, `MgmtDeploySite`, `MgmtDeployArea`; the two bulk deploys get one extra minute of Ask grace beyond it); all other commands use `CommandTimeout`. A non-positive configured value falls back to the 5 min default. |
|
||||
| | | `SecuredWritePendingTtl` (`TimeSpan`, default 24 h) — age after which a `Pending` secured write is transitioned to `Expired` and can no longer be approved/executed; enforced at approve/reject and swept opportunistically on list. A non-positive value disables expiry (arch-review S2). |
|
||||
| | | `SecuredWriteTerminalRetention` (`TimeSpan`, default 90 days) — age (from the row's last lifecycle instant) after which an `Approved`/`Rejected`/`Expired`/`Executed`/`Failed` secured-write row is purged on the list sweep. A non-positive value disables the purge (review 2026-10-21 08/G3). |
|
||||
| | | `SecuredWriteTerminalPurgeInterval` (`TimeSpan`, default 1 h, must be ≥ 0) — minimum interval between purge passes on one node; zero purges on every list. |
|
||||
|
||||
Reference in New Issue
Block a user