Add ActiveNodeHealthCheck that returns 200 only on the Akka.NET cluster leader, enabling Traefik to route traffic to the active central node and automatically fail over when the leader changes. Also fixes AkkaClusterHealthCheck to resolve ActorSystem from AkkaHostedService (was always null via DI).
122 lines
4.7 KiB
Markdown
122 lines
4.7 KiB
Markdown
# Test Infrastructure
|
|
|
|
This document describes the local Docker-based test infrastructure for ScadaLink development. Six services provide the external dependencies needed to run and test the system locally. The first six run in `infra/docker-compose.yml`; Traefik runs alongside the cluster nodes in `docker/docker-compose.yml`.
|
|
|
|
## Services
|
|
|
|
| Service | Image | Port(s) | Config | Compose File |
|
|
|---------|-------|---------|--------|-------------|
|
|
| OPC UA Server | `mcr.microsoft.com/iotedge/opc-plc:latest` | 50000 (OPC UA), 8080 (web) | `infra/opcua/nodes.json` | `infra/` |
|
|
| LDAP Server | `glauth/glauth:latest` | 3893 | `infra/glauth/config.toml` | `infra/` |
|
|
| MS SQL 2022 | `mcr.microsoft.com/mssql/server:2022-latest` | 1433 | `infra/mssql/setup.sql` | `infra/` |
|
|
| SMTP (Mailpit) | `axllent/mailpit:latest` | 1025 (SMTP), 8025 (web) | Environment vars | `infra/` |
|
|
| REST API (Flask) | Custom build (`infra/restapi/Dockerfile`) | 5200 | `infra/restapi/app.py` | `infra/` |
|
|
| LmxFakeProxy | Custom build (`infra/lmxfakeproxy/Dockerfile`) | 50051 (gRPC) | Environment vars | `infra/` |
|
|
| Traefik LB | `traefik:v3.4` | 9000 (proxy), 8180 (dashboard) | `docker/traefik/` | `docker/` |
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
cd infra
|
|
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 \
|
|
-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 \
|
|
-i /docker-entrypoint-initdb.d/machinedata_seed.sql
|
|
```
|
|
|
|
## Per-Service Documentation
|
|
|
|
Each service has a dedicated document with configuration details, verification steps, and troubleshooting:
|
|
|
|
- [test_infra_opcua.md](test_infra_opcua.md) — OPC UA test server (Azure IoT OPC PLC)
|
|
- [test_infra_ldap.md](test_infra_ldap.md) — LDAP test server (GLAuth)
|
|
- [test_infra_db.md](test_infra_db.md) — MS SQL 2022 database
|
|
- [test_infra_smtp.md](test_infra_smtp.md) — SMTP test server (Mailpit)
|
|
- [test_infra_restapi.md](test_infra_restapi.md) — REST API test server (Flask)
|
|
- [test_infra_lmxfakeproxy.md](test_infra_lmxfakeproxy.md) — LmxProxy fake server (OPC UA bridge)
|
|
- Traefik LB — see `docker/README.md` and `docker/traefik/` (runs with the cluster, not in `infra/`)
|
|
|
|
## Connection Strings
|
|
|
|
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"
|
|
},
|
|
"Ldap": {
|
|
"Server": "localhost",
|
|
"Port": 3893,
|
|
"BaseDN": "dc=scadalink,dc=local",
|
|
"UseSsl": false
|
|
},
|
|
"OpcUa": {
|
|
"EndpointUrl": "opc.tcp://localhost:50000"
|
|
},
|
|
"Smtp": {
|
|
"Server": "localhost",
|
|
"Port": 1025,
|
|
"AuthMode": "None",
|
|
"FromAddress": "scada-notifications@company.com",
|
|
"ConnectionTimeout": 30
|
|
},
|
|
"ExternalSystems": {
|
|
"TestApi": {
|
|
"BaseUrl": "http://localhost:5200",
|
|
"AuthMode": "ApiKey",
|
|
"ApiKey": "scadalink-test-key-1"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Stopping & Teardown
|
|
|
|
```bash
|
|
cd infra
|
|
docker compose down # stop containers, preserve SQL data volume
|
|
docker compose stop opcua # stop a single service (also: ldap, mssql, smtp, restapi)
|
|
```
|
|
|
|
**Full teardown** (removes volumes, optionally images and venv):
|
|
```bash
|
|
cd infra
|
|
./teardown.sh # stop containers + delete SQL data volume
|
|
./teardown.sh --images # also remove downloaded Docker images
|
|
./teardown.sh --all # also remove the Python venv
|
|
```
|
|
|
|
After a full teardown, the next `docker compose up -d` starts fresh — re-run the SQL setup script.
|
|
|
|
## Files
|
|
|
|
```
|
|
infra/
|
|
docker-compose.yml # All five services
|
|
teardown.sh # Teardown script (volumes, images, venv)
|
|
glauth/config.toml # LDAP users and groups
|
|
mssql/setup.sql # Database and user creation
|
|
mssql/machinedata_seed.sql # Machine Data tables, stored procedures, sample data
|
|
opcua/nodes.json # Custom OPC UA tag definitions
|
|
restapi/app.py # Flask REST API server
|
|
restapi/Dockerfile # REST API container build
|
|
lmxfakeproxy/ # .NET gRPC proxy bridging LmxProxy protocol to OPC UA
|
|
tools/ # Python CLI tools (opcua, ldap, mssql, smtp, restapi)
|
|
README.md # Quick-start for the infra folder
|
|
|
|
docker/
|
|
traefik/traefik.yml # Traefik static config (entrypoints, file provider)
|
|
traefik/dynamic.yml # Traefik dynamic config (load balancer, health check routing)
|
|
```
|