@celilo/e2e 0.2.0 → 0.3.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.
|
@@ -2,14 +2,14 @@ $ORIGIN iamtheinternet.org.
|
|
|
2
2
|
$TTL 300
|
|
3
3
|
|
|
4
4
|
@ IN SOA ns1.iamtheinternet.org. admin.iamtheinternet.org. (
|
|
5
|
-
|
|
5
|
+
2024010769 300 60 604800 300
|
|
6
6
|
)
|
|
7
7
|
|
|
8
8
|
@ IN NS ns1.iamtheinternet.org.
|
|
9
9
|
ns1 IN A 100.64.0.55
|
|
10
10
|
@ IN A 0.0.0.0
|
|
11
11
|
caddy IN A 100.100.0.100
|
|
12
|
-
www IN A
|
|
12
|
+
www IN A 100.100.0.100
|
|
13
13
|
deathstar IN A 100.100.0.100
|
|
14
14
|
test IN A 0.0.0.0
|
|
15
15
|
auth IN A 100.100.0.100
|
|
@@ -22,9 +22,12 @@ RUN update-ca-certificates
|
|
|
22
22
|
# Point apt at the simulated apt cache proxy (for runtime apt usage)
|
|
23
23
|
RUN echo 'Acquire::http::Proxy "http://100.64.0.2:3142";' > /etc/apt/apt.conf.d/00proxy
|
|
24
24
|
|
|
25
|
+
# Install celilo CLI from npm — provides the `celilo` command
|
|
26
|
+
RUN bun add -g @celilo/cli@0.1.4
|
|
27
|
+
|
|
25
28
|
COPY config/ssh/generate-keys.sh /config/ssh/generate-keys.sh
|
|
26
29
|
COPY config/routing/management-routes.sh /startup.sh
|
|
27
30
|
RUN chmod +x /startup.sh /config/ssh/generate-keys.sh
|
|
28
31
|
|
|
29
|
-
WORKDIR /
|
|
32
|
+
WORKDIR /root
|
|
30
33
|
CMD ["/startup.sh"]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@celilo/e2e",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "E2E test infrastructure for Celilo-deployed applications. Provides a simulated internet with DNS hierarchy, ACME server, firewalls, and target machines in Docker.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
package/src/container-manager.ts
CHANGED
|
@@ -13,7 +13,12 @@ const PACKAGE_ROOT = join(__dirname, '..');
|
|
|
13
13
|
* Find the Celilo project root by walking up from the package directory.
|
|
14
14
|
* Looks for apps/celilo/ as the marker.
|
|
15
15
|
*/
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Try to find the Celilo project root by walking up from the package directory.
|
|
18
|
+
* Returns undefined if not found — the CLI is pre-installed in Docker so this
|
|
19
|
+
* is only needed for development (mounting local source).
|
|
20
|
+
*/
|
|
21
|
+
function findCeliloRoot(): string | undefined {
|
|
17
22
|
let dir = PACKAGE_ROOT;
|
|
18
23
|
for (let i = 0; i < 10; i++) {
|
|
19
24
|
if (existsSync(join(dir, 'apps', 'celilo'))) {
|
|
@@ -23,10 +28,7 @@ function findCeliloRoot(): string {
|
|
|
23
28
|
if (parent === dir) break;
|
|
24
29
|
dir = parent;
|
|
25
30
|
}
|
|
26
|
-
|
|
27
|
-
'Could not find Celilo project root (directory containing apps/celilo/).\n' +
|
|
28
|
-
'Set it explicitly: network().celilo("/path/to/infra").start()',
|
|
29
|
-
);
|
|
31
|
+
return undefined;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
const COMPOSE_TIMEOUT = 120_000;
|
|
@@ -218,7 +220,7 @@ export async function startNetwork(config: NetworkConfig): Promise<NetworkHandle
|
|
|
218
220
|
|
|
219
221
|
// Build and start per-test containers only
|
|
220
222
|
console.log('[progress:start] building Docker images | images built');
|
|
221
|
-
run(`docker compose -f ${COMPOSE_FILE} -p ${projectName} build`, { cwd: composeDir, timeout:
|
|
223
|
+
run(`docker compose -f ${COMPOSE_FILE} -p ${projectName} build`, { cwd: composeDir, timeout: 600_000 });
|
|
222
224
|
|
|
223
225
|
console.log('[progress:start] starting containers | containers running');
|
|
224
226
|
run(`docker compose -f ${COMPOSE_FILE} -p ${projectName} up -d`, { cwd: composeDir, timeout: 120_000 });
|
|
@@ -296,7 +298,7 @@ export async function startNetwork(config: NetworkConfig): Promise<NetworkHandle
|
|
|
296
298
|
// Initialize celilo
|
|
297
299
|
console.log('[progress:start] initializing celilo | celilo initialized');
|
|
298
300
|
const initResult = dockerExec(projectName, composeDir, 'management',
|
|
299
|
-
`
|
|
301
|
+
`celilo system init --accept-defaults \
|
|
300
302
|
network.dmz.subnet=10.0.10.0/24 \
|
|
301
303
|
network.app.subnet=10.0.20.0/24 \
|
|
302
304
|
network.secure.subnet=10.0.30.0/24 \
|
|
@@ -317,7 +319,7 @@ export async function startNetwork(config: NetworkConfig): Promise<NetworkHandle
|
|
|
317
319
|
const timeoutMs = typeof optsOrTimeout === 'number' ? optsOrTimeout : (optsOrTimeout?.timeoutMs ?? 120_000);
|
|
318
320
|
|
|
319
321
|
const result = await dockerExecAsync(projectName, composeDir, 'management',
|
|
320
|
-
`
|
|
322
|
+
`celilo ${cmd}`, timeoutMs);
|
|
321
323
|
|
|
322
324
|
if (check && result.exitCode !== 0) {
|
|
323
325
|
throw new CeliloCommandError(cmd, result);
|
|
@@ -227,7 +227,7 @@ export function generateSharedInfraYaml(): string {
|
|
|
227
227
|
* References the shared infrastructure's isp-external network as external.
|
|
228
228
|
* Creates its own internal, dmz, app, secure networks.
|
|
229
229
|
*/
|
|
230
|
-
export function generateTestComposeYaml(config: NetworkConfig, celiloRoot
|
|
230
|
+
export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: string): string {
|
|
231
231
|
const networks: Record<string, unknown> = {
|
|
232
232
|
internal: networkDef('192.168.0.0/24', '192.168.0.250'),
|
|
233
233
|
dmz: networkDef('10.0.10.0/24', '10.0.10.250'),
|
|
@@ -259,7 +259,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot = '..'
|
|
|
259
259
|
networks: { internal: { ipv4_address: '192.168.0.100' } },
|
|
260
260
|
cap_add: ['NET_ADMIN'],
|
|
261
261
|
volumes: [
|
|
262
|
-
`${celiloRoot}:/celilo
|
|
262
|
+
...(celiloRoot ? [`${celiloRoot}:/celilo`] : []),
|
|
263
263
|
'ssh-keys:/ssh-keys',
|
|
264
264
|
...(config.managementVolumes ?? []),
|
|
265
265
|
],
|
|
@@ -371,7 +371,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
371
371
|
networks: { internal: { ipv4_address: '192.168.0.100' } },
|
|
372
372
|
cap_add: ['NET_ADMIN'],
|
|
373
373
|
volumes: [
|
|
374
|
-
`${celiloRoot}:/celilo
|
|
374
|
+
...(celiloRoot ? [`${celiloRoot}:/celilo`] : []),
|
|
375
375
|
'ssh-keys:/ssh-keys',
|
|
376
376
|
...(config.managementVolumes ?? []),
|
|
377
377
|
],
|
package/src/network-builder.ts
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
1
4
|
import { startNetwork } from './container-manager';
|
|
2
5
|
import type { NetworkConfig, NetworkHandle, TopologyPreset } from './types';
|
|
3
6
|
|
|
7
|
+
/**
|
|
8
|
+
* If a mounted path looks like a celilo module (has scripts/package.json),
|
|
9
|
+
* ensure its dependencies are installed on the host before Docker starts.
|
|
10
|
+
*/
|
|
11
|
+
async function ensureModuleDeps(hostPath: string): Promise<void> {
|
|
12
|
+
// Check common locations for a module's scripts dir
|
|
13
|
+
for (const scriptsDir of [
|
|
14
|
+
join(hostPath, 'scripts'),
|
|
15
|
+
join(hostPath, 'celilo', 'scripts'),
|
|
16
|
+
]) {
|
|
17
|
+
const pkgJson = join(scriptsDir, 'package.json');
|
|
18
|
+
const nodeModules = join(scriptsDir, 'node_modules');
|
|
19
|
+
if (existsSync(pkgJson) && !existsSync(nodeModules)) {
|
|
20
|
+
console.log(`[progress:start] installing deps in ${scriptsDir} | deps installed`);
|
|
21
|
+
try {
|
|
22
|
+
execSync('bun install', { cwd: scriptsDir, timeout: 30_000, stdio: 'pipe' });
|
|
23
|
+
} catch (err) {
|
|
24
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Failed to install module dependencies in ${scriptsDir}:\n${msg}\n\n` +
|
|
27
|
+
`Fix: cd ${scriptsDir} && bun install`,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
4
34
|
export class NetworkBuilder {
|
|
5
35
|
private config: NetworkConfig = {
|
|
6
36
|
topology: 'default',
|
|
@@ -82,6 +112,13 @@ export class NetworkBuilder {
|
|
|
82
112
|
}
|
|
83
113
|
|
|
84
114
|
async start(): Promise<NetworkHandle> {
|
|
115
|
+
// Pre-flight: ensure mounted module directories have deps installed.
|
|
116
|
+
// Without this, `module import` tries to `bun install` inside Docker
|
|
117
|
+
// through the simulated internet, which is slow or fails.
|
|
118
|
+
for (const vol of this.config.managementVolumes) {
|
|
119
|
+
const [hostPath] = vol.split(':');
|
|
120
|
+
await ensureModuleDeps(hostPath);
|
|
121
|
+
}
|
|
85
122
|
return startNetwork(this.config);
|
|
86
123
|
}
|
|
87
124
|
}
|
package/src/runner.ts
CHANGED
|
@@ -505,15 +505,6 @@ async function main() {
|
|
|
505
505
|
console.log(`${bold}╚══════════════════════════════════════════════════════════════╝${reset}`);
|
|
506
506
|
console.log();
|
|
507
507
|
|
|
508
|
-
// Shared infra check
|
|
509
|
-
console.log(`${bold}Shared Infrastructure${reset}`);
|
|
510
|
-
if (isSharedInfraHealthy()) {
|
|
511
|
-
console.log(` ${green}✔ already running (DNS healthy)${reset}`);
|
|
512
|
-
} else {
|
|
513
|
-
console.log(` ${dim}Will start on first test...${reset}`);
|
|
514
|
-
}
|
|
515
|
-
console.log();
|
|
516
|
-
|
|
517
508
|
const suiteStart = Date.now();
|
|
518
509
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
519
510
|
const resultsDir = join(testDir, 'results', timestamp);
|