167 lines
6.3 KiB
Python
167 lines
6.3 KiB
Python
"""
|
|
Kubernetes Job-based Demo Data Cloner
|
|
Triggers a K8s Job to clone demo data at the database level
|
|
"""
|
|
|
|
import httpx
|
|
import structlog
|
|
from typing import Dict, Any
|
|
import os
|
|
|
|
logger = structlog.get_logger()
|
|
|
|
|
|
class K8sJobCloner:
|
|
"""Triggers Kubernetes Jobs to clone demo data"""
|
|
|
|
def __init__(self):
|
|
self.k8s_api_url = os.getenv("KUBERNETES_SERVICE_HOST")
|
|
self.namespace = os.getenv("POD_NAMESPACE", "bakery-ia")
|
|
self.clone_job_image = os.getenv("CLONE_JOB_IMAGE", "bakery/inventory-service:latest")
|
|
# Service account token for K8s API access
|
|
with open("/var/run/secrets/kubernetes.io/serviceaccount/token", "r") as f:
|
|
self.token = f.read()
|
|
|
|
async def clone_tenant_data(
|
|
self,
|
|
session_id: str,
|
|
base_demo_tenant_id: str,
|
|
virtual_tenant_id: str,
|
|
demo_account_type: str
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Clone demo data by creating a Kubernetes Job
|
|
|
|
Args:
|
|
session_id: Session ID
|
|
base_demo_tenant_id: Base demo tenant UUID (not used in job approach)
|
|
virtual_tenant_id: Virtual tenant UUID for this session
|
|
demo_account_type: Type of demo account
|
|
|
|
Returns:
|
|
Job creation status
|
|
"""
|
|
logger.info(
|
|
"Triggering demo data cloning job",
|
|
session_id=session_id,
|
|
virtual_tenant_id=virtual_tenant_id,
|
|
demo_account_type=demo_account_type,
|
|
clone_image=self.clone_job_image
|
|
)
|
|
|
|
job_name = f"demo-clone-{virtual_tenant_id[:8]}"
|
|
|
|
# Create Job manifest
|
|
job_manifest = {
|
|
"apiVersion": "batch/v1",
|
|
"kind": "Job",
|
|
"metadata": {
|
|
"name": job_name,
|
|
"namespace": self.namespace,
|
|
"labels": {
|
|
"app": "demo-clone",
|
|
"session-id": session_id,
|
|
"component": "runtime"
|
|
}
|
|
},
|
|
"spec": {
|
|
"ttlSecondsAfterFinished": 3600,
|
|
"backoffLimit": 2,
|
|
"template": {
|
|
"metadata": {
|
|
"labels": {"app": "demo-clone"}
|
|
},
|
|
"spec": {
|
|
"restartPolicy": "Never",
|
|
"containers": [{
|
|
"name": "clone-data",
|
|
"image": self.clone_job_image, # Configured via environment variable
|
|
"imagePullPolicy": "IfNotPresent", # Don't pull if image exists locally
|
|
"command": ["python", "/app/scripts/demo/clone_demo_tenant.py"],
|
|
"env": [
|
|
{"name": "VIRTUAL_TENANT_ID", "value": virtual_tenant_id},
|
|
{"name": "DEMO_ACCOUNT_TYPE", "value": demo_account_type},
|
|
{
|
|
"name": "INVENTORY_DATABASE_URL",
|
|
"valueFrom": {
|
|
"secretKeyRef": {
|
|
"name": "database-secrets",
|
|
"key": "INVENTORY_DATABASE_URL"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"name": "SALES_DATABASE_URL",
|
|
"valueFrom": {
|
|
"secretKeyRef": {
|
|
"name": "database-secrets",
|
|
"key": "SALES_DATABASE_URL"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"name": "ORDERS_DATABASE_URL",
|
|
"valueFrom": {
|
|
"secretKeyRef": {
|
|
"name": "database-secrets",
|
|
"key": "ORDERS_DATABASE_URL"
|
|
}
|
|
}
|
|
},
|
|
{"name": "LOG_LEVEL", "value": "INFO"}
|
|
],
|
|
"resources": {
|
|
"requests": {"memory": "256Mi", "cpu": "100m"},
|
|
"limits": {"memory": "512Mi", "cpu": "500m"}
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
try:
|
|
# Create the Job via K8s API
|
|
async with httpx.AsyncClient(verify=False, timeout=30.0) as client:
|
|
response = await client.post(
|
|
f"https://{self.k8s_api_url}/apis/batch/v1/namespaces/{self.namespace}/jobs",
|
|
json=job_manifest,
|
|
headers={
|
|
"Authorization": f"Bearer {self.token}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
)
|
|
|
|
if response.status_code == 201:
|
|
logger.info(
|
|
"Demo clone job created successfully",
|
|
job_name=job_name,
|
|
session_id=session_id
|
|
)
|
|
return {
|
|
"success": True,
|
|
"job_name": job_name,
|
|
"method": "kubernetes_job"
|
|
}
|
|
else:
|
|
logger.error(
|
|
"Failed to create demo clone job",
|
|
status_code=response.status_code,
|
|
response=response.text
|
|
)
|
|
return {
|
|
"success": False,
|
|
"error": f"K8s API returned {response.status_code}"
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(
|
|
"Error creating demo clone job",
|
|
error=str(e),
|
|
exc_info=True
|
|
)
|
|
return {
|
|
"success": False,
|
|
"error": str(e)
|
|
}
|