docs: Simplify verbose docstrings

- 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 <noreply@anthropic.com>
This commit is contained in:
kaffa
2026-02-03 13:25:45 +09:00
parent 06ab47aca8
commit 95ab0583b3
2 changed files with 13 additions and 120 deletions

View File

@@ -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: 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 Splits entries into two files for 2-stage routing:
performance. Entries are automatically split into two separate map files - domains.map: Exact matches (map_str, O(log n))
based on whether they are exact domains or wildcard patterns. - wildcards.map: Wildcard entries starting with "." (map_dom, O(n))
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 }
Args: Args:
entries: List of (domain, backend) tuples to write. entries: List of (domain, backend) tuples.
- Exact domains: "api.example.com" -> written to domains.map
- Wildcards: ".example.com" (matches *.example.com) -> written
to wildcards.map
Raises: Raises:
IOError: If either map file cannot be written. IOError: If map files 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.
""" """
# Split into exact and wildcard entries # Split into exact and wildcard entries
exact_entries, wildcard_entries = split_domain_entries(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: def is_legacy_backend(backend: str) -> bool:
"""Check if backend is a legacy static backend (not a dynamic pool). """Check if backend is a legacy static backend (not a dynamic pool).
This function distinguishes between two backend naming conventions used Pool backends: pool_1, pool_2, ..., pool_100 (dynamic, zero-reload)
in the HAProxy MCP system: Legacy backends: {domain}_backend (static, requires reload)
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
Args: Args:
backend: Backend name to check (e.g., "pool_5" or "api_example_com_backend"). backend: Backend name to check.
Returns: Returns:
True if this is a legacy backend (does not start with "pool_"), True if legacy backend, False if pool backend.
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
""" """
return not backend.startswith("pool_") return not backend.startswith("pool_")

View File

@@ -91,43 +91,12 @@ def haproxy_cmd_checked(command: str) -> str:
def _check_response_for_errors(response: str) -> None: def _check_response_for_errors(response: str) -> None:
"""Check HAProxy response for error indicators and raise if found. """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: Args:
response: Response string from HAProxy Runtime API command. response: Response string from HAProxy Runtime API.
Raises: Raises:
HaproxyError: If response contains any error indicator keyword. HaproxyError: If response contains error keywords
(No such, not found, error, failed, invalid, unknown).
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 <addr>:<port>" - Invalid command syntax
Note:
The check is case-insensitive to catch variations like "Error:",
"ERROR:", "error:" etc. that HAProxy may return.
""" """
error_indicators = ["No such", "not found", "error", "failed", "invalid", "unknown"] error_indicators = ["No such", "not found", "error", "failed", "invalid", "unknown"]
if response: if response: