3
0
Fork 0
forked from mirrors/nixpkgs

Merge pull request #9280 from oxij/better-smartd

nixos: make services.smartd much more helpful
This commit is contained in:
Arseniy Seroka 2015-08-17 02:11:43 +03:00
commit 7ca6742acc
2 changed files with 166 additions and 48 deletions

View file

@ -98,6 +98,9 @@ in zipModules ([]
++ obsolete [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ] ++ obsolete [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ]
++ obsolete [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ] ++ obsolete [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ]
# smartd
++ obsolete [ "services" "smartd" "deviceOpts" ] [ "services" "smartd" "defaults" "monitored" ]
# OpenSSH # OpenSSH
++ obsolete [ "services" "sshd" "ports" ] [ "services" "openssh" "ports" ] ++ obsolete [ "services" "sshd" "ports" ] [ "services" "openssh" "ports" ]
++ alias [ "services" "sshd" "enable" ] [ "services" "openssh" "enable" ] ++ alias [ "services" "sshd" "enable" ] [ "services" "openssh" "enable" ]

View file

@ -4,8 +4,66 @@ with lib;
let let
host = config.networking.hostName or "unknown"
+ optionalString (config.networking.domain != null) ".${config.networking.domain}";
cfg = config.services.smartd; cfg = config.services.smartd;
nm = cfg.notifications.mail;
nw = cfg.notifications.wall;
nx = cfg.notifications.x11;
smartdNotify = pkgs.writeScript "smartd-notify.sh" ''
#! ${pkgs.stdenv.shell}
${optionalString nm.enable ''
{
cat << EOF
From: smartd on ${host} <root>
To: undisclosed-recipients:;
Subject: SMART error on $SMARTD_DEVICESTRING: $SMARTD_FAILTYPE
$SMARTD_FULLMESSAGE
EOF
${pkgs.smartmontools}/sbin/smartctl -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE"
} | ${nm.mailer} -i "${nm.recipient}"
''}
${optionalString nw.enable ''
{
cat << EOF
Problem detected with disk: $SMARTD_DEVICESTRING
Warning message from smartd is:
$SMARTD_MESSAGE
EOF
} | ${pkgs.utillinux}/bin/wall 2>/dev/null
''}
${optionalString nx.enable ''
export DISPLAY=${nx.display}
{
cat << EOF
Problem detected with disk: $SMARTD_DEVICESTRING
Warning message from smartd is:
$SMARTD_FULLMESSAGE
EOF
} | ${pkgs.xorg.xmessage}/bin/xmessage -file - 2>/dev/null &
''}
'';
notifyOpts = optionalString (nm.enable || nw.enable || nx.enable)
("-m <nomailer> -M exec ${smartdNotify} " + optionalString cfg.notifications.test "-M test ");
smartdConf = pkgs.writeText "smartd.conf" ''
# Autogenerated smartd startup config file
DEFAULT ${notifyOpts}${cfg.defaults.monitored}
${concatMapStringsSep "\n" (d: "${d.device} ${d.options}") cfg.devices}
${optionalString cfg.autodetect
"DEVICESCAN ${notifyOpts}${cfg.defaults.autodetected}"}
'';
smartdOpts = { name, ... }: { smartdOpts = { name, ... }: {
options = { options = {
@ -22,34 +80,11 @@ let
type = types.separatedString " "; type = types.separatedString " ";
description = "Options that determine how smartd monitors the device."; description = "Options that determine how smartd monitors the device.";
}; };
}; };
}; };
smartdMail = pkgs.writeScript "smartdmail.sh" ''
#! ${pkgs.stdenv.shell}
TMPNAM=/tmp/smartd-message.$$.tmp
if test -n "$SMARTD_ADDRESS"; then
echo >"$TMPNAM" "From: smartd <root>"
echo >>"$TMPNAM" 'To: undisclosed-recipients:;'
echo >>"$TMPNAM" "Subject: $SMARTD_SUBJECT"
echo >>"$TMPNAM"
echo >>"$TMPNAM" "Failure on $SMARTD_DEVICESTRING: $SMARTD_FAILTYPE"
echo >>"$TMPNAM"
cat >>"$TMPNAM"
${pkgs.smartmontools}/sbin/smartctl >>"$TMPNAM" -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE"
/var/setuid-wrappers/sendmail <"$TMPNAM" -f "$SENDER" -i "$SMARTD_ADDRESS"
fi
'';
smartdConf = pkgs.writeText "smartd.conf" (concatMapStrings (device:
''
${device.device} -a -m root -M exec ${smartdMail} ${device.options} ${cfg.deviceOpts}
''
) cfg.devices);
smartdFlags = if (cfg.devices == []) then "" else "--configfile=${smartdConf}";
in in
{ {
@ -59,26 +94,104 @@ in
services.smartd = { services.smartd = {
enable = mkOption { enable = mkEnableOption "smartd daemon from <literal>smartmontools</literal> package";
default = false;
autodetect = mkOption {
default = true;
type = types.bool; type = types.bool;
example = true;
description = '' description = ''
Run smartd from the smartmontools package. Note that e-mail Whenever smartd should monitor all devices connected to the
notifications will not be enabled unless you configure the list of machine at the time it's being started (the default).
devices with <varname>services.smartd.devices</varname> as well.
Set to false to monitor the devices listed in
<option>services.smartd.devices</option> only.
''; '';
}; };
deviceOpts = mkOption { notifications = {
default = "";
type = types.string; mail = {
example = "-o on -s (S/../.././02|L/../../7/04)"; enable = mkOption {
description = '' default = config.services.mail.sendmailSetuidWrapper != null;
Additional options for each device that is monitored. The example type = types.bool;
turns on SMART Automatic Offline Testing on startup, and schedules short description = "Whenever to send e-mail notifications.";
self-tests daily, and long self-tests weekly. };
'';
recipient = mkOption {
default = "root";
type = types.string;
description = "Recipient of the notification messages.";
};
mailer = mkOption {
default = "/var/setuid-wrappers/sendmail";
type = types.path;
description = ''
Sendmail-compatible binary to be used to send the messages.
You should probably enable
<option>services.postfix</option> or some other MTA for
this to work.
'';
};
};
wall = {
enable = mkOption {
default = true;
type = types.bool;
description = "Whenever to send wall notifications to all users.";
};
};
x11 = {
enable = mkOption {
default = config.services.xserver.enable;
type = types.bool;
description = "Whenever to send X11 xmessage notifications.";
};
display = mkOption {
default = ":${toString config.services.xserver.display}";
type = types.string;
description = "DISPLAY to send X11 notifications to.";
};
};
test = mkOption {
default = false;
type = types.bool;
description = "Whenever to send a test notification on startup.";
};
};
defaults = {
monitored = mkOption {
default = "-a";
type = types.separatedString " ";
example = "-a -o on -s (S/../.././02|L/../../7/04)";
description = ''
Common default options for explicitly monitored (listed in
<option>services.smartd.devices</option>) devices.
The default value turns on monitoring of all the things (see
<literal>man 5 smartd.conf</literal>).
The example also turns on SMART Automatic Offline Testing on
startup, and schedules short self-tests daily, and long
self-tests weekly.
'';
};
autodetected = mkOption {
default = cfg.defaults.monitored;
type = types.separatedString " ";
description = ''
Like <option>services.smartd.defaults.monitored</option>, but for the
autodetected devices.
'';
};
}; };
devices = mkOption { devices = mkOption {
@ -86,14 +199,9 @@ in
example = [ { device = "/dev/sda"; } { device = "/dev/sdb"; options = "-d sat"; } ]; example = [ { device = "/dev/sda"; } { device = "/dev/sdb"; options = "-d sat"; } ];
type = types.listOf types.optionSet; type = types.listOf types.optionSet;
options = [ smartdOpts ]; options = [ smartdOpts ];
description = '' description = "List of devices to monitor.";
List of devices to monitor. By default -- if this list is empty --, };
smartd will monitor all devices connected to the machine at the time
it's being run. Configuring this option has the added benefit of
enabling e-mail notifications to "root" every time smartd detects an
error.
'';
};
}; };
}; };
@ -103,12 +211,19 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [ {
assertion = cfg.autodetect || cfg.devices != [];
message = "smartd can't run with both disabled autodetect and an empty list of devices to monitor.";
} ];
systemd.services.smartd = { systemd.services.smartd = {
description = "S.M.A.R.T. Daemon"; description = "S.M.A.R.T. Daemon";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd --no-fork ${smartdFlags}"; path = [ pkgs.nettools ]; # for hostname and dnsdomanname calls in smartd
serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd --no-fork --configfile=${smartdConf}";
}; };
}; };