From 03524bed5e19c5f6f46eaa6a9db3c97d90449c87 Mon Sep 17 00:00:00 2001 From: Tero Virtanen Date: Mon, 30 Sep 2024 14:58:06 +0300 Subject: [PATCH 1/3] chore: heatlhz return status json --- atv/__init__.py | 1 + atv/settings.py | 10 ++++++++- atv/urls.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/atv/__init__.py b/atv/__init__.py index e69de29..0058b93 100644 --- a/atv/__init__.py +++ b/atv/__init__.py @@ -0,0 +1 @@ +__version__ = "1.0.1" \ No newline at end of file diff --git a/atv/settings.py b/atv/settings.py index b3b28c4..245612e 100644 --- a/atv/settings.py +++ b/atv/settings.py @@ -4,6 +4,7 @@ import environ import sentry_sdk from corsheaders.defaults import default_headers +from datetime import datetime from django.core.exceptions import ImproperlyConfigured from sentry_sdk.integrations.django import DjangoIntegration @@ -65,11 +66,11 @@ TOKEN_AUTH_REQUIRE_SCOPE=(bool, False), TOKEN_AUTH_AUTHSERVER_URL=(str, ""), CLAMAV_HOST=(str, "atv-clamav"), + OPENSHIFT_BUILD_COMMIT=(str, ""), ) if os.path.exists(env_file): env.read_env(env_file) - VERSION = env("VERSION") if VERSION is None: try: @@ -282,3 +283,10 @@ # Malware Protection CLAMAV_HOST = env("CLAMAV_HOST") + + +# get build time from a file in docker image +APP_BUILDTIME = datetime.fromtimestamp(os.path.getmtime(__file__)) + +# get build commit from Openshift variable +BUILD_COMMIT = env("OPENSHIFT_BUILD_COMMIT") diff --git a/atv/urls.py b/atv/urls.py index d6002ea..82c1f9d 100644 --- a/atv/urls.py +++ b/atv/urls.py @@ -1,6 +1,11 @@ +import pyclamd +import threading +import time +from atv import __version__ from django.conf import settings from django.contrib import admin -from django.http import HttpResponse +from django.db import connection +from django.http import HttpResponse, JsonResponse from django.urls import include, path from drf_spectacular.views import ( SpectacularAPIView, @@ -68,10 +73,57 @@ # Kubernetes liveness & readiness probes # +# Global variable to store the health check results +health_status = { + "db": {"message": "Initializing"}, + "clamav": {"message": "Initializing"} +} + +def check_db_connection(): + global health_status + while True: + try: + with connection.cursor() as cursor: + cursor.execute("SELECT 1") + health_status["db"] = {"message": "OK"} + except Exception as ex: + health_status["db"] = {"error": str(ex)} + time.sleep(30) # Sleep for 0.5 minutes + +def check_clamav_connection(): + global health_status + while True: + try: + cd = pyclamd.ClamdNetworkSocket(host=settings.CLAMAV_HOST) + cd.ping() + health_status["clamav"] = {"message": "OK"} + except Exception as ex: + health_status["clamav"] = {"error": str(ex)} + time.sleep(30) # Sleep for 0.5 minutes + +# Start the health check threads +threading.Thread(target=check_db_connection, daemon=True).start() +threading.Thread(target=check_clamav_connection, daemon=True).start() def healthz(*args, **kwargs): - return HttpResponse(status=200) + response_data = { + "packageVersion": __version__, + "commitHash": settings.BUILD_COMMIT, + "buildTime": settings.APP_BUILDTIME, + "status": { + "message": {}, + "error": {} + } + } + + for key, status in health_status.items(): + if "message" in status and status["message"] == "OK": + response_data["status"]["message"][key] = status["message"] + else: + response_data["status"]["error"][key] = status.get("error", "Unknown error") + status_code = 200 if all("message" in status and status["message"] == "OK" for status in health_status.values()) else 250 + return JsonResponse(response_data, status=status_code) def readiness(*args, **kwargs): return HttpResponse(status=200) From ca761225023ca1b68fa9203128ca1c968be29c3a Mon Sep 17 00:00:00 2001 From: Tero Virtanen Date: Mon, 30 Sep 2024 15:01:02 +0300 Subject: [PATCH 2/3] chore: healthz check connections every 5 min --- atv/urls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atv/urls.py b/atv/urls.py index 82c1f9d..e70dada 100644 --- a/atv/urls.py +++ b/atv/urls.py @@ -88,7 +88,7 @@ def check_db_connection(): health_status["db"] = {"message": "OK"} except Exception as ex: health_status["db"] = {"error": str(ex)} - time.sleep(30) # Sleep for 0.5 minutes + time.sleep(300) # Sleep for 5 minutes def check_clamav_connection(): global health_status @@ -99,7 +99,7 @@ def check_clamav_connection(): health_status["clamav"] = {"message": "OK"} except Exception as ex: health_status["clamav"] = {"error": str(ex)} - time.sleep(30) # Sleep for 0.5 minutes + time.sleep(300) # Sleep for 5 minutes # Start the health check threads threading.Thread(target=check_db_connection, daemon=True).start() From be02260cf4328b0fa753073a138f4d731713691c Mon Sep 17 00:00:00 2001 From: Tero Virtanen Date: Tue, 1 Oct 2024 07:16:28 +0300 Subject: [PATCH 3/3] chore: coding style fixes --- atv/__init__.py | 2 +- atv/settings.py | 2 +- atv/urls.py | 26 ++++++++++++++++++-------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/atv/__init__.py b/atv/__init__.py index 0058b93..5c4105c 100644 --- a/atv/__init__.py +++ b/atv/__init__.py @@ -1 +1 @@ -__version__ = "1.0.1" \ No newline at end of file +__version__ = "1.0.1" diff --git a/atv/settings.py b/atv/settings.py index 245612e..56c16e7 100644 --- a/atv/settings.py +++ b/atv/settings.py @@ -1,10 +1,10 @@ import os import subprocess +from datetime import datetime import environ import sentry_sdk from corsheaders.defaults import default_headers -from datetime import datetime from django.core.exceptions import ImproperlyConfigured from sentry_sdk.integrations.django import DjangoIntegration diff --git a/atv/urls.py b/atv/urls.py index e70dada..5963362 100644 --- a/atv/urls.py +++ b/atv/urls.py @@ -1,7 +1,7 @@ -import pyclamd import threading import time -from atv import __version__ + +import pyclamd from django.conf import settings from django.contrib import admin from django.db import connection @@ -14,6 +14,7 @@ ) from rest_framework_extensions.routers import ExtendedSimpleRouter +from atv import __version__ from documents.api import AttachmentViewSet, DocumentViewSet from documents.api.viewsets import ( DocumentMetadataViewSet, @@ -76,9 +77,10 @@ # Global variable to store the health check results health_status = { "db": {"message": "Initializing"}, - "clamav": {"message": "Initializing"} + "clamav": {"message": "Initializing"}, } + def check_db_connection(): global health_status while True: @@ -90,6 +92,7 @@ def check_db_connection(): health_status["db"] = {"error": str(ex)} time.sleep(300) # Sleep for 5 minutes + def check_clamav_connection(): global health_status while True: @@ -101,19 +104,18 @@ def check_clamav_connection(): health_status["clamav"] = {"error": str(ex)} time.sleep(300) # Sleep for 5 minutes + # Start the health check threads threading.Thread(target=check_db_connection, daemon=True).start() threading.Thread(target=check_clamav_connection, daemon=True).start() + def healthz(*args, **kwargs): response_data = { "packageVersion": __version__, "commitHash": settings.BUILD_COMMIT, "buildTime": settings.APP_BUILDTIME, - "status": { - "message": {}, - "error": {} - } + "status": {"message": {}, "error": {}}, } for key, status in health_status.items(): @@ -122,9 +124,17 @@ def healthz(*args, **kwargs): else: response_data["status"]["error"][key] = status.get("error", "Unknown error") - status_code = 200 if all("message" in status and status["message"] == "OK" for status in health_status.values()) else 250 + status_code = ( + 200 + if all( + "message" in status and status["message"] == "OK" + for status in health_status.values() + ) + else 200 + ) return JsonResponse(response_data, status=status_code) + def readiness(*args, **kwargs): return HttpResponse(status=200)