boot

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2026 License: BSD-3-Clause Imports: 10 Imported by: 0

Documentation

Overview

Package boot is the first-boot provisioning runner. The host stamps four reserved properties on the VM at create time (weft.boot/source.kind, source.url, source.ref, script — see openweft/weft-webui commit 2c098e7) ; the pkg/properties subscriber mirrors them to /run/weft/properties/weft.boot/* ; THIS package reads from there, pulls the payload, runs the script. One-shot per VM ; idempotent via a sentinel file so reboots don't re-provision.

Why piggyback on properties instead of a dedicated NATS subject : keeps the host-side wire simple (the host already publishes weft.boot/* with the property subscriber's publishes ; a separate subject would duplicate that). Also gives the Properties drawer tab visibility into what was stamped — operator can audit the boot config without a separate panel.

Script execution uses mvdan.cc/sh/v3 (POSIX sh in Go) so the payload doesn't need to ship /bin/sh in its image — works for scratch / distroless / alpine alike. Git clone uses go-git (pure-Go, no /usr/bin/git in the ramdisk) ; OCI pull uses oras-go (pure-Go, anonymous registry pulls). Both are wired via the Cloner / Puller hooks on Runner so tests can stub them.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RunScript

func RunScript(ctx context.Context, body, cwd string, logOut io.Writer) error

RunScript parses + executes a POSIX sh body in cwd via mvdan.cc/sh/v3. Stdout + stderr go to logOut ; stdin is a closed empty reader (no interactive script). Errors from the interpreter (including non-zero exit) propagate.

Exposed separately from Runner.Run so tests can exercise the script path without setting up a workdir / sentinel.

Types

type Buffer

type Buffer struct{ bytes.Buffer }

Buffer is a small helper so callers can capture script output without depending on bytes.Buffer in tests. Wraps a bytes.Buffer so the returned writer is goroutine-safe enough for the runner's single-writer use.

type Config

type Config struct {
	SourceKind string // "" | "git" | "oci"
	SourceURL  string
	SourceRef  string // branch / tag / commit / digest
	Script     string // POSIX sh body
}

Config is the resolved boot request : what to pull + what to run. All fields optional ; an empty Config is a no-op (the runner logs "no provisioning requested" and stamps the sentinel anyway, so a reboot doesn't keep checking).

func ReadFromPropertiesDir

func ReadFromPropertiesDir(root string) (Config, error)

ReadFromPropertiesDir loads a Config from the property tree the pkg/properties subscriber maintains (typically /run/weft/properties). Each weft.boot/* property is a file ; missing files come back as empty strings (not an error — the host may have stamped only a subset).

func (Config) IsEmpty

func (c Config) IsEmpty() bool

IsEmpty reports whether the operator stamped no boot request. Empty kind + empty script = nothing to do.

type Runner

type Runner struct {
	WorkDir      string
	SentinelPath string
	LogOut       io.Writer
	Cloner       func(ctx context.Context, url, ref, dst string) error
	Puller       func(ctx context.Context, url, ref, dst string) error
}

Runner is the apply side : pull + script. WorkDir is the parent directory the payload lands under (.../payload subdir) ; SentinelPath is touched after a successful run so reboots skip. LogOut captures script stdout/stderr ; pass io.Discard if you don't care.

Cloner is the git-clone hook ; nil means "git pull not supported" (the runner returns an error if SourceKind=="git" without a Cloner). Tests inject a stub ; production wires a go-git helper in cmd/weft-microvm-agent/boot.go.

Puller is the symmetric OCI hook ; same nil-means-unsupported rule. Production uses oras-go for anonymous registry pulls.

func (*Runner) Run

func (r *Runner) Run(ctx context.Context, cfg Config) (err error)

Run executes one provisioning pass. Idempotent : if SentinelPath already exists, returns nil immediately without touching anything. On success the sentinel is created ; on failure it isn't, so a re-published config can retry.

Order of effects :

  1. sentinel check (early return when already provisioned)
  2. pull (git clone or oras pull into <WorkDir>/payload ; skipped when SourceKind is empty)
  3. script (mvdan.cc/sh/v3 in payload CWD if it exists, else WorkDir)
  4. sentinel write (only when everything above succeeded)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL