Per decision #137 (dev env credentials documented openly in dev-environment.md; production uses Integrated Security / gMSA per decision #46 and never any value from this table). Section lives at the top of the doc immediately after Two Environment Tiers, so it's discoverable as the single source of truth for "what's actually running here right now". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
461 lines
31 KiB
Markdown
461 lines
31 KiB
Markdown
# Development Environment — OtOpcUa v2
|
||
|
||
> **Status**: DRAFT — concrete inventory + setup plan for every external resource the v2 build needs. Companion to `test-data-sources.md` (which catalogues the simulator/stub strategy per driver) and `implementation/overview.md` (which references the dev environment in entry-gate checklists).
|
||
>
|
||
> **Branch**: `v2`
|
||
> **Created**: 2026-04-17
|
||
|
||
## Scope
|
||
|
||
Every external resource a developer needs on their machine, plus the dedicated integration host that runs the heavier simulators per CI tiering decision #99. Includes Docker container images, ports, default credentials (dev only — production overrides documented), and ownership.
|
||
|
||
**Not in scope here**: production deployment topology (separate doc when v2 ships), CI pipeline configuration (separate ops concern), individual developer's IDE / editor preferences.
|
||
|
||
## Two Environment Tiers
|
||
|
||
Per decision #99:
|
||
|
||
| Tier | Purpose | Where it runs | Resources |
|
||
|------|---------|---------------|-----------|
|
||
| **PR-CI / inner-loop dev** | Fast, runs on minimal Windows + Linux build agents and developer laptops | Each developer's machine; CI runners | Pure-managed in-process simulators (NModbus, OPC Foundation reference server, FOCAS TCP stub from test project). No Docker, no VMs. |
|
||
| **Nightly / integration CI** | Full driver-stack validation against real wire protocols | One dedicated Windows host with Docker Desktop + Hyper-V + a TwinCAT XAR VM | All Docker simulators (`oitc/modbus-server`, `ab_server`, Snap7), TwinCAT XAR VM, Galaxy.Host installer + dev Galaxy access, FOCAS TCP stub binary, FOCAS FaultShim assembly |
|
||
|
||
The tier split keeps developer onboarding fast (no Docker required for first build) while concentrating the heavy simulator setup on one machine the team maintains.
|
||
|
||
## Installed Inventory — This Machine
|
||
|
||
Running record of every v2 dev service stood up on this developer machine. Updated on every install / config change. Credentials here are **dev-only** per decision #137 — production uses Integrated Security / gMSA per decision #46 and never any value in this table.
|
||
|
||
**Last updated**: 2026-04-17
|
||
|
||
### Host
|
||
|
||
| Attribute | Value |
|
||
|-----------|-------|
|
||
| Machine name | `DESKTOP-6JL3KKO` |
|
||
| User | `dohertj2` (member of local Administrators + `docker-users`) |
|
||
| VM platform | VMware (`VMware20,1`), nested virtualization enabled |
|
||
| CPU | Intel Xeon E5-2697 v4 @ 2.30GHz (3 vCPUs) |
|
||
| OS | Windows (WSL2 + Hyper-V Platform features installed) |
|
||
|
||
### Toolchain
|
||
|
||
| Tool | Version | Location | Install method |
|
||
|------|---------|----------|----------------|
|
||
| .NET SDK | 10.0.201 | `C:\Program Files\dotnet\sdk\` | Pre-installed |
|
||
| .NET AspNetCore runtime | 10.0.5 | `C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\` | Pre-installed |
|
||
| .NET NETCore runtime | 10.0.5 | `C:\Program Files\dotnet\shared\Microsoft.NETCore.App\` | Pre-installed |
|
||
| .NET WindowsDesktop runtime | 10.0.5 | `C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\` | Pre-installed |
|
||
| .NET Framework 4.8 SDK | — | Pending (needed for Phase 2 Galaxy.Host; not yet required) | — |
|
||
| Git | Pre-installed | Standard | — |
|
||
| PowerShell 7 | Pre-installed | Standard | — |
|
||
| winget | v1.28.220 | Standard Windows feature | — |
|
||
| WSL | Default v2, distro `docker-desktop` `STATE Running` | — | `wsl --install --no-launch` (2026-04-17) |
|
||
| Docker Desktop | 29.3.1 (engine) / Docker Desktop 4.68.0 (app) | Standard | `winget install --id Docker.DockerDesktop` (2026-04-17) |
|
||
| `dotnet-ef` CLI | 10.0.6 | `%USERPROFILE%\.dotnet\tools\dotnet-ef.exe` | `dotnet tool install --global dotnet-ef --version 10.0.*` (2026-04-17) |
|
||
|
||
### Services
|
||
|
||
| Service | Container / Process | Version | Host:Port | Credentials (dev-only) | Data location | Status |
|
||
|---------|---------------------|---------|-----------|------------------------|---------------|--------|
|
||
| **Central config DB** | Docker container `otopcua-mssql` (image `mcr.microsoft.com/mssql/server:2022-latest`) | 16.0.4250.1 (RTM-CU24-GDR, KB5083252) | `localhost:1433` | User `sa` / Password `OtOpcUaDev_2026!` | Docker named volume `otopcua-mssql-data` (mounted at `/var/opt/mssql` inside container) | ✅ Running |
|
||
| Dev Galaxy (AVEVA System Platform) | Local install on this dev box | v1 baseline | Local COM via MXAccess | Windows Auth | Galaxy repository DB `ZB` on local SQL Server (separate instance from `otopcua-mssql` — legacy v1 Galaxy DB, not related to v2 config DB) | ✅ Available (per CLAUDE.md) |
|
||
| GLAuth (LDAP) | Local install at `C:\publish\glauth\` | v1 baseline | `localhost:3893` (LDAP) / `3894` (LDAPS) | Bind DN `cn=admin,dc=otopcua,dc=local` / password in `glauth-otopcua.cfg` | `C:\publish\glauth\` | Pending — v2 test users + groups config not yet seeded (Phase 1 Stream E task) |
|
||
| OPC Foundation reference server | Not yet built | — | `localhost:62541` (target) | `user1` / `password1` (reference-server defaults) | — | Pending (needed for Phase 5 OPC UA Client driver testing) |
|
||
| FOCAS TCP stub | Not yet built | — | `localhost:8193` (target) | n/a | — | Pending (built in Phase 5) |
|
||
| Modbus simulator (`oitc/modbus-server`) | — | — | `localhost:502` (target) | n/a | — | Pending (needed for Phase 3 Modbus driver; moves to integration host per two-tier model) |
|
||
| libplctag `ab_server` | — | — | `localhost:44818` (target) | n/a | — | Pending (Phase 3/4 AB CIP and AB Legacy drivers) |
|
||
| Snap7 Server | — | — | `localhost:102` (target) | n/a | — | Pending (Phase 4 S7 driver) |
|
||
| TwinCAT XAR VM | — | — | `localhost:48898` (ADS) (target) | TwinCAT default route creds | — | Pending — runs in Hyper-V VM, not on this dev box (per decision #135) |
|
||
|
||
### Connection strings for `appsettings.Development.json`
|
||
|
||
Copy-paste-ready. **Never commit these to the repo** — they go in `appsettings.Development.json` (gitignored per the standard .NET convention) or in user-scoped dotnet secrets.
|
||
|
||
```jsonc
|
||
{
|
||
"ConfigDatabase": {
|
||
"ConnectionString": "Server=localhost,1433;Database=OtOpcUaConfig_Dev;User Id=sa;Password=OtOpcUaDev_2026!;TrustServerCertificate=true;Encrypt=false;"
|
||
},
|
||
"Authentication": {
|
||
"Ldap": {
|
||
"Host": "localhost",
|
||
"Port": 3893,
|
||
"UseLdaps": false,
|
||
"BindDn": "cn=admin,dc=otopcua,dc=local",
|
||
"BindPassword": "<see glauth-otopcua.cfg — pending seeding>"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
For xUnit test fixtures that need a throwaway DB per test run, build connection strings with `Database=OtOpcUaConfig_Test_{timestamp}` to avoid cross-run pollution.
|
||
|
||
### Container management quick reference
|
||
|
||
```powershell
|
||
# Start / stop the SQL Server container (survives reboots via Docker Desktop auto-start)
|
||
docker stop otopcua-mssql
|
||
docker start otopcua-mssql
|
||
|
||
# Logs (useful for diagnosing startup failures or login issues)
|
||
docker logs otopcua-mssql --tail 50
|
||
|
||
# Shell into the container (rarely needed; sqlcmd is the usual tool)
|
||
docker exec -it otopcua-mssql bash
|
||
|
||
# Query via sqlcmd inside the container (Git Bash needs MSYS_NO_PATHCONV=1 to avoid path mangling)
|
||
MSYS_NO_PATHCONV=1 docker exec otopcua-mssql /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "OtOpcUaDev_2026!" -C -Q "SELECT @@VERSION"
|
||
|
||
# Nuclear reset: drop the container + volume (destroys all DB data)
|
||
docker stop otopcua-mssql
|
||
docker rm otopcua-mssql
|
||
docker volume rm otopcua-mssql-data
|
||
# …then re-run the docker run command from Bootstrap Step 6
|
||
```
|
||
|
||
### Credential rotation
|
||
|
||
Dev credentials in this inventory are convenience defaults, not secrets. Change them at will per developer — just update this doc + each developer's `appsettings.Development.json`. There is no shared secret store for dev.
|
||
|
||
## Resource Inventory
|
||
|
||
### A. Always-required (every developer + integration host)
|
||
|
||
| Resource | Purpose | Type | Default port | Default credentials | Owner |
|
||
|----------|---------|------|--------------|---------------------|-------|
|
||
| **.NET 10 SDK** | Build all .NET 10 x64 projects | OS install | n/a | n/a | Developer |
|
||
| **.NET Framework 4.8 SDK + targeting pack** | Build `Driver.Galaxy.Host` (Phase 2+) | Windows install | n/a | n/a | Developer |
|
||
| **Visual Studio 2022 17.8+ or Rider 2024+** | IDE (any C# IDE works; these are the supported configs) | OS install | n/a | n/a | Developer |
|
||
| **Git** | Source control | OS install | n/a | n/a | Developer |
|
||
| **PowerShell 7.4+** | Compliance scripts (`phase-N-compliance.ps1`) | OS install | n/a | n/a | Developer |
|
||
| **Repo clones** | `lmxopcua` (this repo), `scadalink-design` (UI/auth reference per memory file `scadalink_reference.md`), `3yearplan` (handoff + corrections) | Git clone | n/a | n/a | Developer |
|
||
|
||
### B. Inner-loop dev (developer machines + PR-CI)
|
||
|
||
| Resource | Purpose | Type | Default port | Default credentials | Owner |
|
||
|----------|---------|------|--------------|---------------------|-------|
|
||
| **SQL Server 2022 dev edition** | Central config DB; integration tests against `Configuration` project | Local install OR Docker container `mcr.microsoft.com/mssql/server:2022-latest` | 1433 | `sa` / `OtOpcUaDev_2026!` (dev only — production uses Integrated Security or gMSA per decision #46) | Developer (per machine) |
|
||
| **GLAuth (LDAP server)** | Admin UI authentication tests; data-path ACL evaluation tests | Local binary at `C:\publish\glauth\` per existing CLAUDE.md | 3893 (LDAP) / 3894 (LDAPS) | Service principal: `cn=admin,dc=otopcua,dc=local` / `OtOpcUaDev_2026!`; test users defined in GLAuth config | Developer (per machine) |
|
||
| **Local dev Galaxy** (Aveva System Platform) | Galaxy driver tests; v1 IntegrationTests parity | Existing on dev box per CLAUDE.md | n/a (local COM) | Windows Auth | Developer (already present per project setup) |
|
||
|
||
### C. Integration host (one dedicated Windows machine the team shares)
|
||
|
||
| Resource | Purpose | Type | Default port | Default credentials | Owner |
|
||
|----------|---------|------|--------------|---------------------|-------|
|
||
| **Docker Desktop for Windows** | Host for containerized simulators | Install | (Hyper-V required; not compatible with TwinCAT runtime — see TwinCAT row below for the workaround) | n/a | Integration host admin |
|
||
| **`oitc/modbus-server`** | Modbus TCP simulator (per `test-data-sources.md` §1) | Docker container | 502 (Modbus TCP) | n/a (no auth in protocol) | Integration host admin |
|
||
| **`ab_server`** (libplctag binary) | AB CIP + AB Legacy simulator (per `test-data-sources.md` §2 + §3) | Native binary built from libplctag source; runs in a separate VM or host since it conflicts with Docker Desktop's Hyper-V if run on bare metal | 44818 (CIP) | n/a | Integration host admin |
|
||
| **Snap7 Server** | S7 simulator (per `test-data-sources.md` §4) | Native binary; runs in a separate VM or in WSL2 to avoid Hyper-V conflict | 102 (ISO-TCP) | n/a | Integration host admin |
|
||
| **TwinCAT XAR runtime VM** | TwinCAT ADS testing (per `test-data-sources.md` §5; Beckhoff XAR cannot coexist with Hyper-V on the same OS) | Hyper-V VM with Windows + TwinCAT XAR installed under 7-day renewable trial | 48898 (ADS over TCP) | TwinCAT default route credentials configured per Beckhoff docs | Integration host admin |
|
||
| **OPC Foundation reference server** | OPC UA Client driver test source (per `test-data-sources.md` §"OPC UA Client") | Built from `OPCFoundation/UA-.NETStandard` `ConsoleReferenceServer` project | 62541 (default for the reference server) | Anonymous + Username (`user1` / `password1`) per the reference server's built-in user list | Integration host admin |
|
||
| **FOCAS TCP stub** (`Driver.Focas.TestStub`) | FOCAS functional testing (per `test-data-sources.md` §6) | Local .NET 10 console app from this repo | 8193 (FOCAS) | n/a | Developer / integration host (run on demand) |
|
||
| **FOCAS FaultShim** (`Driver.Focas.FaultShim`) | FOCAS native-fault injection (per `test-data-sources.md` §6) | Test-only native DLL named `Fwlib64.dll`, loaded via DLL search path in the test fixture | n/a (in-process) | n/a | Developer / integration host (test-only) |
|
||
|
||
### D. Cloud / external services
|
||
|
||
| Resource | Purpose | Type | Access | Owner |
|
||
|----------|---------|------|--------|-------|
|
||
| **Gitea** at `gitea.dohertylan.com` | Hosts `lmxopcua`, `3yearplan`, `scadalink-design` repos | HTTPS git | Existing org credentials | Org IT |
|
||
| **Anthropic API** (for Codex adversarial reviews) | `/codex:adversarial-review` invocations during exit gates | HTTPS via Codex companion script | API key in developer's `~/.claude/...` config | Developer (per `codex:setup` skill) |
|
||
|
||
## Network Topology (integration host)
|
||
|
||
```
|
||
┌────────────────────────────────────────┐
|
||
│ Integration Host (Windows + Docker) │
|
||
│ │
|
||
│ Docker Desktop (Linux containers): │
|
||
│ ┌───────────────────────────────┐ │
|
||
│ │ oitc/modbus-server :502/tcp │ │
|
||
│ └───────────────────────────────┘ │
|
||
│ │
|
||
│ WSL2 (Snap7 + ab_server, separate │
|
||
│ from Docker Desktop's HyperV): │
|
||
│ ┌───────────────────────────────┐ │
|
||
│ │ snap7-server :102/tcp │ │
|
||
│ │ ab_server :44818/tcp │ │
|
||
│ └───────────────────────────────┘ │
|
||
│ │
|
||
│ Hyper-V VM (Windows + TwinCAT XAR): │
|
||
│ ┌───────────────────────────────┐ │
|
||
│ │ TwinCAT XAR :48898 │ │
|
||
│ └───────────────────────────────┘ │
|
||
│ │
|
||
│ Native processes: │
|
||
│ ┌───────────────────────────────┐ │
|
||
│ │ ConsoleReferenceServer :62541│ │
|
||
│ │ FOCAS TestStub :8193│ │
|
||
│ └───────────────────────────────┘ │
|
||
│ │
|
||
│ SQL Server 2022 (local install): │
|
||
│ ┌───────────────────────────────┐ │
|
||
│ │ OtOpcUaConfig_Test :1433 │ │
|
||
│ └───────────────────────────────┘ │
|
||
└────────────────────────────────────────┘
|
||
▲
|
||
│ tests connect via the host's hostname or 127.0.0.1
|
||
│
|
||
┌────────────────────────────────────────┐
|
||
│ Developer / CI machine running │
|
||
│ `dotnet test --filter Category=...` │
|
||
└────────────────────────────────────────┘
|
||
```
|
||
|
||
## Bootstrap Order — Inner-loop Developer Machine
|
||
|
||
Order matters because some installs have prerequisites and several need admin elevation (UAC). ~60–90 min total on a fresh Windows machine, including reboots.
|
||
|
||
**Admin elevation appears at**: WSL2 install (step 4a), Docker Desktop install (step 4b), and any `wsl --install -d` call. winget will prompt UAC interactively when these run; accept it. There is no fully-silent admin-free install path on Windows for Docker Desktop's prerequisites.
|
||
|
||
1. **Install .NET 10 SDK** (https://dotnet.microsoft.com/) — required to build anything
|
||
```powershell
|
||
winget install --id Microsoft.DotNet.SDK.10 --accept-package-agreements --accept-source-agreements
|
||
```
|
||
|
||
2. **Install .NET Framework 4.8 SDK + targeting pack** — only needed when starting Phase 2 (Galaxy.Host); skip for Phase 0–1 if not yet there
|
||
```powershell
|
||
winget install --id Microsoft.DotNet.Framework.DeveloperPack_4 --accept-package-agreements --accept-source-agreements
|
||
```
|
||
|
||
3. **Install Git + PowerShell 7.4+**
|
||
```powershell
|
||
winget install --id Git.Git --accept-package-agreements --accept-source-agreements
|
||
winget install --id Microsoft.PowerShell --accept-package-agreements --accept-source-agreements
|
||
```
|
||
|
||
4. **Install Docker Desktop** (with WSL2 backend per decision #134, leaves Hyper-V free for the future TwinCAT XAR VM):
|
||
|
||
**4a. Enable WSL2** — UAC required:
|
||
```powershell
|
||
wsl --install
|
||
```
|
||
Reboot when prompted. After reboot, the default Ubuntu distro launches and asks for a username/password — set them (these are WSL-internal, not used for Docker auth).
|
||
|
||
Verify after reboot:
|
||
```powershell
|
||
wsl --status
|
||
wsl --list --verbose
|
||
```
|
||
Expected: `Default Version: 2`, at least one distro (typically `Ubuntu`) with `STATE Running` or `Stopped`.
|
||
|
||
**4b. Install Docker Desktop** — UAC required:
|
||
```powershell
|
||
winget install --id Docker.DockerDesktop --accept-package-agreements --accept-source-agreements
|
||
```
|
||
The installer adds you to the `docker-users` Windows group. **Sign out and back in** (or reboot) so the group membership takes effect.
|
||
|
||
**4c. Configure Docker Desktop** — open it once after sign-in:
|
||
- **Settings → General**: confirm "Use the WSL 2 based engine" is **checked** (decision #134 — coexists with future Hyper-V VMs)
|
||
- **Settings → General**: confirm "Use Windows containers" is **NOT checked** (we use Linux containers for `mcr.microsoft.com/mssql/server`, `oitc/modbus-server`, etc.)
|
||
- **Settings → Resources → WSL Integration**: enable for the default Ubuntu distro
|
||
- (Optional, large fleets) **Settings → Resources → Advanced**: bump CPU / RAM allocation if you have headroom
|
||
|
||
Verify:
|
||
```powershell
|
||
docker --version
|
||
docker ps
|
||
```
|
||
Expected: version reported, `docker ps` returns an empty table (no containers running yet, but the daemon is reachable).
|
||
|
||
5. **Clone repos**:
|
||
```powershell
|
||
git clone https://gitea.dohertylan.com/dohertj2/lmxopcua.git
|
||
git clone https://gitea.dohertylan.com/dohertj2/scadalink-design.git
|
||
git clone https://gitea.dohertylan.com/dohertj2/3yearplan.git
|
||
```
|
||
|
||
6. **Start SQL Server** (Linux container; runs in the WSL2 backend):
|
||
```powershell
|
||
docker run --name otopcua-mssql `
|
||
-e "ACCEPT_EULA=Y" `
|
||
-e "MSSQL_SA_PASSWORD=OtOpcUaDev_2026!" `
|
||
-p 1433:1433 `
|
||
-v otopcua-mssql-data:/var/opt/mssql `
|
||
-d mcr.microsoft.com/mssql/server:2022-latest
|
||
```
|
||
|
||
The `-v otopcua-mssql-data:/var/opt/mssql` named volume preserves database files across container restarts and `docker rm` — drop it only if you want a strictly throwaway instance.
|
||
|
||
Verify:
|
||
```powershell
|
||
docker ps --filter name=otopcua-mssql
|
||
docker exec -it otopcua-mssql /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "OtOpcUaDev_2026!" -C -Q "SELECT @@VERSION"
|
||
```
|
||
Expected: container `STATUS Up`, `SELECT @@VERSION` returns `Microsoft SQL Server 2022 (...)`.
|
||
|
||
To stop / start later:
|
||
```powershell
|
||
docker stop otopcua-mssql
|
||
docker start otopcua-mssql
|
||
```
|
||
|
||
7. **Install GLAuth** at `C:\publish\glauth\` per existing CLAUDE.md instructions; populate `glauth-otopcua.cfg` with the test users + groups (template in `docs/v2/dev-environment-glauth-config.md` — to be added in the setup task)
|
||
|
||
8. **Install EF Core CLI** (used to apply migrations against the SQL Server container starting in Phase 1 Stream B):
|
||
```powershell
|
||
dotnet tool install --global dotnet-ef --version 10.0.*
|
||
```
|
||
|
||
9. **Run `dotnet restore`** in the `lmxopcua` repo
|
||
|
||
10. **Run `dotnet build ZB.MOM.WW.OtOpcUa.slnx`** (post-Phase-0) or `ZB.MOM.WW.LmxOpcUa.slnx` (pre-Phase-0) — verifies the toolchain
|
||
9. **Run `dotnet test`** with the inner-loop filter — should pass on a fresh machine
|
||
|
||
## Bootstrap Order — Integration Host
|
||
|
||
Order matters more here because of Hyper-V conflicts. ~half-day on a fresh machine.
|
||
|
||
1. **Install Windows Server 2022 or Windows 11 Pro** (Hyper-V capable)
|
||
2. **Enable Hyper-V** + WSL2
|
||
3. **Install Docker Desktop for Windows**, configure to use WSL2 backend (NOT Hyper-V backend — leaves Hyper-V free for the TwinCAT XAR VM)
|
||
4. **Set up WSL2 distro** (Ubuntu 22.04 LTS) for native Linux binaries that conflict with Docker Desktop
|
||
5. **Pull / start Modbus simulator**:
|
||
```powershell
|
||
docker run -d --name modbus-sim -p 502:502 -v ${PWD}/modbus-config.yaml:/server_config.yaml oitc/modbus-server
|
||
```
|
||
6. **Build + start ab_server** (in WSL2):
|
||
```bash
|
||
git clone https://github.com/libplctag/libplctag
|
||
cd libplctag/src/tests
|
||
make ab_server
|
||
./ab_server --plc=ControlLogix --port=44818 # default tags loaded from a config file
|
||
```
|
||
7. **Build + start Snap7 Server** (in WSL2):
|
||
- Download Snap7 from https://snap7.sourceforge.net/
|
||
- Build the example server; run on port 102 with the test DB layout from `test-data-sources.md` §4
|
||
8. **Set up TwinCAT XAR VM**:
|
||
- Create a Hyper-V VM (Gen 2, Windows 11)
|
||
- Install TwinCAT 3 XAE + XAR (download from Beckhoff, free for dev/test)
|
||
- Activate the 7-day trial; document the rotation schedule
|
||
- Configure ADS routes for the integration host to reach the VM
|
||
- Deploy the test PLC project from `test-data-sources.md` §5 ("a tiny test project — `MAIN` (PLC code) + `GVL`")
|
||
9. **Build + start OPC Foundation reference server**:
|
||
```bash
|
||
git clone https://github.com/OPCFoundation/UA-.NETStandard
|
||
cd UA-.NETStandard/Applications/ConsoleReferenceServer
|
||
dotnet run --port 62541
|
||
```
|
||
10. **Install SQL Server 2022 dev edition** (or run the Docker container as on developer machines)
|
||
11. **Build + run FOCAS TestStub** (from this repo, post-Phase-5):
|
||
```powershell
|
||
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Driver.Focas.TestStub -- --port 8193
|
||
```
|
||
12. **Verify** by running `dotnet test --filter Category=Integration` from a developer machine pointed at the integration host
|
||
|
||
## Credential Management
|
||
|
||
### Dev environment defaults
|
||
|
||
The defaults in this doc are **for dev environments only**. They're documented here so a developer can stand up a working setup without hunting; they're not secret.
|
||
|
||
### Production overrides
|
||
|
||
For any production deployment:
|
||
- SQL Server: Integrated Security with gMSA (decision #46) — never SQL login with shared password
|
||
- LDAP: production GLAuth or AD instance with proper service principal
|
||
- TwinCAT: paid license (per-runtime), not the 7-day trial
|
||
- All other services: deployment-team's credential management process; documented in deployment-guide.md (separate doc, post-v2.0)
|
||
|
||
### Storage
|
||
|
||
For dev defaults:
|
||
- SQL Server SA password: stored in each developer's local `appsettings.Development.json` (gitignored)
|
||
- GLAuth bind DN/password: stored in `glauth-otopcua.cfg` (gitignored)
|
||
- Docker secrets / volumes: developer-local
|
||
|
||
For production:
|
||
- gMSA / cert-mapped principals — no passwords stored anywhere
|
||
- Per-NodeId credentials in `ClusterNodeCredential` table (per decision #83)
|
||
- Admin app uses LDAP (no SQL credential at all on the user-facing side)
|
||
|
||
## Test Data Seed
|
||
|
||
Each environment needs a baseline data set so cross-developer tests are reproducible. Lives in `tests/ZB.MOM.WW.OtOpcUa.IntegrationTests/SeedData/`:
|
||
|
||
- **GLAuth** users: `test-readonly@otopcua.local` (in `OtOpcUaReadOnly`), `test-operator@otopcua.local` (`OtOpcUaWriteOperate` + `OtOpcUaAlarmAck`), `test-fleetadmin@otopcua.local` (`OtOpcUaAdmins`)
|
||
- **Central config DB**: a seed cluster `TEST-CLUSTER-01` with 1 node + 1 namespace + 0 drivers (other tests add drivers)
|
||
- **Modbus sim**: YAML config preloading the addresses from `test-data-sources.md` §1 (HR 0–9 constants, ramp at HR 100, etc.)
|
||
- **TwinCAT XAR**: the test PLC project deployed; symbols match `test-data-sources.md` §5
|
||
- **OPC Foundation reference server**: starts with built-in test address space; tests don't modify it
|
||
|
||
Seeds are idempotent (re-runnable) and gitignored where they contain credentials.
|
||
|
||
## Setup Plan (executable)
|
||
|
||
### Step 1 — Inner-loop dev environment (each developer, ~1 day with documentation)
|
||
|
||
**Owner**: developer
|
||
**Prerequisite**: Bootstrap order steps 1–10 above (note: steps 4a, 4b, and any later `wsl --install -d` call require admin elevation / UAC interaction — there is no fully-silent admin-free install path on Windows for Docker Desktop's prerequisites)
|
||
**Acceptance**:
|
||
- `dotnet test ZB.MOM.WW.OtOpcUa.slnx` passes
|
||
- A test that touches the central config DB succeeds (proves SQL Server reachable)
|
||
- A test that authenticates against GLAuth succeeds (proves LDAP reachable)
|
||
- `docker ps --filter name=otopcua-mssql` shows the SQL Server container `STATUS Up`
|
||
|
||
### Troubleshooting (common Windows install snags)
|
||
|
||
- **`wsl --install` says "Windows Subsystem for Linux has no installed distributions"** after first reboot — open a fresh PowerShell and run `wsl --install -d Ubuntu` (the `-d` form forces a distro install if the prereq-only install ran first).
|
||
- **Docker Desktop install completes but `docker --version` reports "command not found"** — `PATH` doesn't pick up the new Docker shims until a new shell is opened. Open a fresh PowerShell, or sign out/in, and retry.
|
||
- **`docker ps` reports "permission denied" or "Cannot connect to the Docker daemon"** — your user account isn't in the `docker-users` group yet. Sign out and back in (group membership is loaded at login). Verify with `whoami /groups | findstr docker-users`.
|
||
- **Docker Desktop refuses to start with "WSL 2 installation is incomplete"** — open the WSL2 kernel update from https://aka.ms/wsl2kernel, install, then restart Docker Desktop. (Modern `wsl --install` ships the kernel automatically; this is mostly a legacy problem.)
|
||
- **SQL Server container starts but immediately exits** — SA password complexity. The default `OtOpcUaDev_2026!` meets the requirement (≥8 chars, upper + lower + digit + symbol); if you change it, keep complexity. Check `docker logs otopcua-mssql` for the exact failure.
|
||
- **`docker run` fails with "image platform does not match host platform"** — your Docker is configured for Windows containers. Switch to Linux containers in Docker Desktop tray menu ("Switch to Linux containers"), or recheck Settings → General per step 4c.
|
||
- **Hyper-V conflict when later setting up TwinCAT XAR VM** — confirm Docker Desktop is on the **WSL 2 backend**, not Hyper-V backend. The two coexist only when Docker uses WSL 2.
|
||
|
||
### Step 2 — Integration host (one-time, ~1 week)
|
||
|
||
**Owner**: DevOps lead
|
||
**Prerequisite**: dedicated Windows machine, hardware specs ≥ 8 cores / 32 GB RAM / 500 GB SSD
|
||
**Acceptance**:
|
||
- Each simulator (Modbus, AB, S7, TwinCAT, OPC UA reference) responds to a probe from a developer machine
|
||
- A nightly CI job runs `dotnet test --filter Category=Integration` against the integration host and passes
|
||
- Service-account permissions reviewed by security lead
|
||
|
||
### Step 3 — TwinCAT XAR VM trial rotation automation (one-time, half-day)
|
||
|
||
**Owner**: DevOps lead
|
||
**Prerequisite**: Step 2 complete
|
||
**Acceptance**:
|
||
- A scheduled task on the integration host either re-activates the 7-day trial automatically OR alerts the team 24h before expiry; cycle tested
|
||
|
||
### Step 4 — Per-developer GLAuth config sync (recurring, when test users change)
|
||
|
||
**Owner**: developer (each)
|
||
**Acceptance**:
|
||
- A script in the repo (`scripts/sync-glauth-dev-config.ps1`) updates the local GLAuth config from a template; documented in CLAUDE.md
|
||
- Test users defined in the template work on every developer machine
|
||
|
||
### Step 5 — Docker simulator config (per-developer, ~30 min)
|
||
|
||
**Owner**: developer (each)
|
||
**Acceptance**:
|
||
- The Modbus simulator container is reachable from `127.0.0.1:502` from the developer's test runner (only needed if the developer is debugging Modbus driver work; not required for Phase 0/1)
|
||
|
||
### Step 6 — Codex companion setup (per-developer, ~5 min)
|
||
|
||
**Owner**: developer (each)
|
||
**Acceptance**:
|
||
- `/codex:setup` skill confirms readiness; `/codex:adversarial-review` works against a small test diff
|
||
|
||
## Operational Risks
|
||
|
||
| Risk | Mitigation |
|
||
|------|------------|
|
||
| TwinCAT 7-day trial expires mid-CI run | Step 3 automation; alert before expiry; license budget approved as fallback for production-grade pre-release validation |
|
||
| Docker Desktop license terms change for org use | Track Docker pricing; budget approved or fall back to Podman if license becomes blocking |
|
||
| Integration host single point of failure | Document the setup so a second host can be provisioned in <2 days; test fixtures pin to a hostname so failover changes one DNS entry |
|
||
| GLAuth dev config drifts between developers | Sync script + template (Step 4) keep configs aligned; periodic review |
|
||
| Galaxy / MXAccess licensing for non-dev-machine | Galaxy stays on the dev machines that already have Aveva licenses; integration host does NOT run Galaxy (Galaxy.Host integration tests run on the dev box, not the shared host) |
|
||
| Long-lived dev env credentials in dev `appsettings.Development.json` | Gitignored; documented as dev-only; production never uses these |
|
||
|
||
## Decisions to Add to plan.md
|
||
|
||
| # | Decision | Rationale |
|
||
|---|----------|-----------|
|
||
| 133 | Two-tier dev environment: inner-loop (in-process simulators on developer machines) + integration (Docker / VM / native simulators on a single dedicated Windows host) | Per decision #99. Concrete inventory + setup plan in `dev-environment.md` |
|
||
| 134 | Docker Desktop with WSL2 backend (not Hyper-V backend) on integration host so TwinCAT XAR VM can run in Hyper-V alongside Docker | TwinCAT runtime cannot coexist with Hyper-V-mode Docker Desktop; WSL2 backend leaves Hyper-V free for the XAR VM. Documented operational constraint |
|
||
| 135 | TwinCAT XAR runs only in a dedicated VM on the integration host; developer machines do NOT run XAR locally | The 7-day trial reactivation needs centralized management; the VM is shared infrastructure |
|
||
| 136 | Galaxy / MXAccess testing happens on developer machines that have local Aveva installs, NOT on the shared integration host | Aveva licensing scoped to dev workstations; integration host doesn't carry the license. v1 IntegrationTests parity (Phase 2) runs on developer boxes. |
|
||
| 137 | Dev env credentials are documented openly in `dev-environment.md`; production credentials use Integrated Security / gMSA per decision #46 | Dev defaults are not secrets; they're convenience. Production never uses these values |
|