2013-08-11 11:16:19 +01:00
|
|
|
{ config, pkgs, ... }:
|
|
|
|
|
|
|
|
with pkgs.lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.graphite;
|
|
|
|
writeTextOrNull = f: t: if t == null then null else pkgs.writeText f t;
|
2013-10-13 22:10:29 +01:00
|
|
|
|
2013-08-11 11:16:19 +01:00
|
|
|
dataDir = "/var/db/graphite";
|
2013-10-13 22:10:29 +01:00
|
|
|
carbonOpts = name: with config.ids; ''
|
2013-10-28 16:08:33 +00:00
|
|
|
--nodaemon --syslog --prefix=${name} --pidfile /var/run/${name}.pid \
|
2013-10-13 22:10:29 +01:00
|
|
|
--uid ${toString uids.graphite} --gid ${toString uids.graphite} ${name}
|
|
|
|
'';
|
|
|
|
carbonEnv = {
|
|
|
|
PYTHONPATH = "${pkgs.python27Packages.carbon}/lib/python2.7/site-packages";
|
|
|
|
GRAPHITE_ROOT = dataDir;
|
|
|
|
GRAPHITE_CONF_DIR = "/etc/graphite/";
|
2013-11-07 10:29:18 +00:00
|
|
|
GRAPHITE_STORAGE_DIR = dataDir;
|
2013-10-13 22:10:29 +01:00
|
|
|
};
|
|
|
|
|
2013-08-11 11:16:19 +01:00
|
|
|
in {
|
|
|
|
|
|
|
|
###### interface
|
|
|
|
|
|
|
|
options.services.graphite = {
|
2013-08-19 03:14:53 +01:00
|
|
|
web = {
|
|
|
|
enable = mkOption {
|
|
|
|
description = "Whether to enable graphite web frontend";
|
|
|
|
default = false;
|
|
|
|
type = types.uniq types.bool;
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
host = mkOption {
|
|
|
|
description = "Graphite web frontend listen address";
|
|
|
|
default = "127.0.0.1";
|
2013-10-30 10:02:04 +00:00
|
|
|
type = types.str;
|
2013-08-19 03:14:53 +01:00
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
port = mkOption {
|
|
|
|
description = "Graphite web frontend port";
|
|
|
|
default = "8080";
|
2013-10-30 10:02:04 +00:00
|
|
|
type = types.str;
|
2013-08-19 03:14:53 +01:00
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
};
|
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
carbon = {
|
|
|
|
config = mkOption {
|
|
|
|
description = "Content of carbon configuration file";
|
2013-10-11 10:44:26 +01:00
|
|
|
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
|
2013-10-28 16:09:53 +00:00
|
|
|
# Do not log every update
|
|
|
|
LOG_UPDATES = False
|
|
|
|
LOG_CACHE_HITS = False
|
2013-10-11 10:44:26 +01:00
|
|
|
'';
|
2013-10-30 10:02:04 +00:00
|
|
|
type = types.str;
|
2013-08-19 03:14:53 +01:00
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
enableCache = mkOption {
|
|
|
|
description = "Whether to enable carbon cache, the graphite storage daemon";
|
|
|
|
default = false;
|
|
|
|
type = types.uniq types.bool;
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
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
|
2013-10-13 22:10:29 +01:00
|
|
|
aggregationMethod = min
|
2013-08-19 03:14:53 +01:00
|
|
|
'';
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
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
|
|
|
|
'';
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
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\..*";
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
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 = ".*";
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
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$ =
|
|
|
|
'';
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
enableRelay = mkOption {
|
|
|
|
description = "Whether to enable carbon relay, the carbon replication and sharding service";
|
|
|
|
default = false;
|
|
|
|
type = types.uniq types.bool;
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
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
|
|
|
|
'';
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
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
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
2013-08-11 11:16:19 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
###### implementation
|
|
|
|
|
2013-08-19 09:21:31 +01:00
|
|
|
config = mkIf (cfg.carbon.enableAggregator || cfg.carbon.enableCache || cfg.carbon.enableRelay || cfg.web.enable) {
|
2013-08-11 11:16:19 +01:00
|
|
|
environment.etc = lists.filter (el: el.source != null) [
|
2013-08-19 03:14:53 +01:00
|
|
|
{ source = writeTextOrNull "carbon.conf" cfg.carbon.config;
|
2013-08-11 11:16:19 +01:00
|
|
|
target = "graphite/carbon.conf"; }
|
2013-08-19 03:14:53 +01:00
|
|
|
{ source = writeTextOrNull "storage-agregation.conf" cfg.carbon.storageAggregation;
|
2013-08-11 11:16:19 +01:00
|
|
|
target = "graphite/storage-agregation.conf"; }
|
2013-08-19 03:14:53 +01:00
|
|
|
{ source = writeTextOrNull "storage-schemas.conf" cfg.carbon.storageSchemas;
|
2013-08-11 11:16:19 +01:00
|
|
|
target = "graphite/storage-schemas.conf"; }
|
2013-08-19 03:14:53 +01:00
|
|
|
{ source = writeTextOrNull "blacklist.conf" cfg.carbon.blacklist;
|
2013-08-11 11:16:19 +01:00
|
|
|
target = "graphite/blacklist.conf"; }
|
2013-08-19 03:14:53 +01:00
|
|
|
{ source = writeTextOrNull "whitelist.conf" cfg.carbon.whitelist;
|
2013-08-11 11:16:19 +01:00
|
|
|
target = "graphite/whitelist.conf"; }
|
2013-08-19 03:14:53 +01:00
|
|
|
{ source = writeTextOrNull "rewrite-rules.conf" cfg.carbon.rewriteRules;
|
2013-08-11 11:16:19 +01:00
|
|
|
target = "graphite/rewrite-rules.conf"; }
|
2013-08-19 03:14:53 +01:00
|
|
|
{ source = writeTextOrNull "relay-rules.conf" cfg.carbon.relayRules;
|
2013-08-11 11:16:19 +01:00
|
|
|
target = "graphite/relay-rules.conf"; }
|
2013-08-19 03:14:53 +01:00
|
|
|
{ source = writeTextOrNull "aggregation-rules.conf" cfg.carbon.aggregationRules;
|
2013-08-11 11:16:19 +01:00
|
|
|
target = "graphite/aggregation-rules.conf"; }
|
|
|
|
];
|
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
systemd.services.carbonCache = mkIf cfg.carbon.enableCache {
|
2013-08-11 11:16:19 +01:00
|
|
|
description = "Graphite data storage backend";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
after = [ "network-interfaces.target" ];
|
2013-10-13 22:10:29 +01:00
|
|
|
environment = carbonEnv;
|
|
|
|
serviceConfig.ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-cache"}";
|
2013-08-11 11:16:19 +01:00
|
|
|
restartTriggers = [
|
2013-10-03 15:20:48 +01:00
|
|
|
pkgs.pythonPackages.carbon
|
|
|
|
cfg.carbon.config
|
|
|
|
cfg.carbon.storageAggregation
|
|
|
|
cfg.carbon.storageSchemas
|
|
|
|
cfg.carbon.rewriteRules
|
2013-08-11 11:16:19 +01:00
|
|
|
];
|
|
|
|
preStart = ''
|
|
|
|
mkdir -p ${dataDir}/whisper
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
systemd.services.carbonAggregator = mkIf cfg.carbon.enableAggregator {
|
2013-08-11 11:16:19 +01:00
|
|
|
description = "Carbon data aggregator";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
after = [ "network-interfaces.target" ];
|
2013-10-13 22:10:29 +01:00
|
|
|
environment = carbonEnv;
|
|
|
|
serviceConfig.ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-aggregator"}";
|
2013-08-19 03:14:53 +01:00
|
|
|
restartTriggers = [
|
|
|
|
pkgs.pythonPackages.carbon cfg.carbon.config cfg.carbon.aggregationRules
|
|
|
|
];
|
2013-08-11 11:16:19 +01:00
|
|
|
};
|
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
systemd.services.carbonRelay = mkIf cfg.carbon.enableRelay {
|
2013-08-11 11:16:19 +01:00
|
|
|
description = "Carbon data relay";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
after = [ "network-interfaces.target" ];
|
2013-10-13 22:10:29 +01:00
|
|
|
environment = carbonEnv;
|
|
|
|
serviceConfig.ExecStart = "${pkgs.twisted}/bin/twistd ${carbonOpts "carbon-relay"}";
|
2013-08-19 03:14:53 +01:00
|
|
|
restartTriggers = [
|
|
|
|
pkgs.pythonPackages.carbon cfg.carbon.config cfg.carbon.relayRules
|
|
|
|
];
|
2013-08-11 11:16:19 +01:00
|
|
|
};
|
|
|
|
|
2013-08-19 03:14:53 +01:00
|
|
|
systemd.services.graphiteWeb = mkIf cfg.web.enable {
|
2013-08-11 11:16:19 +01:00
|
|
|
description = "Graphite web interface";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
after = [ "network-interfaces.target" ];
|
|
|
|
environment = {
|
2013-08-19 03:14:53 +01:00
|
|
|
PYTHONPATH = "${pkgs.python27Packages.graphite_web}/lib/python2.7/site-packages";
|
|
|
|
DJANGO_SETTINGS_MODULE = "graphite.settings";
|
2013-08-11 11:16:19 +01:00
|
|
|
GRAPHITE_CONF_DIR = "/etc/graphite/";
|
2013-10-13 22:10:29 +01:00
|
|
|
GRAPHITE_STORAGE_DIR = dataDir;
|
2013-08-11 11:16:19 +01:00
|
|
|
};
|
|
|
|
serviceConfig = {
|
2013-08-19 03:14:53 +01:00
|
|
|
ExecStart = ''
|
|
|
|
${pkgs.python27Packages.waitress}/bin/waitress-serve \
|
|
|
|
--host=${cfg.web.host} --port=${cfg.web.port} \
|
|
|
|
--call django.core.handlers.wsgi:WSGIHandler'';
|
2013-08-11 11:16:19 +01:00
|
|
|
User = "graphite";
|
|
|
|
Group = "graphite";
|
|
|
|
};
|
|
|
|
preStart = ''
|
|
|
|
if ! test -e ${dataDir}/db-created; then
|
|
|
|
mkdir -p ${dataDir}/{whisper/,log/webapp/}
|
|
|
|
|
|
|
|
# populate database
|
2013-08-19 03:14:53 +01:00
|
|
|
${pkgs.python27Packages.graphite_web}/bin/manage-graphite.py syncdb --noinput
|
2013-08-11 11:16:19 +01:00
|
|
|
|
|
|
|
# create index
|
2013-08-19 03:14:53 +01:00
|
|
|
${pkgs.python27Packages.graphite_web}/bin/build-index.sh
|
2013-08-11 11:16:19 +01:00
|
|
|
|
|
|
|
touch ${dataDir}/db-created
|
|
|
|
fi
|
|
|
|
'';
|
2013-08-19 03:14:53 +01:00
|
|
|
restartTriggers = [
|
2013-10-03 15:20:48 +01:00
|
|
|
pkgs.python27Packages.graphite_web
|
|
|
|
pkgs.python27Packages.waitress
|
2013-08-19 03:14:53 +01:00
|
|
|
];
|
2013-08-11 11:16:19 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
environment.systemPackages = [
|
2013-10-03 15:20:48 +01:00
|
|
|
pkgs.pythonPackages.carbon
|
|
|
|
pkgs.python27Packages.graphite_web
|
2013-08-19 03:14:53 +01:00
|
|
|
pkgs.python27Packages.waitress
|
2013-08-11 11:16:19 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
users.extraUsers = singleton {
|
|
|
|
name = "graphite";
|
|
|
|
uid = config.ids.uids.graphite;
|
|
|
|
description = "Graphite daemon user";
|
2013-10-13 22:10:29 +01:00
|
|
|
home = dataDir;
|
2013-08-11 11:16:19 +01:00
|
|
|
createHome = true;
|
|
|
|
};
|
|
|
|
users.extraGroups.graphite.gid = config.ids.gids.graphite;
|
|
|
|
};
|
|
|
|
}
|