morca · API

orca.hcloud

Hetzner Cloud's API, as the pool autoscaler needs it (#267, orca.pool_scale): make a server, list a pool's, delete one, and the architecture of a server type.

var h = HCloud.from_env() # raises without a token var got = h.create(spec) # Created: ok, or no stock, or why not for s in h.servers("orca-pool=lab"): ... _ = h.delete(s.id) # True if it's gone, already or now h.arch("cax31") # "arm"

The token is ORCA_HCLOUD_TOKEN, or the secret ORCA_HCLOUD_TOKEN_SECRET names (orca.control.fetch_secret: ORCA_SECRET_FETCH on a Hetzner stack); it's sent as a bearer token and never put in an error. A call isn't retried and times out after 10 s: the scheduler calls these from its tick and tries again on the next. ORCA_HCLOUD_ENDPOINT (https://api.hetzner.cloud/v1) is for tests' fake. Hetzner says a type can't be had in a location now with resource_unavailable or placement_error, or server_type_unavailable for one it doesn't offer there: Created.no_stock, which the autoscaler waits on, apart from any other refusal, which it reports.

Structs

ServerSpec

struct ServerSpec

A server to make.

Implements Copyable, Movable

Fields
name: String: 1 to 63 of a-z, 0-9 and -: a host name.
server_type: String
location: String
image: String: The OS image, e.g. ubuntu-24.04.
user_data: String: cloud-init.
labels: List[Tuple[String, String]]
ssh_keys: List[String]: Names of the project's SSH keys to put on it; may be empty.
firewall: String: A firewall's name to apply, or empty.

Created

struct Created

What a create came to: ok with the server's id and address, or no_stock (wait and try again, or elsewhere), or neither, with why.

Implements Copyable, Movable

Fields
ok: Bool
no_stock: Bool
id: String
address: String
why: String

Server

struct Server

Implements Copyable, Movable

Fields
id: String
name: String
status: String: initializing, starting, running, stopping, off, ...
server_type: String
location: String
address: String
pool: String: Its orca-pool label, or empty.

HCloud

struct HCloud

Implements Movable

Fields
endpoint: String
timeout_ms: Int

__init__

def __init__(out self, endpoint: String, token: String)

from_env

def from_env() -> Self

From ORCA_HCLOUD_TOKEN (or the secret ORCA_HCLOUD_TOKEN_SECRET names) and ORCA_HCLOUD_ENDPOINT.

arch

def arch(self, server_type: String) -> String

The architecture of server_type (arm or x86); raises for a type Hetzner doesn't have.

firewall_id

def firewall_id(self, name: String) -> String

The id of the firewall named name; raises for none.

create

def create(self, spec: ServerSpec) -> Created

Makes the server spec says. Hetzner out of spec's type in its location is no_stock; any other refusal is why.

servers

def servers(self, label_selector: String) -> List[Server]

The servers with labels label_selector matches (orca-pool=lab), every page.

delete

def delete(self, id: String) -> Bool

Deletes server id: True once it's gone, now or before (404).

Functions

configured

def configured() -> Bool

Whether this process has a Hetzner token to use.

error_of

def error_of(body: String) -> Tuple[String, String]

A Hetzner error body's error.code and error.message, or empty.

is_no_stock

def is_no_stock(code: String) -> Bool

Aliases

comptime DEFAULT_ENDPOINT = "https://api.hetzner.cloud/v1"
comptime TOKEN = "ORCA_HCLOUD_TOKEN"
comptime TOKEN_SECRET = "ORCA_HCLOUD_TOKEN_SECRET"
comptime ENDPOINT = "ORCA_HCLOUD_ENDPOINT"
comptime NO_STOCK = Array[__literal_size__=Int(3)](String("resource_unavailable"), String("placement_error"), String("server_type_unavailable"), __list_literal__=NoneType(None))

Hetzner's error codes for "not now, not here".