diff --git a/README.md b/README.md index 1376fe0..31ce734 100644 --- a/README.md +++ b/README.md @@ -371,6 +371,8 @@ A build runs on the remote build service, in a builder of your own account, from sources the builder fetches itself: a git repository or a tarball, never a directory on this machine. A create takes the properties the API describes; `kraftfile_from` reads the Kraftfile out of a source, and `image_output` pushes the image with your token. +Without a `kraftfile`, the build is the `Dockerfile` in the context on the +`base-compat:latest` runtime. `logs()` follows the progress as buildkit events, every event once, asking again and skipping what it has seen when the stream is cut, and ends with the event that carries the `result` or the `error`: a failed build is that last event, not an exception. diff --git a/src/unikraft_cloud/api/build/models_gen.py b/src/unikraft_cloud/api/build/models_gen.py index b551ca0..fbdd2e3 100644 --- a/src/unikraft_cloud/api/build/models_gen.py +++ b/src/unikraft_cloud/api/build/models_gen.py @@ -116,6 +116,16 @@ class Build(BaseModel): """The state of the build.""" builder: str | None = None """The name of the builder the build runs on.""" + kraftfile: Kraftfile | None = None + """ + The Kraftfile of the request. Absent for a build without one, and for a + build from before the service kept its requests. + """ + contexts: BuildContexts | None = None + """ + The contexts of the request, where the build gets its files from. Absent + for a build from before the service kept its requests. + """ session: str | None = None """ The path to attach the build's session at. Only present while the build is @@ -147,11 +157,11 @@ class BuildContexts(BaseModel): # Fields the specification does not describe are kept rather than dropped, # so a newly added one survives a round trip and does not break this client. - # A field the specification requires is required here too, so a request - # missing one fails at construction rather than at the server. + # Every field is optional: one response shape serves several requests, and a + # summary listing or a failed bulk item carries only some of them. model_config = ConfigDict(extra="allow", populate_by_name=True) - context: Source + context: Source | None = None """ The build context: the directory the Dockerfile is built in, and the directory relative paths in the Kraftfile resolve in. @@ -220,8 +230,7 @@ class BuildOutput(BaseModel): volume: str | None = None """ The name or UUID of an existing volume to import the built filesystem - into. Only valid for a plain image of a single platform. Not supported - yet. + into. Only valid for a build of a single platform. Not supported yet. """ metro: str | None = None """ @@ -335,17 +344,18 @@ class CreateBuildRequest(BaseModel): kraftfile: Kraftfile | None = None """ - The Kraftfile to build, which makes the build a Unikraft image. Without - one, the build is a plain image of `context`, built with the Dockerfile in - `dockerfile`. + The Kraftfile to build. Without one, the build uses a Kraftfile with + `runtime: base-compat:latest` and `rootfs: ./Dockerfile`, so its rootfs + is `contexts.context` built with the file `Dockerfile`, or with the one + that `contexts.dockerfile` gives. """ contexts: BuildContexts """The contexts to build from.""" platforms: list[str] | None = None """ The platforms to build for. Only the architecture selects, so `x86_64` is - `linux/amd64`. Defaults to the targets of the Kraftfile or of its runtime, - or to the builder's own platform for a plain image. + `linux/amd64`. Defaults to the targets of the Kraftfile, or to `x86_64` + when it has none. """ build_args: dict[str, str] | None = None """The values of the Dockerfile's `ARG`s, by name.""" @@ -537,8 +547,8 @@ class Source(BaseModel): # Fields the specification does not describe are kept rather than dropped, # so a newly added one survives a round trip and does not break this client. - # A field the specification requires is required here too, so a request - # missing one fails at construction rather than at the server. + # Every field is optional: one response shape serves several requests, and a + # summary listing or a failed bulk item carries only some of them. model_config = ConfigDict(extra="allow", populate_by_name=True) session: str | None = None diff --git a/src/unikraft_cloud/resources/builds.py b/src/unikraft_cloud/resources/builds.py index 387738d..ca76c48 100644 --- a/src/unikraft_cloud/resources/builds.py +++ b/src/unikraft_cloud/resources/builds.py @@ -2,11 +2,12 @@ # Copyright (c) 2026, Unikraft GmbH. All rights reserved. # # Builds on the remote build service: a request names the sources, the -# Kraftfile and the outputs, the build runs on a builder in the caller's own -# account, and its progress can be followed from the start until it ends. The -# service is global, so no metro scope applies. Every source is a git -# repository or a tarball the builder fetches itself: a directory on this -# machine would need a buildkit session, which the service does not take yet. +# outputs and a Kraftfile, or no Kraftfile to build the context's Dockerfile +# alone; the build runs on a builder in the caller's own account, and its +# progress can be followed from the start until it ends. The service is +# global, so no metro scope applies. Every source is a git repository or a +# tarball the builder fetches itself: a directory on this machine would need +# a buildkit session, which the service does not take yet. from __future__ import annotations @@ -165,6 +166,8 @@ def __init__(self, session: Session) -> None: async def create(self, *, timeout: TimeoutOption = UNSET, **spec: Any) -> Build: """Create a build from the properties the API describes; it runs whether or not followed. + Without a ``kraftfile``, the build is the ``Dockerfile`` in the + ``context`` on the ``base-compat:latest`` runtime, for ``x86_64``. A property the API does not describe is a ``TypeError``. The service refuses a request that uses a part of the API it does not support yet with the code ``unsupported``, and a tenant with as many builds