From 95ab0583b347ae893648849b5a8930337d396db3 Mon Sep 17 00:00:00 2001 From: kaffa Date: Tue, 3 Feb 2026 13:25:45 +0900 Subject: [PATCH] docs: Simplify verbose docstrings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - save_map_file(): 55 lines → 12 lines - is_legacy_backend(): 42 lines → 11 lines - _check_response_for_errors(): 40 lines → 9 lines Keep essential info, remove redundant examples and explanations. Co-Authored-By: Claude Opus 4.5 --- haproxy_mcp/file_ops.py | 96 ++++------------------------------- haproxy_mcp/haproxy_client.py | 37 ++------------ 2 files changed, 13 insertions(+), 120 deletions(-) diff --git a/haproxy_mcp/file_ops.py b/haproxy_mcp/file_ops.py index 4879309..13259c4 100644 --- a/haproxy_mcp/file_ops.py +++ b/haproxy_mcp/file_ops.py @@ -147,61 +147,17 @@ def split_domain_entries(entries: list[tuple[str, str]]) -> tuple[list[tuple[str def save_map_file(entries: list[tuple[str, str]]) -> None: - """Save domain-to-backend entries using 2-stage map routing architecture. + """Save domain-to-backend entries to map files. - This function implements HAProxy's 2-stage domain routing for optimal - performance. Entries are automatically split into two separate map files - based on whether they are exact domains or wildcard patterns. - - 2-Stage Routing Architecture: - Stage 1 - Exact Match (domains.map): - - HAProxy directive: map_str(req.hdr(host),"/path/domains.map") - - Data structure: ebtree (elastic binary tree) - - Lookup complexity: O(log n) - - Use case: Exact domain matches (e.g., "api.example.com") - - Stage 2 - Wildcard Match (wildcards.map): - - HAProxy directive: map_dom(req.hdr(host),"/path/wildcards.map") - - Data structure: Linear suffix search - - Lookup complexity: O(n) where n = number of wildcard entries - - Use case: Wildcard domains (e.g., ".example.com" matches *.example.com) - - Typically small set, so O(n) is acceptable - - Performance Characteristics: - - 1000 exact domains: ~10 comparisons (log2(1000) approx 10) - - 10 wildcard entries: 10 suffix comparisons (acceptable) - - By separating exact and wildcard entries, we avoid O(n) lookup - for the common case (exact domain match) - - HAProxy Configuration Example: - use_backend %[req.hdr(host),lower,map_str(/etc/haproxy/domains.map)] - if { req.hdr(host),lower,map_str(/etc/haproxy/domains.map) -m found } - use_backend %[req.hdr(host),lower,map_dom(/etc/haproxy/wildcards.map)] - if { req.hdr(host),lower,map_dom(/etc/haproxy/wildcards.map) -m found } + Splits entries into two files for 2-stage routing: + - domains.map: Exact matches (map_str, O(log n)) + - wildcards.map: Wildcard entries starting with "." (map_dom, O(n)) Args: - entries: List of (domain, backend) tuples to write. - - Exact domains: "api.example.com" -> written to domains.map - - Wildcards: ".example.com" (matches *.example.com) -> written - to wildcards.map + entries: List of (domain, backend) tuples. Raises: - IOError: If either map file cannot be written. - - File Formats: - domains.map: - # Exact Domain to Backend mapping (for map_str) - api.example.com pool_1 - www.example.com pool_2 - - wildcards.map: - # Wildcard Domain to Backend mapping (for map_dom) - .example.com pool_3 # Matches *.example.com - .test.org pool_4 # Matches *.test.org - - Note: - Both files are written atomically using temp file + rename to prevent - corruption during concurrent access or system failures. + IOError: If map files cannot be written. """ # Split into exact and wildcard entries exact_entries, wildcard_entries = split_domain_entries(entries) @@ -245,46 +201,14 @@ def get_domain_backend(domain: str) -> Optional[str]: def is_legacy_backend(backend: str) -> bool: """Check if backend is a legacy static backend (not a dynamic pool). - This function distinguishes between two backend naming conventions used - in the HAProxy MCP system: - - Pool Backends (Dynamic): - - Named: pool_1, pool_2, ..., pool_100 - - Pre-configured in haproxy.cfg with 10 server slots each - - Domains are dynamically assigned to available pools via domains.map - - Server slots configured at runtime via Runtime API - - Allows zero-reload domain management - - Legacy Backends (Static): - - Named: {domain}_backend (e.g., "api_example_com_backend") - - Defined statically in haproxy.cfg - - Requires HAProxy reload to add new backends - - Used for domains that were configured before pool-based routing + Pool backends: pool_1, pool_2, ..., pool_100 (dynamic, zero-reload) + Legacy backends: {domain}_backend (static, requires reload) Args: - backend: Backend name to check (e.g., "pool_5" or "api_example_com_backend"). + backend: Backend name to check. Returns: - True if this is a legacy backend (does not start with "pool_"), - False if it's a pool backend. - - Usage Scenarios: - - When listing servers: Determines server naming convention - (pool backends use pool_N_M, legacy use {domain}_M) - - When adding servers: Determines which backend configuration - approach to use - - During migration: Helps identify domains that need migration - from legacy to pool-based routing - - Examples: - >>> is_legacy_backend("pool_5") - False - >>> is_legacy_backend("pool_100") - False - >>> is_legacy_backend("api_example_com_backend") - True - >>> is_legacy_backend("myservice_backend") - True + True if legacy backend, False if pool backend. """ return not backend.startswith("pool_") diff --git a/haproxy_mcp/haproxy_client.py b/haproxy_mcp/haproxy_client.py index 36056aa..5411ea4 100644 --- a/haproxy_mcp/haproxy_client.py +++ b/haproxy_mcp/haproxy_client.py @@ -91,43 +91,12 @@ def haproxy_cmd_checked(command: str) -> str: def _check_response_for_errors(response: str) -> None: """Check HAProxy response for error indicators and raise if found. - HAProxy Runtime API returns plain text responses. Success responses are - typically empty or contain requested data. Error responses contain - specific keywords that indicate the command failed. - Args: - response: Response string from HAProxy Runtime API command. + response: Response string from HAProxy Runtime API. Raises: - HaproxyError: If response contains any error indicator keyword. - - Error Indicators: - - "No such": Resource doesn't exist (e.g., backend, server, map entry) - - "not found": Similar to "No such", resource lookup failed - - "error": General error in command execution - - "failed": Operation could not be completed - - "invalid": Malformed command or invalid parameter value - - "unknown": Unrecognized command or parameter - - Examples: - Successful responses (will NOT raise): - - "" (empty string for successful set commands) - - "1" (map entry ID after successful add) - - Server state data (for show commands) - - Error responses (WILL raise HaproxyError): - - "No such server." - Server doesn't exist in specified backend - - "No such backend." - Backend name not found - - "No such map." - Map file not loaded or doesn't exist - - "Entry not found." - Map entry lookup failed - - "Invalid server state." - Bad state value for set server state - - "unknown keyword 'xyz'" - Unrecognized command parameter - - "failed to allocate memory" - Resource allocation failure - - "'set server' expects :" - Invalid command syntax - - Note: - The check is case-insensitive to catch variations like "Error:", - "ERROR:", "error:" etc. that HAProxy may return. + HaproxyError: If response contains error keywords + (No such, not found, error, failed, invalid, unknown). """ error_indicators = ["No such", "not found", "error", "failed", "invalid", "unknown"] if response: