diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index 0b65b4865b15..e0c5ceccfcc9 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -25,6 +25,7 @@ let "artifactory" "bind" "bird" + "bitcoin" "blackbox" "collectd" "dnsmasq" diff --git a/nixos/modules/services/monitoring/prometheus/exporters/bitcoin.nix b/nixos/modules/services/monitoring/prometheus/exporters/bitcoin.nix new file mode 100644 index 000000000000..43721f70b499 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/bitcoin.nix @@ -0,0 +1,82 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.bitcoin; +in +{ + port = 9332; + extraOpts = { + rpcUser = mkOption { + type = types.str; + default = "bitcoinrpc"; + description = '' + RPC user name. + ''; + }; + + rpcPasswordFile = mkOption { + type = types.path; + description = '' + File containing RPC password. + ''; + }; + + rpcScheme = mkOption { + type = types.enum [ "http" "https" ]; + default = "http"; + description = '' + Whether to connect to bitcoind over http or https. + ''; + }; + + rpcHost = mkOption { + type = types.str; + default = "localhost"; + description = '' + RPC host. + ''; + }; + + rpcPort = mkOption { + type = types.port; + default = 8332; + description = '' + RPC port number. + ''; + }; + + refreshSeconds = mkOption { + type = types.ints.unsigned; + default = 300; + description = '' + How often to ask bitcoind for metrics. + ''; + }; + + extraEnv = mkOption { + type = types.attrsOf types.str; + default = {}; + description = '' + Extra environment variables for the exporter. + ''; + }; + }; + serviceOpts = { + script = '' + export BITCOIN_RPC_PASSWORD=$(cat ${cfg.rpcPasswordFile}) + exec ${pkgs.prometheus-bitcoin-exporter}/bin/bitcoind-monitor.py + ''; + + environment = { + BITCOIN_RPC_USER = cfg.rpcUser; + BITCOIN_RPC_SCHEME = cfg.rpcScheme; + BITCOIN_RPC_HOST = cfg.rpcHost; + BITCOIN_RPC_PORT = toString cfg.rpcPort; + METRICS_ADDR = cfg.listenAddress; + METRICS_PORT = toString cfg.port; + REFRESH_SECONDS = toString cfg.refreshSeconds; + } // cfg.extraEnv; + }; +} diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix index a43dca4fe14d..62c0080dd516 100644 --- a/nixos/tests/prometheus-exporters.nix +++ b/nixos/tests/prometheus-exporters.nix @@ -136,6 +136,24 @@ let ''; }; + bitcoin = { + exporterConfig = { + enable = true; + rpcUser = "bitcoinrpc"; + rpcPasswordFile = pkgs.writeText "password" "hunter2"; + }; + metricProvider = { + services.bitcoind.default.enable = true; + services.bitcoind.default.rpc.users.bitcoinrpc.passwordHMAC = "e8fe33f797e698ac258c16c8d7aadfbe$872bdb8f4d787367c26bcfd75e6c23c4f19d44a69f5d1ad329e5adf3f82710f7"; + }; + exporterTest = '' + wait_for_unit("prometheus-bitcoin-exporter.service") + wait_for_unit("bitcoind-default.service") + wait_for_open_port(9332) + succeed("curl -sSf http://localhost:9332/metrics | grep -q '^bitcoin_blocks '") + ''; + }; + blackbox = { exporterConfig = { enable = true; diff --git a/pkgs/development/python-modules/riprova/default.nix b/pkgs/development/python-modules/riprova/default.nix new file mode 100644 index 000000000000..adf327208955 --- /dev/null +++ b/pkgs/development/python-modules/riprova/default.nix @@ -0,0 +1,29 @@ +{ lib +, buildPythonPackage +, fetchPypi +, six +}: + +buildPythonPackage rec{ + pname = "riprova"; + version = "0.2.7"; + + src = fetchPypi { + inherit pname version; + sha256 = "04drdvjjbh370csv2vb5zamg2aanxqkfm6w361qkybnra4g4g0dz"; + }; + + propagatedBuildInputs = [ six ]; + + # PyPI archive doesn't have tests + doCheck = false; + + pythonImportsCheck = [ "riprova" ]; + + meta = with lib; { + homepage = "https://github.com/h2non/riprova"; + description = "Small and versatile library to retry failed operations using different backoff strategies"; + license = licenses.mit; + maintainers = with maintainers; [ mmilata ]; + }; +} diff --git a/pkgs/servers/monitoring/prometheus/bitcoin-exporter.nix b/pkgs/servers/monitoring/prometheus/bitcoin-exporter.nix new file mode 100644 index 000000000000..333be3732112 --- /dev/null +++ b/pkgs/servers/monitoring/prometheus/bitcoin-exporter.nix @@ -0,0 +1,42 @@ +{ lib, fetchFromGitHub, fetchpatch, python3Packages }: + +python3Packages.buildPythonApplication rec { + pname = "bitcoin-prometheus-exporter"; + version = "0.5.0"; + + format = "other"; + + src = fetchFromGitHub { + owner = "jvstein"; + repo = pname; + rev = "v${version}"; + sha256 = "0l0j6dyb0vflh386z3g8srysay5sf47g5rg2f5xrkckv86rjr115"; + }; + + patches = [ + # remove after update to new release + (fetchpatch { + name = "configurable-listening-address.patch"; + url = "https://patch-diff.githubusercontent.com/raw/jvstein/bitcoin-prometheus-exporter/pull/11.patch"; + sha256 = "0a2l8aqgprc1d5k8yg1gisn6imh9hzg6j0irid3pjvp5i5dcnhyq"; + }) + ]; + + propagatedBuildInputs = with python3Packages; [ prometheus_client bitcoinlib riprova ]; + + installPhase = '' + mkdir -p $out/bin + cp bitcoind-monitor.py $out/bin/ + + mkdir -p $out/share/${pname} + cp -r dashboard README.md $out/share/${pname}/ + ''; + + meta = with lib; { + description = "Prometheus exporter for Bitcoin Core nodes"; + homepage = "https://github.com/jvstein/bitcoin-prometheus-exporter"; + license = licenses.bsd3; + maintainers = with maintainers; [ mmilata ]; + platforms = platforms.all; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 56e4e86a576d..3870915745e4 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -18876,6 +18876,7 @@ in prometheus-aws-s3-exporter = callPackage ../servers/monitoring/prometheus/aws-s3-exporter.nix { }; prometheus-bind-exporter = callPackage ../servers/monitoring/prometheus/bind-exporter.nix { }; prometheus-bird-exporter = callPackage ../servers/monitoring/prometheus/bird-exporter.nix { }; + prometheus-bitcoin-exporter = callPackage ../servers/monitoring/prometheus/bitcoin-exporter.nix { }; prometheus-blackbox-exporter = callPackage ../servers/monitoring/prometheus/blackbox-exporter.nix { }; prometheus-collectd-exporter = callPackage ../servers/monitoring/prometheus/collectd-exporter.nix { }; prometheus-consul-exporter = callPackage ../servers/monitoring/prometheus/consul-exporter.nix { }; diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index f84848c072c0..ae06f4348b31 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -7282,6 +7282,8 @@ in { ring-doorbell = callPackage ../development/python-modules/ring-doorbell { }; + riprova = callPackage ../development/python-modules/riprova { }; + ripser = callPackage ../development/python-modules/ripser { }; rising = callPackage ../development/python-modules/rising { };