refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)

Solution + 23 src projects + 26 test projects renamed; folders, csproj,
namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated.
ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated.
SQL roles/logins, LDAP domains, CLI command name, and CLI config dir
(~/.scadalink → ~/.scadabridge) also renamed.

Build green; 5 Host.Tests fail awaiting SQL login rename in next commit.
Pre-existing StaleTagMonitor timing flakes unchanged.

Rename script committed at tools/rename-to-scadabridge.sh.
This commit is contained in:
Joseph Doherty
2026-05-28 09:37:45 -04:00
parent 6d87ee3c3b
commit 7b0b9c7365
1531 changed files with 11180 additions and 11054 deletions
+21 -21
View File
@@ -3,24 +3,24 @@ FROM mcr.microsoft.com/dotnet/sdk:10.0 AS restore
WORKDIR /src
# Copy all .csproj files first (rarely change) for restore layer caching
COPY src/ScadaLink.Commons/ScadaLink.Commons.csproj src/ScadaLink.Commons/
COPY src/ScadaLink.Host/ScadaLink.Host.csproj src/ScadaLink.Host/
COPY src/ScadaLink.TemplateEngine/ScadaLink.TemplateEngine.csproj src/ScadaLink.TemplateEngine/
COPY src/ScadaLink.DeploymentManager/ScadaLink.DeploymentManager.csproj src/ScadaLink.DeploymentManager/
COPY src/ScadaLink.SiteRuntime/ScadaLink.SiteRuntime.csproj src/ScadaLink.SiteRuntime/
COPY src/ScadaLink.DataConnectionLayer/ScadaLink.DataConnectionLayer.csproj src/ScadaLink.DataConnectionLayer/
COPY src/ScadaLink.Communication/ScadaLink.Communication.csproj src/ScadaLink.Communication/
COPY src/ScadaLink.StoreAndForward/ScadaLink.StoreAndForward.csproj src/ScadaLink.StoreAndForward/
COPY src/ScadaLink.ExternalSystemGateway/ScadaLink.ExternalSystemGateway.csproj src/ScadaLink.ExternalSystemGateway/
COPY src/ScadaLink.NotificationService/ScadaLink.NotificationService.csproj src/ScadaLink.NotificationService/
COPY src/ScadaLink.CentralUI/ScadaLink.CentralUI.csproj src/ScadaLink.CentralUI/
COPY src/ScadaLink.Security/ScadaLink.Security.csproj src/ScadaLink.Security/
COPY src/ScadaLink.HealthMonitoring/ScadaLink.HealthMonitoring.csproj src/ScadaLink.HealthMonitoring/
COPY src/ScadaLink.SiteEventLogging/ScadaLink.SiteEventLogging.csproj src/ScadaLink.SiteEventLogging/
COPY src/ScadaLink.ClusterInfrastructure/ScadaLink.ClusterInfrastructure.csproj src/ScadaLink.ClusterInfrastructure/
COPY src/ScadaLink.InboundAPI/ScadaLink.InboundAPI.csproj src/ScadaLink.InboundAPI/
COPY src/ScadaLink.ConfigurationDatabase/ScadaLink.ConfigurationDatabase.csproj src/ScadaLink.ConfigurationDatabase/
COPY src/ScadaLink.ManagementService/ScadaLink.ManagementService.csproj src/ScadaLink.ManagementService/
COPY src/ZB.MOM.WW.ScadaBridge.Commons/ZB.MOM.WW.ScadaBridge.Commons.csproj src/ZB.MOM.WW.ScadaBridge.Commons/
COPY src/ZB.MOM.WW.ScadaBridge.Host/ZB.MOM.WW.ScadaBridge.Host.csproj src/ZB.MOM.WW.ScadaBridge.Host/
COPY src/ZB.MOM.WW.ScadaBridge.TemplateEngine/ZB.MOM.WW.ScadaBridge.TemplateEngine.csproj src/ZB.MOM.WW.ScadaBridge.TemplateEngine/
COPY src/ZB.MOM.WW.ScadaBridge.DeploymentManager/ZB.MOM.WW.ScadaBridge.DeploymentManager.csproj src/ZB.MOM.WW.ScadaBridge.DeploymentManager/
COPY src/ZB.MOM.WW.ScadaBridge.SiteRuntime/ZB.MOM.WW.ScadaBridge.SiteRuntime.csproj src/ZB.MOM.WW.ScadaBridge.SiteRuntime/
COPY src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.csproj src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/
COPY src/ZB.MOM.WW.ScadaBridge.Communication/ZB.MOM.WW.ScadaBridge.Communication.csproj src/ZB.MOM.WW.ScadaBridge.Communication/
COPY src/ZB.MOM.WW.ScadaBridge.StoreAndForward/ZB.MOM.WW.ScadaBridge.StoreAndForward.csproj src/ZB.MOM.WW.ScadaBridge.StoreAndForward/
COPY src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway.csproj src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/
COPY src/ZB.MOM.WW.ScadaBridge.NotificationService/ZB.MOM.WW.ScadaBridge.NotificationService.csproj src/ZB.MOM.WW.ScadaBridge.NotificationService/
COPY src/ZB.MOM.WW.ScadaBridge.CentralUI/ZB.MOM.WW.ScadaBridge.CentralUI.csproj src/ZB.MOM.WW.ScadaBridge.CentralUI/
COPY src/ZB.MOM.WW.ScadaBridge.Security/ZB.MOM.WW.ScadaBridge.Security.csproj src/ZB.MOM.WW.ScadaBridge.Security/
COPY src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/ZB.MOM.WW.ScadaBridge.HealthMonitoring.csproj src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/
COPY src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/ZB.MOM.WW.ScadaBridge.SiteEventLogging.csproj src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/
COPY src/ZB.MOM.WW.ScadaBridge.ClusterInfrastructure/ZB.MOM.WW.ScadaBridge.ClusterInfrastructure.csproj src/ZB.MOM.WW.ScadaBridge.ClusterInfrastructure/
COPY src/ZB.MOM.WW.ScadaBridge.InboundAPI/ZB.MOM.WW.ScadaBridge.InboundAPI.csproj src/ZB.MOM.WW.ScadaBridge.InboundAPI/
COPY src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.csproj src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/
COPY src/ZB.MOM.WW.ScadaBridge.ManagementService/ZB.MOM.WW.ScadaBridge.ManagementService.csproj src/ZB.MOM.WW.ScadaBridge.ManagementService/
# Central Package Management: every .csproj declares versionless PackageReferences
# and the versions live in Directory.Packages.props. It must be present (above the
@@ -29,12 +29,12 @@ COPY Directory.Packages.props ./
# Restore NuGet packages via Host project (follows ProjectReferences to all dependencies)
# This layer is cached until any .csproj changes — source-only changes skip restore entirely
RUN dotnet restore src/ScadaLink.Host/ScadaLink.Host.csproj
RUN dotnet restore src/ZB.MOM.WW.ScadaBridge.Host/ZB.MOM.WW.ScadaBridge.Host.csproj
# Stage 2: Build + Publish
FROM restore AS build
COPY src/ src/
RUN dotnet publish src/ScadaLink.Host/ScadaLink.Host.csproj \
RUN dotnet publish src/ZB.MOM.WW.ScadaBridge.Host/ZB.MOM.WW.ScadaBridge.Host.csproj \
-c Release -o /app/publish
# Stage 3: Runtime (minimal image, no SDK)
@@ -48,4 +48,4 @@ COPY --from=build /app/publish .
EXPOSE 5000 8081 8082
ENTRYPOINT ["dotnet", "ScadaLink.Host.dll"]
ENTRYPOINT ["dotnet", "ZB.MOM.WW.ScadaBridge.Host.dll"]
+35 -35
View File
@@ -1,6 +1,6 @@
# ScadaLink Docker Infrastructure
# ScadaBridge Docker Infrastructure
Local Docker deployment of the full ScadaLink cluster topology: a 2-node central cluster and three 2-node site clusters.
Local Docker deployment of the full ScadaBridge cluster topology: a 2-node central cluster and three 2-node site clusters.
## Cluster Topology
@@ -54,15 +54,15 @@ Each site cluster runs Site Runtime, Data Connection Layer, Store-and-Forward, a
| Node | Container Name | Host Web Port | Host Akka Port | Host gRPC Port | Internal Ports |
|------|---------------|---------------|----------------|----------------|----------------|
| Traefik LB | `scadalink-traefik` | 9000 | — | — | 80 (proxy), 8080 (dashboard) |
| Central A | `scadalink-central-a` | 9001 | 9011 | — | 5000 (web), 8081 (Akka) |
| Central B | `scadalink-central-b` | 9002 | 9012 | — | 5000 (web), 8081 (Akka) |
| Site-A A | `scadalink-site-a-a` | — | 9021 | 9023 | 8082 (Akka), 8083 (gRPC) |
| Site-A B | `scadalink-site-a-b` | — | 9022 | 9024 | 8082 (Akka), 8083 (gRPC) |
| Site-B A | `scadalink-site-b-a` | — | 9031 | 9033 | 8082 (Akka), 8083 (gRPC) |
| Site-B B | `scadalink-site-b-b` | — | 9032 | 9034 | 8082 (Akka), 8083 (gRPC) |
| Site-C A | `scadalink-site-c-a` | — | 9041 | 9043 | 8082 (Akka), 8083 (gRPC) |
| Site-C B | `scadalink-site-c-b` | — | 9042 | 9044 | 8082 (Akka), 8083 (gRPC) |
| Traefik LB | `scadabridge-traefik` | 9000 | — | — | 80 (proxy), 8080 (dashboard) |
| Central A | `scadabridge-central-a` | 9001 | 9011 | — | 5000 (web), 8081 (Akka) |
| Central B | `scadabridge-central-b` | 9002 | 9012 | — | 5000 (web), 8081 (Akka) |
| Site-A A | `scadabridge-site-a-a` | — | 9021 | 9023 | 8082 (Akka), 8083 (gRPC) |
| Site-A B | `scadabridge-site-a-b` | — | 9022 | 9024 | 8082 (Akka), 8083 (gRPC) |
| Site-B A | `scadabridge-site-b-a` | — | 9031 | 9033 | 8082 (Akka), 8083 (gRPC) |
| Site-B B | `scadabridge-site-b-b` | — | 9032 | 9034 | 8082 (Akka), 8083 (gRPC) |
| Site-C A | `scadabridge-site-c-a` | — | 9041 | 9043 | 8082 (Akka), 8083 (gRPC) |
| Site-C B | `scadabridge-site-c-b` | — | 9042 | 9044 | 8082 (Akka), 8083 (gRPC) |
Port block pattern: `90X1`/`90X2` (Akka), `90X3`/`90X4` (gRPC) where X = 0 (central), 2 (site-a), 3 (site-b), 4 (site-c). gRPC streaming ports are used by central nodes to subscribe to real-time site data streams.
@@ -70,13 +70,13 @@ Port block pattern: `90X1`/`90X2` (Akka), `90X3`/`90X4` (gRPC) where X = 0 (cent
| Service | Container Name | Host Port | Purpose |
|---------|---------------|-----------|---------|
| MS SQL 2022 | `scadalink-mssql` | 1433 | Configuration and machine data databases |
| LDAP (GLAuth) | `scadalink-ldap` | 3893 | Authentication with test users |
| SMTP (Mailpit) | `scadalink-smtp` | 1025 / 8025 | Email capture (SMTP / web UI) |
| OPC UA | `scadalink-opcua` | 50000 / 8080 | Simulated OPC UA server (protocol / web UI) |
| REST API | `scadalink-restapi` | 5200 | External REST API for integration testing |
| MS SQL 2022 | `scadabridge-mssql` | 1433 | Configuration and machine data databases |
| LDAP (GLAuth) | `scadabridge-ldap` | 3893 | Authentication with test users |
| SMTP (Mailpit) | `scadabridge-smtp` | 1025 / 8025 | Email capture (SMTP / web UI) |
| OPC UA | `scadabridge-opcua` | 50000 / 8080 | Simulated OPC UA server (protocol / web UI) |
| REST API | `scadabridge-restapi` | 5200 | External REST API for integration testing |
All containers communicate over the shared `scadalink-net` Docker bridge network using container names as hostnames.
All containers communicate over the shared `scadabridge-net` Docker bridge network using container names as hostnames.
## Directory Structure
@@ -130,7 +130,7 @@ Start infrastructure services first, then build and deploy the application:
# 1. Start test infrastructure (MS SQL, LDAP, SMTP, OPC UA)
cd infra && docker compose up -d && cd ..
# 2. Build and deploy all 8 ScadaLink nodes
# 2. Build and deploy all 8 ScadaBridge nodes
docker/deploy.sh
# 3. Seed test sites (first-time only, after cluster is healthy)
@@ -167,7 +167,7 @@ cd infra && docker compose down && cd ..
docker compose -f docker/docker-compose.yml logs -f
# Single node
docker logs -f scadalink-central-a
docker logs -f scadabridge-central-a
# Filter by site cluster
docker compose -f docker/docker-compose.yml logs -f site-a-a site-a-b
@@ -181,7 +181,7 @@ ls docker/central-node-a/logs/
### Restart a Single Node
```bash
docker restart scadalink-central-a
docker restart scadabridge-central-a
```
### Check Cluster Health
@@ -199,7 +199,7 @@ curl -s http://localhost:9002/health/ready | python3 -m json.tool
The CLI connects to the Central Host's HTTP management API via the Traefik load balancer at `http://localhost:9000`, which routes to the active central node:
```bash
dotnet run --project src/ScadaLink.CLI -- \
dotnet run --project src/ZB.MOM.WW.ScadaBridge.CLI -- \
--url http://localhost:9000 \
--username multi-role --password password \
template list
@@ -209,7 +209,7 @@ Direct access to individual nodes is also available at `http://localhost:9001` (
> **Note:** The `multi-role` test user has Admin, Design, and Deployment roles. The `admin` user only has the Admin role and cannot perform design or deployment operations. See `infra/glauth/config.toml` for all test users and their group memberships.
A recommended `~/.scadalink/config.json` for the Docker test environment:
A recommended `~/.scadabridge/config.json` for the Docker test environment:
```json
{
@@ -220,7 +220,7 @@ A recommended `~/.scadalink/config.json` for the Docker test environment:
With this config file in place, the URL is automatic:
```bash
dotnet run --project src/ScadaLink.CLI -- \
dotnet run --project src/ZB.MOM.WW.ScadaBridge.CLI -- \
--username multi-role --password password \
template list
```
@@ -232,19 +232,19 @@ Remove SQLite databases to reset site state (deployed configs, S&F buffers):
```bash
# Single site
rm -rf docker/site-a-node-a/data docker/site-a-node-b/data
docker restart scadalink-site-a-a scadalink-site-a-b
docker restart scadabridge-site-a-a scadabridge-site-a-b
# All sites
rm -rf docker/site-*/data
docker restart scadalink-site-a-a scadalink-site-a-b \
scadalink-site-b-a scadalink-site-b-b \
scadalink-site-c-a scadalink-site-c-b
docker restart scadabridge-site-a-a scadabridge-site-a-b \
scadabridge-site-b-a scadabridge-site-b-b \
scadabridge-site-c-a scadabridge-site-c-b
```
### Rebuild Image From Scratch (no cache)
```bash
docker build --no-cache -t scadalink:latest -f docker/Dockerfile .
docker build --no-cache -t scadabridge:latest -f docker/Dockerfile .
```
## Build Cache
@@ -274,31 +274,31 @@ All test passwords are `password`. See `infra/glauth/config.toml` for the full l
```bash
# Stop the active central node
docker stop scadalink-central-a
docker stop scadabridge-central-a
# Verify central-b takes over (check logs for leader election)
docker logs -f scadalink-central-b
docker logs -f scadabridge-central-b
# Access UI on standby node
open http://localhost:9002
# Restore the original node
docker start scadalink-central-a
docker start scadabridge-central-a
```
### Site Failover
```bash
# Stop the active site-a node
docker stop scadalink-site-a-a
docker stop scadabridge-site-a-a
# Verify site-a-b takes over singleton (DeploymentManager)
docker logs -f scadalink-site-a-b
docker logs -f scadabridge-site-a-b
# Restore
docker start scadalink-site-a-a
docker start scadabridge-site-a-a
```
Same pattern applies for site-b (`scadalink-site-b-a`/`scadalink-site-b-b`) and site-c (`scadalink-site-c-a`/`scadalink-site-c-b`).
Same pattern applies for site-b (`scadabridge-site-b-a`/`scadabridge-site-b-b`) and site-c (`scadabridge-site-c-a`/`scadabridge-site-c-b`).
Failover takes approximately 25 seconds (2s heartbeat + 10s detection threshold + 15s stable-after for split-brain resolver).
+7 -7
View File
@@ -4,19 +4,19 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
echo "=== ScadaLink Docker Build ==="
echo "=== ScadaBridge Docker Build ==="
# Ensure the shared network exists
if ! docker network inspect scadalink-net >/dev/null 2>&1; then
echo "Creating scadalink-net network..."
docker network create scadalink-net
if ! docker network inspect scadabridge-net >/dev/null 2>&1; then
echo "Creating scadabridge-net network..."
docker network create scadabridge-net
fi
# Build from repo root (so COPY paths in Dockerfile resolve correctly)
echo "Building scadalink:latest image..."
echo "Building scadabridge:latest image..."
docker build \
-t scadalink:latest \
-t scadabridge:latest \
-f "$SCRIPT_DIR/Dockerfile" \
"$REPO_ROOT"
echo "Build complete: scadalink:latest"
echo "Build complete: scadabridge:latest"
+11 -11
View File
@@ -1,15 +1,15 @@
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Central",
"NodeName": "central-a",
"NodeHostname": "scadalink-central-a",
"NodeHostname": "scadabridge-central-a",
"RemotingPort": 8081
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@scadalink-central-a:8081",
"akka.tcp://scadalink@scadalink-central-b:8081"
"akka.tcp://scadabridge@scadabridge-central-a:8081",
"akka.tcp://scadabridge@scadabridge-central-b:8081"
],
"SplitBrainResolverStrategy": "keep-oldest",
"StableAfter": "00:00:15",
@@ -18,18 +18,18 @@
"MinNrOfMembers": 1
},
"Database": {
"ConfigurationDb": "Server=scadalink-mssql,1433;Database=ScadaLinkConfig;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true",
"MachineDataDb": "Server=scadalink-mssql,1433;Database=ScadaLinkMachineData;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true"
"ConfigurationDb": "Server=scadabridge-mssql,1433;Database=ScadaBridgeConfig;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true",
"MachineDataDb": "Server=scadabridge-mssql,1433;Database=ScadaBridgeMachineData;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
},
"Security": {
"LdapServer": "scadalink-ldap",
"LdapServer": "scadabridge-ldap",
"LdapPort": 3893,
"LdapUseTls": false,
"AllowInsecureLdap": true,
"LdapSearchBase": "dc=scadalink,dc=local",
"LdapServiceAccountDn": "cn=admin,dc=scadalink,dc=local",
"LdapSearchBase": "dc=scadabridge,dc=local",
"LdapServiceAccountDn": "cn=admin,dc=scadabridge,dc=local",
"LdapServiceAccountPassword": "password",
"JwtSigningKey": "scadalink-dev-jwt-signing-key-must-be-at-least-32-characters-long",
"JwtSigningKey": "scadabridge-dev-jwt-signing-key-must-be-at-least-32-characters-long",
"JwtExpiryMinutes": 15,
"IdleTimeoutMinutes": 30,
"RequireHttpsCookie": false
@@ -49,7 +49,7 @@
"DefaultMethodTimeout": "00:00:30"
},
"Notification": {
"SmtpServer": "scadalink-smtp",
"SmtpServer": "scadabridge-smtp",
"SmtpPort": 1025,
"AuthMode": "None",
"FromAddress": "scada-notifications@company.com"
+11 -11
View File
@@ -1,15 +1,15 @@
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Central",
"NodeName": "central-b",
"NodeHostname": "scadalink-central-b",
"NodeHostname": "scadabridge-central-b",
"RemotingPort": 8081
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@scadalink-central-a:8081",
"akka.tcp://scadalink@scadalink-central-b:8081"
"akka.tcp://scadabridge@scadabridge-central-a:8081",
"akka.tcp://scadabridge@scadabridge-central-b:8081"
],
"SplitBrainResolverStrategy": "keep-oldest",
"StableAfter": "00:00:15",
@@ -18,18 +18,18 @@
"MinNrOfMembers": 1
},
"Database": {
"ConfigurationDb": "Server=scadalink-mssql,1433;Database=ScadaLinkConfig;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true",
"MachineDataDb": "Server=scadalink-mssql,1433;Database=ScadaLinkMachineData;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true"
"ConfigurationDb": "Server=scadabridge-mssql,1433;Database=ScadaBridgeConfig;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true",
"MachineDataDb": "Server=scadabridge-mssql,1433;Database=ScadaBridgeMachineData;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
},
"Security": {
"LdapServer": "scadalink-ldap",
"LdapServer": "scadabridge-ldap",
"LdapPort": 3893,
"LdapUseTls": false,
"AllowInsecureLdap": true,
"LdapSearchBase": "dc=scadalink,dc=local",
"LdapServiceAccountDn": "cn=admin,dc=scadalink,dc=local",
"LdapSearchBase": "dc=scadabridge,dc=local",
"LdapServiceAccountDn": "cn=admin,dc=scadabridge,dc=local",
"LdapServiceAccountPassword": "password",
"JwtSigningKey": "scadalink-dev-jwt-signing-key-must-be-at-least-32-characters-long",
"JwtSigningKey": "scadabridge-dev-jwt-signing-key-must-be-at-least-32-characters-long",
"JwtExpiryMinutes": 15,
"IdleTimeoutMinutes": 30,
"RequireHttpsCookie": false
@@ -49,7 +49,7 @@
"DefaultMethodTimeout": "00:00:30"
},
"Notification": {
"SmtpServer": "scadalink-smtp",
"SmtpServer": "scadabridge-smtp",
"SmtpPort": 1025,
"AuthMode": "None",
"FromAddress": "scada-notifications@company.com"
+1 -1
View File
@@ -3,7 +3,7 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo "=== ScadaLink Docker Deploy ==="
echo "=== ScadaBridge Docker Deploy ==="
# Build image (creates network if needed)
"$SCRIPT_DIR/build.sh"
+27 -27
View File
@@ -1,7 +1,7 @@
services:
central-a:
image: scadalink:latest
container_name: scadalink-central-a
image: scadabridge:latest
container_name: scadabridge-central-a
environment:
SCADALINK_CONFIG: Central
ASPNETCORE_ENVIRONMENT: Development
@@ -13,12 +13,12 @@ services:
- ./central-node-a/appsettings.Central.json:/app/appsettings.Central.json:ro
- ./central-node-a/logs:/app/logs
networks:
- scadalink-net
- scadabridge-net
restart: unless-stopped
central-b:
image: scadalink:latest
container_name: scadalink-central-b
image: scadabridge:latest
container_name: scadabridge-central-b
environment:
SCADALINK_CONFIG: Central
ASPNETCORE_ENVIRONMENT: Development
@@ -30,12 +30,12 @@ services:
- ./central-node-b/appsettings.Central.json:/app/appsettings.Central.json:ro
- ./central-node-b/logs:/app/logs
networks:
- scadalink-net
- scadabridge-net
restart: unless-stopped
site-a-a:
image: scadalink:latest
container_name: scadalink-site-a-a
image: scadabridge:latest
container_name: scadabridge-site-a-a
environment:
SCADALINK_CONFIG: Site
ports:
@@ -46,12 +46,12 @@ services:
- ./site-a-node-a/data:/app/data
- ./site-a-node-a/logs:/app/logs
networks:
- scadalink-net
- scadabridge-net
restart: unless-stopped
site-a-b:
image: scadalink:latest
container_name: scadalink-site-a-b
image: scadabridge:latest
container_name: scadabridge-site-a-b
environment:
SCADALINK_CONFIG: Site
ports:
@@ -62,12 +62,12 @@ services:
- ./site-a-node-b/data:/app/data
- ./site-a-node-b/logs:/app/logs
networks:
- scadalink-net
- scadabridge-net
restart: unless-stopped
site-b-a:
image: scadalink:latest
container_name: scadalink-site-b-a
image: scadabridge:latest
container_name: scadabridge-site-b-a
environment:
SCADALINK_CONFIG: Site
ports:
@@ -78,12 +78,12 @@ services:
- ./site-b-node-a/data:/app/data
- ./site-b-node-a/logs:/app/logs
networks:
- scadalink-net
- scadabridge-net
restart: unless-stopped
site-b-b:
image: scadalink:latest
container_name: scadalink-site-b-b
image: scadabridge:latest
container_name: scadabridge-site-b-b
environment:
SCADALINK_CONFIG: Site
ports:
@@ -94,12 +94,12 @@ services:
- ./site-b-node-b/data:/app/data
- ./site-b-node-b/logs:/app/logs
networks:
- scadalink-net
- scadabridge-net
restart: unless-stopped
site-c-a:
image: scadalink:latest
container_name: scadalink-site-c-a
image: scadabridge:latest
container_name: scadabridge-site-c-a
environment:
SCADALINK_CONFIG: Site
ports:
@@ -110,12 +110,12 @@ services:
- ./site-c-node-a/data:/app/data
- ./site-c-node-a/logs:/app/logs
networks:
- scadalink-net
- scadabridge-net
restart: unless-stopped
site-c-b:
image: scadalink:latest
container_name: scadalink-site-c-b
image: scadabridge:latest
container_name: scadabridge-site-c-b
environment:
SCADALINK_CONFIG: Site
ports:
@@ -126,12 +126,12 @@ services:
- ./site-c-node-b/data:/app/data
- ./site-c-node-b/logs:/app/logs
networks:
- scadalink-net
- scadabridge-net
restart: unless-stopped
traefik:
image: traefik:v3.4
container_name: scadalink-traefik
container_name: scadabridge-traefik
ports:
- "9000:80" # Central load-balanced entrypoint
- "8180:8080" # Traefik dashboard
@@ -139,9 +139,9 @@ services:
- ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- ./traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
networks:
- scadalink-net
- scadabridge-net
restart: unless-stopped
networks:
scadalink-net:
scadabridge-net:
external: true
+5 -5
View File
@@ -4,7 +4,7 @@
#
# Background: protoc (linux/arm64) segfaults inside our Docker build container
# (Grpc.Tools 2.71.0). As a workaround the generated Sitestream.cs +
# SitestreamGrpc.cs are checked into src/ScadaLink.Communication/SiteStreamGrpc/
# SitestreamGrpc.cs are checked into src/ZB.MOM.WW.ScadaBridge.Communication/SiteStreamGrpc/
# and the Protobuf ItemGroup in the .csproj is commented out — Docker just
# compiles the checked-in C# files.
#
@@ -23,8 +23,8 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
COMM_DIR="$REPO_ROOT/src/ScadaLink.Communication"
CSPROJ="$COMM_DIR/ScadaLink.Communication.csproj"
COMM_DIR="$REPO_ROOT/src/ZB.MOM.WW.ScadaBridge.Communication"
CSPROJ="$COMM_DIR/ZB.MOM.WW.ScadaBridge.Communication.csproj"
GEN_DIR="$COMM_DIR/SiteStreamGrpc"
echo "=== Regenerating gRPC files from sitestream.proto ==="
@@ -88,5 +88,5 @@ trap - ERR
echo ""
echo "Done. Review and commit:"
echo " git diff src/ScadaLink.Communication/Protos/sitestream.proto"
echo " git diff src/ScadaLink.Communication/SiteStreamGrpc/"
echo " git diff src/ZB.MOM.WW.ScadaBridge.Communication/Protos/sitestream.proto"
echo " git diff src/ZB.MOM.WW.ScadaBridge.Communication/SiteStreamGrpc/"
+14 -14
View File
@@ -14,11 +14,11 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
CLI="dotnet run --project $PROJECT_ROOT/src/ScadaLink.CLI --"
CLI="dotnet run --project $PROJECT_ROOT/src/ZB.MOM.WW.ScadaBridge.CLI --"
AUTH="--username multi-role --password password"
URL="--url http://localhost:9000"
echo "=== Seeding ScadaLink Sites ==="
echo "=== Seeding ScadaBridge Sites ==="
echo ""
echo "Creating Site-A (Test Plant A)..."
@@ -26,10 +26,10 @@ $CLI $URL $AUTH site create \
--name "Test Plant A" \
--identifier "site-a" \
--description "Test site A - two-node cluster" \
--node-a-address "akka.tcp://scadalink@scadalink-site-a-a:8082" \
--node-b-address "akka.tcp://scadalink@scadalink-site-a-b:8082" \
--grpc-node-a-address "http://scadalink-site-a-a:8083" \
--grpc-node-b-address "http://scadalink-site-a-b:8083" \
--node-a-address "akka.tcp://scadabridge@scadabridge-site-a-a:8082" \
--node-b-address "akka.tcp://scadabridge@scadabridge-site-a-b:8082" \
--grpc-node-a-address "http://scadabridge-site-a-a:8083" \
--grpc-node-b-address "http://scadabridge-site-a-b:8083" \
|| echo " (Site-A may already exist)"
echo ""
@@ -38,10 +38,10 @@ $CLI $URL $AUTH site create \
--name "Test Plant B" \
--identifier "site-b" \
--description "Test site B - two-node cluster" \
--node-a-address "akka.tcp://scadalink@scadalink-site-b-a:8082" \
--node-b-address "akka.tcp://scadalink@scadalink-site-b-b:8082" \
--grpc-node-a-address "http://scadalink-site-b-a:8083" \
--grpc-node-b-address "http://scadalink-site-b-b:8083" \
--node-a-address "akka.tcp://scadabridge@scadabridge-site-b-a:8082" \
--node-b-address "akka.tcp://scadabridge@scadabridge-site-b-b:8082" \
--grpc-node-a-address "http://scadabridge-site-b-a:8083" \
--grpc-node-b-address "http://scadabridge-site-b-b:8083" \
|| echo " (Site-B may already exist)"
echo ""
@@ -50,10 +50,10 @@ $CLI $URL $AUTH site create \
--name "Test Plant C" \
--identifier "site-c" \
--description "Test site C - two-node cluster" \
--node-a-address "akka.tcp://scadalink@scadalink-site-c-a:8082" \
--node-b-address "akka.tcp://scadalink@scadalink-site-c-b:8082" \
--grpc-node-a-address "http://scadalink-site-c-a:8083" \
--grpc-node-b-address "http://scadalink-site-c-b:8083" \
--node-a-address "akka.tcp://scadabridge@scadabridge-site-c-a:8082" \
--node-b-address "akka.tcp://scadabridge@scadabridge-site-c-b:8082" \
--grpc-node-a-address "http://scadabridge-site-c-a:8083" \
--grpc-node-b-address "http://scadabridge-site-c-b:8083" \
|| echo " (Site-C may already exist)"
echo ""
+7 -7
View File
@@ -1,17 +1,17 @@
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Site",
"NodeName": "node-a",
"NodeHostname": "scadalink-site-a-a",
"NodeHostname": "scadabridge-site-a-a",
"SiteId": "site-a",
"RemotingPort": 8082,
"GrpcPort": 8083
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@scadalink-site-a-a:8082",
"akka.tcp://scadalink@scadalink-site-a-b:8082"
"akka.tcp://scadabridge@scadabridge-site-a-a:8082",
"akka.tcp://scadabridge@scadabridge-site-a-b:8082"
],
"SplitBrainResolverStrategy": "keep-oldest",
"StableAfter": "00:00:15",
@@ -20,7 +20,7 @@
"MinNrOfMembers": 1
},
"Database": {
"SiteDbPath": "/app/data/scadalink.db"
"SiteDbPath": "/app/data/scadabridge.db"
},
"DataConnection": {
"ReconnectInterval": "00:00:05",
@@ -33,8 +33,8 @@
},
"Communication": {
"CentralContactPoints": [
"akka.tcp://scadalink@scadalink-central-a:8081",
"akka.tcp://scadalink@scadalink-central-b:8081"
"akka.tcp://scadabridge@scadabridge-central-a:8081",
"akka.tcp://scadabridge@scadabridge-central-b:8081"
],
"DeploymentTimeout": "00:02:00",
"LifecycleTimeout": "00:00:30",
+7 -7
View File
@@ -1,17 +1,17 @@
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Site",
"NodeName": "node-b",
"NodeHostname": "scadalink-site-a-b",
"NodeHostname": "scadabridge-site-a-b",
"SiteId": "site-a",
"RemotingPort": 8082,
"GrpcPort": 8083
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@scadalink-site-a-a:8082",
"akka.tcp://scadalink@scadalink-site-a-b:8082"
"akka.tcp://scadabridge@scadabridge-site-a-a:8082",
"akka.tcp://scadabridge@scadabridge-site-a-b:8082"
],
"SplitBrainResolverStrategy": "keep-oldest",
"StableAfter": "00:00:15",
@@ -20,7 +20,7 @@
"MinNrOfMembers": 1
},
"Database": {
"SiteDbPath": "/app/data/scadalink.db"
"SiteDbPath": "/app/data/scadabridge.db"
},
"DataConnection": {
"ReconnectInterval": "00:00:05",
@@ -33,8 +33,8 @@
},
"Communication": {
"CentralContactPoints": [
"akka.tcp://scadalink@scadalink-central-a:8081",
"akka.tcp://scadalink@scadalink-central-b:8081"
"akka.tcp://scadabridge@scadabridge-central-a:8081",
"akka.tcp://scadabridge@scadabridge-central-b:8081"
],
"DeploymentTimeout": "00:02:00",
"LifecycleTimeout": "00:00:30",
+7 -7
View File
@@ -1,17 +1,17 @@
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Site",
"NodeName": "node-a",
"NodeHostname": "scadalink-site-b-a",
"NodeHostname": "scadabridge-site-b-a",
"SiteId": "site-b",
"RemotingPort": 8082,
"GrpcPort": 8083
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@scadalink-site-b-a:8082",
"akka.tcp://scadalink@scadalink-site-b-b:8082"
"akka.tcp://scadabridge@scadabridge-site-b-a:8082",
"akka.tcp://scadabridge@scadabridge-site-b-b:8082"
],
"SplitBrainResolverStrategy": "keep-oldest",
"StableAfter": "00:00:15",
@@ -20,7 +20,7 @@
"MinNrOfMembers": 1
},
"Database": {
"SiteDbPath": "/app/data/scadalink.db"
"SiteDbPath": "/app/data/scadabridge.db"
},
"DataConnection": {
"ReconnectInterval": "00:00:05",
@@ -33,8 +33,8 @@
},
"Communication": {
"CentralContactPoints": [
"akka.tcp://scadalink@scadalink-central-a:8081",
"akka.tcp://scadalink@scadalink-central-b:8081"
"akka.tcp://scadabridge@scadabridge-central-a:8081",
"akka.tcp://scadabridge@scadabridge-central-b:8081"
],
"DeploymentTimeout": "00:02:00",
"LifecycleTimeout": "00:00:30",
+7 -7
View File
@@ -1,17 +1,17 @@
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Site",
"NodeName": "node-b",
"NodeHostname": "scadalink-site-b-b",
"NodeHostname": "scadabridge-site-b-b",
"SiteId": "site-b",
"RemotingPort": 8082,
"GrpcPort": 8083
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@scadalink-site-b-a:8082",
"akka.tcp://scadalink@scadalink-site-b-b:8082"
"akka.tcp://scadabridge@scadabridge-site-b-a:8082",
"akka.tcp://scadabridge@scadabridge-site-b-b:8082"
],
"SplitBrainResolverStrategy": "keep-oldest",
"StableAfter": "00:00:15",
@@ -20,7 +20,7 @@
"MinNrOfMembers": 1
},
"Database": {
"SiteDbPath": "/app/data/scadalink.db"
"SiteDbPath": "/app/data/scadabridge.db"
},
"DataConnection": {
"ReconnectInterval": "00:00:05",
@@ -33,8 +33,8 @@
},
"Communication": {
"CentralContactPoints": [
"akka.tcp://scadalink@scadalink-central-a:8081",
"akka.tcp://scadalink@scadalink-central-b:8081"
"akka.tcp://scadabridge@scadabridge-central-a:8081",
"akka.tcp://scadabridge@scadabridge-central-b:8081"
],
"DeploymentTimeout": "00:02:00",
"LifecycleTimeout": "00:00:30",
+7 -7
View File
@@ -1,17 +1,17 @@
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Site",
"NodeName": "node-a",
"NodeHostname": "scadalink-site-c-a",
"NodeHostname": "scadabridge-site-c-a",
"SiteId": "site-c",
"RemotingPort": 8082,
"GrpcPort": 8083
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@scadalink-site-c-a:8082",
"akka.tcp://scadalink@scadalink-site-c-b:8082"
"akka.tcp://scadabridge@scadabridge-site-c-a:8082",
"akka.tcp://scadabridge@scadabridge-site-c-b:8082"
],
"SplitBrainResolverStrategy": "keep-oldest",
"StableAfter": "00:00:15",
@@ -20,7 +20,7 @@
"MinNrOfMembers": 1
},
"Database": {
"SiteDbPath": "/app/data/scadalink.db"
"SiteDbPath": "/app/data/scadabridge.db"
},
"DataConnection": {
"ReconnectInterval": "00:00:05",
@@ -33,8 +33,8 @@
},
"Communication": {
"CentralContactPoints": [
"akka.tcp://scadalink@scadalink-central-a:8081",
"akka.tcp://scadalink@scadalink-central-b:8081"
"akka.tcp://scadabridge@scadabridge-central-a:8081",
"akka.tcp://scadabridge@scadabridge-central-b:8081"
],
"DeploymentTimeout": "00:02:00",
"LifecycleTimeout": "00:00:30",
+7 -7
View File
@@ -1,17 +1,17 @@
{
"ScadaLink": {
"ScadaBridge": {
"Node": {
"Role": "Site",
"NodeName": "node-b",
"NodeHostname": "scadalink-site-c-b",
"NodeHostname": "scadabridge-site-c-b",
"SiteId": "site-c",
"RemotingPort": 8082,
"GrpcPort": 8083
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadalink@scadalink-site-c-a:8082",
"akka.tcp://scadalink@scadalink-site-c-b:8082"
"akka.tcp://scadabridge@scadabridge-site-c-a:8082",
"akka.tcp://scadabridge@scadabridge-site-c-b:8082"
],
"SplitBrainResolverStrategy": "keep-oldest",
"StableAfter": "00:00:15",
@@ -20,7 +20,7 @@
"MinNrOfMembers": 1
},
"Database": {
"SiteDbPath": "/app/data/scadalink.db"
"SiteDbPath": "/app/data/scadabridge.db"
},
"DataConnection": {
"ReconnectInterval": "00:00:05",
@@ -33,8 +33,8 @@
},
"Communication": {
"CentralContactPoints": [
"akka.tcp://scadalink@scadalink-central-a:8081",
"akka.tcp://scadalink@scadalink-central-b:8081"
"akka.tcp://scadabridge@scadabridge-central-a:8081",
"akka.tcp://scadabridge@scadabridge-central-b:8081"
],
"DeploymentTimeout": "00:02:00",
"LifecycleTimeout": "00:00:30",
+2 -2
View File
@@ -3,9 +3,9 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo "=== ScadaLink Docker Teardown ==="
echo "=== ScadaBridge Docker Teardown ==="
echo "Stopping ScadaLink application containers..."
echo "Stopping ScadaBridge application containers..."
docker compose -f "$SCRIPT_DIR/docker-compose.yml" down
echo ""
+2 -2
View File
@@ -14,5 +14,5 @@ http:
interval: 5s
timeout: 3s
servers:
- url: "http://scadalink-central-a:5000"
- url: "http://scadalink-central-b:5000"
- url: "http://scadabridge-central-a:5000"
- url: "http://scadabridge-central-b:5000"