chore: remove build.image{,Name,Tag}
and replace its uses with `image.tarball{,.imageName,.imageTag}`. This changeset is a hard deprecation of `build.image{,Name,Tag}` and does not do any option renaming, etc., as the removed options were all marked as internal. This changeset also includes code that ensures the newly-relied-upon options are properly defined, raising user-visible assertion errors if no sane default image name or tag could be inferred.
This commit is contained in:
parent
d2fb84c6e0
commit
491afaa97c
2 changed files with 76 additions and 73 deletions
|
@ -13,23 +13,15 @@ let
|
||||||
|
|
||||||
addDetails = serviceName: service:
|
addDetails = serviceName: service:
|
||||||
builtins.addErrorContext "while evaluating the image for service ${serviceName}"
|
builtins.addErrorContext "while evaluating the image for service ${serviceName}"
|
||||||
(let
|
(
|
||||||
inherit (service) build;
|
let
|
||||||
in {
|
imageAttrName = "image${lib.optionalString (service.image.tarball.isExe or false) "Exe"}";
|
||||||
imageName = build.imageName or service.image.name;
|
in
|
||||||
imageTag =
|
{
|
||||||
if build.image.imageTag != ""
|
inherit (service.image.tarball) imageName imageTag;
|
||||||
then build.image.imageTag
|
${imageAttrName} = service.image.tarball.outPath;
|
||||||
else lib.head (lib.strings.splitString "-" (baseNameOf build.image.outPath));
|
|
||||||
} // (if build.image.isExe or false
|
|
||||||
then {
|
|
||||||
imageExe = build.image.outPath;
|
|
||||||
}
|
}
|
||||||
else {
|
);
|
||||||
image = build.image.outPath;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
|
@ -40,6 +32,26 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
|
assertions =
|
||||||
|
let
|
||||||
|
assertionsForRepoTagComponent = component: attrName:
|
||||||
|
lib.mapAttrsToList
|
||||||
|
(name: value: {
|
||||||
|
assertion = lib.types.nonEmptyStr.check value.${attrName};
|
||||||
|
message = lib.replaceStrings [ "\n" ] [ " " ] ''
|
||||||
|
Unable to infer the ${component} of the image associated with
|
||||||
|
config.services.${name}. Please set
|
||||||
|
config.services.${name}.image.${attrName} to a non-empty
|
||||||
|
string.
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
serviceImages;
|
||||||
|
|
||||||
|
nameAssertions = assertionsForRepoTagComponent "name" "imageName";
|
||||||
|
tagAssertions = assertionsForRepoTagComponent "tag" "imageTag";
|
||||||
|
in
|
||||||
|
nameAssertions ++ tagAssertions;
|
||||||
|
|
||||||
build.imagesToLoad = lib.attrValues serviceImages;
|
build.imagesToLoad = lib.attrValues serviceImages;
|
||||||
docker-compose.extended.images = config.build.imagesToLoad;
|
docker-compose.extended.images = config.build.imagesToLoad;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@ let
|
||||||
bool
|
bool
|
||||||
coercedTo
|
coercedTo
|
||||||
listOf
|
listOf
|
||||||
|
nonEmptyStr
|
||||||
nullOr
|
nullOr
|
||||||
oneOf
|
oneOf
|
||||||
package
|
package
|
||||||
|
@ -35,14 +36,42 @@ let
|
||||||
(pkgs.writeText "dummy-config.json" (builtins.toJSON config.image.rawConfig))
|
(pkgs.writeText "dummy-config.json" (builtins.toJSON config.image.rawConfig))
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Neither image names nor tags can can be empty strings; setting either to an
|
||||||
|
# empty string will cause `docker load` to croak with the error message
|
||||||
|
# "invalid reference format".
|
||||||
|
fallbackImageRepoTagComponent = component: fallback:
|
||||||
|
if nonEmptyStr.check component
|
||||||
|
then component
|
||||||
|
else fallback;
|
||||||
|
fallbackImageName = fallbackImageRepoTagComponent config.image.name;
|
||||||
|
fallbackImageTag = fallbackImageRepoTagComponent config.image.tag;
|
||||||
|
|
||||||
# Shim for `services.<name>.image.tarball` definitions that refer to
|
# Shim for `services.<name>.image.tarball` definitions that refer to
|
||||||
# arbitrary paths and not `dockerTools`-produced derivations.
|
# arbitrary paths and not `dockerTools`-produced derivations.
|
||||||
dummyImagePackage = outPath: {
|
dummyImagePackage = outPath:
|
||||||
inherit outPath;
|
let
|
||||||
type = "derivation";
|
tarballSuffix = ".tar.gz";
|
||||||
imageName = config.image.name;
|
repoTagSeparator = "-";
|
||||||
imageTag = if config.image.tag == null then "" else config.image.tag;
|
baseName = baseNameOf outPath;
|
||||||
};
|
baseNameNoExtension = lib.strings.removeSuffix tarballSuffix baseName;
|
||||||
|
baseNameComponents = lib.strings.splitString repoTagSeparator baseNameNoExtension;
|
||||||
|
fallbacks =
|
||||||
|
if ((lib.isStorePath outPath) && (lib.hasSuffix tarballSuffix baseName) && (lib.hasInfix repoTagSeparator baseName))
|
||||||
|
then {
|
||||||
|
imageName = lib.concatStringsSep repoTagSeparator (lib.tail baseNameComponents);
|
||||||
|
imageTag = lib.head baseNameComponents;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
imageName = null;
|
||||||
|
imageTag = null;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit outPath;
|
||||||
|
type = "derivation";
|
||||||
|
imageName = fallbackImageName fallbacks.imageName;
|
||||||
|
imageTag = fallbackImageTag fallbacks.imageTag;
|
||||||
|
};
|
||||||
|
|
||||||
# Type matching the essential attributes of derivations produced by
|
# Type matching the essential attributes of derivations produced by
|
||||||
# `dockerTools` builder functions.
|
# `dockerTools` builder functions.
|
||||||
|
@ -99,11 +128,11 @@ let
|
||||||
|
|
||||||
builtImage = buildOrStreamLayeredImage {
|
builtImage = buildOrStreamLayeredImage {
|
||||||
inherit (config.image)
|
inherit (config.image)
|
||||||
name
|
|
||||||
tag
|
tag
|
||||||
contents
|
contents
|
||||||
includeStorePaths
|
includeStorePaths
|
||||||
;
|
;
|
||||||
|
name = fallbackImageName ("localhost/" + config.service.name);
|
||||||
config = config.image.rawConfig;
|
config = config.image.rawConfig;
|
||||||
maxLayers = 100;
|
maxLayers = 100;
|
||||||
|
|
||||||
|
@ -129,33 +158,6 @@ let
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
build.image = mkOption {
|
|
||||||
type = nullOr package;
|
|
||||||
description = ''
|
|
||||||
Docker image derivation to be `docker load`-ed.
|
|
||||||
|
|
||||||
By default, when `services.<name>.image.nixBuild` is enabled, this is
|
|
||||||
the image produced using `services.<name>.image.command`,
|
|
||||||
`services.<name>.image.contents`, and
|
|
||||||
`services.<name>.image.rawConfig`.
|
|
||||||
'';
|
|
||||||
defaultText = lib.literalExample ''
|
|
||||||
pkgs.dockerTools.buildLayeredImage {
|
|
||||||
# ...
|
|
||||||
};
|
|
||||||
'';
|
|
||||||
internal = true;
|
|
||||||
};
|
|
||||||
build.imageName = mkOption {
|
|
||||||
type = str;
|
|
||||||
description = "Derived from `build.image`";
|
|
||||||
internal = true;
|
|
||||||
};
|
|
||||||
build.imageTag = mkOption {
|
|
||||||
type = str;
|
|
||||||
description = "Derived from `build.image`";
|
|
||||||
internal = true;
|
|
||||||
};
|
|
||||||
image.nixBuild = mkOption {
|
image.nixBuild = mkOption {
|
||||||
type = bool;
|
type = bool;
|
||||||
description = ''
|
description = ''
|
||||||
|
@ -169,9 +171,8 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
image.name = mkOption {
|
image.name = mkOption {
|
||||||
type = str;
|
type = nullOr str;
|
||||||
default = "localhost/" + config.service.name;
|
default = null;
|
||||||
defaultText = lib.literalExpression or lib.literalExample ''"localhost/" + config.service.name'';
|
|
||||||
description = ''
|
description = ''
|
||||||
A human readable name for the Docker image.
|
A human readable name for the Docker image.
|
||||||
|
|
||||||
|
@ -264,6 +265,11 @@ in
|
||||||
builder functions, or a Docker image tarball at some arbitrary
|
builder functions, or a Docker image tarball at some arbitrary
|
||||||
location.
|
location.
|
||||||
|
|
||||||
|
By default, when `services.<name>.image.nixBuild` is enabled, this is
|
||||||
|
the image produced using `services.<name>.image.command`,
|
||||||
|
`services.<name>.image.contents`, and
|
||||||
|
`services.<name>.image.rawConfig`.
|
||||||
|
|
||||||
::: {.note}
|
::: {.note}
|
||||||
Using this option causes Arion to ignore most other options in the
|
Using this option causes Arion to ignore most other options in the
|
||||||
{option}`services.<name>.image` namespace. The exceptions are
|
{option}`services.<name>.image` namespace. The exceptions are
|
||||||
|
@ -272,35 +278,20 @@ in
|
||||||
is not a derivation with the attributes `imageName` and `imageTag`.
|
is not a derivation with the attributes `imageName` and `imageTag`.
|
||||||
:::
|
:::
|
||||||
'';
|
'';
|
||||||
example = lib.literalExample or lib.literalExpression ''
|
example = lib.literalExpression ''
|
||||||
let
|
pkgs.dockerTools.buildLayeredImage {
|
||||||
myimage = pkgs.dockerTools.buildImage {
|
# ...
|
||||||
name = "my-image";
|
};
|
||||||
contents = [ pkgs.coreutils ];
|
|
||||||
};
|
|
||||||
in
|
|
||||||
config.services = {
|
|
||||||
myservice = {
|
|
||||||
image.tarball = myimage;
|
|
||||||
# ...
|
|
||||||
};
|
|
||||||
}
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = lib.mkMerge [{
|
config = lib.mkMerge [{
|
||||||
build.image = config.image.tarball;
|
|
||||||
build.imageName = config.build.image.imageName;
|
|
||||||
build.imageTag =
|
|
||||||
if config.build.image.imageTag != ""
|
|
||||||
then config.build.image.imageTag
|
|
||||||
else lib.head (lib.strings.splitString "-" (baseNameOf config.build.image.outPath));
|
|
||||||
image.rawConfig.Cmd = config.image.command;
|
image.rawConfig.Cmd = config.image.command;
|
||||||
image.nixBuild = lib.mkDefault (priorityIsDefault options.service.image);
|
image.nixBuild = lib.mkDefault (priorityIsDefault options.service.image);
|
||||||
}
|
}
|
||||||
( lib.mkIf (config.service.build.context == null)
|
( lib.mkIf (config.service.build.context == null)
|
||||||
{
|
{
|
||||||
service.image = lib.mkDefault "${config.build.imageName}:${config.build.imageTag}";
|
service.image = lib.mkDefault "${config.image.tarball.imageName}:${config.image.tarball.imageTag}";
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue