chalkcompute 2.2.0__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/PKG-INFO +1 -1
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/__init__.py +0 -2
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/__init__.pyi +0 -4
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_connect.py +4 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_container.py +253 -73
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_function.py +231 -13
- chalkcompute-2.3.0/chalkcompute/_gen/chalk/container/v1/service_pb2.py +282 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/container/v1/service_pb2.pyi +111 -2
- chalkcompute-2.3.0/chalkcompute/_gen/chalk/sandbox/v1/service_pb2.py +246 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/sandbox/v1/service_pb2.pyi +5 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_image.py +18 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_remote_call_client.py +30 -9
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_sandbox.py +29 -2
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/pyproject.toml +1 -1
- chalkcompute-2.2.0/chalkcompute/_gen/chalk/container/v1/service_pb2.py +0 -262
- chalkcompute-2.2.0/chalkcompute/_gen/chalk/sandbox/v1/service_pb2.py +0 -243
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/README.md +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_arrow_schema.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_auth_config.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_cls.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_concurrency.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/buf/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/buf/validate/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/buf/validate/validate_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/buf/validate/validate_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/buf/validate/validate_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/buf/validate/validate_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/argo/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/argo/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/argo/v1/workflow_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/argo/v1/workflow_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/argo/v1/workflow_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/argo/v1/workflow_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/arrow/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/arrow/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/arrow/v1/arrow_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/arrow/v1/arrow_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/arrow/v1/arrow_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/arrow/v1/arrow_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/agent_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/agent_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/agent_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/agent_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/audit_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/audit_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/audit_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/audit_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/displayagent_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/displayagent_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/displayagent_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/displayagent_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/featurepermission_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/featurepermission_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/featurepermission_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/featurepermission_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/permissions_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/permissions_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/permissions_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/auth/v1/permissions_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/v1/chalk_error_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/v1/chalk_error_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/v1/chalk_error_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/v1/chalk_error_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/v1/log_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/v1/log_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/v1/log_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/common/v1/log_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/container/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/container/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/container/v1/service_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/container/v1/service_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/externalfunctioncatalog/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/externalfunctioncatalog/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/externalfunctioncatalog/v1/service_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/externalfunctioncatalog/v1/service_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/externalfunctioncatalog/v1/service_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/externalfunctioncatalog/v1/service_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/flags/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/flags/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/flags/v1/flags_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/flags/v1/flags_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/flags/v1/flags_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/flags/v1/flags_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/runtime/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/runtime/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/runtime/v1/remote_python_call_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/runtime/v1/remote_python_call_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/runtime/v1/remote_python_call_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/runtime/v1/remote_python_call_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/sandbox/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/sandbox/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/sandbox/v1/service_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/sandbox/v1/service_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/scalinggroup/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/scalinggroup/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/scalinggroup/v1/service_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/scalinggroup/v1/service_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/scalinggroup/v1/service_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/scalinggroup/v1/service_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/encoding_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/encoding_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/encoding_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/encoding_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/field_change_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/field_change_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/field_change_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/field_change_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/sensitive_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/sensitive_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/sensitive_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/utils/v1/sensitive_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v1/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v1/volume_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v1/volume_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v1/volume_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v1/volume_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v2/__init__.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v2/volume_pb2.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v2/volume_pb2.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v2/volume_pb2_grpc.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_gen/chalk/volume/v2/volume_pb2_grpc.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_ignore.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_local_dev.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_logging.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_model.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_naming.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_native.pyi +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_progress.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_proto_pool.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_quota.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_rate_limit.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_remote_function_tracing.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_retry.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_scaling_group.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_secret.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_tracing.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_volume.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/_vvolume.py +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/chalkcompute/py.typed +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/rust/chalkcompute_native/Cargo.lock +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/rust/chalkcompute_native/Cargo.toml +0 -0
- {chalkcompute-2.2.0 → chalkcompute-2.3.0}/rust/chalkcompute_native/src/lib.rs +0 -0
|
@@ -16,12 +16,10 @@ _LAZY_MAP: dict[str, tuple[str, str]] = {
|
|
|
16
16
|
"ContainerSession": ("chalkcompute._container", "ContainerSession"),
|
|
17
17
|
"ContainerSecurityPolicy": ("chalkcompute._container", "ContainerSecurityPolicy"),
|
|
18
18
|
"ContainerExecResult": ("chalkcompute._container", "ExecResult"),
|
|
19
|
-
"AllowedRoute": ("chalkcompute._container", "AllowedRoute"),
|
|
20
19
|
"ImageBuildError": ("chalkcompute._container", "ImageBuildError"),
|
|
21
20
|
"KernelPolicy": ("chalkcompute._container", "KernelPolicy"),
|
|
22
21
|
"ComputeClass": ("chalkcompute._container", "ComputeClass"),
|
|
23
22
|
"NetworkPolicy": ("chalkcompute._container", "NetworkPolicy"),
|
|
24
|
-
"PortRange": ("chalkcompute._container", "PortRange"),
|
|
25
23
|
# _cls.py
|
|
26
24
|
"RemoteClass": ("chalkcompute._cls", "RemoteClass"),
|
|
27
25
|
"ClassError": ("chalkcompute._cls", "ClassError"),
|
|
@@ -11,7 +11,6 @@ from chalkcompute._connect import build_image_from_spec as build_image
|
|
|
11
11
|
from chalkcompute._connect import (
|
|
12
12
|
build_image_with_volumes_from_spec as build_image_with_volumes,
|
|
13
13
|
)
|
|
14
|
-
from chalkcompute._container import AllowedRoute as AllowedRoute
|
|
15
14
|
from chalkcompute._container import Container as Container
|
|
16
15
|
from chalkcompute._container import ContainerError as ContainerError
|
|
17
16
|
from chalkcompute._container import ContainerInfo as ContainerInfo
|
|
@@ -22,7 +21,6 @@ from chalkcompute._container import ImageBuildError as ImageBuildError
|
|
|
22
21
|
from chalkcompute._container import ComputeClass as ComputeClass
|
|
23
22
|
from chalkcompute._container import KernelPolicy as KernelPolicy
|
|
24
23
|
from chalkcompute._container import NetworkPolicy as NetworkPolicy
|
|
25
|
-
from chalkcompute._container import PortRange as PortRange
|
|
26
24
|
from chalkcompute._function import DeployedFunction as DeployedFunction
|
|
27
25
|
from chalkcompute._function import FunctionBuildError as FunctionBuildError
|
|
28
26
|
from chalkcompute._function import FunctionCallHandle as FunctionCallHandle
|
|
@@ -83,12 +81,10 @@ __all__ = [
|
|
|
83
81
|
"ContainerSession",
|
|
84
82
|
"ContainerSecurityPolicy",
|
|
85
83
|
"ContainerExecResult",
|
|
86
|
-
"AllowedRoute",
|
|
87
84
|
"ImageBuildError",
|
|
88
85
|
"ComputeClass",
|
|
89
86
|
"KernelPolicy",
|
|
90
87
|
"NetworkPolicy",
|
|
91
|
-
"PortRange",
|
|
92
88
|
"RemoteClass",
|
|
93
89
|
"ClassError",
|
|
94
90
|
"ClassBuildError",
|
|
@@ -363,6 +363,10 @@ def build_image(
|
|
|
363
363
|
ConnectError
|
|
364
364
|
If the build fails or times out.
|
|
365
365
|
"""
|
|
366
|
+
image_uri = image.as_image_uri_if_possible()
|
|
367
|
+
if image_uri is not None:
|
|
368
|
+
return image_uri
|
|
369
|
+
|
|
366
370
|
from google.protobuf.json_format import MessageToDict
|
|
367
371
|
|
|
368
372
|
spec_dict = MessageToDict(image.to_proto())
|
|
@@ -19,16 +19,15 @@ destination path's common ancestor.
|
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
21
|
import base64
|
|
22
|
-
import ipaddress
|
|
23
22
|
import logging
|
|
24
23
|
import queue
|
|
25
24
|
import time
|
|
26
25
|
import uuid
|
|
27
26
|
from collections import deque
|
|
28
|
-
from collections.abc import Iterator
|
|
27
|
+
from collections.abc import Iterable, Iterator, Mapping
|
|
29
28
|
from dataclasses import dataclass, field
|
|
30
29
|
from enum import Enum
|
|
31
|
-
from typing import TYPE_CHECKING, Any, NoReturn
|
|
30
|
+
from typing import TYPE_CHECKING, Any, NoReturn, cast
|
|
32
31
|
|
|
33
32
|
import grpc
|
|
34
33
|
|
|
@@ -57,8 +56,6 @@ from chalkcompute._vvolume import VersionedVolumeClient
|
|
|
57
56
|
logger = logging.getLogger(__name__)
|
|
58
57
|
|
|
59
58
|
if TYPE_CHECKING:
|
|
60
|
-
from collections.abc import Iterable
|
|
61
|
-
|
|
62
59
|
from chalkcompute._image import Image as _Image
|
|
63
60
|
from chalkcompute._secret import Secret
|
|
64
61
|
|
|
@@ -145,92 +142,275 @@ class ContainerSecurityPolicy:
|
|
|
145
142
|
return {"kernelPolicy": self.kernel_policy.value}
|
|
146
143
|
|
|
147
144
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
145
|
+
_PortRangeInput = tuple[int, int] | int
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class NetworkPolicy:
|
|
149
|
+
"""Network egress policy for a container.
|
|
151
150
|
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
For HOST containers, missing and empty policies deny application egress
|
|
152
|
+
unless allowed routes or hosts are configured.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
@dataclass(init=False)
|
|
156
|
+
class Route:
|
|
157
|
+
"""Allowed destination CIDR and optional destination port ranges."""
|
|
158
|
+
|
|
159
|
+
route: str
|
|
160
|
+
"""Destination CIDR, e.g. ``"10.0.0.0/8"``."""
|
|
161
|
+
|
|
162
|
+
ports: list[tuple[int, int]]
|
|
163
|
+
"""Destination port ranges. Empty means all ports."""
|
|
164
|
+
|
|
165
|
+
def __init__(
|
|
166
|
+
self,
|
|
167
|
+
route: str,
|
|
168
|
+
*,
|
|
169
|
+
ports: Iterable[_PortRangeInput] | None = None,
|
|
170
|
+
) -> None:
|
|
171
|
+
if not isinstance(route, str):
|
|
172
|
+
raise TypeError("route must be a string")
|
|
173
|
+
if not route:
|
|
174
|
+
raise ValueError("route must not be empty")
|
|
175
|
+
self.route = route
|
|
176
|
+
self.ports = [_coerce_port_range(port) for port in ports or []]
|
|
177
|
+
|
|
178
|
+
def to_dict(self) -> dict[str, Any]:
|
|
179
|
+
body: dict[str, Any] = {"route": self.route}
|
|
180
|
+
if self.ports:
|
|
181
|
+
body["portRanges"] = [
|
|
182
|
+
{"startPort": start_port, "endPort": end_port}
|
|
183
|
+
for start_port, end_port in self.ports
|
|
184
|
+
]
|
|
185
|
+
return body
|
|
186
|
+
|
|
187
|
+
@dataclass
|
|
188
|
+
class Matcher:
|
|
189
|
+
"""String matcher for path, query-string, or header values."""
|
|
190
|
+
|
|
191
|
+
exact: str | None = None
|
|
192
|
+
starts_with: str | None = None
|
|
193
|
+
regex: str | None = None
|
|
194
|
+
|
|
195
|
+
def __post_init__(self) -> None:
|
|
196
|
+
values = [
|
|
197
|
+
self.exact is not None,
|
|
198
|
+
self.starts_with is not None,
|
|
199
|
+
self.regex is not None,
|
|
200
|
+
]
|
|
201
|
+
if sum(values) != 1:
|
|
202
|
+
raise ValueError("set exactly one of exact, starts_with, or regex")
|
|
203
|
+
for name, value in (
|
|
204
|
+
("exact", self.exact),
|
|
205
|
+
("starts_with", self.starts_with),
|
|
206
|
+
("regex", self.regex),
|
|
207
|
+
):
|
|
208
|
+
if value is not None and not isinstance(value, str):
|
|
209
|
+
raise TypeError(f"{name} must be a string")
|
|
210
|
+
|
|
211
|
+
def to_dict(self) -> dict[str, str]:
|
|
212
|
+
if self.exact is not None:
|
|
213
|
+
return {"exact": self.exact}
|
|
214
|
+
if self.starts_with is not None:
|
|
215
|
+
return {"startsWith": self.starts_with}
|
|
216
|
+
assert self.regex is not None
|
|
217
|
+
return {"regex": self.regex}
|
|
154
218
|
|
|
155
|
-
|
|
156
|
-
|
|
219
|
+
@dataclass
|
|
220
|
+
class KeyValueMatcher:
|
|
221
|
+
"""Matcher for a query-string or header entry."""
|
|
222
|
+
|
|
223
|
+
key: NetworkPolicy.Matcher
|
|
224
|
+
value: NetworkPolicy.Matcher | None = None
|
|
225
|
+
|
|
226
|
+
def __post_init__(self) -> None:
|
|
227
|
+
if not isinstance(self.key, NetworkPolicy.Matcher):
|
|
228
|
+
raise TypeError("key must be a NetworkPolicy.Matcher")
|
|
229
|
+
if self.value is not None and not isinstance(
|
|
230
|
+
self.value, NetworkPolicy.Matcher
|
|
231
|
+
):
|
|
232
|
+
raise TypeError("value must be a NetworkPolicy.Matcher")
|
|
233
|
+
|
|
234
|
+
def to_dict(self) -> dict[str, Any]:
|
|
235
|
+
body: dict[str, Any] = {"key": self.key.to_dict()}
|
|
236
|
+
if self.value is not None:
|
|
237
|
+
body["value"] = self.value.to_dict()
|
|
238
|
+
return body
|
|
157
239
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
240
|
+
@dataclass
|
|
241
|
+
class Match:
|
|
242
|
+
"""Request matcher for host policy rules."""
|
|
243
|
+
|
|
244
|
+
path: NetworkPolicy.Matcher | None = None
|
|
245
|
+
methods: list[str] = field(default_factory=list)
|
|
246
|
+
query_strings: list[NetworkPolicy.KeyValueMatcher] = field(default_factory=list)
|
|
247
|
+
headers: list[NetworkPolicy.KeyValueMatcher] = field(default_factory=list)
|
|
248
|
+
|
|
249
|
+
def __post_init__(self) -> None:
|
|
250
|
+
if self.path is not None and not isinstance(
|
|
251
|
+
self.path, NetworkPolicy.Matcher
|
|
252
|
+
):
|
|
253
|
+
raise TypeError("path must be a NetworkPolicy.Matcher")
|
|
254
|
+
if isinstance(self.methods, str):
|
|
255
|
+
raise TypeError("methods must be a list of strings")
|
|
256
|
+
self.methods = list(self.methods or [])
|
|
257
|
+
for method in self.methods:
|
|
258
|
+
if not isinstance(method, str):
|
|
259
|
+
raise TypeError("methods must be a list of strings")
|
|
260
|
+
self.query_strings = list(self.query_strings or [])
|
|
261
|
+
for matcher in self.query_strings:
|
|
262
|
+
if not isinstance(matcher, NetworkPolicy.KeyValueMatcher):
|
|
263
|
+
raise TypeError(
|
|
264
|
+
"query_strings must be a list of NetworkPolicy.KeyValueMatcher"
|
|
265
|
+
)
|
|
266
|
+
self.headers = list(self.headers or [])
|
|
267
|
+
for matcher in self.headers:
|
|
268
|
+
if not isinstance(matcher, NetworkPolicy.KeyValueMatcher):
|
|
269
|
+
raise TypeError(
|
|
270
|
+
"headers must be a list of NetworkPolicy.KeyValueMatcher"
|
|
271
|
+
)
|
|
162
272
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
273
|
+
def to_dict(self) -> dict[str, Any]:
|
|
274
|
+
body: dict[str, Any] = {}
|
|
275
|
+
if self.path is not None:
|
|
276
|
+
body["path"] = self.path.to_dict()
|
|
277
|
+
if self.methods:
|
|
278
|
+
body["method"] = list(self.methods)
|
|
279
|
+
if self.query_strings:
|
|
280
|
+
body["queryString"] = [
|
|
281
|
+
matcher.to_dict() for matcher in self.query_strings
|
|
282
|
+
]
|
|
283
|
+
if self.headers:
|
|
284
|
+
body["headers"] = [matcher.to_dict() for matcher in self.headers]
|
|
285
|
+
return body
|
|
166
286
|
|
|
287
|
+
@dataclass
|
|
288
|
+
class Transformer:
|
|
289
|
+
"""Request transform for a host policy rule."""
|
|
167
290
|
|
|
168
|
-
|
|
291
|
+
headers: dict[str, str] = field(default_factory=dict)
|
|
169
292
|
|
|
293
|
+
def __post_init__(self) -> None:
|
|
294
|
+
self.headers = dict(self.headers or {})
|
|
295
|
+
for key, value in self.headers.items():
|
|
296
|
+
if not isinstance(key, str) or not isinstance(value, str):
|
|
297
|
+
raise TypeError("headers must be a dict[str, str]")
|
|
170
298
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
"""Allowed destination CIDR and optional destination port ranges.
|
|
299
|
+
def to_dict(self) -> dict[str, Any]:
|
|
300
|
+
return {"headers": dict(self.headers)}
|
|
174
301
|
|
|
175
|
-
|
|
176
|
-
|
|
302
|
+
@dataclass
|
|
303
|
+
class Rule:
|
|
304
|
+
"""Host policy rule for matching, transforming, or forwarding requests."""
|
|
305
|
+
|
|
306
|
+
transforms: list[NetworkPolicy.Transformer] = field(default_factory=list)
|
|
307
|
+
match: NetworkPolicy.Match | None = None
|
|
308
|
+
forward_url: str | None = None
|
|
309
|
+
|
|
310
|
+
def __post_init__(self) -> None:
|
|
311
|
+
self.transforms = list(self.transforms or [])
|
|
312
|
+
for transformer in self.transforms:
|
|
313
|
+
if not isinstance(transformer, NetworkPolicy.Transformer):
|
|
314
|
+
raise TypeError(
|
|
315
|
+
"transforms must be a list of NetworkPolicy.Transformer"
|
|
316
|
+
)
|
|
317
|
+
if self.match is not None and not isinstance(
|
|
318
|
+
self.match, NetworkPolicy.Match
|
|
319
|
+
):
|
|
320
|
+
raise TypeError("match must be a NetworkPolicy.Match")
|
|
321
|
+
if self.forward_url is not None and not isinstance(self.forward_url, str):
|
|
322
|
+
raise TypeError("forward_url must be a string")
|
|
323
|
+
|
|
324
|
+
def to_dict(self) -> dict[str, Any]:
|
|
325
|
+
body: dict[str, Any] = {}
|
|
326
|
+
if self.transforms:
|
|
327
|
+
body["transform"] = [
|
|
328
|
+
transformer.to_dict() for transformer in self.transforms
|
|
329
|
+
]
|
|
330
|
+
if self.match is not None:
|
|
331
|
+
body["match"] = self.match.to_dict()
|
|
332
|
+
if self.forward_url is not None:
|
|
333
|
+
body["forwardUrl"] = self.forward_url
|
|
334
|
+
return body
|
|
335
|
+
|
|
336
|
+
allowed_routes: list[Route]
|
|
337
|
+
"""Allowed destination routes and their permitted destination ports."""
|
|
177
338
|
|
|
178
|
-
|
|
179
|
-
"""Destination
|
|
339
|
+
denied_routes: list[str]
|
|
340
|
+
"""Destination CIDRs to deny before evaluating allowed routes or hosts."""
|
|
180
341
|
|
|
181
|
-
|
|
182
|
-
"""
|
|
342
|
+
allowed_hosts: dict[str, list[Rule]]
|
|
343
|
+
"""Host patterns mapped to request rules. Empty rule lists allow the host."""
|
|
183
344
|
|
|
184
345
|
def __init__(
|
|
185
346
|
self,
|
|
186
|
-
route: str | None = None,
|
|
187
|
-
port_ranges: Iterable[PortRangeInput] | None = None,
|
|
188
347
|
*,
|
|
189
|
-
|
|
190
|
-
|
|
348
|
+
allowed_routes: Iterable[Route] | None = None,
|
|
349
|
+
denied_routes: Iterable[str] | None = None,
|
|
350
|
+
allowed_hosts: Iterable[str] | Mapping[str, Iterable[Rule]] | None = None,
|
|
191
351
|
) -> None:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
def to_dict(self) -> dict[str, Any]:
|
|
209
|
-
body: dict[str, Any] = {"route": self.route}
|
|
210
|
-
if self.port_ranges:
|
|
211
|
-
body["portRanges"] = [
|
|
212
|
-
port_range.to_dict() for port_range in self.port_ranges
|
|
213
|
-
]
|
|
214
|
-
return body
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
@dataclass
|
|
218
|
-
class NetworkPolicy:
|
|
219
|
-
"""Network egress allowlist for a container.
|
|
352
|
+
self.allowed_routes = list(allowed_routes or [])
|
|
353
|
+
for route in self.allowed_routes:
|
|
354
|
+
if not isinstance(route, NetworkPolicy.Route):
|
|
355
|
+
raise TypeError("allowed_routes must be a list of NetworkPolicy.Route")
|
|
356
|
+
|
|
357
|
+
if isinstance(denied_routes, str):
|
|
358
|
+
raise TypeError("denied_routes must be a list of strings")
|
|
359
|
+
self.denied_routes = list(denied_routes or [])
|
|
360
|
+
for route in self.denied_routes:
|
|
361
|
+
if not isinstance(route, str):
|
|
362
|
+
raise TypeError("denied_routes must be a list of strings")
|
|
363
|
+
|
|
364
|
+
self.allowed_hosts = {}
|
|
365
|
+
if allowed_hosts is None:
|
|
366
|
+
return
|
|
220
367
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
368
|
+
if isinstance(allowed_hosts, Mapping):
|
|
369
|
+
for host, rules in allowed_hosts.items():
|
|
370
|
+
if not isinstance(host, str):
|
|
371
|
+
raise TypeError("allowed_hosts entries must be strings")
|
|
372
|
+
self._validate_host(host)
|
|
373
|
+
if isinstance(rules, NetworkPolicy.Rule):
|
|
374
|
+
raise TypeError(
|
|
375
|
+
"allowed_hosts values must be lists of NetworkPolicy.Rule"
|
|
376
|
+
)
|
|
377
|
+
self.allowed_hosts[host] = list(
|
|
378
|
+
cast(Iterable[NetworkPolicy.Rule], rules)
|
|
379
|
+
)
|
|
380
|
+
for rule in self.allowed_hosts[host]:
|
|
381
|
+
if not isinstance(rule, NetworkPolicy.Rule):
|
|
382
|
+
raise TypeError(
|
|
383
|
+
"allowed_hosts values must be lists of NetworkPolicy.Rule"
|
|
384
|
+
)
|
|
385
|
+
return
|
|
224
386
|
|
|
225
|
-
|
|
226
|
-
|
|
387
|
+
if isinstance(allowed_hosts, str):
|
|
388
|
+
raise TypeError("allowed_hosts must be a list of strings or a dict")
|
|
389
|
+
for host in allowed_hosts:
|
|
390
|
+
self._validate_host(host)
|
|
391
|
+
self.allowed_hosts[host] = []
|
|
227
392
|
|
|
228
393
|
def to_dict(self) -> dict[str, Any]:
|
|
229
|
-
|
|
394
|
+
body: dict[str, Any] = {
|
|
230
395
|
"allowedRoutes": [
|
|
231
396
|
allowed_route.to_dict() for allowed_route in self.allowed_routes
|
|
232
397
|
]
|
|
233
398
|
}
|
|
399
|
+
if self.denied_routes:
|
|
400
|
+
body["deniedRoutes"] = list(self.denied_routes)
|
|
401
|
+
if self.allowed_hosts:
|
|
402
|
+
body["allowedHosts"] = {
|
|
403
|
+
host: {"rules": [rule.to_dict() for rule in rules]}
|
|
404
|
+
for host, rules in self.allowed_hosts.items()
|
|
405
|
+
}
|
|
406
|
+
return body
|
|
407
|
+
|
|
408
|
+
@staticmethod
|
|
409
|
+
def _validate_host(host: str) -> None:
|
|
410
|
+
if not isinstance(host, str):
|
|
411
|
+
raise TypeError("allowed_hosts entries must be strings")
|
|
412
|
+
if not host:
|
|
413
|
+
raise ValueError("allowed_hosts entries must not be empty")
|
|
234
414
|
|
|
235
415
|
|
|
236
416
|
@dataclass
|
|
@@ -1773,15 +1953,15 @@ def _handle_container_grpc_error(
|
|
|
1773
1953
|
raise ContainerError(f"Container session RPC failed: {details}") from e
|
|
1774
1954
|
|
|
1775
1955
|
|
|
1776
|
-
def _coerce_port_range(port_range:
|
|
1777
|
-
if isinstance(port_range, PortRange):
|
|
1778
|
-
return port_range
|
|
1956
|
+
def _coerce_port_range(port_range: _PortRangeInput) -> tuple[int, int]:
|
|
1779
1957
|
if isinstance(port_range, int) and not isinstance(port_range, bool):
|
|
1780
|
-
|
|
1958
|
+
_validate_port_range(port_range, port_range)
|
|
1959
|
+
return port_range, port_range
|
|
1781
1960
|
if isinstance(port_range, tuple) and len(port_range) == 2:
|
|
1782
1961
|
start_port, end_port = port_range
|
|
1783
|
-
|
|
1784
|
-
|
|
1962
|
+
_validate_port_range(start_port, end_port)
|
|
1963
|
+
return start_port, end_port
|
|
1964
|
+
raise TypeError("ports must be integers or (start_port, end_port) tuples")
|
|
1785
1965
|
|
|
1786
1966
|
|
|
1787
1967
|
def _validate_port_range(start_port: int, end_port: int) -> None:
|