pkg

package
v0.7.6 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2025 License: MIT Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// SystemConfigDir is the directory for nbc system configuration
	SystemConfigDir = "/etc/nbc"
	// SystemConfigFile is the main configuration file
	SystemConfigFile = "/etc/nbc/config.json"
)
View Source
const (
	// PristineEtcPath is where we store the pristine /etc from installation
	PristineEtcPath = "/var/lib/nbc/etc.pristine"
	// VarEtcPath is DEPRECATED - we no longer use /var/etc for boot-time bind mount
	// Kept for documentation purposes
	VarEtcPath = "/var/etc.backup"
)

Variables

This section is empty.

Functions

func CheckRequiredTools

func CheckRequiredTools() error

CheckRequiredTools checks if required tools are available

func CheckUpdateNeeded

func CheckUpdateNeeded(installedDigest, remoteDigest string) bool

CheckUpdateNeeded compares the installed image digest with the remote image digest Returns true if an update is needed (digests differ), false otherwise

func ChrootCommand

func ChrootCommand(targetDir string, command string, args ...string) error

ChrootCommand runs a command in a chroot environment

func CloseLUKS added in v0.6.0

func CloseLUKS(mapperName string) error

CloseLUKS closes a LUKS container

func CreateFstab

func CreateFstab(targetDir string, scheme *PartitionScheme) error

CreateFstab creates an /etc/fstab file with the proper mount points

func CreateLUKSContainer added in v0.6.0

func CreateLUKSContainer(partition, passphrase string) error

CreateLUKSContainer creates a LUKS2 container on the given partition

func EnrollTPM2 added in v0.6.0

func EnrollTPM2(partition string, config *LUKSConfig) error

EnrollTPM2 enrolls a TPM2 key for automatic unlock with no PCRs

func FormatPartitions

func FormatPartitions(scheme *PartitionScheme, dryRun bool) error

FormatPartitions formats the partitions with appropriate filesystems

func FormatSize

func FormatSize(bytes uint64) string

FormatSize formats a byte size as human-readable string

func GenerateCrypttab added in v0.6.0

func GenerateCrypttab(devices []*LUKSDevice, tpm2Enabled bool) string

GenerateCrypttab generates /etc/crypttab entries for the LUKS devices

func GetActiveRootPartition

func GetActiveRootPartition() (string, error)

GetActiveRootPartition determines which root partition is currently active

func GetBootDeviceFromPartition

func GetBootDeviceFromPartition(partition string) (string, error)

GetBootDeviceFromPartition extracts the parent disk device from a partition path Example: /dev/sda3 -> /dev/sda, /dev/nvme0n1p3 -> /dev/nvme0n1

func GetCurrentBootDevice

func GetCurrentBootDevice() (string, error)

GetCurrentBootDevice determines the disk device that the system booted from

func GetCurrentBootDeviceInfo

func GetCurrentBootDeviceInfo(verbose bool) (string, error)

GetCurrentBootDeviceInfo returns detailed information about the boot device

func GetDiskByPath

func GetDiskByPath(path string) (string, error)

GetDiskByPath resolves a disk path (handles by-id, by-uuid, etc.)

func GetInactiveRootPartition

func GetInactiveRootPartition(scheme *PartitionScheme) (string, bool, error)

GetInactiveRootPartition returns the inactive root partition given a partition scheme

func GetLUKSUUID added in v0.6.0

func GetLUKSUUID(partition string) (string, error)

GetLUKSUUID retrieves the LUKS container UUID (not filesystem UUID)

func GetPartitionUUID

func GetPartitionUUID(partition string) (string, error)

GetPartitionUUID returns the UUID of a partition

func GetRemoteImageDigest

func GetRemoteImageDigest(imageRef string) (string, error)

GetRemoteImageDigest fetches the digest of a remote container image without downloading layers. Returns the digest in the format "sha256:..."

func InstallEtcMountUnit

func InstallEtcMountUnit(targetDir string, dryRun bool) error

InstallEtcMountUnit is DEPRECATED - do not use. The bind-mount approach causes boot failures because services need /etc before the mount happens. This function is kept for backwards compatibility but does nothing. Use SetupEtcPersistence instead.

func IsBlockDevice

func IsBlockDevice(path string) bool

IsBlockDevice checks if a path is a block device

func MergeEtcFromActive

func MergeEtcFromActive(targetDir string, activeRootPartition string, dryRun bool) error

MergeEtcFromActive merges /etc configuration from the active root during A/B updates.

This function is called during the update process to preserve user modifications to /etc when switching to a new root partition. The approach is:

1. Mount the currently active root partition (contains user's modified /etc) 2. Mount the new root partition (contains fresh /etc from container image) 3. Merge user modifications from active /etc into new /etc, preserving:

  • User-added files (not in container image)
  • User-modified files (changed from container defaults)

4. System identity files (like /etc/os-release) always come from the new container

Parameters:

  • targetDir: mount point of the NEW root partition (e.g., /tmp/nbc-update)
  • activeRootPartition: the CURRENT root partition device (contains user's /etc)
  • dryRun: if true, don't make changes

func MountPartitions

func MountPartitions(scheme *PartitionScheme, mountPoint string, dryRun bool) error

MountPartitions mounts the partitions to a temporary directory

func ParseDeviceName

func ParseDeviceName(device string) (string, error)

ParseDeviceName extracts the base device name without partition number

func ParseOSRelease

func ParseOSRelease(targetDir string) string

ParseOSRelease reads and parses /etc/os-release from the target directory Returns PRETTY_NAME if available, otherwise NAME, otherwise ID, or "Linux" as fallback

func SavePristineEtc

func SavePristineEtc(targetDir string, dryRun bool) error

SavePristineEtc saves a copy of the pristine /etc after installation This is used to detect user modifications during updates

func SetupEtcPersistence

func SetupEtcPersistence(targetDir string, dryRun bool) error

SetupEtcPersistence ensures /etc is properly configured for persistence across A/B updates.

IMPORTANT: We do NOT bind-mount /var/etc to /etc at boot time. The bind-mount approach causes critical boot failures because: 1. Services like dbus-broker, systemd-journald need /etc very early in boot 2. The etc.mount unit runs too late (after var.mount, before local-fs.target) 3. Early systemd generators and services fail trying to read unmounted /etc

Instead, we keep /etc on the root filesystem where services expect it. For A/B updates, /etc contents are merged from the old root to the new root during the update process (see MergeEtcFromActive).

We still backup /etc to /var/etc for disaster recovery purposes.

func SetupLUKS added in v0.6.0

func SetupLUKS(scheme *PartitionScheme, passphrase string, dryRun bool) error

SetupLUKS creates LUKS containers on root and var partitions Returns the opened LUKS devices (must be closed during cleanup)

func SetupSystemDirectories

func SetupSystemDirectories(targetDir string) error

SetupSystemDirectories creates necessary system directories

func UnmountPartitions

func UnmountPartitions(mountPoint string, dryRun bool) error

UnmountPartitions unmounts all partitions

func UpdateSystemConfigImageRef

func UpdateSystemConfigImageRef(imageRef, imageDigest string, dryRun bool) error

UpdateSystemConfigImageRef updates the image reference and digest in the system config

func ValidateDisk

func ValidateDisk(device string, minSize uint64) error

ValidateDisk checks if a disk is suitable for installation

func ValidateInitramfsSupport added in v0.6.0

func ValidateInitramfsSupport(targetDir string, tpm2Enabled bool) []string

ValidateInitramfsSupport checks if the extracted container has LUKS/TPM2 support Returns warnings (not errors) since initramfs contents vary by distro

func WipeDisk

func WipeDisk(device string, dryRun bool) error

WipeDisk securely wipes a disk's partition table

func WriteSystemConfig

func WriteSystemConfig(config *SystemConfig, dryRun bool) error

WriteSystemConfig writes system configuration to /etc/nbc/config.json

func WriteSystemConfigToTarget

func WriteSystemConfigToTarget(targetDir string, config *SystemConfig, dryRun bool) error

WriteSystemConfigToTarget writes system configuration to the target root filesystem

Types

type BootcInstaller

type BootcInstaller struct {
	ImageRef       string
	Device         string
	Verbose        bool
	DryRun         bool
	JSONOutput     bool
	KernelArgs     []string
	MountPoint     string
	FilesystemType string // ext4 or btrfs
	Progress       *ProgressReporter
	Encryption     *LUKSConfig // Encryption configuration
}

BootcInstaller handles bootc container installation

func NewBootcInstaller

func NewBootcInstaller(imageRef, device string) *BootcInstaller

NewBootcInstaller creates a new BootcInstaller

func (*BootcInstaller) AddKernelArg

func (b *BootcInstaller) AddKernelArg(arg string)

AddKernelArg adds a kernel argument

func (*BootcInstaller) Install

func (b *BootcInstaller) Install() error

Install performs the bootc installation to the target disk

func (*BootcInstaller) InstallComplete

func (b *BootcInstaller) InstallComplete(skipPull bool) error

InstallComplete performs the complete installation workflow

func (*BootcInstaller) PullImage

func (b *BootcInstaller) PullImage() error

PullImage validates the image reference and checks if it's accessible The actual image pull happens during Extract() to avoid duplicate work

func (*BootcInstaller) SetDryRun

func (b *BootcInstaller) SetDryRun(dryRun bool)

SetDryRun enables dry run mode

func (*BootcInstaller) SetEncryption added in v0.6.0

func (b *BootcInstaller) SetEncryption(passphrase, keyfile string, tpm2 bool)

SetEncryption enables LUKS encryption with the given passphrase/keyfile and optional TPM2

func (*BootcInstaller) SetFilesystemType

func (b *BootcInstaller) SetFilesystemType(fsType string)

SetFilesystemType sets the filesystem type for root and var partitions

func (*BootcInstaller) SetJSONOutput added in v0.2.0

func (b *BootcInstaller) SetJSONOutput(jsonOutput bool)

SetJSONOutput enables JSON output mode

func (*BootcInstaller) SetMountPoint

func (b *BootcInstaller) SetMountPoint(mountPoint string)

SetMountPoint sets the temporary mount point for installation

func (*BootcInstaller) SetVerbose

func (b *BootcInstaller) SetVerbose(verbose bool)

SetVerbose enables verbose output

func (*BootcInstaller) Verify

func (b *BootcInstaller) Verify() error

Verify performs post-installation verification

type BootloaderInstaller

type BootloaderInstaller struct {
	Type       BootloaderType
	TargetDir  string
	Device     string
	Scheme     *PartitionScheme
	KernelArgs []string
	OSName     string
	Verbose    bool
	Encryption *LUKSConfig // Encryption configuration
}

BootloaderInstaller handles bootloader installation

func NewBootloaderInstaller

func NewBootloaderInstaller(targetDir, device string, scheme *PartitionScheme, osName string) *BootloaderInstaller

NewBootloaderInstaller creates a new BootloaderInstaller

func (*BootloaderInstaller) AddKernelArg

func (b *BootloaderInstaller) AddKernelArg(arg string)

AddKernelArg adds a kernel argument

func (*BootloaderInstaller) Install

func (b *BootloaderInstaller) Install() error

Install installs the bootloader

func (*BootloaderInstaller) SetEncryption added in v0.6.0

func (b *BootloaderInstaller) SetEncryption(config *LUKSConfig)

SetEncryption sets the encryption configuration

func (*BootloaderInstaller) SetType

func (b *BootloaderInstaller) SetType(t BootloaderType)

SetType sets the bootloader type

func (*BootloaderInstaller) SetVerbose

func (b *BootloaderInstaller) SetVerbose(verbose bool)

SetVerbose enables verbose output

type BootloaderType

type BootloaderType string

BootloaderType represents the type of bootloader to install

const (
	BootloaderGRUB2       BootloaderType = "grub2"
	BootloaderSystemdBoot BootloaderType = "systemd-boot"
)

func DetectBootloader

func DetectBootloader(targetDir string) BootloaderType

DetectBootloader detects which bootloader should be used based on the container

type ContainerExtractor

type ContainerExtractor struct {
	ImageRef  string
	TargetDir string
	Verbose   bool
}

ContainerExtractor handles extracting container images to disk

func NewContainerExtractor

func NewContainerExtractor(imageRef, targetDir string) *ContainerExtractor

NewContainerExtractor creates a new ContainerExtractor

func (*ContainerExtractor) Extract

func (c *ContainerExtractor) Extract() error

Extract extracts the container filesystem to the target directory using go-containerregistry

func (*ContainerExtractor) SetVerbose

func (c *ContainerExtractor) SetVerbose(verbose bool)

SetVerbose enables verbose output

type DiskInfo

type DiskInfo struct {
	Device      string
	Size        uint64
	Model       string
	IsRemovable bool
	Partitions  []PartitionInfo
}

DiskInfo represents information about a physical disk

func ListDisks

func ListDisks() ([]DiskInfo, error)

ListDisks returns a list of available physical disks

type EncryptionConfig added in v0.7.3

type EncryptionConfig struct {
	Enabled       bool   `json:"enabled"`         // Whether LUKS encryption is enabled
	TPM2          bool   `json:"tpm2"`            // Whether TPM2 auto-unlock is enabled
	Root1LUKSUUID string `json:"root1_luks_uuid"` // LUKS UUID for root1 partition
	Root2LUKSUUID string `json:"root2_luks_uuid"` // LUKS UUID for root2 partition
	VarLUKSUUID   string `json:"var_luks_uuid"`   // LUKS UUID for var partition
}

EncryptionConfig stores LUKS encryption configuration for A/B updates

type EventType added in v0.2.0

type EventType string

EventType represents the type of progress event

const (
	EventTypeStep     EventType = "step"
	EventTypeProgress EventType = "progress"
	EventTypeMessage  EventType = "message"
	EventTypeWarning  EventType = "warning"
	EventTypeError    EventType = "error"
	EventTypeComplete EventType = "complete"
)

type FilesystemType

type FilesystemType string

FilesystemType represents the supported filesystem types

const (
	FilesystemExt4  FilesystemType = "ext4"
	FilesystemBtrfs FilesystemType = "btrfs"
)

type LUKSConfig added in v0.6.0

type LUKSConfig struct {
	Enabled    bool
	Passphrase string // Passphrase for LUKS (mutually exclusive with Keyfile)
	Keyfile    string // Path to keyfile containing passphrase (mutually exclusive with Passphrase)
	TPM2       bool
}

LUKSConfig holds encryption configuration

type LUKSDevice added in v0.6.0

type LUKSDevice struct {
	Partition  string // Raw partition (e.g., /dev/sda2)
	MapperName string // Device mapper name (e.g., root1)
	MapperPath string // Full path (e.g., /dev/mapper/root1)
	LUKSUUID   string // LUKS container UUID
}

LUKSDevice represents an opened LUKS container

func OpenLUKS added in v0.6.0

func OpenLUKS(partition, mapperName, passphrase string) (*LUKSDevice, error)

OpenLUKS opens a LUKS container and returns the device info

type PartitionInfo

type PartitionInfo struct {
	Device     string
	Size       uint64
	MountPoint string
	FileSystem string
}

PartitionInfo represents information about a disk partition

type PartitionScheme

type PartitionScheme struct {
	BootPartition  string // Boot partition (EFI System Partition, FAT32, 2GB) - holds EFI binaries + kernel/initramfs
	Root1Partition string // First root filesystem partition (12GB)
	Root2Partition string // Second root filesystem partition (12GB)
	VarPartition   string // /var partition (remaining space)
	FilesystemType string // Filesystem type for root/var partitions (ext4, btrfs)

	// LUKS encryption (optional)
	Encrypted   bool          // Whether partitions are LUKS encrypted
	LUKSDevices []*LUKSDevice // Opened LUKS devices (for cleanup)
}

PartitionScheme defines the disk partitioning layout

func CreatePartitions

func CreatePartitions(device string, dryRun bool) (*PartitionScheme, error)

CreatePartitions creates a GPT partition table with EFI, boot, and root partitions

func DetectExistingPartitionScheme

func DetectExistingPartitionScheme(device string) (*PartitionScheme, error)

DetectExistingPartitionScheme detects the partition scheme of an existing installation

func (*PartitionScheme) CloseLUKSDevices added in v0.6.0

func (s *PartitionScheme) CloseLUKSDevices()

CloseLUKSDevices closes all open LUKS containers

func (*PartitionScheme) GetLUKSDevice added in v0.6.0

func (s *PartitionScheme) GetLUKSDevice(mapperName string) *LUKSDevice

GetLUKSDevice returns the LUKS device for a given mapper name

func (*PartitionScheme) GetRoot1Device added in v0.6.0

func (s *PartitionScheme) GetRoot1Device() string

GetRoot1Device returns the device path to use for root1 (mapper or raw partition)

func (*PartitionScheme) GetRoot2Device added in v0.6.0

func (s *PartitionScheme) GetRoot2Device() string

GetRoot2Device returns the device path to use for root2 (mapper or raw partition)

func (*PartitionScheme) GetVarDevice added in v0.6.0

func (s *PartitionScheme) GetVarDevice() string

GetVarDevice returns the device path to use for var (mapper or raw partition)

type ProgressEvent added in v0.2.0

type ProgressEvent struct {
	Type       EventType `json:"type"`
	Timestamp  string    `json:"timestamp"`
	Step       int       `json:"step,omitempty"`
	TotalSteps int       `json:"total_steps,omitempty"`
	StepName   string    `json:"step_name,omitempty"`
	Message    string    `json:"message,omitempty"`
	Percent    int       `json:"percent,omitempty"`
	Details    any       `json:"details,omitempty"`
}

ProgressEvent represents a single line of JSON Lines output for streaming progress

type ProgressReporter added in v0.2.0

type ProgressReporter struct {
	// contains filtered or unexported fields
}

ProgressReporter handles streaming JSON Lines output for progress updates

func NewProgressReporter added in v0.2.0

func NewProgressReporter(jsonEnabled bool, totalSteps int) *ProgressReporter

NewProgressReporter creates a new progress reporter

func (*ProgressReporter) Complete added in v0.2.0

func (p *ProgressReporter) Complete(message string, details any)

Complete reports successful completion with optional result details

func (*ProgressReporter) Error added in v0.2.0

func (p *ProgressReporter) Error(err error, message string)

Error reports an error

func (*ProgressReporter) IsJSON added in v0.2.0

func (p *ProgressReporter) IsJSON() bool

IsJSON returns true if JSON output is enabled

func (*ProgressReporter) Message added in v0.2.0

func (p *ProgressReporter) Message(format string, args ...any)

Message reports an informational message

func (*ProgressReporter) MessagePlain added in v0.2.0

func (p *ProgressReporter) MessagePlain(format string, args ...any)

MessagePlain reports an informational message without indentation (for non-JSON)

func (*ProgressReporter) Progress added in v0.2.0

func (p *ProgressReporter) Progress(percent int, message string)

Progress reports progress within a step (0-100 percent)

func (*ProgressReporter) Step added in v0.2.0

func (p *ProgressReporter) Step(step int, name string)

Step reports the start of a new step

func (*ProgressReporter) Warning added in v0.2.0

func (p *ProgressReporter) Warning(format string, args ...any)

Warning reports a warning message

type SystemConfig

type SystemConfig struct {
	ImageRef       string            `json:"image_ref"`            // Container image reference
	ImageDigest    string            `json:"image_digest"`         // Container image digest (sha256:...)
	Device         string            `json:"device"`               // Installation device
	InstallDate    string            `json:"install_date"`         // Installation timestamp
	KernelArgs     []string          `json:"kernel_args"`          // Custom kernel arguments
	BootloaderType string            `json:"bootloader_type"`      // Bootloader type (grub2, systemd-boot)
	FilesystemType string            `json:"filesystem_type"`      // Filesystem type (ext4, btrfs)
	Encryption     *EncryptionConfig `json:"encryption,omitempty"` // Encryption configuration (nil if not encrypted)
}

SystemConfig represents the system configuration stored in /etc/nbc/

func ReadSystemConfig

func ReadSystemConfig() (*SystemConfig, error)

ReadSystemConfig reads system configuration from /etc/nbc/config.json

type SystemUpdater

type SystemUpdater struct {
	Config           UpdaterConfig
	Scheme           *PartitionScheme
	Active           bool // true if root1 is active, false if root2 is active
	Target           string
	TargetMapperName string // For encrypted systems: "root1" or "root2"
	TargetMapperPath string // For encrypted systems: "/dev/mapper/root1" or "/dev/mapper/root2"
	Progress         *ProgressReporter
	Encryption       *EncryptionConfig // Encryption configuration (loaded from system config)
}

SystemUpdater handles A/B system updates

func NewSystemUpdater

func NewSystemUpdater(device, imageRef string) *SystemUpdater

NewSystemUpdater creates a new SystemUpdater

func (*SystemUpdater) AddKernelArg

func (u *SystemUpdater) AddKernelArg(arg string)

AddKernelArg adds a kernel argument

func (*SystemUpdater) InstallKernelAndInitramfs

func (u *SystemUpdater) InstallKernelAndInitramfs() error

InstallKernelAndInitramfs checks for new kernel and initramfs in the updated root and copies them to the boot partition (which is the combined EFI/boot partition)

func (*SystemUpdater) IsUpdateNeeded

func (u *SystemUpdater) IsUpdateNeeded() (bool, string, error)

IsUpdateNeeded checks if the remote image differs from the currently installed image. Returns true if an update is needed, false if the system is already up-to-date. Also returns the remote digest for use during the update process.

func (*SystemUpdater) PerformUpdate

func (u *SystemUpdater) PerformUpdate(skipPull bool) error

PerformUpdate performs the complete update workflow

func (*SystemUpdater) PrepareUpdate

func (u *SystemUpdater) PrepareUpdate() error

PrepareUpdate prepares for an update by detecting partitions and determining target

func (*SystemUpdater) PullImage

func (u *SystemUpdater) PullImage() error

PullImage validates the image reference and checks if it's accessible The actual image pull happens during Extract() to avoid duplicate work

func (*SystemUpdater) SetDryRun

func (u *SystemUpdater) SetDryRun(dryRun bool)

SetDryRun enables dry run mode

func (*SystemUpdater) SetForce

func (u *SystemUpdater) SetForce(force bool)

SetForce enables non-interactive mode (skips confirmation)

func (*SystemUpdater) SetJSONOutput added in v0.2.0

func (u *SystemUpdater) SetJSONOutput(jsonOutput bool)

SetJSONOutput enables JSON output mode

func (*SystemUpdater) SetVerbose

func (u *SystemUpdater) SetVerbose(verbose bool)

SetVerbose enables verbose output

func (*SystemUpdater) Update

func (u *SystemUpdater) Update() error

Update performs the system update

func (*SystemUpdater) UpdateBootloader

func (u *SystemUpdater) UpdateBootloader() error

UpdateBootloader updates the bootloader to boot from the new partition

type UpdaterConfig

type UpdaterConfig struct {
	Device         string
	ImageRef       string
	ImageDigest    string // Digest of the remote image (set by IsUpdateNeeded)
	FilesystemType string // Filesystem type (ext4, btrfs)
	Verbose        bool
	DryRun         bool
	Force          bool // Skip interactive confirmation
	JSONOutput     bool
	KernelArgs     []string
	MountPoint     string
	BootMountPoint string
}

UpdaterConfig holds configuration for system updates

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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