216 lines
8.6 KiB
Python
216 lines
8.6 KiB
Python
# [DEF:DebugPluginModule:Module]
|
|
# @SEMANTICS: plugin, debug, api, database, superset
|
|
# @PURPOSE: Implements a plugin for system diagnostics and debugging Superset API responses.
|
|
# @LAYER: Plugins
|
|
# @RELATION: Inherits from PluginBase. Uses SupersetClient from core.
|
|
# @RELATION: USES -> TaskContext
|
|
# @CONSTRAINT: Must use belief_scope for logging.
|
|
|
|
# [SECTION: IMPORTS]
|
|
from typing import Dict, Any, Optional
|
|
from ..core.plugin_base import PluginBase
|
|
from ..core.superset_client import SupersetClient
|
|
from ..core.logger import logger, belief_scope
|
|
from ..core.task_manager.context import TaskContext
|
|
# [/SECTION]
|
|
|
|
# [DEF:DebugPlugin:Class]
|
|
# @PURPOSE: Plugin for system diagnostics and debugging.
|
|
class DebugPlugin(PluginBase):
|
|
"""
|
|
Plugin for system diagnostics and debugging.
|
|
"""
|
|
|
|
@property
|
|
# [DEF:id:Function]
|
|
# @PURPOSE: Returns the unique identifier for the debug plugin.
|
|
# @PRE: Plugin instance exists.
|
|
# @POST: Returns string ID.
|
|
# @RETURN: str - "system-debug"
|
|
def id(self) -> str:
|
|
with belief_scope("id"):
|
|
return "system-debug"
|
|
# [/DEF:id:Function]
|
|
|
|
@property
|
|
# [DEF:name:Function]
|
|
# @PURPOSE: Returns the human-readable name of the debug plugin.
|
|
# @PRE: Plugin instance exists.
|
|
# @POST: Returns string name.
|
|
# @RETURN: str - Plugin name.
|
|
def name(self) -> str:
|
|
with belief_scope("name"):
|
|
return "System Debug"
|
|
# [/DEF:name:Function]
|
|
|
|
@property
|
|
# [DEF:description:Function]
|
|
# @PURPOSE: Returns a description of the debug plugin.
|
|
# @PRE: Plugin instance exists.
|
|
# @POST: Returns string description.
|
|
# @RETURN: str - Plugin description.
|
|
def description(self) -> str:
|
|
with belief_scope("description"):
|
|
return "Run system diagnostics and debug Superset API responses."
|
|
# [/DEF:description:Function]
|
|
|
|
@property
|
|
# [DEF:version:Function]
|
|
# @PURPOSE: Returns the version of the debug plugin.
|
|
# @PRE: Plugin instance exists.
|
|
# @POST: Returns string version.
|
|
# @RETURN: str - "1.0.0"
|
|
def version(self) -> str:
|
|
with belief_scope("version"):
|
|
return "1.0.0"
|
|
# [/DEF:version:Function]
|
|
|
|
@property
|
|
# [DEF:ui_route:Function]
|
|
# @PURPOSE: Returns the frontend route for the debug plugin.
|
|
# @RETURN: str - "/tools/debug"
|
|
def ui_route(self) -> str:
|
|
with belief_scope("ui_route"):
|
|
return "/tools/debug"
|
|
# [/DEF:ui_route:Function]
|
|
|
|
# [DEF:get_schema:Function]
|
|
# @PURPOSE: Returns the JSON schema for the debug plugin parameters.
|
|
# @PRE: Plugin instance exists.
|
|
# @POST: Returns dictionary schema.
|
|
# @RETURN: Dict[str, Any] - JSON schema.
|
|
def get_schema(self) -> Dict[str, Any]:
|
|
with belief_scope("get_schema"):
|
|
return {
|
|
"type": "object",
|
|
"properties": {
|
|
"action": {
|
|
"type": "string",
|
|
"title": "Action",
|
|
"enum": ["test-db-api", "get-dataset-structure"],
|
|
"default": "test-db-api"
|
|
},
|
|
"env": {
|
|
"type": "string",
|
|
"title": "Environment",
|
|
"description": "The Superset environment (for dataset structure)."
|
|
},
|
|
"dataset_id": {
|
|
"type": "integer",
|
|
"title": "Dataset ID",
|
|
"description": "The ID of the dataset (for dataset structure)."
|
|
},
|
|
"source_env": {
|
|
"type": "string",
|
|
"title": "Source Environment",
|
|
"description": "Source env for DB API test."
|
|
},
|
|
"target_env": {
|
|
"type": "string",
|
|
"title": "Target Environment",
|
|
"description": "Target env for DB API test."
|
|
}
|
|
},
|
|
"required": ["action"]
|
|
}
|
|
# [/DEF:get_schema:Function]
|
|
|
|
# [DEF:execute:Function]
|
|
# @PURPOSE: Executes the debug logic with TaskContext support.
|
|
# @PARAM: params (Dict[str, Any]) - Debug parameters.
|
|
# @PARAM: context (Optional[TaskContext]) - Task context for logging with source attribution.
|
|
# @PRE: action must be provided in params.
|
|
# @POST: Debug action is executed and results returned.
|
|
# @RETURN: Dict[str, Any] - Execution results.
|
|
async def execute(self, params: Dict[str, Any], context: Optional[TaskContext] = None) -> Dict[str, Any]:
|
|
with belief_scope("execute"):
|
|
action = params.get("action")
|
|
|
|
# Use TaskContext logger if available, otherwise fall back to app logger
|
|
log = context.logger if context else logger
|
|
debug_log = log.with_source("debug") if context else log
|
|
superset_log = log.with_source("superset_api") if context else log
|
|
|
|
debug_log.info(f"Executing debug action: {action}")
|
|
|
|
if action == "test-db-api":
|
|
return await self._test_db_api(params, superset_log)
|
|
elif action == "get-dataset-structure":
|
|
return await self._get_dataset_structure(params, superset_log)
|
|
else:
|
|
debug_log.error(f"Unknown action: {action}")
|
|
raise ValueError(f"Unknown action: {action}")
|
|
# [/DEF:execute:Function]
|
|
|
|
# [DEF:_test_db_api:Function]
|
|
# @PURPOSE: Tests database API connectivity for source and target environments.
|
|
# @PRE: source_env and target_env params exist in params.
|
|
# @POST: Returns DB counts for both envs.
|
|
# @PARAM: params (Dict) - Plugin parameters.
|
|
# @PARAM: log - Logger instance for superset_api source.
|
|
# @RETURN: Dict - Comparison results.
|
|
async def _test_db_api(self, params: Dict[str, Any], log) -> Dict[str, Any]:
|
|
with belief_scope("_test_db_api"):
|
|
source_env_name = params.get("source_env")
|
|
target_env_name = params.get("target_env")
|
|
|
|
if not source_env_name or not target_env_name:
|
|
raise ValueError("source_env and target_env are required for test-db-api")
|
|
|
|
from ..dependencies import get_config_manager
|
|
config_manager = get_config_manager()
|
|
|
|
results = {}
|
|
for name in [source_env_name, target_env_name]:
|
|
log.info(f"Testing database API for environment: {name}")
|
|
env_config = config_manager.get_environment(name)
|
|
if not env_config:
|
|
log.error(f"Environment '{name}' not found.")
|
|
raise ValueError(f"Environment '{name}' not found.")
|
|
|
|
client = SupersetClient(env_config)
|
|
client.authenticate()
|
|
count, dbs = client.get_databases()
|
|
log.debug(f"Found {count} databases in {name}")
|
|
results[name] = {
|
|
"count": count,
|
|
"databases": dbs
|
|
}
|
|
|
|
return results
|
|
# [/DEF:_test_db_api:Function]
|
|
|
|
# [DEF:_get_dataset_structure:Function]
|
|
# @PURPOSE: Retrieves the structure of a dataset.
|
|
# @PRE: env and dataset_id params exist in params.
|
|
# @POST: Returns dataset JSON structure.
|
|
# @PARAM: params (Dict) - Plugin parameters.
|
|
# @PARAM: log - Logger instance for superset_api source.
|
|
# @RETURN: Dict - Dataset structure.
|
|
async def _get_dataset_structure(self, params: Dict[str, Any], log) -> Dict[str, Any]:
|
|
with belief_scope("_get_dataset_structure"):
|
|
env_name = params.get("env")
|
|
dataset_id = params.get("dataset_id")
|
|
|
|
if not env_name or dataset_id is None:
|
|
raise ValueError("env and dataset_id are required for get-dataset-structure")
|
|
|
|
log.info(f"Fetching structure for dataset {dataset_id} in {env_name}")
|
|
|
|
from ..dependencies import get_config_manager
|
|
config_manager = get_config_manager()
|
|
env_config = config_manager.get_environment(env_name)
|
|
if not env_config:
|
|
log.error(f"Environment '{env_name}' not found.")
|
|
raise ValueError(f"Environment '{env_name}' not found.")
|
|
|
|
client = SupersetClient(env_config)
|
|
client.authenticate()
|
|
|
|
dataset_response = client.get_dataset(dataset_id)
|
|
log.debug(f"Retrieved dataset structure for {dataset_id}")
|
|
return dataset_response.get('result') or {}
|
|
# [/DEF:_get_dataset_structure:Function]
|
|
|
|
# [/DEF:DebugPlugin:Class]
|
|
# [/DEF:DebugPluginModule:Module] |