Skip to content

Commit

Permalink
chore: remove build.image{,Name,Tag}
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tomeon committed Oct 14, 2023
1 parent e71c876 commit 457b92c
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 72 deletions.
44 changes: 28 additions & 16 deletions src/nix/modules/composition/images.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -40,6 +32,26 @@ in
};
};
config = {
assertions =
let
assertionsForRepoTagComponent = component: attrName:
lib.mapAttrsToList
(name: value: {
assertion = value.${attrName} != null;
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;
};
Expand Down
99 changes: 43 additions & 56 deletions src/nix/modules/service/image.nix
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,39 @@ 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 (component != null && 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
baseNameNoExtension = lib.strings.removeSuffix ".tar.gz" (baseNameOf outPath);
baseNameComponents = lib.strings.splitString "-" baseNameNoExtension;
fallbacks =
if lib.isStorePath outPath
then {
imageName = lib.concatStringsSep "-" (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.
Expand Down Expand Up @@ -99,11 +124,11 @@ let

builtImage = buildOrStreamLayeredImage {
inherit (config.image)
name
tag
contents
includeStorePaths
;
name = fallbackImageName ("localhost/" + config.service.name);
config = config.image.rawConfig;
maxLayers = 100;

Expand All @@ -129,33 +154,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 = ''
Expand All @@ -169,9 +167,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.
Expand Down Expand Up @@ -258,6 +255,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** that using this option causes Arion to ignore most other
options in the `services.<name>.image` namespace. The exceptions are
`services.<name>.image.name` and `services.<name>.image.tag`, which are
Expand All @@ -266,34 +268,19 @@ in
'';
default = builtImage;
example = lib.literalExample or lib.literalExpression ''
let
myimage = pkgs.dockerTools.buildImage {
name = "my-image";
contents = [ pkgs.coreutils ];
};
in
config.services = {
myservice = {
image.tarball = myimage;
# ...
};
}
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}";
})
];
}

0 comments on commit 457b92c

Please sign in to comment.