- Updated python_coding_microproject.csv to use NVIDIA NIM Kimi K2 - Updated kali_linux_shell_simulator.csv to use NVIDIA NIM Kimi K2 - Made more general-purpose (flexible targets, expanded tools) - Added nemotron-mini-agent.csv for fast local inference via Ollama - Added nemotron-agent.csv for advanced reasoning via Ollama - Added wiki page: Projects for NVIDIA NIMs and Nemotron
111 lines
3.7 KiB
Python
111 lines
3.7 KiB
Python
"""
|
|
Resource Cluster Client for service-to-service communication.
|
|
|
|
Used by Control Panel to notify Resource Cluster of configuration changes
|
|
that require cache invalidation (e.g., API key changes).
|
|
"""
|
|
import logging
|
|
from typing import Optional
|
|
import httpx
|
|
|
|
from app.core.config import settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ResourceClusterClient:
|
|
"""Client for communicating with Resource Cluster internal APIs"""
|
|
|
|
def __init__(
|
|
self,
|
|
resource_cluster_url: str,
|
|
service_auth_token: str,
|
|
service_name: str = "control-panel-backend"
|
|
):
|
|
self.resource_cluster_url = resource_cluster_url.rstrip('/')
|
|
self.service_auth_token = service_auth_token
|
|
self.service_name = service_name
|
|
|
|
def _get_headers(self) -> dict:
|
|
"""Get headers for service-to-service authentication"""
|
|
return {
|
|
"X-Service-Auth": self.service_auth_token,
|
|
"X-Service-Name": self.service_name,
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
async def invalidate_api_key_cache(
|
|
self,
|
|
tenant_domain: Optional[str] = None,
|
|
provider: Optional[str] = None
|
|
) -> bool:
|
|
"""
|
|
Notify Resource Cluster to invalidate API key cache.
|
|
|
|
Called when API keys are added, updated, disabled, or removed.
|
|
|
|
Args:
|
|
tenant_domain: If provided, only invalidate for this tenant
|
|
provider: If provided with tenant_domain, only invalidate this provider
|
|
|
|
Returns:
|
|
True if successful, False otherwise
|
|
"""
|
|
url = f"{self.resource_cluster_url}/internal/cache/api-keys/invalidate"
|
|
|
|
params = {}
|
|
if tenant_domain:
|
|
params["tenant_domain"] = tenant_domain
|
|
if provider:
|
|
params["provider"] = provider
|
|
|
|
try:
|
|
async with httpx.AsyncClient(timeout=5.0) as client:
|
|
response = await client.post(
|
|
url,
|
|
params=params,
|
|
headers=self._get_headers()
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
logger.info(
|
|
f"Cache invalidation successful: tenant={tenant_domain}, provider={provider}"
|
|
)
|
|
return True
|
|
else:
|
|
logger.warning(
|
|
f"Cache invalidation failed: {response.status_code} - {response.text}"
|
|
)
|
|
return False
|
|
|
|
except httpx.RequestError as e:
|
|
# Don't fail the API key operation if cache invalidation fails
|
|
# The cache will expire naturally after TTL
|
|
logger.warning(f"Cache invalidation request failed (non-critical): {e}")
|
|
return False
|
|
except Exception as e:
|
|
logger.warning(f"Cache invalidation error (non-critical): {e}")
|
|
return False
|
|
|
|
|
|
# Singleton instance
|
|
_resource_cluster_client: Optional[ResourceClusterClient] = None
|
|
|
|
|
|
def get_resource_cluster_client() -> ResourceClusterClient:
|
|
"""Get or create the singleton Resource Cluster client"""
|
|
global _resource_cluster_client
|
|
|
|
if _resource_cluster_client is None:
|
|
# Use Docker service name for inter-container communication
|
|
resource_cluster_url = getattr(settings, 'RESOURCE_CLUSTER_URL', None) or "http://resource-cluster:8003"
|
|
service_auth_token = getattr(settings, 'SERVICE_AUTH_TOKEN', None) or "internal-service-token"
|
|
|
|
_resource_cluster_client = ResourceClusterClient(
|
|
resource_cluster_url=resource_cluster_url,
|
|
service_auth_token=service_auth_token,
|
|
service_name="control-panel-backend"
|
|
)
|
|
|
|
return _resource_cluster_client
|