Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create service abstraction layer (proposal, prototype) #5246

Closed
wants to merge 10 commits into from
3 changes: 3 additions & 0 deletions lib/lists.nix
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,7 @@ rec {
xs = unique (drop 1 list);
in [x] ++ remove x xs;

# Checks whether list contains element
contains = el: any (e: e == el);

}
25 changes: 25 additions & 0 deletions lib/modules.nix
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,31 @@ rec {
mkBefore = mkOrder 500;
mkAfter = mkOrder 1500;

# Convenient property used to transfer all definitions and their
# properties from one option to another. This property is useful for
# renaming options, and also for including properties from another module
# system, including sub-modules.
#
# { config, options, ... }:
#
# {
# # 'bar' might not always be defined in the current module-set.
# config.foo.enable = mkAliasDefinitions (options.bar.enable or {});
#
# # 'barbaz' has to be defined in the current module-set.
# config.foobar.paths = mkAliasDefinitions options.barbaz.paths;
# }
#
# Note, this is different than taking the value of the option and using it
# as a definition, as the new definition will not keep the mkOverride /
# mkDefault properties of the previous option.
#
mkAliasDefinitions = mkAliasAndWrapDefinitions id;
mkAliasAndWrapDefinitions = wrap: option:
mkMerge
(optional (isOption option && option.isDefined)
(wrap (mkMerge option.definitions)));


/* Compatibility. */
fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
Expand Down
17 changes: 17 additions & 0 deletions lib/options.nix
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ rec {
type = lib.types.bool;
};

# This option accept anything, but it does not produce any result. This
# is useful for sharing a module across different module sets without
# having to implement similar features as long as the value of the options
# are not expected.
mkSinkUndeclaredOptions = attrs: mkOption ({
internal = true;
visible = false;
default = false;
description = "Sink for option definitions.";
type = mkOptionType {
name = "sink";
check = x: true;
merge = loc: defs: false;
};
apply = x: throw "Option value is not readable because the option is not declared.";
} // attrs);

mergeDefaultOption = loc: defs:
let list = getValues defs; in
if length list == 1 then head list
Expand Down
9 changes: 2 additions & 7 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,12 @@
./services/databases/couchdb.nix
./services/databases/firebird.nix
./services/databases/hbase.nix
./services/databases/influxdb.nix
./services/databases/memcached.nix
./services/databases/monetdb.nix
./services/databases/mongodb.nix
./services/databases/mysql.nix
./services/databases/neo4j.nix
./services/databases/openldap.nix
./services/databases/opentsdb.nix
./services/databases/postgresql.nix
./services/databases/redis.nix
./services/databases/virtuoso.nix
./services/desktops/accountsservice.nix
Expand Down Expand Up @@ -153,7 +150,6 @@
./services/logging/klogd.nix
./services/logging/logcheck.nix
./services/logging/logrotate.nix
./services/logging/logstash.nix
./services/logging/rsyslogd.nix
./services/logging/syslogd.nix
./services/logging/syslog-ng.nix
Expand Down Expand Up @@ -295,7 +291,6 @@
./services/scheduling/chronos.nix
./services/scheduling/cron.nix
./services/scheduling/fcron.nix
./services/search/elasticsearch.nix
./services/search/solr.nix
./services/security/clamav.nix
./services/security/fail2ban.nix
Expand All @@ -321,7 +316,6 @@
./services/web-servers/lighttpd/cgit.nix
./services/web-servers/lighttpd/default.nix
./services/web-servers/lighttpd/gitweb.nix
./services/web-servers/nginx/default.nix
./services/web-servers/phpfpm.nix
./services/web-servers/tomcat.nix
./services/web-servers/varnish/default.nix
Expand Down Expand Up @@ -365,6 +359,7 @@
./system/boot/loader/raspberrypi/raspberrypi.nix
./system/boot/luksroot.nix
./system/boot/modprobe.nix
./system/boot/sal.nix
./system/boot/shutdown.nix
./system/boot/stage-1.nix
./system/boot/stage-2.nix
Expand Down Expand Up @@ -407,4 +402,4 @@
./virtualisation/parallels-guest.nix
./virtualisation/virtualbox-guest.nix
#./virtualisation/xen-dom0.nix
]
] ++ (import ../../services/module-list.nix)
4 changes: 2 additions & 2 deletions nixos/modules/rename.nix
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ let
apply = x: use (toOf config);
inherit visible;
});
}
{ config = setTo (mkMerge (if (fromOf options).isDefined then [ (define (mkMerge (fromOf options).definitions)) ] else []));

config = setTo (mkAliasAndWrapDefinitions define (fromOf options));
}
];

Expand Down
7 changes: 0 additions & 7 deletions nixos/modules/system/activation/activation-script.nix
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,6 @@ in
mv /usr/bin/.env.tmp /usr/bin/env # atomically replace /usr/bin/env
'';

system.activationScripts.tmpfs =
''
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devSize}" none /dev
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devShmSize}" none /dev/shm
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.runSize}" none /run
'';

};

}
109 changes: 109 additions & 0 deletions nixos/modules/system/boot/sal.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
{ config, lib, pkgs, ... }:

with lib;

let
cfg = config.sal;

in {
sal.systemName = "nixos";
sal.processManager.name = "systemd";
sal.processManager.supports = {
platforms = pkgs.systemd.meta.platforms;
fork = true;
syslog = true;
users = true;
privileged = true;
socketTypes = ["inet" "inet6" "unix"];
networkNamespaces = false;
};
sal.processManager.envNames = {
mainPid = "MAINPID";
};
sal.processManager.extraPath = [ pkgs.su ];

systemd.services = mapAttrs (n: s:
let
mkScript = cmd:
if cmd != null then
let c = if cmd.script != null then cmd.script else cmd.command;
in if !cmd.privileged && s.user != "" && c != "" then ''
su -s ${pkgs.stdenv.shell} ${s.user} <<'EOF'
${c}
EOF
'' else c
else "";

in mkMerge [
{
inherit (s) environment description path;

wantedBy = [ "multi-user.target" ];
after = mkMerge [
(map (n: "${n}.socket") s.requires.sockets)
(map (n: "${n}.service") s.requires.services)
(mkIf s.requires.networking ["network.target"])
(mkIf s.requires.displayManager ["display-manager.service"])
];
requires = config.systemd.services.${n}.after;
script = mkIf (s.start.script != null) s.start.script;
preStart = mkIf (s.preStart != null) (mkScript s.preStart);
postStart = mkIf (s.postStart != null) (mkScript s.postStart);
preStop = mkIf (s.stop != null) (mkScript s.stop);
reload = mkIf (s.reload != null) (mkScript s.reload);
postStop = mkIf (s.postStop != null) (mkScript s.postStop);
serviceConfig = {
PIDFile = s.pidFile;
Type = s.type;
KillSignal = "SIG" + (toUpper s.stop.stopSignal);
KillMode = s.stop.stopMode;
PermissionsStartOnly = true;
StartTimeout = s.start.timeout;
StopTimeout = s.stop.timeout;
User = s.user;
Group = s.group;
WorkingDirectory = s.workingDirectory;
Restart = let
restart = remove "changed" s.restart;
in
if length restart == 0 then "no" else
if length restart == 1 then head restart else
if contains "success" restart && contains "failure" restart
then "allways" else "no";
SuccessExitStatus =
concatMapStringsSep " " (c: toString c) s.exitCodes;
};

restartIfChanged = contains "changed" s.restart;
}
(mkIf (s.start.command != "") {
serviceConfig.ExecStart =
if s.start.processName != "" then
let cmd = head (splitString " " s.start.command);
in "@${cmd}${s.start.processName}${removePrefix cmd s.start.command}"
else s.start.command;
})
(mkIf (s.requires.dataContainers != []) {
preStart = mkBefore (
concatStrings (map (n:
let
dc = getAttr n config.sal.dataContainers;
in ''
mkdir -m ${dc.mode} -p ${dc.path}
${optionalString (dc.user != "") "chown -R ${dc.user} ${dc.path}"}
${optionalString (dc.group != "") "chgrp -R ${dc.group} ${dc.path}"}
''
) s.requires.dataContainers)
);
})
(attrByPath ["systemd"] {} s.extra)
]
) config.sal.services;

systemd.sockets = mapAttrs (n: s: {
inherit (s) description;

listenStreams = [ s.listen ];
}) config.resources.sockets;

}
7 changes: 7 additions & 0 deletions nixos/modules/system/boot/stage-2.nix
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ in

config = {

system.activationScripts.tmpfs =
''
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devSize}" none /dev
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devShmSize}" none /dev/shm
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.runSize}" none /run
'';

system.build.bootStage2 = bootStage2;

};
Expand Down
17 changes: 17 additions & 0 deletions nixos/tests/sal.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import ./make-test.nix {
name = "sal";

machine = { config, pkgs, ... }: {
services.mongodb.enable = true;
services.mongodb.extraConfig = ''
nojournal = true
'';
};

testScript =
''
startAll;
$machine->waitForUnit("elasticsearch.service");
$machine->shutdown;
'';
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ in
};

dataDir = mkOption {
default = "/var/db/influxdb";
default = config.resources.dataContainers.influxdb.path;
description = "Data directory for influxd data files.";
type = types.path;
};
Expand Down Expand Up @@ -210,34 +210,42 @@ in

config = mkIf config.services.influxdb.enable {

systemd.services.influxdb = {
sal.services.influxdb = {
inherit (cfg) user group;
description = "InfluxDB Server";
wantedBy = [ "multi-user.target" ];
after = [ "network-interfaces.target" ];
serviceConfig = {
ExecStart = ''${cfg.package}/bin/influxdb -config "${influxdbConfig}"'';
User = "${cfg.user}";
Group = "${cfg.group}";
PermissionsStartOnly = true;
};
preStart = ''
mkdir -m 0770 -p ${cfg.dataDir}
platforms = pkgs.influxdb.meta.platforms;

requires = {
networking = true;
dataContainers = ["influxdb"];
ports = [ cfg.apiPort cfg.adminPort ];
};

start.command = ''${cfg.package}/bin/influxdb -config "${influxdbConfig}"'';

preStart.script = ''
if [ "$(id -u)" = 0 ]; then chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}; fi
'';
postStart = mkBefore ''
postStart.script = mkBefore ''
until ${pkgs.curl}/bin/curl -s -o /dev/null 'http://${cfg.bindAddress}:${toString cfg.apiPort}/'; do
sleep 1;
done
'';
};

users.extraUsers = optional (cfg.user == "influxdb") {
resources.dataContainers.influxdb = {
type = "db";
mode = "0770";
inherit (cfg) user group;
};

users.extraUsers.influxdb = mkIf (cfg.user == "influxdb") {
name = "influxdb";
uid = config.ids.uids.influxdb;
description = "Influxdb daemon user";
};

users.extraGroups = optional (cfg.group == "influxdb") {
users.extraGroups.influxdb = mkIf (cfg.group == "influxdb") {
name = "influxdb";
gid = config.ids.gids.influxdb;
};
Expand Down
Loading