SDK internals¶
Source directory¶
All files that go into an SDK should be placed in a source directory where you’ll run SDKcraft to initialize, define, pack and publish the SDK.
SDK platform¶
A platform describes where an SDK can be built and installed.
The components describing a platform are:
The base image: used to build SDKs and initialize workshops.
The CPU architecture:
amd64,arm64,armhf,i386,ppc64el,riscv64, ors390x.
The easiest way to define a platform is to name it after the CPU architecture:
# ...
base: ubuntu@24.04
platforms:
amd64:
arm64:
The above SDK can be built on amd64 or arm64 machines
and installed in ubuntu@24.04 workshops with the same architecture.
The base can also be moved into the platform names:
# ...
platforms:
ubuntu@24.04:amd64:
ubuntu@24.04:arm64:
More complex scenarios can be described using the following attributes:
Key |
Value |
Description |
|---|---|---|
|
array |
List of supported CPU architectures that can build the SDK for the platform. If the SDK has no |
|
string |
CPU architecture the SDK is expected to run on,
or If the SDK has no |
Architecture-independent SDKs require the complex format:
# ...
platforms:
all:
build-on: [amd64, arm64, riscv64]
build-for: all
SDK parts¶
Parts can be thought of as the building blocks of Workshop and SDKcraft.
Each part in the sdkcraft.yaml definition
describes a specific component or piece of the SDK being packaged,
providing a way to modularize the package and manage its dependencies.
SDKcraft is built as a
craft-application,
which affects how parts are implemented.
However, note that stage-packages and stage-snaps
aren’t enabled yet;
instead, rely on the hooks
to implement custom logic of package and snap installation.
For a complete reference of parts and their properties,
refer to the corresponding Craft Parts
documentation section.
SDK plugs and slots¶
Currently, Workshop and SDKcraft support the following interface plugs:
Slots can only be defined for the mount interface.
Camera interface¶
A camera plug in the definition must specify the plug name and the interface:
# ...
plugs:
<NAME>:
interface: camera
This makes the host’s cameras directly available inside the workshop as video capture devices.
Note
See the explanation for more details.
Desktop interface¶
A desktop plug in the definition must specify the plug name and the interface:
# ...
plugs:
<NAME>:
interface: desktop
This makes the host’s Wayland socket directly available inside the workshop.
Note
See the explanation for more details.
GPU interface¶
A GPU plug in the definition must specify the plug name and the interface:
# ...
plugs:
gpu:
interface: gpu
This makes the host’s GPUs directly available inside the workshop via the GPU pass-through mechanism.
Note
See the explanation for more details.
Mount interface¶
A mount plug in the definition must specify the plug name, the interface, and the target directory. The plug can specify permissions and ownership for the target, and whether it is read-only:
# ...
plugs:
<NAME>:
interface: mount
workshop-target: <WORKSHOP DIRECTORY>
mode: <OCTAL FILE MODE> # optional
uid: <USER ID> # optional
gid: <GROUP ID> # optional
read-only: <true | false> # optional
This mounts a directory automatically created by Workshop on the host
to the workshop-target directory.
The $SDK variable can be used to refer to the SDK installation path
inside the workshop.
The host directory will be created under the path
designated by the $XDG_DATA_HOME variable.
The workshop directory will be created using the given mode, uid, and gid.
A mount slot in the definition must specify the slot name, the interface, and the source directory:
# ...
slots:
<NAME>:
interface: mount
workshop-source: <WORKSHOP DIRECTORY>
This exposes the workshop-source directory inside the workshop
to be mounted to another directory within the workshop.
The $SDK variable can be used to refer to the SDK installation path
inside the workshop.
Note
See the explanation for more details.
SSH interface¶
An SSH plug in the definition must specify the plug name and the interface:
# ...
plugs:
ssh-agent:
interface: ssh-agent
This proxies the host’s SSH keys and configuration inside the workshop via a Unix domain socket.
Note
See the explanation for more details.
Tunnel interface¶
A tunnel plug in the definition must specify the plug name, the interface and optionally an endpoint:
# ...
plugs:
<NAME>:
interface: tunnel
endpoint: <ENDPOINT>
Similarly, a tunnel slot in the definition must specify the slot name, the interface and optionally an endpoint:
# ...
slots:
<NAME>:
interface: tunnel
endpoint: <ENDPOINT>
When a tunnel interface plug is connected to a slot, clients can connect to the address of the plug. The connection will be forwarded to the address of the slot. Regular SDKs define the workshop side of the connection, leaving the host system to the system SDK.
The supported protocols are TCP, UDP and Unix domain sockets. Unix domain sockets are compatible with TCP, but UDP plugs can only connect to UDP slots.
TCP and UDP endpoints look like <IPv4>:<PORT>/<PROTOCOL> or '[<IPv6>]:<PORT>/<PROTOCOL>'.
Workshop doesn’t resolve hostnames,
but supports the aliases localhost, ip6-localhost and ip6-loopback.
Unix domain socket endpoints are either paths to a socket file or abstract sockets of the form '@<STRING>'.
The $HOME and $XDG_RUNTIME_DIR variables can be used in paths.
Attributes can be abbreviated by omitting tcp and localhost:
Address |
Alternatives |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
Port numbers may also be omitted, but only on one side of a connection. For such connections, both sides use the same port.
Note
See the explanation for more details.
SDK hooks¶
Workshop supports the following lifecycle hooks, which can be defined when the SDK is built using SDKcraft:
Name |
When Workshop runs it |
What it does |
|---|---|---|
|
At workshop launch, workshop refresh: after unpacking the base image and starting the workshop, but before mounting the project directory and connecting plugs and slots. |
Configures system packages and services required by the SDK. |
|
At workshop launch, workshop refresh, workshop restore: after mounting the project directory and auto-connecting plugs and slots but before the workshop is set to Ready. |
Configures the user environment for the SDK to become operational. |
|
At workshop refresh, workshop restore: before destroying the old workshop. |
Saves SDK-specific data to the state directory. The hook itself comes from the old SDK revision. |
|
At workshop refresh, workshop restore:
after running |
Restores SDK-specific data from the state directory. The hook itself comes from the new SDK revision. |
|
At workshop launch:
after running At workshop refresh, workshop restore:
after running |
Sets the state of the SDK
( |
Each hook is defined as a bash script of the same name
under hooks/ in the source directory.
Inside the workshop,
the SDK is mounted at /var/lib/workshop/sdk/<SDK>/
and hooks are stored in the sdk/hooks/ subdirectory.
Most hooks run as root
and use that subdirectory as the working directory.
The exception is setup-project,
which runs as the workshop user
in the /project/ directory.
A hook can signal an error by returning a nonzero exit code;
a zero code indicates success.
The options errexit and pipefail
are set by default,
so most commands which return a nonzero exit code
cause the hook to exit with the same code.
If --verbose is passed to workshop launch or workshop refresh,
the option xtrace is also set.
Note
The hooks aren’t mentioned in the SDK definition; SDKcraft automatically enumerates them when packing the SDK.
An SDK’s position in the workshop definition
determines when its hooks execute.
SDKs are always processed in the following order:
system, user-listed SDKs, sketch.
Each hook waits for the previous one to complete before executing.
SDK state¶
An SDK can store any data specific to it within the workshop.
For this purpose, an environment variable named $SDK_STATE_DIR
is exposed by Workshop at runtime;
it resolves to an internal directory in the workshop,
which save-state and restore-state
can use to preserve and recover the data respectively.
Note
The $SDK_STATE_DIR variable is only available
to the save-state and restore-state SDK hooks.
It is not accessible to the workshop user, the SDK itself,
or in the workshop definition.
The state directory is a dedicated volume created by Workshop at runtime
for each SDK in every workshop,
and is removed when the workshop stops.
The *-state hooks can use it
to store or retrieve any arbitrary data required by the SDK.
SDK channels¶
When SDKs are published by their creators and consumed by workshops,
different versions and releases are tracked through the use of channels.
A channel is a combination of a track, a risk, and an optional branch,
e.g., latest/beta.
Tracks allow multiple published versions of an SDK to exist in parallel;
while no specific scheme is enforced,
it is desirable to use a semantic version, e.g., 1.2.3,
or the latest keyword,
which maps to the latest published version and serves as the default.
Risks represent a choice of maturity levels for a particular track:
stable: indicates that the software can be used in productioncandidate: for software that’s being tested prior to stable deploymentbeta: for software that can be used outside of productionedge: for unstable software that’s still in active development; nothing is guaranteed
Branches are short-lived subdivisions of a channel intended for experimentation, e.g. 1.2.3/edge/issue-56789. After 30 days of no activity, a branch will be closed automatically.
Attention
SDK channels should not be confused with SDK revisions.
See also¶
Explanation: