@celilo/e2e 0.4.0 → 0.5.1
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/bin/e2e-build +46 -3
- package/config/dns/iamtheinternet.org.zone +1 -1
- package/config/routing/management-routes.sh +35 -26
- package/docker/Dockerfile.management +12 -2
- package/docker/Dockerfile.target-machine +3 -0
- package/docker/Dockerfile.target-machine-docker +3 -0
- package/netapps/.gitkeep +0 -0
- package/netapps/authentik.netapp +0 -0
- package/netapps/caddy.netapp +0 -0
- package/netapps/greenwave.netapp +0 -0
- package/netapps/iptables.netapp +0 -0
- package/netapps/namecheap.netapp +0 -0
- package/package.json +2 -1
- package/src/container-manager.ts +66 -4
package/bin/e2e-build
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
#
|
|
3
|
-
# Pre-build all E2E Docker images.
|
|
3
|
+
# Pre-build all E2E Docker images and package standard modules as .netapps.
|
|
4
4
|
#
|
|
5
5
|
# Run once before the test suite. Subsequent test runs use the cached
|
|
6
6
|
# images and skip the build phase entirely (~5s vs ~3min per test).
|
|
7
7
|
#
|
|
8
8
|
# Usage:
|
|
9
|
-
# ./e2e/bin/e2e-build # build all images
|
|
9
|
+
# ./e2e/bin/e2e-build # build netapps + all images
|
|
10
10
|
# ./e2e/bin/e2e-build --save # build + save to tarball for colima restarts
|
|
11
11
|
#
|
|
12
12
|
|
|
@@ -14,6 +14,11 @@ set -e
|
|
|
14
14
|
|
|
15
15
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
16
|
E2E_DIR="$(dirname "$SCRIPT_DIR")"
|
|
17
|
+
PKG_DIR="$E2E_DIR"
|
|
18
|
+
REPO_ROOT="$(cd "$E2E_DIR/../.." && pwd)"
|
|
19
|
+
MODULES_DIR="$REPO_ROOT/modules"
|
|
20
|
+
NETAPPS_DIR="$E2E_DIR/netapps"
|
|
21
|
+
|
|
17
22
|
cd "$E2E_DIR"
|
|
18
23
|
|
|
19
24
|
GREEN='\033[0;32m'
|
|
@@ -21,6 +26,43 @@ DIM='\033[2m'
|
|
|
21
26
|
BOLD='\033[1m'
|
|
22
27
|
NC='\033[0m'
|
|
23
28
|
|
|
29
|
+
# ── Step 1: Package standard modules as .netapp files ─────────────────────────
|
|
30
|
+
|
|
31
|
+
STANDARD_MODULES=(namecheap greenwave iptables caddy authentik)
|
|
32
|
+
|
|
33
|
+
echo -e "${BOLD}Packaging standard modules...${NC}"
|
|
34
|
+
echo ""
|
|
35
|
+
|
|
36
|
+
mkdir -p "$NETAPPS_DIR"
|
|
37
|
+
|
|
38
|
+
for MODULE in "${STANDARD_MODULES[@]}"; do
|
|
39
|
+
SRC="$MODULES_DIR/$MODULE"
|
|
40
|
+
OUT="$NETAPPS_DIR/$MODULE.netapp"
|
|
41
|
+
|
|
42
|
+
if [ ! -d "$SRC" ]; then
|
|
43
|
+
echo -e " ${DIM}skip${NC} $MODULE ${DIM}(not found at $SRC)${NC}"
|
|
44
|
+
continue
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
printf " %-20s " "$MODULE"
|
|
48
|
+
BUILD_START=$(date +%s)
|
|
49
|
+
|
|
50
|
+
# Use the wrapper script if available, else bun directly
|
|
51
|
+
if [ -x "$REPO_ROOT/celilo" ]; then
|
|
52
|
+
"$REPO_ROOT/celilo" package "$SRC" --output "$OUT" > /dev/null 2>&1
|
|
53
|
+
else
|
|
54
|
+
bun run "$REPO_ROOT/apps/celilo/src/cli/index.ts" package "$SRC" --output "$OUT" > /dev/null 2>&1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
BUILD_END=$(date +%s)
|
|
58
|
+
SIZE=$(du -h "$OUT" 2>/dev/null | cut -f1)
|
|
59
|
+
echo -e "${GREEN}✔${NC} ${DIM}$((BUILD_END - BUILD_START))s ${SIZE}${NC}"
|
|
60
|
+
done
|
|
61
|
+
|
|
62
|
+
echo ""
|
|
63
|
+
|
|
64
|
+
# ── Step 2: Build Docker images ───────────────────────────────────────────────
|
|
65
|
+
|
|
24
66
|
echo -e "${BOLD}Building E2E Docker images...${NC}"
|
|
25
67
|
echo ""
|
|
26
68
|
|
|
@@ -48,7 +90,8 @@ TOTAL_TIME=$((END - START))
|
|
|
48
90
|
echo ""
|
|
49
91
|
echo -e "${GREEN}All $TOTAL images built in ${TOTAL_TIME}s${NC}"
|
|
50
92
|
|
|
51
|
-
# Optionally save to tarball
|
|
93
|
+
# ── Step 3: Optionally save images to tarball ─────────────────────────────────
|
|
94
|
+
|
|
52
95
|
if [ "$1" = "--save" ]; then
|
|
53
96
|
echo ""
|
|
54
97
|
echo -e "${BOLD}Saving images to tarball...${NC}"
|
|
@@ -34,20 +34,34 @@ echo "nameserver 100.100.0.1" > /etc/resolv.conf
|
|
|
34
34
|
# Create celilo data directory (Linux default: /var/lib/celilo/)
|
|
35
35
|
mkdir -p /var/lib/celilo/modules
|
|
36
36
|
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
# If the monorepo is mounted at /celilo, use it for shell completions (dev mode).
|
|
38
|
+
# Otherwise use the globally installed CLI from npm.
|
|
39
|
+
if [ -d /celilo/apps/celilo ]; then
|
|
40
|
+
CELILO_SRC="/celilo/apps/celilo/src/cli/index.ts"
|
|
41
|
+
CELILO_CMD="bun run $CELILO_SRC"
|
|
42
|
+
|
|
43
|
+
# Warn if node_modules are missing (developer forgot to bun install)
|
|
44
|
+
if [ ! -d /celilo/apps/celilo/node_modules/@clack ]; then
|
|
45
|
+
echo "WARNING: /celilo/apps/celilo/node_modules not found. Run 'cd apps/celilo && bun install' on the host."
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Generate zsh completions from source
|
|
49
|
+
mkdir -p /root/.zsh/completions
|
|
50
|
+
bun run "$CELILO_SRC" completion zsh > /root/.zsh/completions/_celilo 2>/dev/null || true
|
|
51
|
+
|
|
52
|
+
START_DIR="/celilo/apps/celilo"
|
|
53
|
+
else
|
|
54
|
+
CELILO_CMD="celilo"
|
|
55
|
+
START_DIR="/root"
|
|
56
|
+
|
|
57
|
+
# Generate zsh completions from npm-installed CLI
|
|
58
|
+
mkdir -p /root/.zsh/completions
|
|
59
|
+
celilo completion zsh > /root/.zsh/completions/_celilo 2>/dev/null || true
|
|
42
60
|
fi
|
|
43
61
|
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# Shell setup: aliases and completion for zsh
|
|
49
|
-
cat > /root/.zshrc << 'ZSHRC'
|
|
50
|
-
export PATH="/root/.bun/bin:$PATH"
|
|
62
|
+
# Shell setup
|
|
63
|
+
cat > /root/.zshrc << ZSHRC
|
|
64
|
+
export PATH="/root/.bun/bin:/usr/local/bin:\$PATH"
|
|
51
65
|
|
|
52
66
|
# Simulated network overrides
|
|
53
67
|
export DDNS_ENDPOINT="http://100.64.0.55:8080/update"
|
|
@@ -69,27 +83,22 @@ bindkey '^R' history-incremental-search-backward
|
|
|
69
83
|
# Prompt
|
|
70
84
|
PROMPT='%F{cyan}celilo%f:%F{yellow}%~%f# '
|
|
71
85
|
|
|
72
|
-
# Commands
|
|
73
|
-
|
|
74
|
-
c() { celilo "$@"; }
|
|
86
|
+
# Commands — celilo shim in /usr/local/bin prefers source when /celilo is mounted
|
|
87
|
+
alias c='celilo'
|
|
75
88
|
alias ll='ls -la'
|
|
76
89
|
|
|
77
|
-
# Tab completion
|
|
78
|
-
fpath=(~/.zsh/completions
|
|
90
|
+
# Tab completion
|
|
91
|
+
fpath=(~/.zsh/completions \$fpath)
|
|
79
92
|
autoload -Uz compinit && compinit -u
|
|
80
93
|
|
|
81
|
-
|
|
82
|
-
compdef _celilo c
|
|
83
|
-
|
|
84
|
-
cd /celilo/apps/celilo
|
|
94
|
+
cd $START_DIR
|
|
85
95
|
ZSHRC
|
|
86
96
|
|
|
87
|
-
#
|
|
88
|
-
cat > /root/.bashrc <<
|
|
89
|
-
export PATH="/root/.bun/bin
|
|
90
|
-
alias celilo='bun run /celilo/apps/celilo/src/cli/index.ts'
|
|
97
|
+
# Bash fallback (for non-zsh shells)
|
|
98
|
+
cat > /root/.bashrc << BASHRC
|
|
99
|
+
export PATH="/root/.bun/bin:/usr/local/bin:\$PATH"
|
|
91
100
|
alias c='celilo'
|
|
92
|
-
cd
|
|
101
|
+
cd $START_DIR
|
|
93
102
|
BASHRC
|
|
94
103
|
|
|
95
104
|
echo "Management machine ready"
|
|
@@ -22,8 +22,18 @@ 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
|
|
26
|
-
|
|
25
|
+
# Install celilo CLI from npm. bun installs the bin to /usr/local/bin/celilo
|
|
26
|
+
# on the oven/bun base image. We rename it so our shim can fall back to it.
|
|
27
|
+
RUN bun add -g @celilo/cli@0.1.5 \
|
|
28
|
+
&& mv /usr/local/bin/celilo /usr/local/bin/celilo-npm
|
|
29
|
+
|
|
30
|
+
# Shim: prefer /celilo source when mounted (dev loop), fall back to npm install.
|
|
31
|
+
RUN printf '#!/bin/bash\nif [ -d /celilo/apps/celilo ]; then\n exec bun run /celilo/apps/celilo/src/cli/index.ts "$@"\nfi\nexec /usr/local/bin/celilo-npm "$@"\n' > /usr/local/bin/celilo \
|
|
32
|
+
&& chmod +x /usr/local/bin/celilo
|
|
33
|
+
|
|
34
|
+
# Standard modules pre-packaged as .netapp files — built by e2e-build.
|
|
35
|
+
# Tests import from /netapps/<module>.netapp instead of the monorepo mount.
|
|
36
|
+
COPY netapps/ /netapps/
|
|
27
37
|
|
|
28
38
|
COPY config/ssh/generate-keys.sh /config/ssh/generate-keys.sh
|
|
29
39
|
COPY config/routing/management-routes.sh /startup.sh
|
package/netapps/.gitkeep
ADDED
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@celilo/e2e",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
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",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"config/",
|
|
22
22
|
"simulators/",
|
|
23
23
|
"bin/",
|
|
24
|
+
"netapps/",
|
|
24
25
|
"README.md"
|
|
25
26
|
],
|
|
26
27
|
"dependencies": {
|
package/src/container-manager.ts
CHANGED
|
@@ -108,9 +108,11 @@ function dockerExecAsync(
|
|
|
108
108
|
timeoutMs = 60_000,
|
|
109
109
|
): Promise<ExecResult> {
|
|
110
110
|
return new Promise((resolve) => {
|
|
111
|
+
// stdbuf -oL forces line-buffered stdout so output streams in real time
|
|
112
|
+
// rather than appearing in one burst when the process's buffer flushes.
|
|
111
113
|
const args = [
|
|
112
114
|
'compose', '-f', COMPOSE_FILE, '-p', projectName,
|
|
113
|
-
'exec', '-T', container, 'bash', '-c', cmd,
|
|
115
|
+
'exec', '-T', container, 'stdbuf', '-oL', 'bash', '-c', cmd,
|
|
114
116
|
];
|
|
115
117
|
const child = spawn('docker', args, { cwd: composeDir });
|
|
116
118
|
|
|
@@ -158,6 +160,66 @@ async function waitFor(
|
|
|
158
160
|
throw new Error(`Timeout waiting for ${label} after ${timeoutMs}ms`);
|
|
159
161
|
}
|
|
160
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Run `docker compose build` with per-service progress signals.
|
|
165
|
+
* Uses --progress=plain so output is parseable on non-TTY.
|
|
166
|
+
* Emits one [progress:start] per service being built so the runner
|
|
167
|
+
* shows "building <service>" as each image is compiled.
|
|
168
|
+
*/
|
|
169
|
+
async function streamingBuild(
|
|
170
|
+
projectName: string,
|
|
171
|
+
composeDir: string,
|
|
172
|
+
composeFile: string,
|
|
173
|
+
): Promise<void> {
|
|
174
|
+
return new Promise<void>((resolve, reject) => {
|
|
175
|
+
const proc = spawn(
|
|
176
|
+
'docker',
|
|
177
|
+
['compose', '-f', composeFile, '-p', projectName, 'build', '--progress=plain'],
|
|
178
|
+
{ cwd: composeDir },
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const seenServices = new Set<string>();
|
|
182
|
+
let stderr = '';
|
|
183
|
+
|
|
184
|
+
function handleLine(line: string) {
|
|
185
|
+
// --progress=plain lines look like: #5 [management 2/4] RUN apt-get ...
|
|
186
|
+
const svcMatch = line.match(/\[([a-z][a-z0-9-]*)\s+\d+\/\d+\]/);
|
|
187
|
+
if (svcMatch) {
|
|
188
|
+
const svc = svcMatch[1];
|
|
189
|
+
if (!seenServices.has(svc)) {
|
|
190
|
+
seenServices.add(svc);
|
|
191
|
+
// Each new service auto-finalizes the previous [progress:start] in the runner.
|
|
192
|
+
console.log(`[progress:start] building image: ${svc} | ${svc} image ready`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let buf = '';
|
|
198
|
+
function onData(chunk: Buffer) {
|
|
199
|
+
buf += chunk.toString();
|
|
200
|
+
const lines = buf.split('\n');
|
|
201
|
+
buf = lines.pop() ?? '';
|
|
202
|
+
for (const line of lines) handleLine(line.trim());
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
proc.stdout.on('data', onData);
|
|
206
|
+
proc.stderr.on('data', (chunk: Buffer) => {
|
|
207
|
+
stderr += chunk.toString();
|
|
208
|
+
onData(chunk);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
proc.on('close', (code) => {
|
|
212
|
+
if (buf.trim()) handleLine(buf.trim());
|
|
213
|
+
if (code === 0) {
|
|
214
|
+
console.log('[progress:done] images built');
|
|
215
|
+
resolve();
|
|
216
|
+
} else {
|
|
217
|
+
reject(new Error(`docker compose build failed (exit ${code}):\n${stderr.slice(-500)}`));
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
161
223
|
export async function startNetwork(config: NetworkConfig): Promise<NetworkHandle> {
|
|
162
224
|
// Pre-flight: fail if live containers are running that will compete for resources.
|
|
163
225
|
try {
|
|
@@ -218,9 +280,9 @@ export async function startNetwork(config: NetworkConfig): Promise<NetworkHandle
|
|
|
218
280
|
const yaml = generateTestComposeYaml(config, celiloRoot);
|
|
219
281
|
writeFileSync(join(composeDir, COMPOSE_FILE), yaml);
|
|
220
282
|
|
|
221
|
-
// Build and start per-test containers only
|
|
222
|
-
|
|
223
|
-
|
|
283
|
+
// Build and start per-test containers only — stream output so the runner
|
|
284
|
+
// can show which service is currently being built (can take minutes on cold cache).
|
|
285
|
+
await streamingBuild(projectName, composeDir, COMPOSE_FILE);
|
|
224
286
|
|
|
225
287
|
console.log('[progress:start] starting containers | containers running');
|
|
226
288
|
run(`docker compose -f ${COMPOSE_FILE} -p ${projectName} up -d`, { cwd: composeDir, timeout: 120_000 });
|