summaryrefslogtreecommitdiff
path: root/modules/websites/php-application.nix
blob: 7bbae50a943fbf5b8ffb95e951d7f724aa6dc7d9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{ lib, config, ... }:
with lib;
let
  cfg = config.services.phpApplication;
  cfgByEnv = lists.groupBy (x: x.websiteEnv) (builtins.attrValues cfg);
in
{
  options = {
    services.phpApplication = with types; mkOption {
      default = {};
      description = ''
        php applications to define
        '';
      type = attrsOf (submodule {
        options = {
          varDir = mkOption {
            type = nullOr path;
            description = ''
              Path to application’s 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";
          };
          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.
              '';
          };
          app = mkOption {
            type = path;
            description = ''
              Path to application root
              '';
          };
          webappName = mkOption {
            type = nullOr str;
            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
              '';
          };
          watchFiles = mkOption {
            type = listOf path;
            default = [];
            description = ''
              Path to other files to watch to trigger preStart scripts
              '';
          };
        };
      });
    };
  };

  config = {
    services.websites = attrsets.mapAttrs' (name: cfgs: attrsets.nameValuePair
      name {
        modules = [ "proxy_fcgi" ];
        watchPaths = builtins.concatLists (map (c: c.watchFiles) cfgs);
      }
    ) cfgByEnv;

    services.websitesWebappDirs = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
      icfg.webappName icfg.webRoot
    ) (attrsets.filterAttrs (n: v: !isNull v.webappName && !isNull v.webRoot) cfg);

    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.watchFiles == 0) "return 0"}
            [ ! -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.watchFiles == 0) "return 0"}
            sha512sum ${builtins.concatStringsSep " " icfg.watchFiles} > ${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;

    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
          '';
      }
    ) cfg;
  };
}