Skip to content
This repository has been archived by the owner on Apr 20, 2024. It is now read-only.

Commit

Permalink
Heavily refactor ZFS filesystem handling
Browse files Browse the repository at this point in the history
This switches to a model where the waxmill package is assigned a
virtual machine runtime filesystem and takes complete ownership
of it. It knows the underlying ZFS filesystem name, and where the
filesystem is mounted. This ensures that any code that has to deal
with ZFS volumes automatically knows the filesystem that owns them,
and how to find them in /dev/zvol.

Fix: #29
  • Loading branch information
io7m committed Jul 29, 2020
1 parent 0a77ccb commit 77edd14
Show file tree
Hide file tree
Showing 61 changed files with 1,360 additions and 1,284 deletions.
Expand Up @@ -39,6 +39,7 @@
import com.io7m.waxmill.machines.WXMDeviceLPC;
import com.io7m.waxmill.machines.WXMDevicePassthru;
import com.io7m.waxmill.machines.WXMDeviceSlot;
import com.io7m.waxmill.machines.WXMDeviceSlots;
import com.io7m.waxmill.machines.WXMDeviceType;
import com.io7m.waxmill.machines.WXMDeviceVirtioBlockStorage;
import com.io7m.waxmill.machines.WXMDeviceVirtioNetwork;
Expand All @@ -50,14 +51,16 @@
import com.io7m.waxmill.machines.WXMNetworkDeviceBackendType;
import com.io7m.waxmill.machines.WXMOpenOption;
import com.io7m.waxmill.machines.WXMStorageBackendFile;
import com.io7m.waxmill.machines.WXMStorageBackends;
import com.io7m.waxmill.machines.WXMTTYBackendFile;
import com.io7m.waxmill.machines.WXMTTYBackendNMDM;
import com.io7m.waxmill.machines.WXMTTYBackendStdio;
import com.io7m.waxmill.machines.WXMTap;
import com.io7m.waxmill.machines.WXMVMNet;
import com.io7m.waxmill.machines.WXMVirtualMachine;
import com.io7m.waxmill.machines.WXMZFSFilesystems;
import com.io7m.waxmill.machines.WXMZFSVolumes;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
Expand Down Expand Up @@ -483,10 +486,15 @@ private void networkDeviceBackendCommands(

private WXMCommandExecution generateGRUBBhyveCommand()
{
final var machineId =
this.machine.id();
final String machineId =
this.machine.id().toString();

final var basePath =
this.clientConfiguration.virtualMachineRuntimeDirectoryFor(machineId);
WXMZFSFilesystems.resolve(
this.clientConfiguration.virtualMachineRuntimeFilesystem(),
machineId
).mountPoint();

final var deviceMapPath =
this.grubDeviceMapPath();

Expand All @@ -500,7 +508,7 @@ private WXMCommandExecution generateGRUBBhyveCommand()
.addArguments("--root=host")
.addArguments(String.format("--directory=%s", basePath))
.addArguments(String.format("--memory=%sM", memoryMB))
.addArguments(machineId.toString())
.addArguments(machineId)
.build();
}

Expand Down Expand Up @@ -731,7 +739,8 @@ private void configureBhyveDeviceLPCBackend(
"%s,%s",
nmdm.device(),
nmdmPath(
this.clientConfiguration.virtualMachineRuntimeDirectory()
this.clientConfiguration.virtualMachineRuntimeFilesystem()
.mountPoint()
.getFileSystem(),
this.machine.id(),
NMDM_HOST
Expand Down Expand Up @@ -812,10 +821,13 @@ private String configureBhyveDeviceStorageBackend(
private String configureBhyveStorageZFS(
final WXMDeviceType device)
{
return WXMStorageBackends.determineZFSVolumePath(
this.clientConfiguration.virtualMachineRuntimeDirectory(),
this.machine.id(),
device.deviceSlot())
final var vmFs =
this.clientConfiguration.virtualMachineRuntimeFilesystemFor(this.machine.id());
final var diskName =
WXMDeviceSlots.asDiskName(device.deviceSlot());

return WXMZFSVolumes.resolve(vmFs, diskName)
.device()
.toString();
}

Expand Down Expand Up @@ -881,20 +893,22 @@ private WXMEvaluatedBootConfigurationGRUBBhyve evaluateGRUBConfigurationOpenBSD(

private Path grubDeviceMapPath()
{
final var machineId =
this.machine.id();
final var basePath =
this.clientConfiguration.virtualMachineRuntimeDirectoryFor(machineId);
return basePath.resolve("grub-device.map");
final var machineId = this.machine.id();
return WXMZFSFilesystems.resolve(
this.clientConfiguration.virtualMachineRuntimeFilesystem(),
machineId.toString()
).mountPoint()
.resolve("grub-device.map");
}

private Path grubConfigPath()
{
final var machineId =
this.machine.id();
final var basePath =
this.clientConfiguration.virtualMachineRuntimeDirectoryFor(machineId);
return basePath.resolve("grub.cfg");
final var machineId = this.machine.id();
return WXMZFSFilesystems.resolve(
this.clientConfiguration.virtualMachineRuntimeFilesystem(),
machineId.toString()
).mountPoint()
.resolve("grub.cfg");
}

private WXMEvaluatedBootConfigurationGRUBBhyve evaluateGRUBConfigurationLinux(
Expand Down Expand Up @@ -941,23 +955,27 @@ public WXMEvaluatedBootConfigurationType evaluate()
this.errorNoSuchConfiguration()
));

final var deviceMap =
WXMDeviceMap.create(
this.messages,
this.clientConfiguration,
configuration,
this.machine
);

switch (configuration.kind()) {
case GRUB_BHYVE:
return this.evaluateGRUBConfiguration(
(WXMBootConfigurationGRUBBhyve) configuration, deviceMap
);
case UEFI:
return this.evaluateUEFIConfiguration(
(WXMBootConfigurationUEFI) configuration, deviceMap
try {
final var deviceMap =
WXMDeviceMap.create(
this.messages,
this.clientConfiguration,
configuration,
this.machine
);

switch (configuration.kind()) {
case GRUB_BHYVE:
return this.evaluateGRUBConfiguration(
(WXMBootConfigurationGRUBBhyve) configuration, deviceMap
);
case UEFI:
return this.evaluateUEFIConfiguration(
(WXMBootConfigurationUEFI) configuration, deviceMap
);
}
} catch (final IOException e) {
throw new WXMException(e);
}

throw new UnreachableCodeException();
Expand Down Expand Up @@ -1016,6 +1034,7 @@ private WXMEvaluatedBootConfigurationUEFI evaluateUEFIConfiguration(
private WXMEvaluatedBootConfigurationGRUBBhyve evaluateGRUBConfiguration(
final WXMBootConfigurationGRUBBhyve configuration,
final WXMDeviceMap deviceMap)
throws IOException
{
final var kernel =
configuration.kernelInstructions();
Expand Down
Expand Up @@ -25,6 +25,7 @@
import com.io7m.waxmill.machines.WXMDryRun;
import com.io7m.waxmill.machines.WXMEvaluatedBootCommands;
import com.io7m.waxmill.machines.WXMVirtualMachine;
import com.io7m.waxmill.machines.WXMZFSFilesystems;
import com.io7m.waxmill.process.api.WXMProcessDescription;
import com.io7m.waxmill.process.api.WXMProcessesType;
import org.slf4j.Logger;
Expand Down Expand Up @@ -210,7 +211,9 @@ private void checkRequiredPaths()
}
if (!missingPaths.isEmpty()) {
if (!missingNMDMs.isEmpty()) {
throw new IOException(this.errorRequiredPathsMissingWithNMDMs(missingPaths, missingNMDMs));
throw new IOException(this.errorRequiredPathsMissingWithNMDMs(
missingPaths,
missingNMDMs));
}
throw new IOException(this.errorRequiredPathsMissing(missingPaths));
}
Expand Down Expand Up @@ -261,11 +264,13 @@ private void executeGRUBBhyve(
final WXMEvaluatedBootConfigurationGRUBBhyveType grubBhyveConfiguration)
throws IOException, WXMException, InterruptedException
{
final var lockFile =
this.clientConfiguration.virtualMachineRuntimeDirectory()
.resolve(this.machine.id().toString())
.resolve("lock");
final var machineFs =
WXMZFSFilesystems.resolve(
this.clientConfiguration.virtualMachineRuntimeFilesystem(),
this.machine.id().toString()
);

final var lockFile = machineFs.mountPoint().resolve("lock");
try (var ignored = WXMFileLock.acquire(lockFile)) {
writeGrubDeviceMap(execute, grubBhyveConfiguration);
writeGrubConfig(execute, grubBhyveConfiguration);
Expand Down
Expand Up @@ -26,12 +26,14 @@
import com.io7m.waxmill.machines.WXMDeviceAHCIDisk;
import com.io7m.waxmill.machines.WXMDeviceLPC;
import com.io7m.waxmill.machines.WXMDeviceSlot;
import com.io7m.waxmill.machines.WXMDeviceSlots;
import com.io7m.waxmill.machines.WXMDeviceType;
import com.io7m.waxmill.machines.WXMDeviceVirtioBlockStorage;
import com.io7m.waxmill.machines.WXMStorageBackendFile;
import com.io7m.waxmill.machines.WXMStorageBackends;
import com.io7m.waxmill.machines.WXMTTYBackendFile;
import com.io7m.waxmill.machines.WXMVirtualMachine;
import com.io7m.waxmill.machines.WXMZFSFilesystems;
import com.io7m.waxmill.machines.WXMZFSVolumes;

import java.nio.file.Path;
import java.util.ArrayList;
Expand Down Expand Up @@ -202,7 +204,9 @@ private static void processLPC(
break;
case WXM_NMDM:
final Path path = nmdmPath(
clientConfiguration.virtualMachineRuntimeDirectory().getFileSystem(),
clientConfiguration.virtualMachineRuntimeFilesystem()
.mountPoint()
.getFileSystem(),
machine.id(),
NMDM_HOST
);
Expand Down Expand Up @@ -264,19 +268,21 @@ private static WXMDeviceAndPath makeDeviceMapPathStorageBackend(
final WXMVirtualMachine machine)
{
switch (backend.kind()) {
case WXM_STORAGE_FILE:
case WXM_STORAGE_FILE: {
final var file = (WXMStorageBackendFile) backend;
return new WXMDeviceAndPath(index, device, file.file());

case WXM_STORAGE_ZFS_VOLUME:
final Path path =
WXMStorageBackends.determineZFSVolumePath(
clientConfiguration.virtualMachineRuntimeDirectory(),
machine.id(),
device.deviceSlot()
}
case WXM_STORAGE_ZFS_VOLUME: {
final var volume =
WXMZFSVolumes.resolve(
WXMZFSFilesystems.resolve(
clientConfiguration.virtualMachineRuntimeFilesystem(),
machine.id().toString()
),
WXMDeviceSlots.asDiskName(device.deviceSlot())
);
return new WXMDeviceAndPath(index, device, path);

return new WXMDeviceAndPath(index, device, volume.device());
}
case WXM_SCSI:
throw new UnimplementedCodeException();
}
Expand Down
Expand Up @@ -18,6 +18,8 @@

import com.io7m.immutables.styles.ImmutablesStyleType;
import com.io7m.jaffirm.core.Preconditions;
import com.io7m.waxmill.machines.WXMZFSFilesystem;
import com.io7m.waxmill.machines.WXMZFSFilesystems;
import org.immutables.value.Value;

import java.nio.file.Path;
Expand All @@ -41,13 +43,17 @@ public interface WXMClientConfigurationType
Path virtualMachineConfigurationDirectory();

/**
* A directory that contains virtual machines. This directory will contain
* one ZFS filesystem per virtual machine.
* A ZFS filesystem that contains virtual machines. This directory will
* contain one ZFS filesystem per virtual machine. Note that this value is
* the name of the ZFS filesystem, and this doesn't necessarily match where
* that filesystem is mounted! For example, {@code zfs create x/y/z && zfs set mountpoint=/a/b/c x/y/z}
* will create a ZFS filesystem {@code x/y/z} and mount it at {@code /a/b/c};
* the value expected here is {@code x/y/z}.
*
* @return The ZFS directory containing virtual machines
* @return The ZFS filesystem containing virtual machines
*/

Path virtualMachineRuntimeDirectory();
WXMZFSFilesystem virtualMachineRuntimeFilesystem();

/**
* @return The "bhyve" executable path, such as {@code /usr/sbin/bhyve}
Expand Down Expand Up @@ -129,14 +135,13 @@ default Path cuExecutable()
* @return A runtime directory
*/

default Path virtualMachineRuntimeDirectoryFor(
default WXMZFSFilesystem virtualMachineRuntimeFilesystemFor(
final UUID machineId)
{
Objects.requireNonNull(machineId, "machineId");

return this.virtualMachineRuntimeDirectory()
.resolve(machineId.toString())
.toAbsolutePath();
return WXMZFSFilesystems.resolve(
this.virtualMachineRuntimeFilesystem(), machineId.toString());
}

/**
Expand Down Expand Up @@ -175,12 +180,6 @@ default void checkPreconditions()
Path::isAbsolute,
path -> "Virtual machine configuration directory must be absolute"
);

Preconditions.checkPrecondition(
this.virtualMachineRuntimeDirectory(),
Path::isAbsolute,
path -> "Virtual machine runtime directory must be absolute"
);
}
}

Expand Up @@ -266,9 +266,10 @@ private Optional<WXMProcessDescription> handleLPCConsole(
);
}

case WXM_NMDM:
case WXM_NMDM: {
final var fileSystem =
this.configuration.virtualMachineRuntimeDirectory()
this.configuration.virtualMachineRuntimeFilesystem()
.mountPoint()
.getFileSystem();

final var path =
Expand All @@ -285,10 +286,12 @@ private Optional<WXMProcessDescription> handleLPCConsole(
.addArguments(path.toString())
.build()
);
}

case WXM_STDIO:
case WXM_STDIO: {
LOG.debug("cannot use a stdio-based console");
return Optional.empty();
}
}

throw new UnreachableCodeException();
Expand Down

0 comments on commit 77edd14

Please sign in to comment.