Gunnar

nordisk/Skidbladnir

.nornir/layout-guide.md

# layout — guide

> **Class:** `guide` · audience: a techie provisioning a target's directories. The *what* is in
> [`layout-design.md`](layout-design.md).

## Lay out a target

```rust
use skidbladnir::layout::Layout;

let layout = Layout::dated("/var/lib/nordisk", "/var/log/nordisk", "/opt/nordisk");
let (software, data, log) = layout.prepare_product("holger")?;   // creates all three, idempotent
// software = /opt/nordisk/<YYYYMMDD>/holger   data = /var/lib/nordisk/holger   log = /var/log/nordisk/holger
```

`prepare_product` is safe to call again on an update — it never clobbers existing `data/` or
`log/`.

## Activate a generation (atomic upgrade)

```rust
// after unpacking this generation's files under software/<version>/…
layout.activate()?;                              // atomic: current → <version>
assert_eq!(layout.active_version().as_deref(), Some(layout.version.as_str()));
```

The service's unit points through `current`, so activation is the instant the new generation goes
live — no daemon churn, no path rewrite.

## Upgrade to a new generation

```rust
let next = Layout::dated("/var/lib/nordisk", "/var/log/nordisk", "/opt/nordisk");  // new YYYYMMDD
let (sw, _data, _log) = next.prepare_product("holger")?;   // data/log preserved from before
// … unpack the new files under sw …
next.activate()?;                                          // current now points at the new version
```

## Roll back

Rollback is just re-activating an older layout — the previous generation was never deleted:

```rust
old_layout.activate()?;   // current → the previous <version>
```

## Gotchas

- `activate()` needs the temp symlink and `current` to be on the **same filesystem** — the atomic
  `rename(2)` is what makes the swap tear-free.
- The symlink target is the **relative** version name, so you can move the whole `software_dir`
  without breaking `current`.
- `data/` and `log/` live *outside* the versioned `software/` tree on purpose — that is why an
  update swaps binaries while state survives.