Skip to content

Commit

Permalink
Merge #2384
Browse files Browse the repository at this point in the history
2384: Nixos multi instances r=disassembler a=jbgi



Co-authored-by: Jean-Baptiste Giraudeau <jean-baptiste.giraudeau@iohk.io>
  • Loading branch information
iohk-bors[bot] and jbgi committed Feb 19, 2021
2 parents 400f6d7 + 91aa09d commit e877313
Showing 1 changed file with 102 additions and 59 deletions.
161 changes: 102 additions & 59 deletions nix/nixos/cardano-node-service.nix
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,24 @@ in {
description = ''Use systemd socket activation'';
};

extraServiceConfig = mkOption {
# activate type for nixos-21.03:
# type = types.functionTo (types.listOf types.attrs);
default = n: i: {};
description = ''
Extra systemd service config, given service name and instance index.
'';
};

extraSocketConfig = mkOption {
# activate type for nixos-21.03:
# type = types.functionTo (types.listOf types.attrs);
default = n: i: {};
description = ''
Extra systemd socket config, given socket name and instance index.
'';
};

dbPrefix = mkOption {
type = types.str;
default = "db-${cfg.environment}";
Expand Down Expand Up @@ -408,63 +426,88 @@ in {
stateDirBase = "/var/lib/";
genInstanceConf = f: listToAttrs (if cfg.instances > 1 && !cfg.instanced
then genList (i: let n = "${systemdServiceName}-${toString i}"; in nameValuePair n (f n i)) cfg.instances
else [ (nameValuePair systemdServiceName (f systemdServiceName 0)) ]); in {
users.groups.cardano-node.gid = 10016;
users.users.cardano-node = {
description = "cardano-node node daemon user";
uid = 10016;
group = "cardano-node";
};

## TODO: use http://hackage.haskell.org/package/systemd for:
## 1. only declaring success after we perform meaningful init (local state recovery)
## 2. heartbeat & watchdog functionality
systemd.services = genInstanceConf (n: i: {
description = "cardano-node node ${toString i} service";
after = [ "network-online.target" ]
++ lib.optional cfg.systemdSocketActivation "${n}.socket";
requires = lib.mkIf cfg.systemdSocketActivation [ "${n}.socket" ];
wants = [ "network-online.target" ];
script = mkScript cfg i;
serviceConfig = {
User = "cardano-node";
Group = "cardano-node";
Restart = "always";
RuntimeDirectory = cfg.runtimeDir;
WorkingDirectory = cfg.stateDir;
# This assumes /var/lib/ is a prefix of cfg.stateDir.
# This is checked as an assertion below.
StateDirectory = lib.removePrefix stateDirBase cfg.stateDir;
NonBlocking = lib.mkIf cfg.systemdSocketActivation true;
# time to sleep before restarting a service
RestartSec = 1;
};
} // optionalAttrs (!cfg.instanced) {
wantedBy = [ "multi-user.target" ];
});

systemd.sockets = genInstanceConf (n: i: lib.mkIf cfg.systemdSocketActivation {
description = "Socket of the ${n} service.";
wantedBy = [ "sockets.target" ];
socketConfig = {
ListenStream = [ "${cfg.hostAddr}:${toString cfg.port}" ]
++ [(if (i == 0) then cfg.socketPath else "${runtimeDir}/node-${toString i}.socket")];
ReusePort = "yes";
SocketMode = "0660";
SocketUser = "cardano-node";
SocketGroup = "cardano-node";
};
});

assertions = [
{
assertion = lib.hasPrefix stateDirBase cfg.stateDir;
message = "The option services.cardano-node.stateDir should have ${stateDirBase} as a prefix!";
}
{
assertion = (cfg.kesKey == null) == (cfg.vrfKey == null) && (cfg.kesKey == null) == (cfg.operationalCertificate == null);
message = "Shelley Era: all of three [operationalCertificate kesKey vrfKey] options must be defined (or none of them).";
}
];
});
else [ (nameValuePair systemdServiceName (f systemdServiceName 0)) ]); in lib.mkMerge [
{
users.groups.cardano-node.gid = 10016;
users.users.cardano-node = {
description = "cardano-node node daemon user";
uid = 10016;
group = "cardano-node";
};

## TODO: use http://hackage.haskell.org/package/systemd for:
## 1. only declaring success after we perform meaningful init (local state recovery)
## 2. heartbeat & watchdog functionality
systemd.services = genInstanceConf (n: i: recursiveUpdate {
description = "cardano-node node ${toString i} service";
after = [ "network-online.target" ]
++ (optional cfg.systemdSocketActivation "${n}.socket")
++ (optional (cfg.instances > 1) "cardano-node.service");
requires = optional cfg.systemdSocketActivation "${n}.socket"
++ (optional (cfg.instances > 1) "cardano-node.service");
wants = [ "network-online.target" ];
wantedBy = mkIf (!cfg.instanced) [ "multi-user.target" ];
partOf = mkIf (cfg.instances > 1) ["cardano-node.service"];
script = mkScript cfg i;
serviceConfig = {
User = "cardano-node";
Group = "cardano-node";
Restart = "always";
RuntimeDirectory = cfg.runtimeDir;
WorkingDirectory = cfg.stateDir;
# This assumes /var/lib/ is a prefix of cfg.stateDir.
# This is checked as an assertion below.
StateDirectory = lib.removePrefix stateDirBase cfg.stateDir;
NonBlocking = lib.mkIf cfg.systemdSocketActivation true;
# time to sleep before restarting a service
RestartSec = 1;
KillSignal = "SIGINT";
};
} (cfg.extraServiceConfig n i));

systemd.sockets = genInstanceConf (n: i: lib.mkIf cfg.systemdSocketActivation (recursiveUpdate {
description = "Socket of the ${n} service.";
wantedBy = [ "sockets.target" ];
partOf = [ "${n}.service" ];
socketConfig = {
ListenStream = [ "${cfg.hostAddr}:${toString cfg.port}" ]
++ [(if (i == 0) then cfg.socketPath else "${runtimeDir}/node-${toString i}.socket")];
ReusePort = "yes";
SocketMode = "0660";
SocketUser = "cardano-node";
SocketGroup = "cardano-node";
};
} (cfg.extraSocketConfig n i)));
}
{
# oneshot service start allows to easily control all instances at once.
systemd.services.cardano-node = lib.mkIf (cfg.instances > 1) {
description = "Control all ${toString cfg.instances} at once.";
enable = true;
wants = genList (i: "cardano-node-${toString i}.service") cfg.instances;
serviceConfig = {
Type = "oneshot";
RemainAfterExit = "yes";
User = "cardano-node";
Group = "cardano-node";
ExecStart = "${pkgs.coreutils}/bin/echo Starting ${toString cfg.instances} cardano-node instances";
RuntimeDirectory = cfg.runtimeDir;
WorkingDirectory = cfg.stateDir;
StateDirectory = lib.removePrefix stateDirBase cfg.stateDir;
};
};
}
{
assertions = [
{
assertion = lib.hasPrefix stateDirBase cfg.stateDir;
message = "The option services.cardano-node.stateDir should have ${stateDirBase} as a prefix!";
}
{
assertion = (cfg.kesKey == null) == (cfg.vrfKey == null) && (cfg.kesKey == null) == (cfg.operationalCertificate == null);
message = "Shelley Era: all of three [operationalCertificate kesKey vrfKey] options must be defined (or none of them).";
}
];
}
]);
}

0 comments on commit e877313

Please sign in to comment.