Task #220 — AB CIP + S7 live-boot verification (5/5 stages each) #222

Merged
dohertj2 merged 1 commits from task-220-exitgate-abcip-s7 into v2 2026-04-21 12:04:53 -04:00
Owner

Closes #220.

Replicated the Modbus bring-up from #218 against the AB CIP + S7 seeds shipped in #217. Both pass 5/5 e2e stages with the #221 AnonymousRoles=[WriteOperate] knob.

AB CIP (ab_server controllogix fixture, port 44818)

=== AB CIP e2e summary: 5/5 passed ===
[PASS] Probe
[PASS] Driver loopback
[PASS] Server bridge             (driver → server → client)
[PASS] OPC UA write bridge       (client → server → driver)
[PASS] Subscribe sees change

S7 (python-snap7 s7_1500 fixture, port 1102)

=== S7 e2e summary: 5/5 passed ===
[PASS] Probe
[PASS] Driver loopback
[PASS] Server bridge
[PASS] OPC UA write bridge
[PASS] Subscribe sees change

Seed fixes

Bring-up exposed two papercuts when applying seeds in sequence; all four seed scripts now include:

  1. Global SA-credential delete before the per-cluster INSERT. UX_ClusterNodeCredential_Value is a unique index on (Kind, Value) WHERE Enabled=1sa can only bind to one node at a time, so applying AbCip after Modbus was hitting Cannot insert duplicate key. Production deployments using non-SA logins aren't affected.

  2. DashboardPort 5000 → 15050. HttpListener rejects :5000 on Windows without a netsh http add urlacl grant or admin rights. 15050 is unreserved + loopback-safe.

AB Legacy

Factory + seed ship ready; live-boot is blocked on real hardware (#222 — ab_server PCCC dispatcher is upstream-broken). The DELETE + DashboardPort fixes still land here so the sql applies when hardware arrives.

Test plan

  • AB CIP live boot 5/5
  • S7 live boot 5/5
  • Modbus regression re-verified earlier (#221 same config works)
  • AB Legacy — blocked on #222
Closes #220. Replicated the Modbus bring-up from #218 against the AB CIP + S7 seeds shipped in #217. Both pass 5/5 e2e stages with the #221 `AnonymousRoles=[WriteOperate]` knob. ## AB CIP (ab_server controllogix fixture, port 44818) ``` === AB CIP e2e summary: 5/5 passed === [PASS] Probe [PASS] Driver loopback [PASS] Server bridge (driver → server → client) [PASS] OPC UA write bridge (client → server → driver) [PASS] Subscribe sees change ``` ## S7 (python-snap7 s7_1500 fixture, port 1102) ``` === S7 e2e summary: 5/5 passed === [PASS] Probe [PASS] Driver loopback [PASS] Server bridge [PASS] OPC UA write bridge [PASS] Subscribe sees change ``` ## Seed fixes Bring-up exposed two papercuts when applying seeds in sequence; all four seed scripts now include: 1. **Global SA-credential delete** before the per-cluster INSERT. `UX_ClusterNodeCredential_Value` is a unique index on `(Kind, Value) WHERE Enabled=1` — `sa` can only bind to one node at a time, so applying AbCip after Modbus was hitting `Cannot insert duplicate key`. Production deployments using non-SA logins aren't affected. 2. **DashboardPort 5000 → 15050.** `HttpListener` rejects :5000 on Windows without a `netsh http add urlacl` grant or admin rights. 15050 is unreserved + loopback-safe. ## AB Legacy Factory + seed ship ready; live-boot is blocked on real hardware (#222 — ab_server PCCC dispatcher is upstream-broken). The DELETE + DashboardPort fixes still land here so the sql applies when hardware arrives. ## Test plan - [x] AB CIP live boot 5/5 - [x] S7 live boot 5/5 - [x] Modbus regression re-verified earlier (#221 same config works) - [ ] AB Legacy — blocked on #222
dohertj2 added 1 commit 2026-04-21 12:04:49 -04:00
Replicated the Modbus #218 bring-up against the AB CIP + S7 seeds to
confirm the factories + seeds shipped in #217 actually work end-to-end.
Both pass 5/5 e2e stages with `OpcUaServer:AnonymousRoles=[WriteOperate]`
(the #221 knob).

## AB CIP (against ab_server controllogix fixture, port 44818)

```
=== AB CIP e2e summary: 5/5 passed ===
[PASS] Probe
[PASS] Driver loopback
[PASS] Server bridge           (driver → server → client)
[PASS] OPC UA write bridge     (client → server → driver)
[PASS] Subscribe sees change
```

Server log: `DriverInstance abcip-smoke-drv (AbCip) registered +
initialized` ✓.

## S7 (against python-snap7 s7_1500 fixture, port 1102)

```
=== S7 e2e summary: 5/5 passed ===
[PASS] Probe
[PASS] Driver loopback
[PASS] Server bridge
[PASS] OPC UA write bridge
[PASS] Subscribe sees change
```

Server log: `DriverInstance s7-smoke-drv (S7) registered + initialized` ✓.

## Seed fixes so bring-up is idempotent

Live-boot exposed two seed-level papercuts when applying multiple
smoke seeds in sequence:

1. **SA credential collision.** `UX_ClusterNodeCredential_Value` is a
   unique index on `(Kind, Value) WHERE Enabled=1`, so `sa` can only
   bind to one node at a time. Each seed's DELETE block only dropped
   the credential tied to ITS node — seeding AbCip after Modbus blew
   up with `Cannot insert duplicate key` on the sa binding. Added a
   global `DELETE FROM dbo.ClusterNodeCredential WHERE Kind='SqlLogin'
   AND Value='sa'` before the per-cluster INSERTs. Production deployments
   using non-SA logins aren't affected.

2. **DashboardPort 5000 → 15050.** `HealthEndpointsHost` uses
   `HttpListener`, which rejects port 5000 on Windows without a
   `netsh http add urlacl` grant or admin rights. 15050 is unreserved
   + loopback-safe per the HealthEndpointsHost remarks. Applied to all
   four smoke seeds (Modbus was patched at runtime in #218; now baked
   into the seed).

## AB Legacy status

Not live-boot verified — ab_server PCCC dispatcher is upstream-broken
(#222). The factory + seed ship ready for hardware; the seed's DELETE
+ DashboardPort fixes land in this PR so when real SLC/MicroLogix/PLC-5
arrives the sql just applies.

## Closes #220

Umbrella #209 was already closed; #220 was the final child.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit e1f172c053 into v2 2026-04-21 12:04:53 -04:00
dohertj2 deleted branch task-220-exitgate-abcip-s7 2026-04-21 12:04:53 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#222