Repository: esanchezm/prometheus-qbittorrent-exporter

Issue:
HTTPS support
Is there way to export https qbittorrent host?

Discussion:
@esanchezm: Hi @averyanalex, I'm not sure to understand what you want. Can you be more specific or give me an example? Thanks!@averyanalex: My qbittorent behind nginx reverse proxy (with ssl). But if I set host to example.org, and port to 443, I get error "plain http request sent to https port"@esanchezm: Ok, I understand. Well, you should run this exporter in the same network where qbittorrent is running. I don't know if you can do it, but that's what you should do.

However, I think I can work on SSL support, can't promise anything but I'll work on it :smile: @averyanalex: Thanks, now I connect exporter directly to qbittorrent as a workaround@esanchezm: Will be fixed in #35 

Solution patch:
diff --git a/README.md b/README.md
index 9d37eec..d752685 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,8 @@ The application reads configuration using environment variables:
 | -------------------------- | ------------- | ----------- |
 | `QBITTORRENT_HOST`         |               | qbittorrent server hostname |
 | `QBITTORRENT_PORT`         |               | qbittorrent server port |
+| `QBITTORRENT_SSL`          | `False`       | Whether to use SSL to connect or not. Will be forced to `True` when using port 443  |
+| `QBITTORRENT_URL_BASE`     | `""`          | qbittorrent server path or base URL |
 | `QBITTORRENT_USER`         | `""`          | qbittorrent username |
 | `QBITTORRENT_PASS`         | `""`          | qbittorrent password |
 | `EXPORTER_PORT`            | `8000`        | Exporter listening port |
diff --git a/qbittorrent_exporter/exporter.py b/qbittorrent_exporter/exporter.py
index 15bef02..6bb5bd4 100644
--- a/qbittorrent_exporter/exporter.py
+++ b/qbittorrent_exporter/exporter.py
@@ -43,14 +43,20 @@ class Metric:
 class QbittorrentMetricsCollector:
     def __init__(self, config: dict) -> None:
         self.config = config
+        self.server = f"{config['host']}:{config['port']}"
+        self.protocol = "http"
+
+        if config["url_base"]:
+            self.server = f"{self.server}/{config['url_base']}"
+        if config["ssl"] or config["port"] == "443":
+            self.protocol = "https"
+        self.connection_string = f"{self.protocol}://{self.server}"
         self.client = Client(
-            host=config["host"],
-            port=config["port"],
+            host=self.connection_string,
             username=config["username"],
             password=config["password"],
             VERIFY_WEBUI_CERTIFICATE=config["verify_webui_certificate"],
         )
-        self.server = f"{config['host']}:{config['port']}"
 
     def collect(self) -> Iterable[GaugeMetricFamily | CounterMetricFamily]:
         """
@@ -269,6 +275,8 @@ def get_config() -> dict:
     return {
         "host": _get_config_value("QBITTORRENT_HOST", ""),
         "port": _get_config_value("QBITTORRENT_PORT", ""),
+        "ssl": (_get_config_value("QBITTORRENT_SSL", "False") == "True"),
+        "url_base": _get_config_value("QBITTORRENT_URL_BASE", ""),
         "username": _get_config_value("QBITTORRENT_USER", ""),
         "password": _get_config_value("QBITTORRENT_PASS", ""),
         "exporter_port": int(_get_config_value("EXPORTER_PORT", "8000")),


Test patch:
diff --git a/tests/exporter_test.py b/tests/exporter_test.py
index f1e5f50..f676da7 100644
--- a/tests/exporter_test.py
+++ b/tests/exporter_test.py
@@ -18,6 +18,8 @@ class TestQbittorrentMetricsCollector(unittest.TestCase):
         self.config = {
             "host": "localhost",
             "port": "8080",
+            "ssl": False,
+            "url_base": "qbt/",
             "username": "user",
             "password": "pass",
             "verify_webui_certificate": False,
@@ -42,8 +44,7 @@ class TestQbittorrentMetricsCollector(unittest.TestCase):
     def test_init(self):
         self.assertEqual(self.collector.config, self.config)
         self.mock_client.assert_called_once_with(
-            host=self.config["host"],
-            port=self.config["port"],
+            host=f"http://{self.config['host']}:{self.config['port']}/qbt/",
             username=self.config["username"],
             password=self.config["password"],
             VERIFY_WEBUI_CERTIFICATE=self.config["verify_webui_certificate"],
@@ -232,7 +233,7 @@ class TestQbittorrentMetricsCollector(unittest.TestCase):
             Metric(
                 name="qbittorrent_up",
                 value=True,
-                labels={"version": "1.2.3", "server": "localhost:8080"},
+                labels={"version": "1.2.3", "server": "localhost:8080/qbt/"},
                 help_text=(
                     "Whether the qBittorrent server is answering requests from this"
                     " exporter. A `version` label with the server version is added."
@@ -241,7 +242,7 @@ class TestQbittorrentMetricsCollector(unittest.TestCase):
             Metric(
                 name="qbittorrent_connected",
                 value=True,
-                labels={"server": "localhost:8080"},
+                labels={"server": "localhost:8080/qbt/"},
                 help_text=(
                     "Whether the qBittorrent server is connected to the Bittorrent"
                     " network."
@@ -250,7 +251,7 @@ class TestQbittorrentMetricsCollector(unittest.TestCase):
             Metric(
                 name="qbittorrent_firewalled",
                 value=False,
-                labels={"server": "localhost:8080"},
+                labels={"server": "localhost:8080/qbt/"},
                 help_text=(
                     "Whether the qBittorrent server is connected to the Bittorrent"
                     " network but is behind a firewall."
@@ -259,34 +260,34 @@ class TestQbittorrentMetricsCollector(unittest.TestCase):
             Metric(
                 name="qbittorrent_dht_nodes",
                 value=0,
-                labels={"server": "localhost:8080"},
+                labels={"server": "localhost:8080/qbt/"},
                 help_text="Number of DHT nodes connected to.",
             ),
             Metric(
                 name="qbittorrent_dl_info_data",
                 value=0,
-                labels={"server": "localhost:8080"},
+                labels={"server": "localhost:8080/qbt/"},
                 help_text="Data downloaded since the server started, in bytes.",
                 metric_type=MetricType.COUNTER,
             ),
             Metric(
                 name="qbittorrent_up_info_data",
                 value=0,
-                labels={"server": "localhost:8080"},
+                labels={"server": "localhost:8080/qbt/"},
                 help_text="Data uploaded since the server started, in bytes.",
                 metric_type=MetricType.COUNTER,
             ),
             Metric(
                 name="qbittorrent_alltime_dl",
                 value=0,
-                labels={"server": "localhost:8080"},
+                labels={"server": "localhost:8080/qbt/"},
                 help_text="Total historical data downloaded, in bytes.",
                 metric_type=MetricType.COUNTER,
             ),
             Metric(
                 name="qbittorrent_alltime_ul",
                 value=0,
-                labels={"server": "localhost:8080"},
+                labels={"server": "localhost:8080/qbt/"},
                 help_text="Total historical data uploaded, in bytes.",
                 metric_type=MetricType.COUNTER,
             ),
@@ -294,3 +295,56 @@ class TestQbittorrentMetricsCollector(unittest.TestCase):
 
         metrics = self.collector._get_qbittorrent_status_metrics()
         self.assertEqual(metrics, expected_metrics)
+
+    def test_server_string_with_different_settings(self):
+        self.assertEqual(self.collector.server, "localhost:8080/qbt/")
+        self.assertEqual(self.collector.connection_string, "http://localhost:8080/qbt/")
+
+        config = {
+            "host": "qbittorrent.example.com",
+            "port": "8081",
+            "ssl": False,
+            "url_base": "qbittorrent/",
+            "username": "user",
+            "password": "pass",
+            "verify_webui_certificate": False,
+            "metrics_prefix": "qbittorrent",
+        }
+        collector = QbittorrentMetricsCollector(config)
+        self.assertEqual(collector.server, "qbittorrent.example.com:8081/qbittorrent/")
+        self.assertEqual(
+            collector.connection_string,
+            "http://qbittorrent.example.com:8081/qbittorrent/",
+        )
+
+        config = {
+            "host": "qbittorrent2.example.com",
+            "port": "8084",
+            "ssl": True,
+            "url_base": "",
+            "username": "user",
+            "password": "pass",
+            "verify_webui_certificate": True,
+            "metrics_prefix": "qbittorrent",
+        }
+        collector = QbittorrentMetricsCollector(config)
+        self.assertEqual(collector.server, "qbittorrent2.example.com:8084")
+        self.assertEqual(
+            collector.connection_string, "https://qbittorrent2.example.com:8084"
+        )
+
+        config = {
+            "host": "qbittorrent3.example.com",
+            "port": "443",
+            "ssl": False,  # Will be enforced to True because port is 443
+            "url_base": "server/",
+            "username": "user",
+            "password": "pass",
+            "verify_webui_certificate": True,
+            "metrics_prefix": "qbittorrent",
+        }
+        collector = QbittorrentMetricsCollector(config)
+        self.assertEqual(collector.server, "qbittorrent3.example.com:443/server/")
+        self.assertEqual(
+            collector.connection_string, "https://qbittorrent3.example.com:443/server/"
+        )