From 2d4c2dd18511aa301f937d265b23ddc13d2e3139 Mon Sep 17 00:00:00 2001 From: Kacper Sawicki Date: Mon, 6 Apr 2026 17:03:52 +0200 Subject: [PATCH] fix: sync hostname after import --- README.md | 18 ++++++++++++++++++ cmd/ocdev/src/commands.nim | 26 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/README.md b/README.md index 2434887..2c085cf 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,24 @@ In both forms, the cloned environment: - Keeps the same local host directory mounts as the source container Use a live clone for fast local duplication, or a snapshot clone when you need a deliberate point-in-time base. + +## Export and Import + +Use `ocdev export` to create a portable container tarball and `ocdev import` to restore it on another host: + +```bash +# Export from source host +ocdev export myproject --output /tmp/myproject.tar.gz + +# Import on destination host +ocdev import myproject-restored --file /tmp/myproject.tar.gz +``` + +During import, `ocdev` rewrites host-specific settings so the restored environment is ready on the new machine: +- Allocates fresh SSH and service ports +- Recreates host disk mounts for the destination host +- Sets the guest hostname to match the imported container name (for example, `ocdev-myproject-restored`) + ## Custom Setup Scripts Run a custom script after container provisioning using `--post-create`: diff --git a/cmd/ocdev/src/commands.nim b/cmd/ocdev/src/commands.nim index 087d741..0d71c4d 100644 --- a/cmd/ocdev/src/commands.nim +++ b/cmd/ocdev/src/commands.nim @@ -297,6 +297,25 @@ proc addDiskMounts(containerName: string): int = result = 0 +proc setContainerHostname(containerName, hostname: string): int = + ## Set and verify the guest hostname for a container + var exitCode = execCmd(fmt"incus exec {quoteShell(containerName)} -- hostnamectl set-hostname {quoteShell(hostname)}") + if exitCode != 0: + error(fmt"Failed to set container hostname to '{hostname}'") + return exitCode + + let (hostnameOutput, verifyExit) = execCmdEx(fmt"incus exec {quoteShell(containerName)} -- hostname") + if verifyExit != 0: + error("Failed to verify container hostname") + return verifyExit + + let currentHostname = hostnameOutput.strip() + if currentHostname != hostname: + error(fmt"Container hostname verification failed (expected '{hostname}', got '{currentHostname}')") + return 1 + + result = 0 + proc checkPrerequisites(): int = ## Check incus command and group membership let (_, exitCode) = execCmdEx("command -v incus") @@ -1042,6 +1061,13 @@ proc cmdImport*(name: string, file: string): int = cleanup.run() return ord(ecError) + # Align guest hostname with imported container name + info(fmt"Setting container hostname to '{containerName}'...") + exitCode = setContainerHostname(containerName, containerName) + if exitCode != 0: + cleanup.run() + return ord(ecError) + # Save port allocation withLockVoid(exclusive = true) do (): savePortAllocation(name, port)