# Step 08: Create Production Launcher

## Prerequisites
- Step 07 completed (test runner integration working)
- All MCP servers working and tested
- Health check system operational

## Objectives
1. Create production-ready launcher scripts
2. Implement proper error handling and logging
3. Add monitoring and restart capabilities
4. Create systemd service files for production deployment

## Implementation Details

### Step 1: Create Main Production Launcher
Create `_mcp/storm_mcp_launcher.py`:

```python
#!/usr/bin/env python3
"""
Storm Logger MCP Production Launcher
Enterprise-grade launcher for Storm Logger MCP servers
"""

import sys
import os
import json
import logging
import argparse
import signal
import time
from pathlib import Path
from typing import Dict, Optional
from datetime import datetime

# Add project root to path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('_mcp/logs/storm_mcp_launcher.log'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger('storm_mcp_launcher')

class StormMCPLauncher:
    """Production launcher for Storm Logger MCP servers."""
    
    def __init__(self, config_path: Optional[str] = None):
        self.config_path = config_path or "_mcp/config/production.json"
        self.config = self.load_config()
        self.server = None
        self.running = False
        self.start_time = None
        
        # Setup signal handlers
        signal.signal(signal.SIGTERM, self._signal_handler)
        signal.signal(signal.SIGINT, self._signal_handler)
    
    def load_config(self) -> Dict:
        """Load production configuration."""
        try:
            if Path(self.config_path).exists():
                with open(self.config_path, 'r') as f:
                    return json.load(f)
            else:
                # Default configuration
                return {
                    "server_name": "Storm Logger MCP Production Server",
                    "log_level": "INFO",
                    "health_check_interval": 60,
                    "max_restart_attempts": 3,
                    "restart_delay": 5,
                    "monitoring": {
                        "enabled": True,
                        "metrics_file": "_mcp/logs/metrics.json"
                    }
                }
        except Exception as e:
            logger.error(f"Failed to load config: {e}")
            return {}
    
    def create_server(self):
        """Create and configure the MCP server."""
        try:
            from _mcp.main import create_storm_mcp_server
            self.server = create_storm_mcp_server()
            logger.info(f"Server created: {self.server.name}")
            return True
        except Exception as e:
            logger.error(f"Failed to create server: {e}")
            return False
    
    def start_server(self):
        """Start the MCP server."""
        try:
            if not self.server:
                if not self.create_server():
                    return False
            
            self.running = True
            self.start_time = datetime.now()
            
            logger.info("Starting Storm Logger MCP Server")
            logger.info(f"Server: {self.server.name}")
            logger.info(f"Tools: {len(self.server.tools)}")
            
            # Run health check
            if self.run_health_check():
                logger.info("Initial health check: PASSED")
            else:
                logger.warning("Initial health check: FAILED")
            
            # Start monitoring if enabled
            if self.config.get("monitoring", {}).get("enabled", False):
                self.start_monitoring()
            
            # Keep server running
            self.run_server_loop()
            
        except Exception as e:
            logger.error(f"Failed to start server: {e}")
            return False
    
    def run_health_check(self) -> bool:
        """Run health check on the server."""
        try:
            # Find health check tool
            health_tool = None
            for tool in self.server.tools:
                if tool.name == "health_check":
                    health_tool = tool
                    break
            
            if not health_tool:
                logger.warning("No health check tool found")
                return False
            
            # Execute health check
            result = health_tool.function()
            status = result.get("overall_status", "unknown")
            
            if status == "healthy":
                return True
            else:
                logger.warning(f"Health check status: {status}")
                return False
                
        except Exception as e:
            logger.error(f"Health check failed: {e}")
            return False
    
    def start_monitoring(self):
        """Start monitoring thread."""
        import threading
        
        def monitor():
            interval = self.config.get("health_check_interval", 60)
            metrics_file = self.config.get("monitoring", {}).get("metrics_file", "_mcp/logs/metrics.json")
            
            while self.running:
                try:
                    # Run health check
                    health_status = self.run_health_check()
                    
                    # Collect metrics
                    metrics = {
                        "timestamp": datetime.now().isoformat(),
                        "uptime": (datetime.now() - self.start_time).total_seconds(),
                        "health_status": "healthy" if health_status else "unhealthy",
                        "tools_count": len(self.server.tools) if self.server else 0,
                        "memory_usage": self.get_memory_usage()
                    }
                    
                    # Save metrics
                    self.save_metrics(metrics, metrics_file)
                    
                    # Log status
                    logger.info(f"Health check: {'PASSED' if health_status else 'FAILED'}")
                    
                except Exception as e:
                    logger.error(f"Monitoring error: {e}")
                
                time.sleep(interval)
        
        monitoring_thread = threading.Thread(target=monitor, daemon=True)
        monitoring_thread.start()
        logger.info("Monitoring started")
    
    def get_memory_usage(self) -> float:
        """Get current memory usage in MB."""
        try:
            import psutil
            process = psutil.Process(os.getpid())
            return process.memory_info().rss / 1024 / 1024
        except ImportError:
            return 0.0
    
    def save_metrics(self, metrics: Dict, metrics_file: str):
        """Save metrics to file."""
        try:
            # Create directory if it doesn't exist
            Path(metrics_file).parent.mkdir(parents=True, exist_ok=True)
            
            # Load existing metrics
            existing_metrics = []
            if Path(metrics_file).exists():
                with open(metrics_file, 'r') as f:
                    existing_metrics = json.load(f)
            
            # Add new metrics
            existing_metrics.append(metrics)
            
            # Keep only last 100 entries
            if len(existing_metrics) > 100:
                existing_metrics = existing_metrics[-100:]
            
            # Save metrics
            with open(metrics_file, 'w') as f:
                json.dump(existing_metrics, f, indent=2)
                
        except Exception as e:
            logger.error(f"Failed to save metrics: {e}")
    
    def run_server_loop(self):
        """Main server loop."""
        logger.info("Server running. Press Ctrl+C to stop.")
        
        try:
            while self.running:
                time.sleep(1)
        except KeyboardInterrupt:
            logger.info("Received shutdown signal")
        finally:
            self.shutdown()
    
    def shutdown(self):
        """Shutdown the server gracefully."""
        logger.info("Shutting down Storm Logger MCP Server")
        self.running = False
        
        if self.server:
            # Cleanup server resources if needed
            pass
        
        logger.info("Server shutdown complete")
    
    def _signal_handler(self, signum, frame):
        """Handle shutdown signals."""
        logger.info(f"Received signal {signum}")
        self.running = False

def main():
    """Main launcher function."""
    parser = argparse.ArgumentParser(description="Storm Logger MCP Production Launcher")
    parser.add_argument("--config", "-c", help="Configuration file path")
    parser.add_argument("--verbose", "-v", action="store_true", help="Verbose logging")
    parser.add_argument("--health-check", action="store_true", help="Run health check and exit")
    
    args = parser.parse_args()
    
    # Set logging level
    if args.verbose:
        logging.getLogger().setLevel(logging.DEBUG)
    
    # Create launcher
    launcher = StormMCPLauncher(args.config)
    
    # Handle health check mode
    if args.health_check:
        if launcher.create_server():
            if launcher.run_health_check():
                print("✅ Health check: PASSED")
                return 0
            else:
                print("❌ Health check: FAILED")
                return 1
        else:
            print("❌ Server creation failed")
            return 2
    
    # Start server
    try:
        launcher.start_server()
        return 0
    except Exception as e:
        logger.error(f"Launcher failed: {e}")
        return 1

if __name__ == "__main__":
    sys.exit(main())
```

### Step 2: Create Production Configuration
Create `_mcp/config/production.json`:

```json
{
  "server_name": "Storm Logger MCP Production Server",
  "log_level": "INFO",
  "health_check_interval": 60,
  "max_restart_attempts": 3,
  "restart_delay": 5,
  "monitoring": {
    "enabled": true,
    "metrics_file": "_mcp/logs/metrics.json",
    "log_file": "_mcp/logs/storm_mcp_production.log"
  },
  "performance": {
    "max_memory_mb": 512,
    "max_cpu_percent": 80,
    "alert_thresholds": {
      "memory_mb": 400,
      "cpu_percent": 70
    }
  }
}
```

### Step 3: Create Systemd Service File
Create `_mcp/deployment/storm-mcp.service`:

```ini
[Unit]
Description=Storm Logger MCP Server
After=network.target
Wants=network.target

[Service]
Type=simple
User=storm-mcp
Group=storm-mcp
WorkingDirectory=/opt/storm-logger
ExecStart=/usr/bin/python3 _mcp/storm_mcp_launcher.py --config _mcp/config/production.json
ExecReload=/bin/kill -HUP $MAINPID
KillMode=mixed
Restart=always
RestartSec=10
TimeoutStopSec=30

# Security settings
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/storm-logger/_mcp/logs

# Environment
Environment=PYTHONPATH=/opt/storm-logger
Environment=STORM_MCP_ENV=production

[Install]
WantedBy=multi-user.target
```

### Step 4: Create Deployment Script
Create `_mcp/deployment/deploy.sh`:

```bash
#!/bin/bash
# Storm Logger MCP Production Deployment Script

set -e

DEPLOY_DIR="/opt/storm-logger"
SERVICE_NAME="storm-mcp"
USER="storm-mcp"

echo "🚀 Storm Logger MCP Production Deployment"
echo "=========================================="

# Check if running as root
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root"
   exit 1
fi

# Create user if it doesn't exist
if ! id "$USER" &>/dev/null; then
    echo "Creating user $USER..."
    useradd -r -s /bin/false -d "$DEPLOY_DIR" "$USER"
fi

# Create deployment directory
echo "Creating deployment directory..."
mkdir -p "$DEPLOY_DIR"
mkdir -p "$DEPLOY_DIR/_mcp/logs"
mkdir -p "$DEPLOY_DIR/_mcp/config"

# Copy files
echo "Copying application files..."
cp -r . "$DEPLOY_DIR/"
chown -R "$USER:$USER" "$DEPLOY_DIR"

# Install systemd service
echo "Installing systemd service..."
cp "_mcp/deployment/storm-mcp.service" "/etc/systemd/system/"
systemctl daemon-reload

# Enable and start service
echo "Enabling and starting service..."
systemctl enable "$SERVICE_NAME"
systemctl start "$SERVICE_NAME"

# Check service status
echo "Checking service status..."
systemctl status "$SERVICE_NAME"

echo "✅ Deployment complete!"
echo "Use 'systemctl status storm-mcp' to check status"
echo "Use 'journalctl -u storm-mcp -f' to view logs"
```

### Step 5: Create Development Launcher
Create `_mcp/dev_launcher.py`:

```python
#!/usr/bin/env python3
"""
Storm Logger MCP Development Launcher
Simplified launcher for development and testing
"""

import sys
import os
from pathlib import Path

# Add project root to path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

def main():
    """Main development launcher."""
    print("⚡ Storm Logger MCP Development Server")
    print("====================================")
    
    try:
        # Create server
        from _mcp.main import create_storm_mcp_server
        server = create_storm_mcp_server()
        
        print(f"✅ Server created: {server.name}")
        print(f"🛠️  Tools available: {len(server.tools)}")
        
        # List tools
        print("\n🔧 Available Tools:")
        for i, tool in enumerate(server.tools, 1):
            tags = ", ".join(tool.tags) if hasattr(tool, 'tags') else "no tags"
            print(f"  {i}. {tool.name} ({tags})")
        
        # Run health check
        print("\n🏥 Running health check...")
        health_tool = None
        for tool in server.tools:
            if tool.name == "health_check":
                health_tool = tool
                break
        
        if health_tool:
            result = health_tool.function()
            status = result.get("overall_status", "unknown")
            print(f"   Health Status: {status.upper()}")
            
            if status == "healthy":
                print("   ✅ All systems operational")
            else:
                print("   ⚠️  Some issues detected")
                print("   📋 Server Details:")
                for server_info in result.get("servers", []):
                    status_icon = "✅" if server_info["status"] == "healthy" else "⚠️"
                    print(f"     {status_icon} {server_info['name']}")
        else:
            print("   ⚠️  No health check tool found")
        
        print("\n🎉 Development server ready!")
        print("   Use this server for development and testing")
        print("   For production deployment, use storm_mcp_launcher.py")
        
        return 0
        
    except Exception as e:
        print(f"❌ Failed to start development server: {e}")
        import traceback
        traceback.print_exc()
        return 1

if __name__ == "__main__":
    sys.exit(main())
```

## Testing/Validation

### Step 1: Test Development Launcher
```bash
# Test development launcher
python _mcp/dev_launcher.py
```

### Step 2: Test Production Launcher
```bash
# Test production launcher
python _mcp/storm_mcp_launcher.py --health-check
```

### Step 3: Test Configuration Loading
```bash
# Test with custom config
python _mcp/storm_mcp_launcher.py --config _mcp/config/production.json --verbose
```

### Step 4: Test Deployment Script (in VM or test environment)
```bash
# Test deployment script
sudo _mcp/deployment/deploy.sh
```

## Success Criteria
- [ ] Production launcher works correctly
- [ ] Development launcher provides good feedback
- [ ] Configuration system working
- [ ] Systemd service file created
- [ ] Deployment script functional
- [ ] Health check integration working

## JSON Update Instructions

When starting this step:
```json
{
  "steps": {
    "08": {
      "status": "in_progress",
      "progress": 20,
      "issues": ["Creating production launcher"],
      "next_action": "Implement production launcher with monitoring"
    }
  }
}
```

When 50% complete (launcher created):
```json
{
  "steps": {
    "08": {
      "status": "in_progress",
      "progress": 50,
      "issues": ["Creating deployment scripts"],
      "next_action": "Create systemd service and deployment scripts"
    }
  }
}
```

When complete:
```json
{
  "steps": {
    "08": {
      "status": "completed",
      "progress": 100,
      "issues": [],
      "next_action": "Proceed to Step 09"
    }
  },
  "current_step": "09",
  "overall_progress": 80,
  "completed_features": [
    "All 7 server modules implemented",
    "Health check functions added",
    "Server creation working",
    "Import dependencies resolved",
    "Complete health check system",
    "Individual server testing complete",
    "MCP integration with test runner",
    "Production launcher system"
  ]
}
```

## Troubleshooting

### Common Issues

1. **Launcher fails to start**
   - Check Python path setup
   - Verify server creation works
   - Check configuration file

2. **Monitoring not working**
   - Check log directory permissions
   - Verify threading support
   - Check metrics file path

3. **Systemd service fails**
   - Check user permissions
   - Verify file paths
   - Check service dependencies

### Debug Commands
```bash
# Test server creation
python -c "
import sys
sys.path.append('.')
from _mcp.main import create_storm_mcp_server
server = create_storm_mcp_server()
print(f'Server: {server.name}')
"

# Test launcher components
python -c "
import sys
sys.path.append('.')
from _mcp.storm_mcp_launcher import StormMCPLauncher
launcher = StormMCPLauncher()
print(f'Config: {launcher.config}')
"
```

## Next Steps
After completing this step:
1. Update JSON status to "completed"
2. Proceed to Step 09: Implement Monitoring & Logging
3. Use launcher system for monitoring implementation

## Notes
- Production launcher should be robust and handle errors gracefully
- Development launcher should provide helpful feedback
- Deployment script should be tested in staging environment
- Monitor system resources during operation