{ config, lib, pkgs, utils, ... }: with lib; let name = "Ubiquiti mFi Controller"; cfg = config.services.mfi; stateDir = "/var/lib/mfi"; # XXX 2 runtime exceptions using jre8: JSPException on GET / ; can't initialize ./data/keystore on first run. cmd = "@${pkgs.jre7}/bin/java java -jar ${stateDir}/lib/ace.jar"; mountPoints = [ { what = "${pkgs.mfi}/dl"; where = "${stateDir}/dl"; } { what = "${pkgs.mfi}/lib"; where = "${stateDir}/lib"; } { what = "${pkgs.mongodb248}/bin"; where = "${stateDir}/bin"; } { what = "${cfg.dataDir}"; where = "${stateDir}/data"; } ]; systemdMountPoints = map (m: "${utils.escapeSystemdPath m.where}.mount") mountPoints; ports = [ 6080 6880 6443 6843 ]; in { options = { services.mfi = { enable = mkEnableOption name; openPorts = mkOption { type = types.bool; default = true; description = "Whether to open TCP ports ${concatMapStrings (a: "${toString a} ") ports}for the services."; }; dataDir = mkOption { type = types.str; default = "${stateDir}/data"; description = '' Where to store the database and other data. This directory will be bind-mounted to ${stateDir}/data as part of the service startup. ''; }; }; }; config = mkIf cfg.enable { networking.firewall.allowedTCPPorts = mkIf config.services.mfi.openPorts ports; users.users.mfi = { uid = config.ids.uids.mfi; description = "mFi controller daemon user"; home = "${stateDir}"; }; # We must create the binary directories as bind mounts instead of symlinks # This is because the controller resolves all symlinks to absolute paths # to be used as the working directory. systemd.mounts = map ({ what, where }: { bindsTo = [ "mfi.service" ]; partOf = [ "mfi.service" ]; unitConfig.RequiresMountsFor = stateDir; options = "bind"; what = what; where = where; }) mountPoints; systemd.services.mfi = { description = "mFi controller daemon"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ] ++ systemdMountPoints; partOf = systemdMountPoints; bindsTo = systemdMountPoints; unitConfig.RequiresMountsFor = stateDir; preStart = '' # Clear ./webapps each run. rm -rf "${stateDir}/webapps" mkdir -p "${stateDir}/webapps" ln -s "${pkgs.mfi}/webapps/ROOT.war" "${stateDir}/webapps" # Copy initial config only once. test -e "${stateDir}/conf" || cp -ar "${pkgs.mfi}/conf" "${stateDir}/conf" test -e "${stateDir}/data" || cp -ar "${pkgs.mfi}/data" "${stateDir}/data" # Fix Permissions. # (Bind-mounts cause errors; ignore exit codes) chown -fR mfi: "${stateDir}" || true chmod -fR u=rwX,go= "${stateDir}" || true ''; postStop = '' rm -rf "${stateDir}/webapps" ''; serviceConfig = { Type = "simple"; ExecStart = "${cmd} start"; ExecStop = "${cmd} stop"; User = "mfi"; PermissionsStartOnly = true; UMask = "0077"; WorkingDirectory = "${stateDir}"; }; }; }; }