diff --git a/README.md b/README.md index feae4da..db89b6a 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,8 @@ We are providing groupings of tools and associated helpful prompts to support al - [Plot Tools](./src/teradata_mcp_server/tools/plot/README.md) - **BAR** tools, prompts and resources for database backup and restore operations: - [BAR Tools](src/teradata_mcp_server/tools/bar/README.md) integrate AI agents with Teradata DSA (Data Stream Architecture) for comprehensive backup management across multiple storage solutions including disk files, cloud storage (AWS S3, Azure Blob, Google Cloud), and enterprise systems (NetBackup, IBM Spectrum). +- **QueryGrid** tools, prompts and resources for managing Teradata QueryGrid: + - [QueryGrid Tools](src/teradata_mcp_server/tools/qg/README.md) ## Quick start with Claude Desktop (no installation) > Prefer to use other tools? Check out our Quick Starts for [VS Code/Copilot](https://github.com/Teradata/teradata-mcp-server/blob/main/docs/server_guide/QUICK_START_VSCODE.md), [Open WebUI](https://github.com/Teradata/teradata-mcp-server/blob/main/docs/server_guide/QUICK_START_OPEN_WEBUI.md), or dive into [simple code examples](https://github.com/Teradata/teradata-mcp-server/blob/main/examples/README.md#client-applications)! diff --git a/pyproject.toml b/pyproject.toml index 058d922..4233d66 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,11 @@ bar = [ "requests>=2.25.0", ] +# QueryGrid functionality +qg = [ + "requests>=2.25.0", +] + # Development dependencies dev = [ "ruff>=0.1.0", diff --git a/src/teradata_mcp_server/app.py b/src/teradata_mcp_server/app.py index e0a8afc..be8cc3c 100644 --- a/src/teradata_mcp_server/app.py +++ b/src/teradata_mcp_server/app.py @@ -19,6 +19,7 @@ import inspect import os import re +import sys from importlib.resources import files as pkg_files from typing import Annotated, Any @@ -64,6 +65,7 @@ def create_mcp_app(settings: Settings): enableEFS = True if any(re.match(pattern, 'fs_*') for pattern in config.get('tool', [])) else False enableTDVS = True if any(re.match(pattern, 'tdvs_*') for pattern in config.get('tool', [])) else False enableBAR = True if any(re.match(pattern, 'bar_*') for pattern in config.get('tool', [])) else False + enableQG = True if any(re.match(pattern, 'qg_*') for pattern in config.get('tool', [])) else False # Initialize TD connection and optional teradataml/EFS context # Pass settings object to TDConn instead of just connection_url @@ -128,6 +130,18 @@ def create_mcp_app(settings: Settings): logger.warning(f"BAR system dependencies not available - disabling BAR functionality: {e}") enableBAR = False + # QueryGrid dependencies (optional) + qg_manager = None + if enableQG: + try: + # Check for QG system availability by importing required modules + import requests + from teradata_mcp_server.tools.qg.qgm.querygrid_manager import QueryGridManager + qg_manager = QueryGridManager() + except (AttributeError, ImportError, ModuleNotFoundError) as e: + logger.warning(f"QG system dependencies not available - disabling QG functionality: {e}") + enableQG = False + # Middleware (auth + request context) from teradata_mcp_server.tools.auth_cache import SecureAuthCache auth_cache = SecureAuthCache(ttl_seconds=settings.auth_cache_ttl) @@ -321,6 +335,10 @@ def make_tool_wrapper(func): inject_kwargs["fs_config"] = fs_config removable.add("fs_config") + if "qg_manager" in sig.parameters: + inject_kwargs["qg_manager"] = qg_manager + removable.add("qg_manager") + params = [ p for name, p in sig.parameters.items() if name not in removable and p.kind in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY) @@ -358,6 +376,10 @@ def executor(**kwargs): if tool_name.startswith("bar_") and not enableBAR: logger.info(f"Skipping BAR tool: {tool_name} (BAR functionality disabled)") continue + # Skip QueryGrid tools if the functionality is disabled + if tool_name.startswith("qg_") and not enableQG: + logger.info(f"Skipping QueryGrid tool: {tool_name} (functionality disabled)") + continue wrapped = make_tool_wrapper(func) mcp.tool(name=tool_name, description=wrapped.__doc__)(wrapped) logger.info(f"Created tool: {tool_name}") @@ -795,4 +817,8 @@ def get_glossary_term(term_name: str) -> dict: return {"error": f"Glossary term not found: {term_name}"} # Return the configured app and some handles used by the entrypoint if needed - return mcp, logger + def cleanup(): + if qg_manager: + qg_manager.close() + + return mcp, logger, cleanup diff --git a/src/teradata_mcp_server/config/__init__.py b/src/teradata_mcp_server/config/__init__.py index 48e3e1c..e0431b7 100644 --- a/src/teradata_mcp_server/config/__init__.py +++ b/src/teradata_mcp_server/config/__init__.py @@ -34,6 +34,13 @@ class Settings: max_overflow: int = 10 pool_timeout: int = 30 + # QueryGrid Manager + qg_manager_host: str | None = None + qg_manager_port: int | None = None + qg_manager_username: str | None = None + qg_manager_password: str | None = None + qg_manager_verify_ssl: bool = True + # Logging logging_level: str = os.getenv("LOGGING_LEVEL", "WARNING") @@ -57,5 +64,10 @@ def settings_from_env() -> Settings: pool_size=int(os.getenv("TD_POOL_SIZE", "5")), max_overflow=int(os.getenv("TD_MAX_OVERFLOW", "10")), pool_timeout=int(os.getenv("TD_POOL_TIMEOUT", "30")), + qg_manager_host=os.getenv("QG_MANAGER_HOST") or None, + qg_manager_port=int(os.getenv("QG_MANAGER_PORT")) if os.getenv("QG_MANAGER_PORT") else None, + qg_manager_username=os.getenv("QG_MANAGER_USERNAME") or None, + qg_manager_password=os.getenv("QG_MANAGER_PASSWORD") or None, + qg_manager_verify_ssl=os.getenv("QG_MANAGER_VERIFY_SSL", "true").lower() in ["true", "1", "yes"], logging_level=os.getenv("LOGGING_LEVEL", "WARNING"), ) diff --git a/src/teradata_mcp_server/config/profiles.yml b/src/teradata_mcp_server/config/profiles.yml index 46b14c1..e438f7b 100644 --- a/src/teradata_mcp_server/config/profiles.yml +++ b/src/teradata_mcp_server/config/profiles.yml @@ -53,4 +53,12 @@ bar: prompt: - ^bar_* resource: - - ^bar_* \ No newline at end of file + - ^bar_* + +qg: + tool: + - ^qg_* + prompt: + - ^qg_* + resource: + - ^qg_* \ No newline at end of file diff --git a/src/teradata_mcp_server/server.py b/src/teradata_mcp_server/server.py index 38a1784..b56bcf5 100644 --- a/src/teradata_mcp_server/server.py +++ b/src/teradata_mcp_server/server.py @@ -4,6 +4,7 @@ import asyncio import os import signal +import sys from dotenv import load_dotenv from teradata_mcp_server.config import Settings, settings_from_env @@ -28,6 +29,14 @@ def parse_args_to_settings() -> Settings: parser.add_argument('--auth_mode', type=str, required=False) parser.add_argument('--auth_cache_ttl', type=int, required=False) parser.add_argument('--logging_level', type=str, required=False) + # querygrid arguments can be added here as needed + parser.add_argument('--qg_manager_host', type=str, required=False, help='QueryGrid Manager host') + parser.add_argument('--qg_manager_port', type=int, required=False, help='QueryGrid Manager port') + parser.add_argument('--qg_manager_username', type=str, required=False, help='QueryGrid Manager username') + parser.add_argument('--qg_manager_password', required=False, help='QueryGrid Manager password') + parser.add_argument('--qg_manager_verify_ssl', type=str, required=False, help='Verify SSL certificates for QueryGrid Manager (true/false, default: true)') + + args, _ = parser.parse_known_args() @@ -43,20 +52,25 @@ def parse_args_to_settings() -> Settings: auth_mode=(args.auth_mode or env.auth_mode).lower(), auth_cache_ttl=args.auth_cache_ttl if args.auth_cache_ttl is not None else env.auth_cache_ttl, logging_level=(args.logging_level or env.logging_level).upper(), + qg_manager_host=args.qg_manager_host if args.qg_manager_host is not None else env.qg_manager_host, + qg_manager_port=args.qg_manager_port if args.qg_manager_port is not None else env.qg_manager_port, + qg_manager_username=args.qg_manager_username if args.qg_manager_username is not None else env.qg_manager_username, + qg_manager_password=args.qg_manager_password if args.qg_manager_password is not None else env.qg_manager_password, + qg_manager_verify_ssl=args.qg_manager_verify_ssl.lower() in ["true", "1", "yes"] if args.qg_manager_verify_ssl is not None else env.qg_manager_verify_ssl, ) async def main(): load_dotenv() settings = parse_args_to_settings() - mcp, logger = create_mcp_app(settings) + mcp, logger, cleanup = create_mcp_app(settings) # Graceful shutdown try: loop = asyncio.get_running_loop() for s in (signal.SIGTERM, signal.SIGINT): logger.info(f"Registering signal handler for {s.name}") - loop.add_signal_handler(s, lambda s=s: os._exit(0)) + loop.add_signal_handler(s, lambda s=s: (cleanup(), os._exit(0))) except NotImplementedError: logger.warning("Signal handling not supported on this platform") diff --git a/src/teradata_mcp_server/tools/module_loader.py b/src/teradata_mcp_server/tools/module_loader.py index 53265b7..c618b89 100644 --- a/src/teradata_mcp_server/tools/module_loader.py +++ b/src/teradata_mcp_server/tools/module_loader.py @@ -23,6 +23,7 @@ class ModuleLoader: 'base': 'teradata_mcp_server.tools.base', 'dba': 'teradata_mcp_server.tools.dba', 'fs': 'teradata_mcp_server.tools.fs', + 'qg': 'teradata_mcp_server.tools.qg', 'qlty': 'teradata_mcp_server.tools.qlty', 'rag': 'teradata_mcp_server.tools.rag', 'sql_opt': 'teradata_mcp_server.tools.sql_opt', diff --git a/src/teradata_mcp_server/tools/qg/README.md b/src/teradata_mcp_server/tools/qg/README.md new file mode 100644 index 0000000..85a30a1 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/README.md @@ -0,0 +1,208 @@ +# Teradata QueryGrid (QG) tools + +## Prerequisites + +**Teradata QueryGrid (QG) Infrastructure** must be properly configured and running before using QueryGrid tools + +### Environment Variables + +The QG tools require the following environment variables for making connection: + +- `QG_MANAGER_HOST` - Hostname for QG Manager (QGM) APIs (default: localhost) +- `QG_MANAGER_PORT` - Port for QG Manager (QGM) APIs (default: 9443) +- `QG_MANAGER_USERNAME` - Username for QGM authentication (default: support) +- `QG_MANAGER_PASSWORD` - Password for QGM authentication (default: teradata) +- `QG_MANAGER_VERIFY_SSL` - Whether to verify SSL certificates (default: true) + +### QG Profile Configuration +The QG profile is defined in `config/profiles.yml` and controls access to QG-related tools and resources. + +**Profile Configuration:** +```yaml +qg: + tool: + - ^qg_* + prompt: + - ^qg_* + resource: + - ^qg_* +``` +**What the QG profile enables:** +- Access to all `qg_*` tools for managing QueryGrid + +**Usage:** Specify `--profile qg` when running MCP server to enable QG-specific functionality + +## Available QueryGrid Tools + +The QueryGrid MCP server provides **56 GET methods** for retrieving QueryGrid configuration and status information. All tools follow the naming convention `qg_get_*` and provide read-only access to QueryGrid Manager data. + +### Core Resource Methods (42 total) + +#### Managers (2 tools) +- `qg_get_managers` - Get all QueryGrid managers with optional filtering +- `qg_get_manager_by_id` - Get a specific manager by ID + +#### Nodes (3 tools) +- `qg_get_nodes` - Get all nodes with advanced filtering options +- `qg_get_node_by_id` - Get a specific node by ID +- `qg_get_node_heartbeat_by_id` - Get the latest heartbeat sent by a specific node + +#### Systems (2 tools) +- `qg_get_systems` - Get all systems with optional filtering +- `qg_get_system_by_id` - Get a specific system by ID + +#### Connectors (6 tools) +- `qg_get_connectors` - Get all connectors with filtering +- `qg_get_connector_by_id` - Get a specific connector by ID +- `qg_get_connector_active` - Get active connector configuration +- `qg_get_connector_pending` - Get pending connector configuration +- `qg_get_connector_previous` - Get previous connector configuration +- `qg_get_connector_drivers` - Get connector drivers by version + +#### Fabrics (5 tools) +- `qg_get_fabrics` - Get all fabrics with filtering +- `qg_get_fabric_by_id` - Get a specific fabric by ID +- `qg_get_fabric_active` - Get active fabric configuration +- `qg_get_fabric_pending` - Get pending fabric configuration +- `qg_get_fabric_previous` - Get previous fabric configuration + +#### Networks (5 tools) +- `qg_get_networks` - Get all networks with filtering +- `qg_get_network_by_id` - Get a specific network by ID +- `qg_get_network_active` - Get active network configuration +- `qg_get_network_pending` - Get pending network configuration +- `qg_get_network_previous` - Get previous network configuration + +#### Links (5 tools) +- `qg_get_links` - Get all links with filtering +- `qg_get_link_by_id` - Get a specific link by ID +- `qg_get_link_active` - Get active link configuration +- `qg_get_link_pending` - Get pending link configuration +- `qg_get_link_previous` - Get previous link configuration + +#### Communication Policies (5 tools) +- `qg_get_comm_policies` - Get all communication policies +- `qg_get_comm_policy_by_id` - Get a specific communication policy by ID +- `qg_get_comm_policy_active` - Get active communication policy configuration +- `qg_get_comm_policy_pending` - Get pending communication policy configuration +- `qg_get_comm_policy_previous` - Get previous communication policy configuration + +#### Bridges (2 tools) +- `qg_get_bridges` - Get all bridges with filtering +- `qg_get_bridge_by_id` - Get a specific bridge by ID + +#### Data Centers (2 tools) +- `qg_get_datacenters` - Get all datacenters with filtering +- `qg_get_datacenter_by_id` - Get a specific datacenter by ID + +#### Node Virtual IPs (2 tools) +- `qg_get_node_virtual_ips` - Get all node virtual IPs +- `qg_get_node_virtual_ip_by_id` - Get a specific node virtual IP by ID + +### Query & Software Methods (6 total) + +#### Queries (3 tools) +- `qg_get_query_summary` - Get query summary with filtering options +- `qg_get_query_by_id` - Get a specific query by ID +- `qg_get_query_details` - Get detailed information for a specific query + +#### Software (3 tools) +- `qg_get_software` - Get QueryGrid software information +- `qg_get_software_by_id` - Get a specific software package by ID +- `qg_get_software_jdbc_driver` - Get QueryGrid JDBC driver software information +- `qg_get_software_jdbc_driver_by_name` - Get software information for a specific JDBC driver + +### User Management Methods (4 total) + +#### Users (2 tools) +- `qg_get_users` - Get all QueryGrid users +- `qg_get_user_by_username` - Get a specific user by username + +#### User Mappings (2 tools) +- `qg_get_user_mappings` - Get all user mappings with filtering +- `qg_get_user_mapping_by_id` - Get a specific user mapping by ID + +### Monitoring & Diagnostics (5 total) + +#### Issues (2 tools) +- `qg_get_issues` - Get all active QueryGrid issues +- `qg_get_issue_by_id` - Get a specific issue by ID + +#### Diagnostics (3 tools) +- `qg_get_diagnostic_check_status` - Get diagnostic check status +- `qg_get_nodes_auto_install_status` - Get automatic node installation status +- `qg_get_create_foreign_server_status` - Get CONNECTOR_CFS diagnostic check status + +### API Information (1 tool) +- `qg_get_api_info` - Get QueryGrid API information + +## Tool Parameters + +Most tools support optional parameters for filtering and configuration: + +- `extra_info` (bool) - Include additional information in responses +- `filter_by_name` (str) - Filter results by name (supports wildcards with '*') +- `filter_by_tag` (str) - Filter by tag (comma-separated key:value pairs) +- `flatten` (bool) - Flatten nested response structures + +Query-specific tools support additional parameters: +- `last_modified_after` (str) - Filter queries modified after ISO8601 timestamp +- `completed` (bool) - Include only completed queries +- `query_text_phrase` (str) - Filter by text phrase in query +- `query_ref_ids` (str) - Filter by comma-separated query reference IDs +- `initiator_query_id` (str) - Filter by initiator query ID + +Node-specific filtering parameters: +- `filter_by_system_id` (str) - Filter nodes by system ID +- `filter_by_bridge_id` (str) - Filter nodes by bridge ID +- `filter_by_fabric_id` (str) - Filter nodes by fabric ID +- `filter_by_connector_id` (str) - Filter nodes by connector ID +- `fabric_version` (str) - Filter by fabric version +- `connector_version` (str) - Filter by connector version +- `drivers` (str) - Filter with drivers parameter +- `details` (bool) - Include detailed information + +## Usage Examples + +```bash +# Get all managers +qg_get_managers + +# Get managers with extra info +qg_get_managers extra_info=true + +# Get specific manager +qg_get_manager_by_id id=my_manager_id + +# Get nodes with filtering +qg_get_nodes filter_by_system_id=my_system_id filter_by_fabric_id=my_fabric_id + +# Get systems filtered by name +qg_get_systems filter_by_name=my_system + +# Get connectors with extra info +qg_get_connectors extra_info=true + +# Get query summary with filters +qg_get_query_summary completed=true last_modified_after=2024-01-01T00:00:00Z + +# Get fabrics flattened +qg_get_fabrics flatten=true + +# Get networks filtered by tag +qg_get_networks filter_by_tag=env:production,team:backend +``` + +## Test Coverage + +The QueryGrid tools include comprehensive test coverage with **96 test cases** across all 56 tools. Each tool has at least one test case, with complex tools having multiple test scenarios covering different parameter combinations. + +Test cases are located in `tests/cases/qg_test_cases.json` and cover: +- Default parameter usage +- Optional parameter combinations +- Edge cases and filtering scenarios +- All supported parameter types (boolean, string, UUID, etc.) + +--- + +[← Return to Main README](../../../../README.md) \ No newline at end of file diff --git a/src/teradata_mcp_server/tools/qg/__init__.py b/src/teradata_mcp_server/tools/qg/__init__.py new file mode 100644 index 0000000..630dc61 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/__init__.py @@ -0,0 +1,2 @@ +from .qg_resources import * +from .qg_tools import * diff --git a/src/teradata_mcp_server/tools/qg/qg_objects.yml b/src/teradata_mcp_server/tools/qg/qg_objects.yml new file mode 100644 index 0000000..068b51f --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qg_objects.yml @@ -0,0 +1,9 @@ +# QueryGrid Objects Configuration +# This file contains object definitions for QueryGrid tools, prompts, and resources + +# Note: The main QueryGrid tools are implemented in qg_tools.py as they require +# complex HTTP API interactions with QGM systems that cannot be represented +# as simple SQL queries. + +# Future QueryGrid-related prompts and simple tools can be defined here +# following the standard YAML object format. diff --git a/src/teradata_mcp_server/tools/qg/qg_resources.py b/src/teradata_mcp_server/tools/qg/qg_resources.py new file mode 100644 index 0000000..7f48cf3 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qg_resources.py @@ -0,0 +1,11 @@ +""" +QueryGrid Resources for Teradata MCP Server +Provides resources and guidance for QueryGrid operations +""" + +import logging + +logger = logging.getLogger("teradata_mcp_server") + +# Resources will be added here in the future +# For now, this module provides the basic structure diff --git a/src/teradata_mcp_server/tools/qg/qg_tools.py b/src/teradata_mcp_server/tools/qg/qg_tools.py new file mode 100644 index 0000000..911d440 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qg_tools.py @@ -0,0 +1,2253 @@ +""" +Tools for Teradata QueryGrid MCP Server + +""" + +import logging +from teradata_mcp_server.tools.utils import create_response +from .qgm.querygrid_manager import QueryGridManager + +logger = logging.getLogger(__name__) + + +def handle_qg_get_api_info( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + *args, + **kwargs, +): + """ + Get API information including version and features. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_api_info: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.api_info_client.get_api_info() + + metadata = {"tool_name": "qg_get_api_info", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_api_info: {e}") + error_result = f"❌ Error in QueryGrid get API info operation: {str(e)}" + metadata = {"tool_name": "qg_get_api_info", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_managers( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + extra_info: bool = False, + filter_by_name: str | None = None, + *args, + **kwargs, +): + """ + Get details of all QueryGrid managers. + + Args: + extra_info (bool): Include extra information. Values are boolean True/False, not string. + filter_by_name (str | None): [Optional] Get manager associated with the specified hostname (case insensitive). Wildcard matching with '*' is supported. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_managers: args: {args}, kwargs: {kwargs}") + + try: + # Run the synchronous operation + result = qg_manager.manager_client.get_managers( + extra_info=extra_info, filter_by_name=filter_by_name + ) + + metadata = {"tool_name": "qg_get_managers", "success": True} + + logger.debug(f"Tool: handle_qg_get_managers: metadata: {metadata}") + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_managers: {e}") + error_result = f"❌ Error in QueryGrid get managers operation: {str(e)}" + metadata = {"tool_name": "qg_get_managers", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_manager_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get a specific QueryGrid manager by ID. + + Args: + id (str): The ID of the manager to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_manager_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.manager_client.get_manager_by_id(id) + + metadata = {"tool_name": "qg_get_manager_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_manager_by_id: {e}") + error_result = f"❌ Error in QueryGrid get manager by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_manager_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_nodes( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + filter_by_system_id: str | None = None, + filter_by_bridge_id: str | None = None, + filter_by_fabric_id: str | None = None, + filter_by_connector_id: str | None = None, + extra_info: bool = False, + fabric_version: str | None = None, + connector_version: str | None = None, + drivers: str | None = None, + details: bool = False, + filter_by_name: str | None = None, + *args, + **kwargs, +): + """ + Retrieve information about QueryGrid nodes. Use optional filter parameters to narrow results by specific criteria such as system ID, fabric ID, connector ID, or node name. Leave optional parameters unset if no filtering is required. + + Args: + filter_by_system_id (str | None): [Optional] Filter nodes by system ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + filter_by_bridge_id (str | None): [Optional] Filter nodes by bridge ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + filter_by_fabric_id (str | None): [Optional] Filter nodes by fabric ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + filter_by_connector_id (str | None): [Optional] Filter nodes by connector ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + fabric_version (str | None): [Optional] Filter nodes by fabric version. e.g., "03.10.00.01". + connector_version (str | None): [Optional] Filter nodes by connector version. e.g., "03.10.00.01". + drivers (str | None): [Optional] Works with filter_by_connector_id to make status relative to the drivers for the specified connector. Values can be True/False. + details (bool): Include detailed information + filter_by_name (str | None): [Optional] Filter nodes by name. The name can be any sequence of characters representing the node's name, such as 'Node1'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_nodes: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.node_client.get_nodes( + filter_by_system_id=filter_by_system_id, + filter_by_bridge_id=filter_by_bridge_id, + filter_by_fabric_id=filter_by_fabric_id, + filter_by_connector_id=filter_by_connector_id, + extra_info=extra_info, + fabric_version=fabric_version, + connector_version=connector_version, + drivers=drivers, + details=details, + filter_by_name=filter_by_name, + ) + + metadata = {"tool_name": "qg_get_nodes", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_nodes: {e}") + error_result = f"❌ Error in QueryGrid get nodes operation: {str(e)}" + metadata = {"tool_name": "qg_get_nodes", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_node_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get details of a specific QueryGrid node by ID. + + Args: + id (str): The ID of the node to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_node_by_id: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.node_client.get_node_by_id(id) + + metadata = {"tool_name": "qg_get_node_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_node_by_id: {e}") + error_result = f"❌ Error in QueryGrid get node by ID operation: {str(e)}" + metadata = {"tool_name": "qg_get_node_by_id", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_node_heartbeat_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the latest heartbeat sent by a specific QueryGrid node by ID. + + Args: + id (str): The ID of the node to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_node_heartbeat_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.node_client.get_node_heartbeat_by_id(id) + + metadata = {"tool_name": "qg_get_node_heartbeat_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_node_heartbeat_by_id: {e}") + error_result = ( + f"❌ Error in QueryGrid get node heartbeat by ID operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_node_heartbeat_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_systems( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + extra_info: bool = False, + filter_by_proxy_support: str | None = None, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + *args, + **kwargs, +): + """ + Get details of all QueryGrid systems. + + Args: + extra_info (bool): Include extra information. Values are boolean True/False, not string. + filter_by_proxy_support (str | None): [Optional] Filter systems based on proxy support type. Available values : NO_PROXY, LOCAL_PROXY, BRIDGE_PROXY + filter_by_name (str | None): [Optional] Get system associated with the specified name (case insensitive). Wildcard matching with '*' is supported. + filter_by_tag (str | None): [Optional] Get system associated with the specified tag. Provide ','(comma) separated list of key:value pairs. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_systems: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.system_client.get_systems( + extra_info=extra_info, + filter_by_proxy_support=filter_by_proxy_support, + filter_by_name=filter_by_name, + filter_by_tag=filter_by_tag, + ) + + metadata = {"tool_name": "qg_get_systems", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_systems: {e}") + error_result = f"❌ Error in QueryGrid get systems operation: {str(e)}" + metadata = {"tool_name": "qg_get_systems", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_system_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + extra_info: bool = False, + *args, + **kwargs, +): + """ + Get a specific QueryGrid system by ID. + + Args: + id (str): The ID of the system to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_system_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.system_client.get_system_by_id(id, extra_info=extra_info) + + metadata = {"tool_name": "qg_get_system_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_system_by_id: {e}") + error_result = f"❌ Error in QueryGrid get system by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_system_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_connectors( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + flatten: bool = False, + extra_info: bool = False, + filter_by_name: str | None = None, + fabric_version: str | None = None, + filter_by_tag: str | None = None, + *args, + **kwargs, +): + """ + Get details of all QueryGrid connectors. Optional filters can be applied to narrow down the results. + + Args: + flatten (bool): Flatten the response structure + extra_info (bool): Include extra information. Values are boolean True/False, not string. + fabric_version (str | None): [Optional] Filter connectors by fabric version + filter_by_name (str | None): [Optional] Get connector associated with the specified name (case insensitive). Wildcard matching with '*' is supported. + filter_by_tag (str | None): [Optional] Get connector associated with the specified tag. Provide ','(comma) separated list of key:value pairs. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_connectors: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.connector_client.get_connectors( + flatten=flatten, + extra_info=extra_info, + filter_by_name=filter_by_name, + filter_by_tag=filter_by_tag, + fabric_version=fabric_version, + ) + + metadata = {"tool_name": "qg_get_connectors", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_connectors: {e}") + error_result = f"❌ Error in QueryGrid get connectors operation: {str(e)}" + metadata = {"tool_name": "qg_get_connectors", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_connector_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + extra_info: bool = False, + *args, + **kwargs, +): + """ + Get details of a specific QueryGrid connector by ID. + + Args: + id (str): The ID of the connector to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_connector_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.connector_client.get_connector_by_id( + id=id, extra_info=extra_info + ) + + metadata = {"tool_name": "qg_get_connector_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_connector_by_id: {e}") + error_result = f"❌ Error in QueryGrid get connector by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_connector_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_connector_active( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the active configuration for a QueryGrid connector. + + Args: + id (str): The ID of the connector. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_connector_active: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.connector_client.get_connector_active(id) + + metadata = {"tool_name": "qg_get_connector_active", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_connector_active: {e}") + error_result = f"❌ Error in QueryGrid get connector active operation: {str(e)}" + metadata = { + "tool_name": "qg_get_connector_active", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_connector_pending( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get details of the pending configuration for a QueryGrid connector. + + Args: + id (str): The ID of the connector. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_connector_pending: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.connector_client.get_connector_pending(id) + + metadata = {"tool_name": "qg_get_connector_pending", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_connector_pending: {e}") + error_result = ( + f"❌ Error in QueryGrid get connector pending operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_connector_pending", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_connector_previous( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the previous configuration for a QueryGrid connector. + + Args: + id (str): The ID of the connector. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_connector_previous: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.connector_client.get_connector_previous(id) + + metadata = {"tool_name": "qg_get_connector_previous", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_connector_previous: {e}") + error_result = ( + f"❌ Error in QueryGrid get connector previous operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_connector_previous", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_connector_drivers( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + version_id: str, + *args, + **kwargs, +): + """ + Get details of the drivers for a QueryGrid connector. + + Args: + id (str): The ID of the connector. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + version_id (str): The version ID of the connector + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_connector_drivers: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.connector_client.get_connector_drivers( + id=id, version_id=version_id + ) + + metadata = {"tool_name": "qg_get_connector_drivers", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_connector_drivers: {e}") + error_result = ( + f"❌ Error in QueryGrid get connector drivers operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_connector_drivers", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_links( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + flatten: bool = False, + extra_info: bool = False, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + *args, + **kwargs, +): + """ + Get details of all QueryGrid links. Optional filters can be applied to narrow down the results. + + Args: + flatten (bool): Flatten the response structure + extra_info (bool): Include extra information. Values are boolean True/False, not string. + filter_by_name (str | None): [Optional] Get link associated with the specified name (case insensitive). Wildcard matching with '*' is supported. + filter_by_tag (str | None): [Optional] Get link associated with the specified tag. Provide ','(comma) separated list of key:value pairs. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_links: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.link_client.get_links( + flatten=flatten, + extra_info=extra_info, + filter_by_name=filter_by_name, + filter_by_tag=filter_by_tag, + ) + + metadata = {"tool_name": "qg_get_links", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_links: {e}") + error_result = f"❌ Error in QueryGrid get links operation: {str(e)}" + metadata = {"tool_name": "qg_get_links", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_link_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + extra_info: bool = False, + *args, + **kwargs, +): + """ + Get a specific QueryGrid link by ID. + + Args: + id (str): The ID of the link to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_link_by_id: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.link_client.get_link_by_id(id, extra_info=extra_info) + + metadata = {"tool_name": "qg_get_link_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_link_by_id: {e}") + error_result = f"❌ Error in QueryGrid get link by ID operation: {str(e)}" + metadata = {"tool_name": "qg_get_link_by_id", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_link_active( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the active configuration for a QueryGrid link. + + Args: + id (str): The ID of the link. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_link_active: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.link_client.get_link_active(id) + + metadata = {"tool_name": "qg_get_link_active", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_link_active: {e}") + error_result = f"❌ Error in QueryGrid get link active operation: {str(e)}" + metadata = { + "tool_name": "qg_get_link_active", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_link_pending( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the pending configuration for a QueryGrid link. + + Args: + id (str): The ID of the link. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_link_pending: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.link_client.get_link_pending(id) + + metadata = {"tool_name": "qg_get_link_pending", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_link_pending: {e}") + error_result = f"❌ Error in QueryGrid get link pending operation: {str(e)}" + metadata = { + "tool_name": "qg_get_link_pending", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_link_previous( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the previous configuration for a QueryGrid link. + + Args: + id (str): The ID of the link. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_link_previous: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.link_client.get_link_previous(id) + + metadata = {"tool_name": "qg_get_link_previous", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_link_previous: {e}") + error_result = f"❌ Error in QueryGrid get link previous operation: {str(e)}" + metadata = { + "tool_name": "qg_get_link_previous", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_fabrics( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + flatten: bool = False, + extra_info: bool = False, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + *args, + **kwargs, +): + """ + Get all QueryGrid fabrics. + + Args: + flatten (bool): Flatten out the active, pending, and previous versions into array elements instead of nesting them. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + filter_by_name (str | None): [Optional] Get fabric associated with the specified name (case insensitive). Wildcard matching with '*' is supported. + filter_by_tag (str | None): [Optional] Get fabric associated with the specified tag. Provide ','(comma) separated list of key:value pairs. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_fabrics: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.fabric_client.get_fabrics( + flatten=flatten, + extra_info=extra_info, + filter_by_name=filter_by_name, + filter_by_tag=filter_by_tag, + ) + + metadata = {"tool_name": "qg_get_fabrics", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_fabrics: {e}") + error_result = f"❌ Error in QueryGrid get fabrics operation: {str(e)}" + metadata = {"tool_name": "qg_get_fabrics", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_fabric_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + extra_info: bool = False, + *args, + **kwargs, +): + """ + Get a specific QueryGrid fabric by ID. + + Args: + id (str): The ID of the fabric to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_fabric_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.fabric_client.get_fabric_by_id(id, extra_info=extra_info) + + metadata = {"tool_name": "qg_get_fabric_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_fabric_by_id: {e}") + error_result = f"❌ Error in QueryGrid get fabric by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_fabric_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_fabric_active( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the active configuration for a QueryGrid fabric. + + Args: + id (str): The ID of the fabric. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_fabric_active: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.fabric_client.get_fabric_active(id) + + metadata = {"tool_name": "qg_get_fabric_active", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_fabric_active: {e}") + error_result = f"❌ Error in QueryGrid get fabric active operation: {str(e)}" + metadata = { + "tool_name": "qg_get_fabric_active", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_fabric_pending( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the pending configuration for a QueryGrid fabric. + + Args: + id (str): The ID of the fabric. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_fabric_pending: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.fabric_client.get_fabric_pending(id) + + metadata = {"tool_name": "qg_get_fabric_pending", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_fabric_pending: {e}") + error_result = f"❌ Error in QueryGrid get fabric pending operation: {str(e)}" + metadata = { + "tool_name": "qg_get_fabric_pending", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_fabric_previous( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the previous configuration for a QueryGrid fabric. + + Args: + id (str): The ID of the fabric. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_fabric_previous: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.fabric_client.get_fabric_previous(id) + + metadata = {"tool_name": "qg_get_fabric_previous", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_fabric_previous: {e}") + error_result = f"❌ Error in QueryGrid get fabric previous operation: {str(e)}" + metadata = { + "tool_name": "qg_get_fabric_previous", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_software( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + filter_by_name: str | None = None, + *args, + **kwargs, +): + """ + Get QueryGrid software information for all of the uploaded software packages. + Args: + filter_by_name (str | None): [Optional] Get software associated with the specified name (case insensitive). Wildcard matching with '*' is supported. + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_software: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.software_client.get_software(filter_by_name=filter_by_name) + + metadata = {"tool_name": "qg_get_software", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_software: {e}") + error_result = f"❌ Error in QueryGrid get software operation: {str(e)}" + metadata = {"tool_name": "qg_get_software", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_software_jdbc_driver( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + *args, + **kwargs, +): + """ + Get QueryGrid software information for all of the uploaded JDBC driver software packages. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_software_jdbc_driver: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.software_client.get_software_jdbc_driver() + + metadata = {"tool_name": "qg_get_software_jdbc_driver", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_software_jdbc_driver: {e}") + error_result = ( + f"❌ Error in QueryGrid get software JDBC driver operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_software_jdbc_driver", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_software_jdbc_driver_by_name( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + jdbc_driver_name: str, + *args, + **kwargs, +): + """ + Get QueryGrid software information for the uploaded software packages related to a specific JDBC driver name. + + Args: + jdbc_driver_name (str): The JDBC driver name to find + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_software_jdbc_driver_by_name: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.software_client.get_software_jdbc_driver_by_name( + jdbc_driver_name + ) + + metadata = {"tool_name": "qg_get_software_jdbc_driver_by_name", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_software_jdbc_driver_by_name: {e}") + error_result = f"❌ Error in QueryGrid get software JDBC driver by name operation: {str(e)}" + metadata = { + "tool_name": "qg_get_software_jdbc_driver_by_name", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_software_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get a specific QueryGrid software by ID. + + Args: + id (str): The ID of the software to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_software_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.software_client.get_software_by_id(id) + + metadata = {"tool_name": "qg_get_software_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_software_by_id: {e}") + error_result = f"❌ Error in QueryGrid get software by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_software_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_query_summary( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + last_modified_after: str | None = None, + completed: bool = False, + query_text_phrase: str | None = None, + query_ref_ids: str | None = None, + initiator_query_id: str | None = None, + *args, + **kwargs, +): + """ + Get summaries of all the queries run using QueryGrid. Query summaries can be filtered based on various criteria. Optional arguments can be ignored if not needed. + + Args: + last_modified_after (str | None): [Optional] Return all query summary that have been modified since the time provided. Time should be provided in ISO8601 format. e.g., '2023-01-01T00:00:00Z' + completed (bool): Include completed queries. Values are 'true' or 'false'. + query_text_phrase (str | None): [Optional] Only return queries that contain the supplied phrase in the query text. + query_ref_ids (str | None): [Optional] Filter by comma separated query reference IDs. IDs are in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000,223e4567-e89b-12d3-a456-426614174001'. + initiator_query_id (str | None): [Optional] Filter by initiator query ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_query_summary: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.query_client.get_query_summary( + last_modified_after=last_modified_after, + completed=completed, + query_text_phrase=query_text_phrase, + query_ref_ids=query_ref_ids, + initiator_query_id=initiator_query_id, + ) + + metadata = {"tool_name": "qg_get_query_summary", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_query_summary: {e}") + error_result = f"❌ Error in QueryGrid get query summary operation: {str(e)}" + metadata = { + "tool_name": "qg_get_query_summary", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_query_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get a specific QueryGrid query by ID. + + Args: + id (str): The ID of the query to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_query_by_id: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.query_client.get_query_by_id(id) + + metadata = {"tool_name": "qg_get_query_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_query_by_id: {e}") + error_result = f"❌ Error in QueryGrid get query by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_query_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_query_details( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get detailed information for a specific QueryGrid query. + + Args: + id (str): The ID of the query to retrieve details for + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_query_details: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.query_client.get_query_details(id) + + metadata = {"tool_name": "qg_get_query_details", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_query_details: {e}") + error_result = f"❌ Error in QueryGrid get query details operation: {str(e)}" + metadata = { + "tool_name": "qg_get_query_details", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_datacenters( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + filter_by_name: str | None = None, + *args, + **kwargs, +): + """ + Get details of all QueryGrid datacenters. + + Args: + filter_by_name (str | None): [Optional] Filter datacenters by name + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_datacenters: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.datacenter_client.get_datacenters( + filter_by_name=filter_by_name + ) + + metadata = {"tool_name": "qg_get_datacenters", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_datacenters: {e}") + error_result = f"❌ Error in QueryGrid get datacenters operation: {str(e)}" + metadata = { + "tool_name": "qg_get_datacenters", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_datacenter_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get a specific QueryGrid datacenter by ID. + + Args: + id (str): The ID of the datacenter to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_datacenter_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.datacenter_client.get_datacenter_by_id(id) + + metadata = {"tool_name": "qg_get_datacenter_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_datacenter_by_id: {e}") + error_result = f"❌ Error in QueryGrid get datacenter by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_datacenter_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_networks( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + flatten: bool = False, + extra_info: bool = False, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + *args, + **kwargs, +): + """ + Get details of all QueryGrid networks. + + Args: + flatten (bool): Flatten out the active, pending, and previous versions into array elements instead of nesting them. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + filter_by_name (str | None): [Optional] Get network associated with the specified name (case insensitive). Wildcard matching with '*' is supported. + filter_by_tag (str | None): [Optional] Get network associated with the specified tag. Provide ','(comma) separated list of key:value pairs. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_networks: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.network_client.get_networks( + flatten=flatten, + extra_info=extra_info, + filter_by_name=filter_by_name, + filter_by_tag=filter_by_tag, + ) + + metadata = {"tool_name": "qg_get_networks", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_networks: {e}") + error_result = f"❌ Error in QueryGrid get networks operation: {str(e)}" + metadata = {"tool_name": "qg_get_networks", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_network_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + extra_info: bool = False, + *args, + **kwargs, +): + """ + Get a specific QueryGrid network by ID. + + Args: + id (str): The ID of the network to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_network_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.network_client.get_network_by_id(id, extra_info=extra_info) + + metadata = {"tool_name": "qg_get_network_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_network_by_id: {e}") + error_result = f"❌ Error in QueryGrid get network by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_network_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_network_active( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the active configuration for a QueryGrid network. + + Args: + id (str): The ID of the network. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_network_active: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.network_client.get_network_active(id) + + metadata = {"tool_name": "qg_get_network_active", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_network_active: {e}") + error_result = f"❌ Error in QueryGrid get network active operation: {str(e)}" + metadata = { + "tool_name": "qg_get_network_active", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_network_pending( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the pending configuration for a QueryGrid network. + + Args: + id (str): The ID of the network. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_network_pending: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.network_client.get_network_pending(id) + + metadata = {"tool_name": "qg_get_network_pending", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_network_pending: {e}") + error_result = f"❌ Error in QueryGrid get network pending operation: {str(e)}" + metadata = { + "tool_name": "qg_get_network_pending", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_network_previous( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the previous configuration for a QueryGrid network. + + Args: + id (str): The ID of the network. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_network_previous: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.network_client.get_network_previous(id) + + metadata = {"tool_name": "qg_get_network_previous", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_network_previous: {e}") + error_result = f"❌ Error in QueryGrid get network previous operation: {str(e)}" + metadata = { + "tool_name": "qg_get_network_previous", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_node_virtual_ips( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + *args, + **kwargs, +): + """ + Get all QueryGrid node virtual IPs associated with the QueryGrid nodes. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_node_virtual_ips: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.node_virtual_ip_client.get_node_virtual_ips() + + metadata = {"tool_name": "qg_get_node_virtual_ips", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_node_virtual_ips: {e}") + error_result = f"❌ Error in QueryGrid get node virtual IPs operation: {str(e)}" + metadata = { + "tool_name": "qg_get_node_virtual_ips", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_node_virtual_ip_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get a specific QueryGrid node virtual IP by ID. + + Args: + id (str): The ID of the virtual IP to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_node_virtual_ip_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.node_virtual_ip_client.get_node_virtual_ip_by_id(id) + + metadata = {"tool_name": "qg_get_node_virtual_ip_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_node_virtual_ip_by_id: {e}") + error_result = ( + f"❌ Error in QueryGrid get node virtual IP by ID operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_node_virtual_ip_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_user_mappings( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + filter_by_name: str | None = None, + *args, + **kwargs, +): + """ + Get details of all QueryGrid user mappings. + + Args: + filter_by_name (str | None): [Optional] Filter user mappings by the specified name. Wildcard matching with '*' is supported. This parameter is optional. Do not provide it if no filtering is needed. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_user_mappings: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.user_mapping_client.get_user_mappings( + filter_by_name=filter_by_name + ) + + metadata = {"tool_name": "qg_get_user_mappings", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_user_mappings: {e}") + error_result = f"❌ Error in QueryGrid get user mappings operation: {str(e)}" + metadata = { + "tool_name": "qg_get_user_mappings", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_user_mapping_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get details of a specific QueryGrid user mapping by ID. + + Args: + id (str): The ID of the user mapping to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_user_mapping_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.user_mapping_client.get_user_mapping_by_id(id) + + metadata = {"tool_name": "qg_get_user_mapping_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_user_mapping_by_id: {e}") + error_result = ( + f"❌ Error in QueryGrid get user mapping by ID operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_user_mapping_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_users( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + *args, + **kwargs, +): + """ + Get all QueryGrid user accounts. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_users: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.user_client.get_users() + + metadata = {"tool_name": "qg_get_users", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_users: {e}") + error_result = f"❌ Error in QueryGrid get users operation: {str(e)}" + metadata = {"tool_name": "qg_get_users", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_user_by_username( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + username: str, + *args, + **kwargs, +): + """ + Get a specific QueryGrid user account by username. + + Args: + username (str): The username of the user to retrieve + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_user_by_username: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.user_client.get_user_by_username(username) + + metadata = {"tool_name": "qg_get_user_by_username", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_user_by_username: {e}") + error_result = f"❌ Error in QueryGrid get user by username operation: {str(e)}" + metadata = { + "tool_name": "qg_get_user_by_username", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_issues( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + *args, + **kwargs, +): + """ + Get all QueryGrid issues. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_issues: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.issue_client.get_issues() + + metadata = {"tool_name": "qg_get_issues", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_issues: {e}") + error_result = f"❌ Error in QueryGrid get issues operation: {str(e)}" + metadata = {"tool_name": "qg_get_issues", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_issue_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get a specific QueryGrid issue by ID. + + Args: + id (str): The ID of the issue to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_issue_by_id: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.issue_client.get_issue_by_id(id) + + metadata = {"tool_name": "qg_get_issue_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_issue_by_id: {e}") + error_result = f"❌ Error in QueryGrid get issue by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_issue_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_diagnostic_check_status( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the status of a QueryGrid diagnostic check. + + Args: + id (str): The ID of the diagnostic check. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_diagnostic_check_status: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.diagnostic_client.get_diagnostic_check_status(id) + + metadata = {"tool_name": "qg_get_diagnostic_check_status", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_diagnostic_check_status: {e}") + error_result = ( + f"❌ Error in QueryGrid get diagnostic check status operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_diagnostic_check_status", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_bridges( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + filter_by_system_id: str | None = None, + filter_by_name: str | None = None, + *args, + **kwargs, +): + """ + Get all QueryGrid bridges. Optional arguments can be ignored if not needed. + + Args: + filter_by_system_id (str | None): [Optional] Filter by system ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000' + filter_by_name (str | None): [Optional] Filter bridges by name + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug(f"Tool: handle_qg_get_bridges: args: {args}, kwargs: {kwargs}") + + try: + result = qg_manager.bridge_client.get_bridges( + filter_by_system_id=filter_by_system_id, filter_by_name=filter_by_name + ) + + metadata = {"tool_name": "qg_get_bridges", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_bridges: {e}") + error_result = f"❌ Error in QueryGrid get bridges operation: {str(e)}" + metadata = {"tool_name": "qg_get_bridges", "error": str(e), "success": False} + return create_response(error_result, metadata) + + +def handle_qg_get_bridge_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get a specific QueryGrid bridge by ID. + + Args: + id (str): The ID of the bridge to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_bridge_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.bridge_client.get_bridge_by_id(id) + + metadata = {"tool_name": "qg_get_bridge_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_bridge_by_id: {e}") + error_result = f"❌ Error in QueryGrid get bridge by ID operation: {str(e)}" + metadata = { + "tool_name": "qg_get_bridge_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_comm_policies( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + flatten: bool = False, + extra_info: bool = False, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + *args, + **kwargs, +): + """ + Get all QueryGrid communication policies. Optional arguments can be ignored if not needed. + + Args: + flatten (bool): Flatten out the active, pending, and previous versions into array elements instead of nesting them. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + filter_by_name (str | None): [Optional] Get communication policy associated with the specified name (case insensitive). Wildcard matching with '*' is supported. + filter_by_tag (str | None): [Optional] Get communication policy associated with the specified tag. Provide ','(comma) separated list of key:value pairs. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_comm_policies: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.comm_policy_client.get_comm_policies( + flatten=flatten, + extra_info=extra_info, + filter_by_name=filter_by_name, + filter_by_tag=filter_by_tag, + ) + + metadata = {"tool_name": "qg_get_comm_policies", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_comm_policies: {e}") + error_result = ( + f"❌ Error in QueryGrid get communication policies operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_comm_policies", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_comm_policy_by_id( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + extra_info: bool = False, + *args, + **kwargs, +): + """ + Get a specific QueryGrid communication policy by ID. + + Args: + id (str): The ID of the communication policy to retrieve. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + extra_info (bool): Include extra information. Values are boolean True/False, not string. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_comm_policy_by_id: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.comm_policy_client.get_comm_policy_by_id( + id, extra_info=extra_info + ) + + metadata = {"tool_name": "qg_get_comm_policy_by_id", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_comm_policy_by_id: {e}") + error_result = ( + f"❌ Error in QueryGrid get communication policy by ID operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_comm_policy_by_id", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_comm_policy_active( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the active configuration for a QueryGrid communication policy. + + Args: + id (str): The ID of the communication policy. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_comm_policy_active: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.comm_policy_client.get_comm_policy_active(id) + + metadata = {"tool_name": "qg_get_comm_policy_active", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_comm_policy_active: {e}") + error_result = ( + f"❌ Error in QueryGrid get communication policy active operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_comm_policy_active", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_comm_policy_pending( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the pending configuration for a QueryGrid communication policy. + + Args: + id (str): The ID of the communication policy. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_comm_policy_pending: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.comm_policy_client.get_comm_policy_pending(id) + + metadata = {"tool_name": "qg_get_comm_policy_pending", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_comm_policy_pending: {e}") + error_result = f"❌ Error in QueryGrid get communication policy pending operation: {str(e)}" + metadata = { + "tool_name": "qg_get_comm_policy_pending", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_comm_policy_previous( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the previous configuration for a QueryGrid communication policy. + + Args: + id (str): The ID of the communication policy. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_comm_policy_previous: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.comm_policy_client.get_comm_policy_previous(id) + + metadata = {"tool_name": "qg_get_comm_policy_previous", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_comm_policy_previous: {e}") + error_result = f"❌ Error in QueryGrid get communication policy previous operation: {str(e)}" + metadata = { + "tool_name": "qg_get_comm_policy_previous", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_nodes_auto_install_status( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the status of the automatic node installation. + + Args: + id (str): The installation ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_nodes_auto_install_status: args: {args}, kwargs: {kwargs}" + ) + + try: + result = qg_manager.nodes_auto_install_client.get_nodes_auto_install_status(id) + + metadata = {"tool_name": "qg_get_nodes_auto_install_status", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_nodes_auto_install_status: {e}") + error_result = ( + f"❌ Error in QueryGrid get nodes auto install status operation: {str(e)}" + ) + metadata = { + "tool_name": "qg_get_nodes_auto_install_status", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) + + +def handle_qg_get_create_foreign_server_status( + conn: any, # Not used for QG operations, but required by MCP framework + qg_manager: QueryGridManager, # Automatically injected QueryGrid manager instance + id: str, + *args, + **kwargs, +): + """ + Get the status of the CONNECTOR_CFS diagnostic check for foreign server creation. + + Args: + id (str): The diagnostic check ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + ResponseType: formatted response with operation results + metadata + """ + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + f"Tool: handle_qg_get_create_foreign_server_status: args: {args}, kwargs: {kwargs}" + ) + + try: + result = ( + qg_manager.create_foreign_server_client.get_create_foreign_server_status(id) + ) + + metadata = {"tool_name": "qg_get_create_foreign_server_status", "success": True} + + return create_response(result, metadata) + + except Exception as e: + logger.error(f"Error in handle_qg_get_create_foreign_server_status: {e}") + error_result = f"❌ Error in QueryGrid get create foreign server status operation: {str(e)}" + metadata = { + "tool_name": "qg_get_create_foreign_server_status", + "error": str(e), + "success": False, + } + return create_response(error_result, metadata) diff --git a/src/teradata_mcp_server/tools/qg/qgm/__init__.py b/src/teradata_mcp_server/tools/qg/qgm/__init__.py new file mode 100644 index 0000000..e762c2f --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/__init__.py @@ -0,0 +1,20 @@ +from .base import * +from .bridges import * +from .comm_policies import * +from .connectors import * +from .datacenters import * +from .diagnostics import * +from .fabrics import * +from .issues import * +from .links import * +from .managers import * +from .networks import * +from .node_virtual_ips import * +from .nodes import * +from .querygrid_manager import qgm +from .queries import * +from .softwares import * +from .support_archive import * +from .systems import * +from .user_mappings import * +from .users import * diff --git a/src/teradata_mcp_server/tools/qg/qgm/api_info.py b/src/teradata_mcp_server/tools/qg/qgm/api_info.py new file mode 100644 index 0000000..986774c --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/api_info.py @@ -0,0 +1,16 @@ +""" +API Info client for QueryGrid Manager API. +""" + +from .base import BaseClient + + +class ApiInfoClient(BaseClient): + """Client for API info operations.""" + + BASE_ENDPOINT = "/api/" + + def get_api_info(self) -> dict: + """Get information about the API version and features.""" + api_endpoint = self.BASE_ENDPOINT + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/base.py b/src/teradata_mcp_server/tools/qg/qgm/base.py new file mode 100644 index 0000000..623a87f --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/base.py @@ -0,0 +1,31 @@ +""" +Base client class for QueryGrid Manager API. +""" + +import logging +import os +from typing import Any + +import requests + + +class BaseClient: + """Base class for QueryGrid Manager API resource clients.""" + + def __init__(self, session: requests.Session, base_url: str): + self.session = session + self.base_url = base_url.rstrip("/") + self.logger = logging.getLogger(self.__class__.__module__) + + def _request(self, method: str, endpoint: str, **kwargs) -> Any: + """Make a request to the QGM API.""" + url = f"{self.base_url}{endpoint}" + self.logger.debug(f"Making {method} request to {url}") + + response = self.session.request(method, url, **kwargs) + response.raise_for_status() + + try: + return response.json() + except ValueError: + return response.text diff --git a/src/teradata_mcp_server/tools/qg/qgm/bridges.py b/src/teradata_mcp_server/tools/qg/qgm/bridges.py new file mode 100644 index 0000000..318bdfb --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/bridges.py @@ -0,0 +1,58 @@ +""" +Manager for QueryGrid bridges. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class BridgeClient(BaseClient): + """Manager for QueryGrid bridges.""" + + BASE_ENDPOINT = "/api/config/bridges" + + def get_bridges( + self, filter_by_system_id: str | None = None, filter_by_name: str | None = None + ) -> Dict[str, Any]: + """ + Retrieve the list of QueryGrid bridge objects from the API. + + Args: + filter_by_system_id (str | None): Get bridges associated with the specified system ID. + filter_by_name (str | None): If provided, filters the bridges by name. + + Returns: + Dict[str, Any]: A dictionary containing the list of bridges and + any additional metadata from the API response. + """ + api_endpoint = self.BASE_ENDPOINT + params = {} + if ( + filter_by_system_id is not None + and filter_by_system_id != "" + and filter_by_system_id != "null" + ): + params["filterBySystemId"] = filter_by_system_id + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + return self._request( + "GET", self.BASE_ENDPOINT, params=params if params else None + ) + + def get_bridge_by_id(self, id: str) -> Dict[str, Any]: + """ + Retrieve a specific QueryGrid bridge object by its ID. + + Args: + id (str): The unique identifier of the bridge. + + Returns: + Dict[str, Any]: A dictionary containing the bridge details. + """ + api_endpoint = f"{self.BASE_ENDPOINT}/{id}" + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/comm_policies.py b/src/teradata_mcp_server/tools/qg/qgm/comm_policies.py new file mode 100644 index 0000000..7066fb0 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/comm_policies.py @@ -0,0 +1,89 @@ +""" +Manager for QueryGrid communication policies. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class CommPolicyClient(BaseClient): + """Manager for QueryGrid communication policies.""" + + BASE_ENDPOINT = "/api/config/comm-policies" + + def get_comm_policies( + self, + flatten: bool = False, + extra_info: bool = False, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + ) -> Dict[str, Any]: + """ + Retrieve the list of QueryGrid communication policy objects from the API. + + Args: + flatten (bool): Flatten versions into array elements. Defaults to False. + extra_info (bool): Include extra details. Defaults to False. + filter_by_name (str | None): Filter by name. + filter_by_tag (str | None): Filter by tag (comma-separated key:value pairs). + + Returns: + Dict[str, Any]: A dictionary containing the list of communication policies. + """ + api_endpoint = self.BASE_ENDPOINT + params = {} + if flatten: + params["flatten"] = flatten + if extra_info: + params["extraInfo"] = extra_info + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + if ( + filter_by_tag is not None + and filter_by_tag != "" + and filter_by_tag != "null" + ): + params["filterByTag"] = filter_by_tag + return self._request( + "GET", self.BASE_ENDPOINT, params=params if params else None + ) + + def get_comm_policy_by_id( + self, id: str, extra_info: bool = False + ) -> Dict[str, Any]: + """ + Retrieve a specific communication policy by ID. + + Args: + id (str): The policy ID. + extra_info (bool): Include extra details. + + Returns: + Dict[str, Any]: The communication policy details. + """ + params = {} + if extra_info: + params["extraInfo"] = extra_info + return self._request( + "GET", f"{self.BASE_ENDPOINT}/{id}", params=params if params else None + ) + + def get_comm_policy_active(self, id: str) -> Dict[str, Any]: + """Get the active version of a communication policy.""" + api_endpoint = f"{self.BASE_ENDPOINT}/{id}/active" + return self._request("GET", api_endpoint) + + def get_comm_policy_pending(self, id: str) -> Dict[str, Any]: + """Get the pending version of a communication policy.""" + api_endpoint = f"{self.BASE_ENDPOINT}/{id}/pending" + return self._request("GET", api_endpoint) + + def get_comm_policy_previous(self, id: str) -> Dict[str, Any]: + """Get the previous version of a communication policy.""" + api_endpoint = f"{self.BASE_ENDPOINT}/{id}/previous" + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/connectors.py b/src/teradata_mcp_server/tools/qg/qgm/connectors.py new file mode 100644 index 0000000..12d54a9 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/connectors.py @@ -0,0 +1,76 @@ +""" +Manager for QueryGrid connectors. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class ConnectorClient(BaseClient): + """Manager for QueryGrid connectors.""" + + BASE_ENDPOINT = "/api/config/connectors" + + def __init__(self, session, base_url: str): + super().__init__(session, base_url) + self.resource_path = self.BASE_ENDPOINT + + def get_connectors( + self, + flatten: bool = False, + extra_info: bool = False, + fabric_version: str | None = None, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + ) -> Dict[str, Any]: + """Get all connectors.""" + params = {} + if flatten: + params["flatten"] = flatten + if extra_info: + params["extraInfo"] = extra_info + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + if ( + filter_by_tag is not None + and filter_by_tag != "" + and filter_by_tag != "null" + ): + params["filterByTag"] = filter_by_tag + if ( + fabric_version is not None + and fabric_version != "" + and fabric_version != "null" + ): + params["fabricVersion"] = fabric_version + return self._request("GET", self.resource_path, params=params) + + def get_connector_by_id(self, id: str, extra_info: bool = False) -> Dict[str, Any]: + """Get a connector by ID.""" + params = {} + if extra_info: + params["extraInfo"] = extra_info + return self._request("GET", f"{self.resource_path}/{id}", params=params) + + def get_connector_active(self, id: str) -> Dict[str, Any]: + """Get the active version of a connector.""" + return self._request("GET", f"{self.resource_path}/{id}/active") + + def get_connector_pending(self, id: str) -> Dict[str, Any]: + """Get the pending version of a connector.""" + return self._request("GET", f"{self.resource_path}/{id}/pending") + + def get_connector_previous(self, id: str) -> Dict[str, Any]: + """Get the previous version of a connector.""" + return self._request("GET", f"{self.resource_path}/{id}/previous") + + def get_connector_drivers(self, id: str, version_id: str) -> Dict[str, Any]: + """Get drivers for a connector version.""" + return self._request( + "GET", f"{self.resource_path}/{id}/versions/{version_id}/drivers" + ) diff --git a/src/teradata_mcp_server/tools/qg/qgm/create_foreign_server.py b/src/teradata_mcp_server/tools/qg/qgm/create_foreign_server.py new file mode 100644 index 0000000..313326e --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/create_foreign_server.py @@ -0,0 +1,26 @@ +""" +Manager for QueryGrid create foreign server operations. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class CreateForeignServerClient(BaseClient): + """Manager for QueryGrid create foreign server operations.""" + + BASE_ENDPOINT = "/api/operations" + + def get_create_foreign_server_status(self, id: str) -> Dict[str, Any]: + """ + Get the status of the CONNECTOR_CFS diagnostic check for foreign server creation. + + Args: + id (str): The diagnostic check ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + Dict[str, Any]: The diagnostic check status. + """ + api_endpoint = f"{self.BASE_ENDPOINT}/create-foreign-server/{id}" + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/datacenters.py b/src/teradata_mcp_server/tools/qg/qgm/datacenters.py new file mode 100644 index 0000000..5913263 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/datacenters.py @@ -0,0 +1,47 @@ +""" +Manager for QueryGrid data centers. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class DataCenterClient(BaseClient): + """Manager for QueryGrid data centers.""" + + BASE_ENDPOINT = "/api/config/datacenters" + + def get_datacenters(self, filter_by_name: str | None = None) -> Dict[str, Any]: + """ + Retrieve the list of QueryGrid data center objects from the API. + + Args: + filter_by_name (str | None): If provided, filters the data centers by name. + Defaults to None. + + Returns: + Dict[str, Any]: A dictionary containing the list of data centers and + any additional metadata from the API response. + """ + params = {} + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + return self._request("GET", self.BASE_ENDPOINT, params=params) + + def get_datacenter_by_id(self, id: str) -> Dict[str, Any]: + """ + Retrieve a specific QueryGrid data center object by its ID. + + Args: + id (str): The unique identifier of the data center. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + Dict[str, Any]: A dictionary containing the data center details. + """ + api_endpoint = f"{self.BASE_ENDPOINT}/{id}" + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/datasource_registration.py b/src/teradata_mcp_server/tools/qg/qgm/datasource_registration.py new file mode 100644 index 0000000..2af4940 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/datasource_registration.py @@ -0,0 +1,32 @@ +""" +Manager for QueryGrid datasource registration operations. +""" + +from .base import BaseClient + + +class DatasourceRegistrationClient(BaseClient): + """Manager for QueryGrid datasource registration operations.""" + + BASE_ENDPOINT = "/api/operations" + + def get_datasource_registration( + self, datasource_type: str, system_id: str + ) -> bytes: + """ + Generate node registration zip file for a given data source. + + Args: + datasource_type (str): Name of the data source type. E.g. emr, dataproc, hdinsight, genericjdbc, cdp, bigquery, onpremtd + system_id (str): ID of the system. + + Returns: + bytes: The zip file content. + """ + params = {} + params["datasourceType"] = datasource_type + params["systemId"] = system_id + api_endpoint = f"{self.BASE_ENDPOINT}/datasource-registration" + response = self.session.get(f"{self.base_url}{api_endpoint}", params=params) + response.raise_for_status() + return response.content diff --git a/src/teradata_mcp_server/tools/qg/qgm/diagnostics.py b/src/teradata_mcp_server/tools/qg/qgm/diagnostics.py new file mode 100644 index 0000000..1568d50 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/diagnostics.py @@ -0,0 +1,17 @@ +""" +Manager for QueryGrid diagnostic operations. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class DiagnosticClient(BaseClient): + """Manager for QueryGrid diagnostic operations.""" + + BASE_ENDPOINT = "/api/operations/diagnostic-check" + + def get_diagnostic_check_status(self, id: str) -> Dict[str, Any]: + """Get the status of a diagnostic check operation.""" + return self._request("GET", f"{self.BASE_ENDPOINT}/{id}") diff --git a/src/teradata_mcp_server/tools/qg/qgm/fabrics.py b/src/teradata_mcp_server/tools/qg/qgm/fabrics.py new file mode 100644 index 0000000..d2f0677 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/fabrics.py @@ -0,0 +1,63 @@ +""" +Manager for QueryGrid fabrics. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class FabricClient(BaseClient): + """Manager for QueryGrid fabrics.""" + + BASE_ENDPOINT = "/api/config/fabrics" + + def __init__(self, session, base_url: str): + super().__init__(session, base_url) + self.resource_path = self.BASE_ENDPOINT + + def get_fabrics( + self, + flatten: bool = False, + extra_info: bool = False, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + ) -> Dict[str, Any]: + """Get all fabrics.""" + params = {} + if flatten: + params["flatten"] = flatten + if extra_info: + params["extraInfo"] = extra_info + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + if ( + filter_by_tag is not None + and filter_by_tag != "" + and filter_by_tag != "null" + ): + params["filterByTag"] = filter_by_tag + return self._request("GET", self.resource_path, params=params) + + def get_fabric_by_id(self, id: str, extra_info: bool = False) -> Dict[str, Any]: + """Get a fabric by ID.""" + params = {} + if extra_info: + params["extraInfo"] = extra_info + return self._request("GET", f"{self.resource_path}/{id}", params=params) + + def get_fabric_active(self, id: str) -> Dict[str, Any]: + """Get the active version of a fabric.""" + return self._request("GET", f"{self.resource_path}/{id}/active") + + def get_fabric_pending(self, id: str) -> Dict[str, Any]: + """Get the pending version of a fabric.""" + return self._request("GET", f"{self.resource_path}/{id}/pending") + + def get_fabric_previous(self, id: str) -> Dict[str, Any]: + """Get the previous version of a fabric.""" + return self._request("GET", f"{self.resource_path}/{id}/previous") diff --git a/src/teradata_mcp_server/tools/qg/qgm/issues.py b/src/teradata_mcp_server/tools/qg/qgm/issues.py new file mode 100644 index 0000000..695e075 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/issues.py @@ -0,0 +1,51 @@ +""" +Manager for QueryGrid issues. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class IssueClient(BaseClient): + """Manager for QueryGrid issues.""" + + BASE_ENDPOINT = "/api/issues" + + def get_issues(self) -> Dict[str, Any]: + """ + Retrieve all active issues from the system. + + This method sends a GET request to the '/api/issues' endpoint and returns + the response as a dictionary containing details of all currently active issues. + If no issues are present, an empty dictionary or appropriate response may be returned. + + Returns: + Dict[str, Any]: A dictionary representing the active issues data. + + Raises: + Any exceptions raised by the underlying _request method, such as network errors + or API-specific errors (e.g., authentication failures). + """ + """Get all active issues.""" + return self._request("GET", self.BASE_ENDPOINT) + + def get_issue_by_id(self, id: str) -> Dict[str, Any]: + """ + Retrieve a specific active issue by its unique identifier. + + This method sends a GET request to the '/api/issues/{id}' endpoint and returns + the response as a dictionary containing details of the specified issue. + If the issue does not exist, the API may return an error or an empty response. + + Args: + id (str): The unique identifier of the issue to retrieve. + + Returns: + Dict[str, Any]: A dictionary representing the issue data. + + Raises: + Any exceptions raised by the underlying _request method, such as network errors, + authentication failures, or API-specific errors (e.g., issue not found). + """ + return self._request("GET", f"{self.BASE_ENDPOINT}/{id}") diff --git a/src/teradata_mcp_server/tools/qg/qgm/links.py b/src/teradata_mcp_server/tools/qg/qgm/links.py new file mode 100644 index 0000000..3d24018 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/links.py @@ -0,0 +1,63 @@ +""" +Manager for QueryGrid links. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class LinkClient(BaseClient): + """Manager for QueryGrid links.""" + + BASE_ENDPOINT = "/api/config/links" + + def __init__(self, session, base_url: str): + super().__init__(session, base_url) + self.resource_path = self.BASE_ENDPOINT + + def get_links( + self, + flatten: bool = False, + extra_info: bool = False, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + ) -> Dict[str, Any]: + """Get all links.""" + params = {} + if flatten: + params["flatten"] = flatten + if extra_info: + params["extraInfo"] = extra_info + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + if ( + filter_by_tag is not None + and filter_by_tag != "" + and filter_by_tag != "null" + ): + params["filterByTag"] = filter_by_tag + return self._request("GET", self.resource_path, params=params) + + def get_link_by_id(self, id: str, extra_info: bool = False) -> Dict[str, Any]: + """Get a link by ID.""" + params = {} + if extra_info: + params["extraInfo"] = extra_info + return self._request("GET", f"{self.resource_path}/{id}", params=params) + + def get_link_active(self, id: str) -> Dict[str, Any]: + """Get the active version of a link.""" + return self._request("GET", f"{self.resource_path}/{id}/active") + + def get_link_pending(self, id: str) -> Dict[str, Any]: + """Get the pending version of a link.""" + return self._request("GET", f"{self.resource_path}/{id}/pending") + + def get_link_previous(self, id: str) -> Dict[str, Any]: + """Get the previous version of a link.""" + return self._request("GET", f"{self.resource_path}/{id}/previous") diff --git a/src/teradata_mcp_server/tools/qg/qgm/managers.py b/src/teradata_mcp_server/tools/qg/qgm/managers.py new file mode 100644 index 0000000..bc9006c --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/managers.py @@ -0,0 +1,53 @@ +""" +Manager for QueryGrid managers. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class ManagerClient(BaseClient): + """Manager for QueryGrid managers.""" + + BASE_ENDPOINT = "/api/managers" + + def get_managers( + self, extra_info: bool = False, filter_by_name: str | None = None + ) -> Dict[str, Any]: + """ + Retrieve the list of QueryGrid manager objects from the API. + + Args: + extra_info (bool): If True, includes additional detailed information + about each manager in the response. Defaults to False. + filter_by_name (str | None): If provided, filters the managers by name. + Defaults to None. + + Returns: + Dict[str, Any]: A dictionary containing the list of managers and + any additional metadata from the API response. + """ + params = {} + if extra_info: + params["extraInfo"] = extra_info + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + return self._request("GET", self.BASE_ENDPOINT, params=params) + + def get_manager_by_id(self, id: str) -> Dict[str, Any]: + """ + Retrieve a specific QueryGrid manager object by its ID. + + Args: + id (str): The unique identifier of the manager. + + Returns: + Dict[str, Any]: A dictionary containing the manager details. + """ + api_endpoint = f"{self.BASE_ENDPOINT}/{id}" + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/networks.py b/src/teradata_mcp_server/tools/qg/qgm/networks.py new file mode 100644 index 0000000..32a2c70 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/networks.py @@ -0,0 +1,86 @@ +""" +Manager for QueryGrid networks. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class NetworkClient(BaseClient): + """Manager for QueryGrid networks.""" + + BASE_ENDPOINT = "/api/config/networks" + + def get_networks( + self, + flatten: bool = False, + extra_info: bool = False, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + ) -> Dict[str, Any]: + """ + Retrieve the list of QueryGrid network objects from the API. + + Args: + flatten (bool): Flatten versions into array elements. Defaults to False. + extra_info (bool): Include extra details. Defaults to False. + filter_by_name (str | None): Filter by name. + filter_by_tag (str | None): Filter by tag (comma-separated key:value pairs). + + Returns: + Dict[str, Any]: A dictionary containing the list of networks. + """ + params = {} + if flatten: + params["flatten"] = flatten + if extra_info: + params["extraInfo"] = extra_info + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + if ( + filter_by_tag is not None + and filter_by_tag != "" + and filter_by_tag != "null" + ): + params["filterByTag"] = filter_by_tag + return self._request( + "GET", self.BASE_ENDPOINT, params=params if params else None + ) + + def get_network_by_id(self, id: str, extra_info: bool = False) -> Dict[str, Any]: + """ + Retrieve a specific network by ID. + + Args: + id (str): The network ID. + extra_info (bool): Include extra details. + + Returns: + Dict[str, Any]: The network details. + """ + params = {} + if extra_info: + params["extraInfo"] = extra_info + return self._request( + "GET", f"{self.BASE_ENDPOINT}/{id}", params=params if params else None + ) + + def get_network_active(self, id: str) -> Dict[str, Any]: + """Get the active version of a network.""" + api_endpoint = f"{self.BASE_ENDPOINT}/{id}/active" + return self._request("GET", api_endpoint) + + def get_network_pending(self, id: str) -> Dict[str, Any]: + """Get the pending version of a network.""" + api_endpoint = f"{self.BASE_ENDPOINT}/{id}/pending" + return self._request("GET", api_endpoint) + + def get_network_previous(self, id: str) -> Dict[str, Any]: + """Get the previous version of a network.""" + api_endpoint = f"{self.BASE_ENDPOINT}/{id}/previous" + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/node_virtual_ips.py b/src/teradata_mcp_server/tools/qg/qgm/node_virtual_ips.py new file mode 100644 index 0000000..7e086b2 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/node_virtual_ips.py @@ -0,0 +1,36 @@ +""" +Manager for QueryGrid node virtual IPs. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class NodeVirtualIPClient(BaseClient): + """Manager for QueryGrid node virtual IPs.""" + + BASE_ENDPOINT = "/api/config/node-virtual-ips" + + def get_node_virtual_ips(self) -> Dict[str, Any]: + """ + Retrieve the list of QueryGrid node virtual IP objects from the API. + + Returns: + Dict[str, Any]: A dictionary containing the list of node virtual IPs. + """ + api_endpoint = self.BASE_ENDPOINT + return self._request("GET", api_endpoint) + + def get_node_virtual_ip_by_id(self, id: str) -> Dict[str, Any]: + """ + Retrieve a specific node virtual IP by ID. + + Args: + id (str): The virtual IP ID. + + Returns: + Dict[str, Any]: The node virtual IP details. + """ + api_endpoint = f"{self.BASE_ENDPOINT}/{id}" + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/nodes.py b/src/teradata_mcp_server/tools/qg/qgm/nodes.py new file mode 100644 index 0000000..d7a081a --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/nodes.py @@ -0,0 +1,64 @@ +""" +Manager for QueryGrid nodes. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class NodeClient(BaseClient): + """Manager for QueryGrid nodes.""" + + BASE_ENDPOINT = "/api/nodes" + + def get_nodes( + self, + filter_by_system_id: str | None = None, + filter_by_bridge_id: str | None = None, + filter_by_fabric_id: str | None = None, + filter_by_connector_id: str | None = None, + extra_info: bool = False, + fabric_version: str | None = None, + connector_version: str | None = None, + drivers: str | None = None, + details: bool = False, + filter_by_name: str | None = None, + ) -> Dict[str, Any]: + """Get all nodes configured in QueryGrid Manager.""" + params = {} + if filter_by_system_id is not None and filter_by_system_id != "null": + params["filterBySystemId"] = filter_by_system_id + if filter_by_bridge_id is not None and filter_by_bridge_id != "null": + params["filterByBridgeId"] = filter_by_bridge_id + if filter_by_fabric_id is not None and filter_by_fabric_id != "null": + params["filterByFabricId"] = filter_by_fabric_id + if filter_by_connector_id is not None and filter_by_connector_id != "null": + params["filterByConnectorId"] = filter_by_connector_id + if extra_info: + params["extraInfo"] = extra_info + if fabric_version is not None and fabric_version != "null": + params["fabricVersion"] = fabric_version + if connector_version is not None and connector_version != "null": + params["connectorVersion"] = connector_version + if drivers is not None and drivers != "null": + params["drivers"] = drivers + if details: + params["details"] = details + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + return self._request( + "GET", self.BASE_ENDPOINT, params=params if params else None + ) + + def get_node_by_id(self, id: str) -> Dict[str, Any]: + """Get a specific node configured in QueryGrid Manager by its ID.""" + return self._request("GET", f"{self.BASE_ENDPOINT}/{id}") + + def get_node_heartbeat_by_id(self, id: str) -> Dict[str, Any]: + """Get the latest node heartbeat sent by a node to the QueryGrid Manager by its ID.""" + return self._request("GET", f"{self.BASE_ENDPOINT}/{id}/heartbeat") diff --git a/src/teradata_mcp_server/tools/qg/qgm/nodes_auto_install.py b/src/teradata_mcp_server/tools/qg/qgm/nodes_auto_install.py new file mode 100644 index 0000000..8c91299 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/nodes_auto_install.py @@ -0,0 +1,26 @@ +""" +Manager for QueryGrid nodes auto install operations. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class NodesAutoInstallClient(BaseClient): + """Manager for QueryGrid nodes auto install operations.""" + + BASE_ENDPOINT = "/api/operations" + + def get_nodes_auto_install_status(self, id: str) -> Dict[str, Any]: + """ + Get the status of the automatic node installation. + + Args: + id (str): The installation ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + Dict[str, Any]: The installation status. + """ + api_endpoint = f"{self.BASE_ENDPOINT}/nodes-auto-install/{id}" + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/privatelink_template.py b/src/teradata_mcp_server/tools/qg/qgm/privatelink_template.py new file mode 100644 index 0000000..45136ee --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/privatelink_template.py @@ -0,0 +1,27 @@ +""" +Manager for QueryGrid privatelink template operations. +""" + +from .base import BaseClient + + +class PrivatelinkTemplateClient(BaseClient): + """Manager for QueryGrid privatelink template operations.""" + + BASE_ENDPOINT = "/api/operations" + + def get_privatelink_template(self, cloud_platform: str) -> bytes: + """ + Generate private link template file for a given cloud platform. + + Args: + cloud_platform (str): Name of the cloud platform. E.g. aws, azure, gc + + Returns: + bytes: The template file content. + """ + params = {"cloud_platform": cloud_platform} + api_endpoint = f"{self.BASE_ENDPOINT}/privatelink-template" + response = self.session.get(f"{self.base_url}{api_endpoint}", params=params) + response.raise_for_status() + return response.content diff --git a/src/teradata_mcp_server/tools/qg/qgm/queries.py b/src/teradata_mcp_server/tools/qg/qgm/queries.py new file mode 100644 index 0000000..3b4a65c --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/queries.py @@ -0,0 +1,61 @@ +""" +Manager for QueryGrid queries. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class QueryClient(BaseClient): + """Manager for QueryGrid queries.""" + + BASE_ENDPOINT = "/api/queries" + + def get_query_summary( + self, + last_modified_after: str | None = None, + completed: bool = False, + query_text_phrase: str | None = None, + query_ref_ids: str | None = None, + initiator_query_id: str | None = None, + ) -> Dict[str, Any]: + """Get query summary records.""" + params = {} + if ( + last_modified_after is not None + and last_modified_after != "" + and last_modified_after != "null" + ): + params["lastModifiedAfter"] = last_modified_after + if completed: + params["completed"] = completed + if ( + query_text_phrase is not None + and query_text_phrase != "" + and query_text_phrase != "null" + ): + params["queryTextPhrase"] = query_text_phrase + if ( + query_ref_ids is not None + and query_ref_ids != "" + and query_ref_ids != "null" + ): + params["queryRefIds"] = query_ref_ids + if ( + initiator_query_id is not None + and initiator_query_id != "" + and initiator_query_id != "null" + ): + params["initiatorQueryId"] = initiator_query_id + return self._request( + "GET", self.BASE_ENDPOINT, params=params if params else None + ) + + def get_query_by_id(self, id: str) -> Dict[str, Any]: + """Get query summary by ID.""" + return self._request("GET", f"{self.BASE_ENDPOINT}/{id}") + + def get_query_details(self, id: str) -> Dict[str, Any]: + """Get query details by ID.""" + return self._request("GET", f"{self.BASE_ENDPOINT}/{id}/details") diff --git a/src/teradata_mcp_server/tools/qg/qgm/querygrid_manager.py b/src/teradata_mcp_server/tools/qg/qgm/querygrid_manager.py new file mode 100644 index 0000000..0597771 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/querygrid_manager.py @@ -0,0 +1,115 @@ +""" +QueryGrid Manager API client. +""" + +import logging +import os + +import requests + +from .connectors import ConnectorClient +from .datacenters import DataCenterClient +from .diagnostics import DiagnosticClient +from .fabrics import FabricClient +from .issues import IssueClient +from .links import LinkClient +from .managers import ManagerClient +from .networks import NetworkClient +from .node_virtual_ips import NodeVirtualIPClient +from .nodes import NodeClient +from .nodes_auto_install import NodesAutoInstallClient +from .create_foreign_server import CreateForeignServerClient +from .datasource_registration import DatasourceRegistrationClient +from .privatelink_template import PrivatelinkTemplateClient +from .queries import QueryClient +from .softwares import SoftwareClient +from .systems import SystemClient +from .user_mappings import UserMappingClient +from .users import UserClient +from .support_archive import SupportArchiveClient +from .bridges import BridgeClient +from .comm_policies import CommPolicyClient +from .api_info import ApiInfoClient + +logger = logging.getLogger(__name__) + + +class QueryGridManager: + """Client for interacting with QueryGrid Manager API.""" + + def __init__( + self, username: str = None, password: str = None, verify_ssl: bool = None + ): + """ + Initialize the QueryGrid client. + + Args: + username: Username for authentication (optional, can be set via QG_MANAGER_USERNAME env var) + password: Password for authentication (optional, can be set via QG_MANAGER_PASSWORD env var) + verify_ssl: Whether to verify SSL certificates (optional, can be set via QG_MANAGER_VERIFY_SSL env var) + """ + # Construct base_url from environment variables + host = os.getenv("QG_MANAGER_HOST") + port = os.getenv("QG_MANAGER_PORT") + if host and port: + base_url = f"https://{host}:{port}" + else: + raise ValueError( + "Both QG_MANAGER_HOST and QG_MANAGER_PORT environment variables must be set" + ) + + self.base_url = base_url.rstrip("/") + self.username = username or os.getenv("QG_MANAGER_USERNAME") + self.password = password or os.getenv("QG_MANAGER_PASSWORD") + self.verify_ssl = ( + verify_ssl + if verify_ssl is not None + else os.getenv("QG_MANAGER_VERIFY_SSL", "true").lower() + in ["true", "1", "yes"] + ) + self.session = requests.Session() + self.session.auth = (self.username, self.password) + self.session.verify = self.verify_ssl + + # Initialize resource managers + self.manager_client = ManagerClient(self.session, self.base_url) + self.node_client = NodeClient(self.session, self.base_url) + self.issue_client = IssueClient(self.session, self.base_url) + self.system_client = SystemClient(self.session, self.base_url) + self.connector_client = ConnectorClient(self.session, self.base_url) + self.link_client = LinkClient(self.session, self.base_url) + self.fabric_client = FabricClient(self.session, self.base_url) + self.software_client = SoftwareClient(self.session, self.base_url) + self.query_client = QueryClient(self.session, self.base_url) + self.diagnostic_client = DiagnosticClient(self.session, self.base_url) + self.datacenter_client = DataCenterClient(self.session, self.base_url) + self.bridge_client = BridgeClient(self.session, self.base_url) + self.comm_policy_client = CommPolicyClient(self.session, self.base_url) + self.network_client = NetworkClient(self.session, self.base_url) + self.user_mapping_client = UserMappingClient(self.session, self.base_url) + self.node_virtual_ip_client = NodeVirtualIPClient(self.session, self.base_url) + self.user_client = UserClient(self.session, self.base_url) + self.support_archive_client = SupportArchiveClient(self.session, self.base_url) + self.api_info_client = ApiInfoClient(self.session, self.base_url) + self.nodes_auto_install_client = NodesAutoInstallClient( + self.session, self.base_url + ) + self.create_foreign_server_client = CreateForeignServerClient( + self.session, self.base_url + ) + self.datasource_registration_client = DatasourceRegistrationClient( + self.session, self.base_url + ) + self.privatelink_template_client = PrivatelinkTemplateClient( + self.session, self.base_url + ) + + logger.info(f"Initialized QueryGrid client for {self.base_url}") + + def close(self): + """Close the underlying session.""" + logger.info("Closing QueryGrid Manager session") + self.session.close() + + +qgm = QueryGridManager() diff --git a/src/teradata_mcp_server/tools/qg/qgm/softwares.py b/src/teradata_mcp_server/tools/qg/qgm/softwares.py new file mode 100644 index 0000000..3df759f --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/softwares.py @@ -0,0 +1,61 @@ +""" +Manager for QueryGrid software. +""" + +from typing import Any, Dict +from unicodedata import name + +from .base import BaseClient + + +class SoftwareClient(BaseClient): + """Manager for QueryGrid software.""" + + BASE_ENDPOINT = "/api/software" + + def __init__(self, session, base_url: str): + super().__init__(session, base_url) + self.resource_path = self.BASE_ENDPOINT + + def get_software(self, filter_by_name: str | None = None) -> Dict[str, Any]: + """Get all software packages.""" + params = {} + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + return self._request( + "GET", self.resource_path, params=params + ) # No extraInfo for software + + def get_software_jdbc_driver(self) -> Dict[str, Any]: + """Find all JDBC driver related software.""" + api_endpoint = f"{self.resource_path}/jdbc-driver" + return self._request("GET", api_endpoint) # No extraInfo for software + + def get_software_jdbc_driver_by_name(self, jdbc_driver_name: str) -> Dict[str, Any]: + """Find JDBC driver software by name.""" + api_endpoint = f"{self.resource_path}/jdbc-driver/{jdbc_driver_name}" + return self._request("GET", api_endpoint) + + def get_software_by_id(self, id: str) -> Dict[str, Any]: + """Get software by ID.""" + api_endpoint = f"{self.resource_path}/{id}" + return self._request("GET", api_endpoint) + + def get_software_package(self, id: str) -> Dict[str, Any]: + """Download software package by ID.""" + api_endpoint = f"{self.resource_path}/{id}/package" + return self._request("GET", api_endpoint) + + def get_software_resource_bundle( + self, id: str, locale: str | None = None + ) -> Dict[str, Any]: + """Download software resource bundle by ID.""" + api_endpoint = f"{self.resource_path}/{id}/resource-bundle" + params = {} + if locale is not None and locale != "" and locale != "null": + params["locale"] = locale + return self._request("GET", api_endpoint, params=params) diff --git a/src/teradata_mcp_server/tools/qg/qgm/support_archive.py b/src/teradata_mcp_server/tools/qg/qgm/support_archive.py new file mode 100644 index 0000000..bca8658 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/support_archive.py @@ -0,0 +1,127 @@ +""" +Manager for QueryGrid support archives. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class SupportArchiveClient(BaseClient): + """Manager for QueryGrid support archives.""" + + BASE_ENDPOINT = "/api/support-archive" + + def get_support_archive_manager( + self, + start_time: str | None = None, + end_time: str | None = None, + days: str | None = None, + hours: str | None = None, + ) -> Dict[str, Any]: + """ + Generate and download manager support archive. + + Args: + start_time (str | None): [Optional] The start of the time range to collect logs in ISO8601 format. + end_time (str | None): [Optional] The end of the time range to collect logs in ISO8601 format. + days (str | None): [Optional] The number of days back to include log files, defaults to 7. + hours (str | None): [Optional] The number of hours back to include log files. + Returns: + Dict[str, Any]: The support archive data. + """ + params = {} + if start_time is not None and start_time != "" and start_time != "null": + params["start-time"] = start_time + if end_time is not None and end_time != "" and end_time != "null": + params["end-time"] = end_time + if days is not None and days != "" and days != "null": + params["days"] = days + if hours is not None and hours != "" and hours != "null": + params["hours"] = hours + return self._request("GET", f"{self.BASE_ENDPOINT}/manager", params=params) + + def get_support_archive_query( + self, queryId: str, all: bool = True + ) -> Dict[str, Any]: + """ + Generate and download query support archive. + + Args: + queryId (str): The query ID. + all (bool): Collect support information for all operations associated with the specified query Id. + + Returns: + Dict[str, Any]: The support archive data. + """ + params = {"query": queryId} + if all: + params["all"] = all + return self._request("GET", f"{self.BASE_ENDPOINT}/query", params=params) + + def get_support_archive_config(self) -> Dict[str, Any]: + """Generate config support archive.""" + return self._request("GET", f"{self.BASE_ENDPOINT}/config") + + def get_support_archive_node( + self, + start_time: str | None = None, + end_time: str | None = None, + days: str | None = None, + hours: str | None = None, + node: str | None = None, + system_name: str | None = None, + threads: int | None = None, + sender: str | None = None, + ) -> Dict[str, Any]: + """ + Generate and download node support archive. + + Args: + start_time (str | None): The start of the time range to collect logs in ISO8601 format. + end_time (str | None): The end of the time range to collect logs in ISO8601 format. + days (str | None): The number of days back to include log files, defaults to 7. + hours (str | None): The number of hours back to include log files. + node (str | None): Id or the hostname of a specific node. + system_name (str | None): Generate node-logs support archive for a specific system name. + threads (int | None): The number of threads to use for collecting node logs, defaults to 10. + sender (str | None): Generate node-logs support archive for a specific sender. Examples - [node, fabric, connector] + + Returns: + Dict[str, Any]: The support archive data. + """ + params = {} + if start_time is not None and start_time != "" and start_time != "null": + params["start-time"] = start_time + if end_time is not None and end_time != "" and end_time != "null": + params["end-time"] = end_time + if days is not None and days != "" and days != "null": + params["days"] = days + if hours is not None and hours != "" and hours != "null": + params["hours"] = hours + if node is not None and node != "" and node != "null": + params["node"] = node + if system_name is not None and system_name != "" and system_name != "null": + params["system-name"] = system_name + if threads: + params["threads"] = threads + if sender is not None and sender != "" and sender != "null": + params["sender"] = sender + return self._request("GET", f"{self.BASE_ENDPOINT}/node", params=params) + + def get_support_archive_diagnostic_check( + self, diagnosticCheckId: str + ) -> Dict[str, Any]: + """ + Generate and download diagnostic check support archive. + + Args: + diagnosticCheckId (str): The diagnostic check ID. ID is in UUID format. e.g., '123e4567-e89b-12d3-a456-426614174000'. + + Returns: + Dict[str, Any]: The support archive data. + """ + params = {"id": diagnosticCheckId} + return self._request( + "GET", f"{self.BASE_ENDPOINT}/diagnostic-check", params=params + ) diff --git a/src/teradata_mcp_server/tools/qg/qgm/systems.py b/src/teradata_mcp_server/tools/qg/qgm/systems.py new file mode 100644 index 0000000..43d3295 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/systems.py @@ -0,0 +1,55 @@ +""" +Manager for QueryGrid systems. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class SystemClient(BaseClient): + """Manager for QueryGrid systems.""" + + BASE_ENDPOINT = "/api/config/systems" + + def __init__(self, session, base_url: str): + super().__init__(session, base_url) + self.resource_path = self.BASE_ENDPOINT + + def get_systems( + self, + extra_info: bool = False, + filter_by_proxy_support: str | None = None, + filter_by_name: str | None = None, + filter_by_tag: str | None = None, + ) -> Dict[str, Any]: + """Get all systems.""" + params = {} + if extra_info: + params["extraInfo"] = extra_info + if ( + filter_by_proxy_support is not None + and filter_by_proxy_support != "" + and filter_by_proxy_support != "null" + ): + params["filterByProxySupport"] = filter_by_proxy_support + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + if ( + filter_by_tag is not None + and filter_by_tag != "" + and filter_by_tag != "null" + ): + params["filterByTag"] = filter_by_tag + return self._request("GET", self.resource_path, params=params) + + def get_system_by_id(self, id: str, extra_info: bool = False) -> Dict[str, Any]: + """Get a system by ID.""" + params = {} + if extra_info: + params["extraInfo"] = extra_info + return self._request("GET", f"{self.resource_path}/{id}", params=params) diff --git a/src/teradata_mcp_server/tools/qg/qgm/user_mappings.py b/src/teradata_mcp_server/tools/qg/qgm/user_mappings.py new file mode 100644 index 0000000..353c438 --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/user_mappings.py @@ -0,0 +1,47 @@ +""" +Manager for QueryGrid user/role mappings. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class UserMappingClient(BaseClient): + """Manager for QueryGrid user/role mappings.""" + + BASE_ENDPOINT = "/api/config/user-mappings" + + def get_user_mappings(self, filter_by_name: str | None = None) -> Dict[str, Any]: + """ + Retrieve the list of QueryGrid user mapping objects from the API. + + Args: + filter_by_name (str | None): If provided, filters the user mappings by name. + + Returns: + Dict[str, Any]: A dictionary containing the list of user mappings. + """ + params = {} + if ( + filter_by_name is not None + and filter_by_name != "" + and filter_by_name != "null" + ): + params["filterByName"] = filter_by_name + return self._request( + "GET", self.BASE_ENDPOINT, params=params if params else None + ) + + def get_user_mapping_by_id(self, mapping_id: str) -> Dict[str, Any]: + """ + Retrieve a specific user mapping by ID. + + Args: + mapping_id (str): The mapping ID. + + Returns: + Dict[str, Any]: The user mapping details. + """ + api_endpoint = f"{self.BASE_ENDPOINT}/{mapping_id}" + return self._request("GET", api_endpoint) diff --git a/src/teradata_mcp_server/tools/qg/qgm/users.py b/src/teradata_mcp_server/tools/qg/qgm/users.py new file mode 100644 index 0000000..e03472b --- /dev/null +++ b/src/teradata_mcp_server/tools/qg/qgm/users.py @@ -0,0 +1,36 @@ +""" +Manager for QueryGrid users. +""" + +from typing import Any, Dict + +from .base import BaseClient + + +class UserClient(BaseClient): + """Manager for QueryGrid users.""" + + BASE_ENDPOINT = "/api/users" + + def get_users(self) -> Dict[str, Any]: + """ + Retrieve the list of QueryGrid user objects from the API. + + Returns: + Dict[str, Any]: A dictionary containing the list of users. + """ + api_endpoint = self.BASE_ENDPOINT + return self._request("GET", api_endpoint) + + def get_user_by_username(self, username: str) -> Dict[str, Any]: + """ + Retrieve a specific user by username. + + Args: + username (str): The username. + + Returns: + Dict[str, Any]: The user details. + """ + api_endpoint = f"{self.BASE_ENDPOINT}/{username}" + return self._request("GET", api_endpoint) diff --git a/tests/cases/qg_test_cases.json b/tests/cases/qg_test_cases.json new file mode 100644 index 0000000..833285e --- /dev/null +++ b/tests/cases/qg_test_cases.json @@ -0,0 +1,770 @@ +{ + "test_cases": { + "qg_get_api_info": [ + { + "name": "get_api_info", + "parameters": {}, + "description": "Retrieve QueryGrid Manager API information including version and features" + } + ], + "qg_get_managers": [ + { + "name": "get_all_managers", + "parameters": {}, + "description": "Retrieve all QueryGrid managers" + }, + { + "name": "get_managers_with_extra_info", + "parameters": { + "extra_info": true + }, + "description": "Retrieve all managers with additional information" + }, + { + "name": "get_managers_filtered_by_name", + "parameters": { + "filter_by_name": "qg-centos-6773" + }, + "description": "Retrieve managers filtered by name" + } + ], + "qg_get_manager_by_id": [ + { + "name": "get_specific_manager", + "parameters": { + "id": "a68b3790-683d-4cbb-aaf8-8f18b8619861" + }, + "description": "Retrieve a specific manager by ID" + } + ], + "qg_get_nodes": [ + { + "name": "get_all_nodes", + "parameters": {}, + "description": "Retrieve all QueryGrid nodes" + }, + { + "name": "get_nodes_with_details", + "parameters": { + "details": true, + "extra_info": true + }, + "description": "Retrieve nodes with detailed information" + }, + { + "name": "get_nodes_filtered_by_system_id", + "parameters": { + "filter_by_system_id": "9bc2af30-a865-4fe8-8a06-48d1c0d6be35", + "extra_info": true + }, + "description": "Retrieve nodes filtered by system ID" + }, + { + "name": "get_nodes_filtered_by_fabric_id_and_version", + "parameters": { + "filter_by_fabric_id": "7193ab30-766c-4f76-a0c2-c40b1f81304d", + "fabric_version": "03.09.00.01-4" + }, + "description": "Retrieve nodes filtered by fabric and version" + }, + { + "name": "get_nodes_filtered_by_bridge_id", + "parameters": { + "filter_by_bridge_id": "d6529e41-4b2f-4013-833c-50a38e730d6b" + }, + "description": "Retrieve nodes filtered by bridge ID" + }, + { + "name": "get_nodes_filtered_by_connector_id", + "parameters": { + "filter_by_connector_id": "b2df2354-0c7b-418a-8365-1252a64f0f25" + }, + "description": "Retrieve nodes filtered by connector ID" + }, + { + "name": "get_nodes_filtered_by_connector_version", + "parameters": { + "connector_version": "03.09.00.01-5" + }, + "description": "Retrieve nodes filtered by connector version" + }, + { + "name": "get_nodes_with_drivers_filter", + "parameters": { + "filter_by_connector_id": "b2df2354-0c7b-418a-8365-1252a64f0f25", + "drivers": "true" + }, + "description": "Retrieve nodes with drivers filter" + }, + { + "name": "get_nodes_filtered_by_name", + "parameters": { + "filter_by_name": "pe16-tdvm-smp-0041-01" + }, + "description": "Retrieve nodes filtered by name" + } + ], + "qg_get_node_by_id": [ + { + "name": "get_specific_node", + "parameters": { + "id": "c9af1ea7-d56a-4bdb-a77c-234841078c7a" + }, + "description": "Retrieve a specific node by ID" + } + ], + "qg_get_node_heartbeat_by_id": [ + { + "name": "get_node_heartbeat", + "parameters": { + "id": "c9af1ea7-d56a-4bdb-a77c-234841078c7a" + }, + "description": "Retrieve the latest heartbeat sent by a specific node" + } + ], + "qg_get_systems": [ + { + "name": "get_all_systems", + "parameters": {}, + "description": "Retrieve all QueryGrid systems" + }, + { + "name": "get_systems_with_extra_info", + "parameters": { + "extra_info": true + }, + "description": "Retrieve systems with additional information" + }, + { + "name": "get_systems_filtered_by_name", + "parameters": { + "filter_by_name": "test_system_0041" + }, + "description": "Retrieve systems filtered by name" + }, + { + "name": "get_systems_by_proxy_support", + "parameters": { + "filter_by_proxy_support": "NO_PROXY" + }, + "description": "Retrieve systems filtered by proxy support type" + }, + { + "name": "get_systems_filtered_by_tag", + "parameters": { + "filter_by_tag": "env:production,team:backend" + }, + "description": "Retrieve systems filtered by tag" + } + ], + "qg_get_system_by_id": [ + { + "name": "get_specific_system", + "parameters": { + "id": "9bc2af30-a865-4fe8-8a06-48d1c0d6be35" + }, + "description": "Retrieve a specific system by ID" + }, + { + "name": "get_specific_system_with_extra_info", + "parameters": { + "id": "9bc2af30-a865-4fe8-8a06-48d1c0d6be35", + "extra_info": true + }, + "description": "Retrieve a specific system with additional information" + } + ], + "qg_get_connectors": [ + { + "name": "get_all_connectors", + "parameters": {}, + "description": "Retrieve all QueryGrid connectors" + }, + { + "name": "get_connectors_flattened", + "parameters": { + "flatten": true, + "extra_info": true + }, + "description": "Retrieve connectors with flattened structure" + }, + { + "name": "get_connectors_filtered_by_name", + "parameters": { + "filter_by_name": "test_connector_0041" + }, + "description": "Retrieve connectors filtered by name" + }, + { + "name": "get_connectors_by_tag", + "parameters": { + "filter_by_tag": "env:production" + }, + "description": "Retrieve connectors filtered by tag" + } + ], + "qg_get_connector_by_id": [ + { + "name": "get_specific_connector", + "parameters": { + "id": "2f2f71d5-5edb-4fd0-9162-9063cd6b1e79" + }, + "description": "Retrieve a specific connector by ID" + }, + { + "name": "get_specific_connector_with_extra_info", + "parameters": { + "id": "2f2f71d5-5edb-4fd0-9162-9063cd6b1e79", + "extra_info": true + }, + "description": "Retrieve a specific connector with additional information" + } + ], + "qg_get_connector_active": [ + { + "name": "get_active_connector_config", + "parameters": { + "id": "2f2f71d5-5edb-4fd0-9162-9063cd6b1e79" + }, + "description": "Retrieve active configuration for a connector" + } + ], + "qg_get_connector_pending": [ + { + "name": "get_pending_connector_config", + "parameters": { + "id": "2f2f71d5-5edb-4fd0-9162-9063cd6b1e79" + }, + "description": "Retrieve pending configuration for a connector" + } + ], + "qg_get_connector_previous": [ + { + "name": "get_previous_connector_config", + "parameters": { + "id": "2f2f71d5-5edb-4fd0-9162-9063cd6b1e79" + }, + "description": "Retrieve previous configuration for a connector" + } + ], + "qg_get_connector_drivers": [ + { + "name": "get_connector_drivers", + "parameters": { + "id": "2f2f71d5-5edb-4fd0-9162-9063cd6b1e79", + "version_id": "7cf7c7e2-4698-4ae7-a555-a84f80c5a6ce" + }, + "description": "Retrieve drivers for a specific connector version" + } + ], + "qg_get_links": [ + { + "name": "get_all_links", + "parameters": {}, + "description": "Retrieve all QueryGrid links" + }, + { + "name": "get_links_flattened", + "parameters": { + "flatten": true, + "extra_info": true + }, + "description": "Retrieve links with flattened structure" + }, + { + "name": "get_links_filtered_by_name", + "parameters": { + "filter_by_name": "test_link_41_47" + }, + "description": "Retrieve links filtered by name" + } + ], + "qg_get_link_by_id": [ + { + "name": "get_specific_link", + "parameters": { + "id": "f5d72daf-aa8f-486c-8058-4fc587c0b471" + }, + "description": "Retrieve a specific link by ID" + }, + { + "name": "get_specific_link_with_extra_info", + "parameters": { + "id": "f5d72daf-aa8f-486c-8058-4fc587c0b471", + "extra_info": true + }, + "description": "Retrieve a specific link with additional information" + } + ], + "qg_get_link_active": [ + { + "name": "get_active_link_config", + "parameters": { + "id": "f5d72daf-aa8f-486c-8058-4fc587c0b471" + }, + "description": "Retrieve active configuration for a link" + } + ], + "qg_get_link_pending": [ + { + "name": "get_pending_link_config", + "parameters": { + "id": "f5d72daf-aa8f-486c-8058-4fc587c0b471" + }, + "description": "Retrieve pending configuration for a link" + } + ], + "qg_get_link_previous": [ + { + "name": "get_previous_link_config", + "parameters": { + "id": "f5d72daf-aa8f-486c-8058-4fc587c0b471" + }, + "description": "Retrieve previous configuration for a link" + } + ], + "qg_get_fabrics": [ + { + "name": "get_all_fabrics", + "parameters": {}, + "description": "Retrieve all QueryGrid fabrics" + }, + { + "name": "get_fabrics_flattened", + "parameters": { + "flatten": true, + "extra_info": true + }, + "description": "Retrieve fabrics with flattened structure" + }, + { + "name": "get_fabrics_filtered_by_name", + "parameters": { + "filter_by_name": "test_fabric" + }, + "description": "Retrieve fabrics filtered by name" + }, + { + "name": "get_fabrics_by_tag", + "parameters": { + "filter_by_tag": "env:production" + }, + "description": "Retrieve fabrics filtered by tag" + } + ], + "qg_get_fabric_by_id": [ + { + "name": "get_specific_fabric", + "parameters": { + "id": "7193ab30-766c-4f76-a0c2-c40b1f81304d" + }, + "description": "Retrieve a specific fabric by ID" + }, + { + "name": "get_specific_fabric_with_extra_info", + "parameters": { + "id": "7193ab30-766c-4f76-a0c2-c40b1f81304d", + "extra_info": true + }, + "description": "Retrieve a specific fabric with additional information" + } + ], + "qg_get_fabric_active": [ + { + "name": "get_active_fabric_config", + "parameters": { + "id": "7193ab30-766c-4f76-a0c2-c40b1f81304d" + }, + "description": "Retrieve active configuration for a fabric" + } + ], + "qg_get_fabric_pending": [ + { + "name": "get_pending_fabric_config", + "parameters": { + "id": "7193ab30-766c-4f76-a0c2-c40b1f81304d" + }, + "description": "Retrieve pending configuration for a fabric" + } + ], + "qg_get_fabric_previous": [ + { + "name": "get_previous_fabric_config", + "parameters": { + "id": "7193ab30-766c-4f76-a0c2-c40b1f81304d" + }, + "description": "Retrieve previous configuration for a fabric" + } + ], + "qg_get_software": [ + { + "name": "get_software_info", + "parameters": {}, + "description": "Retrieve QueryGrid software information" + } + ], + "qg_get_software_jdbc_driver": [ + { + "name": "get_software_jdbc_driver", + "parameters": {}, + "description": "Retrieve QueryGrid software information for JDBC drivers" + } + ], + "qg_get_software_jdbc_driver_by_name": [ + { + "name": "get_software_jdbc_driver_by_name", + "parameters": { + "jdbc_driver_name": "test_driver" + }, + "description": "Retrieve software information for a specific JDBC driver" + } + ], + "qg_get_software_by_id": [ + { + "name": "get_software_by_id", + "parameters": { + "id": "d13626fd-cb87-4a19-9c30-b74a6a1cf3de" + }, + "description": "Retrieve a specific software package by ID" + } + ], + "qg_get_networks": [ + { + "name": "get_all_networks", + "parameters": {}, + "description": "Retrieve all QueryGrid networks" + }, + { + "name": "get_networks_flattened", + "parameters": { + "flatten": true, + "extra_info": true + }, + "description": "Retrieve networks with flattened structure" + }, + { + "name": "get_networks_filtered_by_name", + "parameters": { + "filter_by_name": "test_network" + }, + "description": "Retrieve networks filtered by name" + } + ], + "qg_get_network_by_id": [ + { + "name": "get_specific_network", + "parameters": { + "id": "11fe9ff6-c3d2-4115-b0af-c26b1677c0a3" + }, + "description": "Retrieve a specific network by ID" + }, + { + "name": "get_specific_network_with_extra_info", + "parameters": { + "id": "11fe9ff6-c3d2-4115-b0af-c26b1677c0a3", + "extra_info": true + }, + "description": "Retrieve a specific network with additional information" + } + ], + "qg_get_network_active": [ + { + "name": "get_active_network_config", + "parameters": { + "id": "11fe9ff6-c3d2-4115-b0af-c26b1677c0a3" + }, + "description": "Retrieve active configuration for a network" + } + ], + "qg_get_network_pending": [ + { + "name": "get_pending_network_config", + "parameters": { + "id": "11fe9ff6-c3d2-4115-b0af-c26b1677c0a3" + }, + "description": "Retrieve pending configuration for a network" + } + ], + "qg_get_network_previous": [ + { + "name": "get_previous_network_config", + "parameters": { + "id": "11fe9ff6-c3d2-4115-b0af-c26b1677c0a3" + }, + "description": "Retrieve previous configuration for a network" + } + ], + "qg_get_comm_policies": [ + { + "name": "get_all_comm_policies", + "parameters": {}, + "description": "Retrieve all QueryGrid communication policies" + }, + { + "name": "get_comm_policies_flattened", + "parameters": { + "flatten": true, + "extra_info": true + }, + "description": "Retrieve communication policies with flattened structure" + }, + { + "name": "get_comm_policies_filtered_by_name", + "parameters": { + "filter_by_name": "No Compression" + }, + "description": "Retrieve communication policies filtered by name" + } + ], + "qg_get_comm_policy_by_id": [ + { + "name": "get_specific_comm_policy", + "parameters": { + "id": "4d530c9a-7d01-4735-9ca2-74541cc38ced" + }, + "description": "Retrieve a specific communication policy by ID" + }, + { + "name": "get_specific_comm_policy_with_extra_info", + "parameters": { + "id": "4d530c9a-7d01-4735-9ca2-74541cc38ced", + "extra_info": true + }, + "description": "Retrieve a specific communication policy with additional information" + } + ], + "qg_get_comm_policy_active": [ + { + "name": "get_active_comm_policy_config", + "parameters": { + "id": "4d530c9a-7d01-4735-9ca2-74541cc38ced" + }, + "description": "Retrieve active configuration for a communication policy" + } + ], + "qg_get_comm_policy_pending": [ + { + "name": "get_pending_comm_policy_config", + "parameters": { + "id": "4d530c9a-7d01-4735-9ca2-74541cc38ced" + }, + "description": "Retrieve pending configuration for a communication policy" + } + ], + "qg_get_comm_policy_previous": [ + { + "name": "get_previous_comm_policy_config", + "parameters": { + "id": "4d530c9a-7d01-4735-9ca2-74541cc38ced" + }, + "description": "Retrieve previous configuration for a communication policy" + } + ], + "qg_get_bridges": [ + { + "name": "get_all_bridges", + "parameters": {}, + "description": "Retrieve all QueryGrid bridges" + }, + { + "name": "get_bridges_filtered_by_system", + "parameters": { + "filter_by_system_id": "9bc2af30-a865-4fe8-8a06-48d1c0d6be35" + }, + "description": "Retrieve bridges filtered by system" + }, + { + "name": "get_bridges_filtered_by_name", + "parameters": { + "filter_by_name": "test_bridge" + }, + "description": "Retrieve bridges filtered by name" + } + ], + "qg_get_bridge_by_id": [ + { + "name": "get_specific_bridge", + "parameters": { + "id": "d6529e41-4b2f-4013-833c-50a38e730d6b" + }, + "description": "Retrieve a specific bridge by ID" + } + ], + "qg_get_datacenters": [ + { + "name": "get_all_datacenters", + "parameters": {}, + "description": "Retrieve all QueryGrid datacenters" + }, + { + "name": "get_datacenters_filtered_by_name", + "parameters": { + "filter_by_name": "test_datacenter" + }, + "description": "Retrieve datacenters filtered by name" + } + ], + "qg_get_datacenter_by_id": [ + { + "name": "get_specific_datacenter", + "parameters": { + "id": "8a0d2875-13c4-4796-8787-acc6805c3271" + }, + "description": "Retrieve a specific datacenter by ID" + } + ], + "qg_get_node_virtual_ips": [ + { + "name": "get_all_node_virtual_ips", + "parameters": {}, + "description": "Retrieve all QueryGrid node virtual IPs" + } + ], + "qg_get_node_virtual_ip_by_id": [ + { + "name": "get_specific_node_virtual_ip", + "parameters": { + "id": "8a0d2875-13c4-4796-8787-acc6805c3271" + }, + "description": "Retrieve a specific node virtual IP by ID" + } + ], + "qg_get_query_summary": [ + { + "name": "get_query_summary_recent", + "parameters": { + "last_modified_after": "2024-01-01T00:00:00Z" + }, + "description": "Retrieve query summary for recent queries" + }, + { + "name": "get_query_summary_completed", + "parameters": { + "completed": true + }, + "description": "Retrieve summary of completed queries" + }, + { + "name": "get_query_summary_with_phrase", + "parameters": { + "query_text_phrase": "SELECT * FROM" + }, + "description": "Retrieve query summary filtered by search phrase" + }, + { + "name": "get_query_summary_by_initiator_query_id", + "parameters": { + "initiator_query_id": "8a0d2875-13c4-4796-8787-acc6805c3271" + }, + "description": "Retrieve query summary for specific initiator query ID" + }, + { + "name": "get_query_summary_by_ref_ids", + "parameters": { + "query_ref_ids": "123e4567-e89b-12d3-a456-426614174000,223e4567-e89b-12d3-a456-426614174001" + }, + "description": "Retrieve query summary filtered by reference IDs" + } + ], + "qg_get_query_by_id": [ + { + "name": "get_specific_query", + "parameters": { + "id": "8a0d2875-13c4-4796-8787-acc6805c3271" + }, + "description": "Retrieve a specific query by ID" + } + ], + "qg_get_query_details": [ + { + "name": "get_query_details", + "parameters": { + "id": "8a0d2875-13c4-4796-8787-acc6805c3271" + }, + "description": "Retrieve detailed information for a specific query" + } + ], + "qg_get_user_mappings": [ + { + "name": "get_all_user_mappings", + "parameters": {}, + "description": "Retrieve all QueryGrid user mappings" + }, + { + "name": "get_user_mappings_filtered_by_name", + "parameters": { + "filter_by_name": "test_mapping" + }, + "description": "Retrieve user mappings filtered by name" + } + ], + "qg_get_user_mapping_by_id": [ + { + "name": "get_specific_user_mapping", + "parameters": { + "id": "77a7fb39-ab70-43d3-991c-ba36d9622fe1" + }, + "description": "Retrieve a specific user mapping by ID" + } + ], + "qg_get_users": [ + { + "name": "get_all_users", + "parameters": {}, + "description": "Retrieve all QueryGrid users" + } + ], + "qg_get_user_by_username": [ + { + "name": "get_specific_user", + "parameters": { + "username": "support" + }, + "description": "Retrieve a specific user by username" + } + ], + "qg_get_issues": [ + { + "name": "get_all_issues", + "parameters": {}, + "description": "Retrieve all active QueryGrid issues" + } + ], + "qg_get_issue_by_id": [ + { + "name": "get_specific_issue", + "parameters": { + "id": "4f25c89d-d1a7-4374-b592-20870f91c527" + }, + "description": "Retrieve a specific issue by ID" + } + ], + "qg_get_diagnostic_check_status": [ + { + "name": "get_diagnostic_check_status", + "parameters": { + "id": "4f25c89d-d1a7-4374-b592-20870f91c527" + }, + "description": "Retrieve status of a specific diagnostic check" + } + ], + "qg_get_nodes_auto_install_status": [ + { + "name": "get_nodes_auto_install_status", + "parameters": { + "id": "4f25c89d-d1a7-4374-b592-20870f91c527" + }, + "description": "Retrieve automatic node installation status by installation ID" + } + ], + "qg_get_create_foreign_server_status": [ + { + "name": "get_create_foreign_server_status", + "parameters": { + "id": "4f25c89d-d1a7-4374-b592-20870f91c527" + }, + "description": "Retrieve CONNECTOR_CFS diagnostic check status for foreign server creation" + } + ] + } +} \ No newline at end of file diff --git a/uv.lock b/uv.lock index 447a930..63be39f 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.12'", @@ -2326,6 +2326,9 @@ fs = [ { name = "tdfs4ds" }, { name = "teradataml" }, ] +qg = [ + { name = "requests" }, +] tdvs = [ { name = "teradatagenai" }, ] @@ -2344,6 +2347,7 @@ requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.0" }, { name = "pyyaml", specifier = ">=6.0.0" }, { name = "requests", marker = "extra == 'bar'", specifier = ">=2.25.0" }, + { name = "requests", marker = "extra == 'qg'", specifier = ">=2.25.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, { name = "sqlalchemy", specifier = ">=2.0.0,<3.0.0" }, { name = "tdfs4ds", marker = "extra == 'fs'", specifier = ">=0.2.4.0" }, @@ -2352,7 +2356,7 @@ requires-dist = [ { name = "teradatasqlalchemy", specifier = ">=20.0.0.0" }, { name = "types-pyyaml", marker = "extra == 'dev'" }, ] -provides-extras = ["fs", "tdvs", "bar", "dev"] +provides-extras = ["fs", "tdvs", "bar", "qg", "dev"] [package.metadata.requires-dev] dev = [{ name = "build", specifier = ">=1.3.0" }]