705dd70b32
mkdir -m will only set the permissions if it *creates* the directory. Existing directories, with possibly wrong permissions, will not be updated. Use explicit chmod so permissions will always be correct.
293 lines
9.0 KiB
Nix
293 lines
9.0 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
cfg = config.services.graphite;
|
|
writeTextOrNull = f: t: if t == null then null else pkgs.writeTextDir f t;
|
|
|
|
dataDir = cfg.dataDir;
|
|
|
|
configDir = pkgs.buildEnv {
|
|
name = "graphite-config";
|
|
paths = lists.filter (el: el != null) [
|
|
(writeTextOrNull "carbon.conf" cfg.carbon.config)
|
|
(writeTextOrNull "storage-agregation.conf" cfg.carbon.storageAggregation)
|
|
(writeTextOrNull "storage-schemas.conf" cfg.carbon.storageSchemas)
|
|
(writeTextOrNull "blacklist.conf" cfg.carbon.blacklist)
|
|
(writeTextOrNull "whitelist.conf" cfg.carbon.whitelist)
|
|
(writeTextOrNull "rewrite-rules.conf" cfg.carbon.rewriteRules)
|
|
(writeTextOrNull "relay-rules.conf" cfg.carbon.relayRules)
|
|
(writeTextOrNull "aggregation-rules.conf" cfg.carbon.aggregationRules)
|
|
];
|
|
};
|
|
|
|
carbonOpts = name: with config.ids; ''
|
|
--nodaemon --syslog --prefix=${name} --pidfile ${dataDir}/${name}.pid ${name}
|
|
'';
|
|
carbonEnv = {
|
|
PYTHONPATH = "${pkgs.python27Packages.carbon}/lib/python2.7/site-packages";
|
|
GRAPHITE_ROOT = dataDir;
|
|
GRAPHITE_CONF_DIR = configDir;
|
|
GRAPHITE_STORAGE_DIR = dataDir;
|
|
};
|
|
|
|
in {
|
|
|
|
###### interface
|
|
|
|
options.services.graphite = {
|
|
dataDir = mkOption {
|
|
type = types.path;
|
|
default = "/var/db/graphite";
|
|
description = ''
|
|
Data directory for graphite.
|
|
'';
|
|
};
|
|
|
|
web = {
|
|
enable = mkOption {
|
|
description = "Whether to enable graphite web frontend";
|
|
default = false;
|
|
type = types.uniq types.bool;
|
|
};
|
|
|
|
host = mkOption {
|
|
description = "Graphite web frontend listen address";
|
|
default = "127.0.0.1";
|
|
type = types.str;
|
|
};
|
|
|
|
port = mkOption {
|
|
description = "Graphite web frontend port";
|
|
default = 8080;
|
|
type = types.int;
|
|
};
|
|
};
|
|
|
|
carbon = {
|
|
config = mkOption {
|
|
description = "Content of carbon configuration file";
|
|
default = ''
|
|
[cache]
|
|
# Listen on localhost by default for security reasons
|
|
UDP_RECEIVER_INTERFACE = 127.0.0.1
|
|
PICKLE_RECEIVER_INTERFACE = 127.0.0.1
|
|
LINE_RECEIVER_INTERFACE = 127.0.0.1
|
|
CACHE_QUERY_INTERFACE = 127.0.0.1
|
|
# Do not log every update
|
|
LOG_UPDATES = False
|
|
LOG_CACHE_HITS = False
|
|
'';
|
|
type = types.str;
|
|
};
|
|
|
|
enableCache = mkOption {
|
|
description = "Whether to enable carbon cache, the graphite storage daemon";
|
|
default = false;
|
|
type = types.uniq types.bool;
|
|
};
|
|
|
|
storageAggregation = mkOption {
|
|
description = "Defines how to aggregate data to lower-precision retentions";
|
|
default = null;
|
|
type = types.uniq (types.nullOr types.string);
|
|
example = ''
|
|
[all_min]
|
|
pattern = \.min$
|
|
xFilesFactor = 0.1
|
|
aggregationMethod = min
|
|
'';
|
|
};
|
|
|
|
storageSchemas = mkOption {
|
|
description = "Defines retention rates for storing metrics";
|
|
default = "";
|
|
type = types.uniq (types.nullOr types.string);
|
|
example = ''
|
|
[apache_busyWorkers]
|
|
pattern = ^servers\.www.*\.workers\.busyWorkers$
|
|
retentions = 15s:7d,1m:21d,15m:5y
|
|
'';
|
|
};
|
|
|
|
blacklist = mkOption {
|
|
description = "Any metrics received which match one of the experssions will be dropped";
|
|
default = null;
|
|
type = types.uniq (types.nullOr types.string);
|
|
example = "^some\.noisy\.metric\.prefix\..*";
|
|
};
|
|
|
|
whitelist = mkOption {
|
|
description = "Only metrics received which match one of the experssions will be persisted";
|
|
default = null;
|
|
type = types.uniq (types.nullOr types.string);
|
|
example = ".*";
|
|
};
|
|
|
|
rewriteRules = mkOption {
|
|
description = "Regular expression patterns that can be used to rewrite metric names in a search and replace fashion";
|
|
default = null;
|
|
type = types.uniq (types.nullOr types.string);
|
|
example = ''
|
|
[post]
|
|
_sum$ =
|
|
_avg$ =
|
|
'';
|
|
};
|
|
|
|
enableRelay = mkOption {
|
|
description = "Whether to enable carbon relay, the carbon replication and sharding service";
|
|
default = false;
|
|
type = types.uniq types.bool;
|
|
};
|
|
|
|
relayRules = mkOption {
|
|
description = "Relay rules are used to send certain metrics to a certain backend.";
|
|
default = null;
|
|
type = types.uniq (types.nullOr types.string);
|
|
example = ''
|
|
[example]
|
|
pattern = ^mydata\.foo\..+
|
|
servers = 10.1.2.3, 10.1.2.4:2004, myserver.mydomain.com
|
|
'';
|
|
};
|
|
|
|
enableAggregator = mkOption {
|
|
description = "Whether to enable carbon agregator, the carbon buffering service";
|
|
default = false;
|
|
type = types.uniq types.bool;
|
|
};
|
|
|
|
aggregationRules = mkOption {
|
|
description = "Defines if and how received metrics will be agregated";
|
|
default = null;
|
|
type = types.uniq (types.nullOr types.string);
|
|
example = ''
|
|
<env>.applications.<app>.all.requests (60) = sum <env>.applications.<app>.*.requests
|
|
<env>.applications.<app>.all.latency (60) = avg <env>.applications.<app>.*.latency
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
###### implementation
|
|
|
|
config = mkIf (cfg.carbon.enableAggregator || cfg.carbon.enableCache || cfg.carbon.enableRelay || cfg.web.enable) {
|
|
systemd.services.carbonCache = {
|
|
enable = cfg.carbon.enableCache;
|
|
description = "Graphite Data Storage Backend";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network-interfaces.target" ];
|
|
environment = carbonEnv;
|
|
serviceConfig = {
|
|
ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-cache"}";
|
|
User = "graphite";
|
|
Group = "graphite";
|
|
PermissionsStartOnly = true;
|
|
};
|
|
restartTriggers = [
|
|
pkgs.pythonPackages.carbon
|
|
cfg.carbon.config
|
|
cfg.carbon.storageAggregation
|
|
cfg.carbon.storageSchemas
|
|
cfg.carbon.rewriteRules
|
|
];
|
|
preStart = ''
|
|
mkdir -p ${cfg.dataDir}/whisper
|
|
chmod 0700 ${cfg.dataDir}/whisper
|
|
chown -R graphite:graphite ${cfg.dataDir}
|
|
'';
|
|
};
|
|
|
|
systemd.services.carbonAggregator = {
|
|
enable = cfg.carbon.enableAggregator;
|
|
description = "Carbon Data Aggregator";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network-interfaces.target" ];
|
|
environment = carbonEnv;
|
|
serviceConfig = {
|
|
ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-aggregator"}";
|
|
User = "graphite";
|
|
Group = "graphite";
|
|
};
|
|
restartTriggers = [
|
|
pkgs.pythonPackages.carbon cfg.carbon.config cfg.carbon.aggregationRules
|
|
];
|
|
};
|
|
|
|
systemd.services.carbonRelay = {
|
|
enable = cfg.carbon.enableRelay;
|
|
description = "Carbon Data Relay";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network-interfaces.target" ];
|
|
environment = carbonEnv;
|
|
serviceConfig = {
|
|
ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-relay"}";
|
|
User = "graphite";
|
|
Group = "graphite";
|
|
};
|
|
restartTriggers = [
|
|
pkgs.pythonPackages.carbon cfg.carbon.config cfg.carbon.relayRules
|
|
];
|
|
};
|
|
|
|
systemd.services.graphiteWeb = {
|
|
enable = cfg.web.enable;
|
|
description = "Graphite Web Interface";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network-interfaces.target" ];
|
|
path = [ pkgs.perl ];
|
|
environment = {
|
|
PYTHONPATH = "${pkgs.python27Packages.graphite_web}/lib/python2.7/site-packages";
|
|
DJANGO_SETTINGS_MODULE = "graphite.settings";
|
|
GRAPHITE_CONF_DIR = "/etc/graphite/";
|
|
GRAPHITE_STORAGE_DIR = dataDir;
|
|
};
|
|
serviceConfig = {
|
|
ExecStart = ''
|
|
${pkgs.python27Packages.waitress}/bin/waitress-serve \
|
|
--host=${cfg.web.host} --port=${toString cfg.web.port} \
|
|
--call django.core.handlers.wsgi:WSGIHandler'';
|
|
User = "graphite";
|
|
Group = "graphite";
|
|
PermissionsStartOnly = true;
|
|
};
|
|
preStart = ''
|
|
if ! test -e ${dataDir}/db-created; then
|
|
mkdir -p ${dataDir}/{whisper/,log/webapp/}
|
|
chmod 0700 ${dataDir}/{whisper/,log/webapp/}
|
|
|
|
# populate database
|
|
${pkgs.python27Packages.graphite_web}/bin/manage-graphite.py syncdb --noinput
|
|
|
|
# create index
|
|
${pkgs.python27Packages.graphite_web}/bin/build-index.sh
|
|
|
|
touch ${dataDir}/db-created
|
|
|
|
chown -R graphite:graphite ${cfg.dataDir}
|
|
fi
|
|
'';
|
|
restartTriggers = [
|
|
pkgs.python27Packages.graphite_web
|
|
pkgs.python27Packages.waitress
|
|
];
|
|
};
|
|
|
|
environment.systemPackages = [
|
|
pkgs.pythonPackages.carbon
|
|
pkgs.python27Packages.graphite_web
|
|
pkgs.python27Packages.waitress
|
|
];
|
|
|
|
users.extraUsers = singleton {
|
|
name = "graphite";
|
|
uid = config.ids.uids.graphite;
|
|
description = "Graphite daemon user";
|
|
home = dataDir;
|
|
};
|
|
users.extraGroups.graphite.gid = config.ids.gids.graphite;
|
|
};
|
|
}
|