Compare commits

..

No commits in common. "main" and "patch-1" have entirely different histories.

25 changed files with 133 additions and 372 deletions

2
.gitignore vendored
View file

@ -5,5 +5,3 @@ dist/
dist-newstyle/
cabal.project.local
*.swp

View file

@ -1,18 +1,5 @@
# Revision history for Arion
## 0.2.1.0 -- 2023-07-26
### Added
* `service.networks` now supports attribute set values with various options, thanks to @pedorich-n.
* `docker-compose.volumes` can now be specified in multiple modules, thanks to @qaifshaikh.
* `image.fakeRootCommands` for making modifications to the image that aren't "add a link farm".
### Fixed
* Regular maintenance fixes, including one by olebedev
## 0.2.0.0 -- 2022-12-02
### BREAKING

View file

@ -1,7 +1,7 @@
cabal-version: 2.4
name: arion-compose
version: 0.2.1.0
version: 0.2.0.0
synopsis: Run docker-compose with help from Nix/NixOS
description: Arion is a tool for building and running applications that consist of multiple docker containers using NixOS modules. It has special support for docker images that are built with Nix, for a smooth development experience and improved performance.
homepage: https://github.com/hercules-ci/arion#readme
@ -30,7 +30,7 @@ source-repository head
location: https://github.com/hercules-ci/arion
common common
build-depends: base >=4.12.0.0 && <4.99
build-depends: base >=4.12.0.0 && <4.17
, aeson >=2
, aeson-pretty
, async

View file

@ -45,21 +45,18 @@ NOTE: This deployment method does NOT use an `arion-pkgs.nix` file, but reuses
# Pick one of:
# - niv
((import ./nix/sources.nix).arion + "/nixos-module.nix")
# - or flakes (where arion is a flake input)
# - flakes (where arion is a flake input)
arion.nixosModules.arion
# - or other: copy commit hash of arion and replace HASH in:
(builtins.fetchTarball "https://github.com/hercules-ci/arion/archive/HASH.tar.gz") + "/nixos-module.nix")
# - other
arionPath + "/nixos-module.nix")
];
virtualisation.arion = {
backend = "podman-socket"; # or "docker"
projects.example = {
serviceName = "example"; # optional systemd service name, defaults to arion-example in this case
settings = {
# Specify you project here, or import it from a file.
# NOTE: This does NOT use ./arion-pkgs.nix, but defaults to NixOS' pkgs.
imports = [ ./arion-compose.nix ];
};
projects.example.settings = {
# Specify you project here, or import it from a file.
# NOTE: This does NOT use ./arion-pkgs.nix, but defaults to NixOS' pkgs.
imports = [ ./arion-compose.nix ];
};
};
}

View file

@ -148,7 +148,7 @@ Describe containers using NixOS-style modules. There are a few options:
project.name = "full-nixos";
services.webserver = { pkgs, lib, ... }: {
nixos.useSystemd = true;
nixos.configuration.boot.tmp.useTmpfs = true;
nixos.configuration.boot.tmpOnTmpfs = true;
nixos.configuration.services.nginx.enable = true;
nixos.configuration.services.nginx.virtualHosts.localhost.root = "${pkgs.nix.doc}/share/doc/nix/manual";
nixos.configuration.services.nscd.enable = false;

View file

@ -2,7 +2,7 @@
project.name = "full-nixos";
services.webserver = { pkgs, lib, ... }: {
nixos.useSystemd = true;
nixos.configuration.boot.tmp.useTmpfs = true;
nixos.configuration.boot.tmpOnTmpfs = true;
nixos.configuration.networking.useDHCP = false;
nixos.configuration.services.nginx.enable = true;
nixos.configuration.services.nginx.virtualHosts.localhost.root = "${pkgs.nix.doc}/share/doc/nix/manual";

View file

@ -10,17 +10,6 @@
*/
{ lib, pkgs, ... }: {
config.project.name = "traefik";
config.networks = {
traefik-custom = {
name = "traefik-custom";
ipam = {
config = [{
subnet = "172.32.0.0/16";
gateway = "172.32.0.1";
}];
};
};
};
config.services = {
traefik = {
image.command = [
@ -35,7 +24,6 @@
stop_signal = "SIGINT";
ports = [ "80:80" "8080:8080" ];
volumes = [ "/var/run/docker.sock:/var/run/docker.sock:ro" ];
networks = [ "traefik-custom" ];
};
};
@ -46,17 +34,14 @@
${pkgs.python3}/bin/python -m http.server
''}"];
service.container_name = "simple-service";
service.ports = [
"8000:8000" # host:container
];
service.stop_signal = "SIGINT";
service.labels = {
"traefik.enable" = "true";
"traefik.http.routers.nix-docs.rule" = "Host(`nix-docs.localhost`)";
"traefik.http.routers.nix-docs.entrypoints" = "web";
"traefik.http.services.nix-docs.loadBalancer.server.port" = "8000";
};
service.networks = {
traefik-custom = {
ipv4_address = "172.32.0.5";
};
};
};
};

View file

@ -7,11 +7,11 @@
]
},
"locked": {
"lastModified": 1722555600,
"narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=",
"lastModified": 1675933616,
"narHash": "sha256-/rczJkJHtx16IFxMmAWu5nNYcSXNg1YYXTHoGjLrLUA=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "8471fe90ad337a8074e957b69ca4d0089218391d",
"rev": "47478a4a003e745402acf63be7f9a092d51b83d7",
"type": "github"
},
"original": {
@ -20,26 +20,6 @@
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": [
"hercules-ci-effects",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"id": "flake-parts",
"type": "indirect"
}
},
"haskell-flake": {
"locked": {
"lastModified": 1675296942,
@ -56,34 +36,13 @@
"type": "github"
}
},
"hercules-ci-effects": {
"inputs": {
"flake-parts": "flake-parts_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1719226092,
"narHash": "sha256-YNkUMcCUCpnULp40g+svYsaH1RbSEj6s4WdZY/SHe38=",
"owner": "hercules-ci",
"repo": "hercules-ci-effects",
"rev": "11e4b8dc112e2f485d7c97e1cee77f9958f498f5",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "hercules-ci-effects",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1722630782,
"narHash": "sha256-hMyG9/WlUi0Ho9VkRrrez7SeNlDzLxalm9FwY7n/Noo=",
"lastModified": 1676300157,
"narHash": "sha256-1HjRzfp6LOLfcj/HJHdVKWAkX9QRAouoh6AjzJiIerU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d04953086551086b44b6f3c6b7eeb26294f207da",
"rev": "545c7a31e5dedea4a6d372712a18e00ce097d462",
"type": "github"
},
"original": {
@ -97,7 +56,6 @@
"inputs": {
"flake-parts": "flake-parts",
"haskell-flake": "haskell-flake",
"hercules-ci-effects": "hercules-ci-effects",
"nixpkgs": "nixpkgs"
}
}

View file

@ -6,15 +6,12 @@
haskell-flake.url = "github:srid/haskell-flake/0.1.0";
flake-parts.url = "github:hercules-ci/flake-parts";
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
hercules-ci-effects.url = "github:hercules-ci/hercules-ci-effects";
hercules-ci-effects.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = inputs@{ self, flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } ({ config, lib, extendModules, ... }: {
imports = [
inputs.haskell-flake.flakeModule
inputs.hercules-ci-effects.flakeModule
inputs.flake-parts.flakeModules.easyOverlay
./docs/flake-module.nix
./tests/flake-module.nix
@ -66,26 +63,15 @@
];
});
};
hercules-ci.flake-update = {
enable = true;
autoMergeMethod = "merge";
when = {
hour = [ 2 ];
dayOfMonth = [ 5 ];
};
};
herculesCI.ciSystems = [
# "aarch64-darwin"
# "aarch64-linux"
"x86_64-darwin"
"x86_64-linux"
];
flake = {
debug = { inherit inputs config lib; };
defaultPackage =
lib.mapAttrs
(ps: lib.warn "arion.defaultPackage has been removed in favor of arion.packages.\${system}.default"
ps.default)
config.flake.packages;
lib = {
eval = import ./src/nix/eval-composition.nix;
build = args@{ ... }:
@ -93,6 +79,12 @@
in composition.config.out.dockerComposeYaml;
};
nixosModules.arion = ./nixos-module.nix;
herculesCI.ciSystems = [
# "aarch64-darwin"
# "aarch64-linux"
"x86_64-darwin"
"x86_64-linux"
];
};
});
}

View file

@ -26,14 +26,9 @@ let
visible = "shallow";
};
_systemd = mkOption { internal = true; };
serviceName = mkOption {
description = "The name of the Arion project's systemd service";
type = types.str;
default = "arion-${name}";
};
};
config = {
_systemd.services.${config.serviceName} = {
_systemd.services."arion-${name}" = {
wantedBy = [ "multi-user.target" ];
after = [ "sockets.target" ];

View file

@ -3,4 +3,4 @@
# For manual testing of a hacked arion built via Nix.
# Works when called from outside the project directory.
exec nix run -f "$(dirname ${BASH_SOURCE[0]})" arion "$@"
exec nix run -f "$(dirname ${BASH_SOURCE[0]})" arion -c arion "$@"

View file

@ -13,34 +13,19 @@ import qualified Data.Text as T
import qualified Data.Text.IO as T
spec :: Spec
spec = describe "evaluateComposition" $ do
it "matches an example" $ do
x <- Arion.Nix.evaluateComposition EvaluationArgs
{ evalUid = 123
, evalModules = NEL.fromList
["src/haskell/testdata/Arion/NixSpec/arion-compose.nix"]
, evalPkgs = "import <nixpkgs> { system = \"x86_64-linux\"; }"
, evalWorkDir = Nothing
, evalMode = ReadOnly
, evalUserArgs = ["--show-trace"]
}
let actual = pretty x
expected <- T.readFile "src/haskell/testdata/Arion/NixSpec/arion-compose.json"
censorPaths actual `shouldBe` censorPaths expected
it "matches an build.context example" $ do
x <- Arion.Nix.evaluateComposition EvaluationArgs
{ evalUid = 1234
, evalModules = NEL.fromList
["src/haskell/testdata/Arion/NixSpec/arion-context-compose.nix"]
, evalPkgs = "import <nixpkgs> { system = \"x86_64-linux\"; }"
, evalWorkDir = Nothing
, evalMode = ReadOnly
, evalUserArgs = ["--show-trace"]
}
let actual = pretty x
expected <- T.readFile "src/haskell/testdata/Arion/NixSpec/arion-context-compose.json"
censorPaths actual `shouldBe` censorPaths expected
spec = describe "evaluateComposition" $ it "matches an example" $ do
x <- Arion.Nix.evaluateComposition EvaluationArgs
{ evalUid = 123
, evalModules = NEL.fromList
["src/haskell/testdata/Arion/NixSpec/arion-compose.nix"]
, evalPkgs = "import <nixpkgs> { system = \"x86_64-linux\"; }"
, evalWorkDir = Nothing
, evalMode = ReadOnly
, evalUserArgs = ["--show-trace"]
}
let actual = pretty x
expected <- T.readFile "src/haskell/testdata/Arion/NixSpec/arion-compose.json"
censorPaths actual `shouldBe` censorPaths expected
censorPaths :: Text -> Text
censorPaths = censorImages . censorStorePaths

View file

@ -9,4 +9,3 @@ import qualified Arion.NixSpec
spec :: Spec
spec = do
describe "Arion.Nix" Arion.NixSpec.spec

View file

@ -2,7 +2,7 @@
project.name = "unit-test-data";
services.webserver = { pkgs, ... }: {
nixos.useSystemd = true;
nixos.configuration.boot.tmp.useTmpfs = true;
nixos.configuration.boot.tmpOnTmpfs = true;
nixos.configuration.services.nginx.enable = true;
nixos.configuration.services.nginx.virtualHosts.localhost.root = "${pkgs.nix.doc}/share/doc/nix/manual";
service.useHostStore = true;

View file

@ -1,41 +0,0 @@
{
"networks": {
"default": {
"name": "unit-test-data"
}
},
"services": {
"webserver": {
"build": {
"context": "<STOREPATH>"
},
"environment": {},
"ports": [
"8080:80"
],
"sysctls": {},
"volumes": []
}
},
"version": "3.4",
"volumes": {},
"x-arion": {
"images": [
{
"imageExe": "<STOREPATH>",
"imageName": "localhost/webserver",
"imageTag": "<HASH>"
}
],
"project": {
"name": "unit-test-data"
},
"serviceInfo": {
"webserver": {
"defaultExec": [
"/bin/sh"
]
}
}
}
}

View file

@ -1,9 +0,0 @@
{
project.name = "unit-test-data";
services.webserver.service = {
build.context = "${./build-context}";
ports = [
"8080:80"
];
};
}

View file

@ -1,4 +0,0 @@
FROM nginx
RUN echo this is a dockerfile to be built

View file

@ -3,19 +3,13 @@ let
link = url: text: ''[${text}](${url})'';
composeSpecRev = "55b450aee50799a2f33cc99e1d714518babe305e";
serviceRef = fragment:
''See ${link "https://github.com/compose-spec/compose-spec/blob/${composeSpecRev}/05-services.md#${fragment}" "Compose Spec Services #${fragment}"}'';
networkRef = fragment:
''See ${link "https://github.com/compose-spec/compose-spec/blob/${composeSpecRev}/06-networks.md#${fragment}" "Compose Spec Networks #${fragment}"}'';
dockerComposeRef = fragment:
''See ${link "https://docs.docker.com/compose/compose-file/#${fragment}" "Docker Compose#${fragment}"}'';
in
{
inherit
dockerComposeRef
link
networkRef
serviceRef
;
}

View file

@ -7,7 +7,7 @@ let
types
;
inherit (import ../../lib.nix { inherit lib; })
link
dockerComposeRef
;
in
{
@ -19,7 +19,7 @@ in
];
});
description = ''
See ${link "https://docs.docker.com/compose/compose-file/06-networks/" "Docker Compose Networks"}
${dockerComposeRef "networks-top-level-element"}
'';
};
enableDefaultNetwork = mkOption {

View file

@ -7,7 +7,7 @@ let
types
;
inherit (import ../../lib.nix { inherit lib; })
networkRef
dockerComposeRef
;
in
{
@ -15,21 +15,21 @@ in
driver = mkOption {
description = ''
`"none"`, `"host"`, or a platform-specific value.
${networkRef "driver"}
${dockerComposeRef "driver"}
'';
type = types.str;
};
driver_opts = mkOption {
description = ''
${networkRef "driver_opts"}
${dockerComposeRef "driver_opts"}
'';
type = types.lazyAttrsOf types.raw or types.unspecified;
};
attachable = mkOption {
description = ''
${networkRef "attachable"}
${dockerComposeRef "attachable"}
'';
type = types.bool;
example = true;
@ -39,7 +39,7 @@ in
description = ''
Whether we've entered the 21st century yet.
${networkRef "enable_ipv6"}
${dockerComposeRef "enable_ipv6"}
'';
type = types.bool;
};
@ -49,7 +49,7 @@ in
description = ''
Manage IP addresses.
${networkRef "ipam"}
${dockerComposeRef "ipam"}
'';
type = types.raw or types.unspecified;
};
@ -58,7 +58,7 @@ in
description = ''
Achieves "external isolation".
${networkRef "internal"}
${dockerComposeRef "internal"}
'';
defaultText = false;
type = types.bool;
@ -68,7 +68,7 @@ in
description = ''
Metadata.
${networkRef "labels"}
${dockerComposeRef "labels"}
'';
# no list support, because less expressive wrt overriding
type = types.attrsOf types.str;
@ -79,7 +79,7 @@ in
When `true`, don't create or destroy the network, but assume that it
exists.
${networkRef "external"}
${dockerComposeRef "external"}
'';
type = types.bool;
};
@ -92,7 +92,7 @@ in
Note the `default` network's default `name` is set to `project.name` by Arion.
${networkRef "name"}
${dockerComposeRef "name"}
'';
type = types.str;
};

View file

@ -12,9 +12,15 @@ let
inherit (import ../../lib.nix { inherit lib; })
link
serviceRef
dockerComposeRef
;
dockerComposeKitchenSink = ''
Analogous to the `docker run` counterpart.
${dockerComposeRef "domainname-hostname-ipc-mac_address-privileged-read_only-shm_size-stdin_open-tty-user-working_dir"}
'';
cap_add = lib.attrNames (lib.filterAttrs (name: value: value == true) config.service.capabilities);
cap_drop = lib.attrNames (lib.filterAttrs (name: value: value == false) config.service.capabilities);
@ -50,12 +56,12 @@ in
service.volumes = mkOption {
type = listOf types.unspecified;
default = [];
description = serviceRef "volumes";
description = dockerComposeRef "volumes";
};
service.tmpfs = mkOption {
type = listOf types.str;
default = [];
description = serviceRef "tmpfs";
description = dockerComposeRef "tmpfs";
};
service.build.context = mkOption {
type = nullOr str;
@ -63,65 +69,44 @@ in
description = ''
Locates a Dockerfile to use for creating an image to use in this service.
https://docs.docker.com/compose/compose-file/build/#context
'';
};
service.build.dockerfile = mkOption {
type = nullOr str;
default = null;
description = ''
Sets an alternate Dockerfile. A relative path is resolved from the build context.
https://docs.docker.com/compose/compose-file/build/#dockerfile
'';
};
service.build.target = mkOption {
type = nullOr str;
default = null;
description = ''
Defines the stage to build as defined inside a multi-stage Dockerfile.
https://docs.docker.com/compose/compose-file/build/#target
${dockerComposeRef "context"}
'';
};
service.hostname = mkOption {
type = nullOr str;
default = null;
description = ''
${serviceRef "hostname"}
'';
description = dockerComposeKitchenSink;
};
service.tty = mkOption {
type = nullOr bool;
default = null;
description = ''
${serviceRef "tty"}
'';
description = dockerComposeKitchenSink;
};
service.environment = mkOption {
type = attrsOf (either str int);
default = {};
description = serviceRef "environment";
description = dockerComposeRef "environment";
};
service.image = mkOption {
type = nullOr str;
default = null;
description = serviceRef "image";
type = str;
description = dockerComposeRef "image";
};
service.command = mkOption {
type = nullOr types.unspecified;
default = null;
description = serviceRef "command";
description = dockerComposeRef "command";
};
service.container_name = mkOption {
type = nullOr types.str;
default = null;
description = serviceRef "container_name";
description = dockerComposeRef "container_name";
};
service.depends_on =
let conditionsModule = {
options = {
condition = mkOption {
type = enum ["service_started" "service_healthy" "service_completed_successfully"];
description = serviceRef "depends_on";
description = dockerComposeRef "depends_on";
default = "service_started";
};
};
@ -129,10 +114,10 @@ in
in mkOption {
type = either (listOf str) (attrsOf (submodule conditionsModule));
default = [];
description = serviceRef "depends_on";
description = dockerComposeRef "depends_on";
};
service.healthcheck = mkOption {
description = serviceRef "healthcheck";
description = dockerComposeRef "healthcheck";
type = submodule ({ config, options, ...}: {
options = {
_out = mkOption {
@ -145,30 +130,30 @@ in
type = nullOr (listOf str);
default = null;
example = [ "CMD" "pg_isready" ];
description = serviceRef "healthcheck";
description = dockerComposeRef "healthcheck";
};
interval = mkOption {
type = str;
default = "30s";
example = "1m";
description = serviceRef "healthcheck";
description = dockerComposeRef "healthcheck";
};
timeout = mkOption {
type = str;
default = "30s";
example = "10s";
description = serviceRef "healthcheck";
description = dockerComposeRef "healthcheck";
};
start_period = mkOption {
type = str;
default = "0s";
example = "30s";
description = serviceRef "healthcheck";
description = dockerComposeRef "healthcheck";
};
retries = mkOption {
type = int;
default = 3;
description = serviceRef "healthcheck";
description = dockerComposeRef "healthcheck";
};
};
});
@ -180,14 +165,14 @@ in
See ${link "https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities"
"`docker run --device` documentation"}
${serviceRef "devices"}
${dockerComposeRef "devices"}
'';
};
service.dns = mkOption {
type = listOf str;
default = [];
example = [ "8.8.8.8" "8.8.4.4" ];
description = serviceRef "dns";
description = dockerComposeRef "dns";
};
service.labels = mkOption {
type = attrsOf str;
@ -198,58 +183,47 @@ in
"traefik.http.routers.my-service.rule" = "Host(`my-service.localhost`)";
"traefik.http.routers.my-service.entrypoints" = "web";
};
description = serviceRef "labels";
description = dockerComposeRef "labels";
};
service.links = mkOption {
type = listOf str;
default = [];
description = serviceRef "links";
description = dockerComposeRef "links";
};
service.external_links = mkOption {
type = listOf str;
default = [];
description = serviceRef "external_links";
};
service.profiles = mkOption {
type = listOf str;
default = [];
description = serviceRef "profiles";
description = dockerComposeRef "external_links";
};
service.extra_hosts = mkOption {
type = listOf str;
default = [];
description = serviceRef "extra_hosts";
description = dockerComposeRef "extra_hosts";
};
service.working_dir = mkOption {
type = nullOr str;
default = null;
description = ''
${serviceRef "working_dir"}
'';
description = dockerComposeKitchenSink;
};
service.privileged = mkOption {
type = nullOr bool;
default = null;
description = ''
${serviceRef "privileged"}
'';
description = dockerComposeKitchenSink;
};
service.entrypoint = mkOption {
type = nullOr str;
default = null;
description = serviceRef "entrypoint";
description = dockerComposeRef "entrypoint";
};
service.restart = mkOption {
type = nullOr str;
default = null;
description = serviceRef "restart";
description = dockerComposeRef "restart";
};
service.user = mkOption {
type = nullOr str;
default = null;
description = ''
${serviceRef "user"}
'';
description = dockerComposeKitchenSink;
};
service.ports = mkOption {
type = listOf types.unspecified;
@ -257,76 +231,38 @@ in
description = ''
Expose ports on host. "host:container" or structured.
${serviceRef "ports"}
${dockerComposeRef "ports"}
'';
};
service.expose = mkOption {
type = listOf str;
default = [];
description = serviceRef "expose";
description = dockerComposeRef "expose";
};
service.env_file = mkOption {
type = listOf str;
default = [];
description = serviceRef "env_file";
description = dockerComposeRef "env_file";
};
service.network_mode = mkOption {
type = nullOr str;
default = null;
description = serviceRef "network_mode";
description = dockerComposeRef "network_mode";
};
service.networks = mkOption {
type = nullOr (listOf types.str);
default = null;
description = dockerComposeRef "networks";
};
service.networks =
let
networksModule = submodule ({ config, options, ...}: {
options = {
_out = mkOption {
internal = true;
readOnly = true;
default = lib.mapAttrs (k: opt: opt.value) (lib.filterAttrs (_: opt: opt.isDefined) { inherit (options) aliases ipv4_address ipv6_address link_local_ips priority; });
};
aliases = mkOption {
type = listOf str;
description = serviceRef "aliases";
default = [ ];
};
ipv4_address = mkOption {
type = str;
description = serviceRef "ipv4_address-ipv6_address";
};
ipv6_address = mkOption {
type = str;
description = serviceRef "ipv4_address-ipv6_address";
};
link_local_ips = mkOption {
type = listOf str;
description = serviceRef "link_local_ips";
};
priority = mkOption {
type = int;
description = serviceRef "priority";
};
};
});
in
mkOption {
type = either (listOf str) (attrsOf networksModule);
default = [];
description = serviceRef "networks";
};
service.stop_signal = mkOption {
type = nullOr str;
default = null;
description = serviceRef "stop_signal";
};
service.stop_grace_period = mkOption {
type = nullOr str;
default = null;
description = serviceRef "stop_grace_period";
description = dockerComposeRef "stop_signal";
};
service.sysctls = mkOption {
type = attrsOf (either str int);
default = {};
description = serviceRef "sysctls";
description = dockerComposeRef "sysctls";
};
service.capabilities = mkOption {
type = attrsOf (nullOr bool);
@ -337,15 +273,13 @@ in
Setting a capability to `true` means that it will be
"added". Setting it to `false` means that it will be "dropped".
${dockerComposeRef "cap_add-cap_drop"}
Omitted and `null` capabilities will therefore be set
according to Docker's ${
link "https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities"
"default list of capabilities."
}
${serviceRef "cap_add"}
${serviceRef "cap_drop"}
'';
};
};
@ -355,11 +289,10 @@ in
volumes
environment
sysctls
image
;
} // lib.optionalAttrs (config.service.image != null) {
inherit (config.service) image;
} // lib.optionalAttrs (config.service.build.context != null ) {
build = lib.filterAttrs (n: v: v != null) config.service.build;
} // lib.optionalAttrs (config.service.build.context != null) {
inherit (config.service) build;
} // lib.optionalAttrs (cap_add != []) {
inherit cap_add;
} // lib.optionalAttrs (cap_drop != []) {
@ -398,16 +331,12 @@ in
inherit (config.service) privileged;
} // lib.optionalAttrs (config.service.network_mode != null) {
inherit (config.service) network_mode;
} // lib.optionalAttrs (config.service.networks != [] && config.service.networks != {}) {
networks =
if (builtins.isAttrs config.service.networks) then builtins.mapAttrs (_: v: v._out) config.service.networks
else config.service.networks;
} // lib.optionalAttrs (config.service.networks != null) {
inherit (config.service) networks;
} // lib.optionalAttrs (config.service.restart != null) {
inherit (config.service) restart;
} // lib.optionalAttrs (config.service.stop_signal != null) {
inherit (config.service) stop_signal;
} // lib.optionalAttrs (config.service.stop_grace_period != null) {
inherit (config.service) stop_grace_period;
} // lib.optionalAttrs (config.service.tmpfs != []) {
inherit (config.service) tmpfs;
} // lib.optionalAttrs (config.service.tty != null) {
@ -416,7 +345,5 @@ in
inherit (config.service) working_dir;
} // lib.optionalAttrs (config.service.user != null) {
inherit (config.service) user;
} // lib.optionalAttrs (config.service.profiles != []) {
inherit (config.service) profiles;
};
}

View file

@ -163,19 +163,17 @@ in
'';
};
};
config = lib.mkMerge [{
build.image = builtImage;
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}";
})
];
config = {
build.image = builtImage;
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));
service.image = lib.mkDefault "${config.build.imageName}:${config.build.imageTag}";
image.rawConfig.Cmd = config.image.command;
image.nixBuild = lib.mkDefault (priorityIsDefault options.service.image);
};
}

View file

@ -39,7 +39,7 @@ in
service.tmpfs = [
"/run" # noexec is fine because exes should be symlinked from elsewhere anyway
"/run/wrappers" # noexec breaks this intentionally
] ++ lib.optional (config.nixos.evaluatedConfig.boot.tmp.useTmpfs) "/tmp:exec,mode=777";
] ++ lib.optional (config.nixos.evaluatedConfig.boot.tmpOnTmpfs) "/tmp:exec,mode=777";
service.stop_signal = "SIGRTMIN+3";
service.tty = true;

View file

@ -45,7 +45,7 @@ in
pkgs.stdenv
];
virtualisation.memorySize = 2048;
virtualisation.memorySize = 1024;
virtualisation.diskSize = 8000;
};
testScript = ''

View file

@ -4,7 +4,7 @@ pkgs.nixosTest {
name = "test-basic-arion-kafka";
nodes = {
machine = { ... }: {
virtualisation.memorySize = 4096;
virtualisation.memorySize = 3000;
virtualisation.diskSize = 10000;
imports = [
../../nixos-module.nix