Compare commits

..

1 commit

Author SHA1 Message Date
Robert Hensing
9334c8ec11 Set default PATH when image.enableRecommendedContents is true 2022-12-09 17:11:39 +01:00
44 changed files with 1574 additions and 494 deletions

2
.gitignore vendored
View file

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

View file

@ -1,18 +1,5 @@
# Revision history for Arion # 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 ## 0.2.0.0 -- 2022-12-02
### BREAKING ### BREAKING

View file

@ -1,7 +1,7 @@
cabal-version: 2.4 cabal-version: 2.4
name: arion-compose name: arion-compose
version: 0.2.1.0 version: 0.2.0.0
synopsis: Run docker-compose with help from Nix/NixOS 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. 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 homepage: https://github.com/hercules-ci/arion#readme
@ -30,7 +30,7 @@ source-repository head
location: https://github.com/hercules-ci/arion location: https://github.com/hercules-ci/arion
common common common common
build-depends: base >=4.12.0.0 && <4.99 build-depends: base >=4.12.0.0 && <4.17
, aeson >=2 , aeson >=2
, aeson-pretty , aeson-pretty
, async , async

View file

@ -1,5 +1,5 @@
status = [ status = [
"ci/hercules/onPush/default", "ci/hercules/derivations",
"ci/hercules/evaluation", "ci/hercules/evaluation",
] ]
delete_merged_branches = true delete_merged_branches = true

View file

@ -4,4 +4,3 @@ version: 'master'
nav: nav:
- modules/ROOT/nav.adoc - modules/ROOT/nav.adoc
- modules/reference/nav.adoc - modules/reference/nav.adoc
nix: true

View file

@ -1,31 +1,20 @@
{ {
perSystem = { config, pkgs, lib, ... }: { perSystem = { config, pkgs, ... }:
packages.generated-option-doc-arion =
# TODO: use the render pipeline in flake-parts,
# which has support for things like {options}`foo`.
let let
eval = lib.evalModules { doc-options = import ./options.nix { };
modules = import ../src/nix/modules.nix;
};
in
(pkgs.nixosOptionsDoc
{
options = eval.options;
}).optionsCommonMark;
packages.generated-antora-files = in
pkgs.runCommand "generated-antora-files"
{ {
nativeBuildInputs = [ pkgs.pandoc ]; packages.doc-options = pkgs.callPackage ./options.nix { };
doc_arion = config.packages.generated-option-doc-arion;
} checks.doc-options = pkgs.runCommand "doc-options-check" { } ''
# TODO: use the render pipeline in flake-parts, if diff --color -u ${./modules/ROOT/partials/NixOSOptions.adoc} ${config.packages.doc-options}; then
# which has support for things like {options}`foo`. touch $out
'' else
mkdir -p $out/modules/ROOT/partials echo 1>&2 "The doc options have changed and need to be added."
pandoc --from=markdown --to=asciidoc \ echo 1>&2 "Please run ./update-options in the root of your arion clone."
< $doc_arion \ exit 1
> $out/modules/ROOT/partials/arion-options.adoc fi
''; '';
}; };
} }

View file

@ -1 +0,0 @@
../../../../../examples/full-nixos/arion-compose.nix

View file

@ -1 +0,0 @@
../../../../../examples/minimal/arion-compose.nix

View file

@ -1 +0,0 @@
../../../../../examples/nixos-unit/arion-compose.nix

View file

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

View file

@ -113,16 +113,14 @@ Describe containers using NixOS-style modules. There are a few options:
==== Minimal: Plain command using nixpkgs ==== Minimal: Plain command using nixpkgs
`examples/minimal/arion-compose.nix` `examples/minimal/arion-compose.nix`:
[,nix]
---- ```nix
{ pkgs, ... }: { pkgs, ... }:
{ {
project.name = "webapp"; config.services = {
services = {
webserver = { webserver = {
image.enableRecommendedContents = true;
service.useHostStore = true; service.useHostStore = true;
service.command = [ "sh" "-c" '' service.command = [ "sh" "-c" ''
cd "$$WEB_ROOT" cd "$$WEB_ROOT"
@ -132,36 +130,58 @@ Describe containers using NixOS-style modules. There are a few options:
"8000:8000" # host:container "8000:8000" # host:container
]; ];
service.environment.WEB_ROOT = "${pkgs.nix.doc}/share/doc/nix/manual"; service.environment.WEB_ROOT = "${pkgs.nix.doc}/share/doc/nix/manual";
service.stop_signal = "SIGINT";
}; };
}; };
} }
---- ```
==== NixOS: run full OS ==== NixOS: run only one systemd service
`examples/full-nixos/arion-compose.nix`: `examples/nixos-unit/arion-compose.nix`:
[,nix] ```nix
----
{ {
project.name = "full-nixos"; services.webserver = { config, pkgs, ... }: {
services.webserver = { pkgs, lib, ... }: {
nixos.useSystemd = true; nixos.configuration = {config, pkgs, ...}: {
nixos.configuration.boot.tmp.useTmpfs = true; boot.isContainer = true;
nixos.configuration.services.nginx.enable = true; services.nginx.enable = true;
nixos.configuration.services.nginx.virtualHosts.localhost.root = "${pkgs.nix.doc}/share/doc/nix/manual"; services.nginx.virtualHosts.localhost.root = "${pkgs.nix.doc}/share/doc/nix/manual";
nixos.configuration.services.nscd.enable = false; system.build.run-nginx = pkgs.writeScript "run-nginx" ''
nixos.configuration.system.nssModules = lib.mkForce []; #!${pkgs.bash}/bin/bash
nixos.configuration.systemd.services.nginx.serviceConfig.AmbientCapabilities = PATH='${config.systemd.services.nginx.environment.PATH}'
lib.mkForce [ "CAP_NET_BIND_SERVICE" ]; echo nginx:x:${toString config.users.users.nginx.uid}:${toString config.users.groups.nginx.gid}:nginx web server user:/var/empty:/bin/sh >>/etc/passwd
echo nginx:x:${toString config.users.groups.nginx.gid}:nginx >>/etc/group
${config.systemd.services.nginx.runner}
'';
};
service.command = [ config.nixos.build.run-nginx ];
service.useHostStore = true; service.useHostStore = true;
service.ports = [ service.ports = [
"8000:80" # host:container "8000:80" # host:container
]; ];
}; };
} }
---- ```
==== NixOS: run full OS
`examples/full-nixos/arion-compose.nix`:
```nix
{
services.webserver = { pkgs, ... }: {
nixos.useSystemd = 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;
service.ports = [
"8000:80" # host:container
];
};
}
```
==== Docker image from DockerHub ==== Docker image from DockerHub
@ -175,11 +195,6 @@ Describe containers using NixOS-style modules. There are a few options:
} }
``` ```
==== NixOS: run only one systemd service
Running individual units from NixOS is possible using an experimental script.
See `examples/nixos-unit/arion-compose.nix`.
=== Run === Run
Start containers and watch their logs: Start containers and watch their logs:

View file

@ -1,3 +1,5 @@
# Arion Options // To update option descriptions
// - use git grep or github search
// - or browse through src/nix/modules
include::partial$arion-options.adoc[] include::partial$NixOSOptions.adoc[]

File diff suppressed because it is too large Load diff

View file

@ -2,8 +2,7 @@
project.name = "full-nixos"; project.name = "full-nixos";
services.webserver = { pkgs, lib, ... }: { services.webserver = { pkgs, lib, ... }: {
nixos.useSystemd = true; 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.enable = true;
nixos.configuration.services.nginx.virtualHosts.localhost.root = "${pkgs.nix.doc}/share/doc/nix/manual"; nixos.configuration.services.nginx.virtualHosts.localhost.root = "${pkgs.nix.doc}/share/doc/nix/manual";
nixos.configuration.services.nscd.enable = false; nixos.configuration.services.nscd.enable = false;

View file

@ -1,7 +1,7 @@
{ pkgs, ... }: { pkgs, ... }:
{ {
project.name = "webapp"; config.project.name = "webapp";
services = { config.services = {
webserver = { webserver = {
image.enableRecommendedContents = true; image.enableRecommendedContents = true;

View file

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

64
flake.lock generated
View file

@ -7,88 +7,47 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1722555600, "lastModified": 1669931201,
"narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=", "narHash": "sha256-UnYFeaLPLj7e4eEt4GJooeJZhaZXyloQZYinwO/CeUw=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "8471fe90ad337a8074e957b69ca4d0089218391d", "rev": "995d6bc162c0539998ef6375c2c6b612972dc016",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "hercules-ci", "owner": "hercules-ci",
"ref": "easyOverlay",
"repo": "flake-parts", "repo": "flake-parts",
"type": "github" "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": { "haskell-flake": {
"locked": { "locked": {
"lastModified": 1675296942, "lastModified": 1668167720,
"narHash": "sha256-u1X1sblozi5qYEcLp1hxcyo8FfDHnRUVX3dJ/tW19jY=", "narHash": "sha256-5wDTR6xt9BB3BjgKR+YOjOkZgMyDXKaX79g42sStzDU=",
"owner": "srid", "owner": "srid",
"repo": "haskell-flake", "repo": "haskell-flake",
"rev": "c2cafce9d57bfca41794dc3b99c593155006c71e", "rev": "4fc511d93a55fedf815c1647ad146c26d7a2054e",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "srid", "owner": "srid",
"ref": "0.1.0",
"repo": "haskell-flake", "repo": "haskell-flake",
"type": "github" "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": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1722630782, "lastModified": 1669980218,
"narHash": "sha256-hMyG9/WlUi0Ho9VkRrrez7SeNlDzLxalm9FwY7n/Noo=", "narHash": "sha256-HBK1tIqarj7ZsSwQEKGlyvbAIFnglytG7FxuS4K3nY8=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d04953086551086b44b6f3c6b7eeb26294f207da", "rev": "da7988fe440ef5b8779d4f76340ad7dc79ff3b33",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-unstable", "ref": "haskell-updates",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -97,7 +56,6 @@
"inputs": { "inputs": {
"flake-parts": "flake-parts", "flake-parts": "flake-parts",
"haskell-flake": "haskell-flake", "haskell-flake": "haskell-flake",
"hercules-ci-effects": "hercules-ci-effects",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }
} }

View file

@ -2,19 +2,16 @@
description = "Arion - use Docker Compose via Nix"; description = "Arion - use Docker Compose via Nix";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/haskell-updates";
haskell-flake.url = "github:srid/haskell-flake/0.1.0"; haskell-flake.url = "github:srid/haskell-flake";
flake-parts.url = "github:hercules-ci/flake-parts"; flake-parts.url = "github:hercules-ci/flake-parts/easyOverlay"; # TODO merge
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; 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, ... }: outputs = inputs@{ self, flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } ({ config, lib, extendModules, ... }: { flake-parts.lib.mkFlake { inherit self; } ({ config, lib, extendModules, ... }: {
imports = [ imports = [
inputs.haskell-flake.flakeModule inputs.haskell-flake.flakeModule
inputs.hercules-ci-effects.flakeModule
inputs.flake-parts.flakeModules.easyOverlay inputs.flake-parts.flakeModules.easyOverlay
./docs/flake-module.nix ./docs/flake-module.nix
./tests/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 = { flake = {
debug = { inherit inputs config lib; }; 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 = { lib = {
eval = import ./src/nix/eval-composition.nix; eval = import ./src/nix/eval-composition.nix;
build = args@{ ... }: build = args@{ ... }:
@ -93,6 +79,12 @@
in composition.config.out.dockerComposeYaml; in composition.config.out.dockerComposeYaml;
}; };
nixosModules.arion = ./nixos-module.nix; nixosModules.arion = ./nixos-module.nix;
herculesCI.ciSystems = [
# "aarch64-darwin"
# "aarch64-linux"
"x86_64-darwin"
"x86_64-linux"
];
}; };
}); });
} }

View file

@ -1,4 +1,4 @@
{ config, lib, options, pkgs, ... }: { config, lib, pkgs, ... }:
let let
inherit (lib) inherit (lib)
attrValues attrValues
@ -26,14 +26,9 @@ let
visible = "shallow"; visible = "shallow";
}; };
_systemd = mkOption { internal = true; }; _systemd = mkOption { internal = true; };
serviceName = mkOption {
description = "The name of the Arion project's systemd service";
type = types.str;
default = "arion-${name}";
};
}; };
config = { config = {
_systemd.services.${config.serviceName} = { _systemd.services."arion-${name}" = {
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
after = [ "sockets.target" ]; after = [ "sockets.target" ];
@ -102,10 +97,7 @@ in
virtualisation.docker.enable = false; virtualisation.docker.enable = false;
virtualisation.podman.enable = true; virtualisation.podman.enable = true;
virtualisation.podman.dockerSocket.enable = true; virtualisation.podman.dockerSocket.enable = true;
virtualisation.podman.defaultNetwork = virtualisation.podman.defaultNetwork.dnsname.enable = true;
if options?virtualisation.podman.defaultNetwork.settings
then { settings.dns_enabled = true; } # since 2023-01 https://github.com/NixOS/nixpkgs/pull/199965
else { dnsname.enable = true; }; # compat <2023
virtualisation.arion.docker.client.package = pkgs.docker-client; virtualisation.arion.docker.client.package = pkgs.docker-client;
}) })

View file

@ -3,4 +3,4 @@
# For manual testing of a hacked arion built via Nix. # For manual testing of a hacked arion built via Nix.
# Works when called from outside the project directory. # 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,8 +13,7 @@ import qualified Data.Text as T
import qualified Data.Text.IO as T import qualified Data.Text.IO as T
spec :: Spec spec :: Spec
spec = describe "evaluateComposition" $ do spec = describe "evaluateComposition" $ it "matches an example" $ do
it "matches an example" $ do
x <- Arion.Nix.evaluateComposition EvaluationArgs x <- Arion.Nix.evaluateComposition EvaluationArgs
{ evalUid = 123 { evalUid = 123
, evalModules = NEL.fromList , evalModules = NEL.fromList
@ -28,20 +27,6 @@ spec = describe "evaluateComposition" $ do
expected <- T.readFile "src/haskell/testdata/Arion/NixSpec/arion-compose.json" expected <- T.readFile "src/haskell/testdata/Arion/NixSpec/arion-compose.json"
censorPaths actual `shouldBe` censorPaths expected 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
censorPaths :: Text -> Text censorPaths :: Text -> Text
censorPaths = censorImages . censorStorePaths censorPaths = censorImages . censorStorePaths

View file

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

View file

@ -33,7 +33,6 @@
} }
}, },
"version": "3.4", "version": "3.4",
"volumes": {},
"x-arion": { "x-arion": {
"images": [ "images": [
{ {

View file

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

@ -1,21 +1,16 @@
{ lib }: { lib }:
let let
link = url: text: ''[${text}](${url})''; link = url: text:
''link:${url}[${text}]'';
composeSpecRev = "55b450aee50799a2f33cc99e1d714518babe305e"; dockerComposeRef = fragment:
''See ${link "https://docs.docker.com/compose/compose-file/#${fragment}" "Docker Compose#${fragment}"}'';
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}"}'';
in in
{ {
inherit inherit
dockerComposeRef
link link
networkRef
serviceRef
; ;
} }

View file

@ -3,7 +3,7 @@ let
inherit (lib) types mkOption; inherit (lib) types mkOption;
link = url: text: link = url: text:
''[${text}](${url})''; ''link:${url}[${text}]'';
in in
{ {

View file

@ -63,11 +63,6 @@ in
type = lib.types.attrsOf (lib.types.submodule service); type = lib.types.attrsOf (lib.types.submodule service);
description = "An attribute set of service configurations. A service specifies how to run an image as a container."; description = "An attribute set of service configurations. A service specifies how to run an image as a container.";
}; };
docker-compose.volumes = lib.mkOption {
type = lib.types.attrsOf lib.types.unspecified;
description = "A attribute set of volume configurations.";
default = {};
};
}; };
config = { config = {
out.dockerComposeYaml = pkgs.writeText "docker-compose.yaml" config.out.dockerComposeYamlText; out.dockerComposeYaml = pkgs.writeText "docker-compose.yaml" config.out.dockerComposeYamlText;
@ -78,7 +73,6 @@ in
version = "3.4"; version = "3.4";
services = lib.mapAttrs (k: c: c.out.service) config.services; services = lib.mapAttrs (k: c: c.out.service) config.services;
x-arion = config.docker-compose.extended; x-arion = config.docker-compose.extended;
volumes = config.docker-compose.volumes;
}; };
}; };
} }

View file

@ -23,9 +23,9 @@
stored at an alternate location without altering the format of stored at an alternate location without altering the format of
store paths. store paths.
For example: instead of mounting the host's `/nix/store` as the For example: instead of mounting the host's /nix/store as the
container's `/nix/store`, this will mount `/mnt/foo/nix/store` container's /nix/store, this will mount /mnt/foo/nix/store
as the container's `/nix/store`. as the container's /nix/store.
''; '';
}; };

View file

@ -36,7 +36,7 @@ in
build.imagesToLoad = lib.mkOption { build.imagesToLoad = lib.mkOption {
type = listOf unspecified; type = listOf unspecified;
internal = true; internal = true;
description = "List of `dockerTools` image derivations."; description = "List of dockerTools image derivations.";
}; };
}; };
config = { config = {

View file

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

View file

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

View file

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

View file

@ -12,7 +12,7 @@ in
type = attrsOf unspecified; type = attrsOf unspecified;
description = '' description = ''
Information about a service to include in the Docker Compose file, Information about a service to include in the Docker Compose file,
but that will not be used by the `docker-compose` command but that will not be used by the `docker-compose`> command
itself. itself.
It will be inserted in `x-arion.serviceInfo.<service.name>`. It will be inserted in `x-arion.serviceInfo.<service.name>`.

View file

@ -20,7 +20,7 @@ in
service.hostStoreAsReadOnly = mkOption { service.hostStoreAsReadOnly = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
description = "Adds a `:ro` (read-only) access mode to the host nix store bind mount."; description = "Adds a ':ro' (read-only) access mode to the host nix store bind mount.";
}; };
service.useHostNixDaemon = mkOption { service.useHostNixDaemon = mkOption {
type = types.bool; type = types.bool;

View file

@ -28,9 +28,12 @@ in
}; };
}; };
config = { config = mkIf config.image.enableRecommendedContents {
image.contents = mkIf config.image.enableRecommendedContents [ image.contents = [
(pkgs.callPackage recommendedContents {}) (pkgs.callPackage recommendedContents {})
]; ];
image.rawConfig.Env = {
"PATH" = lib.mkDefault "/run/current-system/sw/bin:/bin:/usr/bin:/usr/local/bin";
};
}; };
} }

View file

@ -30,7 +30,6 @@ let
{ {
name = null; tag = null; contents = null; config = null; name = null; tag = null; contents = null; config = null;
created = null; extraCommands = null; maxLayers = null; created = null; extraCommands = null; maxLayers = null;
fakeRootCommands = null;
} }
args; args;
acceptedArgs = functionArgs dockerTools.streamLayeredImage; acceptedArgs = functionArgs dockerTools.streamLayeredImage;
@ -68,8 +67,6 @@ let
ln -s $i nix/var/nix/gcroots/docker/$(basename $i) ln -s $i nix/var/nix/gcroots/docker/$(basename $i)
done; done;
''; '';
fakeRootCommands = config.image.fakeRootCommands;
}; };
priorityIsDefault = option: option.highestPrio >= (lib.mkDefault true).priority; priorityIsDefault = option: option.highestPrio >= (lib.mkDefault true).priority;
@ -79,18 +76,18 @@ in
build.image = mkOption { build.image = mkOption {
type = nullOr package; type = nullOr package;
description = '' description = ''
Docker image derivation to be `docker load`-ed. Docker image derivation to be `docker load`ed.
''; '';
internal = true; internal = true;
}; };
build.imageName = mkOption { build.imageName = mkOption {
type = str; type = str;
description = "Derived from `build.image`"; description = "Derived from build.image";
internal = true; internal = true;
}; };
build.imageTag = mkOption { build.imageTag = mkOption {
type = str; type = str;
description = "Derived from `build.image`"; description = "Derived from build.image";
internal = true; internal = true;
}; };
image.nixBuild = mkOption { image.nixBuild = mkOption {
@ -123,22 +120,13 @@ in
Top level paths in the container. Top level paths in the container.
''; '';
}; };
image.fakeRootCommands = mkOption {
type = types.lines;
default = "";
description = ''
Commands that build the root of the container in the current working directory.
See [`dockerTools.buildLayeredImage`](https://nixos.org/manual/nixpkgs/stable/#ssec-pkgs-dockerTools-buildLayeredImage).
'';
};
image.includeStorePaths = mkOption { image.includeStorePaths = mkOption {
type = bool; type = bool;
default = true; default = true;
internal = true; internal = true;
description = '' description = ''
Include all referenced store paths. You generally want this in your Include all referenced store paths. You generally want this in your
image, unless you load store paths via some other means, like `useHostStore = true`; image, unless you load store paths via some other means, like useHostStore = true;
''; '';
}; };
image.rawConfig = mkOption { image.rawConfig = mkOption {
@ -152,8 +140,8 @@ in
Please use the specific `image` options instead. Please use the specific `image` options instead.
Run-time configuration of the container. A full list of the Run-time configuration of the container. A full list of the
options is available in the [Docker Image Specification options is available in the https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions[Docker Image Specification
v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions). v1.2.0].
''; '';
}; };
image.command = mkOption { image.command = mkOption {
@ -163,19 +151,17 @@ in
''; '';
}; };
}; };
config = lib.mkMerge [{ config = {
build.image = builtImage; build.image = builtImage;
build.imageName = config.build.image.imageName; build.imageName = config.build.image.imageName;
build.imageTag = build.imageTag =
if config.build.image.imageTag != "" if config.build.image.imageTag != ""
then config.build.image.imageTag then config.build.image.imageTag
else lib.head (lib.strings.splitString "-" (baseNameOf config.build.image.outPath)); 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.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 = [ service.tmpfs = [
"/run" # noexec is fine because exes should be symlinked from elsewhere anyway "/run" # noexec is fine because exes should be symlinked from elsewhere anyway
"/run/wrappers" # noexec breaks this intentionally "/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.stop_signal = "SIGRTMIN+3";
service.tty = true; service.tty = true;

View file

@ -31,7 +31,15 @@ in
}; };
# no caches, because no internet # no caches, because no internet
nix.settings.substituters = lib.mkForce []; nix.binaryCaches = lib.mkForce [];
# FIXME: Sandbox seems broken with current version of NixOS test
# w/ writable store. Error:
# machine# error: linking '/nix/store/7r8z2zvhwda85pgpdn5hzzz6hs1njklc-stdenv-linux.drv.chroot/nix/store/6v3y7s4q4wd16hsw393gjpxvcf9159bv-patch-shebangs.sh' to '/nix/store/6v3y7s4q4wd16hsw393gjpxvcf9159bv-patch-shebangs.sh': Operation not permitted
#
# There should be no reason why arion can't run without
# sandboxing, so please re-enable.
nix.useSandbox = false;
virtualisation.writableStore = true; virtualisation.writableStore = true;
# Switch to virtualisation.additionalPaths when dropping all NixOS <= 21.05. # Switch to virtualisation.additionalPaths when dropping all NixOS <= 21.05.
@ -45,7 +53,7 @@ in
pkgs.stdenv pkgs.stdenv
]; ];
virtualisation.memorySize = 2048; virtualisation.memorySize = 1024;
virtualisation.diskSize = 8000; virtualisation.diskSize = 8000;
}; };
testScript = '' testScript = ''

View file

@ -12,11 +12,10 @@
virtualisation.arion.backend = "docker"; virtualisation.arion.backend = "docker";
}; };
# Currently broken; kafka can't reach zookeeper nixosModuleWithPodman =
# nixosModuleWithPodman = import ./nixos-virtualization-arion-test/test.nix final {
# import ./nixos-virtualization-arion-test/test.nix final { virtualisation.arion.backend = "podman-socket";
# virtualisation.arion.backend = "podman-socket"; };
# };
testWithPodman = testWithPodman =
nixosTest (import ./arion-test { usePodman = true; pkgs = final; }); nixosTest (import ./arion-test { usePodman = true; pkgs = final; });

View file

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

9
update-options Executable file
View file

@ -0,0 +1,9 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p jq
set -eu -o pipefail
cd "$(dirname ${BASH_SOURCE[0]})"
doc_options="$(nix build .#doc-options --json | jq -r .[].outputs.out)"
cat "$doc_options" >docs/modules/ROOT/partials/NixOSOptions.adoc