1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.longview;
7
8 runDir = "/run/longview";
9 configsDir = "${runDir}/longview.d";
10
11in {
12 options = {
13
14 services.longview = {
15
16 enable = mkOption {
17 type = types.bool;
18 default = false;
19 description = ''
20 If enabled, system metrics will be sent to Linode LongView.
21 '';
22 };
23
24 apiKey = mkOption {
25 type = types.str;
26 default = "";
27 example = "01234567-89AB-CDEF-0123456789ABCDEF";
28 description = ''
29 Longview API key. To get this, look in Longview settings which
30 are found at https://manager.linode.com/longview/.
31
32 Warning: this secret is stored in the world-readable Nix store!
33 Use <option>apiKeyFile</option> instead.
34 '';
35 };
36
37 apiKeyFile = mkOption {
38 type = types.nullOr types.path;
39 default = null;
40 example = "/run/keys/longview-api-key";
41 description = ''
42 A file containing the Longview API key.
43 To get this, look in Longview settings which
44 are found at https://manager.linode.com/longview/.
45
46 <option>apiKeyFile</option> takes precedence over <option>apiKey</option>.
47 '';
48 };
49
50 apacheStatusUrl = mkOption {
51 type = types.str;
52 default = "";
53 example = "http://127.0.0.1/server-status";
54 description = ''
55 The Apache status page URL. If provided, Longview will
56 gather statistics from this location. This requires Apache
57 mod_status to be loaded and enabled.
58 '';
59 };
60
61 nginxStatusUrl = mkOption {
62 type = types.str;
63 default = "";
64 example = "http://127.0.0.1/nginx_status";
65 description = ''
66 The Nginx status page URL. Longview will gather statistics
67 from this URL. This requires the Nginx stub_status module to
68 be enabled and configured at the given location.
69 '';
70 };
71
72 mysqlUser = mkOption {
73 type = types.str;
74 default = "";
75 description = ''
76 The user for connecting to the MySQL database. If provided,
77 Longview will connect to MySQL and collect statistics about
78 queries, etc. This user does not need to have been granted
79 any extra privileges.
80 '';
81 };
82
83 mysqlPassword = mkOption {
84 type = types.str;
85 default = "";
86 description = ''
87 The password corresponding to <option>mysqlUser</option>.
88 Warning: this is stored in cleartext in the Nix store!
89 Use <option>mysqlPasswordFile</option> instead.
90 '';
91 };
92
93 mysqlPasswordFile = mkOption {
94 type = types.nullOr types.path;
95 default = null;
96 example = "/run/keys/dbpassword";
97 description = ''
98 A file containing the password corresponding to <option>mysqlUser</option>.
99 '';
100 };
101
102 };
103
104 };
105
106 config = mkIf cfg.enable {
107 systemd.services.longview =
108 { description = "Longview Metrics Collection";
109 after = [ "network.target" ];
110 wantedBy = [ "multi-user.target" ];
111 serviceConfig.Type = "forking";
112 serviceConfig.ExecStop = "-${pkgs.coreutils}/bin/kill -TERM $MAINPID";
113 serviceConfig.ExecReload = "-${pkgs.coreutils}/bin/kill -HUP $MAINPID";
114 serviceConfig.PIDFile = "${runDir}/longview.pid";
115 serviceConfig.ExecStart = "${pkgs.longview}/bin/longview";
116 preStart = ''
117 umask 077
118 mkdir -p ${configsDir}
119 '' + (optionalString (cfg.apiKeyFile != null) ''
120 cp --no-preserve=all "${cfg.apiKeyFile}" ${runDir}/longview.key
121 '') + (optionalString (cfg.apacheStatusUrl != "") ''
122 cat > ${configsDir}/Apache.conf <<EOF
123 location ${cfg.apacheStatusUrl}?auto
124 EOF
125 '') + (optionalString (cfg.mysqlUser != "" && cfg.mysqlPasswordFile != null) ''
126 cat > ${configsDir}/MySQL.conf <<EOF
127 username ${cfg.mysqlUser}
128 password `head -n1 "${cfg.mysqlPasswordFile}"`
129 EOF
130 '') + (optionalString (cfg.nginxStatusUrl != "") ''
131 cat > ${configsDir}/Nginx.conf <<EOF
132 location ${cfg.nginxStatusUrl}
133 EOF
134 '');
135 };
136
137 warnings = let warn = k: optional (cfg.${k} != "")
138 "config.services.longview.${k} is insecure. Use ${k}File instead.";
139 in concatMap warn [ "apiKey" "mysqlPassword" ];
140
141 assertions = [
142 { assertion = cfg.apiKeyFile != null;
143 message = "Longview needs an API key configured";
144 }
145 ];
146
147 # Create API key file if not configured.
148 services.longview.apiKeyFile = mkIf (cfg.apiKey != "")
149 (mkDefault (toString (pkgs.writeTextFile {
150 name = "longview.key";
151 text = cfg.apiKey;
152 })));
153
154 # Create MySQL password file if not configured.
155 services.longview.mysqlPasswordFile = mkDefault (toString (pkgs.writeTextFile {
156 name = "mysql-password-file";
157 text = cfg.mysqlPassword;
158 }));
159 };
160}