""" DevOps service for script and configuration generation. """ from typing import Union from fastapi import HTTPException, status from jinja2 import Environment from app.core.config import Settings from app.models.schemas import ConfigState, NginxConfigRequest class DevOpsService: """Service for generating DevOps scripts and configurations.""" def __init__(self, template_env: Environment, settings: Settings, logger): self.template_env = template_env self.settings = settings self.logger = logger def get_script_templates(self, config: ConfigState) -> list[str]: """ Determine which templates to include based on configuration. """ templates = [] # Stack type templates stack_map = { "python": "python_setup.j2", "nodejs": "nodejs_setup.j2", "php": "php_setup.j2", "react": "react_setup.j2", "vue": "vue_setup.j2", "angular": "angular_setup.j2", "go": "go_setup.j2", "java": "java_setup.j2", "dotnet": "dotnet_setup.j2", "docker": "docker_setup.j2", } if config.stackType in stack_map: templates.append(stack_map[config.stackType]) # Web server templates web_map = { "nginx": "nginx_setup.j2", "apache": "apache_setup.j2", "caddy": "caddy_setup.j2", "litespeed": "litespeed_setup.j2", "tomcat": "tomcat_setup.j2", "cherokee": "cherokee_setup.j2", "haproxy": "haproxy_setup.j2", } if config.webServer and config.webServer != "none": template_name = web_map.get(config.webServer) if template_name: templates.append(template_name) # Database templates db_map = { "postgresql": "postgresql_setup.j2", "mysql": "mysql_setup.j2", "mariadb": "mariadb_setup.j2", "mongodb": "mongodb_setup.j2", "redis": "redis_setup.j2", } if config.database and config.database != "none": template_name = db_map.get(config.database) if template_name: templates.append(template_name) # Process manager templates pm_map = { "pm2": "pm2_setup.j2", "systemd": "systemd_setup.j2", "docker-compose": "docker_compose_setup.j2", } if config.processManager and config.processManager != "none": template_name = pm_map.get(config.processManager) if template_name: templates.append(template_name) # Security templates if config.security.ufw: templates.append("ufw_setup.j2") if config.security.fail2ban: templates.append("fail2ban_setup.j2") if config.security.disableRoot: templates.append("disable_root_setup.j2") if config.security.autoUpdates: templates.append("auto_updates_setup.j2") # Advanced templates if config.advanced.swap: templates.append("swap_setup.j2") if config.advanced.sshKey: templates.append("ssh_key_setup.j2") if config.advanced.backups: templates.append("backups_setup.j2") if config.advanced.monitoring: templates.append("monitoring_setup.j2") # SSL template if config.ssl: templates.append("ssl_setup.j2") return templates def generate_bash_script(self, config: ConfigState, script_id: str) -> str: """ Generate a bash script by combining multiple modular templates. """ templates = self.get_script_templates(config) script_parts = [] for template_name in templates: try: # Read template directly from disk to avoid caching issues template_path = self.settings.templates_dir / template_name with open(template_path, 'r', encoding='utf-8') as f: template_content = f.read() # Render using Jinja2 Template directly from jinja2 import Template template = Template( template_content, trim_blocks=True, lstrip_blocks=True ) part = template.render( config=config, script_id=script_id ) if part.strip(): # Only add non-empty parts script_parts.append(part) except Exception as e: self.logger.warning(f"Template error for {template_name}: {e}") combined_script = "\n\n".join(script_parts) # Add header header = f"""#!/bin/bash # Generated DevOps Toolkit Script - {script_id} # Stack: {config.stackType} # Web Server: {config.webServer or 'None'} # Database: {config.database or 'None'} # Process Manager: {config.processManager or 'None'} set -euo pipefail echo "🚀 Starting server setup..." # Update system packages for security echo "📦 Updating system packages..." sudo apt-get update -y sudo apt-get upgrade -y """ # Add footer footer = """ echo "✅ Setup complete! Your server is ready." echo "📝 Next steps:" echo " 1. Configure your application" echo " 2. Upload your code" echo " 3. Start your application service" """ return header + combined_script + footer def generate_nginx_config( self, config: Union[ConfigState, NginxConfigRequest], script_id: str ) -> str: """ Generate nginx configuration using modular templates. """ stack = config.stackType # Map stack types to nginx config templates nginx_map = { "python": "nginx/nginx_python.conf.j2", "nodejs": "nginx/nginx_nodejs.conf.j2", "php": "nginx/nginx_php.conf.j2", "react": "nginx/nginx_static.conf.j2", "vue": "nginx/nginx_static.conf.j2", "angular": "nginx/nginx_static.conf.j2", "go": "nginx/nginx_go.conf.j2", "java": "nginx/nginx_java.conf.j2", "dotnet": "nginx/nginx_dotnet.conf.j2", "docker": "nginx/nginx_docker.conf.j2", } template_name = nginx_map.get( stack, "nginx/nginx_static.conf.j2" ) # Default to static try: # Read template directly from disk to avoid caching issues template_path = self.settings.templates_dir / template_name with open(template_path, 'r', encoding='utf-8') as f: template_content = f.read() # Render using Jinja2 Template directly from jinja2 import Template template = Template(template_content, trim_blocks=True, lstrip_blocks=True) return template.render(config=config, script_id=script_id) except Exception as e: self.logger.error(f"Nginx template error for {template_name}: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Required nginx template {template_name} not found", )