154 lines
4.4 KiB
Python
154 lines
4.4 KiB
Python
"""
|
|
Deployment Configuration Manager
|
|
|
|
Manages saving and loading deployment configurations for tracking and cleanup
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
from dataclasses import asdict, dataclass
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Dict, List, Optional
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass
|
|
class DeploymentMetadata:
|
|
"""Metadata for a single deployment"""
|
|
subdomain: str
|
|
url: str
|
|
domain: str
|
|
compose_project_name: str
|
|
db_name: str
|
|
db_user: str
|
|
deployment_timestamp: str
|
|
dns_record_id: Optional[str] = None
|
|
dns_ip: Optional[str] = None
|
|
containers: Optional[List[str]] = None
|
|
volumes: Optional[List[str]] = None
|
|
networks: Optional[List[str]] = None
|
|
env_file_path: Optional[str] = None
|
|
|
|
|
|
class DeploymentConfigManager:
|
|
"""Manages deployment configuration persistence"""
|
|
|
|
def __init__(self, config_dir: Path = Path("deployments")):
|
|
"""
|
|
Initialize deployment config manager
|
|
|
|
Args:
|
|
config_dir: Directory to store deployment configs
|
|
"""
|
|
self.config_dir = config_dir
|
|
self.config_dir.mkdir(exist_ok=True)
|
|
self._logger = logging.getLogger(f"{__name__}.DeploymentConfigManager")
|
|
|
|
def save_deployment(self, metadata: DeploymentMetadata) -> Path:
|
|
"""
|
|
Save deployment configuration to disk
|
|
|
|
Args:
|
|
metadata: DeploymentMetadata instance
|
|
|
|
Returns:
|
|
Path to saved config file
|
|
"""
|
|
# Create filename based on subdomain and timestamp
|
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
filename = f"{metadata.subdomain}_{timestamp}.json"
|
|
config_path = self.config_dir / filename
|
|
|
|
# Convert to dict and save as JSON
|
|
config_data = asdict(metadata)
|
|
|
|
with open(config_path, 'w') as f:
|
|
json.dump(config_data, f, indent=2)
|
|
|
|
self._logger.info(f"Saved deployment config: {config_path}")
|
|
return config_path
|
|
|
|
def load_deployment(self, config_file: Path) -> DeploymentMetadata:
|
|
"""
|
|
Load deployment configuration from disk
|
|
|
|
Args:
|
|
config_file: Path to config file
|
|
|
|
Returns:
|
|
DeploymentMetadata instance
|
|
|
|
Raises:
|
|
FileNotFoundError: If config file doesn't exist
|
|
ValueError: If config file is invalid
|
|
"""
|
|
if not config_file.exists():
|
|
raise FileNotFoundError(f"Config file not found: {config_file}")
|
|
|
|
with open(config_file, 'r') as f:
|
|
config_data = json.load(f)
|
|
|
|
return DeploymentMetadata(**config_data)
|
|
|
|
def list_deployments(self) -> List[Path]:
|
|
"""
|
|
List all deployment config files
|
|
|
|
Returns:
|
|
List of config file paths sorted by modification time (newest first)
|
|
"""
|
|
config_files = list(self.config_dir.glob("*.json"))
|
|
return sorted(config_files, key=lambda p: p.stat().st_mtime, reverse=True)
|
|
|
|
def find_deployment_by_subdomain(self, subdomain: str) -> Optional[Path]:
|
|
"""
|
|
Find the most recent deployment config for a subdomain
|
|
|
|
Args:
|
|
subdomain: Subdomain to search for
|
|
|
|
Returns:
|
|
Path to config file or None if not found
|
|
"""
|
|
matching_files = list(self.config_dir.glob(f"{subdomain}_*.json"))
|
|
if not matching_files:
|
|
return None
|
|
|
|
# Return most recent
|
|
return max(matching_files, key=lambda p: p.stat().st_mtime)
|
|
|
|
def find_deployment_by_url(self, url: str) -> Optional[Path]:
|
|
"""
|
|
Find deployment config by URL
|
|
|
|
Args:
|
|
url: Full URL to search for
|
|
|
|
Returns:
|
|
Path to config file or None if not found
|
|
"""
|
|
for config_file in self.list_deployments():
|
|
try:
|
|
metadata = self.load_deployment(config_file)
|
|
if metadata.url == url:
|
|
return config_file
|
|
except (ValueError, json.JSONDecodeError) as e:
|
|
self._logger.warning(f"Failed to load config {config_file}: {e}")
|
|
continue
|
|
|
|
return None
|
|
|
|
def delete_deployment_config(self, config_file: Path) -> None:
|
|
"""
|
|
Delete deployment config file
|
|
|
|
Args:
|
|
config_file: Path to config file
|
|
"""
|
|
if config_file.exists():
|
|
config_file.unlink()
|
|
self._logger.info(f"Deleted deployment config: {config_file}")
|