|
|
|
@ -14,14 +14,17 @@ import tempfile
|
|
|
|
|
import webbrowser
|
|
|
|
|
from urllib.parse import urljoin
|
|
|
|
|
|
|
|
|
|
from glances.stats import GlancesStats
|
|
|
|
|
|
|
|
|
|
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 +34,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
|
|
|
|
@ -53,6 +56,17 @@ import time
|
|
|
|
|
security = HTTPBasic()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GlancesUvicornServer(uvicorn.Server):
|
|
|
|
|
def install_signal_handlers(self):
|
|
|
|
|
pass
|
|
|
|
@ -106,11 +120,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
|
|
|
|
@ -161,9 +175,6 @@ class GlancesRestfulApi:
|
|
|
|
|
self.stats.update()
|
|
|
|
|
self.timer = Timer(self.args.cached_time)
|
|
|
|
|
|
|
|
|
|
def app(self):
|
|
|
|
|
return self._app()
|
|
|
|
|
|
|
|
|
|
def authentication(self, creds: Annotated[HTTPBasicCredentials, Depends(security)]):
|
|
|
|
|
"""Check if a username/password combination is valid."""
|
|
|
|
|
if creds.username == self.args.username:
|
|
|
|
@ -173,107 +184,52 @@ class GlancesRestfulApi:
|
|
|
|
|
|
|
|
|
|
# If the username/password combination is invalid, return an HTTP 401
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
|
|
|
detail="Incorrect username or password",
|
|
|
|
|
headers={"WWW-Authenticate": "Basic"},
|
|
|
|
|
status.HTTP_401_UNAUTHORIZED, "Incorrect username or password", {"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")
|
|
|
|
@ -293,7 +249,7 @@ class GlancesRestfulApi:
|
|
|
|
|
|
|
|
|
|
return router
|
|
|
|
|
|
|
|
|
|
def start(self, stats):
|
|
|
|
|
def start(self, stats: GlancesStats) -> None:
|
|
|
|
|
"""Start the bottle."""
|
|
|
|
|
# Init stats
|
|
|
|
|
self.stats = stats
|
|
|
|
@ -344,13 +300,7 @@ class GlancesRestfulApi:
|
|
|
|
|
self.__update__()
|
|
|
|
|
|
|
|
|
|
# Display
|
|
|
|
|
return self._templates.TemplateResponse(
|
|
|
|
|
"index.html",
|
|
|
|
|
{
|
|
|
|
|
"request": request,
|
|
|
|
|
"refresh_time": refresh_time,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
return self._templates.TemplateResponse("index.html", {"request": request, "refresh_time": refresh_time})
|
|
|
|
|
|
|
|
|
|
def _api_status(self):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
@ -361,7 +311,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.
|
|
|
|
@ -371,9 +321,9 @@ class GlancesRestfulApi:
|
|
|
|
|
try:
|
|
|
|
|
plist = self.stats.get_plugin("help").get_view_data()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get help view data ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get help view data ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(plist)
|
|
|
|
|
return GlancesJSONResponse(plist)
|
|
|
|
|
|
|
|
|
|
def _api_plugins(self):
|
|
|
|
|
"""Glances API RESTFul implementation.
|
|
|
|
@ -407,9 +357,9 @@ class GlancesRestfulApi:
|
|
|
|
|
try:
|
|
|
|
|
plist = self.plugins_list
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get plugin list ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get plugin list ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(plist)
|
|
|
|
|
return GlancesJSONResponse(plist)
|
|
|
|
|
|
|
|
|
|
def _api_all(self):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
@ -434,9 +384,9 @@ class GlancesRestfulApi:
|
|
|
|
|
# Get the RAW value of the stat ID
|
|
|
|
|
statval = self.stats.getAllAsDict()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get stats ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get stats ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(statval)
|
|
|
|
|
return GlancesJSONResponse(statval)
|
|
|
|
|
|
|
|
|
|
def _api_all_limits(self):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
@ -450,9 +400,9 @@ class GlancesRestfulApi:
|
|
|
|
|
# Get the RAW value of the stat limits
|
|
|
|
|
limits = self.stats.getAllLimitsAsDict()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get limits ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get limits ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(limits)
|
|
|
|
|
return GlancesJSONResponse(limits)
|
|
|
|
|
|
|
|
|
|
def _api_all_views(self):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
@ -466,11 +416,11 @@ class GlancesRestfulApi:
|
|
|
|
|
# Get the RAW value of the stat view
|
|
|
|
|
limits = self.stats.getAllViewsAsDict()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get views ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get views ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(limits)
|
|
|
|
|
return GlancesJSONResponse(limits)
|
|
|
|
|
|
|
|
|
|
def _api(self, plugin):
|
|
|
|
|
def _api(self, plugin: str):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of a given plugin
|
|
|
|
@ -478,11 +428,7 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/400 if plugin is not found
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
)
|
|
|
|
|
self._check_if_plugin_available(plugin)
|
|
|
|
|
|
|
|
|
|
# Update the stat
|
|
|
|
|
self.__update__()
|
|
|
|
@ -491,11 +437,19 @@ class GlancesRestfulApi:
|
|
|
|
|
# Get the RAW value of the stat ID
|
|
|
|
|
statval = self.stats.get_plugin(plugin).get_raw()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get plugin {plugin} ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get plugin {plugin} ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(statval)
|
|
|
|
|
return GlancesJSONResponse(statval)
|
|
|
|
|
|
|
|
|
|
def _api_top(self, plugin, nb: int = 0):
|
|
|
|
|
def _check_if_plugin_available(self, plugin: str) -> None:
|
|
|
|
|
if plugin in self.plugins_list:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status.HTTP_400_BAD_REQUEST, f"Unknown plugin {plugin} (available plugins: {self.plugins_list})"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def _api_top(self, plugin: str, nb: int = 0):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of a given plugin limited to the top nb items.
|
|
|
|
@ -505,11 +459,7 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/400 if plugin is not found
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
)
|
|
|
|
|
self._check_if_plugin_available(plugin)
|
|
|
|
|
|
|
|
|
|
# Update the stat
|
|
|
|
|
self.__update__()
|
|
|
|
@ -518,16 +468,16 @@ class GlancesRestfulApi:
|
|
|
|
|
# Get the RAW value of the stat ID
|
|
|
|
|
statval = self.stats.get_plugin(plugin).get_raw()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get plugin {plugin} ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get plugin {plugin} ({str(e)})")
|
|
|
|
|
|
|
|
|
|
print(statval)
|
|
|
|
|
|
|
|
|
|
if isinstance(statval, list):
|
|
|
|
|
statval = statval[:nb]
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(statval)
|
|
|
|
|
return GlancesJSONResponse(statval)
|
|
|
|
|
|
|
|
|
|
def _api_history(self, plugin, nb: int = 0):
|
|
|
|
|
def _api_history(self, plugin: str, nb: int = 0):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of a given plugin history
|
|
|
|
@ -536,11 +486,7 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/400 if plugin is not found
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
)
|
|
|
|
|
self._check_if_plugin_available(plugin)
|
|
|
|
|
|
|
|
|
|
# Update the stat
|
|
|
|
|
self.__update__()
|
|
|
|
@ -549,13 +495,11 @@ class GlancesRestfulApi:
|
|
|
|
|
# Get the RAW value of the stat ID
|
|
|
|
|
statval = self.stats.get_plugin(plugin).get_raw_history(nb=int(nb))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get plugin history {plugin} ({str(e)})"
|
|
|
|
|
)
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get plugin history {plugin} ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return statval
|
|
|
|
|
|
|
|
|
|
def _api_limits(self, plugin):
|
|
|
|
|
def _api_limits(self, plugin: str):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON limits of a given plugin
|
|
|
|
@ -563,23 +507,17 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/400 if plugin is not found
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
)
|
|
|
|
|
self._check_if_plugin_available(plugin)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Get the RAW value of the stat limits
|
|
|
|
|
ret = self.stats.get_plugin(plugin).limits
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get limits for plugin {plugin} ({str(e)})"
|
|
|
|
|
)
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get limits for plugin {plugin} ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(ret)
|
|
|
|
|
return GlancesJSONResponse(ret)
|
|
|
|
|
|
|
|
|
|
def _api_views(self, plugin):
|
|
|
|
|
def _api_views(self, plugin: str):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON views of a given plugin
|
|
|
|
@ -589,21 +527,18 @@ class GlancesRestfulApi:
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
status.HTTP_400_BAD_REQUEST, f"Unknown plugin {plugin} (available plugins: {self.plugins_list})"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Get the RAW value of the stat views
|
|
|
|
|
ret = self.stats.get_plugin(plugin).get_views()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get views for plugin {plugin} ({str(e)})"
|
|
|
|
|
)
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get views for plugin {plugin} ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(ret)
|
|
|
|
|
return GlancesJSONResponse(ret)
|
|
|
|
|
|
|
|
|
|
def _api_item(self, plugin, item):
|
|
|
|
|
def _api_item(self, plugin: str, item: str):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of the couple plugin/item
|
|
|
|
@ -611,11 +546,7 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/400 if plugin is not found
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
)
|
|
|
|
|
self._check_if_plugin_available(plugin)
|
|
|
|
|
|
|
|
|
|
# Update the stat
|
|
|
|
|
self.__update__()
|
|
|
|
@ -625,13 +556,13 @@ class GlancesRestfulApi:
|
|
|
|
|
ret = self.stats.get_plugin(plugin).get_raw_stats_item(item)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
detail=f"Cannot get item {item} in plugin {plugin} ({str(e)})",
|
|
|
|
|
status.HTTP_404_NOT_FOUND,
|
|
|
|
|
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):
|
|
|
|
|
def _api_item_history(self, plugin: str, item: str, nb: int = 0):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of the couple plugin/history of item
|
|
|
|
@ -640,11 +571,7 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
)
|
|
|
|
|
self._check_if_plugin_available(plugin)
|
|
|
|
|
|
|
|
|
|
# Update the stat
|
|
|
|
|
self.__update__()
|
|
|
|
@ -653,13 +580,11 @@ class GlancesRestfulApi:
|
|
|
|
|
# Get the RAW value of the stat history
|
|
|
|
|
ret = self.stats.get_plugin(plugin).get_raw_history(item, nb=nb)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get history for plugin {plugin} ({str(e)})"
|
|
|
|
|
)
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get history for plugin {plugin} ({str(e)})")
|
|
|
|
|
else:
|
|
|
|
|
return ORJSONResponse(ret)
|
|
|
|
|
return GlancesJSONResponse(ret)
|
|
|
|
|
|
|
|
|
|
def _api_item_description(self, plugin, item):
|
|
|
|
|
def _api_item_description(self, plugin: str, item: str):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of the couple plugin/item description
|
|
|
|
@ -667,24 +592,19 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/400 if plugin is not found
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
)
|
|
|
|
|
self._check_if_plugin_available(plugin)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Get the description
|
|
|
|
|
ret = self.stats.get_plugin(plugin).get_item_info(item, 'description')
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
detail=f"Cannot get {item} description for plugin {plugin} ({str(e)})",
|
|
|
|
|
status.HTTP_404_NOT_FOUND, f"Cannot get {item} description for plugin {plugin} ({str(e)})"
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
return ORJSONResponse(ret)
|
|
|
|
|
return GlancesJSONResponse(ret)
|
|
|
|
|
|
|
|
|
|
def _api_item_unit(self, plugin, item):
|
|
|
|
|
def _api_item_unit(self, plugin: str, item: str):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of the couple plugin/item unit
|
|
|
|
@ -692,24 +612,17 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/400 if plugin is not found
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
)
|
|
|
|
|
self._check_if_plugin_available(plugin)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Get the unit
|
|
|
|
|
ret = self.stats.get_plugin(plugin).get_item_info(item, 'unit')
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
detail=f"Cannot get {item} unit for plugin {plugin} ({str(e)})",
|
|
|
|
|
)
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get {item} unit for plugin {plugin} ({str(e)})")
|
|
|
|
|
else:
|
|
|
|
|
return ORJSONResponse(ret)
|
|
|
|
|
return GlancesJSONResponse(ret)
|
|
|
|
|
|
|
|
|
|
def _api_value(self, plugin, item, value):
|
|
|
|
|
def _api_value(self, plugin: str, item: str, value: Any):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the process stats (dict) for the given item=value
|
|
|
|
@ -717,11 +630,7 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/400 if plugin is not found
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
"""
|
|
|
|
|
if plugin not in self.plugins_list:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
detail=f"Unknown plugin {plugin} (available plugins: {self.plugins_list})",
|
|
|
|
|
)
|
|
|
|
|
self._check_if_plugin_available(plugin)
|
|
|
|
|
|
|
|
|
|
# Update the stat
|
|
|
|
|
self.__update__()
|
|
|
|
@ -731,11 +640,10 @@ class GlancesRestfulApi:
|
|
|
|
|
ret = self.stats.get_plugin(plugin).get_raw_stats_value(item, value)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
detail=f"Cannot get {item} = {value} for plugin {plugin} ({str(e)})",
|
|
|
|
|
status.HTTP_404_NOT_FOUND, 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.
|
|
|
|
@ -748,11 +656,11 @@ class GlancesRestfulApi:
|
|
|
|
|
# Get the RAW value of the config' dict
|
|
|
|
|
args_json = self.config.as_dict()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get config ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get config ({str(e)})")
|
|
|
|
|
else:
|
|
|
|
|
return ORJSONResponse(args_json)
|
|
|
|
|
return GlancesJSONResponse(args_json)
|
|
|
|
|
|
|
|
|
|
def _api_config_section(self, section):
|
|
|
|
|
def _api_config_section(self, section: str):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of the Glances configuration section
|
|
|
|
@ -762,19 +670,17 @@ class GlancesRestfulApi:
|
|
|
|
|
"""
|
|
|
|
|
config_dict = self.config.as_dict()
|
|
|
|
|
if section not in config_dict:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unknown configuration item {section}")
|
|
|
|
|
raise HTTPException(status.HTTP_400_BAD_REQUEST, f"Unknown configuration item {section}")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Get the RAW value of the config' dict
|
|
|
|
|
ret_section = config_dict[section]
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get config section {section} ({str(e)})"
|
|
|
|
|
)
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get config section {section} ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(ret_section)
|
|
|
|
|
return GlancesJSONResponse(ret_section)
|
|
|
|
|
|
|
|
|
|
def _api_config_section_item(self, section, item):
|
|
|
|
|
def _api_config_section_item(self, section: str, item: str):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of the Glances configuration section/item
|
|
|
|
@ -784,26 +690,23 @@ class GlancesRestfulApi:
|
|
|
|
|
"""
|
|
|
|
|
config_dict = self.config.as_dict()
|
|
|
|
|
if section not in config_dict:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unknown configuration item {section}")
|
|
|
|
|
raise HTTPException(status.HTTP_400_BAD_REQUEST, f"Unknown configuration item {section}")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Get the RAW value of the config' dict section
|
|
|
|
|
ret_section = config_dict[section]
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get config section {section} ({str(e)})"
|
|
|
|
|
)
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get config section {section} ({str(e)})")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Get the RAW value of the config' dict item
|
|
|
|
|
ret_item = ret_section[item]
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
detail=f"Cannot get item {item} in config section {section} ({str(e)})",
|
|
|
|
|
status.HTTP_404_NOT_FOUND, 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.
|
|
|
|
@ -818,11 +721,11 @@ class GlancesRestfulApi:
|
|
|
|
|
# Source: https://docs.python.org/%s/library/functions.html#vars
|
|
|
|
|
args_json = vars(self.args)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get args ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get args ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(args_json)
|
|
|
|
|
return GlancesJSONResponse(args_json)
|
|
|
|
|
|
|
|
|
|
def _api_args_item(self, item):
|
|
|
|
|
def _api_args_item(self, item: str):
|
|
|
|
|
"""Glances API RESTful implementation.
|
|
|
|
|
|
|
|
|
|
Return the JSON representation of the Glances command line arguments item
|
|
|
|
@ -831,7 +734,7 @@ class GlancesRestfulApi:
|
|
|
|
|
HTTP/404 if others error
|
|
|
|
|
"""
|
|
|
|
|
if item not in self.args:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unknown argument item {item}")
|
|
|
|
|
raise HTTPException(status.HTTP_400_BAD_REQUEST, f"Unknown argument item {item}")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Get the RAW value of the args' dict
|
|
|
|
@ -839,6 +742,6 @@ class GlancesRestfulApi:
|
|
|
|
|
# Source: https://docs.python.org/%s/library/functions.html#vars
|
|
|
|
|
args_json = vars(self.args)[item]
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Cannot get args item ({str(e)})")
|
|
|
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get args item ({str(e)})")
|
|
|
|
|
|
|
|
|
|
return ORJSONResponse(args_json)
|
|
|
|
|
return GlancesJSONResponse(args_json)
|
|
|
|
|