From 9adc4ab7bbe52e7a23c5fa762bf30c6ccedf5588 Mon Sep 17 00:00:00 2001 From: Prasanth Viswanadham Date: Sun, 2 Mar 2025 08:40:55 -0500 Subject: [PATCH 01/13] Update requirements and sync files --- requirements.txt | 2 + sync.py | 105 ++++++++++++++++++++++------------------------- 2 files changed, 51 insertions(+), 56 deletions(-) diff --git a/requirements.txt b/requirements.txt index 9a2f608..164fe63 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ requests==2.32.3 PyYAML==6.0.2 +fastapi==0.95.1 +uvicorn==0.22.0 \ No newline at end of file diff --git a/sync.py b/sync.py index 914adac..9a8a8a4 100644 --- a/sync.py +++ b/sync.py @@ -3,6 +3,8 @@ import os import yaml import requests +from pydantic import BaseModel +from fastapi import FastAPI, Request from http.server import BaseHTTPRequestHandler, HTTPServer @@ -23,6 +25,11 @@ LOKI_API_ENDPOINT = os.environ['LOKI_API_ENDPOINT'] LOKI_POST_HEADERS = {"Content-Type": "application/yaml"} +app = FastAPI() + +class StringPayload(BaseModel): + text: str + def create_or_update_alerting_rule_group( rule_namespace, yaml_rule_group_definition, @@ -57,78 +64,64 @@ def get_alerting_rules_in_namespace(rule_namespace,): return yaml.safe_load(response.text)[rule_namespace][0] - -class LokiRuleGroupHandler(BaseHTTPRequestHandler): - def do_POST(self): - content_length = int(self.headers['Content-Length']) - request_body = self.rfile.read(content_length).decode('utf-8') - request_data = json.loads(request_body) - - parent = request_data['parent'] - rule_group = yaml.dump(parent.get('spec', {})) - try: +@app.get("/sync") +def post(request_body: StringPayload): + request_data = json.loads(request_body) + parent = request_data['parent'] + rule_group = yaml.dump(parent.get('spec', {})) + try: rule_group_namespace = request_data['parent']['spec']['name'] - except Exception: + except Exception: status = 'Degraded' logger.exception(f'failed to parse request: {request_data}') - - if self.path.endswith('/finalize'): - # Handle the finalize hook - try: - response = delete_alerting_rule_group( - rule_name=rule_group_namespace, - rule_namespace=rule_group_namespace, - ) - response_data = { - "finalized": response.ok - } - self.send_response(200) - self.send_header('Content-Type', 'application/json') - self.end_headers() - self.wfile.write(json.dumps(response_data).encode('utf-8')) - except Exception: - response_data = { - "finalized": True - } - self.send_response(200) - self.send_header('Content-Type', 'application/json') - self.end_headers() - self.wfile.write(json.dumps(response_data).encode('utf-8')) - logger.warning( - f'failed to delete rule group from request, did it exist?: {request_data}' - ) - - else: - # Sync the object with the external API - try: - response = create_or_update_alerting_rule_group( + try: + response = create_or_update_alerting_rule_group( rule_namespace=rule_group_namespace, yaml_rule_group_definition=rule_group ) # check if rule group was created - if yaml.safe_load(rule_group) == get_alerting_rules_in_namespace( + if yaml.safe_load(rule_group) == get_alerting_rules_in_namespace( rule_namespace=rule_group_namespace - ): + ): status = 'Healthy' - else: + else: status = 'Progressing' - except Exception: + except Exception: status = "Degraded" logger.exception(f'failed to create rule group: {rule_group}') - - - # Prepare the response for Metacontroller - response_data = { + response_data = { 'status': { 'health': { 'status': status }, }, - } + } - self.send_response(200) - self.send_header('Content-Type', 'application/json') - self.end_headers() - self.wfile.write(json.dumps(response_data).encode('utf-8')) + return response_data + +@app.post("/finalize") +def finalize(request_body: StringPayload): + request_data = json.loads(request_body) + parent = request_data['parent'] + rule_group = yaml.dump(parent.get('spec', {})) + try: + rule_group_namespace = request_data['parent']['spec']['name'] + except Exception: + status = 'Degraded' + logger.exception(f'failed to parse request: {request_data}') + try: + response = delete_alerting_rule_group( + rule_name=rule_group_namespace, + rule_namespace=rule_group_namespace, + ) + response_data = { + "finalized": response.ok + } + return {response_data} + except Exception: + response_data = { + "finalized": True + } + return {response_data} + -HTTPServer(("", 80), LokiRuleGroupHandler).serve_forever() From 780a07f84e9b7b65e425e6768f0ab044f2b329e9 Mon Sep 17 00:00:00 2001 From: null Date: Sun, 2 Mar 2025 13:54:30 +0000 Subject: [PATCH 02/13] udpated docker file --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b8367ad..726f140 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,6 @@ COPY ./src ./src RUN pip install -r requirements.txt -CMD ["python", "/app/sync.py"] +#CMD ["python", "/app/sync.py"] + +CMD ["fastapi", "run", "app/sync.py", "--port", "80"] From f03059b0633b2d05cbbba82c117bd348443aa988 Mon Sep 17 00:00:00 2001 From: null Date: Sun, 2 Mar 2025 13:57:11 +0000 Subject: [PATCH 03/13] udpated docker file --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 726f140..3abc539 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ COPY ./requirements.txt . COPY ./sync.py . COPY ./src ./src -RUN pip install -r requirements.txt +RUN pip install --no-cache-dir --upgrade -r /requirements.txt #CMD ["python", "/app/sync.py"] From 5b7fe22e6f4e16f0a84270abc5ce0c4a7eb4e812 Mon Sep 17 00:00:00 2001 From: null Date: Sun, 2 Mar 2025 13:58:13 +0000 Subject: [PATCH 04/13] udpated docker file --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3abc539..6ffbee8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ COPY ./requirements.txt . COPY ./sync.py . COPY ./src ./src -RUN pip install --no-cache-dir --upgrade -r /requirements.txt +RUN pip install --no-cache-dir --upgrade -r requirements.txt #CMD ["python", "/app/sync.py"] From 291bd03936efc262e8ad501580eaf509709616a0 Mon Sep 17 00:00:00 2001 From: null Date: Sun, 2 Mar 2025 14:00:33 +0000 Subject: [PATCH 05/13] udpated docker file --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 6ffbee8..6c4fada 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,7 @@ COPY ./sync.py . COPY ./src ./src RUN pip install --no-cache-dir --upgrade -r requirements.txt +RUN pip install fastapi uvicorn #CMD ["python", "/app/sync.py"] From d3a41441ecd709a02d688eefcc09458ac5587e82 Mon Sep 17 00:00:00 2001 From: Prasanth Viswanadham Date: Sun, 2 Mar 2025 09:07:38 -0500 Subject: [PATCH 06/13] Update requirements and sync files --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6c4fada..30fc3c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,6 @@ COPY ./src ./src RUN pip install --no-cache-dir --upgrade -r requirements.txt RUN pip install fastapi uvicorn -#CMD ["python", "/app/sync.py"] + CMD ["fastapi", "run", "app/sync.py", "--port", "80"] From b5126c35e518b34051a163214a0e5183f4606426 Mon Sep 17 00:00:00 2001 From: Prasanth Viswanadham Date: Sun, 2 Mar 2025 09:13:53 -0500 Subject: [PATCH 07/13] Update requirements and sync files --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 30fc3c5..910503a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,8 +9,8 @@ COPY ./sync.py . COPY ./src ./src RUN pip install --no-cache-dir --upgrade -r requirements.txt -RUN pip install fastapi uvicorn +RUN pip install uvicorn["standard"] - -CMD ["fastapi", "run", "app/sync.py", "--port", "80"] +CMD ["uvicorn", "sync:app", "--host", "0.0.0.0", "--port", "80", "--reload"] +#CMD ["uvicorn", "run", "app/sync.py", "--port", "80"] From 08fe4490506ae42b5ba7d7735993229c10555bd5 Mon Sep 17 00:00:00 2001 From: Prasanth Viswanadham Date: Mon, 3 Mar 2025 11:00:23 -0500 Subject: [PATCH 08/13] Update requirements and sync files --- sync.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync.py b/sync.py index 9a8a8a4..ba08226 100644 --- a/sync.py +++ b/sync.py @@ -64,7 +64,7 @@ def get_alerting_rules_in_namespace(rule_namespace,): return yaml.safe_load(response.text)[rule_namespace][0] -@app.get("/sync") +@app.post("/sync") def post(request_body: StringPayload): request_data = json.loads(request_body) parent = request_data['parent'] From 118dc01a578ed161b92f74983962e862a5eb44d0 Mon Sep 17 00:00:00 2001 From: Prasanth Viswanadham Date: Mon, 3 Mar 2025 11:27:44 -0500 Subject: [PATCH 09/13] Update requirements and sync files --- sync.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sync.py b/sync.py index ba08226..9c9830d 100644 --- a/sync.py +++ b/sync.py @@ -5,7 +5,7 @@ import requests from pydantic import BaseModel from fastapi import FastAPI, Request - +from typing import Dict, Any from http.server import BaseHTTPRequestHandler, HTTPServer from src.json_log_formatter import JsonFormatter @@ -64,8 +64,8 @@ def get_alerting_rules_in_namespace(rule_namespace,): return yaml.safe_load(response.text)[rule_namespace][0] -@app.post("/sync") -def post(request_body: StringPayload): +@app.get("/sync") +def post(request_body: Dict[str, Any]): request_data = json.loads(request_body) parent = request_data['parent'] rule_group = yaml.dump(parent.get('spec', {})) @@ -100,7 +100,7 @@ def post(request_body: StringPayload): return response_data @app.post("/finalize") -def finalize(request_body: StringPayload): +def finalize(request_body: Dict[str, Any]): request_data = json.loads(request_body) parent = request_data['parent'] rule_group = yaml.dump(parent.get('spec', {})) From 6674cd6c8fbd2dca26863b4ad6e0d864ce76ec87 Mon Sep 17 00:00:00 2001 From: Prasanth Viswanadham Date: Mon, 3 Mar 2025 11:34:37 -0500 Subject: [PATCH 10/13] Update requirements and sync files --- sync.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sync.py b/sync.py index 9c9830d..5c229fd 100644 --- a/sync.py +++ b/sync.py @@ -64,7 +64,7 @@ def get_alerting_rules_in_namespace(rule_namespace,): return yaml.safe_load(response.text)[rule_namespace][0] -@app.get("/sync") +@app.post("/sync") def post(request_body: Dict[str, Any]): request_data = json.loads(request_body) parent = request_data['parent'] @@ -117,11 +117,11 @@ def finalize(request_body: Dict[str, Any]): response_data = { "finalized": response.ok } - return {response_data} + return response_data except Exception: response_data = { "finalized": True } - return {response_data} + return response_data From 07ddb81e933da1487256f0298d3987ea5aa3d2cc Mon Sep 17 00:00:00 2001 From: Prasanth Viswanadham Date: Mon, 3 Mar 2025 11:37:33 -0500 Subject: [PATCH 11/13] Update requirements and sync files --- sync.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sync.py b/sync.py index 5c229fd..5292577 100644 --- a/sync.py +++ b/sync.py @@ -65,8 +65,8 @@ def get_alerting_rules_in_namespace(rule_namespace,): @app.post("/sync") -def post(request_body: Dict[str, Any]): - request_data = json.loads(request_body) +def post(request_body:StringPayload): + request_data = json.loads(request_body.text) parent = request_data['parent'] rule_group = yaml.dump(parent.get('spec', {})) try: @@ -100,8 +100,8 @@ def post(request_body: Dict[str, Any]): return response_data @app.post("/finalize") -def finalize(request_body: Dict[str, Any]): - request_data = json.loads(request_body) +def finalize(request_body: StringPayload): + request_data = json.loads(request_body.text) parent = request_data['parent'] rule_group = yaml.dump(parent.get('spec', {})) try: From 896bfbd0ea780841ec246323de83a5e0b3766f3d Mon Sep 17 00:00:00 2001 From: Prasanth Viswanadham Date: Mon, 3 Mar 2025 11:45:35 -0500 Subject: [PATCH 12/13] Update requirements and sync files --- sync.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sync.py b/sync.py index 5292577..9b630ae 100644 --- a/sync.py +++ b/sync.py @@ -65,8 +65,10 @@ def get_alerting_rules_in_namespace(rule_namespace,): @app.post("/sync") -def post(request_body:StringPayload): - request_data = json.loads(request_body.text) +async def post(request: Request): + request_data = await request.json() # Accepts any dynamic JSON payload + #request_data = json.loads(request_body) + print(request_data) parent = request_data['parent'] rule_group = yaml.dump(parent.get('spec', {})) try: From 8838f52dff746193ce77005ce9b0af787c3931b5 Mon Sep 17 00:00:00 2001 From: Prasanth Viswanadham Date: Mon, 3 Mar 2025 11:48:30 -0500 Subject: [PATCH 13/13] Update requirements and sync files --- sync.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sync.py b/sync.py index 9b630ae..294fe7c 100644 --- a/sync.py +++ b/sync.py @@ -102,8 +102,8 @@ async def post(request: Request): return response_data @app.post("/finalize") -def finalize(request_body: StringPayload): - request_data = json.loads(request_body.text) +async def finalize(request: Request): + request_data = await request.json() parent = request_data['parent'] rule_group = yaml.dump(parent.get('spec', {})) try: