From f2cfdf7c01275f1577cd40f82ffb2042b87ebe02 Mon Sep 17 00:00:00 2001 From: Sergio Santiago Date: Tue, 22 Aug 2023 12:40:14 +0200 Subject: [PATCH] Add bad_statuses and state --- .github/workflows/ci.yml | 2 +- samples/config.yaml.template | 6 +++ src/tableau_prometheus_exporter/server.py | 66 ++++++++++++----------- tests/test_server.py | 35 ++++++++---- 4 files changed, 69 insertions(+), 40 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 915911d..fe5c577 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: ref: 'main' fetch-depth: 0 - name: Generate Changelog - uses: sergioasantiago/generate-changelog-action@main + uses: pfandie/generate-changelog-action@v1 id: changelog with: output_file: CHANGELOG.md diff --git a/samples/config.yaml.template b/samples/config.yaml.template index e7cf3bf..2124271 100644 --- a/samples/config.yaml.template +++ b/samples/config.yaml.template @@ -3,6 +3,12 @@ tableau_server_management: username: password: sleep_interval_seconds: <30> + bad_statuses: + - Unlicensed + - Degraded + - Error + - Stopped + - Status Unavailable metrics: port: <8000> diff --git a/src/tableau_prometheus_exporter/server.py b/src/tableau_prometheus_exporter/server.py index 3002c86..1c34297 100644 --- a/src/tableau_prometheus_exporter/server.py +++ b/src/tableau_prometheus_exporter/server.py @@ -20,36 +20,47 @@ "service_name", "instance_id", "status", + "state", ], ) -def parse(status: Dict) -> None: - """ - Parse Tableau Server Management Status and export as Prometheus Gauge - - :return: None - """ - - GAUGE_TABLEAU_SERVICE_STATUS.clear() - - for node in status.get("clusterStatus", {}).get("nodes", []): - for service in node.get("services", []): - for instance in service.get("instances", []): - GAUGE_TABLEAU_SERVICE_STATUS.labels( - node.get("nodeId", ""), - service.get("serviceName", ""), - instance.get("instanceId", ""), - instance.get("processStatus", ""), - ).set(1) - - class Server: def __init__(self, config: Dict): - self.config = config + self.tsm_config = config["tableau_server_management"] + self.metrics_port = config["metrics"].get("metrics_port", DEFAULT_METRICS_PORT) + self.sleep_interval = self.tsm_config.get( + "sleep_interval_seconds", DEFAULT_SLEEP_INTERVAL_SECONDS + ) + self.bad_statuses = self.tsm_config.get("bad_statuses", []) RUNNING = True + def parse(self, status: Dict) -> None: + """ + Parse Tableau Server Management Status and export as Prometheus Gauge + + :return: None + """ + + GAUGE_TABLEAU_SERVICE_STATUS.clear() + + for node in status.get("clusterStatus", {}).get("nodes", []): + for service in node.get("services", []): + for instance in service.get("instances", []): + value = ( + 0 + if instance.get("processStatus", "") in self.bad_statuses + else 1 + ) + GAUGE_TABLEAU_SERVICE_STATUS.labels( + node.get("nodeId", ""), + service.get("serviceName", ""), + instance.get("instanceId", ""), + instance.get("processStatus", ""), + instance.get("currentDeploymentState", ""), + ).set(value) + def start_and_run_forever(self) -> None: """ Start up the server to expose the metrics. @@ -60,15 +71,10 @@ def start_and_run_forever(self) -> None: """ _logger.info("Starting Metrics Server...") - metrics_port = self.config["metrics"].get("metrics_port", DEFAULT_METRICS_PORT) - sleep_interval = self.config["tableau_server_management"].get( - "sleep_interval_seconds", DEFAULT_SLEEP_INTERVAL_SECONDS - ) - - start_http_server(port=metrics_port) + start_http_server(port=self.metrics_port) while self.RUNNING: - with TableauSession(self.config) as session: + with TableauSession(self.tsm_config) as session: status = session.status() - parse(status) + self.parse(status) - time.sleep(sleep_interval) + time.sleep(self.sleep_interval) diff --git a/tests/test_server.py b/tests/test_server.py index 518b365..aa2f444 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -2,11 +2,7 @@ from unittest.mock import PropertyMock import tableau_prometheus_exporter -from tableau_prometheus_exporter.server import ( - DEFAULT_SLEEP_INTERVAL_SECONDS, - Server, - parse, -) +from tableau_prometheus_exporter.server import DEFAULT_SLEEP_INTERVAL_SECONDS, Server MOCK_CONFIG = { "metrics": {"port": 1234}, @@ -14,6 +10,7 @@ "host": "http://test.local", "username": "test", "password": "test", + "bad_statuses": ["error"], }, } @@ -26,7 +23,16 @@ { "serviceName": "service1", "instances": [ - {"instanceId": "instance1", "processStatus": "running"} + { + "instanceId": "instance1", + "processStatus": "running", + "currentDeploymentState": "enabled", + }, + { + "instanceId": "instance2", + "processStatus": "error", + "currentDeploymentState": "enabled", + }, ], } ], @@ -44,7 +50,6 @@ def test_start_and_run_forever(mocker): mock_manager.status.return_value = {} mocker.patch("requests.Session", return_value=mocker.MagicMock()) mocker.patch("tableau_prometheus_exporter.server.start_http_server") - mocker.patch("tableau_prometheus_exporter.server.parse") mocker.patch("time.sleep") server = Server(MOCK_CONFIG) @@ -60,12 +65,11 @@ def test_start_and_run_forever(mocker): tableau_prometheus_exporter.server.start_http_server.assert_called_once() mock_tableau_session.assert_called_once_with(MOCK_CONFIG) mock_manager.status.assert_called_once() - tableau_prometheus_exporter.server.parse.assert_called_once() time.sleep.assert_called_with(DEFAULT_SLEEP_INTERVAL_SECONDS) def test_parse_method(): - parse(MOCK_STATUS) + Server(MOCK_CONFIG).parse(MOCK_STATUS) metric_samples = list( tableau_prometheus_exporter.server.GAUGE_TABLEAU_SERVICE_STATUS.collect() @@ -80,5 +84,18 @@ def test_parse_method(): "service_name": "service1", "instance_id": "instance1", "status": "running", + "state": "enabled", } assert sample.value == 1.0 + + sample = metric_samples[1] + + assert sample.name == "tableau_service_status" + assert sample.labels == { + "node_id": "node1", + "service_name": "service1", + "instance_id": "instance2", + "status": "error", + "state": "enabled", + } + assert sample.value == 0.0