NAME

App::FuguVM::State - what FuguVM remembers about one VM between runs

SYNOPSIS

use App::FuguVM::State;

my $state = App::FuguVM::State->new($state_dir, 'default')
    or die "cannot open the state of 'default'\n";

$state->mark_running;

if ($state->was_unclean_shutdown) {
    check_the_disk();
}

DESCRIPTION

Each VM has a directory under the state directory:

<state_dir>/<vm>/status           the JSON state, mode 0600
<state_dir>/<vm>/vm.pid           the QEMU process
<state_dir>/<vm>/proxy.pid        the proxy child
<state_dir>/<vm>/autoinstall.pid  the responder child
<state_dir>/<vm>/disk.qcow2       the working disk

The JSON blob rides on Fugu::StateFile. The two process IDs ride on Fugu::Pidfile, which takes its lock before it truncates and reaps a zombie before it answers "running". A QEMU that became a zombie therefore reads as stopped, which is what a caller that is about to start a second one needs to know.

The module is persistence only. It starts nothing and stops nothing: the proxy lifecycle belongs to App::FuguVM::Guest. That split is what removed the require cycle between the two modules.

METHODS

new

App::FuguVM::State->new($state_dir, $vm_name)

Open the state of one VM, and create its directory when it is absent.

The VM name becomes a directory name, so it must be one safe path component: no separator, no NUL byte, and not one of the two directory entries. A name that is not returns undef and a message in the log. The method also returns undef when the directory is a symlink, is not a directory, or cannot be created.

load, save

Read and write the JSON state. new loads. A corrupt file gives empty state and does not stop the program that would rewrite it.

store, state_dir, vm_state_dir, vm_name, data

store returns the Fugu::StateFile. App::FuguVM::Guest gives it to the proxy, which keeps its port there.

state_dir returns the directory that holds every VM's state, and vm_state_dir the one that holds this VM's. data returns the state hash reference for a caller that changes several keys at once.

vm_pidfile, proxy_pidfile, autoinstall_pidfile

Return the Fugu::Pidfile objects. QEMU writes the first itself, through its -pidfile option; the proxy supervisor owns the second, and the autoinstall responder supervisor owns the third. Each file lives in the state directory of the guest, so an interrupted run leaves no child that nothing owns.

get_vm_pid, clear_vm_pid, is_vm_running

The QEMU process. QEMU writes the pid file itself, through its -pidfile option, so there is no setter.

disk_path, disk_exists

The working disk of the VM.

set_runtime, get_runtime, clear_runtime

The runtime record: the facts of one run of one guest. The record holds accel and the resolved ssh_port and console_port. App::FuguVM::Guest writes it before it spawns QEMU, and reads it back for status and for the guest connections.

get_runtime returns the facts as a hash reference, and an empty hash reference when the guest never ran. The stop verbs call clear_runtime beside clear_vm_pid, so the record dies with the run. destroy needs no call, because it empties the whole store.

is_installed, mark_installed, get_installed_arch

Whether OpenBSD is installed on the disk. An installed system boots its own disk and never attaches the miniroot again.

mark_installed takes the architecture of the installed disk. The argument is required, so no path can forget it. get_installed_arch returns the recorded architecture, or undef. App::FuguVM::Guest compares it with the configured value before it boots an existing disk.

set_root_password, get_root_password

The password that the installer set. The store writes at mode 0600.

mark_ssh_key_installed, get_installed_ssh_pubkey

Which SSH public key the guest holds. The state records the key itself, not only that there is one. Thus a key that changed in the configuration is installed again on the next fuguvm up.

mark_running, mark_clean_shutdown, mark_unclean_shutdown, was_unclean_shutdown, clear_shutdown_state

Whether the last stop was clean. was_unclean_shutdown also reports true when the state says running and the process is gone: the VM crashed or was killed, and the disk may need a check.

SEE ALSO

Fugu::Pidfile, Fugu::StateFile, App::FuguVM::Guest

AUTHOR

Dick Olsson <hi@senzilla.io>