@celilo/e2e 0.19.2 → 0.20.0

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.
Files changed (50) hide show
  1. package/README.md +30 -13
  2. package/bin/e2e-bake-management +171 -12
  3. package/bin/e2e-infra +0 -1
  4. package/bin/e2e-up +14 -3
  5. package/docker/Dockerfile.observer +12 -1
  6. package/docker/Dockerfile.target-machine +22 -1
  7. package/npm-registry-server/package.json +1 -1
  8. package/package.json +3 -3
  9. package/registry-server/package.json +1 -1
  10. package/scripts/pack-celilo-packages.ts +15 -0
  11. package/src/block-timing.test.ts +559 -0
  12. package/src/block-timing.ts +366 -0
  13. package/src/cli/build.test.ts +54 -4
  14. package/src/cli/build.ts +204 -88
  15. package/src/cli/command-registry.ts +21 -0
  16. package/src/cli/command-tree-parser.ts +11 -2
  17. package/src/cli/completion.ts +9 -0
  18. package/src/cli/host.ts +252 -0
  19. package/src/cli/index.ts +78 -51
  20. package/src/cli/module-discovery.ts +108 -13
  21. package/src/cli/scaffold.ts +18 -26
  22. package/src/container-manager.cleanup.test.ts +284 -0
  23. package/src/container-manager.runner.test.ts +351 -0
  24. package/src/container-manager.test.ts +84 -0
  25. package/src/container-manager.ts +721 -185
  26. package/src/docker-compose-generator.ts +135 -61
  27. package/src/doctor.test.ts +259 -4
  28. package/src/doctor.ts +276 -3
  29. package/src/exit-cleanup.test.ts +83 -1
  30. package/src/fleet-nameserver-gate.test.ts +45 -0
  31. package/src/host-vm.test.ts +156 -0
  32. package/src/host-vm.ts +230 -0
  33. package/src/index.ts +11 -0
  34. package/src/live-stack.test.ts +184 -0
  35. package/src/live-stack.ts +145 -0
  36. package/src/no-unjustified-sleep.test.ts +90 -0
  37. package/src/proxmox-provisioner.test.ts +18 -2
  38. package/src/proxmox-provisioner.ts +22 -0
  39. package/src/public-sim-routes.test.ts +9 -2
  40. package/src/repo-root.ts +33 -0
  41. package/src/run-args.test.ts +76 -0
  42. package/src/run-args.ts +89 -0
  43. package/src/runner.ts +213 -8
  44. package/src/shared-infra.ts +83 -32
  45. package/src/socks-proxy.ts +2 -0
  46. package/src/source-fingerprint.test.ts +213 -0
  47. package/src/source-fingerprint.ts +201 -0
  48. package/src/stage-simulator-inputs.ts +93 -0
  49. package/src/stages.ts +133 -0
  50. package/src/wait-for-run.ts +1 -0
@@ -0,0 +1,84 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { removeAlienInterface } from './container-manager';
3
+ import type { ExecResult } from './types';
4
+
5
+ // A faithful `ip -o addr show scope global` line: "N: name<tab>inet addr/prefix
6
+ // scope global name\..." — the same shape the real container reports, so the
7
+ // orphan regex under test matches it the way it matches the real thing.
8
+ function tableLine(iface: string, cidr: string): string {
9
+ return `5: ${iface}\t inet ${cidr} scope global ${iface}\\ valid_lft forever preferred_lft forever`;
10
+ }
11
+
12
+ /** Fakes exec. Interface-table reads return `tables` in sequence, holding the
13
+ * last one once exhausted; `ip link del` returns `delExitCode`. Every command
14
+ * is recorded for reach assertions. */
15
+ function fakeExec(tables: string[], delExitCode = 0) {
16
+ const cmds: string[] = [];
17
+ let read = 0;
18
+ const exec = (cmd: string): ExecResult => {
19
+ cmds.push(cmd);
20
+ if (cmd.includes('ip -o addr show scope global')) {
21
+ const stdout = tables[Math.min(read, tables.length - 1)];
22
+ read++;
23
+ return { stdout, stderr: '', exitCode: 0 };
24
+ }
25
+ if (cmd.startsWith('ip link del ')) {
26
+ return {
27
+ stdout: '',
28
+ stderr: delExitCode === 0 ? '' : 'RTNETLINK answers: Operation not permitted',
29
+ exitCode: delExitCode,
30
+ };
31
+ }
32
+ throw new Error(`fakeExec: unexpected command: ${cmd}`);
33
+ };
34
+ return { exec, cmds };
35
+ }
36
+
37
+ const SUBNET = '172.31.99.0/24';
38
+ const ORPHAN_TABLE = `${tableLine('eth0', '10.226.20.5/24')}\n${tableLine('eth4', '172.31.99.2/24')}`;
39
+ const CLEAN_TABLE = tableLine('eth0', '10.226.20.5/24');
40
+
41
+ describe('removeAlienInterface', () => {
42
+ test('deletes the orphan interface carrying the alien subnet', () => {
43
+ const { exec, cmds } = fakeExec([ORPHAN_TABLE, CLEAN_TABLE]);
44
+ removeAlienInterface({ service: 'fw-main', subnet: SUBNET, exec });
45
+ expect(cmds).toContain('ip link del eth4');
46
+ });
47
+
48
+ test('does nothing when no interface carries the alien subnet', () => {
49
+ const { exec, cmds } = fakeExec([CLEAN_TABLE]);
50
+ removeAlienInterface({ service: 'fw-main', subnet: SUBNET, exec });
51
+ expect(cmds).toEqual(['ip -o addr show scope global']);
52
+ });
53
+
54
+ test('throws naming the surviving interface and container when the repair does not hold', () => {
55
+ // Both reads report eth4: the delete claimed to run, the interface is
56
+ // still there. This is exactly the state that made stage 3 of
57
+ // firewall-interface-classification fail twelve seconds and one converge
58
+ // away from the real event (celilo#1261).
59
+ const { exec } = fakeExec([ORPHAN_TABLE, ORPHAN_TABLE]);
60
+ expect(() => removeAlienInterface({ service: 'fw-main', subnet: SUBNET, exec })).toThrow(
61
+ /eth4.*fw-main|fw-main.*eth4/s,
62
+ );
63
+ });
64
+
65
+ test('the throw carries the disconnect failure when docker refused to detach', () => {
66
+ const { exec } = fakeExec([ORPHAN_TABLE, ORPHAN_TABLE]);
67
+ expect(() =>
68
+ removeAlienInterface({
69
+ service: 'fw-main',
70
+ subnet: SUBNET,
71
+ exec,
72
+ disconnectError: 'Error response from daemon: endpoint not found',
73
+ }),
74
+ ).toThrow(/endpoint not found/);
75
+ });
76
+
77
+ test('does not throw when the interface is gone after the repair, even if the delete reported failure', () => {
78
+ // docker's exit code is not to be believed for veth surgery (see
79
+ // attachAlienSegment), so a failed delete over a table that is actually
80
+ // clean is surfaced, not fatal.
81
+ const { exec } = fakeExec([ORPHAN_TABLE, CLEAN_TABLE], 1);
82
+ expect(() => removeAlienInterface({ service: 'fw-main', subnet: SUBNET, exec })).not.toThrow();
83
+ });
84
+ });