Skip to content

Commit

Permalink
nixos/storage: Switch to a new mkDeviceSpecOption
Browse files Browse the repository at this point in the history
Having just a single type for a device specification doesn't work out
well if we want to have an apply function, which we do want, because it
makes more sense if we want to resolve such a device specification
without using builtins.match all over the place.

It also improves a lot in readability of the option descriptions,
because every such option now has not only a description of what a
device specification is but also lists the valid types for the device
specification.

This has another advantage that instead for something like the
following:

Type: list of device specification of <type>.<name>s

The type description is now just:

Type: list of device specifications

We're also heading for more consistency, speaking about "device
specification" or shortly "devspec". Say if we have something like
"storage.foo.bar", "foo.bar" is the "device specification" and "foo" is
the "device specification type" and "bar" is the "device specification
name".

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
  • Loading branch information
aszlig committed Jan 6, 2017
1 parent c469816 commit 17d464b
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 27 deletions.
45 changes: 25 additions & 20 deletions nixos/modules/tasks/storage/default.nix
Expand Up @@ -73,17 +73,19 @@ let
};

orderableOptions = deviceSpec: {
options.before = mkOption {
type = types.listOf (storageLib.types.deviceSpec [ deviceSpec.name ]);
options.before = storageLib.mkDeviceSpecOption {
typeContainer = types.listOf;
validDeviceTypes = [ deviceSpec.name ];
default = [];
description = ''
List of ${deviceSpec.description}s that will be created after this
${deviceSpec.description}.
'';
};

options.after = mkOption {
type = types.listOf (storageLib.types.deviceSpec [ deviceSpec.name ]);
options.after = storageLib.mkDeviceSpecOption {
typeContainer = types.listOf;
validDeviceTypes = [ deviceSpec.name ];
default = [];
description = ''
List of ${deviceSpec.description}s that will be created prior to this
Expand All @@ -93,8 +95,8 @@ let
};

partitionOptions.options = {
targetDevice = mkOption {
type = storageLib.types.deviceSpec containerTypes;
targetDevice = storageLib.mkDeviceSpecOption {
validDeviceTypes = containerTypes;
description = ''
The target device of this partition.
'';
Expand All @@ -110,35 +112,38 @@ let
'';
};

devices = mkOption {
type = types.listOf (storageLib.types.deviceSpec containerTypes);
devices = storageLib.mkDeviceSpecOption {
typeContainer = types.listOf;
validDeviceTypes = containerTypes;
description = ''
List of devices that will be part of this array.
'';
};
};

volgroupOptions.options = {
devices = mkOption {
type = types.listOf (storageLib.types.deviceSpec containerTypes);
devices = storageLib.mkDeviceSpecOption {
typeContainer = types.listOf;
validDeviceTypes = containerTypes;
description = ''
List of devices that will be part of this volume group.
'';
};
};

logvolOptions.options = {
group = mkOption {
type = storageLib.types.deviceSpec [ "volgroup" ];
group = storageLib.mkDeviceSpecOption {
validDeviceTypes = [ "volgroup" ];
description = ''
The volume group this volume should be part of.
'';
};
};

btrfsOptions.options = {
devices = mkOption {
type = types.listOf (storageLib.types.deviceSpec containerTypes);
devices = storageLib.mkDeviceSpecOption {
typeContainer = types.listOf;
validDeviceTypes = containerTypes;
description = ''
List of devices that will be part of this BTRFS volume.
'';
Expand Down Expand Up @@ -250,12 +255,11 @@ in

options.fileSystems = mkOption {
type = types.loaOf (types.submodule ({ config, ... }: {
options.storage = mkOption {
options.storage = storageLib.mkDeviceSpecOption {
validDeviceTypes = containerTypes ++ [ "btrfs" ];
typeContainer = types.nullOr;
default = null;
example = "partition.root";
type = types.nullOr (storageLib.types.deviceSpec (containerTypes ++ [
"btrfs"
]));
description = ''
Storage device from <option>storage.*</option> to use for
this file system.
Expand All @@ -272,10 +276,11 @@ in

options.swapDevices = mkOption {
type = types.listOf (types.submodule {
options.storage = mkOption {
options.storage = storageLib.mkDeviceSpecOption {
validDeviceTypes = containerTypes;
typeContainer = types.nullOr;
default = null;
example = "partition.swap";
type = types.nullOr (storageLib.types.deviceSpec containerTypes);
description = ''
Storage device from <option>storage.*</option> to use for
this swap device.
Expand Down
31 changes: 24 additions & 7 deletions nixos/modules/tasks/storage/lib.nix
Expand Up @@ -108,22 +108,39 @@ let
else builtins.trace invalidTypeMsg false;
in if typeAndName == null then syntaxError else assertType;

deviceSpecType = validTypes: lib.mkOptionType {
name = "deviceSpec";
description = "device specification";
check = spec: lib.isString spec && assertSpec validTypes spec;
merge = lib.mergeEqualOption;
};

in {
inherit sizeUnits;

mkDeviceSpecOption = attrs: lib.mkOption ({
type = let
# This is a list of valid device types in a device specification, such as
# "partition", "disk" and so on.
validDeviceTypes = attrs.validDeviceTypes or [];
# The outer type wrapping the internal deviceSpecType, so it's possible to
# wrap the deviceSpecType in any other container type in lib.types.
typeContainer = attrs.typeContainer or lib.id;
in typeContainer (deviceSpecType validDeviceTypes);
description = attrs.description + ''
The device specification has to be in the form
<literal>&lt;type&gt;.&lt;name&gt;</literal> where <literal>type</literal>
is ${oneOf (attrs.validDeviceTypes or [])} and <literal>name</literal> is
the name in <option>storage.sometype.name</option>.
'';
} // removeAttrs attrs [ "validDeviceTypes" "typeContainer" "description" ]);

types = {
size = lib.mkOptionType {
name = "size";
description = "\"fill\", integer in bytes or attrset of unit -> size";
check = s: s == "fill" || lib.isInt s || (lib.isAttrs s && assertUnits s);
merge = lib.mergeEqualOption;
};

deviceSpec = validTypes: lib.mkOptionType {
name = "deviceSpec";
description = "device specification of <type>.<name>";
check = spec: lib.isString spec && assertSpec validTypes spec;
merge = lib.mergeEqualOption;
};
};
}

0 comments on commit 17d464b

Please sign in to comment.