NAME
App::FuguVM::Autoinstall - serve one autoinstall(8) response file
SYNOPSIS
use App::FuguVM::Autoinstall;
my $responder = App::FuguVM::Autoinstall->new(
file => '/project/install.conf',
pidfile => $state->autoinstall_pidfile,
store => $state->store,
proxy_url => $proxy->guest_url,
logfile => $state->vm_state_dir . '/autoinstall.log',
);
my $port = $responder->start
or die $responder->error;
# The guest fetches http://10.0.2.2:<port>/install.conf
say $responder->guest_url;
$responder->stop;
DESCRIPTION
The module holds the response file of an autoinstall(8) run and the responder: a small HTTP child that answers that one file to one guest. The OpenBSD installer fetches the file once, at the start of the install, and the file answers every installer question.
The child binds 127.0.0.1 only, because a response file can hold the root password. The guest still reaches it: QEMU user-mode networking routes a request to the gateway address 10.0.2.2 to the host, so no port forward is needed. The child takes a free port from 8181 to 8280, one range above the mirror proxy.
The child answers one path:
GET /install.conf 200, the rendered bytes, text/plain
HEAD /install.conf 200, the headers only
any other path 404
any other method 405
a head above 8 KB 400, and the connection closes
Every answer carries Content-Length and Connection: close. The child parses the request line and nothing else, it logs each request line, and it never logs the file content. A connection that sends nothing gets no answer and no log line: the readiness probe of start connects and closes. It uses IO::Socket::INET, which is core Perl, so the module adds no CPAN dependency.
The tool serves the file byte for byte, with one exception: it replaces every occurrence of the token @PROXY_URL@ with the guest URL of the mirror proxy. The substitution happens at serve time, and it does not change the image-cache key, because a proxy port does not shape the installed disk. A response file with no token installs its sets straight from the mirror; the download is then not cached, and a second installation pays for it again.
METHODS
new
App::FuguVM::Autoinstall->new(%args)
Take file, pidfile, store, proxy_url, logfile and log. pidfile is a Fugu::Pidfile and store is a Fugu::StateFile; both are required. The constructor opens nothing.
path
Return the response-file path.
start
Take a free port, spawn the child, record the PID and the port, and wait until the port answers. Return the port, or undef with the reason in error. A responder that already runs returns its port and starts nothing.
stop
Stop the child and forget the port. The method returns 1.
is_running
Report whether the child is alive. The check reaps first, so a child that became a zombie reads as stopped.
port
Return the recorded port, or undef.
error
Return the reason of the last failed start, or undef.
guest_url
Return the response-file URL as the guest reaches it: http://10.0.2.2:<port>/install.conf. Return undef when no port is recorded.
run_child
App::FuguVM::Autoinstall->run_child($port, $file, $proxy_url)
The entry point of the spawned child. The child reads the file, renders it, and serves it until a SIGTERM.
render
App::FuguVM::Autoinstall->render($bytes, $proxy_url)
Return the bytes with every @PROXY_URL@ token replaced. The method is pure, so a test proves it with no socket. With an undefined or empty proxy URL the bytes return unchanged.
SECURITY
A response file answers the root password question of the installer. The child therefore binds the loopback address only, and the tool never copies the file into the cache or into the state directory. The image-cache key hashes the file content, and the key is a truncated digest, not the content.
SEE ALSO
Fugu::Pidfile, Fugu::Process, Fugu::StateFile, App::FuguVM::Guest, App::FuguVM::Proxy, fuguvm(1)
AUTHOR
Dick Olsson <hi@dickolsson.com>