@elaraai/e3-rack 0.0.0-bootstrap.0 → 1.0.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +407 -2
- package/dist/src/client/client.spec.d.ts +6 -0
- package/dist/src/client/client.spec.d.ts.map +1 -0
- package/dist/src/client/client.spec.js +150 -0
- package/dist/src/client/client.spec.js.map +1 -0
- package/dist/src/client/connect.d.ts +52 -0
- package/dist/src/client/connect.d.ts.map +1 -0
- package/dist/src/client/connect.js +112 -0
- package/dist/src/client/connect.js.map +1 -0
- package/dist/src/client/hub-client.d.ts +57 -0
- package/dist/src/client/hub-client.d.ts.map +1 -0
- package/dist/src/client/hub-client.js +87 -0
- package/dist/src/client/hub-client.js.map +1 -0
- package/dist/src/client/local-http.d.ts +78 -0
- package/dist/src/client/local-http.d.ts.map +1 -0
- package/dist/src/client/local-http.js +149 -0
- package/dist/src/client/local-http.js.map +1 -0
- package/dist/src/client/session-attempts.d.ts +20 -0
- package/dist/src/client/session-attempts.d.ts.map +1 -0
- package/dist/src/client/session-attempts.js +88 -0
- package/dist/src/client/session-attempts.js.map +1 -0
- package/dist/src/client/session-data-server.d.ts +37 -0
- package/dist/src/client/session-data-server.d.ts.map +1 -0
- package/dist/src/client/session-data-server.js +280 -0
- package/dist/src/client/session-data-server.js.map +1 -0
- package/dist/src/client/session-data-server.spec.d.ts +6 -0
- package/dist/src/client/session-data-server.spec.d.ts.map +1 -0
- package/dist/src/client/session-data-server.spec.js +192 -0
- package/dist/src/client/session-data-server.spec.js.map +1 -0
- package/dist/src/client/session.d.ts +119 -0
- package/dist/src/client/session.d.ts.map +1 -0
- package/dist/src/client/session.js +290 -0
- package/dist/src/client/session.js.map +1 -0
- package/dist/src/hub/config.d.ts +74 -0
- package/dist/src/hub/config.d.ts.map +1 -0
- package/dist/src/hub/config.js +159 -0
- package/dist/src/hub/config.js.map +1 -0
- package/dist/src/hub/fair-lease-store.d.ts +36 -0
- package/dist/src/hub/fair-lease-store.d.ts.map +1 -0
- package/dist/src/hub/fair-lease-store.js +73 -0
- package/dist/src/hub/fair-lease-store.js.map +1 -0
- package/dist/src/hub/hub.d.ts +91 -0
- package/dist/src/hub/hub.d.ts.map +1 -0
- package/dist/src/hub/hub.js +641 -0
- package/dist/src/hub/hub.js.map +1 -0
- package/dist/src/hub/hub.spec.d.ts +6 -0
- package/dist/src/hub/hub.spec.d.ts.map +1 -0
- package/dist/src/hub/hub.spec.js +363 -0
- package/dist/src/hub/hub.spec.js.map +1 -0
- package/dist/src/hub/infrastructure.spec.d.ts +6 -0
- package/dist/src/hub/infrastructure.spec.d.ts.map +1 -0
- package/dist/src/hub/infrastructure.spec.js +211 -0
- package/dist/src/hub/infrastructure.spec.js.map +1 -0
- package/dist/src/hub/lock.d.ts +62 -0
- package/dist/src/hub/lock.d.ts.map +1 -0
- package/dist/src/hub/lock.js +165 -0
- package/dist/src/hub/lock.js.map +1 -0
- package/dist/src/hub/main.d.ts +16 -0
- package/dist/src/hub/main.d.ts.map +1 -0
- package/dist/src/hub/main.js +56 -0
- package/dist/src/hub/main.js.map +1 -0
- package/dist/src/hub/session-bridge.d.ts +116 -0
- package/dist/src/hub/session-bridge.d.ts.map +1 -0
- package/dist/src/hub/session-bridge.js +336 -0
- package/dist/src/hub/session-bridge.js.map +1 -0
- package/dist/src/identity/file-identity-store.d.ts +18 -0
- package/dist/src/identity/file-identity-store.d.ts.map +1 -0
- package/dist/src/identity/file-identity-store.js +34 -0
- package/dist/src/identity/file-identity-store.js.map +1 -0
- package/dist/src/identity/file-identity-store.spec.d.ts +6 -0
- package/dist/src/identity/file-identity-store.spec.d.ts.map +1 -0
- package/dist/src/identity/file-identity-store.spec.js +59 -0
- package/dist/src/identity/file-identity-store.spec.js.map +1 -0
- package/dist/src/identity/in-memory-identity-store.d.ts +48 -0
- package/dist/src/identity/in-memory-identity-store.d.ts.map +1 -0
- package/dist/src/identity/in-memory-identity-store.js +102 -0
- package/dist/src/identity/in-memory-identity-store.js.map +1 -0
- package/dist/src/identity/machine-identity.d.ts +134 -0
- package/dist/src/identity/machine-identity.d.ts.map +1 -0
- package/dist/src/identity/machine-identity.js +65 -0
- package/dist/src/identity/machine-identity.js.map +1 -0
- package/dist/src/index.d.ts +34 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +34 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lease/closure.d.ts +96 -0
- package/dist/src/lease/closure.d.ts.map +1 -0
- package/dist/src/lease/closure.js +192 -0
- package/dist/src/lease/closure.js.map +1 -0
- package/dist/src/lease/closure.spec.d.ts +6 -0
- package/dist/src/lease/closure.spec.d.ts.map +1 -0
- package/dist/src/lease/closure.spec.js +35 -0
- package/dist/src/lease/closure.spec.js.map +1 -0
- package/dist/src/lease/coordinator.d.ts +34 -0
- package/dist/src/lease/coordinator.d.ts.map +1 -0
- package/dist/src/lease/coordinator.js +42 -0
- package/dist/src/lease/coordinator.js.map +1 -0
- package/dist/src/lease/in-memory-lease-store.d.ts +58 -0
- package/dist/src/lease/in-memory-lease-store.d.ts.map +1 -0
- package/dist/src/lease/in-memory-lease-store.js +132 -0
- package/dist/src/lease/in-memory-lease-store.js.map +1 -0
- package/dist/src/lease/lease-store.d.ts +169 -0
- package/dist/src/lease/lease-store.d.ts.map +1 -0
- package/dist/src/lease/lease-store.js +94 -0
- package/dist/src/lease/lease-store.js.map +1 -0
- package/dist/src/lease/lease-store.spec.d.ts +6 -0
- package/dist/src/lease/lease-store.spec.d.ts.map +1 -0
- package/dist/src/lease/lease-store.spec.js +8 -0
- package/dist/src/lease/lease-store.spec.js.map +1 -0
- package/dist/src/lease/rack-dispatch.d.ts +105 -0
- package/dist/src/lease/rack-dispatch.d.ts.map +1 -0
- package/dist/src/lease/rack-dispatch.js +6 -0
- package/dist/src/lease/rack-dispatch.js.map +1 -0
- package/dist/src/mutation-queue.d.ts +13 -0
- package/dist/src/mutation-queue.d.ts.map +1 -0
- package/dist/src/mutation-queue.js +17 -0
- package/dist/src/mutation-queue.js.map +1 -0
- package/dist/src/paths.d.ts +56 -0
- package/dist/src/paths.d.ts.map +1 -0
- package/dist/src/paths.js +82 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/protocol/control.d.ts +295 -0
- package/dist/src/protocol/control.d.ts.map +1 -0
- package/dist/src/protocol/control.js +74 -0
- package/dist/src/protocol/control.js.map +1 -0
- package/dist/src/protocol/index.d.ts +9 -0
- package/dist/src/protocol/index.d.ts.map +1 -0
- package/dist/src/protocol/index.js +9 -0
- package/dist/src/protocol/index.js.map +1 -0
- package/dist/src/protocol/rack-wire.d.ts +357 -0
- package/dist/src/protocol/rack-wire.d.ts.map +1 -0
- package/dist/src/protocol/rack-wire.js +262 -0
- package/dist/src/protocol/rack-wire.js.map +1 -0
- package/dist/src/protocol/rack-wire.spec.d.ts +6 -0
- package/dist/src/protocol/rack-wire.spec.d.ts.map +1 -0
- package/dist/src/protocol/rack-wire.spec.js +14 -0
- package/dist/src/protocol/rack-wire.spec.js.map +1 -0
- package/dist/src/protocol/registration.d.ts +70 -0
- package/dist/src/protocol/registration.d.ts.map +1 -0
- package/dist/src/protocol/registration.js +67 -0
- package/dist/src/protocol/registration.js.map +1 -0
- package/dist/src/protocol/session-data.d.ts +69 -0
- package/dist/src/protocol/session-data.d.ts.map +1 -0
- package/dist/src/protocol/session-data.js +26 -0
- package/dist/src/protocol/session-data.js.map +1 -0
- package/dist/src/protocol/task-envelope.d.ts +198 -0
- package/dist/src/protocol/task-envelope.d.ts.map +1 -0
- package/dist/src/protocol/task-envelope.js +93 -0
- package/dist/src/protocol/task-envelope.js.map +1 -0
- package/dist/src/protocol/wire-golden.d.ts +8 -0
- package/dist/src/protocol/wire-golden.d.ts.map +1 -0
- package/dist/src/protocol/wire-golden.js +34 -0
- package/dist/src/protocol/wire-golden.js.map +1 -0
- package/dist/src/protocol/wire-samples.d.ts +11 -0
- package/dist/src/protocol/wire-samples.d.ts.map +1 -0
- package/dist/src/protocol/wire-samples.js +52 -0
- package/dist/src/protocol/wire-samples.js.map +1 -0
- package/dist/src/registry/file-rack-registry.d.ts +68 -0
- package/dist/src/registry/file-rack-registry.d.ts.map +1 -0
- package/dist/src/registry/file-rack-registry.js +138 -0
- package/dist/src/registry/file-rack-registry.js.map +1 -0
- package/dist/src/registry/file-rack-registry.spec.d.ts +6 -0
- package/dist/src/registry/file-rack-registry.spec.d.ts.map +1 -0
- package/dist/src/registry/file-rack-registry.spec.js +50 -0
- package/dist/src/registry/file-rack-registry.spec.js.map +1 -0
- package/dist/src/registry/rack-registry.d.ts +64 -0
- package/dist/src/registry/rack-registry.d.ts.map +1 -0
- package/dist/src/registry/rack-registry.js +65 -0
- package/dist/src/registry/rack-registry.js.map +1 -0
- package/dist/src/registry/rack-registry.spec.d.ts +6 -0
- package/dist/src/registry/rack-registry.spec.d.ts.map +1 -0
- package/dist/src/registry/rack-registry.spec.js +8 -0
- package/dist/src/registry/rack-registry.spec.js.map +1 -0
- package/dist/src/routing/eligibility.d.ts +38 -0
- package/dist/src/routing/eligibility.d.ts.map +1 -0
- package/dist/src/routing/eligibility.js +78 -0
- package/dist/src/routing/eligibility.js.map +1 -0
- package/dist/src/routing/host-coupling.d.ts +26 -0
- package/dist/src/routing/host-coupling.d.ts.map +1 -0
- package/dist/src/routing/host-coupling.js +62 -0
- package/dist/src/routing/host-coupling.js.map +1 -0
- package/dist/src/routing/policy.d.ts +188 -0
- package/dist/src/routing/policy.d.ts.map +1 -0
- package/dist/src/routing/policy.js +212 -0
- package/dist/src/routing/policy.js.map +1 -0
- package/dist/src/routing/routing.spec.d.ts +6 -0
- package/dist/src/routing/routing.spec.d.ts.map +1 -0
- package/dist/src/routing/routing.spec.js +100 -0
- package/dist/src/routing/routing.spec.js.map +1 -0
- package/dist/src/routing/tiers.d.ts +22 -0
- package/dist/src/routing/tiers.d.ts.map +1 -0
- package/dist/src/routing/tiers.js +26 -0
- package/dist/src/routing/tiers.js.map +1 -0
- package/dist/src/runner/api-server.d.ts +45 -0
- package/dist/src/runner/api-server.d.ts.map +1 -0
- package/dist/src/runner/api-server.js +21 -0
- package/dist/src/runner/api-server.js.map +1 -0
- package/dist/src/runner/capacity.d.ts +13 -0
- package/dist/src/runner/capacity.d.ts.map +1 -0
- package/dist/src/runner/capacity.js +18 -0
- package/dist/src/runner/capacity.js.map +1 -0
- package/dist/src/runner/rack-body.d.ts +43 -0
- package/dist/src/runner/rack-body.d.ts.map +1 -0
- package/dist/src/runner/rack-body.js +208 -0
- package/dist/src/runner/rack-body.js.map +1 -0
- package/dist/src/runner/rack-runner.d.ts +62 -0
- package/dist/src/runner/rack-runner.d.ts.map +1 -0
- package/dist/src/runner/rack-runner.js +75 -0
- package/dist/src/runner/rack-runner.js.map +1 -0
- package/dist/src/runner/rack-runner.spec.d.ts +6 -0
- package/dist/src/runner/rack-runner.spec.d.ts.map +1 -0
- package/dist/src/runner/rack-runner.spec.js +302 -0
- package/dist/src/runner/rack-runner.spec.js.map +1 -0
- package/dist/src/runner/split.spec.d.ts +6 -0
- package/dist/src/runner/split.spec.d.ts.map +1 -0
- package/dist/src/runner/split.spec.js +188 -0
- package/dist/src/runner/split.spec.js.map +1 -0
- package/dist/src/runner-event.d.ts +261 -0
- package/dist/src/runner-event.d.ts.map +1 -0
- package/dist/src/runner-event.js +332 -0
- package/dist/src/runner-event.js.map +1 -0
- package/dist/src/server/beast2.d.ts +19 -0
- package/dist/src/server/beast2.d.ts.map +1 -0
- package/dist/src/server/beast2.js +18 -0
- package/dist/src/server/beast2.js.map +1 -0
- package/dist/src/server/body-limit.d.ts +16 -0
- package/dist/src/server/body-limit.d.ts.map +1 -0
- package/dist/src/server/body-limit.js +53 -0
- package/dist/src/server/body-limit.js.map +1 -0
- package/dist/src/server/body-limit.spec.d.ts +2 -0
- package/dist/src/server/body-limit.spec.d.ts.map +1 -0
- package/dist/src/server/body-limit.spec.js +32 -0
- package/dist/src/server/body-limit.spec.js.map +1 -0
- package/dist/src/server/bounded.d.ts +16 -0
- package/dist/src/server/bounded.d.ts.map +1 -0
- package/dist/src/server/bounded.js +39 -0
- package/dist/src/server/bounded.js.map +1 -0
- package/dist/src/server/dispatch.d.ts +137 -0
- package/dist/src/server/dispatch.d.ts.map +1 -0
- package/dist/src/server/dispatch.js +267 -0
- package/dist/src/server/dispatch.js.map +1 -0
- package/dist/src/server/env-publication.d.ts +45 -0
- package/dist/src/server/env-publication.d.ts.map +1 -0
- package/dist/src/server/env-publication.js +10 -0
- package/dist/src/server/env-publication.js.map +1 -0
- package/dist/src/server/index.d.ts +16 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +17 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/protocol.spec.d.ts +6 -0
- package/dist/src/server/protocol.spec.d.ts.map +1 -0
- package/dist/src/server/protocol.spec.js +78 -0
- package/dist/src/server/protocol.spec.js.map +1 -0
- package/dist/src/server/rack-routes.d.ts +175 -0
- package/dist/src/server/rack-routes.d.ts.map +1 -0
- package/dist/src/server/rack-routes.js +755 -0
- package/dist/src/server/rack-routes.js.map +1 -0
- package/dist/src/server/rack-routes.spec.d.ts +6 -0
- package/dist/src/server/rack-routes.spec.d.ts.map +1 -0
- package/dist/src/server/rack-routes.spec.js +477 -0
- package/dist/src/server/rack-routes.spec.js.map +1 -0
- package/dist/src/server/storage-bridge.d.ts +140 -0
- package/dist/src/server/storage-bridge.d.ts.map +1 -0
- package/dist/src/server/storage-bridge.js +6 -0
- package/dist/src/server/storage-bridge.js.map +1 -0
- package/dist/src/state-file.d.ts +10 -0
- package/dist/src/state-file.d.ts.map +1 -0
- package/dist/src/state-file.js +38 -0
- package/dist/src/state-file.js.map +1 -0
- package/dist/src/testing/in-memory.d.ts +116 -0
- package/dist/src/testing/in-memory.d.ts.map +1 -0
- package/dist/src/testing/in-memory.js +193 -0
- package/dist/src/testing/in-memory.js.map +1 -0
- package/dist/src/testing/index.d.ts +14 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +14 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/lease-store-contract.d.ts +14 -0
- package/dist/src/testing/lease-store-contract.d.ts.map +1 -0
- package/dist/src/testing/lease-store-contract.js +78 -0
- package/dist/src/testing/lease-store-contract.js.map +1 -0
- package/dist/src/testing/protocol-suite.d.ts +38 -0
- package/dist/src/testing/protocol-suite.d.ts.map +1 -0
- package/dist/src/testing/protocol-suite.js +207 -0
- package/dist/src/testing/protocol-suite.js.map +1 -0
- package/dist/src/testing/rack-registry-contract.d.ts +15 -0
- package/dist/src/testing/rack-registry-contract.d.ts.map +1 -0
- package/dist/src/testing/rack-registry-contract.js +106 -0
- package/dist/src/testing/rack-registry-contract.js.map +1 -0
- package/dist/src/testing/test-rack-agent.d.ts +121 -0
- package/dist/src/testing/test-rack-agent.d.ts.map +1 -0
- package/dist/src/testing/test-rack-agent.js +316 -0
- package/dist/src/testing/test-rack-agent.js.map +1 -0
- package/dist/src/tls/tls.d.ts +67 -0
- package/dist/src/tls/tls.d.ts.map +1 -0
- package/dist/src/tls/tls.js +200 -0
- package/dist/src/tls/tls.js.map +1 -0
- package/dist/src/tls/tls.spec.d.ts +6 -0
- package/dist/src/tls/tls.spec.d.ts.map +1 -0
- package/dist/src/tls/tls.spec.js +101 -0
- package/dist/src/tls/tls.spec.js.map +1 -0
- package/dist/src/version.d.ts +9 -0
- package/dist/src/version.d.ts.map +1 -0
- package/dist/src/version.js +10 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +67 -7
package/README.md
CHANGED
|
@@ -1,5 +1,410 @@
|
|
|
1
1
|
# @elaraai/e3-rack
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Delegate eligible task bodies from a local e3 repository to a rack agent. The
|
|
4
|
+
local process still plans the graph, checks caches and owns the repository.
|
|
5
|
+
One hub per operating-system user coordinates the rack fleet across projects.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
## Connect a rack
|
|
8
|
+
|
|
9
|
+
A rack reaches this machine's hub over HTTPS. The hub serves its rack listener
|
|
10
|
+
with its own certificate, made the first time the listener serves TLS, and every
|
|
11
|
+
rack pins that certificate by its SHA-256 fingerprint. No certificate authority
|
|
12
|
+
or DNS name is involved, so the rack can reach the hub through any relay, and a
|
|
13
|
+
relay or tunnel in between forwards bytes it cannot read.
|
|
14
|
+
|
|
15
|
+
The usual path is an SSH reverse tunnel. The hub listens on the loopback only;
|
|
16
|
+
this machine keeps a tunnel open to a relay that the rack can reach, for
|
|
17
|
+
example `ssh -N -R 7401:127.0.0.1:7331 relay`, and nothing connects into this
|
|
18
|
+
machine directly:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
e3 rack enroll --listen 127.0.0.1:7331 --allow 127.0.0.1 \
|
|
22
|
+
--advertise-url https://relay.example:7401 --label workshop
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
On a private network the rack can connect to the hub directly instead:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
e3 rack enroll --listen 10.0.0.5:7331 --label workshop
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This starts the hub and prints the **source origin**, the hub's **certificate
|
|
32
|
+
SHA-256**, the matching e3-rack release and a short-lived single-use enrollment
|
|
33
|
+
token. The source origin is how the rack reaches this machine: the
|
|
34
|
+
`--advertise-url`, or the listener's own address when none is set. It is not a
|
|
35
|
+
repository URL or the rack server's address; `localhost` on the rack would point
|
|
36
|
+
back at the worker itself. Keep the hub and any tunnel available while work runs.
|
|
37
|
+
|
|
38
|
+
`--advertise-url` names the origin racks reach the hub at: a relay's, a
|
|
39
|
+
tunnel's or a TLS terminator's. The hub builds every rack and data URL on it.
|
|
40
|
+
Without it, data URLs use the origin each rack request named, which is right
|
|
41
|
+
only when the rack connects to the listener directly. A listener on every
|
|
42
|
+
address (`0.0.0.0` or `::`) has no address to hand out, so enrollment needs
|
|
43
|
+
`--advertise-url` there.
|
|
44
|
+
|
|
45
|
+
The certificate is kept in the hub's private state (`hub-tls.beast2`, beside
|
|
46
|
+
its other state) until it is removed. With the hub stopped, removing that file
|
|
47
|
+
makes a new certificate on the next start, which every worker must then pin again.
|
|
48
|
+
|
|
49
|
+
Plain HTTP (`--no-tls`) is for a TLS terminator in front of the hub, as in
|
|
50
|
+
`e3 rack config --no-tls --listen 127.0.0.1:7331 --allow 127.0.0.1 --advertise-url https://terminator.example`.
|
|
51
|
+
The hub refuses a plain-HTTP listener on a wildcard or public address, or
|
|
52
|
+
without `--allow`: anything on the path of plain HTTP reads every rack token,
|
|
53
|
+
data URL, input, output and log. A VPN whose hub decrypts and re-encrypts
|
|
54
|
+
traffic is not encrypted end to end. `--allow <ip,...>` admits only the named
|
|
55
|
+
addresses (through a local tunnel or terminator, `127.0.0.1`); it does not
|
|
56
|
+
encrypt anything.
|
|
57
|
+
|
|
58
|
+
Use the matching, verified companion release from e3-cloud **inside an already
|
|
59
|
+
prepared worker VM**, at the release `e3 rack enroll` printed. Replace the public
|
|
60
|
+
allocation path below with the one the host provisioner supplies; do not write
|
|
61
|
+
allocation JSON yourself:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
sudo /opt/e3-rack/releases/<release>/e3-rack configure \
|
|
65
|
+
--allocation '/var/lib/e3-rack/<agent-uuid>/allocation.json'
|
|
66
|
+
sudo /opt/e3-rack/releases/<release>/e3-rack enroll \
|
|
67
|
+
--allocation '/var/lib/e3-rack/<agent-uuid>/allocation.json'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`configure` asks for the source origin and, for an HTTPS origin, the
|
|
71
|
+
certificate SHA-256 the hub printed (none for a publicly trusted certificate,
|
|
72
|
+
such as a cloud deployment's), then the worker label (`workshop` here), runtime
|
|
73
|
+
settings and optional private-registry access. `enroll` asks for the one-time
|
|
74
|
+
token. Both use hidden terminal prompts. The worker stores origins, pins,
|
|
75
|
+
identities, settings and registry credentials together in encrypted storage; no
|
|
76
|
+
token or source address is included in the printed shell commands. The
|
|
77
|
+
enrollment token is intentionally displayed by this local minting command: do
|
|
78
|
+
not copy its output into logs or a plaintext file.
|
|
79
|
+
|
|
80
|
+
A plain-HTTP source origin needs `--allow-vpn-http` on both worker commands, and
|
|
81
|
+
the worker's host must authorize that exact destination. Use it only on a path
|
|
82
|
+
encrypted end to end, such as an SSH tunnel.
|
|
83
|
+
|
|
84
|
+
The local command waits for a **new registration**, including one with no boot,
|
|
85
|
+
tiers or capacity yet; `--no-wait` returns after printing the handoff. A label
|
|
86
|
+
filters the observed registrations, so compare the result with the worker's
|
|
87
|
+
enrollment result. Enrollment does not prove service activation or readiness.
|
|
88
|
+
`e3 rack list` shows `enrolled-not-started` before a first heartbeat.
|
|
89
|
+
|
|
90
|
+
Once the worker has been activated and explicitly resumed, its heartbeat
|
|
91
|
+
publishes concurrent capacity as free plus occupied slots. Busy workers remain
|
|
92
|
+
eligible; fenced, draining or unhealthy workers publish zero capacity and show
|
|
93
|
+
`unavailable`. Existing work can still finish during drain. Only heartbeats
|
|
94
|
+
refresh readiness: lease polling cannot keep an old capacity report alive.
|
|
95
|
+
After 45 seconds without a heartbeat the worker stops counting as available.
|
|
96
|
+
Source boot approval, when required, remains a separate gate from worker resume:
|
|
97
|
+
`e3 rack config --require-approval` quarantines a rack after each reboot until
|
|
98
|
+
`e3 rack approve <rack>` admits the boot it reports; enrollment admits the first.
|
|
99
|
+
|
|
100
|
+
Independent agents belong to separate worker VMs, each with its own identity,
|
|
101
|
+
encrypted configuration and host-enforced resource allocation. Whole GPUs are
|
|
102
|
+
assigned through the host lifecycle, independently of this enrollment command.
|
|
103
|
+
One worker can connect to up to 32 mutually trusted e3 sources. To add another,
|
|
104
|
+
first drain the worker and stop its services and socket activation. Inside it:
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
sudo /opt/e3-rack/releases/<release>/e3-rack configure \
|
|
108
|
+
--allocation '/var/lib/e3-rack/<agent-uuid>/allocation.json' --add-source
|
|
109
|
+
sudo /opt/e3-rack/releases/<release>/e3-rack enroll \
|
|
110
|
+
--allocation '/var/lib/e3-rack/<agent-uuid>/allocation.json' --source '<new-source-uuid>'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`configure --add-source` asks you to confirm that these sources may share the
|
|
114
|
+
agent's trust boundary, then privately asks for the new origin. It prints the
|
|
115
|
+
source UUID for `enroll`. Obtain that source's token with `e3 rack enroll` on
|
|
116
|
+
the additional local e3 machine, or from the chosen cloud deployment. Omit the
|
|
117
|
+
HTTP opt-in for HTTPS. The host must approve the additional endpoint. Existing
|
|
118
|
+
identities and registry access are preserved, every source must be enrolled
|
|
119
|
+
before startup, and the next boot remains fenced.
|
|
120
|
+
|
|
121
|
+
Connections have separate clients, credentials, caches and completion journals.
|
|
122
|
+
One worker-wide task/GPU limit bounds actual execution across them; per-source
|
|
123
|
+
capacity reports must not be added together as physical reservations. All
|
|
124
|
+
connections share the worker's lifecycle. They also share its process and
|
|
125
|
+
credential trust boundary: a worker is the trust boundary. Put sources on one
|
|
126
|
+
worker only when they trust each other, such as one team's developer hubs.
|
|
127
|
+
Each client environment needs a worker of its own, and a cloud deployment and
|
|
128
|
+
developer hubs belong on separate workers. Independent agents have no shared
|
|
129
|
+
e3 task scheduler.
|
|
130
|
+
|
|
131
|
+
The hub keeps no task data: leases and data URLs live in its memory, and every
|
|
132
|
+
object passes through it from the repository's session. What a worker keeps is
|
|
133
|
+
the worker's own policy. The hub checks each object a rack reads against its
|
|
134
|
+
lease's closure only, so an agent that fetches every object again for each task
|
|
135
|
+
and keeps nothing once the task ends works with it unchanged.
|
|
136
|
+
|
|
137
|
+
The companion now provides `e3-rack source list --allocation <path>` inside the
|
|
138
|
+
worker. It lists source UUIDs and enrollment state; `--show-origins` displays
|
|
139
|
+
origins only on a terminal. To disconnect or re-enroll, drain and stop the worker,
|
|
140
|
+
revoke the selected rack at its source, then use `source remove` or `source reset`
|
|
141
|
+
with `--allocation <path> --source <UUID> --acknowledge-revocation`. Confirm the
|
|
142
|
+
UUID at the hidden prompt. Reset prints a **new** UUID. Use it with `enroll
|
|
143
|
+
--source`, supplying a fresh token obtained from the e3 source. Reset preserves
|
|
144
|
+
the origin and keeps old caches/pending results out of the new identity.
|
|
145
|
+
The flag acknowledges prior revocation; it does
|
|
146
|
+
not revoke remotely. Other sources and retained data are preserved. Reconcile
|
|
147
|
+
host endpoint policy before activation; the next boot remains fenced.
|
|
148
|
+
|
|
149
|
+
Private registry access has its own worker-local commands:
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
sudo /opt/e3-rack/releases/<release>/e3-rack registry status \
|
|
153
|
+
--allocation '/var/lib/e3-rack/<agent-uuid>/allocation.json'
|
|
154
|
+
# After a verified drain and stopping the worker services/sockets:
|
|
155
|
+
sudo /opt/e3-rack/releases/<release>/e3-rack registry configure \
|
|
156
|
+
--allocation '/var/lib/e3-rack/<agent-uuid>/allocation.json'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Status can run while active and shows only whether credentials are stored; it
|
|
160
|
+
does not test GHCR access. Configure privately prompts for username/read-only
|
|
161
|
+
token without re-entering worker settings. Use `registry clear --allocation
|
|
162
|
+
<path>` to remove stored access, confirming the installation UUID privately.
|
|
163
|
+
Changes require the same release, the writer lock and no unresolved enrollment
|
|
164
|
+
or service transition. They preserve current source identities/rotations, settings,
|
|
165
|
+
journals and cached images/task data. Credentials stay in the encrypted bundle;
|
|
166
|
+
no Docker login file is created. A later service activation receives the change,
|
|
167
|
+
with the next boot still fenced. Neither replacing nor clearing revokes a token
|
|
168
|
+
remotely. After interruption, repeat configure with the intended values or clear
|
|
169
|
+
to ensure absence; repeating the current values or an absent clear makes no write.
|
|
170
|
+
|
|
171
|
+
The companion also provides worker-local `reconcile-services`: after a completed
|
|
172
|
+
drain and stopped services, it applies the host's next allocation generation and
|
|
173
|
+
resource limits. The previous service-plan hash and exact drain/operation/boot
|
|
174
|
+
binding protect the transition. Interrupted updates keep activation guarded and
|
|
175
|
+
retry with the same operation; ciphertext and journals remain unchanged. This
|
|
176
|
+
supports prepared GPU/VFIO assignments at the same executable release; the host
|
|
177
|
+
still performs and verifies the physical move, and network quarantine remains.
|
|
178
|
+
|
|
179
|
+
For a compatible upgrade or downgrade, the target verified executable's
|
|
180
|
+
`switch-release` uses another completed drain, the previous plan hash and a new
|
|
181
|
+
allocation generation, with unchanged resource/device budgets. Both binaries
|
|
182
|
+
must report the same managed-state contract. It changes the runtime version in
|
|
183
|
+
the **current** encrypted configuration, preserving all identities, registry
|
|
184
|
+
access and journals. Interrupted commits stay guarded and retry with the same
|
|
185
|
+
operation; downgrades never restore saved credentials or state. Keep both
|
|
186
|
+
four-file releases available through receipt recovery. Services stay stopped
|
|
187
|
+
and quarantined until separately activated and resumed.
|
|
188
|
+
|
|
189
|
+
If the selected release never resumed, its exact recorded predecessor's
|
|
190
|
+
`recover-release` uses the completed release receipt, current plan hash and a
|
|
191
|
+
new operation at another generation increase. It requires either the original
|
|
192
|
+
drained journal or a valid fenced journal with no operation at the failed
|
|
193
|
+
generation, and verifies both releases against the recorded fingerprints. Any
|
|
194
|
+
resume attempt, including one from a prior boot, prevents this recovery. Current
|
|
195
|
+
credentials and journals are preserved; services remain stopped and quarantined.
|
|
196
|
+
A release that resumed needs a fresh drain and normal `switch-release`; general
|
|
197
|
+
journal repair and recovery after an undrainable resumed release remain open.
|
|
198
|
+
|
|
199
|
+
The named host manager, source aliases, incompatible-state migrations,
|
|
200
|
+
service/network activation and hardware acceptance remain
|
|
201
|
+
[cloud #253](https://github.com/elaraai/e3-cloud/issues/253) work. Enrollment alone
|
|
202
|
+
is not an end-to-end deployment. See the companion's
|
|
203
|
+
[worker configuration and service contract](https://github.com/elaraai/e3-cloud/blob/72c5c629e1708421171d3c86b8d7cb470f46802e/packages/e3-rack-agent/credentials/README.md).
|
|
204
|
+
|
|
205
|
+
## Select work
|
|
206
|
+
|
|
207
|
+
```sh
|
|
208
|
+
e3 rack policy . set 'train_*' rack --size large
|
|
209
|
+
e3 dataflow run . dev --rack
|
|
210
|
+
e3 watch src/main.ts . dev --start --rack
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Policies live in `<repo>/rack/policy.beast2`. Rules match the entire task name
|
|
214
|
+
with `*` and `?`; the first matching rule wins. By default, unmatched tasks
|
|
215
|
+
stay local. Rules and placement do not change task or cache hashes.
|
|
216
|
+
|
|
217
|
+
```sh
|
|
218
|
+
e3 rack policy . show
|
|
219
|
+
e3 rack policy . enable # opt in without a flag on each run
|
|
220
|
+
e3 rack policy . mode auto # route eligible unmatched tasks too
|
|
221
|
+
e3 rack policy . set 'ingest_*' local
|
|
222
|
+
e3 rack policy . defaults --no-spill --claim-timeout 30
|
|
223
|
+
e3 dataflow run . dev --no-rack # override the saved opt-in
|
|
224
|
+
e3 dataflow run . dev --rack-only # wait when compatible racks are busy
|
|
225
|
+
e3 rack policy . unset 'train_*'
|
|
226
|
+
e3 rack policy . reset
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Defaults are disabled, opt-in selection, `large`, a 1440-minute timeout,
|
|
230
|
+
capacity spill enabled, a 30-second claim recheck and no local retry of task
|
|
231
|
+
failures. `--rack-only` disables capacity spill; infrastructure failures can
|
|
232
|
+
still fall back locally. It does not force ineligible tasks onto a rack.
|
|
233
|
+
Rack flags apply to local dataflows and watch with `--start`, and are refused
|
|
234
|
+
for remote repository URLs. Calls, mutations and intake remain local.
|
|
235
|
+
|
|
236
|
+
Only stock runner configurations can delegate. Custom commands, environments,
|
|
237
|
+
platform extensions and unscannable programs stay local. Programs that access
|
|
238
|
+
host files, environment variables or network resources also stay local by
|
|
239
|
+
default: their dependencies may exist only on this machine. A task rule's
|
|
240
|
+
`--allow-host-access` deliberately overrides that guard, for a rack that
|
|
241
|
+
provides those resources itself. The companion agent's task VMs have no network
|
|
242
|
+
device, host files or injected environment, so such a task fails there.
|
|
243
|
+
|
|
244
|
+
## Execution and recovery
|
|
245
|
+
|
|
246
|
+
Current sources include optional first-claim queue timings in grant response
|
|
247
|
+
headers. The companion agent records admission, input/image preparation, VM and
|
|
248
|
+
guest startup milestones on its own monotonic clock. Its
|
|
249
|
+
[latency benchmark and p50/p95 report](https://github.com/elaraai/e3-cloud/blob/998d879ac6c199e7f300bf9b9531293b4e8f5dc0/scripts/rack/LATENCY.md)
|
|
250
|
+
separate cached CPU, GPU and first-use observations, including failures and
|
|
251
|
+
missing data. Guest execution entry precedes runtime imports and CUDA startup;
|
|
252
|
+
source queue time is separate and cannot be added as exact end-to-end latency.
|
|
253
|
+
This adds no persisted or BEAST2 wire field and requires no new credentials.
|
|
254
|
+
|
|
255
|
+
After a cache miss, the local planner offers an eligible task or split-task
|
|
256
|
+
unit to the hub. A compatible healthy agent claims it, downloads the task and
|
|
257
|
+
its complete input object graph, executes in a VM, and streams logs. It uploads
|
|
258
|
+
each output object by hash and size, then commits its upload receipt. The local
|
|
259
|
+
session verifies the complete output graph before recording success. Planning,
|
|
260
|
+
splitting and merging decisions remain local; map and merge bodies can both
|
|
261
|
+
run remotely, including when the map outputs were already cached.
|
|
262
|
+
|
|
263
|
+
Local work and fallback share the run's existing `-j` and `--memory` budget.
|
|
264
|
+
Remote bodies consume rack slots without reserving a local runner slot. Local
|
|
265
|
+
orchestrator width includes compatible rack capacity.
|
|
266
|
+
|
|
267
|
+
Concurrent sessions of the same canonical repository and e3 release can share
|
|
268
|
+
one lease. Cancelling one subscriber leaves the others running; cancelling
|
|
269
|
+
the last stops the lease. An interrupted remote attempt and its local retry
|
|
270
|
+
have distinct execution records. The task's timeout and the run's own
|
|
271
|
+
cancellation are not retried locally; an attempt the rack stopped on its own
|
|
272
|
+
is. Task failures are returned unless the policy explicitly enables
|
|
273
|
+
`--retry-task-failures-locally`; infrastructure failures fall back locally.
|
|
274
|
+
|
|
275
|
+
Ctrl-C in `e3 dataflow run` requests cancellation of that run, including its
|
|
276
|
+
delegated work. A current companion agent keeps an outbound cancellation
|
|
277
|
+
request open while work is active. The source checks the watched leases every
|
|
278
|
+
250 ms and answers as soon as one stops; the agent aborts that task and destroys
|
|
279
|
+
its VM before waiting for log delivery. Other tasks and sources keep running.
|
|
280
|
+
The normal health heartbeat remains 15 seconds. Against an older source without
|
|
281
|
+
this endpoint, the new agent uses a one-second heartbeat while busy.
|
|
282
|
+
|
|
283
|
+
The companion also cancels input/layer downloads, output uploads, storage requests
|
|
284
|
+
and upload retry waits. It stops parallel transfers and waits for their cleanup
|
|
285
|
+
before deleting staging or releasing the invocation slot. A finished guest's VM
|
|
286
|
+
is destroyed before waiting for output delivery. Each object/layer HTTP attempt
|
|
287
|
+
has a 120-second deadline, including its body; cancellation interrupts it immediately.
|
|
288
|
+
Cancellation also reaches first-use image builds, environment composition,
|
|
289
|
+
scratch-disk preparation and VM startup. A shared image build continues for its
|
|
290
|
+
remaining leases; the last cancelled waiter stops it and waits for cleanup.
|
|
291
|
+
Cancelled boots retain GPU ownership until process exit is confirmed, and
|
|
292
|
+
uncertain teardown requires recovery. Filesystem operations and final publication
|
|
293
|
+
already in progress still finish safely before cleanup; a process stuck in kernel I/O can
|
|
294
|
+
delay that. See the [companion cancellation boundaries](https://github.com/elaraai/e3-cloud/blob/72c5c629e1708421171d3c86b8d7cb470f46802e/packages/e3-rack-agent/README.md#cancelling-delegated-work).
|
|
295
|
+
|
|
296
|
+
This targets cancellation delivery within about a second on a healthy connection;
|
|
297
|
+
network failures and VM/GPU teardown can take longer. The CLI's cancellation
|
|
298
|
+
message is not confirmation that the remote VM has exited. Killing the CLI
|
|
299
|
+
without allowing its signal handler to run relies on lost-session cleanup.
|
|
300
|
+
|
|
301
|
+
```sh
|
|
302
|
+
e3 rack status # does not start an absent hub
|
|
303
|
+
e3 rack list
|
|
304
|
+
e3 task logs . dev.train_model --follow
|
|
305
|
+
e3 rack remove workshop # revoke this rack's credential
|
|
306
|
+
e3 rack config --require-approval # quarantine each reboot until approved
|
|
307
|
+
e3 rack approve workshop # admit the boot this rack last reported
|
|
308
|
+
e3 rack stop # stop the shared hub
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Hub state lives under `~/.e3/rack` (override with `E3_RACK_HOME`). The rack
|
|
312
|
+
listener is off until configured. A running hub and client must have compatible
|
|
313
|
+
control schemas (currently protocol 2 exactly); incompatible clients receive
|
|
314
|
+
an explicit diagnostic. Agents must report a bundled e3 version at least as
|
|
315
|
+
new as the project's. Stop and restart the hub after an incompatible upgrade.
|
|
316
|
+
|
|
317
|
+
A hub that `e3 dataflow run` starts exits after 15 idle minutes, while a run
|
|
318
|
+
waits up to 10 seconds for an enrolled rack to report healthy and fixes its
|
|
319
|
+
parallelism as it starts; with no rack enrolled, or a policy that selects no
|
|
320
|
+
task for a rack, it starts at once. An agent reconnecting after the hub exits
|
|
321
|
+
backs off for up to 30 seconds. For a hub racks can always reach, run
|
|
322
|
+
`e3 rack hub` as a service, or set `e3 rack config --idle-exit 0`.
|
|
323
|
+
|
|
324
|
+
A rack reads and writes each object through a data URL that lasts 15 minutes,
|
|
325
|
+
and a transfer may take all of it; an object is at most 5 GiB. Over a slow
|
|
326
|
+
link, a large object can outlast its URL, and the work then falls back locally.
|
|
327
|
+
|
|
328
|
+
## Local API server
|
|
329
|
+
|
|
330
|
+
Install matching `@elaraai/e3-api-server` and `@elaraai/e3-rack`, then opt in:
|
|
331
|
+
|
|
332
|
+
```sh
|
|
333
|
+
e3-api-server --repos ./repos --rack -j 4 --memory 8G
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Each API dataflow run gets its own rack session using the server's existing
|
|
337
|
+
shared budget. Repository rules still select tasks; explicit server opt-in
|
|
338
|
+
overrides the policy's `enabled` default. A programmatic server can use:
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
import { createServer } from '@elaraai/e3-api-server';
|
|
342
|
+
import { createDataflowRunnerFactory } from '@elaraai/e3-rack';
|
|
343
|
+
|
|
344
|
+
const server = await createServer({
|
|
345
|
+
reposDir: './repos',
|
|
346
|
+
dataflowRunner: createDataflowRunnerFactory(),
|
|
347
|
+
});
|
|
348
|
+
await server.start();
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
The server can run without the optional rack package. Its portable handlers
|
|
352
|
+
accept a runner factory; they do not import Node-only hub code.
|
|
353
|
+
|
|
354
|
+
## Compatibility and verification boundaries
|
|
355
|
+
|
|
356
|
+
If `rack status` reports a listener error, confirm the configured address is
|
|
357
|
+
present on this machine and the port is free; a listener the hub refuses to
|
|
358
|
+
serve says why. Prefer a stable source origin, such as a relay's address. A
|
|
359
|
+
changed source origin needs a deliberate managed source transition;
|
|
360
|
+
re-running worker `configure` preserves an enrolled source's origin and identity.
|
|
361
|
+
If a rack is incompatible, its executable's bundled e3 must be upgraded along
|
|
362
|
+
with its runtime images. Managed `configure` deliberately refuses a release
|
|
363
|
+
change: use the companion's guarded `switch-release` workflow above. Releases
|
|
364
|
+
without its managed-state compatibility contract are refused. Do not switch its executable symlink or erase its service plan and
|
|
365
|
+
journals to bypass this guard. If a task stays local, inspect `rack policy show`,
|
|
366
|
+
the task's runner/platforms and host-access dependencies; `--rack-only` cannot
|
|
367
|
+
override eligibility.
|
|
368
|
+
|
|
369
|
+
Public package entries are `@elaraai/e3-rack` (local hub/client/routing/runner
|
|
370
|
+
APIs), `@elaraai/e3-rack/protocol` (wire types),
|
|
371
|
+
`@elaraai/e3-rack/server` (shared control-plane mechanisms without local hub startup),
|
|
372
|
+
`@elaraai/e3-rack/testing` (test agent and contracts), and
|
|
373
|
+
`@elaraai/e3-rack/hub-main` (hub process entry point).
|
|
374
|
+
|
|
375
|
+
Hosts adopt shared routes, dispatch, identity and store interfaces through the
|
|
376
|
+
server entry; this avoids importing the local hub's filesystem/runner adapters.
|
|
377
|
+
They implement `RackRegistry.compareAndSetRack`:
|
|
378
|
+
replace exactly the observed registration, atomically, and refuse a missing or
|
|
379
|
+
changed record. `updateRack` retries a patch against the latest value. This
|
|
380
|
+
preserves revocation, boot approval and drain state across concurrent requests;
|
|
381
|
+
a process-local coordinator alone cannot protect a distributed control plane.
|
|
382
|
+
Run `rackRegistryContract` from the testing entry against each backend. The file
|
|
383
|
+
registry retains its single-writer hub lock and heartbeat coalescing. This changes
|
|
384
|
+
no persisted or wire schema.
|
|
385
|
+
|
|
386
|
+
The shared routes retain a fixed 250 ms claim cadence by default. Cloud hosts
|
|
387
|
+
can set `pollMaxMs` to back off an idle poll (×1.5 per empty check), and
|
|
388
|
+
`policyRecheckMs` to reduce idle policy reads. For example, the cloud adapter
|
|
389
|
+
uses a one-second maximum and five-second idle policy refresh. Every actual
|
|
390
|
+
claim rereads registration and policy, including drain, revocation and boot
|
|
391
|
+
approval; cached idle permission cannot authorize work. Cancellation watches
|
|
392
|
+
keep their separate 250 ms cadence. Object reads, target signing and environment
|
|
393
|
+
layer signing run at most eight operations concurrently. Output declarations
|
|
394
|
+
are reserved first, and every started operation settles before the lease fence
|
|
395
|
+
is released, including after a failure. Commits stay sequential for distributed
|
|
396
|
+
backends whose transactions condition on the same lease row.
|
|
397
|
+
|
|
398
|
+
This implementation speaks e3-cloud's v2 task/unit leases with per-object
|
|
399
|
+
uploads. The protocol golden fixtures come from e3-cloud's rack protocol, and
|
|
400
|
+
the cancellation-watch fixtures match the companion agent
|
|
401
|
+
([e3-cloud #254](https://github.com/elaraai/e3-cloud/pull/254)). The test rack
|
|
402
|
+
agent executes real e3 runners and exercises the transfer path, over TLS with a
|
|
403
|
+
pinned certificate; those tests do not establish KVM or hardware acceptance for
|
|
404
|
+
the deployed agent. A companion agent must bundle e3 at least as new as this
|
|
405
|
+
release, and pin the hub's certificate; an older bundle falls back locally.
|
|
406
|
+
|
|
407
|
+
See [the epic reconciliation](../../design/e3-rack-reconciliation.md) for the
|
|
408
|
+
changes required by current cloud and workspace APIs, wire migration rules,
|
|
409
|
+
and the remaining companion work. Custom environments, remote function calls,
|
|
410
|
+
automatic reconnect after hub restart and embedded UI integration are deferred.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.spec.d.ts","sourceRoot":"","sources":["../../../src/client/client.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { afterEach, it } from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import { mkdtemp, readFile, readdir, rm } from 'node:fs/promises';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { spawn } from 'node:child_process';
|
|
11
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
12
|
+
import { Hono } from 'hono';
|
|
13
|
+
import { some, variant } from '@elaraai/east';
|
|
14
|
+
import { LocalStorage, repoInit, uuidv7 } from '@elaraai/e3-core';
|
|
15
|
+
import { sendSuccess } from '../server/beast2.js';
|
|
16
|
+
import { connectHub, RackHubOutdatedError, RackHubUnavailableError } from './connect.js';
|
|
17
|
+
import { HubClient } from './hub-client.js';
|
|
18
|
+
import { RackSession } from './session.js';
|
|
19
|
+
import { closeSocketServer, serveOnSocket } from './local-http.js';
|
|
20
|
+
import { EmptyType, HubHelloType } from '../protocol/control.js';
|
|
21
|
+
import { HUB_PROTOCOL } from '../version.js';
|
|
22
|
+
import { hubSocketPath } from '../paths.js';
|
|
23
|
+
import { readHubLock } from '../hub/lock.js';
|
|
24
|
+
import { TestRackAgent } from '../testing/test-rack-agent.js';
|
|
25
|
+
const cleanup = [];
|
|
26
|
+
afterEach(async () => { for (const close of cleanup.splice(0).reverse())
|
|
27
|
+
await close(); });
|
|
28
|
+
async function home() {
|
|
29
|
+
const path = await mkdtemp(join(tmpdir(), 'e3c-'));
|
|
30
|
+
cleanup.push(() => rm(path, { recursive: true, force: true }));
|
|
31
|
+
cleanup.push(async () => {
|
|
32
|
+
await new HubClient(path).stop().catch(() => { });
|
|
33
|
+
for (let i = 0; i < 100 && await readHubLock(path) !== null; i++)
|
|
34
|
+
await delay(20);
|
|
35
|
+
const lock = await readHubLock(path);
|
|
36
|
+
if (lock !== null)
|
|
37
|
+
try {
|
|
38
|
+
process.kill(Number(lock.pid), 'SIGKILL');
|
|
39
|
+
}
|
|
40
|
+
catch { /* already gone */ }
|
|
41
|
+
});
|
|
42
|
+
return path;
|
|
43
|
+
}
|
|
44
|
+
async function fixture() {
|
|
45
|
+
const path = await home();
|
|
46
|
+
const client = await connectHub({ home: path });
|
|
47
|
+
await client.setConfig({ ...await client.getConfig(), listen: some({ host: '127.0.0.1', port: 0n }) });
|
|
48
|
+
const mint = await client.enroll();
|
|
49
|
+
const agent = await TestRackAgent.enroll(mint.apiUrl, mint.enrollmentToken, { certificateSha256: mint.certificateSha256.type === 'some' ? mint.certificateSha256.value : undefined });
|
|
50
|
+
cleanup.push(() => agent.close());
|
|
51
|
+
const repo = join(path, 'repo');
|
|
52
|
+
assert(repoInit(repo).success);
|
|
53
|
+
const storage = new LocalStorage();
|
|
54
|
+
const session = await RackSession.open(client, { storage, repoPath: repo, workspace: 'dev', label: 'client test' });
|
|
55
|
+
cleanup.push(() => session.close());
|
|
56
|
+
const request = { tier: 'node', computeSize: 'large', eventJson: JSON.stringify({ version: 2, workspace: 'dev', taskName: 'task', closure: { hashes: [] },
|
|
57
|
+
runnerEvent: { mode: 'task', taskHash: 'a'.repeat(64), repo: 'replaced', inputHashes: [], launchId: uuidv7(), timeoutMs: 30000 } }) };
|
|
58
|
+
return { path, client, agent, repo, storage, session, request };
|
|
59
|
+
}
|
|
60
|
+
it('cold-starts the published hub entry, logs startup and shares it across three processes', async () => {
|
|
61
|
+
const path = await home();
|
|
62
|
+
const module = new URL('./connect.js', import.meta.url).href;
|
|
63
|
+
const script = `import { connectHub } from ${JSON.stringify(module)};
|
|
64
|
+
const hub = await connectHub({ home: process.argv[1] });
|
|
65
|
+
console.log(Number((await hub.hello()).pid));`;
|
|
66
|
+
const run = () => new Promise((resolve, reject) => {
|
|
67
|
+
const child = spawn(process.execPath, ['--input-type=module', '-e', script, path], { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
|
|
68
|
+
let out = '';
|
|
69
|
+
let error = '';
|
|
70
|
+
child.stdout.on('data', (data) => { out += data.toString(); });
|
|
71
|
+
child.stderr.on('data', (data) => { error += data.toString(); });
|
|
72
|
+
child.once('error', reject);
|
|
73
|
+
child.once('exit', (code) => { if (code !== 0)
|
|
74
|
+
reject(new Error(error));
|
|
75
|
+
else
|
|
76
|
+
resolve(Number(out.trim())); });
|
|
77
|
+
});
|
|
78
|
+
const pids = await Promise.all([run(), run(), run()]);
|
|
79
|
+
assert.equal(new Set(pids).size, 1);
|
|
80
|
+
const client = await connectHub({ home: path, spawn: false });
|
|
81
|
+
assert.equal(Number((await client.status()).hello.pid), pids[0]);
|
|
82
|
+
assert.match(await readFile(join(path, 'hub.log'), 'utf8'), /rack hub started/);
|
|
83
|
+
assert.equal(Number((await readHubLock(path)).pid), pids[0]);
|
|
84
|
+
});
|
|
85
|
+
it('drains an older protocol, refuses a newer one and leaves its sessions alone', async () => {
|
|
86
|
+
const path = await home();
|
|
87
|
+
let protocol = BigInt(HUB_PROTOCOL) - 1n;
|
|
88
|
+
let drains = 0;
|
|
89
|
+
const app = new Hono();
|
|
90
|
+
app.post('/v1/hello', () => sendSuccess(HubHelloType, { version: '1.0.0', protocol, pid: BigInt(process.pid), draining: false }));
|
|
91
|
+
app.post('/v1/drain', () => { drains++; return sendSuccess(EmptyType, {}); });
|
|
92
|
+
const server = await serveOnSocket(app, hubSocketPath(path));
|
|
93
|
+
cleanup.push(() => closeSocketServer(server, hubSocketPath(path)));
|
|
94
|
+
await assert.rejects(connectHub({ home: path }), (err) => err instanceof RackHubOutdatedError && /older.*exit once idle/.test(err.message));
|
|
95
|
+
assert.equal(drains, 1);
|
|
96
|
+
protocol = BigInt(HUB_PROTOCOL) + 1n;
|
|
97
|
+
await assert.rejects(connectHub({ home: path }), (err) => err instanceof RackHubOutdatedError && /newer/.test(err.message));
|
|
98
|
+
assert.equal(drains, 1);
|
|
99
|
+
});
|
|
100
|
+
it('delivers claim, log tee and terminal outcome in order, then removes its session data socket', async () => {
|
|
101
|
+
const f = await fixture();
|
|
102
|
+
const handle = await f.session.createLease(f.request);
|
|
103
|
+
const grant = await f.agent.claim();
|
|
104
|
+
assert(grant);
|
|
105
|
+
const claimed = await handle.next();
|
|
106
|
+
assert.equal(claimed.kind, 'claimed');
|
|
107
|
+
assert(handle.attempt);
|
|
108
|
+
const logs = [];
|
|
109
|
+
f.session.onLog(handle.attempt.executionId, (_stream, data) => { logs.push(data); });
|
|
110
|
+
await f.agent.logs(grant, [{ stream: variant('stdout', null), data: 'first\n' }, { stream: variant('stdout', null), data: 'second\n' }]);
|
|
111
|
+
assert.deepEqual(logs, ['first\n', 'second\n']);
|
|
112
|
+
await f.agent.complete(grant, { taskName: 'task', status: 'failed', exitCode: 7, error: 'expected failure' });
|
|
113
|
+
const completed = await handle.next();
|
|
114
|
+
assert.equal(completed.kind, 'completed');
|
|
115
|
+
if (completed.kind === 'completed')
|
|
116
|
+
assert.equal(completed.result.exitCode, 7);
|
|
117
|
+
await f.session.close();
|
|
118
|
+
await f.session.close();
|
|
119
|
+
assert.equal((await f.client.status()).sessions.length, 0);
|
|
120
|
+
assert.equal((await readdir(f.path)).filter((name) => name.startsWith('s-') && name.endsWith('.sock')).length, 0);
|
|
121
|
+
});
|
|
122
|
+
it('unblocks every lease promptly after the real hub is killed and refuses reconnecting the old session', async () => {
|
|
123
|
+
const f = await fixture();
|
|
124
|
+
const handle = await f.session.createLease(f.request);
|
|
125
|
+
const hello = await f.client.hello();
|
|
126
|
+
const waiting = handle.next();
|
|
127
|
+
const started = Date.now();
|
|
128
|
+
process.kill(Number(hello.pid), 'SIGKILL');
|
|
129
|
+
const update = await waiting;
|
|
130
|
+
assert.equal(update.kind, 'lost');
|
|
131
|
+
assert(Date.now() - started < 3000);
|
|
132
|
+
assert.equal(f.session.hubLost, true);
|
|
133
|
+
await assert.rejects(f.session.createLease(f.request), RackHubUnavailableError);
|
|
134
|
+
const replacement = await connectHub({ home: f.path });
|
|
135
|
+
assert.notEqual(Number((await replacement.hello()).pid), Number(hello.pid));
|
|
136
|
+
assert.equal((await replacement.status()).sessions.length, 0);
|
|
137
|
+
});
|
|
138
|
+
it('keeps another handle subscribed when identical work is requested twice in one session', async () => {
|
|
139
|
+
const f = await fixture();
|
|
140
|
+
const [first, second] = await Promise.all([f.session.createLease(f.request), f.session.createLease(f.request)]);
|
|
141
|
+
assert.equal(first.leaseId, second.leaseId);
|
|
142
|
+
await first.cancel();
|
|
143
|
+
assert.equal((await first.next()).kind, 'cancelled');
|
|
144
|
+
const grant = await f.agent.claim();
|
|
145
|
+
assert(grant);
|
|
146
|
+
assert.equal((await second.next()).kind, 'claimed');
|
|
147
|
+
await f.agent.complete(grant, { taskName: 'task', status: 'failed' });
|
|
148
|
+
assert.equal((await second.next()).kind, 'completed');
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=client.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.spec.js","sourceRoot":"","sources":["../../../src/client/client.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { HubClient } from './hub-client.js';
|
|
6
|
+
import { RackHubError } from './local-http.js';
|
|
7
|
+
/** Reports a running hub whose protocol cannot serve this e3 release. */
|
|
8
|
+
export declare class RackHubOutdatedError extends RackHubError {
|
|
9
|
+
/** @param message - The mismatch and how to replace the hub */
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
/** Reports unavailable rack service; a task runner may safely run locally. */
|
|
13
|
+
export declare class RackHubUnavailableError extends RackHubError {
|
|
14
|
+
/** @param message - Transport failure and diagnostic log path */
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
/** Configures discovery and automatic background startup. */
|
|
18
|
+
export interface ConnectHubOptions {
|
|
19
|
+
/** Starts a missing hub; defaults to true. */
|
|
20
|
+
spawn?: boolean;
|
|
21
|
+
/** Absolute startup deadline in milliseconds; defaults to ten seconds. */
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
/** Emits progress lines such as "starting rack hub…". */
|
|
24
|
+
log?: (line: string) => void;
|
|
25
|
+
/** Uses a specific private home, useful for isolated hosts/tests. */
|
|
26
|
+
home?: string;
|
|
27
|
+
/** Ends the wait for the hub when the caller's run is aborted. */
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Spawns a detached hub through this package's published entry point.
|
|
32
|
+
* Several callers may spawn concurrently; the hub lock elects one winner.
|
|
33
|
+
* @param home - Private state home and log destination
|
|
34
|
+
* @returns After the child was spawned and its inherited log descriptor closed
|
|
35
|
+
*/
|
|
36
|
+
export declare function spawnHub(home?: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Finds or starts the shared hub and negotiates its exact control protocol.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* This wire has no cross-protocol decoder. A newer protocol is refused too,
|
|
42
|
+
* without draining it. An older hub is asked to drain and the caller runs
|
|
43
|
+
* locally this time. A dead hub is never silently reattached mid-session.
|
|
44
|
+
* @param options - Startup policy, deadline and progress sink
|
|
45
|
+
* @returns A ready typed client
|
|
46
|
+
* @throws {RackHubOutdatedError} On an incompatible control protocol
|
|
47
|
+
* @throws {RackHubUnavailableError} On startup, connection or drain timeout
|
|
48
|
+
* @example
|
|
49
|
+
* const hub = await connectHub({ log: console.log });
|
|
50
|
+
*/
|
|
51
|
+
export declare function connectHub(options?: ConnectHubOptions): Promise<HubClient>;
|
|
52
|
+
//# sourceMappingURL=connect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../../src/client/connect.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,yEAAyE;AACzE,qBAAa,oBAAqB,SAAQ,YAAY;IACpD,+DAA+D;gBACnD,OAAO,EAAE,MAAM;CAC5B;AACD,8EAA8E;AAC9E,qBAAa,uBAAwB,SAAQ,YAAY;IACvD,iEAAiE;gBACrD,OAAO,EAAE,MAAM;CAC5B;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,IAAI,SAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAU/D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,SAAS,CAAC,CAqCpF"}
|