#!/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 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): self.git_version = self._load_git_version() @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) 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 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): version_path = r"/v[0-9]" return tornado.web.Application([ (version_path + r"/health", HealthHandler), (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() util.run_tornado_server(make_app(auth_provider), server_port=port) # Teardown print("Server stopped") if __name__ == "__main__": main()