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:
|
||||
builtins.addErrorContext "while evaluating the image for service ${serviceName}"
|
||||
(let
|
||||
inherit (service) build;
|
||||
in {
|
||||
imageName = build.imageName or service.image.name;
|
||||
imageTag =
|
||||
if build.image.imageTag != ""
|
||||
then build.image.imageTag
|
||||
else lib.head (lib.strings.splitString "-" (baseNameOf build.image.outPath));
|
||||
} // (if build.image.isExe or false
|
||||
then {
|
||||
imageExe = build.image.outPath;
|
||||
(
|
||||
let
|
||||
imageAttrName = "image${lib.optionalString (service.image.tarball.isExe or false) "Exe"}";
|
||||
in
|
||||
{
|
||||
inherit (service.image.tarball) imageName imageTag;
|
||||
${imageAttrName} = service.image.tarball.outPath;
|
||||
}
|
||||
else {
|
||||
image = build.image.outPath;
|
||||
}
|
||||
)
|
||||
);
|
||||
);
|
||||
in
|
||||
{
|
||||
options = {
|
||||
|
@ -40,6 +32,26 @@ in
|
|||
};
|
||||
};
|
||||
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;
|
||||
docker-compose.extended.images = config.build.imagesToLoad;
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@ let
|
|||
bool
|
||||
coercedTo
|
||||
listOf
|
||||
nonEmptyStr
|
||||
nullOr
|
||||
oneOf
|
||||
package
|
||||
|
@ -35,14 +36,42 @@ let
|
|||
(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
|
||||
# arbitrary paths and not `dockerTools`-produced derivations.
|
||||
dummyImagePackage = outPath: {
|
||||
inherit outPath;
|
||||
type = "derivation";
|
||||
imageName = config.image.name;
|
||||
imageTag = if config.image.tag == null then "" else config.image.tag;
|
||||
};
|
||||
dummyImagePackage = outPath:
|
||||
let
|
||||
tarballSuffix = ".tar.gz";
|
||||
repoTagSeparator = "-";
|
||||
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
|
||||
# `dockerTools` builder functions.
|
||||
|
@ -99,11 +128,11 @@ let
|
|||
|
||||
builtImage = buildOrStreamLayeredImage {
|
||||
inherit (config.image)
|
||||
name
|
||||
tag
|
||||
contents
|
||||
includeStorePaths
|
||||
;
|
||||
name = fallbackImageName ("localhost/" + config.service.name);
|
||||
config = config.image.rawConfig;
|
||||
maxLayers = 100;
|
||||
|
||||
|
@ -129,33 +158,6 @@ let
|
|||
in
|
||||
{
|
||||
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 {
|
||||
type = bool;
|
||||
description = ''
|
||||
|
@ -169,9 +171,8 @@ in
|
|||
'';
|
||||
};
|
||||
image.name = mkOption {
|
||||
type = str;
|
||||
default = "localhost/" + config.service.name;
|
||||
defaultText = lib.literalExpression or lib.literalExample ''"localhost/" + config.service.name'';
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
A human readable name for the Docker image.
|
||||
|
||||
|
@ -264,6 +265,11 @@ in
|
|||
builder functions, or a Docker image tarball at some arbitrary
|
||||
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}
|
||||
Using this option causes Arion to ignore most other options in the
|
||||
{option}`services.<name>.image` namespace. The exceptions are
|
||||
|
@ -272,35 +278,20 @@ in
|
|||
is not a derivation with the attributes `imageName` and `imageTag`.
|
||||
:::
|
||||
'';
|
||||
example = lib.literalExample or lib.literalExpression ''
|
||||
let
|
||||
myimage = pkgs.dockerTools.buildImage {
|
||||
name = "my-image";
|
||||
contents = [ pkgs.coreutils ];
|
||||
};
|
||||
in
|
||||
config.services = {
|
||||
myservice = {
|
||||
image.tarball = myimage;
|
||||
# ...
|
||||
};
|
||||
}
|
||||
example = lib.literalExpression ''
|
||||
pkgs.dockerTools.buildLayeredImage {
|
||||
# ...
|
||||
};
|
||||
'';
|
||||
};
|
||||
};
|
||||
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.nixBuild = lib.mkDefault (priorityIsDefault options.service.image);
|
||||
}
|
||||
( 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