PR 7.2 — Retire legacy Galaxy projects + service
Matrix-gate satisfied (14 passed / 1 skipped / 0 failed on 2026-04-30 per docs/v2/Galaxy.ParityMatrix.md). Galaxy access flows through the in-process GalaxyDriver → mxaccessgw exclusively. Legacy infrastructure deleted in this commit: Source projects (6): - src/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host (.NET 4.8 x86 + MXAccess COM) - src/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Proxy (in-process pipe client) - src/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared (pipe-IPC contracts) - tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Tests - tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Proxy.Tests - tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared.Tests Test projects with no consumer after legacy retired (3): - tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.E2E (drove Galaxy.Host EXE) - tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.ParityTests (drove both backends) - tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.TestSupport (only consumed by Host/Proxy tests) Edits: - ZB.MOM.WW.OtOpcUa.slnx: drop nine project entries - Server.csproj: drop Driver.Galaxy.Proxy ProjectReference - Server/Program.cs: drop GalaxyProxyDriverFactoryExtensions.Register + the parallel-registration comment block; only GalaxyDriverFactoryExtensions registers now under DriverType "GalaxyMxGateway" - Install-Services.ps1: rewrite to drop OtOpcUaGalaxyHost service install + the GalaxySharedSecret/ZbConnection/GalaxyClientName/GalaxyPipeName/ AvevaServiceDependencies/MxAccessInitialConnect* parameters that only applied to the legacy host. Adds a closing note pointing operators at the separate mxaccessgw install - Uninstall-Services.ps1: keep OtOpcUaGalaxyHost in the cleanup loop so pre-7.2 rigs upgrade-uninstall cleanly, plus add OtOpcUaWonderwareHistorian - scripts/e2e/test-galaxy.ps1: deleted (drove the legacy E2E) - scripts/e2e/e2e-config.sample.json: rewrite the galaxy section comment to reflect the GalaxyMxGateway-only path - scripts/e2e/README.md: drop OtOpcUaGalaxyHost references - scripts/compliance/phase-7-compliance.ps1: drop Galaxy.Shared HistorianAlarms* checks (those contracts moved to Driver.Historian.Wonderware.Client in PR 3.4) Live state: OtOpcUaGalaxyHost Windows service stopped + removed via NSSM before this commit. The dev box's Galaxy access is now exclusively through the running mxaccessgw (separate repo). Stays out of scope for PR 7.2 (PR 7.3 territory): - CLAUDE.md Galaxy section rewrite - mxaccess_documentation.md deletion - Memory entries for the now-retired Galaxy.Host service Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,39 +1,52 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Registers the two v2 Windows services on a node: OtOpcUa (main server, net10) and
|
||||
OtOpcUaGalaxyHost (out-of-process Galaxy COM host, net48 x86).
|
||||
Registers the v2 Windows services on a node: OtOpcUa (main server, net10) and
|
||||
optionally OtOpcUaWonderwareHistorian (Wonderware historian sidecar).
|
||||
|
||||
.DESCRIPTION
|
||||
Phase 2 Stream D.2 — replaces the v1 single-service install (TopShelf-based OtOpcUa.Host).
|
||||
Installs both services with the correct service-account SID + per-process shared secret
|
||||
provisioning per `driver-stability.md §"IPC Security"`. Galaxy.Host depends on OtOpcUa
|
||||
(Galaxy.Host must be reachable when OtOpcUa starts; service dependency wiring + retry
|
||||
handled by OtOpcUa.Server NodeBootstrap).
|
||||
PR 7.2 retired the legacy out-of-process OtOpcUaGalaxyHost service alongside the
|
||||
GalaxyProxyDriver / GalaxyHost / GalaxyShared projects. Galaxy access now flows
|
||||
through the in-process GalaxyDriver talking gRPC to a separately-installed
|
||||
mxaccessgw. The mxaccessgw server runs out of its own repo
|
||||
(`c:\Users\dohertj2\Desktop\mxaccessgw\`) — see
|
||||
`docs/v2/Galaxy.ParityRig.md` for the gw setup recipe.
|
||||
|
||||
.PARAMETER InstallRoot
|
||||
Where the binaries live (typically C:\Program Files\OtOpcUa).
|
||||
|
||||
.PARAMETER ServiceAccount
|
||||
Service account SID or DOMAIN\name. Both services run under this account; the
|
||||
Galaxy.Host pipe ACL only allows this SID to connect (decision #76).
|
||||
Service account SID or DOMAIN\name. The OtOpcUa service runs under this account.
|
||||
|
||||
.PARAMETER GalaxySharedSecret
|
||||
Per-process secret passed to Galaxy.Host via env var. Generated freshly per install.
|
||||
.PARAMETER InstallWonderwareHistorian
|
||||
Gate the OtOpcUaWonderwareHistorian sidecar install. Off by default; set when
|
||||
the deployment uses the Wonderware historian for history reads + alarm-event
|
||||
persistence.
|
||||
|
||||
.PARAMETER ZbConnection
|
||||
Galaxy ZB SQL connection string (passed to Galaxy.Host via env var).
|
||||
.PARAMETER HistorianSharedSecret
|
||||
Per-process secret passed to the Historian sidecar via env var. Generated
|
||||
freshly per install when not supplied.
|
||||
|
||||
.EXAMPLE
|
||||
.\Install-Services.ps1 -InstallRoot 'C:\Program Files\OtOpcUa' -ServiceAccount 'OTOPCUA\svc-otopcua'
|
||||
|
||||
.EXAMPLE
|
||||
.\Install-Services.ps1 -InstallRoot 'C:\Program Files\OtOpcUa' -ServiceAccount 'OTOPCUA\svc-otopcua' `
|
||||
-InstallWonderwareHistorian
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)] [string]$InstallRoot,
|
||||
[Parameter(Mandatory)] [string]$ServiceAccount,
|
||||
[string]$GalaxySharedSecret,
|
||||
[string]$ZbConnection = 'Server=localhost;Database=ZB;Integrated Security=True;TrustServerCertificate=True;Encrypt=False;',
|
||||
[string]$GalaxyClientName = 'OtOpcUa-Galaxy.Host',
|
||||
[string]$GalaxyPipeName = 'OtOpcUaGalaxy'
|
||||
|
||||
# PR 3.W — Wonderware historian sidecar. Optional; gates the
|
||||
# OtOpcUaWonderwareHistorian service. Secret + pipe defaults match the server's
|
||||
# Historian:Wonderware appsettings block.
|
||||
[switch]$InstallWonderwareHistorian,
|
||||
[string]$HistorianSharedSecret,
|
||||
[string]$HistorianPipeName = 'OtOpcUaWonderwareHistorian',
|
||||
[string]$HistorianServer = 'localhost',
|
||||
[int]$HistorianPort = 32568,
|
||||
[string[]]$AvevaServiceDependencies = @('NmxSvc', 'aaBootstrap', 'aaGR')
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
@@ -42,17 +55,18 @@ if (-not (Test-Path "$InstallRoot\OtOpcUa.Server.exe")) {
|
||||
Write-Error "OtOpcUa.Server.exe not found at $InstallRoot — copy the publish output first"
|
||||
exit 1
|
||||
}
|
||||
if (-not (Test-Path "$InstallRoot\Galaxy\OtOpcUa.Driver.Galaxy.Host.exe")) {
|
||||
Write-Error "OtOpcUa.Driver.Galaxy.Host.exe not found at $InstallRoot\Galaxy — copy the publish output first"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Generate a fresh shared secret per install if not supplied. Stored in DPAPI-protected file
|
||||
# rather than the registry so the service account can read it but other local users cannot.
|
||||
if (-not $GalaxySharedSecret) {
|
||||
# Generate fresh shared secrets per install if not supplied.
|
||||
function New-SharedSecret {
|
||||
$bytes = New-Object byte[] 32
|
||||
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
|
||||
$GalaxySharedSecret = [Convert]::ToBase64String($bytes)
|
||||
return [Convert]::ToBase64String($bytes)
|
||||
}
|
||||
if ($InstallWonderwareHistorian -and -not $HistorianSharedSecret) { $HistorianSharedSecret = New-SharedSecret }
|
||||
|
||||
if ($InstallWonderwareHistorian -and -not (Test-Path "$InstallRoot\WonderwareHistorian\OtOpcUa.Driver.Historian.Wonderware.exe")) {
|
||||
Write-Error "OtOpcUa.Driver.Historian.Wonderware.exe not found at $InstallRoot\WonderwareHistorian — copy the publish output first"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Resolve the SID — the IPC ACL needs the SID, not the down-level name.
|
||||
@@ -62,41 +76,67 @@ $sid = if ($ServiceAccount.StartsWith('S-1-')) {
|
||||
(New-Object System.Security.Principal.NTAccount $ServiceAccount).Translate([System.Security.Principal.SecurityIdentifier]).Value
|
||||
}
|
||||
|
||||
# --- Install OtOpcUaGalaxyHost first (OtOpcUa starts after, depends on it being up).
|
||||
$galaxyEnv = @(
|
||||
"OTOPCUA_GALAXY_PIPE=$GalaxyPipeName"
|
||||
"OTOPCUA_ALLOWED_SID=$sid"
|
||||
"OTOPCUA_GALAXY_SECRET=$GalaxySharedSecret"
|
||||
"OTOPCUA_GALAXY_BACKEND=mxaccess"
|
||||
"OTOPCUA_GALAXY_ZB_CONN=$ZbConnection"
|
||||
"OTOPCUA_GALAXY_CLIENT_NAME=$GalaxyClientName"
|
||||
) -join "`0"
|
||||
$galaxyEnv += "`0`0"
|
||||
# --- Install OtOpcUaWonderwareHistorian (PR 3.W) — separate sidecar that exposes the
|
||||
# Wonderware Historian SDK via a named-pipe protocol consumed by the .NET 10 server.
|
||||
# Optional: only installed when -InstallWonderwareHistorian is supplied. Depends on the
|
||||
# hard AVEVA services that host the historian SDK runtime path.
|
||||
$historianDepend = $null
|
||||
if ($InstallWonderwareHistorian) {
|
||||
$historianEnv = @(
|
||||
"OTOPCUA_HISTORIAN_PIPE=$HistorianPipeName"
|
||||
"OTOPCUA_ALLOWED_SID=$sid"
|
||||
"OTOPCUA_HISTORIAN_SECRET=$HistorianSharedSecret"
|
||||
"OTOPCUA_HISTORIAN_ENABLED=true"
|
||||
"OTOPCUA_HISTORIAN_SERVER=$HistorianServer"
|
||||
"OTOPCUA_HISTORIAN_PORT=$HistorianPort"
|
||||
) -join "`0"
|
||||
$historianEnv += "`0`0"
|
||||
|
||||
Write-Host "Installing OtOpcUaGalaxyHost..."
|
||||
& sc.exe create OtOpcUaGalaxyHost binPath= "`"$InstallRoot\Galaxy\OtOpcUa.Driver.Galaxy.Host.exe`"" `
|
||||
DisplayName= 'OtOpcUa Galaxy Host (out-of-process MXAccess)' `
|
||||
start= auto `
|
||||
obj= $ServiceAccount | Out-Null
|
||||
Write-Host "Installing OtOpcUaWonderwareHistorian..."
|
||||
& sc.exe create OtOpcUaWonderwareHistorian binPath= "`"$InstallRoot\WonderwareHistorian\OtOpcUa.Driver.Historian.Wonderware.exe`"" `
|
||||
DisplayName= 'OtOpcUa Wonderware Historian Sidecar (out-of-process aahClient)' `
|
||||
start= auto `
|
||||
depend= ($AvevaServiceDependencies -join '/') `
|
||||
obj= $ServiceAccount | Out-Null
|
||||
& sc.exe config OtOpcUaWonderwareHistorian start= delayed-auto | Out-Null
|
||||
|
||||
# Set per-service environment variables via the registry — sc.exe doesn't expose them directly.
|
||||
$svcKey = "HKLM:\SYSTEM\CurrentControlSet\Services\OtOpcUaGalaxyHost"
|
||||
$envValue = $galaxyEnv.Split("`0") | Where-Object { $_ -ne '' }
|
||||
Set-ItemProperty -Path $svcKey -Name 'Environment' -Type MultiString -Value $envValue
|
||||
$svcKey = "HKLM:\SYSTEM\CurrentControlSet\Services\OtOpcUaWonderwareHistorian"
|
||||
$envValue = $historianEnv.Split("`0") | Where-Object { $_ -ne '' }
|
||||
Set-ItemProperty -Path $svcKey -Name 'Environment' -Type MultiString -Value $envValue
|
||||
|
||||
$historianDepend = 'OtOpcUaWonderwareHistorian'
|
||||
}
|
||||
|
||||
# --- Install OtOpcUa. Galaxy access flows through GalaxyDriver → mxaccessgw (gRPC),
|
||||
# so OtOpcUa no longer depends on a sibling service for Galaxy connectivity. The
|
||||
# mxaccessgw is installed separately. When the Wonderware sidecar is installed,
|
||||
# depend on it for startup ordering.
|
||||
$otOpcUaDepends = @()
|
||||
if ($historianDepend) { $otOpcUaDepends += $historianDepend }
|
||||
|
||||
# --- Install OtOpcUa (depends on Galaxy host being installed; doesn't strictly require it
|
||||
# started — OtOpcUa.Server NodeBootstrap retries on the IPC connect path).
|
||||
Write-Host "Installing OtOpcUa..."
|
||||
& sc.exe create OtOpcUa binPath= "`"$InstallRoot\OtOpcUa.Server.exe`"" `
|
||||
DisplayName= 'OtOpcUa Server' `
|
||||
start= auto `
|
||||
depend= 'OtOpcUaGalaxyHost' `
|
||||
obj= $ServiceAccount | Out-Null
|
||||
$createArgs = @(
|
||||
'create', 'OtOpcUa',
|
||||
'binPath=', "`"$InstallRoot\OtOpcUa.Server.exe`"",
|
||||
'DisplayName=', 'OtOpcUa Server',
|
||||
'start=', 'auto',
|
||||
'obj=', $ServiceAccount
|
||||
)
|
||||
if ($otOpcUaDepends.Count -gt 0) {
|
||||
$createArgs += @('depend=', ($otOpcUaDepends -join '/'))
|
||||
}
|
||||
& sc.exe @createArgs | Out-Null
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Installed. Start with:"
|
||||
Write-Host " sc.exe start OtOpcUaGalaxyHost"
|
||||
if ($InstallWonderwareHistorian) { Write-Host " sc.exe start OtOpcUaWonderwareHistorian" }
|
||||
Write-Host " sc.exe start OtOpcUa"
|
||||
if ($InstallWonderwareHistorian) {
|
||||
Write-Host ""
|
||||
Write-Host "Wonderware historian shared secret (configure into appsettings.json Historian:Wonderware:SharedSecret):"
|
||||
Write-Host " $HistorianSharedSecret"
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host "Galaxy shared secret (record this offline — required for service rebinding):"
|
||||
Write-Host " $GalaxySharedSecret"
|
||||
Write-Host "NOTE: Galaxy access flows through mxaccessgw — install + run that separately"
|
||||
Write-Host " per docs/v2/Galaxy.ParityRig.md. OtOpcUa connects via the Galaxy.Gateway"
|
||||
Write-Host " section of appsettings.json (default endpoint http://localhost:5120)."
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Stops + removes the two v2 services. Mirrors Install-Services.ps1.
|
||||
Stops + removes the v2 services. Mirrors Install-Services.ps1.
|
||||
|
||||
.DESCRIPTION
|
||||
PR 7.2 retired the legacy OtOpcUaGalaxyHost service. Galaxy access now flows
|
||||
through the in-process GalaxyDriver against a separately-installed mxaccessgw.
|
||||
OtOpcUaGalaxyHost is included in the cleanup loop below so this script safely
|
||||
removes it from any rig still carrying the legacy service from a pre-7.2
|
||||
install.
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
$ErrorActionPreference = 'Continue'
|
||||
|
||||
foreach ($svc in 'OtOpcUa', 'OtOpcUaGalaxyHost') {
|
||||
foreach ($svc in 'OtOpcUa', 'OtOpcUaWonderwareHistorian', 'OtOpcUaGalaxyHost') {
|
||||
if (Get-Service $svc -ErrorAction SilentlyContinue) {
|
||||
Write-Host "Stopping $svc..."
|
||||
Stop-Service $svc -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Reference in New Issue
Block a user