Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

init grafana service #108

Merged
merged 11 commits into from
Feb 22, 2024
40 changes: 40 additions & 0 deletions doc/grafana.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Grafana

[Grafana open source](https://grafana.com/docs/grafana/latest/) is open source visualization and analytics software. It allows you to query, visualize, alert on, and explore your metrics, logs, and traces no matter where they are stored. It provides you with tools to turn your time-series database (TSDB) data into insightful graphs and visualizations.

## Getting Started

```nix
# In `perSystem.process-compose.<name>`
{
services.grafana."gf1".enable = true;
}
```

{#tips}
## Tips & Tricks

{#change-database}
### Changing Grafana database

By default, Grafana stores data in the `sqlite3` [database](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#database). It also supports `mysql` and `postgres`.

To change the database to `postgres`, we can use the following config:

```nix
services.postgres.pg1 = {
enable = true;
listen_addresses = "127.0.0.1";
initialScript.after = "CREATE USER root SUPERUSER;";
};
services.grafana.gf1 = {
enable = true;
extraConf.database = with config.services.postgres.pg1; {
type = "postgres";
host = "${listen_addresses}:${builtins.toString port}";
name = "postgres"; # database name
};
};
settings.processes."gf1".depends_on."pg1".condition = "process_healthy";
};
```
1 change: 1 addition & 0 deletions doc/services.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ short-title: Services
- [ ] Redis
- [ ] Redis Cluster
- [ ] Zookeeper
- [ ] [[grafana]]#
- [ ] ...

[gh]: https://github.com/juspay/services-flake
1 change: 1 addition & 0 deletions nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ in
./redis-cluster.nix
./redis.nix
./zookeeper.nix
./grafana.nix
];
}
99 changes: 99 additions & 0 deletions nix/grafana.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{ pkgs, lib, name, config, ... }:
let
inherit (lib) types;
iniFormat = pkgs.formats.ini { };
in
{
options = {
description = ''
Configure grafana.
'';
enable = lib.mkEnableOption name;

package = lib.mkPackageOption pkgs "grafana" { };

http_port = lib.mkOption {
type = types.int;
description = "Which port to run grafana on.";
default = 3000;
};

domain = lib.mkOption {
type = types.str;
description = "The public facing domain name used to access grafana from a browser.";
default = "localhost";
};

protocol = lib.mkOption {
type = types.str;
description = "Protocol (http, https, h2, socket).";
default = "http";
};

dataDir = lib.mkOption {
type = types.str;
description = "Directory where grafana stores its logs and data.";
default = "./data/${name}";
};

extraConf = lib.mkOption {
type = iniFormat.type;
description = "Extra configuration for grafana.";
default = { };
example = ''
{
security.admin_user = "patato";
security.admin_password = "potato";
}
'';
};

outputs.settings = lib.mkOption {
type = types.deferredModule;
internal = true;
readOnly = true;
default = {
processes."${name}" =
let
grafanaConfig = lib.recursiveUpdate
{
server = {
inherit (config) protocol http_port domain;
};
}
config.extraConf;
grafanaConfigIni = iniFormat.generate "defaults.ini" grafanaConfig;
startScript = pkgs.writeShellApplication {
name = "start-grafana";
runtimeInputs = [ config.package ];
text = ''
grafana server --config ${grafanaConfigIni} \
--homepath ${config.package}/share/grafana \
cfg:paths.data="$(readlink -m ${config.dataDir})"
'';
};
in
{
command = startScript;
readiness_probe = {
http_get = {
host = config.domain;
scheme = config.protocol;
port = config.http_port;
path = "/api/health";
};
initial_delay_seconds = 15;
period_seconds = 10;
timeout_seconds = 2;
success_threshold = 1;
failure_threshold = 5;
};
namespace = name;

# https://github.com/F1bonacc1/process-compose#-auto-restart-if-not-healthy
availability.restart = "on_failure";
};
};
};
};
}
32 changes: 32 additions & 0 deletions nix/grafana_test.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{ pkgs, config, ... }: {
services.grafana."gf1" =
{
enable = true;
http_port = 3000;
extraConf = {
security.admin_user = "patato";
security.admin_password = "potato";
};
};

settings.processes.test =
let
cfg = config.services.grafana."gf1";
in
{
# Tests based on: https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/grafana/basic.nix
command = pkgs.writeShellApplication {
runtimeInputs = [ cfg.package pkgs.gnugrep pkgs.curl pkgs.uutils-coreutils-noprefix ];
text =
''
ADMIN=${cfg.extraConf.security.admin_user}
PASSWORD=${cfg.extraConf.security.admin_password}
ROOT_URL="${cfg.protocol}://${cfg.domain}:${builtins.toString cfg.http_port}";
curl -sSfN -u $ADMIN:$PASSWORD $ROOT_URL/api/org/users -i
curl -sSfN -u $ADMIN:$PASSWORD $ROOT_URL/api/org/users | grep admin\@localhost
'';
name = "grafana-test";
};
depends_on."gf1".condition = "process_healthy";
};
}
1 change: 1 addition & 0 deletions test/flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"${inputs.services-flake}/nix/redis_test.nix"
"${inputs.services-flake}/nix/redis-cluster_test.nix"
"${inputs.services-flake}/nix/zookeeper_test.nix"
"${inputs.services-flake}/nix/grafana_test.nix"
]);
};
};
Expand Down
Loading