367 lines
8.5 KiB
TypeScript
367 lines
8.5 KiB
TypeScript
|
|
/**
|
||
|
|
* CLI Router for Onebox
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { logger } from './onebox.logging.ts';
|
||
|
|
import { projectInfo } from './onebox.info.ts';
|
||
|
|
import { Onebox } from './onebox.classes.onebox.ts';
|
||
|
|
|
||
|
|
export async function runCli(): Promise<void> {
|
||
|
|
const args = Deno.args;
|
||
|
|
|
||
|
|
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
||
|
|
printHelp();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (args.includes('--version') || args.includes('-v')) {
|
||
|
|
console.log(`${projectInfo.name} v${projectInfo.version}`);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const command = args[0];
|
||
|
|
const subcommand = args[1];
|
||
|
|
|
||
|
|
try {
|
||
|
|
// Initialize Onebox
|
||
|
|
const onebox = new Onebox();
|
||
|
|
await onebox.init();
|
||
|
|
|
||
|
|
// Route commands
|
||
|
|
switch (command) {
|
||
|
|
case 'service':
|
||
|
|
await handleServiceCommand(onebox, subcommand, args.slice(2));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'registry':
|
||
|
|
await handleRegistryCommand(onebox, subcommand, args.slice(2));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'dns':
|
||
|
|
await handleDnsCommand(onebox, subcommand, args.slice(2));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'ssl':
|
||
|
|
await handleSslCommand(onebox, subcommand, args.slice(2));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'nginx':
|
||
|
|
await handleNginxCommand(onebox, subcommand, args.slice(2));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'daemon':
|
||
|
|
await handleDaemonCommand(onebox, subcommand, args.slice(2));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'config':
|
||
|
|
await handleConfigCommand(onebox, subcommand, args.slice(2));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'status':
|
||
|
|
await handleStatusCommand(onebox);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
logger.error(`Unknown command: ${command}`);
|
||
|
|
printHelp();
|
||
|
|
Deno.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Cleanup
|
||
|
|
await onebox.shutdown();
|
||
|
|
} catch (error) {
|
||
|
|
logger.error(error.message);
|
||
|
|
Deno.exit(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Service commands
|
||
|
|
async function handleServiceCommand(onebox: Onebox, subcommand: string, args: string[]) {
|
||
|
|
switch (subcommand) {
|
||
|
|
case 'add': {
|
||
|
|
const name = args[0];
|
||
|
|
const image = getArg(args, '--image');
|
||
|
|
const domain = getArg(args, '--domain');
|
||
|
|
const port = parseInt(getArg(args, '--port') || '80', 10);
|
||
|
|
const envArgs = args.filter((a) => a.startsWith('--env=')).map((a) => a.slice(6));
|
||
|
|
const envVars: Record<string, string> = {};
|
||
|
|
for (const env of envArgs) {
|
||
|
|
const [key, value] = env.split('=');
|
||
|
|
envVars[key] = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
await onebox.services.deployService({ name, image, port, domain, envVars });
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case 'remove':
|
||
|
|
await onebox.services.removeService(args[0]);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'start':
|
||
|
|
await onebox.services.startService(args[0]);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'stop':
|
||
|
|
await onebox.services.stopService(args[0]);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'restart':
|
||
|
|
await onebox.services.restartService(args[0]);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'list': {
|
||
|
|
const services = onebox.services.listServices();
|
||
|
|
logger.table(
|
||
|
|
['Name', 'Image', 'Status', 'Domain', 'Port'],
|
||
|
|
services.map((s) => [s.name, s.image, s.status, s.domain || '-', s.port.toString()])
|
||
|
|
);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case 'logs': {
|
||
|
|
const logs = await onebox.services.getServiceLogs(args[0]);
|
||
|
|
console.log(logs);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
logger.error(`Unknown service subcommand: ${subcommand}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Registry commands
|
||
|
|
async function handleRegistryCommand(onebox: Onebox, subcommand: string, args: string[]) {
|
||
|
|
switch (subcommand) {
|
||
|
|
case 'add': {
|
||
|
|
const url = getArg(args, '--url');
|
||
|
|
const username = getArg(args, '--username');
|
||
|
|
const password = getArg(args, '--password');
|
||
|
|
await onebox.registries.addRegistry(url, username, password);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case 'remove':
|
||
|
|
await onebox.registries.removeRegistry(getArg(args, '--url'));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'list': {
|
||
|
|
const registries = onebox.registries.listRegistries();
|
||
|
|
logger.table(
|
||
|
|
['URL', 'Username'],
|
||
|
|
registries.map((r) => [r.url, r.username])
|
||
|
|
);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
logger.error(`Unknown registry subcommand: ${subcommand}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// DNS commands
|
||
|
|
async function handleDnsCommand(onebox: Onebox, subcommand: string, args: string[]) {
|
||
|
|
switch (subcommand) {
|
||
|
|
case 'add':
|
||
|
|
await onebox.dns.addDNSRecord(args[0]);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'remove':
|
||
|
|
await onebox.dns.removeDNSRecord(args[0]);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'list': {
|
||
|
|
const records = onebox.dns.listDNSRecords();
|
||
|
|
logger.table(
|
||
|
|
['Domain', 'Type', 'Value'],
|
||
|
|
records.map((r) => [r.domain, r.type, r.value])
|
||
|
|
);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case 'sync':
|
||
|
|
await onebox.dns.syncFromCloudflare();
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
logger.error(`Unknown dns subcommand: ${subcommand}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// SSL commands
|
||
|
|
async function handleSslCommand(onebox: Onebox, subcommand: string, args: string[]) {
|
||
|
|
switch (subcommand) {
|
||
|
|
case 'renew':
|
||
|
|
if (args[0]) {
|
||
|
|
await onebox.ssl.renewCertificate(args[0]);
|
||
|
|
} else {
|
||
|
|
await onebox.ssl.renewExpiring();
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'list': {
|
||
|
|
const certs = onebox.ssl.listCertificates();
|
||
|
|
logger.table(
|
||
|
|
['Domain', 'Expiry', 'Issuer'],
|
||
|
|
certs.map((c) => [c.domain, new Date(c.expiryDate).toISOString(), c.issuer])
|
||
|
|
);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case 'force-renew':
|
||
|
|
await onebox.ssl.renewCertificate(args[0]);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
logger.error(`Unknown ssl subcommand: ${subcommand}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Nginx commands
|
||
|
|
async function handleNginxCommand(onebox: Onebox, subcommand: string, _args: string[]) {
|
||
|
|
switch (subcommand) {
|
||
|
|
case 'reload':
|
||
|
|
await onebox.nginx.reload();
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'test':
|
||
|
|
await onebox.nginx.test();
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'status': {
|
||
|
|
const status = await onebox.nginx.getStatus();
|
||
|
|
logger.info(`Nginx status: ${status}`);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
logger.error(`Unknown nginx subcommand: ${subcommand}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Daemon commands
|
||
|
|
async function handleDaemonCommand(onebox: Onebox, subcommand: string, _args: string[]) {
|
||
|
|
switch (subcommand) {
|
||
|
|
case 'install':
|
||
|
|
await onebox.daemon.installService();
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'start':
|
||
|
|
await onebox.startDaemon();
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'stop':
|
||
|
|
await onebox.stopDaemon();
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'logs': {
|
||
|
|
const command = new Deno.Command('journalctl', {
|
||
|
|
args: ['-u', 'smartdaemon_onebox', '-f'],
|
||
|
|
stdout: 'inherit',
|
||
|
|
stderr: 'inherit',
|
||
|
|
});
|
||
|
|
await command.output();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case 'status': {
|
||
|
|
const status = await onebox.daemon.getServiceStatus();
|
||
|
|
logger.info(`Daemon status: ${status}`);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
logger.error(`Unknown daemon subcommand: ${subcommand}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Config commands
|
||
|
|
async function handleConfigCommand(onebox: Onebox, subcommand: string, args: string[]) {
|
||
|
|
switch (subcommand) {
|
||
|
|
case 'show': {
|
||
|
|
const settings = onebox.database.getAllSettings();
|
||
|
|
logger.table(
|
||
|
|
['Key', 'Value'],
|
||
|
|
Object.entries(settings).map(([k, v]) => [k, v])
|
||
|
|
);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case 'set':
|
||
|
|
onebox.database.setSetting(args[0], args[1]);
|
||
|
|
logger.success(`Setting ${args[0]} updated`);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
logger.error(`Unknown config subcommand: ${subcommand}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Status command
|
||
|
|
async function handleStatusCommand(onebox: Onebox) {
|
||
|
|
const status = await onebox.getSystemStatus();
|
||
|
|
console.log(JSON.stringify(status, null, 2));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Helpers
|
||
|
|
function getArg(args: string[], flag: string): string {
|
||
|
|
const arg = args.find((a) => a.startsWith(`${flag}=`));
|
||
|
|
return arg ? arg.split('=')[1] : '';
|
||
|
|
}
|
||
|
|
|
||
|
|
function printHelp(): void {
|
||
|
|
console.log(`
|
||
|
|
Onebox v${projectInfo.version} - Self-hosted container platform
|
||
|
|
|
||
|
|
Usage: onebox <command> [options]
|
||
|
|
|
||
|
|
Commands:
|
||
|
|
service add <name> --image <image> [--domain <domain>] [--port <port>] [--env KEY=VALUE]
|
||
|
|
service remove <name>
|
||
|
|
service start <name>
|
||
|
|
service stop <name>
|
||
|
|
service restart <name>
|
||
|
|
service list
|
||
|
|
service logs <name>
|
||
|
|
|
||
|
|
registry add --url <url> --username <user> --password <pass>
|
||
|
|
registry remove --url <url>
|
||
|
|
registry list
|
||
|
|
|
||
|
|
dns add <domain>
|
||
|
|
dns remove <domain>
|
||
|
|
dns list
|
||
|
|
dns sync
|
||
|
|
|
||
|
|
ssl renew [domain]
|
||
|
|
ssl list
|
||
|
|
ssl force-renew <domain>
|
||
|
|
|
||
|
|
nginx reload
|
||
|
|
nginx test
|
||
|
|
nginx status
|
||
|
|
|
||
|
|
daemon install
|
||
|
|
daemon start
|
||
|
|
daemon stop
|
||
|
|
daemon logs
|
||
|
|
daemon status
|
||
|
|
|
||
|
|
config show
|
||
|
|
config set <key> <value>
|
||
|
|
|
||
|
|
status
|
||
|
|
|
||
|
|
Options:
|
||
|
|
--help, -h Show this help message
|
||
|
|
--version, -v Show version
|
||
|
|
--debug Enable debug logging
|
||
|
|
|
||
|
|
Examples:
|
||
|
|
onebox service add myapp --image nginx:latest --domain app.example.com --port 80
|
||
|
|
onebox registry add --url registry.example.com --username user --password pass
|
||
|
|
onebox daemon install
|
||
|
|
onebox daemon start
|
||
|
|
`);
|
||
|
|
}
|