mirror of
https://github.com/nicolargo/glances.git
synced 2024-11-23 20:45:33 +03:00
chg: restful_api - use internal serialization features
This commit is contained in:
parent
538013d192
commit
2a5251ca2d
@ -15,13 +15,14 @@ import webbrowser
|
||||
from urllib.parse import urljoin
|
||||
|
||||
try:
|
||||
from typing import Annotated
|
||||
from typing import Annotated, Any
|
||||
except ImportError:
|
||||
# Only for Python 3.8
|
||||
# To be removed when Python 3.8 support will be dropped
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from glances import __apiversion__, __version__
|
||||
from glances.globals import json_dumps
|
||||
from glances.logger import logger
|
||||
from glances.password import GlancesPassword
|
||||
from glances.timer import Timer
|
||||
@ -31,7 +32,7 @@ try:
|
||||
from fastapi import APIRouter, Depends, FastAPI, HTTPException, Request, status
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.middleware.gzip import GZipMiddleware
|
||||
from fastapi.responses import HTMLResponse, ORJSONResponse
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
@ -50,6 +51,18 @@ import contextlib
|
||||
import threading
|
||||
import time
|
||||
|
||||
|
||||
class GlancesJSONResponse(JSONResponse):
|
||||
"""
|
||||
Glances impl of fastapi's JSONResponse to use internal JSON Serialization features
|
||||
|
||||
Ref: https://fastapi.tiangolo.com/advanced/custom-response/
|
||||
"""
|
||||
|
||||
def render(self, content: Any) -> bytes:
|
||||
return json_dumps(content)
|
||||
|
||||
|
||||
security = HTTPBasic()
|
||||
|
||||
|
||||
@ -106,11 +119,11 @@ class GlancesRestfulApi:
|
||||
|
||||
# FastAPI Init
|
||||
if self.args.password:
|
||||
self._app = FastAPI(dependencies=[Depends(self.authentication)])
|
||||
self._app = FastAPI(default_response_class=GlancesJSONResponse, dependencies=[Depends(self.authentication)])
|
||||
self._password = GlancesPassword(username=args.username, config=config)
|
||||
|
||||
else:
|
||||
self._app = FastAPI()
|
||||
self._app = FastAPI(default_response_class=GlancesJSONResponse)
|
||||
self._password = None
|
||||
|
||||
# Set path for WebUI
|
||||
@ -178,102 +191,49 @@ class GlancesRestfulApi:
|
||||
headers={"WWW-Authenticate": "Basic"},
|
||||
)
|
||||
|
||||
def _router(self):
|
||||
def _router(self) -> APIRouter:
|
||||
"""Define a custom router for Glances path."""
|
||||
# Create une main router
|
||||
base_path = f'/api/{self.API_VERSION}'
|
||||
plugin_path = f"{base_path}/{{plugin}}"
|
||||
|
||||
# Create the main router
|
||||
router = APIRouter(prefix=self.url_prefix)
|
||||
|
||||
# REST API
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/status',
|
||||
status_code=status.HTTP_200_OK,
|
||||
methods=['HEAD', 'GET'],
|
||||
response_class=ORJSONResponse,
|
||||
endpoint=self._api_status,
|
||||
)
|
||||
router.add_api_route(f'{base_path}/status', self._api_status, methods=['HEAD', 'GET'])
|
||||
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/config', response_class=ORJSONResponse, endpoint=self._api_config
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/config/{{section}}',
|
||||
response_class=ORJSONResponse,
|
||||
endpoint=self._api_config_section,
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/config/{{section}}/{{item}}',
|
||||
response_class=ORJSONResponse,
|
||||
endpoint=self._api_config_section_item,
|
||||
)
|
||||
route_mapping = {
|
||||
f'{base_path}/config': self._api_config,
|
||||
f'{base_path}/config/{{section}}': self._api_config_section,
|
||||
f'{base_path}/config/{{section}}/{{item}}': self._api_config_section_item,
|
||||
f'{base_path}/args': self._api_args,
|
||||
f'{base_path}/args/{{item}}': self._api_args_item,
|
||||
f'{base_path}/help': self._api_help,
|
||||
f'{base_path}/all': self._api_all,
|
||||
f'{base_path}/all/limits': self._api_all_limits,
|
||||
f'{base_path}/all/views': self._api_all_views,
|
||||
f'{base_path}/pluginslist': self._api_plugins,
|
||||
f'{plugin_path}': self._api,
|
||||
f'{plugin_path}/history': self._api_history,
|
||||
f'{plugin_path}/history/{{nb}}': self._api_history,
|
||||
f'{plugin_path}/top/{{nb}}': self._api_top,
|
||||
f'{plugin_path}/limits': self._api_limits,
|
||||
f'{plugin_path}/views': self._api_views,
|
||||
f'{plugin_path}/{{item}}': self._api_item,
|
||||
f'{plugin_path}/{{item}}/history': self._api_item_history,
|
||||
f'{plugin_path}/{{item}}/history/{{nb}}': self._api_item_history,
|
||||
f'{plugin_path}/{{item}}/description': self._api_item_description,
|
||||
f'{plugin_path}/{{item}}/unit': self._api_item_unit,
|
||||
f'{plugin_path}/{{item}}/{{value:path}}': self._api_value,
|
||||
}
|
||||
|
||||
router.add_api_route(f'/api/{self.API_VERSION}/args', response_class=ORJSONResponse, endpoint=self._api_args)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/args/{{item}}', response_class=ORJSONResponse, endpoint=self._api_args_item
|
||||
)
|
||||
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/pluginslist', response_class=ORJSONResponse, endpoint=self._api_plugins
|
||||
)
|
||||
router.add_api_route(f'/api/{self.API_VERSION}/all', response_class=ORJSONResponse, endpoint=self._api_all)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/all/limits', response_class=ORJSONResponse, endpoint=self._api_all_limits
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/all/views', response_class=ORJSONResponse, endpoint=self._api_all_views
|
||||
)
|
||||
|
||||
router.add_api_route(f'/api/{self.API_VERSION}/help', response_class=ORJSONResponse, endpoint=self._api_help)
|
||||
router.add_api_route(f'/api/{self.API_VERSION}/{{plugin}}', response_class=ORJSONResponse, endpoint=self._api)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/history', response_class=ORJSONResponse, endpoint=self._api_history
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/history/{{nb}}',
|
||||
response_class=ORJSONResponse,
|
||||
endpoint=self._api_history,
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/top/{{nb}}', response_class=ORJSONResponse, endpoint=self._api_top
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/limits', response_class=ORJSONResponse, endpoint=self._api_limits
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/views', response_class=ORJSONResponse, endpoint=self._api_views
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/{{item}}', response_class=ORJSONResponse, endpoint=self._api_item
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/{{item}}/history',
|
||||
response_class=ORJSONResponse,
|
||||
endpoint=self._api_item_history,
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/{{item}}/history/{{nb}}',
|
||||
response_class=ORJSONResponse,
|
||||
endpoint=self._api_item_history,
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/{{item}}/description',
|
||||
response_class=ORJSONResponse,
|
||||
endpoint=self._api_item_description,
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/{{item}}/unit',
|
||||
response_class=ORJSONResponse,
|
||||
endpoint=self._api_item_unit,
|
||||
)
|
||||
router.add_api_route(
|
||||
f'/api/{self.API_VERSION}/{{plugin}}/{{item}}/{{value:path}}',
|
||||
response_class=ORJSONResponse,
|
||||
endpoint=self._api_value,
|
||||
)
|
||||
for path, endpoint in route_mapping.items():
|
||||
router.add_api_route(path, endpoint)
|
||||
|
||||
# WEB UI
|
||||
if not self.args.disable_webui:
|
||||
# Template for the root index.html file
|
||||
router.add_api_route('/', response_class=HTMLResponse, endpoint=self._index)
|
||||
router.add_api_route('/', self._index, response_class=HTMLResponse)
|
||||
|
||||
# Statics files
|
||||
self._app.mount(self.url_prefix + '/static', StaticFiles(directory=self.STATIC_PATH), name="static")
|
||||
@ -361,7 +321,7 @@ class GlancesRestfulApi:
|
||||
See related issue: Web server health check endpoint #1988
|
||||
"""
|
||||
|
||||
return ORJSONResponse({'version': __version__})
|
||||
return GlancesJSONResponse({'version': __version__})
|
||||
|
||||
def _api_help(self):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -373,7 +333,7 @@ class GlancesRestfulApi:
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get help view data ({str(e)})")
|
||||
|
||||
return ORJSONResponse(plist)
|
||||
return GlancesJSONResponse(plist)
|
||||
|
||||
def _api_plugins(self):
|
||||
"""Glances API RESTFul implementation.
|
||||
@ -409,7 +369,7 @@ class GlancesRestfulApi:
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get plugin list ({str(e)})")
|
||||
|
||||
return ORJSONResponse(plist)
|
||||
return GlancesJSONResponse(plist)
|
||||
|
||||
def _api_all(self):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -436,7 +396,7 @@ class GlancesRestfulApi:
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get stats ({str(e)})")
|
||||
|
||||
return ORJSONResponse(statval)
|
||||
return GlancesJSONResponse(statval)
|
||||
|
||||
def _api_all_limits(self):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -452,7 +412,7 @@ class GlancesRestfulApi:
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get limits ({str(e)})")
|
||||
|
||||
return ORJSONResponse(limits)
|
||||
return GlancesJSONResponse(limits)
|
||||
|
||||
def _api_all_views(self):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -468,7 +428,7 @@ class GlancesRestfulApi:
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get views ({str(e)})")
|
||||
|
||||
return ORJSONResponse(limits)
|
||||
return GlancesJSONResponse(limits)
|
||||
|
||||
def _api(self, plugin):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -493,7 +453,7 @@ class GlancesRestfulApi:
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get plugin {plugin} ({str(e)})")
|
||||
|
||||
return ORJSONResponse(statval)
|
||||
return GlancesJSONResponse(statval)
|
||||
|
||||
def _api_top(self, plugin, nb: int = 0):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -525,7 +485,7 @@ class GlancesRestfulApi:
|
||||
if isinstance(statval, list):
|
||||
statval = statval[:nb]
|
||||
|
||||
return ORJSONResponse(statval)
|
||||
return GlancesJSONResponse(statval)
|
||||
|
||||
def _api_history(self, plugin, nb: int = 0):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -577,7 +537,7 @@ class GlancesRestfulApi:
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get limits for plugin {plugin} ({str(e)})"
|
||||
)
|
||||
|
||||
return ORJSONResponse(ret)
|
||||
return GlancesJSONResponse(ret)
|
||||
|
||||
def _api_views(self, plugin):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -601,7 +561,7 @@ class GlancesRestfulApi:
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get views for plugin {plugin} ({str(e)})"
|
||||
)
|
||||
|
||||
return ORJSONResponse(ret)
|
||||
return GlancesJSONResponse(ret)
|
||||
|
||||
def _api_item(self, plugin, item):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -629,7 +589,7 @@ class GlancesRestfulApi:
|
||||
detail=f"Cannot get item {item} in plugin {plugin} ({str(e)})",
|
||||
)
|
||||
|
||||
return ORJSONResponse(ret)
|
||||
return GlancesJSONResponse(ret)
|
||||
|
||||
def _api_item_history(self, plugin, item, nb: int = 0):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -657,7 +617,7 @@ class GlancesRestfulApi:
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get history for plugin {plugin} ({str(e)})"
|
||||
)
|
||||
else:
|
||||
return ORJSONResponse(ret)
|
||||
return GlancesJSONResponse(ret)
|
||||
|
||||
def _api_item_description(self, plugin, item):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -682,7 +642,7 @@ class GlancesRestfulApi:
|
||||
detail=f"Cannot get {item} description for plugin {plugin} ({str(e)})",
|
||||
)
|
||||
else:
|
||||
return ORJSONResponse(ret)
|
||||
return GlancesJSONResponse(ret)
|
||||
|
||||
def _api_item_unit(self, plugin, item):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -707,7 +667,7 @@ class GlancesRestfulApi:
|
||||
detail=f"Cannot get {item} unit for plugin {plugin} ({str(e)})",
|
||||
)
|
||||
else:
|
||||
return ORJSONResponse(ret)
|
||||
return GlancesJSONResponse(ret)
|
||||
|
||||
def _api_value(self, plugin, item, value):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -735,7 +695,7 @@ class GlancesRestfulApi:
|
||||
detail=f"Cannot get {item} = {value} for plugin {plugin} ({str(e)})",
|
||||
)
|
||||
else:
|
||||
return ORJSONResponse(ret)
|
||||
return GlancesJSONResponse(ret)
|
||||
|
||||
def _api_config(self):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -750,7 +710,7 @@ class GlancesRestfulApi:
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get config ({str(e)})")
|
||||
else:
|
||||
return ORJSONResponse(args_json)
|
||||
return GlancesJSONResponse(args_json)
|
||||
|
||||
def _api_config_section(self, section):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -772,7 +732,7 @@ class GlancesRestfulApi:
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get config section {section} ({str(e)})"
|
||||
)
|
||||
|
||||
return ORJSONResponse(ret_section)
|
||||
return GlancesJSONResponse(ret_section)
|
||||
|
||||
def _api_config_section_item(self, section, item):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -803,7 +763,7 @@ class GlancesRestfulApi:
|
||||
detail=f"Cannot get item {item} in config section {section} ({str(e)})",
|
||||
)
|
||||
|
||||
return ORJSONResponse(ret_item)
|
||||
return GlancesJSONResponse(ret_item)
|
||||
|
||||
def _api_args(self):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -820,7 +780,7 @@ class GlancesRestfulApi:
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get args ({str(e)})")
|
||||
|
||||
return ORJSONResponse(args_json)
|
||||
return GlancesJSONResponse(args_json)
|
||||
|
||||
def _api_args_item(self, item):
|
||||
"""Glances API RESTful implementation.
|
||||
@ -841,4 +801,4 @@ class GlancesRestfulApi:
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get args item ({str(e)})")
|
||||
|
||||
return ORJSONResponse(args_json)
|
||||
return GlancesJSONResponse(args_json)
|
||||
|
Loading…
Reference in New Issue
Block a user