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:
@@ -1,6 +1,6 @@
|
||||
# Test Infrastructure
|
||||
|
||||
This document describes the local Docker-based test infrastructure for ScadaLink development. Seven services provide the external dependencies needed to run and test the system locally. The first seven run in `infra/docker-compose.yml`; Traefik runs alongside the cluster nodes in `docker/docker-compose.yml`.
|
||||
This document describes the local Docker-based test infrastructure for ScadaBridge development. Seven services provide the external dependencies needed to run and test the system locally. The first seven run in `infra/docker-compose.yml`; Traefik runs alongside the cluster nodes in `docker/docker-compose.yml`.
|
||||
|
||||
## Services
|
||||
|
||||
@@ -25,12 +25,12 @@ docker compose up -d
|
||||
After the first startup, run the SQL setup and seed scripts:
|
||||
|
||||
```bash
|
||||
docker exec -i scadalink-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaLink_Dev1#' -C \
|
||||
docker exec -i scadabridge-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaBridge_Dev1#' -C \
|
||||
-i /docker-entrypoint-initdb.d/setup.sql
|
||||
|
||||
docker exec -i scadalink-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaLink_Dev1#' -C \
|
||||
docker exec -i scadabridge-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaBridge_Dev1#' -C \
|
||||
-i /docker-entrypoint-initdb.d/machinedata_seed.sql
|
||||
```
|
||||
|
||||
@@ -59,13 +59,13 @@ For use in `appsettings.Development.json`:
|
||||
```json
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"ScadaLinkConfig": "Server=localhost,1433;Database=ScadaLinkConfig;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true",
|
||||
"ScadaLinkMachineData": "Server=localhost,1433;Database=ScadaLinkMachineData;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true"
|
||||
"ScadaBridgeConfig": "Server=localhost,1433;Database=ScadaBridgeConfig;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true",
|
||||
"ScadaBridgeMachineData": "Server=localhost,1433;Database=ScadaBridgeMachineData;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
|
||||
},
|
||||
"Ldap": {
|
||||
"Server": "localhost",
|
||||
"Port": 3893,
|
||||
"BaseDN": "dc=scadalink,dc=local",
|
||||
"BaseDN": "dc=scadabridge,dc=local",
|
||||
"UseSsl": false
|
||||
},
|
||||
"OpcUa": {
|
||||
@@ -85,7 +85,7 @@ For use in `appsettings.Development.json`:
|
||||
"TestApi": {
|
||||
"BaseUrl": "http://localhost:5200",
|
||||
"AuthMode": "ApiKey",
|
||||
"ApiKey": "scadalink-test-key-1"
|
||||
"ApiKey": "scadabridge-test-key-1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The test database uses Microsoft SQL Server 2022 Developer Edition running in Docker. It provides two empty databases for ScadaLink — schema creation is handled by EF Core migrations at application startup (dev mode).
|
||||
The test database uses Microsoft SQL Server 2022 Developer Edition running in Docker. It provides two empty databases for ScadaBridge — schema creation is handled by EF Core migrations at application startup (dev mode).
|
||||
|
||||
## Image & Ports
|
||||
|
||||
@@ -14,21 +14,21 @@ The test database uses Microsoft SQL Server 2022 Developer Edition running in Do
|
||||
|
||||
| Account | Username | Password | Purpose |
|
||||
|---------|----------|----------|---------|
|
||||
| SA | `sa` | `ScadaLink_Dev1#` | Server admin (setup only) |
|
||||
| App | `scadalink_app` | `ScadaLink_Dev1#` | Application login (db_owner on both databases) |
|
||||
| SA | `sa` | `ScadaBridge_Dev1#` | Server admin (setup only) |
|
||||
| App | `scadabridge_app` | `ScadaBridge_Dev1#` | Application login (db_owner on both databases) |
|
||||
|
||||
## Databases
|
||||
|
||||
| Database | Purpose |
|
||||
|----------|---------|
|
||||
| `ScadaLinkConfig` | Configuration Database component — templates, deployments, users, audit log |
|
||||
| `ScadaLinkMachineData` | Machine/operational data storage |
|
||||
| `ScadaBridgeConfig` | Configuration Database component — templates, deployments, users, audit log |
|
||||
| `ScadaBridgeMachineData` | Machine/operational data storage |
|
||||
|
||||
Both databases are created by `infra/mssql/setup.sql`. EF Core migrations populate the `ScadaLinkConfig` schema. The `ScadaLinkMachineData` database is seeded with sample tables and stored procedures by `infra/mssql/machinedata_seed.sql`.
|
||||
Both databases are created by `infra/mssql/setup.sql`. EF Core migrations populate the `ScadaBridgeConfig` schema. The `ScadaBridgeMachineData` database is seeded with sample tables and stored procedures by `infra/mssql/machinedata_seed.sql`.
|
||||
|
||||
## Data Persistence
|
||||
|
||||
SQL data is stored in the named Docker volume `scadalink-mssql-data`. Data survives container restarts and `docker compose down`. To reset the database completely:
|
||||
SQL data is stored in the named Docker volume `scadabridge-mssql-data`. Data survives container restarts and `docker compose down`. To reset the database completely:
|
||||
|
||||
```bash
|
||||
docker compose down -v
|
||||
@@ -41,16 +41,16 @@ docker compose up -d
|
||||
After the first `docker compose up -d`, run the setup script:
|
||||
|
||||
```bash
|
||||
docker exec -i scadalink-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaLink_Dev1#' -C \
|
||||
docker exec -i scadabridge-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaBridge_Dev1#' -C \
|
||||
-i /docker-entrypoint-initdb.d/setup.sql
|
||||
```
|
||||
|
||||
This creates the databases and the `scadalink_app` login. Then seed the Machine Data database with sample tables, stored procedures, and data:
|
||||
This creates the databases and the `scadabridge_app` login. Then seed the Machine Data database with sample tables, stored procedures, and data:
|
||||
|
||||
```bash
|
||||
docker exec -i scadalink-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaLink_Dev1#' -C \
|
||||
docker exec -i scadabridge-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaBridge_Dev1#' -C \
|
||||
-i /docker-entrypoint-initdb.d/machinedata_seed.sql
|
||||
```
|
||||
|
||||
@@ -61,11 +61,11 @@ You only need to run these once (or again after deleting the volume).
|
||||
For `appsettings.Development.json`:
|
||||
|
||||
```
|
||||
Server=localhost,1433;Database=ScadaLinkConfig;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true
|
||||
Server=localhost,1433;Database=ScadaBridgeConfig;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true
|
||||
```
|
||||
|
||||
```
|
||||
Server=localhost,1433;Database=ScadaLinkMachineData;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true
|
||||
Server=localhost,1433;Database=ScadaBridgeMachineData;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true
|
||||
```
|
||||
|
||||
## Verification
|
||||
@@ -73,23 +73,23 @@ Server=localhost,1433;Database=ScadaLinkMachineData;User Id=scadalink_app;Passwo
|
||||
1. Check the container is running:
|
||||
|
||||
```bash
|
||||
docker ps --filter name=scadalink-mssql
|
||||
docker ps --filter name=scadabridge-mssql
|
||||
```
|
||||
|
||||
2. Query using `sqlcmd` inside the container:
|
||||
|
||||
```bash
|
||||
docker exec -it scadalink-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaLink_Dev1#' -C \
|
||||
docker exec -it scadabridge-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U sa -P 'ScadaBridge_Dev1#' -C \
|
||||
-Q "SELECT name FROM sys.databases"
|
||||
```
|
||||
|
||||
3. Verify the app login:
|
||||
|
||||
```bash
|
||||
docker exec -it scadalink-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U scadalink_app -P 'ScadaLink_Dev1#' -C \
|
||||
-d ScadaLinkConfig \
|
||||
docker exec -it scadabridge-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||||
-S localhost -U scadabridge_app -P 'ScadaBridge_Dev1#' -C \
|
||||
-d ScadaBridgeConfig \
|
||||
-Q "SELECT DB_NAME()"
|
||||
```
|
||||
|
||||
@@ -112,17 +112,17 @@ python infra/tools/mssql_tool.py check
|
||||
python infra/tools/mssql_tool.py setup --script infra/mssql/setup.sql
|
||||
|
||||
# List tables in a database
|
||||
python infra/tools/mssql_tool.py tables --database ScadaLinkConfig
|
||||
python infra/tools/mssql_tool.py tables --database ScadaBridgeConfig
|
||||
|
||||
# Run an ad-hoc query
|
||||
python infra/tools/mssql_tool.py query --database ScadaLinkConfig --sql "SELECT name FROM sys.tables"
|
||||
python infra/tools/mssql_tool.py query --database ScadaBridgeConfig --sql "SELECT name FROM sys.tables"
|
||||
```
|
||||
|
||||
Use `--host`, `--port`, `--user`, `--password` to override defaults (localhost:1433, sa, ScadaLink_Dev1#). Run with `--help` for full usage.
|
||||
Use `--host`, `--port`, `--user`, `--password` to override defaults (localhost:1433, sa, ScadaBridge_Dev1#). Run with `--help` for full usage.
|
||||
|
||||
## Machine Data Tables & Stored Procedures
|
||||
|
||||
The `machinedata_seed.sql` script creates the following in `ScadaLinkMachineData`:
|
||||
The `machinedata_seed.sql` script creates the following in `ScadaBridgeMachineData`:
|
||||
|
||||
**Tables**:
|
||||
|
||||
@@ -145,13 +145,13 @@ The `machinedata_seed.sql` script creates the following in `ScadaLinkMachineData
|
||||
| `usp_GetEquipmentEvents` | Get recent equipment events with optional filters |
|
||||
| `usp_GetActiveAlarms` | Get active/acknowledged alarms by severity |
|
||||
|
||||
## Relevance to ScadaLink Components
|
||||
## Relevance to ScadaBridge Components
|
||||
|
||||
- **Configuration Database** — primary consumer; EF Core context targets `ScadaLinkConfig`.
|
||||
- **Deployment Manager** — reads/writes deployment records in `ScadaLinkConfig`.
|
||||
- **Template Engine** — reads/writes template definitions in `ScadaLinkConfig`.
|
||||
- **Security & Auth** — user/role data stored in `ScadaLinkConfig`.
|
||||
- **External System Gateway** — scripts use `Database.Connection("machineDataConnection")` to query `ScadaLinkMachineData` tables and stored procedures.
|
||||
- **Configuration Database** — primary consumer; EF Core context targets `ScadaBridgeConfig`.
|
||||
- **Deployment Manager** — reads/writes deployment records in `ScadaBridgeConfig`.
|
||||
- **Template Engine** — reads/writes template definitions in `ScadaBridgeConfig`.
|
||||
- **Security & Auth** — user/role data stored in `ScadaBridgeConfig`.
|
||||
- **External System Gateway** — scripts use `Database.Connection("machineDataConnection")` to query `ScadaBridgeMachineData` tables and stored procedures.
|
||||
- **Site Runtime** — scripts call stored procedures via `Database.Connection()` and `Database.CachedWrite()` for batch recording and data queries.
|
||||
- **Inbound API** — methods can query machine data via named database connections.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The test LDAP server uses [GLAuth](https://glauth.github.io/), a lightweight LDAP server backed by a TOML config file. It provides test users and groups that map to ScadaLink's role-based authorization model.
|
||||
The test LDAP server uses [GLAuth](https://glauth.github.io/), a lightweight LDAP server backed by a TOML config file. It provides test users and groups that map to ScadaBridge's role-based authorization model.
|
||||
|
||||
## Image & Ports
|
||||
|
||||
@@ -12,20 +12,20 @@ The test LDAP server uses [GLAuth](https://glauth.github.io/), a lightweight LDA
|
||||
## Base DN
|
||||
|
||||
```
|
||||
dc=scadalink,dc=local
|
||||
dc=scadabridge,dc=local
|
||||
```
|
||||
|
||||
## Test Users
|
||||
|
||||
All users have the password `password`.
|
||||
|
||||
| Username | Email | Primary Group | Additional Groups | ScadaLink Role |
|
||||
| Username | Email | Primary Group | Additional Groups | ScadaBridge Role |
|
||||
|----------|-------|---------------|-------------------|----------------|
|
||||
| `admin` | admin@scadalink.local | SCADA-Admins | — | Full administrator |
|
||||
| `designer` | designer@scadalink.local | SCADA-Designers | — | Template designer |
|
||||
| `deployer` | deployer@scadalink.local | SCADA-Deploy-All | — | Deploy to all sites |
|
||||
| `site-deployer` | site-deployer@scadalink.local | SCADA-Deploy-SiteA | — | Deploy to SiteA only |
|
||||
| `multi-role` | multi-role@scadalink.local | SCADA-Admins | SCADA-Designers, SCADA-Deploy-All | Multiple roles |
|
||||
| `admin` | admin@scadabridge.local | SCADA-Admins | — | Full administrator |
|
||||
| `designer` | designer@scadabridge.local | SCADA-Designers | — | Template designer |
|
||||
| `deployer` | deployer@scadabridge.local | SCADA-Deploy-All | — | Deploy to all sites |
|
||||
| `site-deployer` | site-deployer@scadabridge.local | SCADA-Deploy-SiteA | — | Deploy to SiteA only |
|
||||
| `multi-role` | multi-role@scadabridge.local | SCADA-Admins | SCADA-Designers, SCADA-Deploy-All | Multiple roles |
|
||||
|
||||
## Groups
|
||||
|
||||
@@ -41,36 +41,36 @@ All users have the password `password`.
|
||||
Users bind with their full DN, which includes the primary group as an OU:
|
||||
|
||||
```
|
||||
cn=<username>,ou=<PrimaryGroupName>,ou=users,dc=scadalink,dc=local
|
||||
cn=<username>,ou=<PrimaryGroupName>,ou=users,dc=scadabridge,dc=local
|
||||
```
|
||||
|
||||
For example: `cn=admin,ou=SCADA-Admins,ou=users,dc=scadalink,dc=local`
|
||||
For example: `cn=admin,ou=SCADA-Admins,ou=users,dc=scadabridge,dc=local`
|
||||
|
||||
The full DNs for all test users:
|
||||
|
||||
| Username | Full DN |
|
||||
|----------|---------|
|
||||
| `admin` | `cn=admin,ou=SCADA-Admins,ou=users,dc=scadalink,dc=local` |
|
||||
| `designer` | `cn=designer,ou=SCADA-Designers,ou=users,dc=scadalink,dc=local` |
|
||||
| `deployer` | `cn=deployer,ou=SCADA-Deploy-All,ou=users,dc=scadalink,dc=local` |
|
||||
| `site-deployer` | `cn=site-deployer,ou=SCADA-Deploy-SiteA,ou=users,dc=scadalink,dc=local` |
|
||||
| `multi-role` | `cn=multi-role,ou=SCADA-Admins,ou=users,dc=scadalink,dc=local` |
|
||||
| `admin` | `cn=admin,ou=SCADA-Admins,ou=users,dc=scadabridge,dc=local` |
|
||||
| `designer` | `cn=designer,ou=SCADA-Designers,ou=users,dc=scadabridge,dc=local` |
|
||||
| `deployer` | `cn=deployer,ou=SCADA-Deploy-All,ou=users,dc=scadabridge,dc=local` |
|
||||
| `site-deployer` | `cn=site-deployer,ou=SCADA-Deploy-SiteA,ou=users,dc=scadabridge,dc=local` |
|
||||
| `multi-role` | `cn=multi-role,ou=SCADA-Admins,ou=users,dc=scadabridge,dc=local` |
|
||||
|
||||
## Verification
|
||||
|
||||
1. Check the container is running:
|
||||
|
||||
```bash
|
||||
docker ps --filter name=scadalink-ldap
|
||||
docker ps --filter name=scadabridge-ldap
|
||||
```
|
||||
|
||||
2. Test a user bind with `ldapsearch`:
|
||||
|
||||
```bash
|
||||
ldapsearch -H ldap://localhost:3893 \
|
||||
-D "cn=admin,ou=SCADA-Admins,ou=users,dc=scadalink,dc=local" \
|
||||
-D "cn=admin,ou=SCADA-Admins,ou=users,dc=scadabridge,dc=local" \
|
||||
-w password \
|
||||
-b "dc=scadalink,dc=local" \
|
||||
-b "dc=scadabridge,dc=local" \
|
||||
"(objectClass=*)"
|
||||
```
|
||||
|
||||
@@ -78,9 +78,9 @@ ldapsearch -H ldap://localhost:3893 \
|
||||
|
||||
```bash
|
||||
ldapsearch -H ldap://localhost:3893 \
|
||||
-D "cn=admin,ou=SCADA-Admins,ou=users,dc=scadalink,dc=local" \
|
||||
-D "cn=admin,ou=SCADA-Admins,ou=users,dc=scadabridge,dc=local" \
|
||||
-w password \
|
||||
-b "dc=scadalink,dc=local" \
|
||||
-b "dc=scadabridge,dc=local" \
|
||||
"(cn=multi-role)"
|
||||
```
|
||||
|
||||
@@ -114,14 +114,14 @@ python infra/tools/ldap_tool.py search --filter "(cn=multi-role)"
|
||||
|
||||
Use `--host` and `--port` to override defaults (localhost:3893). Run with `--help` for full usage.
|
||||
|
||||
## Relevance to ScadaLink Components
|
||||
## Relevance to ScadaBridge Components
|
||||
|
||||
- **Security & Auth** — test LDAP bind authentication, group-to-role mapping, and multi-group resolution.
|
||||
- **Central UI** — test login flows with different role combinations.
|
||||
|
||||
## Notes
|
||||
|
||||
- GLAuth uses plain LDAP on port 3893. ScadaLink's Security & Auth component requires LDAPS/StartTLS in production. For dev testing, configure the LDAP client to allow plaintext connections.
|
||||
- GLAuth uses plain LDAP on port 3893. ScadaBridge's Security & Auth component requires LDAPS/StartTLS in production. For dev testing, configure the LDAP client to allow plaintext connections.
|
||||
- To add users or groups, edit `infra/glauth/config.toml` locally and restart the container: `docker compose restart ldap`. Note that the file is named `config.toml` on the host but is mounted into the container as `/app/config/config.cfg` (the path GLAuth expects).
|
||||
- The `admin` user is configured with `[[users.capabilities]]` (`action = "search"`, `object = "*"`) in the GLAuth config. This grants the admin account permission to perform LDAP search operations, which is required for user/group lookups.
|
||||
- Anonymous bind is not allowed. All LDAP operations (including searches) require an authenticated bind. Use the `admin` account for search operations.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The test OPC UA server uses [Azure IoT OPC PLC](https://github.com/Azure-Samples/iot-edge-opc-plc), a simulated OPC UA server that generates realistic data. It is configured with custom nodes that match ScadaLink attribute patterns.
|
||||
The test OPC UA server uses [Azure IoT OPC PLC](https://github.com/Azure-Samples/iot-edge-opc-plc), a simulated OPC UA server that generates realistic data. It is configured with custom nodes that match ScadaBridge attribute patterns.
|
||||
|
||||
## Image & Ports
|
||||
|
||||
@@ -10,8 +10,8 @@ Two identical OPC UA server instances run with the same tag configuration, on di
|
||||
|
||||
| Instance | OPC UA Endpoint | Web UI | Container |
|
||||
|----------|----------------|--------|-----------|
|
||||
| opcua | `opc.tcp://localhost:50000` | `http://localhost:8080` | scadalink-opcua |
|
||||
| opcua2 | `opc.tcp://localhost:50010` | `http://localhost:8081` | scadalink-opcua2 |
|
||||
| opcua | `opc.tcp://localhost:50000` | `http://localhost:8080` | scadabridge-opcua |
|
||||
| opcua2 | `opc.tcp://localhost:50010` | `http://localhost:8081` | scadabridge-opcua2 |
|
||||
|
||||
- **Image**: `mcr.microsoft.com/iotedge/opc-plc:latest`
|
||||
|
||||
@@ -30,7 +30,7 @@ Two identical OPC UA server instances run with the same tag configuration, on di
|
||||
|
||||
## Custom Nodes
|
||||
|
||||
The file `infra/opcua/nodes.json` defines a single `ConfigFolder` object (not an array) with a root "ScadaLink" folder containing four equipment subfolders. Tags match typical ScadaLink instance attribute patterns:
|
||||
The file `infra/opcua/nodes.json` defines a single `ConfigFolder` object (not an array) with a root "ScadaBridge" folder containing four equipment subfolders. Tags match typical ScadaBridge instance attribute patterns:
|
||||
|
||||
| Folder | Tags | Types |
|
||||
|--------|------|-------|
|
||||
@@ -44,14 +44,14 @@ All custom nodes hold their initial/default values (0 for numerics, false for bo
|
||||
|
||||
Custom nodes live in namespace 3 (`http://microsoft.com/Opc/OpcPlc/`). Node IDs follow the pattern `ns=3;s=<Folder>.<Tag>` (e.g., `ns=3;s=Motor.Speed`). Nested folders use dot notation: `ns=3;s=JoeAppEngine.Scheduler.ScanTime`.
|
||||
|
||||
The browse path from the Objects root is: `OpcPlc > ScadaLink > Motor|Pump|Tank|Valve|JoeAppEngine`.
|
||||
The browse path from the Objects root is: `OpcPlc > ScadaBridge > Motor|Pump|Tank|Valve|JoeAppEngine`.
|
||||
|
||||
## Verification
|
||||
|
||||
1. Check both containers are running:
|
||||
|
||||
```bash
|
||||
docker ps --filter name=scadalink-opcua
|
||||
docker ps --filter name=scadabridge-opcua
|
||||
```
|
||||
|
||||
2. Verify both OPC UA endpoints using any OPC UA client (e.g., UaExpert, opcua-commander):
|
||||
@@ -83,7 +83,7 @@ python infra/tools/opcua_tool.py check
|
||||
python infra/tools/opcua_tool.py browse
|
||||
|
||||
# Browse a specific equipment folder
|
||||
python infra/tools/opcua_tool.py browse --path "3:OpcPlc.3:ScadaLink.3:Motor"
|
||||
python infra/tools/opcua_tool.py browse --path "3:OpcPlc.3:ZB.MOM.WW.ScadaBridge.3:Motor"
|
||||
|
||||
# Read a tag value
|
||||
python infra/tools/opcua_tool.py read --node "ns=3;s=Motor.Speed"
|
||||
@@ -99,12 +99,12 @@ Use `--endpoint` to override the default endpoint (`opc.tcp://localhost:50000`).
|
||||
|
||||
```bash
|
||||
python infra/tools/opcua_tool.py --endpoint opc.tcp://localhost:50010 check
|
||||
python infra/tools/opcua_tool.py --endpoint opc.tcp://localhost:50010 browse --path "3:OpcPlc.3:ScadaLink.3:Motor"
|
||||
python infra/tools/opcua_tool.py --endpoint opc.tcp://localhost:50010 browse --path "3:OpcPlc.3:ZB.MOM.WW.ScadaBridge.3:Motor"
|
||||
```
|
||||
|
||||
Run with `--help` for full usage.
|
||||
|
||||
## Relevance to ScadaLink Components
|
||||
## Relevance to ScadaBridge Components
|
||||
|
||||
- **Data Connection Layer** — connect to this server to test OPC UA subscription, read/write, and reconnection behavior.
|
||||
- **Site Runtime / Instance Actors** — deploy instances with tag mappings pointing at these nodes.
|
||||
|
||||
@@ -35,7 +35,7 @@ var browser = await playwright.Chromium.ConnectAsync("ws://localhost:3000");
|
||||
var page = await browser.NewPageAsync();
|
||||
|
||||
// Browser runs inside Docker — use the Docker network hostname for Traefik.
|
||||
await page.GotoAsync("http://scadalink-traefik");
|
||||
await page.GotoAsync("http://scadabridge-traefik");
|
||||
```
|
||||
|
||||
### Node.js
|
||||
@@ -44,7 +44,7 @@ await page.GotoAsync("http://scadalink-traefik");
|
||||
const { chromium } = require('playwright');
|
||||
const browser = await chromium.connect('ws://localhost:3000');
|
||||
const page = await browser.newPage();
|
||||
await page.goto('http://scadalink-traefik');
|
||||
await page.goto('http://scadabridge-traefik');
|
||||
```
|
||||
|
||||
### Python
|
||||
@@ -55,18 +55,18 @@ from playwright.sync_api import sync_playwright
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.connect("ws://localhost:3000")
|
||||
page = browser.new_page()
|
||||
page.goto("http://scadalink-traefik")
|
||||
page.goto("http://scadabridge-traefik")
|
||||
```
|
||||
|
||||
## Central UI Access
|
||||
|
||||
The Playwright container is on the `scadalink-net` Docker network, so it can reach the Central UI cluster nodes directly:
|
||||
The Playwright container is on the `scadabridge-net` Docker network, so it can reach the Central UI cluster nodes directly:
|
||||
|
||||
| Target | URL in Test Scripts |
|
||||
|--------|---------------------|
|
||||
| Traefik LB | `http://scadalink-traefik` |
|
||||
| Central Node A | `http://scadalink-central-a:5000` |
|
||||
| Central Node B | `http://scadalink-central-b:5000` |
|
||||
| Traefik LB | `http://scadabridge-traefik` |
|
||||
| Central Node A | `http://scadabridge-central-a:5000` |
|
||||
| Central Node B | `http://scadabridge-central-b:5000` |
|
||||
|
||||
**Important**: The browser runs inside the Docker container, so `page.goto()` URLs must use Docker network hostnames (not `localhost`). The test script itself connects to the Playwright server via `ws://localhost:3000` (host-mapped port), but all URLs navigated by the browser resolve inside the container.
|
||||
|
||||
@@ -75,13 +75,13 @@ The Playwright container is on the `scadalink-net` Docker network, so it can rea
|
||||
1. Check the container is running:
|
||||
|
||||
```bash
|
||||
docker ps --filter name=scadalink-playwright
|
||||
docker ps --filter name=scadabridge-playwright
|
||||
```
|
||||
|
||||
2. Check the server is accepting connections (look for the WebSocket endpoint in logs):
|
||||
|
||||
```bash
|
||||
docker logs scadalink-playwright 2>&1 | head -5
|
||||
docker logs scadabridge-playwright 2>&1 | head -5
|
||||
```
|
||||
|
||||
3. Quick smoke test with a one-liner (requires `npx` and `playwright` on the host):
|
||||
@@ -90,7 +90,7 @@ docker logs scadalink-playwright 2>&1 | head -5
|
||||
npx playwright@1.58.2 test --browser chromium --connect ws://localhost:3000
|
||||
```
|
||||
|
||||
## Relevance to ScadaLink Components
|
||||
## Relevance to ScadaBridge Components
|
||||
|
||||
- **Central UI** — end-to-end UI testing of all Blazor Server pages (login, admin, design, deployment, monitoring workflows).
|
||||
- **Traefik Proxy** — verify load balancer behavior, failover, and active node routing from a browser perspective.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The test REST API server is a lightweight Python/Flask application that provides HTTP endpoints matching the patterns used by ScadaLink's External System Gateway and Inbound API components. It supports simple parameter/response methods, complex nested object/list methods, authentication, and error simulation.
|
||||
The test REST API server is a lightweight Python/Flask application that provides HTTP endpoints matching the patterns used by ScadaBridge's External System Gateway and Inbound API components. It supports simple parameter/response methods, complex nested object/list methods, authentication, and error simulation.
|
||||
|
||||
## Image & Ports
|
||||
|
||||
@@ -20,7 +20,7 @@ The test REST API server is a lightweight Python/Flask application that provides
|
||||
|
||||
The server validates requests using one of two methods:
|
||||
|
||||
- **API Key**: `X-API-Key: scadalink-test-key-1` header
|
||||
- **API Key**: `X-API-Key: scadabridge-test-key-1` header
|
||||
- **Basic Auth**: Any username/password (accepts all credentials)
|
||||
|
||||
The `GET /api/Ping` endpoint is always unauthenticated (health check).
|
||||
@@ -35,7 +35,7 @@ For `appsettings.Development.json` (External System Gateway):
|
||||
"TestApi": {
|
||||
"BaseUrl": "http://localhost:5200",
|
||||
"AuthMode": "ApiKey",
|
||||
"ApiKey": "scadalink-test-key-1"
|
||||
"ApiKey": "scadabridge-test-key-1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ Response: `{"batchId": "BATCH-A1B2C3D4", "accepted": true, "itemCount": 2}`
|
||||
1. Check the container is running:
|
||||
|
||||
```bash
|
||||
docker ps --filter name=scadalink-restapi
|
||||
docker ps --filter name=scadabridge-restapi
|
||||
```
|
||||
|
||||
2. Test the health endpoint:
|
||||
@@ -162,7 +162,7 @@ curl http://localhost:5200/api/Ping
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5200/api/Add \
|
||||
-H "X-API-Key: scadalink-test-key-1" \
|
||||
-H "X-API-Key: scadabridge-test-key-1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"a": 2, "b": 3}'
|
||||
```
|
||||
@@ -192,7 +192,7 @@ python infra/tools/restapi_tool.py methods
|
||||
|
||||
Use `--url` to override the base URL (default: `http://localhost:5200`), `--api-key` for the API key. Run with `--help` for full usage.
|
||||
|
||||
## Relevance to ScadaLink Components
|
||||
## Relevance to ScadaBridge Components
|
||||
|
||||
- **External System Gateway** — test HTTP/REST calls (`ExternalSystem.Call()` and `CachedCall()`), API key authentication, error classification (5xx vs 4xx), and timeout handling.
|
||||
- **Inbound API** — test the `POST /api/{methodName}` pattern, flat JSON parameters, and extended type system (Object, List) with complex nested responses.
|
||||
|
||||
@@ -40,8 +40,8 @@ For `appsettings.Development.json` (Notification Service):
|
||||
|
||||
> **`Server` host**: use `localhost` only when the Notification Service runs directly on
|
||||
> the host. When it runs inside the docker cluster, set `Server` to the container name
|
||||
> `scadalink-smtp` — the cluster compose stack and the infra compose stack share the
|
||||
> `scadalink-net` network, so the container is reachable by name.
|
||||
> `scadabridge-smtp` — the cluster compose stack and the infra compose stack share the
|
||||
> `scadabridge-net` network, so the container is reachable by name.
|
||||
|
||||
The delivery service (`MailKitSmtpClientWrapper`) only accepts `Basic` or `OAuth2` —
|
||||
there is no "no auth" mode — so the working config above uses `Basic`:
|
||||
@@ -70,7 +70,7 @@ Mailpit exposes a REST API at `http://localhost:8025/api` for programmatic acces
|
||||
1. Check the container is running:
|
||||
|
||||
```bash
|
||||
docker ps --filter name=scadalink-smtp
|
||||
docker ps --filter name=scadabridge-smtp
|
||||
```
|
||||
|
||||
2. Open the web UI at `http://localhost:8025` to view captured emails.
|
||||
@@ -100,7 +100,7 @@ python infra/tools/smtp_tool.py check
|
||||
# Send a test email
|
||||
python infra/tools/smtp_tool.py send --to user@example.com --subject "Alarm: Tank High Level" --body "Tank level exceeded 95%"
|
||||
|
||||
# Send with BCC (matches ScadaLink notification delivery pattern)
|
||||
# Send with BCC (matches ScadaBridge notification delivery pattern)
|
||||
python infra/tools/smtp_tool.py send --to scada-notifications@company.com --bcc "operator1@company.com,operator2@company.com" --subject "Shift Report"
|
||||
|
||||
# List captured messages
|
||||
@@ -115,7 +115,7 @@ python infra/tools/smtp_tool.py clear
|
||||
|
||||
Use `--host` and `--port` to override SMTP defaults (localhost:1025), `--api` for the Mailpit API URL. Run with `--help` for full usage.
|
||||
|
||||
## Relevance to ScadaLink Components
|
||||
## Relevance to ScadaBridge Components
|
||||
|
||||
- **Notification Service** — test SMTP delivery, BCC recipient handling, plain-text formatting, and store-and-forward retry behavior (Mailpit can be stopped/started to simulate transient failures).
|
||||
- **Store-and-Forward Engine** — verify buffered retry by stopping the SMTP container and observing queued notifications.
|
||||
|
||||
Reference in New Issue
Block a user