From db656f8ef2e972ba492b6e51f28aa3b0ae1729b9 Mon Sep 17 00:00:00 2001 From: Lukas Juozas Janusaitis Date: Sun, 3 Dec 2023 22:17:50 +0200 Subject: [PATCH] Add base action functionality --- .github/workflows/ci.yml | 24 +++++++++++++++++++++++ Dockerfile | 7 +++++++ README.md | 13 ++++++++++++- action.yml | 32 ++++++++++++++++++++++++++++++ requirements.txt | 1 + validate.py | 42 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml create mode 100644 Dockerfile create mode 100644 action.yml create mode 100644 requirements.txt create mode 100644 validate.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2ecb177 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,24 @@ +name: Test metricsure +on: [push] +jobs: + metricsure: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Run metricsure + id: metricsure + uses: ./ + with: + endpoint: 'https://prometheus.demo.do.prometheus.io' + metric: 'prometheus_remote_storage_exemplars_in_total' + label: 'instance' + values: 'demo.do.prometheus.io:9100,demo.do.prometheus.io:9090,http://localhost:9100' + + - name: send message + uses: appleboy/discord-action@v1.0.0 + with: + webhook_id: ${{ secrets.WEBHOOK_ID }} + webhook_token: ${{ secrets.WEBHOOK_TOKEN }} + message: "Metrics are not available for:\n`${{steps.metricsure.outputs.invalid_values}}`" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b4ef7fa --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.9-slim + +COPY * . + +RUN pip install --no-cache-dir -r requirements.txt + +CMD ["python", "validate.py"] diff --git a/README.md b/README.md index b378450..615d0fb 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ +[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) +[![Star on GitHub](https://img.shields.io/github/stars/LukoJy3D/metricsure.svg?style=social)](https://github.com/LukoJy3D/metricsure/stargazers) + # metricsure -Boost data integrity with a tool for validating metrics' existence for specified instances. + +Simple github action to validate metric existence with specific labels and values against prometheus like endpoint. + +## Inputs + +`endpoint` - Prometheus like endpoint to query metrics from. +`metric` - Metric name to query. (Currently only supports single metric) +`label` - Label name to query. (Currently only supports single label) +`values` - Label values to query. diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..16386a3 --- /dev/null +++ b/action.yml @@ -0,0 +1,32 @@ +name: "Metric existence check" +description: "Validate metric existence using python script quering against prometheus endpoint" +branding: + color: blue + icon: check-circle + +inputs: + endpoint: + description: "Prometheus endpoint URL" + required: true + metric: + description: "Prometheus metric to check" + required: true + label: + description: "Label associated with the metric" + required: true + values: + description: "Comma seperated list of values to check against" + required: false + +outputs: + invalid_values: + description: "Values that were not present in the metric check" + +runs: + using: "docker" + image: "Dockerfile" + env: + ENDPOINT: ${{ inputs.endpoint }} + METRIC: ${{ inputs.metric }} + LABEL: ${{ inputs.label }} + VALUES: ${{ inputs.values }} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4f5b899 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +requests==2.26.0 \ No newline at end of file diff --git a/validate.py b/validate.py new file mode 100644 index 0000000..c95c906 --- /dev/null +++ b/validate.py @@ -0,0 +1,42 @@ +import requests +from datetime import datetime, timedelta +import logging +import os + +endpoint = os.environ.get('ENDPOINT') +metric = os.environ.get('METRIC') +label = os.environ.get('LABEL') +values = os.environ.get('VALUES', '') + +def query_prometheus(endpoint, metric, label, label_value): + end_time = datetime.utcnow() + start_time = end_time - timedelta(days=1) + + start_str = start_time.strftime('%Y-%m-%dT%H:%M:%SZ') + end_str = end_time.strftime('%Y-%m-%dT%H:%M:%SZ') + + query = f'{metric}{{{label}="{label_value}"}}' + url = f'{endpoint}/api/v1/query_range?query={query}&start={start_str}&end={end_str}&step=1m' + + response = requests.get(url) + + if 'result' in response.json()['data'] and response.json()['data']['result'] and 'values' in response.json()['data']['result'][0]: + logging.info(f'Metric {metric} with {label}="{label_value}" exists in the last 24 hours.') + return True + else: + logging.error(f'Metric {metric} with {label}="{label_value}" not found in the last 24 hours.') + return False + +label_values = [value.strip() for value in values.split(',') if value.strip()] +label_value_pair_with_no_metrics = [] + +for label_value in label_values: + if not query_prometheus(endpoint, metric, label, label_value): + label_value_pair_with_no_metrics.append(label_value) + +if label_value_pair_with_no_metrics: + invalid_values = ','.join(label_value_pair_with_no_metrics) + with open(os.environ['GITHUB_OUTPUT'], 'a') as fh: + print(f'invalid_values={invalid_values}', file=fh) +else: + print("All instances have metrics in the last 24 hours.") \ No newline at end of file