Files
ttulttul-ComfyUI-Modal/remote_configurations.py

220 lines
7.6 KiB
Python

"""Workflow-declared remote execution configuration models."""
from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any
if __package__:
from .execution_environments import ExecutionProvider
from .remote_hosts import SshHostConfig
from .vast_models import VastResourceProfile
else: # pragma: no cover - direct ComfyUI loading fallback.
from execution_environments import ExecutionProvider
from remote_hosts import SshHostConfig
from vast_models import VastResourceProfile
@dataclass(frozen=True)
class RemoteConfiguration(ABC):
"""Describe one workflow-declared pool of remote execution capacity."""
configuration_id: str
display_name: str
def __post_init__(self) -> None:
"""Reject ambiguous identities before provider discovery begins."""
if not self.configuration_id.strip():
raise ValueError("Remote configuration_id must not be empty.")
if not self.display_name.strip():
raise ValueError("Remote configuration display_name must not be empty.")
@property
@abstractmethod
def provider(self) -> ExecutionProvider:
"""Return the provider represented by this configuration."""
@property
@abstractmethod
def capacity_limit(self) -> int:
"""Return the maximum concurrent worker capacity contributed by this pool."""
@abstractmethod
def to_safe_dict(self) -> dict[str, Any]:
"""Return credential-free workflow and diagnostic metadata."""
@dataclass(frozen=True)
class ModalRemoteConfiguration(RemoteConfiguration):
"""Declare a Modal GPU type and its maximum concurrent container capacity."""
gpu_type: str
instance_count: int = 1
def __post_init__(self) -> None:
"""Validate Modal capacity fields."""
super().__post_init__()
if not self.gpu_type.strip():
raise ValueError("Modal gpu_type must not be empty.")
if self.instance_count <= 0:
raise ValueError("Modal instance_count must be positive.")
@property
def provider(self) -> ExecutionProvider:
"""Return the Modal provider identifier."""
return ExecutionProvider.MODAL
@property
def capacity_limit(self) -> int:
"""Return the configured Modal container ceiling."""
return self.instance_count
def to_safe_dict(self) -> dict[str, Any]:
"""Return credential-free Modal configuration metadata."""
return {
"configuration_id": self.configuration_id,
"display_name": self.display_name,
"provider": self.provider.value,
"gpu_type": self.gpu_type,
"instance_count": self.instance_count,
}
@dataclass(frozen=True)
class VastRemoteConfiguration(RemoteConfiguration):
"""Declare one Vast.ai marketplace capacity pool."""
profile: VastResourceProfile
def __post_init__(self) -> None:
"""Keep the wrapper identity aligned with the underlying Vast profile."""
super().__post_init__()
if self.profile.profile_id != self.configuration_id:
raise ValueError(
"Vast profile_id must match its remote configuration_id."
)
if self.profile.profile_name != self.display_name:
raise ValueError(
"Vast profile_name must match its remote configuration display_name."
)
@property
def provider(self) -> ExecutionProvider:
"""Return the Vast.ai provider identifier."""
return ExecutionProvider.VAST
@property
def capacity_limit(self) -> int:
"""Return the maximum number of managed Vast.ai instances."""
return self.profile.maximum_instances
def to_safe_dict(self) -> dict[str, Any]:
"""Return credential-free Vast configuration metadata."""
return {
"configuration_id": self.configuration_id,
"display_name": self.display_name,
"provider": self.provider.value,
"maximum_instances": self.profile.maximum_instances,
"search": self.profile.search_payload(),
}
@dataclass(frozen=True)
class SshRemoteConfiguration(RemoteConfiguration):
"""Declare one SSH-accessible Docker host and its worker capacity."""
host: SshHostConfig
def __post_init__(self) -> None:
"""Keep workflow and host identities aligned."""
super().__post_init__()
if self.host.environment_id != self.configuration_id:
raise ValueError(
"SSH environment_id must match its remote configuration_id."
)
if self.host.display_name != self.display_name:
raise ValueError(
"SSH display_name must match its remote configuration display_name."
)
if self.host.maximum_workers <= 0:
raise ValueError("SSH maximum_workers must be positive in a workflow.")
@property
def provider(self) -> ExecutionProvider:
"""Return the SSH Docker provider identifier."""
return ExecutionProvider.SSH_DOCKER
@property
def capacity_limit(self) -> int:
"""Return the configured worker-container ceiling for this host."""
return self.host.maximum_workers
def to_safe_dict(self) -> dict[str, Any]:
"""Return credential-free SSH configuration metadata."""
return {
"configuration_id": self.configuration_id,
"display_name": self.display_name,
"provider": self.provider.value,
"host": self.host.to_dict(),
}
@dataclass(frozen=True)
class RemoteConfigurationSet:
"""Hold the complete authoritative remote capacity declaration for a workflow."""
configurations: tuple[RemoteConfiguration, ...]
def __post_init__(self) -> None:
"""Require at least one uniquely identified and named configuration."""
if not self.configurations:
raise ValueError(
"Remote Execution Configurator requires at least one configuration."
)
configuration_ids = [
configuration.configuration_id for configuration in self.configurations
]
if len(configuration_ids) != len(set(configuration_ids)):
raise ValueError("Remote configuration IDs must be unique.")
normalized_names = [
configuration.display_name.casefold()
for configuration in self.configurations
]
if len(normalized_names) != len(set(normalized_names)):
raise ValueError("Remote configuration names must be unique.")
modal_gpu_types = [
configuration.gpu_type
for configuration in self.configurations
if isinstance(configuration, ModalRemoteConfiguration)
]
if len(modal_gpu_types) != len(set(modal_gpu_types)):
raise ValueError(
"Each Modal GPU type may appear in only one remote configuration."
)
ssh_targets = [
configuration.host.ssh_target
for configuration in self.configurations
if isinstance(configuration, SshRemoteConfiguration)
]
if len(ssh_targets) != len(set(ssh_targets)):
raise ValueError(
"Each SSH destination may appear in only one remote configuration."
)
def to_safe_list(self) -> list[dict[str, Any]]:
"""Return ordered credential-free configuration metadata."""
return [
configuration.to_safe_dict()
for configuration in self.configurations
]
__all__ = [
"ModalRemoteConfiguration",
"RemoteConfiguration",
"RemoteConfigurationSet",
"SshRemoteConfiguration",
"VastRemoteConfiguration",
]