Add secrets options to service and composition
This commit is contained in:
parent
221bccd7f1
commit
a6878c0391
6 changed files with 128 additions and 1 deletions
|
@ -11,8 +11,36 @@
|
|||
*/
|
||||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
cfg = config.docker-compose;
|
||||
inherit (lib) mkOption optionalAttrs mapAttrs;
|
||||
inherit (lib.types) submodule attrsOf nullOr str path bool;
|
||||
evalService = name: modules: pkgs.callPackage ../../eval-service.nix {} { inherit name modules; inherit (config) host; };
|
||||
|
||||
dockerComposeRef = fragment:
|
||||
''See <link xlink:href="https://docs.docker.com/compose/compose-file/#${fragment}">Docker Compose#${fragment}</link>'';
|
||||
|
||||
secretType = submodule {
|
||||
options = {
|
||||
file = mkOption {
|
||||
type = either path str;
|
||||
description = ''
|
||||
Sets the secret's value to this file.
|
||||
|
||||
${dockerComposeRef "secrets"}
|
||||
'';
|
||||
};
|
||||
external = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether the value of this secret is set via other means.
|
||||
|
||||
${dockerComposeRef "secrets"}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
options = {
|
||||
|
@ -42,6 +70,11 @@ in
|
|||
description = "Attribute set of evaluated service configurations.";
|
||||
readOnly = true;
|
||||
};
|
||||
docker-compose.secrets = lib.mkOption {
|
||||
type = attrsOf secretType;
|
||||
description = dockerComposeRef "secrets";
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
build.dockerComposeYaml = pkgs.writeText "docker-compose.yaml" config.build.dockerComposeYamlText;
|
||||
|
@ -52,6 +85,13 @@ in
|
|||
version = "3.4";
|
||||
services = lib.mapAttrs (k: c: c.config.build.service) config.docker-compose.evaluatedServices;
|
||||
x-arion = config.docker-compose.extended;
|
||||
} // optionalAttrs (cfg.secrets != {}) {
|
||||
secrets = mapAttrs (_k: s: optionalAttrs (s.external != false) {
|
||||
inherit (s) external;
|
||||
} // optionalAttrs (s.file != null) {
|
||||
file = toString s.file;
|
||||
}
|
||||
) cfg.secrets;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
{ pkgs, lib, config, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (lib) mkOption types mapAttrs mapAttrsToList;
|
||||
inherit (types) listOf nullOr attrsOf str either int bool;
|
||||
|
||||
cfg = config.service;
|
||||
|
||||
link = url: text:
|
||||
''<link xlink:href="${url}">${text}</link>'';
|
||||
dockerComposeRef = fragment:
|
||||
|
@ -23,6 +25,48 @@ let
|
|||
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);
|
||||
|
||||
serviceSecretType = types.submodule {
|
||||
options = {
|
||||
source = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = dockerComposeRef "secrets";
|
||||
};
|
||||
uid = mkOption {
|
||||
type = nullOr (either str int);
|
||||
default = null;
|
||||
description = dockerComposeRef "secrets";
|
||||
};
|
||||
gid = mkOption {
|
||||
type = nullOr (either str int);
|
||||
default = null;
|
||||
description = dockerComposeRef "secrets";
|
||||
};
|
||||
mode = mkOption {
|
||||
type = nullOr str;
|
||||
# default = "0444";
|
||||
default = null;
|
||||
description = ''
|
||||
The default value of is usually 0444. This option may not be supported
|
||||
when not deploying to a Swarm.
|
||||
|
||||
${dockerComposeRef "secrets"}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
secrets = mapAttrsToList (k: s: {
|
||||
target = k;
|
||||
} //lib.optionalAttrs (s.source != null) {
|
||||
inherit (s) source;
|
||||
} // lib.optionalAttrs (s.uid != null) {
|
||||
inherit (s) uid;
|
||||
} // lib.optionalAttrs (s.gid != null) {
|
||||
inherit (s) gid;
|
||||
} // lib.optionalAttrs (s.mode != null) {
|
||||
inherit (s) mode;
|
||||
}) cfg.secrets;
|
||||
|
||||
in
|
||||
{
|
||||
options = {
|
||||
|
@ -197,6 +241,19 @@ in
|
|||
}
|
||||
'';
|
||||
};
|
||||
service.secrets = mkOption {
|
||||
type = attrsOf serviceSecretType;
|
||||
default = {};
|
||||
description = dockerComposeRef "secrets";
|
||||
example = {
|
||||
redis_secret = {
|
||||
source = "web_cache_redis_secret";
|
||||
uid = 123;
|
||||
gid = 123;
|
||||
mode = "0440";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config.build.service = {
|
||||
|
@ -242,6 +299,8 @@ in
|
|||
inherit (config.service) restart;
|
||||
} // lib.optionalAttrs (config.service.stop_signal != null) {
|
||||
inherit (config.service) stop_signal;
|
||||
} // lib.optionalAttrs (secrets != null) {
|
||||
inherit secrets;
|
||||
} // lib.optionalAttrs (config.service.tmpfs != []) {
|
||||
inherit (config.service) tmpfs;
|
||||
} // lib.optionalAttrs (config.service.tty != null) {
|
||||
|
|
|
@ -63,5 +63,13 @@ in
|
|||
$machine->succeed("cd work && NIX_PATH=nixpkgs='${pkgs.path}' arion down && rm -rf work");
|
||||
$machine->waitUntilFails("curl localhost:8000");
|
||||
};
|
||||
|
||||
subtest "secrets", sub {
|
||||
$machine->succeed("cp -r ${../testcases/secrets} work && cd work && NIX_PATH=nixpkgs='${pkgs.path}' arion up -d");
|
||||
$machine->waitUntilSucceeds("curl localhost:8000");
|
||||
$machine->succeed("test qux = \"$(curl localhost:8000)\"");
|
||||
$machine->succeed("cd work && NIX_PATH=nixpkgs='${pkgs.path}' arion down && rm -rf work");
|
||||
$machine->waitUntilFails("curl localhost:8000");
|
||||
};
|
||||
'';
|
||||
}
|
||||
|
|
17
tests/testcases/secrets/arion-compose.nix
Normal file
17
tests/testcases/secrets/arion-compose.nix
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
docker-compose.services.webserver = { pkgs, ... }: {
|
||||
nixos.useSystemd = true;
|
||||
nixos.configuration.boot.tmpOnTmpfs = true;
|
||||
nixos.configuration.services.nginx.enable = true;
|
||||
|
||||
# Please don't do this
|
||||
nixos.configuration.services.nginx.virtualHosts.localhost.root = "/run/secrets";
|
||||
|
||||
service.useHostStore = true;
|
||||
service.ports = [
|
||||
"8000:80" # host:container
|
||||
];
|
||||
service.secrets."foo.txt".source = "foo";
|
||||
};
|
||||
docker-compose.secrets.foo.file = ./foo.key;
|
||||
}
|
2
tests/testcases/secrets/arion-pkgs.nix
Normal file
2
tests/testcases/secrets/arion-pkgs.nix
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Instead of pinning Nixpkgs, we can opt to use the one in NIX_PATH
|
||||
import <nixpkgs> {}
|
1
tests/testcases/secrets/foo.key
Normal file
1
tests/testcases/secrets/foo.key
Normal file
|
@ -0,0 +1 @@
|
|||
qux
|
Loading…
Reference in a new issue