Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/integration_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ jobs:
--build-env PIP_EXTRA_INDEX_URL=https://pypi.org/simple/

echo "--- 2. Deploy ---"
tl deploy /tmp/test_app.py \
--build-env PIP_INDEX_URL=https://test.pypi.org/simple/ \
--build-env PIP_EXTRA_INDEX_URL=https://pypi.org/simple/
tl deploy /tmp/test_app.py

echo "--- All integration tests passed ---"
'
2 changes: 1 addition & 1 deletion crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ enum Commands {

/// Deploy applications to Tensorlake Cloud
Deploy {
/// Arguments passed to the deploy Python module (use --build-env KEY=VALUE to inject ENV directives into generated Dockerfiles)
/// Arguments passed to the deploy Python module
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<String>,
},
Expand Down
8 changes: 6 additions & 2 deletions src/tensorlake/applications/remote/deploy.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
from typing import List, Set
from typing import Dict, List, Set

from ..applications import filter_applications
from ..interface.function import Function
Expand All @@ -8,6 +8,7 @@
ApplicationManifest,
create_application_manifest,
)
from ..remote.manifests.function_manifests import ImageRef
from .code.ignored_code_paths import ignored_code_paths
from .code.loader import load_code
from .code.zip import zip_code
Expand All @@ -18,6 +19,7 @@ def deploy_applications(
upgrade_running_requests: bool = True,
load_source_dir_modules: bool = False,
api_client=None,
image_refs: Dict[str, ImageRef] | None = None,
) -> None:
"""Deploys all applications in the supplied .py file so they are runnable in remote mode (i.e. on Tensorlake Cloud).

Expand Down Expand Up @@ -61,7 +63,9 @@ def deploy_applications(
try:
for application in filter_applications(functions):
app_manifest: ApplicationManifest = create_application_manifest(
application_function=application, all_functions=functions
application_function=application,
all_functions=functions,
image_refs=image_refs,
)
api_client.upsert_application(
manifest_json=app_manifest.model_dump_json(),
Expand Down
16 changes: 14 additions & 2 deletions src/tensorlake/applications/remote/manifests/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
)
from ...interface.function import Function, _ApplicationConfiguration
from .function import FunctionManifest, create_function_manifest
from .function_manifests import ImageRef


class EntryPointInputManifest(BaseModel):
Expand Down Expand Up @@ -63,18 +64,29 @@ def model_dump_json(self, **kwargs: Any) -> str:


def create_application_manifest(
application_function: Function, all_functions: List[Function]
application_function: Function,
all_functions: List[Function],
image_refs: Dict[str, ImageRef] | None = None,
) -> ApplicationManifest:
"""Creates ApplicationManifest for the supplied application function.

`image_refs` maps `Image._id` to the pre-built image reference for any
function whose image was built up-front (e.g. through the sandbox-template
builder). Functions without a mapped image get `image_ref=None` and the
platform falls through to the legacy image lookup.

Raises TensorlakeError on error.
"""
app_config: _ApplicationConfiguration = application_function._application_config
app_signature: inspect.Signature = function_signature(application_function)

image_refs = image_refs or {}
function_manifests: Dict[str, FunctionManifest] = {
fn._function_config.function_name: create_function_manifest(
application_function, app_config.version, fn
application_function,
app_config.version,
fn,
image_ref=image_refs.get(fn._function_config.image._id),
)
for fn in all_functions
}
Expand Down
16 changes: 15 additions & 1 deletion src/tensorlake/applications/remote/manifests/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
)
from .function_manifests import (
FunctionResourcesManifest,
ImageRef,
JSONSchema,
ParameterManifest,
PlacementConstraintsManifest,
Expand Down Expand Up @@ -60,6 +61,10 @@ class FunctionManifest(pydantic.BaseModel):
warm_containers: int | None = None
min_containers: int | None = None
max_containers: int | None = None
# Reference to the pre-built image the platform should run this function
# on. When None, the platform looks the image up through its legacy
# Image-Builder-Service-keyed path (function namespace/app/name/version).
image_ref: ImageRef | None = None


@dataclass
Expand Down Expand Up @@ -208,10 +213,18 @@ def _function_return_type_schema(


def create_function_manifest(
application_function: Function, application_version: str, function: Function
application_function: Function,
application_version: str,
function: Function,
image_ref: ImageRef | None = None,
) -> FunctionManifest:
"""Creates FunctionManifest for the supplied function.

`image_ref` is the pre-built image reference the platform should use to
run this function. Pass it when the deploy flow built the function's
image through the sandbox-template path; leave None to fall through to
the platform's legacy image-builder-service lookup.

Raises TensorlakeError on error.
"""
app_config: _ApplicationConfiguration = application_function._application_config
Expand Down Expand Up @@ -286,6 +299,7 @@ def create_function_manifest(
description=function._function_config.description,
docstring=docstring,
is_api=function._application_config is not None,
image_ref=image_ref,
secret_names=function._function_config.secrets,
# When a function doesn't have a class_init_timeout set it means it's not a class method.
# In this case FE initialization timeout should be the same as function timeout.
Expand Down
20 changes: 20 additions & 0 deletions src/tensorlake/applications/remote/manifests/function_manifests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Any,
Dict,
List,
Literal,
Union,
)

Expand Down Expand Up @@ -108,3 +109,22 @@ class RetryPolicyManifest(BaseModel):

class PlacementConstraintsManifest(BaseModel):
filter_expressions: List[str]


class ImageRef(BaseModel):
"""Reference to a pre-built image for a function executor.

`kind == "sandbox_template"` points at a sandbox template registered via
the SDK's sandbox image builder; the dataplane resolves it to an ext4
filesystem snapshot and boots a Firecracker VM directly from that rootfs.

`kind == "oci"` points at an OCI image (e.g. from the Image Builder
Service); the dataplane imports the rootfs at runtime. This is the legacy
path and is the implicit shape when `image_ref` is absent on a function
manifest.
"""

kind: Literal["sandbox_template", "oci"]
# For `sandbox_template`: the platform sandbox-template id. For `oci`:
# the image URI (e.g., `registry/path@digest`).
id: str
74 changes: 0 additions & 74 deletions src/tensorlake/builder/__init__.py

This file was deleted.

Loading
Loading