NAME
App::FuguVM::Proxy - the OpenBSD mirror policy over Fugu::Proxy
SYNOPSIS
use App::FuguVM::Proxy;
my $proxy = App::FuguVM::Proxy->new(
cache => App::FuguVM::Proxy::Cache->new($cache_dir),
pidfile => $state->proxy_pidfile,
store => $state->store,
child => 'App::FuguVM::Proxy',
logfile => $state->vm_state_dir . '/proxy.log',
);
my $port = $proxy->start;
my $url = $proxy->guest_url; # http://10.0.2.2:<port>
DESCRIPTION
An OpenBSD installation downloads a miniroot image and a full set of file sets. A second installation downloads them again. This proxy keeps them, thus a repeated install reads from the disk.
Fugu::Proxy holds the serve loop, the cache and the metadata. This file holds only what is true of an OpenBSD mirror and of a QEMU guest.
The file has two packages. App::FuguVM::Proxy inherits the supervisor and adds the guest URL. App::FuguVM::Proxy::Cache inherits the cache and adds the mirror patterns and the version-scoped prune.
METHODS
Every method of Fugu::Proxy and Fugu::Proxy::Cache applies. These are the additions.
run_child
App::FuguVM::Proxy->run_child($port, $cache_dir)
The entry point of the spawned child. The child builds its own cache, warms the metadata table, and serves until a SIGTERM arrives. The spawn passes a fixed argument list, so the child reads the distfile cap from FUGUVM_DISTFILE_LIMIT in its environment, which it inherits from fuguvm. An absent variable means 0.
guest_url
$proxy->guest_url
Return the proxy URL as the guest reaches it. QEMU user-mode networking puts the host at 10.0.2.2, and no other address gets out of the SLIRP network. The loopback address serves the same proxy, but the guest cannot reach it.
The method returns undef while the proxy does not run: a recorded port that a crash left behind is not a reachable proxy.
new
App::FuguVM::Proxy::Cache->new($cache_dir, $limit)
Build the cache over the directory. The optional $limit is the distfile cap in bytes. The default is 0, and 0 turns the distfile cache off: the distfile pattern then admits nothing, and trim_distfiles empties the tree.
prune
my $removed = $cache->prune(@keep_versions);
Remove the cached download tree of every OpenBSD version other than the ones named. The method returns an array reference of { version, path, size }, one for each removed tree.
Nothing else bounds this cache. fuguvm cache clear --stale prunes installed images, which live beside these downloads under the same cache_dir, but no common key connects them. Thus a version bump left the full file sets of the previous version behind for good. Nothing read them again, because every cacheable pattern is version-scoped, and every copy that a continuous-integration cache made still carried them.
The method removes whole directories and not matching files. Removal of the files alone leaves the empty version tree behind, and a continuous-integration cache walks that tree.
The method does not touch a directory whose name is not a version. distfiles is not a version name, so the method leaves the distfile tree: a distfile belongs to a port and not to a release, and a port keeps its distfile across releases. A cache under $HOME is the wrong place to delete on a guess.
trim_distfiles
my $removed = $cache->trim_distfiles;
Hold the distfile tree under the cap. The eviction removes the oldest file first, by modification time, and stops when the tree fits. The modification time is the store time of the file, because store writes each file one time; the access time is not usable, because a host can mount its home directory with noatime. A cap of 0 removes the whole tree, because the operator turned the cache off. The method removes files and leaves the directories, because a later fetch refills them. It returns the removed files as [ { path, size } ].
store calls the method after each distfile store, and the child of the proxy is the only writer. The cap is therefore true between two requests, and not only after a run. A Fugu::Proxy::Meta entry of an evicted file reads as absent, so an eviction needs no invalidation.
distfile_size, distfile_limit
distfile_size returns the bytes of the distfile tree, over every cached host. distfile_limit returns the cap in bytes.
CACHEABLE CONTENT
The cache keeps the release file sets, the packages, the syspatch sets, the checksums and their signatures, the miniroot images, the kernels, the build info, the index files, the four source tarballs of a release (ports.tar.gz, src.tar.gz, sys.tar.gz and xenocara.tar.gz), and the manifest pair of the version directory that signs them. Every pattern names a version, and that is what makes prune safe.
The distfile tree, under /pub/OpenBSD/distfiles/, is the one unversioned admission, and it is conditional: a distfile URL is cacheable only while the cap is above zero. The pattern requires a file name at the end, so a directory listing with a trailing solidus stays outside the cache, and it filters no extension, because a distfile carries every extension and sometimes none. The cap of trim_distfiles bounds the tree, because no version prune can.
Everything else is not cacheable, and neither is any response whose status is not 200. A cached 404 is a mirror that stays broken after the upstream is fixed.
SEE ALSO
Fugu::Proxy, App::FuguVM::Miniroot, App::FuguVM::Guest
AUTHOR
Dick Olsson <hi@senzilla.io>