refactor: remove config import from startup and update README for CLI usage
This commit is contained in:
parent
b25ed606b2
commit
04cbb58559
4 changed files with 27 additions and 76 deletions
|
|
@ -1,6 +1,5 @@
|
|||
import { eq } from "drizzle-orm";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import slugify from "slugify";
|
||||
import { db } from "../../db/db";
|
||||
import {
|
||||
|
|
@ -70,23 +69,6 @@ function interpolateEnvVars(value: unknown): unknown {
|
|||
return value;
|
||||
}
|
||||
|
||||
async function loadConfigFromFile(): Promise<unknown | null> {
|
||||
try {
|
||||
const configPath = process.env.ZEROBYTE_CONFIG_PATH || "zerobyte.config.json";
|
||||
const configFullPath = path.resolve(process.cwd(), configPath);
|
||||
try {
|
||||
const raw = await fs.readFile(configFullPath, "utf-8");
|
||||
return JSON.parse(raw);
|
||||
} catch (error) {
|
||||
if (isRecord(error) && error.code === "ENOENT") return null;
|
||||
throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(`No config file loaded or error parsing config: ${toError(error).message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function parseImportConfig(configRaw: unknown): ImportConfig {
|
||||
const root = isRecord(configRaw) ? configRaw : {};
|
||||
const config = isRecord(root.config) ? (root.config as Record<string, unknown>) : root;
|
||||
|
|
@ -838,21 +820,3 @@ export async function applyConfigImport(configRaw: unknown, options: ImportOptio
|
|||
logImportSummary(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import configuration from a file (used by env var startup)
|
||||
*/
|
||||
export async function applyConfigImportFromFile(): Promise<void> {
|
||||
const configRaw = await loadConfigFromFile();
|
||||
if (configRaw === null) return; // No config file, nothing to do
|
||||
|
||||
logger.info("Starting config import from file...");
|
||||
const config = parseImportConfig(configRaw);
|
||||
|
||||
try {
|
||||
const result = await runImport(config);
|
||||
logImportSummary(result);
|
||||
} catch (e) {
|
||||
logger.error(`Config import failed: ${toError(e).message}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import { VolumeHealthCheckJob } from "../../jobs/healthchecks";
|
|||
import { RepositoryHealthCheckJob } from "../../jobs/repository-healthchecks";
|
||||
import { BackupExecutionJob } from "../../jobs/backup-execution";
|
||||
import { CleanupSessionsJob } from "../../jobs/cleanup-sessions";
|
||||
import { applyConfigImportFromFile } from "./config-import";
|
||||
import { repositoriesService } from "../repositories/repositories.service";
|
||||
import { notificationsService } from "../notifications/notifications.service";
|
||||
import { VolumeAutoRemountJob } from "~/server/jobs/auto-remount";
|
||||
|
|
@ -45,13 +44,6 @@ export const startup = async () => {
|
|||
await Scheduler.start();
|
||||
await Scheduler.clear();
|
||||
|
||||
if (process.env.ZEROBYTE_CONFIG_IMPORT === "true") {
|
||||
logger.info("Config import enabled (ZEROBYTE_CONFIG_IMPORT=true)");
|
||||
await applyConfigImportFromFile();
|
||||
} else {
|
||||
logger.info("Config import skipped (set ZEROBYTE_CONFIG_IMPORT=true to enable)");
|
||||
}
|
||||
|
||||
await restic.ensurePassfile().catch((err) => {
|
||||
logger.error(`Error ensuring restic passfile exists: ${err.message}`);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Config file import (Infrastructure as Code)
|
||||
|
||||
Zerobyte supports **config file import** on startup.
|
||||
Zerobyte supports **config file import** via the CLI.
|
||||
This lets you pre-configure volumes, repositories, backup schedules, notification destinations, and an initial user.
|
||||
|
||||
This example includes:
|
||||
|
|
@ -13,7 +13,7 @@ This example includes:
|
|||
|
||||
- Docker + Docker Compose
|
||||
|
||||
This example includes `SYS_ADMIN` and `/dev/fuse` because it’s compatible with remote volume mounts (SMB/NFS/WebDAV).
|
||||
This example includes `SYS_ADMIN` and `/dev/fuse` because it's compatible with remote volume mounts (SMB/NFS/WebDAV).
|
||||
|
||||
## Setup
|
||||
|
||||
|
|
@ -48,31 +48,19 @@ This is the recommended workflow for quick testing: if you don't have your own J
|
|||
docker compose up -d
|
||||
```
|
||||
|
||||
6. Access the UI at `http://localhost:4096`.
|
||||
6. Run the config import:
|
||||
|
||||
```bash
|
||||
docker compose exec zerobyte bun run cli import-config --config /app/zerobyte.config.json
|
||||
```
|
||||
|
||||
7. Access the UI at `http://localhost:4096`.
|
||||
|
||||
## Notes
|
||||
|
||||
### Import methods
|
||||
### CLI import command
|
||||
|
||||
Zerobyte supports two ways to import configuration:
|
||||
|
||||
#### Method 1: Environment variable (automatic on startup)
|
||||
|
||||
Set `ZEROBYTE_CONFIG_IMPORT=true` and the import runs automatically when the container starts:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
zerobyte:
|
||||
environment:
|
||||
- ZEROBYTE_CONFIG_IMPORT=true
|
||||
- ZEROBYTE_CONFIG_PATH=/app/zerobyte.config.json # optional, this is the default
|
||||
```
|
||||
|
||||
This is ideal for automated deployments where you want `docker compose up` to fully configure the instance.
|
||||
|
||||
#### Method 2: CLI command (manual control)
|
||||
|
||||
Run the import explicitly using the CLI:
|
||||
Import configuration using the CLI:
|
||||
|
||||
```bash
|
||||
# Import from a mounted config file (starts a new temporary container)
|
||||
|
|
@ -89,15 +77,23 @@ Get-Content zerobyte.config.json | docker compose exec -T zerobyte bun run cli i
|
|||
|
||||
# Validate config without importing (dry run)
|
||||
docker compose run --rm zerobyte bun run cli import-config --config /app/zerobyte.config.json --dry-run
|
||||
|
||||
# Get JSON output for scripting
|
||||
docker compose exec zerobyte bun run cli import-config --config /app/zerobyte.config.json --json
|
||||
```
|
||||
|
||||
The `--stdin` option is useful when you don't want to mount the config file - just pipe it directly.
|
||||
|
||||
This is useful when you want to:
|
||||
- See import output directly in your terminal
|
||||
- Re-run import after fixing issues
|
||||
- Test config files before applying them
|
||||
- Import without modifying your docker-compose.yml
|
||||
### CLI options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--config <path>` | Path to the configuration file inside the container |
|
||||
| `--stdin` | Read configuration from stdin |
|
||||
| `--dry-run` | Validate the config without importing |
|
||||
| `--json` | Output results in JSON format |
|
||||
| `--log-level <level>` | Set log level (debug, info, warn, error) |
|
||||
| `--overwrite-recovery-key` | Overwrite existing recovery key (only allowed if database is empty) |
|
||||
|
||||
### Secrets via env vars
|
||||
|
||||
|
|
@ -170,7 +166,7 @@ Supported formats:
|
|||
- `env://VAR_NAME` → reads `process.env.VAR_NAME` at runtime
|
||||
- `file://secret_name` → reads `/run/secrets/secret_name` (Docker secrets)
|
||||
|
||||
This is useful when you want to keep secrets out of the database and rotate them without editing Zerobyte’s stored config.
|
||||
This is useful when you want to keep secrets out of the database and rotate them without editing Zerobyte's stored config.
|
||||
|
||||
See the runnable example:
|
||||
|
||||
|
|
@ -178,14 +174,14 @@ See the runnable example:
|
|||
|
||||
### Config file behavior (create-only)
|
||||
|
||||
The config file is applied on startup using a **create-only** approach:
|
||||
The config file is applied using a **create-only** approach:
|
||||
|
||||
- **Volumes, notifications, schedules**: Skipped if a resource with the same name already exists
|
||||
- **Repositories**: Skipped if any of these conditions are met:
|
||||
- A repository pointing to the same location (path/bucket/endpoint) is already registered
|
||||
- For local repos: the path is already a restic repository (set `isExistingRepository: true` to import it)
|
||||
- A repository with the same name already exists
|
||||
- Changes made via the UI are preserved across container restarts
|
||||
- Changes made via the UI are preserved across imports
|
||||
- To update a resource from config, either modify it via the UI or delete it first
|
||||
|
||||
This makes the config file better suited as "initial setup" than as a "desired state sync".
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ services:
|
|||
- .env
|
||||
environment:
|
||||
- TZ=${TZ:-UTC}
|
||||
- ZEROBYTE_CONFIG_IMPORT=true
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /var/lib/zerobyte:/var/lib/zerobyte
|
||||
|
|
|
|||
Loading…
Reference in a new issue