@@ -64,6 +64,8 @@ def __init__(self):
6464 self .db_host = os .getenv ("SCM_DB_HOST" , "localhost" )
6565 self .db_port = os .getenv ("SCM_DB_PORT" , 5432 )
6666 self .db_user = os .getenv ("SCM_DB_USER" , "postgres" )
67+ self .hc_user = os .getenv ("SCM_HC_USER" , "healthz" )
68+ self .hc_password = os .getenv ("SCM_HC_PASSWORD" , "healthzpassword" )
6769 password_file_path = os .getenv ("SCM_DB_PASSWORD_FILE" , None )
6870 if password_file_path :
6971 with open (os .path .abspath (password_file_path ), "r" ) as fileobj :
@@ -123,6 +125,7 @@ class ViewType(Enum):
123125# do I hate these globals, but I don't see another way with these frameworks
124126app = FastAPI ()
125127security = HTTPBasic (realm = "Compliance monitor" , auto_error = True ) # use False for optional login
128+ optional_security = HTTPBasic (realm = "Compliance monitor" , auto_error = False )
126129settings = Settings ()
127130# see https://passlib.readthedocs.io/en/stable/narr/quickstart.html
128131cryptctx = CryptContext (
@@ -719,6 +722,39 @@ async def post_results(
719722 conn .commit ()
720723
721724
725+ @app .get ("/healthz" )
726+ async def get_healthz (
727+ request : Request ,
728+ ):
729+ """return monitor's health status"""
730+ credentials = await optional_security (request )
731+
732+ # check credentials
733+ if credentials is None :
734+ # no credentials were set
735+ check_db_connection ()
736+ elif credentials .username == settings .hc_user and credentials .password == settings .hc_password :
737+ # healthz user
738+ check_db_connection (authorized = True )
739+ else :
740+ # unauthorized user
741+ check_db_connection ()
742+
743+ return {"message" : "OK" }
744+
745+ def check_db_connection (authorized : bool = False ):
746+ # check database connection
747+ try :
748+ mk_conn (settings = settings )
749+ except psycopg2 .OperationalError as e :
750+ if authorized :
751+ # authorized user
752+ raise HTTPException (status_code = 500 ,
753+ detail = "Database Connection Error. " + e .args [0 ].capitalize ())
754+ else :
755+ raise HTTPException (status_code = 500 , detail = "Internal Server Error" )
756+
757+
722758def pick_filter (results , subject , scope ):
723759 """Jinja filter to pick scope results from `results` for given `subject` and `scope`"""
724760 return results .get (subject , {}).get (scope , {})
0 commit comments