{ config, lib, pkgs, ... }:
with lib;
let
targetOpts = { name, config, ... }: {
options = {
name = mkOption {
type = types.str;
};
backingStore = mkOption {
type = types.str;
};
index = mkOption {
type = types.int;
description = "the index of the target, must be unique within the server";
};
};
config = {
name = mkDefault name;
};
};
makeService = target: {
name = target.name;
value = {
description = target.name+" auto-starter";
wantedBy = [ "basic.target" ];
partOf = [ "tgtd.service" ];
script = ''
${pkgs.tgt}/bin/tgtadm --lld iscsi --op new --mode target --tid ${builtins.toString target.index} -T ${target.name}
${pkgs.tgt}/bin/tgtadm --lld iscsi --op new --mode logicalunit --tid ${builtins.toString target.index} --lun 1 -b ${target.backingStore}
${pkgs.tgt}/bin/tgtadm --lld iscsi --op bind --mode target --tid ${builtins.toString target.index} -I ALL # gives everybody access
'';
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "${pkgs.tgt}/bin/tgtadm --lld iscsi --op delete --mode target --tid ${builtins.toString target.index}";
};
};
};
in
{
options = {
services.tgtd = {
enable = mkOption {
type = types.bool;
default = false;
description = "enable tgtd running on startup";
};
targets = mkOption {
default = [];
type = types.loaOf types.optionSet;
options = targetOpts;
};
};
};
config = let
LUNs = builtins.listToAttrs (map makeService (attrValues config.services.tgtd.targets));
tgtd = {
description = "tgtd daemon";
wantedBy = [ "basic.target" ];
serviceConfig = {
ExecStart = "${pkgs.tgt}/bin/tgtd -f --iscsi nop_interval=30 --iscsi nop_count=10";
ExecStop = "${pkgs.coreutils}/bin/sleep 30 ; ${pkgs.tgt}/bin/tgtadm --op delete --mode system";
KillMode = "process";
Restart = "on-success";
};
};
in
mkIf config.services.tgtd.enable {
systemd.services = LUNs // { tgtd = tgtd; };
};
}
[root@nas:~]# cat /etc/nixos/nixcfg/nas.nix
{ ... }:
let
keys = import ./keys.nix;
in
{
...
services = {
tgtd = {
enable = true;
targets = {
"iqn.2016-01.laptop-root" = { backingStore = "/dev/naspool/laptop-root"; index = 1; };
"iqn.2016-02.windows-extra" = { backingStore = "/dev/naspool/windows-extra"; index = 2; };
};
};
};
}
[root@nas:~]# nix-repl '<nixos>'
Welcome to Nix version 1.11.2. Type :? for help.
Loading ‘<nixos>’...
Added 6 variables.
nix-repl> config.systemd.services."iqn.2016-01.laptop-root".description
"iqn.2016-01.laptop-root auto-starter"
nix-repl> config.systemd.services."iqn.2016-01.laptop-root".serviceConfig.ExecStart
"/nix/store/r5jddxlql2hkahaphl06yqclh0ahp5zi-unit-script/bin/iqn.2016-01.laptop-root-start "
nix-repl> config.systemd.services."iqn.2016-01.laptop-root".script
"/nix/store/vkz0bkpki3ha7p5h0b9wav35lnn4aj4v-tgt-1.0.60/bin/tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.2016-01.laptop-root\n/nix/store/vkz0bkpki3ha7p5h0b9wav35lnn4aj4v-tgt-1.0.60/bin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun 1 -b /dev/naspool/laptop-root\n/nix/store/vkz0bkpki3ha7p5h0b9wav35lnn4aj4v-tgt-1.0.60/bin/tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL # gives everybody access\n"
{ lib, config, pkgs, ... }:
with lib;
let
cfg = config.services.motion;
camera_list = builtins.attrValues cfg.cameras;
final_config = concatStringsSep "\n" ([ cfg.config ] ++ (map (cam: "thread ${cam}") thread_config_files));
config_file = pkgs.writeText "motion.conf" final_config;
thread_configs = (listToAttrs (map (cam: {
name = "motion/${cam.name}.conf";
value = { text = cfg.camera_common_config + "\n" + cam.config;};
}) camera_list));
thread_config_files = map (cam: pkgs.writeText "thread-${cam.name}.conf" (cfg.camera_common_config + "\n" + cam.config)) camera_list;
camera_options = { name, config, ... }:
{
options = {
name = mkOption { type = types.str; };
config = mkOption { type = types.str; };
};
config = {
name = mkDefault name;
};
};
in
{
options = {
services.motion = {
enable = mkEnableOption "motion";
config = mkOption {
type = types.str;
default = "";
description = "the raw contents of motion.conf";
};
cameras = mkOption {
type = types.loaOf types.optionSet;
options = camera_options;
default = [];
};
camera_common_config = mkOption {
type = types.str;
default = "";
description = "lines inserted into every thread file";
};
};
};
config = mkIf config.services.motion.enable {
systemd.services.motion = {
description = builtins.trace "reading description" "Motion daemon";
wantedBy = [ "basic.target" ];
serviceConfig = {
ExecStart = "${pkgs.motion}/bin/motion -c ${config_file}";
KillMode = "process";
Restart = "always";
User = "motion";
};
};
environment.etc = {
"motion.conf".text = final_config;
} // thread_configs;
users.users = {
motion = {
uid = 1012;
};
};
};
}
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.boot.initrd.iscsi;
fileSystems = attrValues config.fileSystems ++ config.swapDevices;
iscsiDevs = filter (dev: dev.iscsi.enable) fileSystems;
anyiscsi = fold (j: v: v || j.iscsi.enable) false iscsiDevs;
iscsiOptions = {
iscsi = {
enable = mkOption { default = false; type = types.bool; description = "The block device is backed by iscsi, adds this device as a initrd entry"; };
host = mkOption { example = "192.168.2.61"; type = types.string; description = "the iscsi target"; };
lun = mkOption { example = "iqn.2015-01.com.example:san.img"; type = types.string; description = "the LUN to connect"; };
};
};
in
{
options = {
fileSystems = mkOption {
options = [ iscsiOptions ];
};
swapDevices = mkOption {
options = [ iscsiOptions ];
};
boot.initrd.iscsi = {
initiatorName = mkOption {
example = "iqn.2015-09.com.example:3255a7223b2";
type = types.string;
description = "the initiator name used when connecting";
};
netDev = mkOption {
example = "eth0";
type = types.string;
description = "the network device the initrd will setup for iscsi";
};
}; # iscsi
}; # options
config = mkIf anyiscsi (
let
ipAddress = config.networking.interfaces.${cfg.netDev}.ipAddress;
prefixLength = config.networking.interfaces.${cfg.netDev}.prefixLength;
defaultGateway = config.networking.defaultGateway;
in
{
boot.initrd = {
kernelModules = [ "iscsi_tcp" ];
availableKernelModules = [ "crc32c" ];
preLVMCommands = ''
export PATH=$PATH:${pkgs.openiscsi.iscsistart}/bin/
ip link set ${cfg.netDev} up
ip addr add ${ipAddress}/${toString prefixLength} dev ${cfg.netDev}
# todo, make this optional
ip route add via ${defaultGateway} dev ${cfg.netDev}
'' + concatMapStrings (dev: "iscsistart -t ${dev.iscsi.lun} -a ${dev.iscsi.host} -i ${config.boot.initrd.iscsi.initiatorName} -g 0\n") iscsiDevs;
}; # initrd
}); # config
}