@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.
- package/README.md +30 -13
- package/bin/e2e-bake-management +171 -12
- package/bin/e2e-infra +0 -1
- package/bin/e2e-up +14 -3
- package/docker/Dockerfile.observer +12 -1
- package/docker/Dockerfile.target-machine +22 -1
- package/npm-registry-server/package.json +1 -1
- package/package.json +3 -3
- package/registry-server/package.json +1 -1
- package/scripts/pack-celilo-packages.ts +15 -0
- package/src/block-timing.test.ts +559 -0
- package/src/block-timing.ts +366 -0
- package/src/cli/build.test.ts +54 -4
- package/src/cli/build.ts +204 -88
- package/src/cli/command-registry.ts +21 -0
- package/src/cli/command-tree-parser.ts +11 -2
- package/src/cli/completion.ts +9 -0
- package/src/cli/host.ts +252 -0
- package/src/cli/index.ts +78 -51
- package/src/cli/module-discovery.ts +108 -13
- package/src/cli/scaffold.ts +18 -26
- package/src/container-manager.cleanup.test.ts +284 -0
- package/src/container-manager.runner.test.ts +351 -0
- package/src/container-manager.test.ts +84 -0
- package/src/container-manager.ts +721 -185
- package/src/docker-compose-generator.ts +135 -61
- package/src/doctor.test.ts +259 -4
- package/src/doctor.ts +276 -3
- package/src/exit-cleanup.test.ts +83 -1
- package/src/fleet-nameserver-gate.test.ts +45 -0
- package/src/host-vm.test.ts +156 -0
- package/src/host-vm.ts +230 -0
- package/src/index.ts +11 -0
- package/src/live-stack.test.ts +184 -0
- package/src/live-stack.ts +145 -0
- package/src/no-unjustified-sleep.test.ts +90 -0
- package/src/proxmox-provisioner.test.ts +18 -2
- package/src/proxmox-provisioner.ts +22 -0
- package/src/public-sim-routes.test.ts +9 -2
- package/src/repo-root.ts +33 -0
- package/src/run-args.test.ts +76 -0
- package/src/run-args.ts +89 -0
- package/src/runner.ts +213 -8
- package/src/shared-infra.ts +83 -32
- package/src/socks-proxy.ts +2 -0
- package/src/source-fingerprint.test.ts +213 -0
- package/src/source-fingerprint.ts +201 -0
- package/src/stage-simulator-inputs.ts +93 -0
- package/src/stages.ts +133 -0
- package/src/wait-for-run.ts +1 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, rmSync } from 'node:fs';
|
|
2
2
|
import { basename, join } from 'node:path';
|
|
3
|
-
import { stringify } from 'yaml';
|
|
3
|
+
import { parse as parseYaml, stringify } from 'yaml';
|
|
4
4
|
import { normalizeObservers, observerEnv, observerPlacement } from './observer';
|
|
5
5
|
import { PROXMOX_SIM_IP, SIMULATOR_IPS } from './simulator-ips';
|
|
6
6
|
import type { MachineSpec, NetworkConfig, TopologyPreset, Zone } from './types';
|
|
@@ -113,21 +113,35 @@ function zoneNetworkDef(zone: Zone) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
|
116
|
-
* Image tag prefix for
|
|
117
|
-
* tags
|
|
118
|
-
*
|
|
119
|
-
*
|
|
116
|
+
* Image tag prefix for baked e2e images. `cele2e build-infra` creates these
|
|
117
|
+
* tags; e2e-save/e2e-load persist them across colima restarts. A compose
|
|
118
|
+
* referencing one of these tags never builds it — a missing tag is a loud
|
|
119
|
+
* failure naming the remedy (see referencedImages / container-manager).
|
|
120
120
|
*/
|
|
121
121
|
const IMAGE_PREFIX = 'celilo-e2e';
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
/**
|
|
124
|
+
* The image tag `baseService` assigns a service built from `dockerfile`.
|
|
125
|
+
* Stable across runs (unlike compose's `<project>-<service>` default), which is
|
|
126
|
+
* what lets callers rebuild a sim image by tag — e.g. the bake re-building the
|
|
127
|
+
* registry sim after re-staging tarballs (celilo#1299).
|
|
128
|
+
*/
|
|
129
|
+
export function imageTag(dockerfile: string): string {
|
|
124
130
|
// docker/Dockerfile.management -> celilo-e2e/management
|
|
125
131
|
const name = dockerfile.replace('docker/Dockerfile.', '');
|
|
126
132
|
return `${IMAGE_PREFIX}/${name}`;
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
function baseService(opts: {
|
|
130
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Which Dockerfile bakes this image: `docker/Dockerfile.firewall` ->
|
|
138
|
+
* `celilo-e2e/firewall`. The yaml carries `image:` ONLY. `cele2e
|
|
139
|
+
* build-infra` is the one builder (it owns the network phase); a suite
|
|
140
|
+
* run verifies the tag exists instead of building, so a missing image
|
|
141
|
+
* fails loudly rather than silently resolving FROM from docker.io.
|
|
142
|
+
* See tests/composes-reference-baked-images.test.ts.
|
|
143
|
+
*/
|
|
144
|
+
dockerfile?: string;
|
|
131
145
|
image?: string;
|
|
132
146
|
networks: Record<string, { ipv4_address: string }>;
|
|
133
147
|
cap_add?: string[];
|
|
@@ -148,11 +162,12 @@ function baseService(opts: {
|
|
|
148
162
|
/** Host devices to expose, e.g. `/dev/net/tun` for a userspace WireGuard tunnel. */
|
|
149
163
|
devices?: string[];
|
|
150
164
|
}) {
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
165
|
+
// The Dockerfile name drives the tag but must NOT reach the yaml: compose
|
|
166
|
+
// rejects unknown service keys. The emitted service carries `image:` only.
|
|
167
|
+
const { dockerfile, ...rest } = opts;
|
|
168
|
+
const service: Record<string, unknown> = { ...rest, restart: 'unless-stopped' };
|
|
169
|
+
if (dockerfile && !opts.image) {
|
|
170
|
+
service.image = imageTag(dockerfile);
|
|
156
171
|
}
|
|
157
172
|
return service;
|
|
158
173
|
}
|
|
@@ -162,6 +177,30 @@ function baseService(opts: {
|
|
|
162
177
|
// manager and per-test compose files (to reference external networks).
|
|
163
178
|
// ---------------------------------------------------------------------------
|
|
164
179
|
|
|
180
|
+
/**
|
|
181
|
+
* The baked images a run needs — every service's `celilo-e2e/*` tag, paired
|
|
182
|
+
* with the tag `baseService` assigned it.
|
|
183
|
+
*
|
|
184
|
+
* Used to answer "is everything the compose references present?" before the
|
|
185
|
+
* run. The yaml carries `image:` only (never `build:`), so this is the full
|
|
186
|
+
* set: a missing tag is a loud failure naming `cele2e build-infra`, never a
|
|
187
|
+
* silent suite-time build resolving FROM from docker.io (tasks.md 5b.2).
|
|
188
|
+
*
|
|
189
|
+
* Pure and parsed back out of the emitted YAML rather than computed alongside
|
|
190
|
+
* it, so it reports what the compose file actually says. A service that gains
|
|
191
|
+
* a reference is covered without anyone remembering to add it here.
|
|
192
|
+
*/
|
|
193
|
+
export function referencedImages(yaml: string): string[] {
|
|
194
|
+
const compose = parseYaml(yaml) as {
|
|
195
|
+
services?: Record<string, { image?: string }>;
|
|
196
|
+
};
|
|
197
|
+
const images = new Set<string>();
|
|
198
|
+
for (const service of Object.values(compose.services ?? {})) {
|
|
199
|
+
if (service.image) images.add(service.image);
|
|
200
|
+
}
|
|
201
|
+
return [...images].sort();
|
|
202
|
+
}
|
|
203
|
+
|
|
165
204
|
export const SHARED_PROJECT_NAME = 'celilo-e2e-shared';
|
|
166
205
|
|
|
167
206
|
/** Docker network names as created by the shared infrastructure project */
|
|
@@ -186,14 +225,38 @@ export const SHARED_NETWORKS = {
|
|
|
186
225
|
const SECURE_MGMT_GATEWAY = ZONE_GATEWAYS['secure-mgmt'];
|
|
187
226
|
const SECURE_MGMT_MANAGEMENT_IP = zoneIp('secure-mgmt', 100);
|
|
188
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Zones deliberately LEFT OUT of the no-NAT class, each mapped to the reason it
|
|
230
|
+
* is excluded. The no-NAT set is computed as every declared zone (ZONE_SUBNETS)
|
|
231
|
+
* minus these, so a zone added to the Zone type joins the class by default and
|
|
232
|
+
* leaving one out is a deliberate edit to this map, never an omission. A test
|
|
233
|
+
* over this map is the recurrence gate for celilo#1263: the suite once
|
|
234
|
+
* reproduced that bug class by listing these zones by hand, and a hand-written
|
|
235
|
+
* list rots the moment a zone is added.
|
|
236
|
+
*/
|
|
237
|
+
export const NO_NAT_EXCLUDED_ZONES: Partial<Record<Zone, string>> = {
|
|
238
|
+
internal:
|
|
239
|
+
'A LAN device’s DNS query must arrive SNAT’d to a zone-gateway address so it matches the passthrough view and gets the natIp answer, not the protected one (ISS-0156).',
|
|
240
|
+
};
|
|
241
|
+
|
|
189
242
|
/**
|
|
190
243
|
* The zones fw-main routes between WITHOUT NAT, so the dmz-resident resolver
|
|
191
244
|
* sees each client's real zone (source-based split-horizon, ISS-0156).
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
245
|
+
*
|
|
246
|
+
* Computed, never listed: every declared zone minus
|
|
247
|
+
* {@link NO_NAT_EXCLUDED_ZONES}. THE COST OF EXCLUDING `internal`, recorded so
|
|
248
|
+
* the next reader can connect it (celilo#1263): traffic in the other direction —
|
|
249
|
+
* from a no-NAT zone to an internal host, e.g. the control plane on secure-mgmt
|
|
250
|
+
* reaching fw-isp at 10.226.1.1 — matches no RETURN row and falls through to the
|
|
251
|
+
* blanket MASQUERADE. Traffic to every other declared zone keeps its source;
|
|
252
|
+
* traffic to internal does not. Whether that asymmetry is tolerable is a
|
|
253
|
+
* control-plane question, not a fixture typo.
|
|
195
254
|
*/
|
|
196
|
-
|
|
255
|
+
export function noNatZones(): Zone[] {
|
|
256
|
+
return (Object.keys(ZONE_SUBNETS) as Zone[]).filter((zone) => !(zone in NO_NAT_EXCLUDED_ZONES));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const PROTECTED_SUBNETS = noNatZones()
|
|
197
260
|
.map((zone) => ZONE_SUBNETS[zone])
|
|
198
261
|
.join(' ');
|
|
199
262
|
|
|
@@ -239,7 +302,7 @@ function firewallNetworks(topology: TopologyPreset): Record<string, { ipv4_addre
|
|
|
239
302
|
function defaultTopologyServices(config: NetworkConfig): Record<string, unknown> {
|
|
240
303
|
return {
|
|
241
304
|
'fw-main': baseService({
|
|
242
|
-
|
|
305
|
+
dockerfile: 'docker/Dockerfile.firewall',
|
|
243
306
|
networks: firewallNetworks('default'),
|
|
244
307
|
cap_add: ['NET_ADMIN', 'SYS_ADMIN'],
|
|
245
308
|
// A firewall may also terminate a VPN (the admin tunnel the `wireguard`
|
|
@@ -251,7 +314,7 @@ function defaultTopologyServices(config: NetworkConfig): Record<string, unknown>
|
|
|
251
314
|
environment: { PROTECTED_SUBNETS },
|
|
252
315
|
}),
|
|
253
316
|
'fw-isp': baseService({
|
|
254
|
-
|
|
317
|
+
dockerfile: 'docker/Dockerfile.greenwave-sim',
|
|
255
318
|
networks: {
|
|
256
319
|
internal: { ipv4_address: greenwaveRouterIp() },
|
|
257
320
|
'isp-external': { ipv4_address: '203.0.113.100' },
|
|
@@ -284,7 +347,7 @@ function defaultTopologyServices(config: NetworkConfig): Record<string, unknown>
|
|
|
284
347
|
function directInternetTopologyServices(): Record<string, unknown> {
|
|
285
348
|
return {
|
|
286
349
|
'fw-main': baseService({
|
|
287
|
-
|
|
350
|
+
dockerfile: 'docker/Dockerfile.firewall',
|
|
288
351
|
networks: firewallNetworks('direct-internet'),
|
|
289
352
|
cap_add: ['NET_ADMIN', 'SYS_ADMIN'],
|
|
290
353
|
// A firewall may also terminate a VPN (the admin tunnel the `wireguard`
|
|
@@ -332,7 +395,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
332
395
|
const services: Record<string, unknown> = {};
|
|
333
396
|
|
|
334
397
|
services['root-dns'] = baseService({
|
|
335
|
-
|
|
398
|
+
dockerfile: 'docker/Dockerfile.authoritative-dns',
|
|
336
399
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.ROOT_DNS } },
|
|
337
400
|
cap_add: ['NET_ADMIN'],
|
|
338
401
|
volumes: [
|
|
@@ -342,7 +405,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
342
405
|
});
|
|
343
406
|
|
|
344
407
|
services['tld-dns'] = baseService({
|
|
345
|
-
|
|
408
|
+
dockerfile: 'docker/Dockerfile.authoritative-dns',
|
|
346
409
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.TLD_DNS } },
|
|
347
410
|
cap_add: ['NET_ADMIN'],
|
|
348
411
|
volumes: [
|
|
@@ -354,7 +417,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
354
417
|
});
|
|
355
418
|
|
|
356
419
|
services['namecheap-dns'] = baseService({
|
|
357
|
-
|
|
420
|
+
dockerfile: 'docker/Dockerfile.namecheap-dns',
|
|
358
421
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.NAMECHEAP_DNS } },
|
|
359
422
|
cap_add: ['NET_ADMIN'],
|
|
360
423
|
// Per-domain DDNS passwords for the cross-domain test. Fallback
|
|
@@ -384,7 +447,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
384
447
|
// cycle. See CLAUDE.md history for details.
|
|
385
448
|
|
|
386
449
|
services.letsencrypt = baseService({
|
|
387
|
-
|
|
450
|
+
dockerfile: 'docker/Dockerfile.pebble',
|
|
388
451
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.PEBBLE } },
|
|
389
452
|
cap_add: ['NET_ADMIN'],
|
|
390
453
|
command: '-config /config/pebble-config.json -dnsserver 203.0.113.1:53',
|
|
@@ -400,7 +463,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
400
463
|
// the package (bundled at build time from packages/registry-server,
|
|
401
464
|
// shipped in the npm tarball). See packages/e2e/src/registry-bundle.ts.
|
|
402
465
|
services.registry = baseService({
|
|
403
|
-
|
|
466
|
+
dockerfile: 'docker/Dockerfile.registry',
|
|
404
467
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.REGISTRY } },
|
|
405
468
|
cap_add: ['NET_ADMIN'],
|
|
406
469
|
volumes: getRegistryVolumes(),
|
|
@@ -422,7 +485,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
422
485
|
// internet-external with the authoritative servers, so it needs no route
|
|
423
486
|
// through fw-ext to reach them.
|
|
424
487
|
services['public-resolver'] = baseService({
|
|
425
|
-
|
|
488
|
+
dockerfile: 'docker/Dockerfile.resolver',
|
|
426
489
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.PUBLIC_RESOLVER } },
|
|
427
490
|
cap_add: ['NET_ADMIN'],
|
|
428
491
|
command: '/public-resolver-startup.sh',
|
|
@@ -434,7 +497,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
434
497
|
// check's EXPECTATION comes from; comparing public DNS against the
|
|
435
498
|
// registrar's own response would be self-agreement.
|
|
436
499
|
services['ip-echo'] = baseService({
|
|
437
|
-
|
|
500
|
+
dockerfile: 'docker/Dockerfile.ip-echo',
|
|
438
501
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.IP_ECHO } },
|
|
439
502
|
cap_add: ['NET_ADMIN'],
|
|
440
503
|
});
|
|
@@ -445,7 +508,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
445
508
|
// at 203.0.113.1 as DNS so it can recursively resolve the simulated public
|
|
446
509
|
// zones (e.g. iamtheinternet.org).
|
|
447
510
|
services.isitup = baseService({
|
|
448
|
-
|
|
511
|
+
dockerfile: 'docker/Dockerfile.isitup',
|
|
449
512
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.ISITUP } },
|
|
450
513
|
cap_add: ['NET_ADMIN'],
|
|
451
514
|
dns: ['203.0.113.1'],
|
|
@@ -457,7 +520,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
457
520
|
// without reaching the real internet. Static content is staged into the
|
|
458
521
|
// image at build time from modules/celilo-website/site/dist/.
|
|
459
522
|
services['celilo-website'] = baseService({
|
|
460
|
-
|
|
523
|
+
dockerfile: 'docker/Dockerfile.celilo-website-sim',
|
|
461
524
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.WEBSITE } },
|
|
462
525
|
cap_add: ['NET_ADMIN'],
|
|
463
526
|
dns: ['203.0.113.1'],
|
|
@@ -474,13 +537,13 @@ export function generateSharedInfraYaml(): string {
|
|
|
474
537
|
// DNS resolves tangohost.com straight to this address. It runs its own Apache
|
|
475
538
|
// and its own pre-installed TLS — celilo governs none of it.
|
|
476
539
|
services['cpanel-host'] = baseService({
|
|
477
|
-
|
|
540
|
+
dockerfile: 'docker/Dockerfile.cpanel-host-sim',
|
|
478
541
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.CPANEL_HOST } },
|
|
479
542
|
cap_add: ['NET_ADMIN'],
|
|
480
543
|
});
|
|
481
544
|
|
|
482
545
|
services['npm-registry'] = baseService({
|
|
483
|
-
|
|
546
|
+
dockerfile: 'docker/Dockerfile.npm-registry-sim',
|
|
484
547
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.NPM_REGISTRY } },
|
|
485
548
|
cap_add: ['NET_ADMIN'],
|
|
486
549
|
});
|
|
@@ -492,7 +555,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
492
555
|
// inside the image (Dockerfile.apt-repo-sim). Drives the bootstrap-apt
|
|
493
556
|
// test's `apt install celilo-bootstrap`.
|
|
494
557
|
services['apt-repo'] = baseService({
|
|
495
|
-
|
|
558
|
+
dockerfile: 'docker/Dockerfile.apt-repo-sim',
|
|
496
559
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.APT_REPO } },
|
|
497
560
|
cap_add: ['NET_ADMIN'],
|
|
498
561
|
});
|
|
@@ -505,7 +568,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
505
568
|
// Drives the migration restore e2e (push via `backup --storage`, pull via
|
|
506
569
|
// `backup pull`).
|
|
507
570
|
services.minio = baseService({
|
|
508
|
-
|
|
571
|
+
dockerfile: 'docker/Dockerfile.minio',
|
|
509
572
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.MINIO } },
|
|
510
573
|
cap_add: ['NET_ADMIN'],
|
|
511
574
|
});
|
|
@@ -533,7 +596,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
533
596
|
*/
|
|
534
597
|
function proxmoxSimService() {
|
|
535
598
|
return baseService({
|
|
536
|
-
|
|
599
|
+
dockerfile: 'docker/Dockerfile.proxmox-sim',
|
|
537
600
|
networks: { 'secure-mgmt': { ipv4_address: PROXMOX_SIM_IP } },
|
|
538
601
|
volumes: ['/var/run/docker.sock:/var/run/docker.sock'],
|
|
539
602
|
// Compose substitutes this at up-time from `-p`, so the generator does not
|
|
@@ -592,14 +655,17 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
592
655
|
|
|
593
656
|
// Pick the management image based on variant. Both branches use
|
|
594
657
|
// `image:` (not `build:`) so docker compose uses the existing tag —
|
|
595
|
-
// critical,
|
|
596
|
-
// `docker commit`s the result onto :latest (Phase 2
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
//
|
|
600
|
-
//
|
|
601
|
-
//
|
|
602
|
-
//
|
|
658
|
+
// critical for two reasons. First, `cele2e build-infra` runs
|
|
659
|
+
// install.sh and `docker commit`s the result onto :latest (Phase 2
|
|
660
|
+
// bake step). If compose rebuilt from Dockerfile.management it would
|
|
661
|
+
// OVERWRITE the bake commit, destroying the post-install.sh image.
|
|
662
|
+
// Confirmed bitten on 2026-05-06: caddy-custom-hostname test failed
|
|
663
|
+
// with `celilo: command not found` because the compose rebuild had
|
|
664
|
+
// wiped install.sh's output. Second, no compose anywhere may carry a
|
|
665
|
+
// `build:` section: a suite-time build resolves FROM from docker.io
|
|
666
|
+
// and fetches over the network (tasks.md 5b.2). Every generated
|
|
667
|
+
// compose is image-references-only; the gate is
|
|
668
|
+
// tests/composes-reference-baked-images.test.ts.
|
|
603
669
|
//
|
|
604
670
|
// :vanilla — bun + unzip + bunfig, no celilo. Used by the
|
|
605
671
|
// install-sh regression test.
|
|
@@ -683,6 +749,14 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
683
749
|
DEFAULT_GATEWAY: zone === 'secure-mgmt' ? SECURE_MGMT_GATEWAY : managementDefaultGw,
|
|
684
750
|
...(zone === 'secure-mgmt' ? { FW_MAIN_HOP: SECURE_MGMT_GATEWAY } : {}),
|
|
685
751
|
CELILO_REGISTRY_URL: 'http://e2e-registry.lab',
|
|
752
|
+
// `cele2e run --source-cli` sets this, and the image's shim reads it to
|
|
753
|
+
// run the mounted workspace instead of the CLI install.sh installed.
|
|
754
|
+
// Off by default: the installed CLI is the artifact under test, and
|
|
755
|
+
// running the source over the bind mount roughly doubles a celilo
|
|
756
|
+
// command's start-up (see the shim's comment in bin/e2e-bake-management).
|
|
757
|
+
...(process.env.CELILO_E2E_SOURCE_CLI
|
|
758
|
+
? { CELILO_E2E_SOURCE_CLI: process.env.CELILO_E2E_SOURCE_CLI }
|
|
759
|
+
: {}),
|
|
686
760
|
},
|
|
687
761
|
});
|
|
688
762
|
|
|
@@ -707,7 +781,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
707
781
|
config.dmzMachines[0]?.ip ??
|
|
708
782
|
zoneIp('dmz', 10);
|
|
709
783
|
services['dns-int'] = baseService({
|
|
710
|
-
|
|
784
|
+
dockerfile: 'docker/Dockerfile.internal-resolver',
|
|
711
785
|
networks: { internal: { ipv4_address: internalResolverIp() } },
|
|
712
786
|
cap_add: ['NET_ADMIN'],
|
|
713
787
|
environment: {
|
|
@@ -734,7 +808,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
734
808
|
|
|
735
809
|
// --- Routing infrastructure (bridges per-test to shared infra) ---
|
|
736
810
|
services['fw-ext'] = baseService({
|
|
737
|
-
|
|
811
|
+
dockerfile: 'docker/Dockerfile.router',
|
|
738
812
|
networks: {
|
|
739
813
|
'isp-external': { ipv4_address: '203.0.113.101' },
|
|
740
814
|
'internet-external': { ipv4_address: '100.64.0.1' },
|
|
@@ -745,7 +819,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
745
819
|
});
|
|
746
820
|
|
|
747
821
|
services['comcast-resolver'] = baseService({
|
|
748
|
-
|
|
822
|
+
dockerfile: 'docker/Dockerfile.resolver',
|
|
749
823
|
networks: {
|
|
750
824
|
'isp-external': { ipv4_address: '203.0.113.1' },
|
|
751
825
|
'real-internet': { ipv4_address: '172.30.0.4' },
|
|
@@ -780,7 +854,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
780
854
|
}
|
|
781
855
|
|
|
782
856
|
services[machine.name] = baseService({
|
|
783
|
-
|
|
857
|
+
dockerfile,
|
|
784
858
|
networks: { [zoneNetwork]: { ipv4_address: machine.ip } },
|
|
785
859
|
privileged: true,
|
|
786
860
|
volumes: machineVolumes,
|
|
@@ -792,7 +866,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
792
866
|
// --- Optional DHCP client ---
|
|
793
867
|
if (config.dhcpClient) {
|
|
794
868
|
services['dhcp-client'] = baseService({
|
|
795
|
-
|
|
869
|
+
dockerfile: 'docker/Dockerfile.dhcp-client',
|
|
796
870
|
networks: { internal: { ipv4_address: zoneIp('internal', 210) } },
|
|
797
871
|
cap_add: ['NET_ADMIN'],
|
|
798
872
|
});
|
|
@@ -804,7 +878,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
804
878
|
// on internet-external. Unlinked: the JSON-RPC surface needs no account.
|
|
805
879
|
if (config.signalCli) {
|
|
806
880
|
services['signal-cli'] = baseService({
|
|
807
|
-
|
|
881
|
+
dockerfile: 'docker/Dockerfile.signal-cli',
|
|
808
882
|
networks: { internal: { ipv4_address: zoneIp('internal', 90) } },
|
|
809
883
|
cap_add: ['NET_ADMIN'],
|
|
810
884
|
});
|
|
@@ -815,7 +889,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
815
889
|
// module downloads FROM the internet at deploy time.
|
|
816
890
|
if (config.signalRelease) {
|
|
817
891
|
services['signal-release'] = baseService({
|
|
818
|
-
|
|
892
|
+
dockerfile: 'docker/Dockerfile.signal-release',
|
|
819
893
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.SIGNAL_RELEASE } },
|
|
820
894
|
cap_add: ['NET_ADMIN'],
|
|
821
895
|
});
|
|
@@ -826,7 +900,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
826
900
|
// other without touching the module's configured endpoint.
|
|
827
901
|
if (config.signalSim) {
|
|
828
902
|
services['signal-sim'] = baseService({
|
|
829
|
-
|
|
903
|
+
dockerfile: 'docker/Dockerfile.signal-sim',
|
|
830
904
|
networks: { internal: { ipv4_address: zoneIp('internal', 91) } },
|
|
831
905
|
cap_add: ['NET_ADMIN'],
|
|
832
906
|
environment: {
|
|
@@ -848,7 +922,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
848
922
|
for (const spec of normalizeObservers(config.observers ?? [])) {
|
|
849
923
|
const p = observerPlacement(spec.vantage);
|
|
850
924
|
services[p.service] = baseService({
|
|
851
|
-
|
|
925
|
+
dockerfile: 'docker/Dockerfile.observer',
|
|
852
926
|
networks: { [p.network]: { ipv4_address: p.ip } },
|
|
853
927
|
cap_add: ['NET_ADMIN'],
|
|
854
928
|
// A vantage may dial a VPN and probe from INSIDE the tunnel — the only way
|
|
@@ -894,7 +968,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
894
968
|
config.topology === 'direct-internet' ? ZONE_GATEWAYS.internal : greenwaveRouterIp();
|
|
895
969
|
|
|
896
970
|
services.management = baseService({
|
|
897
|
-
|
|
971
|
+
dockerfile: 'docker/Dockerfile.management',
|
|
898
972
|
networks: { internal: { ipv4_address: zoneIp('internal', 100) } },
|
|
899
973
|
cap_add: ['NET_ADMIN'],
|
|
900
974
|
volumes: [
|
|
@@ -916,7 +990,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
916
990
|
config.dmzMachines[0]?.ip ??
|
|
917
991
|
zoneIp('dmz', 10);
|
|
918
992
|
services['dns-int'] = baseService({
|
|
919
|
-
|
|
993
|
+
dockerfile: 'docker/Dockerfile.internal-resolver',
|
|
920
994
|
networks: { internal: { ipv4_address: internalResolverIp() } },
|
|
921
995
|
cap_add: ['NET_ADMIN'],
|
|
922
996
|
environment: {
|
|
@@ -927,7 +1001,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
927
1001
|
});
|
|
928
1002
|
|
|
929
1003
|
services['fw-ext'] = baseService({
|
|
930
|
-
|
|
1004
|
+
dockerfile: 'docker/Dockerfile.router',
|
|
931
1005
|
networks: {
|
|
932
1006
|
'isp-external': { ipv4_address: '203.0.113.101' },
|
|
933
1007
|
'internet-external': { ipv4_address: '100.64.0.1' },
|
|
@@ -938,7 +1012,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
938
1012
|
});
|
|
939
1013
|
|
|
940
1014
|
services['comcast-resolver'] = baseService({
|
|
941
|
-
|
|
1015
|
+
dockerfile: 'docker/Dockerfile.resolver',
|
|
942
1016
|
networks: {
|
|
943
1017
|
'isp-external': { ipv4_address: '203.0.113.1' },
|
|
944
1018
|
'real-internet': { ipv4_address: '172.30.0.4' },
|
|
@@ -947,7 +1021,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
947
1021
|
});
|
|
948
1022
|
|
|
949
1023
|
services['root-dns'] = baseService({
|
|
950
|
-
|
|
1024
|
+
dockerfile: 'docker/Dockerfile.authoritative-dns',
|
|
951
1025
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.ROOT_DNS } },
|
|
952
1026
|
cap_add: ['NET_ADMIN'],
|
|
953
1027
|
volumes: [
|
|
@@ -957,7 +1031,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
957
1031
|
});
|
|
958
1032
|
|
|
959
1033
|
services['tld-dns'] = baseService({
|
|
960
|
-
|
|
1034
|
+
dockerfile: 'docker/Dockerfile.authoritative-dns',
|
|
961
1035
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.TLD_DNS } },
|
|
962
1036
|
cap_add: ['NET_ADMIN'],
|
|
963
1037
|
volumes: [
|
|
@@ -969,7 +1043,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
969
1043
|
});
|
|
970
1044
|
|
|
971
1045
|
services['namecheap-dns'] = baseService({
|
|
972
|
-
|
|
1046
|
+
dockerfile: 'docker/Dockerfile.namecheap-dns',
|
|
973
1047
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.NAMECHEAP_DNS } },
|
|
974
1048
|
cap_add: ['NET_ADMIN'],
|
|
975
1049
|
// Per-domain DDNS passwords for the cross-domain test. Fallback
|
|
@@ -999,7 +1073,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
999
1073
|
// cycle. See CLAUDE.md history for details.
|
|
1000
1074
|
|
|
1001
1075
|
services.letsencrypt = baseService({
|
|
1002
|
-
|
|
1076
|
+
dockerfile: 'docker/Dockerfile.pebble',
|
|
1003
1077
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.PEBBLE } },
|
|
1004
1078
|
cap_add: ['NET_ADMIN'],
|
|
1005
1079
|
command: '-config /config/pebble-config.json -dnsserver 203.0.113.1:53',
|
|
@@ -1015,7 +1089,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
1015
1089
|
// the package (bundled at build time from packages/registry-server,
|
|
1016
1090
|
// shipped in the npm tarball). See packages/e2e/src/registry-bundle.ts.
|
|
1017
1091
|
services.registry = baseService({
|
|
1018
|
-
|
|
1092
|
+
dockerfile: 'docker/Dockerfile.registry',
|
|
1019
1093
|
networks: { 'internet-external': { ipv4_address: SIMULATOR_IPS.REGISTRY } },
|
|
1020
1094
|
cap_add: ['NET_ADMIN'],
|
|
1021
1095
|
volumes: getRegistryVolumes(),
|
|
@@ -1045,7 +1119,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
1045
1119
|
}
|
|
1046
1120
|
|
|
1047
1121
|
services[machine.name] = baseService({
|
|
1048
|
-
|
|
1122
|
+
dockerfile,
|
|
1049
1123
|
networks: { [zoneNetwork]: { ipv4_address: machine.ip } },
|
|
1050
1124
|
privileged: true,
|
|
1051
1125
|
volumes: machineVolumes,
|
|
@@ -1056,7 +1130,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
1056
1130
|
|
|
1057
1131
|
if (config.dhcpClient) {
|
|
1058
1132
|
services['dhcp-client'] = baseService({
|
|
1059
|
-
|
|
1133
|
+
dockerfile: 'docker/Dockerfile.dhcp-client',
|
|
1060
1134
|
networks: { internal: { ipv4_address: zoneIp('internal', 210) } },
|
|
1061
1135
|
cap_add: ['NET_ADMIN'],
|
|
1062
1136
|
});
|