#!/usr/bin/python3 from abc import ABCMeta import tornado.web import os import subprocess from datetime import datetime import isodate import json import util from auth import AuthProvider from gitmgr import GitManagerConfiguration, GitManager startup_timestamp = datetime.now() class AuthenticatedHandler(tornado.web.RequestHandler, metaclass=ABCMeta): # noinspection PyAttributeOutsideInit def initialize(self, auth_provider=None): self.auth_provider = auth_provider def prepare(self): if self.auth_provider is None: return # check authentication auth_hdr = "Authentication" if auth_hdr not in self.request.headers: raise tornado.web.HTTPError(401, reason="authentication not provided") tk = self.request.headers[auth_hdr] if not self.auth_provider.validate_token(tk): raise tornado.web.HTTPError(403, reason="invalid authentication token provided") class HealthHandler(tornado.web.RequestHandler, metaclass=ABCMeta): # noinspection PyAttributeOutsideInit def initialize(self, sources=None): self.git_version = self._load_git_version() self.sources = sources @staticmethod def _load_git_version(): v = None # try file git-version.txt first gitversion_file = "git-version.txt" if os.path.exists(gitversion_file): with open(gitversion_file) as f: v = f.readline().strip() # if not available, try git if v is None: try: v = subprocess.check_output(["git", "describe", "--always", "--dirty"], cwd=os.path.dirname(__file__)).strip().decode() except subprocess.CalledProcessError as e: print("Checking git version lead to non-null return code ", e.returncode) return v def get(self): health = dict() health['api-version'] = 'v0' if self.git_version is not None: health['git-version'] = self.git_version health['timestamp'] = isodate.datetime_isoformat(datetime.now()) health['uptime'] = isodate.duration_isoformat(datetime.now() - startup_timestamp) if self.sources: for s in self.sources: h = s() if h is not None: health = {**health, **h} self.set_header("Content-Type", "application/json") self.write(json.dumps(health, indent=4)) self.set_status(200) class Oas3Handler(tornado.web.RequestHandler, metaclass=ABCMeta): def get(self): self.set_header("Content-Type", "text/plain") # This is the proposed content type, # but browsers like Firefox try to download instead of display the content # self.set_header("Content-Type", "text/vnd.yml") with open('OAS3.yml', 'r') as f: oas3 = f.read() self.write(oas3) self.finish() class AllEntitiesHandler(AuthenticatedHandler, metaclass=ABCMeta): # noinspection PyAttributeOutsideInit def initialize(self, auth_provider=None): super().initialize(auth_provider) def post(self): pass def get(self): pass class SingleEntityHandler(AuthenticatedHandler, metaclass=ABCMeta): # noinspection PyAttributeOutsideInit def initialize(self, auth_provider=None): super().initialize(auth_provider) def post(self, identifier): pass def get(self, identifier): pass def make_app(_auth_provider=None, gitmgr=None): version_path = r"/v[0-9]" return tornado.web.Application([ (version_path + r"/health", HealthHandler, {"sources": [lambda: {"git-head": gitmgr.head_sha}] if gitmgr else None}), (version_path + r"/oas3", Oas3Handler), (version_path + r"/entities", AllEntitiesHandler, {"auth_provider": _auth_provider}), (version_path + r"/entity/{.*}", SingleEntityHandler, {"auth_provider": _auth_provider}), ]) def main(): port = util.load_env('PORT', 8080) # Setup auth_provider = AuthProvider.from_environment() gitcfg = GitManagerConfiguration.from_environment() gitmgr = GitManager(configuration=gitcfg) gitmgr.setup() gitmgr.printout() util.run_tornado_server(make_app(auth_provider, gitmgr), server_port=port) # Teardown gitmgr.teardown() print("Server stopped") if __name__ == "__main__": main()