blob: 20e2a5dde77311103aa2ab71c4ff53a4f54c3d1e (
plain) (
tree)
|
|
{ lib, config, ... }:
with lib;
let
cfg = config.services.phpApplication;
cfgByEnv = lists.groupBy (x: x.websiteEnv) (builtins.attrValues cfg.apps);
in
{
options = with types; {
services.phpApplication.apps = mkOption {
default = {};
description = ''
php applications to define
'';
type = attrsOf (submodule {
options = {
varDir = mkOption {
type = nullOr path;
description = ''
Path to application’s vardir.
'';
};
varDirPaths = mkOption {
type = attrsOf str;
default = {};
description = ''
Map of additional folders => mode to create under varDir
'';
};
mode = mkOption {
type = str;
default = "0700";
description = ''
Mode to apply to the vardir
'';
};
phpSession = mkOption {
type = bool;
default = true;
description = "Handle phpsession files separately in vardir";
};
phpListen = mkOption {
type = nullOr str;
default = null;
description = "Name of the socket to listen to. Defaults to app name if null";
};
phpPool = mkOption {
type = attrsOf str;
default = {};
description = "Pool configuration to append";
};
phpEnv = mkOption {
type = attrsOf str;
default = {};
description = "Pool environment to append";
};
phpOptions = mkOption {
type = lines;
default = "";
description = "php configuration to append";
};
phpOpenbasedir = mkOption {
type = listOf path;
default = [];
description = ''
paths to add to php open_basedir configuration in addition to app and vardir
'';
};
phpWatchFiles = mkOption {
type = listOf path;
default = [];
description = ''
Path to other files to watch to trigger preStart scripts
'';
};
websiteEnv = mkOption {
type = str;
description = ''
website instance name to use
'';
};
httpdUser = mkOption {
type = str;
default = config.services.httpd.user;
description = ''
httpd user to run the prestart scripts as.
'';
};
httpdGroup = mkOption {
type = str;
default = config.services.httpd.group;
description = ''
httpd group to run the prestart scripts as.
'';
};
httpdWatchFiles = mkOption {
type = listOf path;
default = [];
description = ''
Path to other files to watch to trigger httpd reload
'';
};
app = mkOption {
type = path;
description = ''
Path to application root
'';
};
webappName = mkOption {
type = nullOr str;
default = null;
description = ''
Alias name for the app, to be used in services.websites.webappDirs
'';
};
webRoot = mkOption {
type = nullOr path;
description = ''
Path to the web root path of the application. May differ from the application itself (usually a subdirectory)
'';
};
preStartActions = mkOption {
type = listOf str;
default = [];
description = ''
List of actions to run as apache user at preStart when
whatchFiles or app dir changed.
'';
};
serviceDeps = mkOption {
type = listOf str;
default = [];
description = ''
List of systemd services this application depends on
'';
};
};
});
};
# Read-only variables
services.phpApplication.phpListenPaths = mkOption {
type = attrsOf path;
default = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
name config.services.phpfpm.pools."${name}".socket
) cfg.apps;
readOnly = true;
description = ''
Full paths to listen for php
'';
};
services.phpApplication.webappDirs = mkOption {
type = attrsOf path;
default = attrsets.filterAttrs (n: v: builtins.hasAttr n cfg.apps) config.services.websites.webappDirsPaths;
readOnly = true;
description = ''
Stable name webapp dirs for httpd
'';
};
};
config = {
services.websites.env = attrsets.mapAttrs' (name: cfgs: attrsets.nameValuePair
name {
modules = [ "proxy_fcgi" ];
watchPaths = builtins.concatLists (map (c: c.httpdWatchFiles) cfgs);
}
) cfgByEnv;
services.phpfpm.pools = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
name {
user = icfg.httpdUser;
group = icfg.httpdUser;
settings = {
"listen.owner" = icfg.httpdUser;
"listen.group" = icfg.httpdGroup;
"php_admin_value[open_basedir]" = builtins.concatStringsSep ":" ([icfg.app icfg.varDir] ++ icfg.phpWatchFiles ++ icfg.phpOpenbasedir);
}
// optionalAttrs (icfg.phpSession) { "php_admin_value[session.save_path]" = "${icfg.varDir}/phpSessions"; }
// icfg.phpPool;
phpOptions = config.services.phpfpm.phpOptions + icfg.phpOptions;
inherit (icfg) phpEnv;
}
) cfg.apps;
services.websites.webappDirs = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
(if icfg.webappName == null then name else icfg.webappName) icfg.webRoot
) (attrsets.filterAttrs (n: v: !isNull v.webRoot) cfg.apps);
services.filesWatcher = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
"phpfpm-${name}" {
restart = true;
paths = icfg.phpWatchFiles;
}
) (attrsets.filterAttrs (n: v: builtins.length v.phpWatchFiles > 0) cfg.apps);
systemd.services = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
"phpfpm-${name}" {
after = lib.mkAfter icfg.serviceDeps;
wants = icfg.serviceDeps;
preStart = lib.mkAfter (optionalString (!isNull icfg.varDir) ''
watchFilesChanged() {
${optionalString (builtins.length icfg.phpWatchFiles == 0) "return 1"}
[ ! -f "${icfg.varDir}"/watchedFiles ] \
|| ! sha512sum -c --status ${icfg.varDir}/watchedFiles
}
appDirChanged() {
[ ! -f "${icfg.varDir}/currentWebappDir" -o \
"${icfg.app}" != "$(cat ${icfg.varDir}/currentWebappDir 2>/dev/null)" ]
}
updateWatchFiles() {
${optionalString (builtins.length icfg.phpWatchFiles == 0) "return 0"}
sha512sum ${builtins.concatStringsSep " " icfg.phpWatchFiles} > ${icfg.varDir}/watchedFiles
}
if watchFilesChanged || appDirChanged; then
pushd ${icfg.app} > /dev/null
${builtins.concatStringsSep "\n " (map (c: "/run/wrappers/bin/sudo -u ${icfg.httpdUser} ${c}") icfg.preStartActions) }
popd > /dev/null
echo -n "${icfg.app}" > ${icfg.varDir}/currentWebappDir
updateWatchFiles
fi
'');
}
) cfg.apps;
system.activationScripts = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
name {
deps = [];
text = optionalString (!isNull icfg.varDir) ''
install -m ${icfg.mode} -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}
'' + optionalString (icfg.phpSession) ''
install -m 0700 -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}/phpSessions
'' + builtins.concatStringsSep "\n" (attrsets.mapAttrsToList (n: v: ''
install -m ${v} -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}/${n}
'') icfg.varDirPaths);
}
) cfg.apps;
};
}
|