Python SDK
unikraft-cloud is the official Python SDK for the Unikraft Cloud platform and control-plane APIs.
It has two layers. The idiomatic layer is what you reach for: envelope-free results, automatic pagination, chainable references, and multi-metro fan-out. The plumbing layer underneath mirrors the OpenAPI specification exactly, and stays available for anything the idiomatic layer does not cover yet.
The SDK is async-only.
Installation
Code
Requires Python 3.10 or newer.
Quickstart
Code
The client owns a connection pool, so close it when you are done — either with async with, or by awaiting ukc.aclose().
Authentication
Pass a bearer token to the constructor, or set the UKC_TOKEN environment variable.
Create a token in the Unikraft Cloud console.
Configuration
Code
| Argument | Purpose |
|---|---|
token | Bearer token. Falls back to UKC_TOKEN. |
metro | The metro code that operations default to, such as fra, or a full http(s):// URL for a staging or self-hosted deployment. Falls back to UKC_METRO. A metro code leaves the other metros reachable with ukc.metro(...); a URL pins the client to that endpoint, and naming another metro then raises. |
metros | The metros operations cover by default: "all", one metro, or a list. Creating a resource needs exactly one, so name a metro somewhere when you create. |
base_url | Explicit platform API base URL. It settles where requests go, so it overrides metro and UKC_METRO alike, and pins the client to that one endpoint. |
control_plane_url | Override the control-plane API base URL. |
headers | Extra headers sent with every request. |
user_agent | Override the default User-Agent. |
http | An httpx.AsyncClient to send through. Supplying one makes its lifetime yours. |
transport | An httpx.AsyncBaseTransport, chiefly for testing with httpx.MockTransport. |
trust_env | Honour HTTP_PROXY/HTTPS_PROXY/NO_PROXY. Defaults to True. |
timeout | Timeout for every request. Omitted, an injected http client keeps its own; otherwise the default bounds connecting but not reading, because wait operations block for as long as you asked. |
Metros
The platform API is metro-scoped. By default the client is account-wide: reads ask every metro the account can reach and merge the answers as they arrive, and each result carries the metro it came from.
Code
Naming metros is also how you skip metro discovery, which is otherwise one extra request per client. The metros page lists the regions themselves.
References
A resource is addressed by name or uuid — one or the other, because the API validates whichever field it is given.
Code
A name is only unique within a metro, so the same name can exist in several.
Add metro= to say which you mean, which also saves a lookup:
Code
Without it, and with more than one metro in scope, the SDK asks every metro.
If the name matches in several it raises AmbiguousRefError rather than picking one — with the matches attached, so recovering costs no further requests:
Code
To act on all of them deliberately, use each():
Code
Bulk operations take a sequence of references, as Ref objects, plain dicts, or names:
Code
An operation the API could only carry out in part raises, naming what failed.
What did succeed is on err.results, so a partial failure costs nothing already done:
Code
Chainable handles
Single-resource operations return a handle rather than a coroutine, so they compose. A handle is awaitable too, so awaiting one gives you the resource:
Code
Nothing is sent until a handle is awaited or an operation is chained onto it.
With one metro in scope, get(name=...).suspend() is a single request; when the scope spans metros, the instance is located first so the operation reaches the metro that holds it.
A handle that is dropped without ever being awaited emits a RuntimeWarning: unlike a forgotten await on a coroutine, nothing else would tell you no request was sent.
A handle is awaitable but is not a coroutine, so asyncio.gather(...) takes one while asyncio.create_task(...) does not; wrap it in asyncio.ensure_future(...) for a task.
Updating a resource
Properties are keyword arguments.
A value sets the property, REMOVE clears it out, and anything omitted is left alone — all in one request.
Code
When set is not what you mean — merging into a property, or removing individual members — stage the operations and apply them together:
Code
apply() returns a handle, so the chain continues.
For anything keyword arguments cannot express, patch() takes the raw triples.
Resources
instances, volumes, services, certificates and users hang off any scope — ukc, ukc.metro("fra") or ukc.metros([...]).
Creating one takes the properties the API describes as keyword arguments, and a property it does not have is a TypeError rather than a field the server quietly ignores.
Code
Errors
Every failure is an UnikraftCloudError, so one except catches the lot.
Its kind says which layer failed ("http", "network", "parse" or "fanout") and status carries the HTTP status where there was one.
Code
AuthenticationError (401/403), NotFoundError (404), AlreadyExistsError (409), RateLimitError (429) and ServerError (5xx) are raised for the statuses they name, and all subclass UnikraftCloudError.
The API reports some failures inside an otherwise-200 envelope, per item; those carry the API's own code on err.errors[n].code and are raised with the status that says the same thing.
A wait() that runs out of time raises WaitTimeoutError, which is also a builtin TimeoutError, and carries the state the API last saw:
Code
When the API attaches a warning to an answer — a deprecated field, say — the SDK issues it as a Python UnikraftCloudWarning, so the standard warnings filters apply.
A multi-metro operation that only partly succeeded raises MetroFanoutError.
An iteration yields everything the healthy metros returned before raising, so a partial failure never costs you the whole answer; operations that cannot yield as they go attach what did arrive to err.results.
Code
The plumbing layer
Every operation in the specification is available raw, returning the response envelope untouched.
Each client talks to exactly one metro, and a single call can be redirected with base_url=.
Code
It can also be used on its own, without the idiomatic layer:
Code
Self-hosted and staging deployments
metro (and UKC_METRO) also accepts a full http(s):// base URL, which is used verbatim instead of being expanded into https://api.<metro>.unikraft.cloud.
A named endpoint is then the only endpoint there is: no metro discovery is attempted, and naming another metro raises.
Point the control plane at a matching deployment with control_plane_url.
Code
Source
The SDK source lives at github.com/unikraft-cloud/python-sdk, and the published package at pypi.org/project/unikraft-cloud.
See examples/ for complete programs.
Learn more
- JavaScript SDK: the client library for the same platform API in JavaScript and TypeScript.
- Go SDK: the client library for the same platform API in Go.
- Metros: the regions that the SDK fans out across.
- Instances: create and manage the instances that the SDK drives.
- Unikraft Cloud's REST API reference, which the plumbing layer mirrors.