2
2
import argparse
3
3
import asyncio
4
4
import logging
5
- from typing import Any , Iterable
6
5
7
- from commonwealth .utils .apis import GenericErrorHandlingRoute
8
6
from commonwealth .utils .logs import InterceptHandler , init_logger
9
- from commonwealth .utils .streaming import streamer , timeout_streamer
10
- from fastapi import FastAPI , HTTPException , status
11
- from fastapi .responses import HTMLResponse , PlainTextResponse , StreamingResponse
12
- from fastapi_versioning import VersionedFastAPI , version
13
7
from loguru import logger
14
- from pydantic import BaseModel
15
8
from uvicorn import Config , Server
16
9
17
- from kraken import Kraken
18
-
19
-
20
- class Extension (BaseModel ):
21
- name : str
22
- docker : str
23
- tag : str
24
- permissions : str
25
- enabled : bool
26
- identifier : str
27
- user_permissions : str
28
-
29
- def is_valid (self ) -> bool :
30
- return all ([self .name , self .docker , self .tag , any ([self .permissions , self .user_permissions ]), self .identifier ])
31
-
32
-
33
- SERVICE_NAME = "kraken"
10
+ from api import application
11
+ from config import SERVICE_NAME
34
12
35
13
logging .basicConfig (handlers = [InterceptHandler ()], level = 0 )
36
14
init_logger (SERVICE_NAME )
37
15
38
- kraken = Kraken ()
39
-
40
- app = FastAPI (
41
- title = "Kraken API" ,
42
- description = "Kraken is the BlueOS service responsible for installing and managing thirdy-party extensions." ,
43
- )
44
- app .router .route_class = GenericErrorHandlingRoute
45
- logger .info ("Releasing the Kraken!" )
46
-
47
-
48
- @app .get ("/extensions_manifest" , status_code = status .HTTP_200_OK )
49
- @version (1 , 0 )
50
- async def fetch_manifest () -> Any :
51
- return await kraken .fetch_manifest ()
52
-
53
-
54
- @app .get ("/installed_extensions" , status_code = status .HTTP_200_OK )
55
- @version (1 , 0 )
56
- async def get_installed_extensions () -> Any :
57
- extensions = await kraken .get_configured_extensions ()
58
- extensions_list = [
59
- Extension (
60
- identifier = extension .identifier ,
61
- name = extension .name ,
62
- docker = extension .docker ,
63
- tag = extension .tag ,
64
- permissions = extension .permissions ,
65
- enabled = extension .enabled ,
66
- user_permissions = extension .user_permissions ,
67
- )
68
- for extension in extensions
69
- ]
70
- extensions_list .sort (key = lambda extension : extension .name )
71
- return extensions_list
72
-
73
-
74
- @app .post ("/extension/install" , status_code = status .HTTP_201_CREATED )
75
- @version (1 , 0 )
76
- async def install_extension (extension : Extension ) -> Any :
77
- if not extension .is_valid ():
78
- raise HTTPException (
79
- status_code = status .HTTP_400_BAD_REQUEST ,
80
- detail = "Invalid extension description" ,
81
- )
82
- if not kraken .has_enough_disk_space ():
83
- raise HTTPException (
84
- status_code = status .HTTP_507_INSUFFICIENT_STORAGE ,
85
- detail = "Not enough disk space to install the extension" ,
86
- )
87
- compatible_digest = await kraken .is_compatible_extension (extension .identifier , extension .tag )
88
- # Throw an exception only if compatible_digest is False, indicating the extension is in the manifest but it is
89
- # incompatible. If compatible_digest is None, we are going to trusty that the image is compatible and will work
90
- if compatible_digest is False :
91
- raise HTTPException (
92
- status_code = status .HTTP_400_BAD_REQUEST ,
93
- detail = "Extension is not compatible with the current machine running BlueOS." ,
94
- )
95
- return StreamingResponse (streamer (kraken .install_extension (extension , compatible_digest )))
96
-
97
-
98
- @app .post ("/extension/update_to_version" , status_code = status .HTTP_201_CREATED )
99
- @version (1 , 0 )
100
- async def update_extension (extension_identifier : str , new_version : str ) -> Any :
101
- return StreamingResponse (streamer (kraken .update_extension_to_version (extension_identifier , new_version )))
102
-
103
-
104
- @app .post ("/extension/uninstall" , status_code = status .HTTP_200_OK )
105
- @version (1 , 0 )
106
- async def uninstall_extension (extension_identifier : str ) -> Any :
107
- return await kraken .uninstall_extension_from_identifier (extension_identifier )
108
-
109
-
110
- @app .post ("/extension/enable" , status_code = status .HTTP_200_OK )
111
- @version (1 , 0 )
112
- async def enable_extension (extension_identifier : str ) -> Any :
113
- return await kraken .enable_extension (extension_identifier )
114
-
115
-
116
- @app .post ("/extension/disable" , status_code = status .HTTP_200_OK )
117
- @version (1 , 0 )
118
- async def disable_extension (extension_identifier : str ) -> Any :
119
- return await kraken .disable_extension (extension_identifier )
120
-
121
-
122
- @app .post ("/extension/restart" , status_code = status .HTTP_202_ACCEPTED )
123
- @version (1 , 0 )
124
- async def restart_extension (extension_identifier : str ) -> Any :
125
- return await kraken .restart_extension (extension_identifier )
126
-
127
-
128
- @app .get ("/list_containers" , status_code = status .HTTP_200_OK )
129
- @version (1 , 0 )
130
- async def list_containers () -> Any :
131
- containers = await kraken .list_containers ()
132
- return [
133
- {
134
- "name" : container ["Names" ][0 ],
135
- "image" : container ["Image" ],
136
- "imageId" : container ["ImageID" ],
137
- "status" : container ["Status" ],
138
- }
139
- for container in containers
140
- ]
141
-
142
-
143
- @app .get ("/log" , status_code = status .HTTP_200_OK , response_class = PlainTextResponse )
144
- @version (1 , 0 )
145
- async def log_containers (container_name : str ) -> Iterable [bytes ]:
146
- return StreamingResponse (timeout_streamer (kraken .stream_logs (container_name )), media_type = "text/plain" ) # type: ignore
147
-
148
-
149
- @app .get ("/stats" , status_code = status .HTTP_200_OK )
150
- @version (1 , 0 )
151
- async def load_stats () -> Any :
152
- return await kraken .load_stats ()
153
-
154
-
155
- app = VersionedFastAPI (app , version = "1.0.0" , prefix_format = "/v{major}.{minor}" , enable_latest = True )
156
-
157
-
158
- @app .get ("/" )
159
- async def root () -> Any :
160
- html_content = """
161
- <html>
162
- <head>
163
- <title>Kraken</title>
164
- </head>
165
- </html>
166
- """
167
- return HTMLResponse (content = html_content , status_code = 200 )
168
-
16
+ from kraken import kraken_instance
169
17
170
18
if __name__ == "__main__" :
171
19
parser = argparse .ArgumentParser ()
@@ -179,9 +27,9 @@ async def root() -> Any:
179
27
180
28
loop = asyncio .new_event_loop ()
181
29
182
- config = Config (app = app , loop = loop , host = "0.0.0.0" , port = 9134 , log_config = None )
30
+ config = Config (app = application , loop = loop , host = "0.0.0.0" , port = 9134 , log_config = None )
183
31
server = Server (config )
184
32
185
- loop .create_task (kraken .run ())
33
+ loop .create_task (kraken_instance .run ())
186
34
loop .run_until_complete (server .serve ())
187
- loop .run_until_complete (kraken .stop ())
35
+ loop .run_until_complete (kraken_instance .stop ())
0 commit comments