From 596c486e53dfab8fe1e5d6f782cbe88b3eee5a5f Mon Sep 17 00:00:00 2001
From: Martin Milata <martin@martinmilata.cz>
Date: Sun, 31 May 2020 13:41:59 +0200
Subject: [PATCH 1/3] pythonPackages.riprova: init at 0.2.7

---
 .../python-modules/riprova/default.nix        | 29 +++++++++++++++++++
 pkgs/top-level/python-packages.nix            |  2 ++
 2 files changed, 31 insertions(+)
 create mode 100644 pkgs/development/python-modules/riprova/default.nix

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/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix
index f460f07a0fc5..395f54a56f39 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 { };

From dbb07aba88caa08ac4fc0a1ec2dd1ca344615b56 Mon Sep 17 00:00:00 2001
From: Martin Milata <martin@martinmilata.cz>
Date: Sun, 31 May 2020 13:45:24 +0200
Subject: [PATCH 2/3] prometheus-bitcoin-exporter: init at 0.5.0

---
 .../prometheus/bitcoin-exporter.nix           | 42 +++++++++++++++++++
 pkgs/top-level/all-packages.nix               |  1 +
 2 files changed, 43 insertions(+)
 create mode 100644 pkgs/servers/monitoring/prometheus/bitcoin-exporter.nix

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 4d49a2ec7f70..ce99161e3450 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -18863,6 +18863,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 { };

From 6b028bcf358fbba1f48db6e380d3348e8bd5210a Mon Sep 17 00:00:00 2001
From: Martin Milata <martin@martinmilata.cz>
Date: Sun, 31 May 2020 22:47:10 +0200
Subject: [PATCH 3/3] nixos/prometheus-bitcoin-exporter: init

---
 .../monitoring/prometheus/exporters.nix       |  1 +
 .../prometheus/exporters/bitcoin.nix          | 82 +++++++++++++++++++
 nixos/tests/prometheus-exporters.nix          | 18 ++++
 3 files changed, 101 insertions(+)
 create mode 100644 nixos/modules/services/monitoring/prometheus/exporters/bitcoin.nix

diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix
index 5f6a86afdcd9..7dc7630ac0ab 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 c32cd341e5e5..b921090f5272 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;