Files
n8n/packages/testing/containers/helm-start-stack.ts
alighasami 3d5eaf9445
Some checks failed
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
first commit
2026-03-17 16:22:57 +03:30

154 lines
5.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env tsx
import { writeFileSync } from 'node:fs';
import { parseArgs } from 'node:util';
import { createHelmStack, type HelmStackMode } from './helm-stack';
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
red: '\x1b[31m',
cyan: '\x1b[36m',
};
const log = {
info: (msg: string) => console.log(`${colors.blue}${colors.reset} ${msg}`),
success: (msg: string) => console.log(`${colors.green}${colors.reset} ${msg}`),
error: (msg: string) => console.error(`${colors.red}${colors.reset} ${msg}`),
header: (msg: string) => console.log(`\n${colors.bright}${colors.cyan}${msg}${colors.reset}\n`),
};
function showHelp() {
console.log(`
${colors.bright}n8n Helm Stack${colors.reset}
Start n8n via Helm chart in a K3s (lightweight Kubernetes) container.
${colors.yellow}Usage:${colors.reset}
pnpm stack:helm [options]
${colors.yellow}Options:${colors.reset}
--mode <mode> standalone (SQLite, default) or queue (PostgreSQL + Redis + workers)
--image <image> n8n Docker image (default: n8nio/n8n:local)
--chart-ref <ref> Git branch/tag for n8n-hosting repo (default: main)
--chart-repo <url> Git repo URL (default: https://github.com/n8n-io/n8n-hosting.git)
--k3s-image <image> K3s image (default: rancher/k3s:v1.32.2-k3s1)
--env <KEY=VALUE> Set environment variable in n8n pods (repeatable)
--url-file <path> Write URL to file when ready (for CI)
--help, -h Show this help
${colors.yellow}Examples:${colors.reset}
${colors.bright}# Start with default local image${colors.reset}
pnpm stack:helm
${colors.bright}# Test specific n8n version against specific chart${colors.reset}
pnpm stack:helm --image n8nio/n8n:1.80.0 --chart-ref v1.2.0
${colors.bright}# Queue mode (PostgreSQL + Redis + workers)${colors.reset}
pnpm stack:helm --mode queue --image n8nio/n8n:latest
${colors.bright}# E2E test mode (requires INCLUDE_TEST_CONTROLLER image)${colors.reset}
pnpm stack:helm --env E2E_TESTS=true --env NODE_ENV=development
${colors.bright}# CI mode (writes URL to file)${colors.reset}
pnpm stack:helm --url-file /tmp/n8n-url.txt &
${colors.yellow}Prerequisites:${colors.reset}
• Docker with privileged container support
• helm and kubectl CLIs installed locally
• n8n Docker image built locally (pnpm build:docker) or available on Docker Hub
• See HELM-TESTING.md for full requirements
${colors.yellow}Notes:${colors.reset}
• helm and kubectl run on your host (not inside K3s)
• Startup takes ~60-120s (K3s boot + image load + Helm install)
• After startup, use kubectl with KUBECONFIG printed below
• Press Ctrl+C to stop
`);
}
async function main() {
const { values } = parseArgs({
args: process.argv.slice(2),
options: {
help: { type: 'boolean', short: 'h' },
mode: { type: 'string' },
image: { type: 'string' },
'chart-ref': { type: 'string' },
'chart-repo': { type: 'string' },
'k3s-image': { type: 'string' },
env: { type: 'string', multiple: true },
'url-file': { type: 'string' },
'kubeconfig-file': { type: 'string' },
},
allowPositionals: false,
});
if (values.help) {
showHelp();
process.exit(0);
}
log.header('Starting n8n Helm Stack');
const mode = (values.mode as HelmStackMode) || undefined;
// Parse --env KEY=VALUE pairs into a record
const envOverrides: Record<string, string> = {};
for (const entry of values.env ?? []) {
const eqIndex = entry.indexOf('=');
if (eqIndex === -1) {
log.error(`Invalid --env format: "${entry}" (expected KEY=VALUE)`);
process.exit(1);
}
envOverrides[entry.slice(0, eqIndex)] = entry.slice(eqIndex + 1);
}
const stack = await createHelmStack({
n8nImage: values.image,
helmChartRef: values['chart-ref'],
helmChartRepo: values['chart-repo'],
k3sImage: values['k3s-image'],
mode,
env: Object.keys(envOverrides).length > 0 ? envOverrides : undefined,
});
log.header('Stack Ready');
log.success(`n8n URL: ${colors.bright}${colors.green}${stack.baseUrl}${colors.reset}`);
log.info(`Kubeconfig: ${colors.bright}${stack.kubeConfigPath}${colors.reset}`);
if (values['url-file']) {
writeFileSync(values['url-file'], stack.baseUrl);
log.info(`URL written to ${values['url-file']}`);
}
if (values['kubeconfig-file']) {
writeFileSync(values['kubeconfig-file'], stack.kubeConfigPath);
log.info(`Kubeconfig path written to ${values['kubeconfig-file']}`);
}
console.log('');
log.info('Debug with kubectl (context already active):');
log.info(` ${colors.bright}kubectl get pods${colors.reset}`);
log.info(` ${colors.bright}kubectl logs -l app.kubernetes.io/name=n8n${colors.reset}`);
console.log('');
log.info(`Cleanup: ${colors.bright}pnpm --filter n8n-containers stack:helm:clean${colors.reset}`);
console.log('');
if (envOverrides.E2E_TESTS === 'true') {
log.info('Run tests against this instance:');
log.info(
` ${colors.bright}N8N_BASE_URL=${stack.baseUrl} RESET_E2E_DB=true npx playwright test tests/e2e/building-blocks/ --workers=1${colors.reset}`,
);
}
// Container stays alive in Docker (Ryuk disabled) — clean up via stack:helm:clean.
}
main().catch((error) => {
log.error(`Failed to start: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
});