Skip to content

Python Functions

copa can execute Python functions directly, allowing you to integrate custom logic alongside Ansible playbooks.

Function Integration

Commands in toc.yml that don't end in .yml or .yaml are treated as Python module.function references:

commands:
  - monitoring:
    - health: monitoring.health_check
    - metrics: monitoring.collect_metrics
  - reporting:
    - daily: reports.generate_daily_report

Function Requirements

Module Structure

Functions must be importable from copa's execution context:

# monitoring.py
import logging

logger = logging.getLogger(__name__)

def health_check():
    """Check application health status."""
    logger.info("Starting health check")

    # Your health check logic here
    services = ["web", "database", "cache"]
    status = {}

    for service in services:
        status[service] = check_service_status(service)

    logger.info(f"Health check complete: {status}")
    return status

def check_service_status(service_name):
    """Check if a specific service is running."""
    # Implementation here
    return "healthy"

Function Signatures

Functions can accept various parameter types:

def deploy_application(version="latest", environment="staging"):
    """Deploy application with specified version."""
    pass

def process_data(*args, **kwargs):
    """Process data with flexible arguments."""
    pass

Logging Integration

Use Python's standard logging module - copa will capture and format the output:

import logging

logger = logging.getLogger(__name__)

def example_function():
    logger.debug("Debug information")
    logger.info("General information")
    logger.warning("Warning message")
    logger.error("Error occurred")
    logger.critical("Critical failure")

Logging output respects Copa's verbosity levels: - Default: ERROR and CRITICAL only - '-v': WARNING and above - -vv: INFO and above - -vvv: DEBUG and above

Error Handling

Handle errors gracefully in your functions:

import logging
from typing import Dict, Any

logger = logging.getLogger(__name__)

def robust_function() -> Dict[str, Any]:
    """Example of proper error handling."""
    try:
        # Your logic here
        result = perform_operation()
        logger.info("Operation completed successfully")
        return {"status": "success", "data": result}

    except ValueError as e:
        logger.error(f"Invalid input: {e}")
        return {"status": "error", "message": str(e)}

    except Exception as e:
        logger.critical(f"Unexpected error: {e}")
        raise  # Re-raise for Copa to handle

Return Values

Functions can return various types of data:

def get_status():
    """Return simple status."""
    return "operational"

def get_metrics():
    """Return structured data."""
    return {
        "cpu_usage": 45.2,
        "memory_usage": 67.8,
        "disk_usage": 23.1
    }

def generate_report():
    """Return nothing (side effects only)."""
    # Write report to file
    with open("report.txt", "w") as f:
        f.write("Report content")
    # No return value needed

Integration with Ansible

Functions can complement Ansible playbooks:

import subprocess
import json

def prepare_inventory():
    """Generate dynamic inventory for Ansible."""
    inventory = {
        "web_servers": {
            "hosts": discover_web_servers()
        },
        "db_servers": {
            "hosts": discover_db_servers()
        }
    }

    with open("inventory.json", "w") as f:
        json.dump(inventory, f)

    return inventory

def post_deployment_checks():
    """Run checks after Ansible deployment."""
    # Verify services are running
    # Check application endpoints
    # Send notifications
    pass

Best Practices

Module Organization

copa/
├── functions/
│   ├── __init__.py
│   ├── monitoring.py
│   ├── deployment.py
│   └── reporting.py
└── conf/
    └── toc.yml

Documentation

Use Google-style docstrings:

def deploy_service(service_name: str, version: str = "latest") -> bool:
    """Deploy a service to the specified version.

    Args:
        service_name: Name of the service to deploy
        version: Version to deploy (defaults to 'latest')

    Returns:
        True if deployment succeeded, False otherwise

    Raises:
        ValueError: If service_name is invalid
        DeploymentError: If deployment fails
    """
    pass

Type Hints

Use type hints for better code clarity:

from typing import List, Dict, Optional, Union

def process_hosts(hosts: List[str]) -> Dict[str, str]:
    """Process a list of hostnames."""
    pass

def get_config(key: str) -> Optional[Union[str, int, bool]]:
    """Get configuration value."""
    pass

Testing

Write tests for your functions:

# tests/test_monitoring.py
import pytest
from monitoring import health_check

def test_health_check():
    """Test health check function."""
    result = health_check()
    assert isinstance(result, dict)
    assert "web" in result
    assert "database" in result