diff --git a/CHANGELOG.md b/CHANGELOG.md index fee9bec..e2af744 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,68 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). --- +## [1.0.4] — 2026-05-12 + +**VM runtime + cloud-init paths per-user.** Fourth patch +release of the 1.x line. `lib/vm_run.cpp` now resolves the +VM DNS share and cloud-init user-data temp directories to +the per-user base when the privops socket is detected. + +### What changes + +New file-local `vmBaseDir()` helper in `lib/vm_run.cpp` — +same lazy-resolve pattern as `stack.cpp` (1.0.3) and +`network_lease.cpp` (0.9.27). + +| Mode | DNS share base | cloud-init temp dir | +|-------------------------------|--------------------------------------|--------------------------------------| +| Legacy (no `crated`) | `/var/run/crate/vm//dns/` | `/var/run/crate/cloud-init/` | +| Rootless (crated + privops) | `/var/run/crate//vm//dns/` | `/var/run/crate//cloud-init/`| + +Two functions updated: + +- `configureVmDns()` — DNS share dir tree (`vm//dns/`) + resolves under per-user root +- The cloud-init user-data writer (anonymous helper near line + 340) — writes `user-data-9p-.yaml` under per-user root + +### Why this matters + +Before this release, two operators on a rootless host with +the VM track enabled would clobber each other's resolv.conf +9p-share AND collide on cloud-init user-data files (despite +the PID suffix). Single-tenant deployments saw no impact. + +VM track is `#ifdef HAVE_LIBVIRT`-gated, so non-libvirt +builds are completely unaffected. + +### 1.x backlog + +Path-leak track complete with this release. Remaining 1.x +items (different shapes): + +- `lib/run_net.cpp:446` direct `ifconfig -vnet` (should use + `SetIfaceUp` privops verb) +- **PfctlOps privops-wiring** — `lib/run.cpp` call sites + (1.1.0) +- Query-side privops verbs (inspect/doctor/migrate) +- Test coverage on impure modules (run.cpp 1810 / run_pure.cpp + 24 lines) + +### Tests + +No new tests — single helper + 2 sites. Same `dnsBaseDir` +pattern from 1.0.3. Suite stays at 1303. + +### Files + +- `lib/vm_run.cpp` — `vmBaseDir()` helper; 2 sites routed + through it; new includes +- `cli/args.cpp` — version `crate 1.0.4` +- `CHANGELOG.md` — this entry + +--- + ## [1.0.3] — 2026-05-12 **Stack DNS dirs per-user.** Third patch release of the 1.x diff --git a/cli/args.cpp b/cli/args.cpp index d99346e..17792c3 100644 --- a/cli/args.cpp +++ b/cli/args.cpp @@ -753,7 +753,7 @@ Args parseArguments(int argc, char** argv, unsigned &processed) { args.noColor = true; break; } else if (strEq(argv[a], "--version")) { - std::cout << "crate 1.0.3" << std::endl; + std::cout << "crate 1.0.4" << std::endl; exit(0); } else if (auto argShort = isShort(argv[a])) { switch (argShort) { @@ -764,7 +764,7 @@ Args parseArguments(int argc, char** argv, unsigned &processed) { args.logProgress = true; break; case 'V': - std::cout << "crate 1.0.3" << std::endl; + std::cout << "crate 1.0.4" << std::endl; exit(0); default: err("unsupported short option '%s'", argv[a]); diff --git a/lib/vm_run.cpp b/lib/vm_run.cpp index 13bc21a..436f09d 100644 --- a/lib/vm_run.cpp +++ b/lib/vm_run.cpp @@ -4,6 +4,8 @@ #include "vm_run.h" #include "ifconfig_ops.h" +#include "privops_client.h" +#include "runtime_paths_pure.h" #include "util.h" #include "err.h" #include @@ -25,6 +27,28 @@ namespace VmRun { +namespace { + +// 1.0.4: resolve the base directory for VM runtime state (DNS share, +// cloud-init user-data temp files). Legacy single-tenant uses +// /var/run/crate; rootless mode lazy-resolves to +// /var/run/crate/ when crated's privops socket is detected. +// Same pattern as stack.cpp (1.0.3) and network_lease.cpp (0.9.27). +const std::string &vmBaseDir() { + static std::string cached; + static bool computed = false; + if (!computed) { + if (!PrivOpsClient::detectSocketPath().empty()) + cached = RuntimePathsPure::perUserRoot((uint32_t)::getuid()); + else + cached = "/var/run/crate"; + computed = true; + } + return cached; +} + +} // anon + // --------------------------------------------------------------------------- // libvirt connection (singleton) // --------------------------------------------------------------------------- @@ -225,12 +249,15 @@ void connectToSharedBridge(const std::string &vmName, void configureVmDns(const std::string &vmName, const std::string &dnsIp) { // Create a shared directory with resolv.conf for the VM - std::string dnsShareDir = "/var/run/crate/vm/" + vmName + "/dns"; + const std::string &base = vmBaseDir(); + std::string vmDir = base + "/vm"; + std::string vmInstance = vmDir + "/" + vmName; + std::string dnsShareDir = vmInstance + "/dns"; // Create the directory tree - ::mkdir("/var/run/crate", 0755); - ::mkdir("/var/run/crate/vm", 0755); - ::mkdir(("/var/run/crate/vm/" + vmName).c_str(), 0755); + ::mkdir(base.c_str(), 0755); + ::mkdir(vmDir.c_str(), 0755); + ::mkdir(vmInstance.c_str(), 0755); ::mkdir(dnsShareDir.c_str(), 0755); // Write resolv.conf with the stack DNS IP @@ -340,12 +367,14 @@ std::string generateCloudInitFor9p( << " 9p " << opts << " 0 0\n"; } - // Write to a temp file under /var/run/crate - ::mkdir("/var/run/crate", 0755); - ::mkdir("/var/run/crate/cloud-init", 0755); + // Write to a temp file under the per-user (or legacy) base dir + const std::string &base = vmBaseDir(); + std::string cloudInitDir = base + "/cloud-init"; + ::mkdir(base.c_str(), 0755); + ::mkdir(cloudInitDir.c_str(), 0755); // Use a unique name based on PID to avoid collisions - std::string path = "/var/run/crate/cloud-init/user-data-9p-" + std::string path = cloudInitDir + "/user-data-9p-" + std::to_string(::getpid()) + ".yaml"; std::ofstream ofs(path);