NAME

App::FuguVM::Config - the VM defaults over Fugu::Config

SYNOPSIS

use App::FuguVM::Config;

my $root   = App::FuguVM::Config->find_project_root
    or die "not in a FuguVM project\n";
my $config = App::FuguVM::Config->new($root);

my $vm = $config->load_vm($config->default_vm);
printf "%s: OpenBSD %s, %s of memory\n",
    $vm->{name}, $vm->{version}, $vm->{memory};

DESCRIPTION

FuguVM reads two files, both named .fuguvmrc: one in the home directory and one in the project root. The project file wins.

cache_dir ~/.cache/fuguvm
state_dir .fuguvm/state
default_vm default
qemu_version 9.0

vm "default" {
    arch         arm64
    version      7.8
    memory       2048
    disk_size    8G
    ssh_port     2222
    console_port 4444
    bind_address 127.0.0.1
}

The grammar, the tilde expansion and the yes/no spellings come from Fugu::Config. This module holds only what is true of FuguVM: the defaults for a machine, the merge of the two files, and the switch that turns the installed-image cache off.

METHODS

new

App::FuguVM::Config->new($project_root)

Read both files. An absent file is normal: a checkout has no global file, and a global-only setup has no project file.

find_project_root

App::FuguVM::Config->find_project_root

Walk up from the working directory to the first directory that holds .fuguvmrc. The method returns undef when the walk reaches the root without a match.

load_vm

my $vm = $config->load_vm($name);

Return the merged configuration of one VM as a hash reference. Return undef when no file declares it, or when a value does not validate. In the second case, error reports the reason.

The method applies the defaults for arch, version, memory, disk_size, ssh_port and console_port, and folds in ssh_pubkey, cache_dir, verify, signify_dir and distfile_cache from the enclosing configuration.

verify arrives normalized to 1 or 0, like image_cache. signify_dir arrives resolved, and a value that is not a directory makes load_vm return undef with the reason in error. distfile_cache arrives as the byte count of the project setting; the distfile tree is one tree under cache_dir and each guest of a project shares it, so a per-guest cap would have no meaning. A distfile_cache line in a vm block does not apply, and the loader gives one warning for it.

arch selects the guest architecture: amd64 or arm64. The default is arm64. The comparison is case sensitive, so AMD64 is an unknown value. This loader is the boundary of the directive: it validates the value one time, and no module downstream repeats the check. The same rule applies to bind_address, ssh_port, console_port and qemu_version.

ssh_port and console_port take a decimal number from 1 to 65535, or the word auto. The defaults are 2222 and 4444. With auto, App::FuguVM::Guest takes a free host port from a fixed range and records it.

bind_address names the host address of every forwarded port, as one IPv4 address in dotted-decimal form. The default is 127.0.0.1. A host name is invalid: a name resolves once for QEMU and once for the tool, and the two answers can differ. The directive lives in a vm block, in the project .fuguvmrc, or in the global ~/.fuguvmrc, with that precedence.

qemu_version pins the version of the QEMU system binary. The value is one or more dot-separated decimal numbers, for example 9.0. The match runs over the components that the value names, so 9 pins the major version alone. The directive lives in the project .fuguvmrc or in the global ~/.fuguvmrc. A qemu_version line inside a VM declaration is an error: such a pin would silently not apply. With no directive the tool checks nothing.

cache_dir is folded in on purpose. Without it, fuguvm up would write its images under $HOME while the cache subcommands worked on a different tree.

The install modes

The loader derives install_mode from the directives, and there is no install_mode directive. Every module downstream reads that one field, and no module compares the directives again.

neither directive     expect       install with install.exp
autoinstall <file>    autoinstall  install from the response file
base_disk <path>      import       overlay an existing image

autoinstall names an autoinstall(8) response file. base_disk names an existing full-disk image; qemu-img reads a qcow2 file and a raw file. root_password_file names a file whose first line is the root password of the image. Each of the three values is a path: a leading tilde expands, and a relative path resolves against the project root. The loader validates each path one time, and the file must be readable.

The loader refuses these configurations, and error names the cause:

  • An absent or unreadable autoinstall, base_disk or root_password_file file. The message names the resolved path.

  • autoinstall together with base_disk. One guest has one origin.

  • base_disk with image_cache no. An imported base lives in the cache.

  • ssh_pubkey without root_password_file, outside the expect mode. The tool cannot install a key without a password, and the message names both remedies: add root_password_file, or unset ssh_pubkey and bake the key into the image.

error

Return the reason of the last failed load_vm, or undef.

cache_dir, state_dir, default_vm, ssh_pubkey, bind_address, qemu_version

The top-level settings. cache_dir expands a leading tilde; state_dir resolves a relative path against the project root. bind_address returns the setting of the enclosing files, or 127.0.0.1. qemu_version returns the setting, or undef.

verify

Return 1 or 0. The directive switches the mirror verification of App::FuguVM::Mirror, and the default is 1. A value that is neither yes nor no gives a warning and the default, like image_cache.

signify_dir

Return the resolved directory of the signify public keys, or undef without the directive. The value expands a leading tilde, and a relative path resolves against the project root.

distfile_cache

Return the distfile cap in bytes. The value of the directive is a size: a bare number of bytes, or a number with a K, M or G suffix. The suffix is 1024-based, and the letter case does not matter. The default is 0, and 0 turns the distfile cache off. An unparsable value gives one warning and the value 0: an unrecognized spelling must not silently mean its opposite, and off is the closed state for a cache.

declared_ports

Return the fixed ports of every VM declaration of the project, as a hash reference keyed by port. A declaration that omits a port directive holds the default port of that directive. load_vm folds the set into the per-VM configuration, and the port probe of App::FuguVM::Guest skips each port of the set.

image_cache

Whether fuguvm up may use the installed-image cache. The default is on.

ERRORS

A file that exists but does not parse gives an error in the log that names the file and the line, and the caller gets empty settings rather than half of them. The parser never skips a line it did not understand: a typo that a parser ignores is a setting that silently does not apply, and the operator finds out weeks later from the behavior of the VM.

A switch whose value is neither yes nor no gives a warning and falls back to its default. An unrecognized spelling must not silently mean the opposite.

SEE ALSO

Fugu::Config, App::FuguVM::CLI, App::FuguVM::Guest, fuguvm(1)

AUTHOR

Dick Olsson <hi@senzilla.io>