geronimo.deploy

Geronimo Deploy Module.

This module provides the necessary tooling to deploy infrastructure and applications to cloud providers using Infrastructure as Code (IaC). It primarily integrates with Pulumi's Automation API to programmatically manage cloud resources.

It allows you to:

  • Define infrastructure resources (S3 buckets, EC2 instances, SageMaker endpoints)
  • Deploy entire stacks with a single Python command
  • Manage deployment state and targeted environments (dev/stage/prod)
  • Destroy resources when no longer needed

Note: Pulumi is an optional dependency. Install it with pip install geronimo[pulumi].

 1"""Geronimo Deploy Module.
 2
 3This module provides the necessary tooling to deploy infrastructure and applications
 4to cloud providers using Infrastructure as Code (IaC). It primarily integrates with
 5Pulumi's Automation API to programmatically manage cloud resources.
 6
 7It allows you to:
 8- Define infrastructure resources (S3 buckets, EC2 instances, SageMaker endpoints)
 9- Deploy entire stacks with a single Python command
10- Manage deployment state and targeted environments (dev/stage/prod)
11- Destroy resources when no longer needed
12
13Note: Pulumi is an optional dependency. Install it with `pip install geronimo[pulumi]`.
14"""
15
16from geronimo.deploy.config import DeploymentConfig
17from geronimo.deploy.targets import deploy, destroy, get_available_targets
18from geronimo.deploy.protocol import DeploymentTarget, DeploymentInfo, DeploymentStatus
19
20__all__ = [
21    "DeploymentConfig",
22    "deploy",
23    "destroy",
24    "get_available_targets",
25    "DeploymentTarget",
26    "DeploymentInfo",
27    "DeploymentStatus",
28]
29
30__docformat__ = "google"
class DeploymentConfig(pydantic.main.BaseModel):
33class DeploymentConfig(BaseModel):
34    """Complete deployment configuration.
35    
36    Example:
37        config = DeploymentConfig(
38            project="iris-classifier",
39            target="aws",
40            region="us-west-2",
41        )
42    """
43    
44    project: str
45    version: str = "1.0.0"
46    target: Literal["aws", "gcp", "azure"] = "aws"
47    region: str = "us-east-1"
48    
49    # Component configs
50    artifacts: ArtifactStorageConfig = ArtifactStorageConfig()
51    serving: Optional[ServingConfig] = None
52    batch: Optional[BatchConfig] = None
53    
54    # Pulumi settings
55    stack_name: str = "dev"

Complete deployment configuration.

Example:

config = DeploymentConfig( project="iris-classifier", target="aws", region="us-west-2", )

project: str = PydanticUndefined
version: str = '1.0.0'
target: Literal['aws', 'gcp', 'azure'] = 'aws'
region: str = 'us-east-1'
artifacts: geronimo.deploy.config.ArtifactStorageConfig = ArtifactStorageConfig(bucket_prefix='geronimo-artifacts', retention_days=90, versioning=True)
serving: Optional[geronimo.deploy.config.ServingConfig] = None
batch: Optional[geronimo.deploy.config.BatchConfig] = None
stack_name: str = 'dev'
def deploy( config: DeploymentConfig, component: str | None = None) -> dict:
37def deploy(config: DeploymentConfig, component: str | None = None) -> dict:
38    """Deploy infrastructure using Pulumi.
39    
40    Args:
41        config: Deployment configuration
42        component: Optional component to deploy (artifacts, serving, batch)
43                   If None, deploys all configured components
44    
45    Returns:
46        Dict with deployment outputs (URLs, resource IDs, etc.)
47    
48    Raises:
49        PulumiNotInstalledError: If Pulumi is not installed
50    """
51    if not _check_pulumi_available():
52        raise PulumiNotInstalledError()
53    
54    # Import Pulumi providers dynamically
55    if config.target == "aws":
56        from geronimo.deploy.providers.aws import deploy_aws
57        return deploy_aws(config, component)
58    elif config.target == "gcp":
59        from geronimo.deploy.providers.gcp import deploy_gcp
60        return deploy_gcp(config, component)
61    elif config.target == "azure":
62        from geronimo.deploy.providers.azure import deploy_azure
63        return deploy_azure(config, component)
64    elif config.target == "gdc":
65        from geronimo.deploy_cloud import GeronimoCloudTarget
66        target = GeronimoCloudTarget(config)
67        return target.deploy(component)
68    else:
69        raise ValueError(f"Unknown target: {config.target}")

Deploy infrastructure using Pulumi.

Arguments:
  • config: Deployment configuration
  • component: Optional component to deploy (artifacts, serving, batch) If None, deploys all configured components
Returns:

Dict with deployment outputs (URLs, resource IDs, etc.)

Raises:
  • PulumiNotInstalledError: If Pulumi is not installed
def destroy(config: DeploymentConfig) -> dict:
 72def destroy(config: DeploymentConfig) -> dict:
 73    """Destroy deployed infrastructure.
 74    
 75    Args:
 76        config: Deployment configuration
 77    
 78    Returns:
 79        Dict with destruction summary
 80    
 81    Raises:
 82        PulumiNotInstalledError: If Pulumi is not installed (unless target is cloud)
 83    """
 84    if config.target == "gdc":
 85        from geronimo.deploy_cloud import GeronimoCloudTarget
 86        target = GeronimoCloudTarget(config)
 87        return target.destroy()
 88
 89    if not _check_pulumi_available():
 90        raise PulumiNotInstalledError()
 91    
 92    if config.target == "aws":
 93        from geronimo.deploy.providers.aws import destroy_aws
 94        return destroy_aws(config)
 95    elif config.target == "gcp":
 96        from geronimo.deploy.providers.gcp import destroy_gcp
 97        return destroy_gcp(config)
 98    elif config.target == "azure":
 99        from geronimo.deploy.providers.azure import destroy_azure
100        return destroy_azure(config)
101    else:
102        raise ValueError(f"Unknown target: {config.target}")

Destroy deployed infrastructure.

Arguments:
  • config: Deployment configuration
Returns:

Dict with destruction summary

Raises:
  • PulumiNotInstalledError: If Pulumi is not installed (unless target is cloud)
def get_available_targets() -> list[str]:
28def get_available_targets() -> list[str]:
29    """Get list of available deployment targets.
30    
31    Returns:
32        List of target names (aws, gcp, azure)
33    """
34    return ["aws", "gcp", "azure", "gdc"]

Get list of available deployment targets.

Returns:

List of target names (aws, gcp, azure)

@runtime_checkable
class DeploymentTarget(typing.Protocol):
 30@runtime_checkable
 31class DeploymentTarget(Protocol):
 32    """Protocol for custom deployment targets.
 33    
 34    Implement this protocol to deploy Geronimo models to your own
 35    infrastructure (internal K8s, custom ECS, on-prem servers, etc.).
 36    
 37    Example:
 38        class InternalK8sTarget(DeploymentTarget):
 39            def __init__(self, cluster: str, namespace: str):
 40                self.cluster = cluster
 41                self.namespace = namespace
 42            
 43            def deploy(self, config, artifacts) -> DeploymentInfo:
 44                # Use Helm, kubectl, or K8s API
 45                return DeploymentInfo(
 46                    deployment_id=f"{self.namespace}/{config.project}",
 47                    status=DeploymentStatus.RUNNING,
 48                    endpoint_url=f"http://{config.project}.{self.namespace}.svc",
 49                )
 50            
 51            def status(self, deployment_id) -> DeploymentInfo:
 52                # Query K8s for pod status
 53                ...
 54            
 55            def teardown(self, deployment_id) -> None:
 56                # Delete K8s resources
 57                ...
 58    
 59    Usage in geronimo.yaml:
 60        deployment:
 61          target: custom
 62          custom_target:
 63            class: my_company.deploy.InternalK8sTarget
 64            config:
 65              cluster: production-eks
 66              namespace: ml-models
 67    """
 68    
 69    def deploy(self, config: Any, artifacts: dict[str, str]) -> DeploymentInfo:
 70        """Deploy a model.
 71        
 72        Args:
 73            config: DeploymentConfig or GeronimoConfig
 74            artifacts: Dict of artifact name -> URI
 75        
 76        Returns:
 77            DeploymentInfo with endpoint URL and status
 78        """
 79        ...
 80    
 81    def status(self, deployment_id: str) -> DeploymentInfo:
 82        """Check deployment status.
 83        
 84        Args:
 85            deployment_id: ID returned from deploy()
 86        
 87        Returns:
 88            Current deployment status
 89        """
 90        ...
 91    
 92    def teardown(self, deployment_id: str) -> None:
 93        """Remove a deployment.
 94        
 95        Args:
 96            deployment_id: ID of deployment to remove
 97        """
 98        ...
 99    
100    def logs(self, deployment_id: str, lines: int = 100) -> list[str]:
101        """Get deployment logs.
102        
103        Args:
104            deployment_id: ID of deployment
105            lines: Number of log lines to retrieve
106        
107        Returns:
108            List of log lines
109        """
110        ...

Protocol for custom deployment targets.

Implement this protocol to deploy Geronimo models to your own infrastructure (internal K8s, custom ECS, on-prem servers, etc.).

Example:

class InternalK8sTarget(DeploymentTarget): def __init__(self, cluster: str, namespace: str): self.cluster = cluster self.namespace = namespace

def deploy(self, config, artifacts) -> DeploymentInfo:
    # Use Helm, kubectl, or K8s API
    return DeploymentInfo(
        deployment_id=f"{self.namespace}/{config.project}",
        status=DeploymentStatus.RUNNING,
        endpoint_url=f"http://{config.project}.{self.namespace}.svc",
    )

def status(self, deployment_id) -> DeploymentInfo:
    # Query K8s for pod status
    ...

def teardown(self, deployment_id) -> None:
    # Delete K8s resources
    ...

Usage in geronimo.yaml: deployment: target: custom custom_target: class: my_company.deploy.InternalK8sTarget config: cluster: production-eks namespace: ml-models

DeploymentTarget(*args, **kwargs)
1953def _no_init_or_replace_init(self, *args, **kwargs):
1954    cls = type(self)
1955
1956    if cls._is_protocol:
1957        raise TypeError('Protocols cannot be instantiated')
1958
1959    # Already using a custom `__init__`. No need to calculate correct
1960    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1961    if cls.__init__ is not _no_init_or_replace_init:
1962        return
1963
1964    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1965    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1966    # searches for a proper new `__init__` in the MRO. The new `__init__`
1967    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1968    # instantiation of the protocol subclass will thus use the new
1969    # `__init__` and no longer call `_no_init_or_replace_init`.
1970    for base in cls.__mro__:
1971        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1972        if init is not _no_init_or_replace_init:
1973            cls.__init__ = init
1974            break
1975    else:
1976        # should not happen
1977        cls.__init__ = object.__init__
1978
1979    cls.__init__(self, *args, **kwargs)
def deploy( self, config: Any, artifacts: dict[str, str]) -> DeploymentInfo:
69    def deploy(self, config: Any, artifacts: dict[str, str]) -> DeploymentInfo:
70        """Deploy a model.
71        
72        Args:
73            config: DeploymentConfig or GeronimoConfig
74            artifacts: Dict of artifact name -> URI
75        
76        Returns:
77            DeploymentInfo with endpoint URL and status
78        """
79        ...

Deploy a model.

Arguments:
  • config: DeploymentConfig or GeronimoConfig
  • artifacts: Dict of artifact name -> URI
Returns:

DeploymentInfo with endpoint URL and status

def status(self, deployment_id: str) -> DeploymentInfo:
81    def status(self, deployment_id: str) -> DeploymentInfo:
82        """Check deployment status.
83        
84        Args:
85            deployment_id: ID returned from deploy()
86        
87        Returns:
88            Current deployment status
89        """
90        ...

Check deployment status.

Arguments:
  • deployment_id: ID returned from deploy()
Returns:

Current deployment status

def teardown(self, deployment_id: str) -> None:
92    def teardown(self, deployment_id: str) -> None:
93        """Remove a deployment.
94        
95        Args:
96            deployment_id: ID of deployment to remove
97        """
98        ...

Remove a deployment.

Arguments:
  • deployment_id: ID of deployment to remove
def logs(self, deployment_id: str, lines: int = 100) -> list[str]:
100    def logs(self, deployment_id: str, lines: int = 100) -> list[str]:
101        """Get deployment logs.
102        
103        Args:
104            deployment_id: ID of deployment
105            lines: Number of log lines to retrieve
106        
107        Returns:
108            List of log lines
109        """
110        ...

Get deployment logs.

Arguments:
  • deployment_id: ID of deployment
  • lines: Number of log lines to retrieve
Returns:

List of log lines

class DeploymentInfo(pydantic.main.BaseModel):
20class DeploymentInfo(BaseModel):
21    """Information about a deployment."""
22    
23    deployment_id: str
24    status: DeploymentStatus
25    endpoint_url: str | None = None
26    message: str | None = None
27    resources: dict[str, Any] = {}

Information about a deployment.

deployment_id: str = PydanticUndefined
status: DeploymentStatus = PydanticUndefined
endpoint_url: str | None = None
message: str | None = None
resources: dict[str, typing.Any] = {}
class DeploymentStatus(builtins.str, enum.Enum):
 9class DeploymentStatus(str, Enum):
10    """Status of a deployment."""
11    
12    PENDING = "pending"
13    DEPLOYING = "deploying"
14    RUNNING = "running"
15    FAILED = "failed"
16    STOPPING = "stopping"
17    STOPPED = "stopped"

Status of a deployment.

PENDING = <DeploymentStatus.PENDING: 'pending'>
DEPLOYING = <DeploymentStatus.DEPLOYING: 'deploying'>
RUNNING = <DeploymentStatus.RUNNING: 'running'>
FAILED = <DeploymentStatus.FAILED: 'failed'>
STOPPING = <DeploymentStatus.STOPPING: 'stopping'>
STOPPED = <DeploymentStatus.STOPPED: 'stopped'>