refactor(sandbox): sandbox provider system default configuration

This commit is contained in:
Harry
2026-01-16 18:21:53 +08:00
parent 8b42435f7a
commit 0bd17c6d0f
19 changed files with 382 additions and 457 deletions

View File

@ -12,13 +12,13 @@ from .constants import (
DIFY_CLI_PATH,
DIFY_CLI_PATH_PATTERN,
)
from .factory import VMBuilder, VMType
from .initializer import AppAssetsInitializer, DifyCliInitializer, SandboxInitializer
from .manager import SandboxManager
from .session import SandboxSession
from .storage import ArchiveSandboxStorage, SandboxStorage
from .utils.debug import sandbox_debug
from .utils.encryption import create_sandbox_config_encrypter, masked_config
from .vm import SandboxBuilder, SandboxType, VMConfig
__all__ = [
"APP_ASSETS_PATH",
@ -34,12 +34,13 @@ __all__ = [
"DifyCliInitializer",
"DifyCliLocator",
"DifyCliToolConfig",
"SandboxBuilder",
"SandboxInitializer",
"SandboxManager",
"SandboxSession",
"SandboxStorage",
"VMBuilder",
"VMType",
"SandboxType",
"VMConfig",
"create_sandbox_config_encrypter",
"masked_config",
"sandbox_debug",

View File

@ -0,0 +1,3 @@
from .providers import SandboxProviderApiEntity
__all__ = ["SandboxProviderApiEntity"]

View File

@ -0,0 +1,21 @@
from collections.abc import Mapping
from typing import Any
from pydantic import BaseModel, Field
class SandboxProviderApiEntity(BaseModel):
provider_type: str = Field(..., description="Provider type identifier")
is_system_configured: bool = Field(default=False)
is_tenant_configured: bool = Field(default=False)
is_active: bool = Field(default=False)
config: Mapping[str, Any] = Field(default_factory=dict)
config_schema: list[dict[str, Any]] = Field(default_factory=list)
class SandboxProviderEntity(BaseModel):
id: str = Field(..., description="Provider identifier")
provider_type: str = Field(..., description="Provider type identifier")
is_active: bool = Field(default=False)
config: Mapping[str, Any] = Field(default_factory=dict)
config_schema: list[dict[str, Any]] = Field(default_factory=list)

View File

@ -1,81 +0,0 @@
from __future__ import annotations
from collections.abc import Mapping, Sequence
from enum import StrEnum
from typing import TYPE_CHECKING, Any
from core.virtual_environment.__base.virtual_environment import VirtualEnvironment
if TYPE_CHECKING:
from .initializer import SandboxInitializer
class VMType(StrEnum):
DOCKER = "docker"
E2B = "e2b"
LOCAL = "local"
def _get_vm_class(vm_type: VMType) -> type[VirtualEnvironment]:
match vm_type:
case VMType.DOCKER:
from core.virtual_environment.providers.docker_daemon_sandbox import DockerDaemonEnvironment
return DockerDaemonEnvironment
case VMType.E2B:
from core.virtual_environment.providers.e2b_sandbox import E2BEnvironment
return E2BEnvironment
case VMType.LOCAL:
from core.virtual_environment.providers.local_without_isolation import LocalVirtualEnvironment
return LocalVirtualEnvironment
case _:
raise ValueError(f"Unsupported VM type: {vm_type}")
class VMBuilder:
def __init__(self, tenant_id: str, vm_type: VMType) -> None:
self._tenant_id = tenant_id
self._vm_type = vm_type
self._user_id: str | None = None
self._options: dict[str, Any] = {}
self._environments: dict[str, str] = {}
self._initializers: list[SandboxInitializer] = []
def user(self, user_id: str) -> VMBuilder:
self._user_id = user_id
return self
def options(self, options: Mapping[str, Any]) -> VMBuilder:
self._options = dict(options)
return self
def environments(self, environments: Mapping[str, str]) -> VMBuilder:
self._environments = dict(environments)
return self
def initializer(self, initializer: SandboxInitializer) -> VMBuilder:
self._initializers.append(initializer)
return self
def initializers(self, initializers: Sequence[SandboxInitializer]) -> VMBuilder:
self._initializers.extend(initializers)
return self
def build(self) -> VirtualEnvironment:
vm_class = _get_vm_class(self._vm_type)
vm = vm_class(
tenant_id=self._tenant_id,
options=self._options,
environments=self._environments,
user_id=self._user_id,
)
for init in self._initializers:
init.initialize(vm)
return vm
@staticmethod
def validate(vm_type: VMType, options: Mapping[str, Any]) -> None:
vm_class = _get_vm_class(vm_type)
vm_class.validate(options)

109
api/core/sandbox/vm.py Normal file
View File

@ -0,0 +1,109 @@
"""
Facade module for virtual machine providers.
Provides unified interfaces to access different VM provider implementations
(E2B, Docker, Local) through VMType, VMBuilder, and VMConfig.
"""
from __future__ import annotations
from collections.abc import Mapping, Sequence
from enum import StrEnum
from typing import Any
from configs import dify_config
from core.entities.provider_entities import BasicProviderConfig
from core.virtual_environment.__base.virtual_environment import VirtualEnvironment
from .initializer import SandboxInitializer
class SandboxType(StrEnum):
"""
Sandbox types.
"""
DOCKER = "docker"
E2B = "e2b"
LOCAL = "local"
@classmethod
def get_all(cls) -> list[str]:
"""
Get all available sandbox types.
"""
if dify_config.EDITION == "SELF_HOSTED":
return [p.value for p in cls]
else:
return [p.value for p in cls if p != SandboxType.LOCAL]
def _get_sandbox_class(sandbox_type: SandboxType) -> type[VirtualEnvironment]:
match sandbox_type:
case SandboxType.DOCKER:
from core.virtual_environment.providers.docker_daemon_sandbox import DockerDaemonEnvironment
return DockerDaemonEnvironment
case SandboxType.E2B:
from core.virtual_environment.providers.e2b_sandbox import E2BEnvironment
return E2BEnvironment
case SandboxType.LOCAL:
from core.virtual_environment.providers.local_without_isolation import LocalVirtualEnvironment
return LocalVirtualEnvironment
case _:
raise ValueError(f"Unsupported sandbox type: {sandbox_type}")
class SandboxBuilder:
def __init__(self, tenant_id: str, sandbox_type: SandboxType) -> None:
self._tenant_id = tenant_id
self._sandbox_type = sandbox_type
self._user_id: str | None = None
self._options: dict[str, Any] = {}
self._environments: dict[str, str] = {}
self._initializers: list[SandboxInitializer] = []
def user(self, user_id: str) -> SandboxBuilder:
self._user_id = user_id
return self
def options(self, options: Mapping[str, Any]) -> SandboxBuilder:
self._options = dict(options)
return self
def environments(self, environments: Mapping[str, str]) -> SandboxBuilder:
self._environments = dict(environments)
return self
def initializer(self, initializer: SandboxInitializer) -> SandboxBuilder:
self._initializers.append(initializer)
return self
def initializers(self, initializers: Sequence[SandboxInitializer]) -> SandboxBuilder:
self._initializers.extend(initializers)
return self
def build(self) -> VirtualEnvironment:
vm_class = _get_sandbox_class(self._sandbox_type)
vm = vm_class(
tenant_id=self._tenant_id,
options=self._options,
environments=self._environments,
user_id=self._user_id,
)
for init in self._initializers:
init.initialize(vm)
return vm
@staticmethod
def validate(vm_type: SandboxType, options: Mapping[str, Any]) -> None:
vm_class = _get_sandbox_class(vm_type)
vm_class.validate(options)
class VMConfig:
@staticmethod
def get_schema(vm_type: SandboxType) -> list[BasicProviderConfig]:
return _get_sandbox_class(vm_type).get_config_schema()