From 9a0a1b62e1c41406f28c0616a03511c9feea97ca Mon Sep 17 00:00:00 2001 From: Joao Mario Lago Date: Thu, 16 May 2024 12:45:03 -0300 Subject: [PATCH] kraken: main: Change main to use new API module --- .../kraken/api/v1/routers/extension.py | 1 + core/services/kraken/api/v1/routers/index.py | 1 + .../kraken/api/v2/routers/manifest.py | 1 + core/services/kraken/kraken.py | 2 - core/services/kraken/main.py | 164 +----------------- 5 files changed, 9 insertions(+), 160 deletions(-) diff --git a/core/services/kraken/api/v1/routers/extension.py b/core/services/kraken/api/v1/routers/extension.py index 98c6923a91..341f721799 100644 --- a/core/services/kraken/api/v1/routers/extension.py +++ b/core/services/kraken/api/v1/routers/extension.py @@ -15,6 +15,7 @@ responses={status.HTTP_404_NOT_FOUND: {"description": "Not found"}}, ) + @extension_router_v1.post("/install", status_code=status.HTTP_201_CREATED) async def install_extension(extension: Extension) -> Any: if not extension.is_valid(): diff --git a/core/services/kraken/api/v1/routers/index.py b/core/services/kraken/api/v1/routers/index.py index 83dcd42baf..abc665b0a1 100644 --- a/core/services/kraken/api/v1/routers/index.py +++ b/core/services/kraken/api/v1/routers/index.py @@ -14,6 +14,7 @@ responses={status.HTTP_404_NOT_FOUND: {"description": "Not found"}}, ) + @index_router_v1.get("/extensions_manifest", status_code=status.HTTP_200_OK) async def fetch_manifest() -> Any: return await kraken_instance.fetch_manifest() diff --git a/core/services/kraken/api/v2/routers/manifest.py b/core/services/kraken/api/v2/routers/manifest.py index be7f0df920..b2d8390aeb 100644 --- a/core/services/kraken/api/v2/routers/manifest.py +++ b/core/services/kraken/api/v2/routers/manifest.py @@ -9,6 +9,7 @@ responses={status.HTTP_404_NOT_FOUND: {"description": "Not found"}}, ) + @manifest_router_v2.get("/", status_code=status.HTTP_200_OK) async def fetch(_data: bool = True) -> Response: """ diff --git a/core/services/kraken/kraken.py b/core/services/kraken/kraken.py index 319c721d6c..8c0a1f6e88 100644 --- a/core/services/kraken/kraken.py +++ b/core/services/kraken/kraken.py @@ -371,6 +371,4 @@ async def stop(self) -> None: self.should_run = False -# Global Kraken control instance - kraken_instance = Kraken() diff --git a/core/services/kraken/main.py b/core/services/kraken/main.py index e2e26d6eb5..14082d7a21 100755 --- a/core/services/kraken/main.py +++ b/core/services/kraken/main.py @@ -2,170 +2,18 @@ import argparse import asyncio import logging -from typing import Any, Iterable -from commonwealth.utils.apis import GenericErrorHandlingRoute from commonwealth.utils.logs import InterceptHandler, init_logger -from commonwealth.utils.streaming import streamer, timeout_streamer -from fastapi import FastAPI, HTTPException, status -from fastapi.responses import HTMLResponse, PlainTextResponse, StreamingResponse -from fastapi_versioning import VersionedFastAPI, version from loguru import logger -from pydantic import BaseModel from uvicorn import Config, Server -from kraken import Kraken - - -class Extension(BaseModel): - name: str - docker: str - tag: str - permissions: str - enabled: bool - identifier: str - user_permissions: str - - def is_valid(self) -> bool: - return all([self.name, self.docker, self.tag, any([self.permissions, self.user_permissions]), self.identifier]) - - -SERVICE_NAME = "kraken" +from api import application +from config import SERVICE_NAME logging.basicConfig(handlers=[InterceptHandler()], level=0) init_logger(SERVICE_NAME) -kraken = Kraken() - -app = FastAPI( - title="Kraken API", - description="Kraken is the BlueOS service responsible for installing and managing thirdy-party extensions.", -) -app.router.route_class = GenericErrorHandlingRoute -logger.info("Releasing the Kraken!") - - -@app.get("/extensions_manifest", status_code=status.HTTP_200_OK) -@version(1, 0) -async def fetch_manifest() -> Any: - return await kraken.fetch_manifest() - - -@app.get("/installed_extensions", status_code=status.HTTP_200_OK) -@version(1, 0) -async def get_installed_extensions() -> Any: - extensions = await kraken.get_configured_extensions() - extensions_list = [ - Extension( - identifier=extension.identifier, - name=extension.name, - docker=extension.docker, - tag=extension.tag, - permissions=extension.permissions, - enabled=extension.enabled, - user_permissions=extension.user_permissions, - ) - for extension in extensions - ] - extensions_list.sort(key=lambda extension: extension.name) - return extensions_list - - -@app.post("/extension/install", status_code=status.HTTP_201_CREATED) -@version(1, 0) -async def install_extension(extension: Extension) -> Any: - if not extension.is_valid(): - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Invalid extension description", - ) - if not kraken.has_enough_disk_space(): - raise HTTPException( - status_code=status.HTTP_507_INSUFFICIENT_STORAGE, - detail="Not enough disk space to install the extension", - ) - compatible_digest = await kraken.is_compatible_extension(extension.identifier, extension.tag) - # Throw an exception only if compatible_digest is False, indicating the extension is in the manifest but it is - # incompatible. If compatible_digest is None, we are going to trusty that the image is compatible and will work - if compatible_digest is False: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Extension is not compatible with the current machine running BlueOS.", - ) - return StreamingResponse(streamer(kraken.install_extension(extension, compatible_digest))) - - -@app.post("/extension/update_to_version", status_code=status.HTTP_201_CREATED) -@version(1, 0) -async def update_extension(extension_identifier: str, new_version: str) -> Any: - return StreamingResponse(streamer(kraken.update_extension_to_version(extension_identifier, new_version))) - - -@app.post("/extension/uninstall", status_code=status.HTTP_200_OK) -@version(1, 0) -async def uninstall_extension(extension_identifier: str) -> Any: - return await kraken.uninstall_extension_from_identifier(extension_identifier) - - -@app.post("/extension/enable", status_code=status.HTTP_200_OK) -@version(1, 0) -async def enable_extension(extension_identifier: str) -> Any: - return await kraken.enable_extension(extension_identifier) - - -@app.post("/extension/disable", status_code=status.HTTP_200_OK) -@version(1, 0) -async def disable_extension(extension_identifier: str) -> Any: - return await kraken.disable_extension(extension_identifier) - - -@app.post("/extension/restart", status_code=status.HTTP_202_ACCEPTED) -@version(1, 0) -async def restart_extension(extension_identifier: str) -> Any: - return await kraken.restart_extension(extension_identifier) - - -@app.get("/list_containers", status_code=status.HTTP_200_OK) -@version(1, 0) -async def list_containers() -> Any: - containers = await kraken.list_containers() - return [ - { - "name": container["Names"][0], - "image": container["Image"], - "imageId": container["ImageID"], - "status": container["Status"], - } - for container in containers - ] - - -@app.get("/log", status_code=status.HTTP_200_OK, response_class=PlainTextResponse) -@version(1, 0) -async def log_containers(container_name: str) -> Iterable[bytes]: - return StreamingResponse(timeout_streamer(kraken.stream_logs(container_name)), media_type="text/plain") # type: ignore - - -@app.get("/stats", status_code=status.HTTP_200_OK) -@version(1, 0) -async def load_stats() -> Any: - return await kraken.load_stats() - - -app = VersionedFastAPI(app, version="1.0.0", prefix_format="/v{major}.{minor}", enable_latest=True) - - -@app.get("/") -async def root() -> Any: - html_content = """ - - - Kraken - - - """ - return HTMLResponse(content=html_content, status_code=200) - +from kraken import kraken_instance if __name__ == "__main__": parser = argparse.ArgumentParser() @@ -179,9 +27,9 @@ async def root() -> Any: loop = asyncio.new_event_loop() - config = Config(app=app, loop=loop, host="0.0.0.0", port=9134, log_config=None) + config = Config(app=application, loop=loop, host="0.0.0.0", port=9134, log_config=None) server = Server(config) - loop.create_task(kraken.run()) + loop.create_task(kraken_instance.run()) loop.run_until_complete(server.serve()) - loop.run_until_complete(kraken.stop()) + loop.run_until_complete(kraken_instance.stop())