Skip to main content

Module http

Module http 

Source
Expand description

The socket: HTTP/1.1, hand-rolled, because one of the behaviours is not a status code.

Behaviour 2 is that GET /1.3/price fails at the transport level — connection reset, nothing written — and monetize’s start-time credential probe reported “the credential in UPCLOUD_TOKEN could not be verified” for what was a dropped socket. A framework that hands back a Response cannot express “write nothing and close”, and a mock that answered 503 there would never have provoked the misreport. So the server is a TcpListener, a request parser and a response writer: about two hundred lines, and every one of the twenty-two behaviours is reachable from it.

Keep-alive is supported (the real plugin’s reqwest client pools connections, and a mock that closed every socket would hide a pooling bug). Bodies are read by Content-Length; Transfer-Encoding: chunked requests are refused by name, because the real API does not send them and a silent mis-parse is worse than a refusal.

§The surface

methodpathnotes
GET/1.3/pricebehaviour 2 lives here
GET/1.3/accountwhat a credential probe reads
GET/1.3/server?label=k=v, repeatable; thin rows (behaviour 4)
GET/1.3/server/{uuid}the only place attachments and IPs exist; 404 SERVER_NOT_FOUND for a uuid the LIST carries (36, by name)
POST/1.3/server98–105 s in maintenance (behaviour 6); 412 out_of_stock in a sold-out zone (37)
PUT/1.3/server/{uuid}plan · boot_order · labels · remote_access (behaviours 9, 14, 17)
DELETE/1.3/server/{uuid}?storages=1&backups=keep; needs stopped (11); slow (7)
POST/1.3/server/{uuid}/start412 out_of_stock (behaviour 3)
POST/1.3/server/{uuid}/stopsoft/hard; timeout is a STRING
POST/1.3/server/{uuid}/restart
POST/1.3/server/{uuid}/storage/attach
POST/1.3/server/{uuid}/storage/detachrefused on a started server (16); can answer 200 and leave the device attached (38, by name)
POST/1.3/server/{uuid}/cdrom/ejectworks on a started server (16)
POST/1.3/server/{uuid}/cdrom/loada medium into an EMPTY tray; 409 CDROM_DEVICE_IN_USE otherwise (L110, documented, not measured)
GET/1.3/server/{uuid}/firewall_rule403 ERROR_AUTHENTICATION_FAILED for a deleted server (1); the SAME 403 for a live one under a credential without the firewall permission (35, by name)
GET/1.3/storageincludes public templates
GET/1.3/storage/privatethe account’s own
GET/1.3/storage/{uuid}
POST/1.3/storage
PUT/1.3/storage/{uuid}a shrink is refused by name (22)
POST/1.3/storage/{uuid}/resizetakes a Resize Backup FIRST and hands it back as resize_backup (34)
DELETE/1.3/storage/{uuid}
POST/1.3/storage/{uuid}/importdirect upload

§The terraform door

private-holger-ops reaches the same account through UpCloudLtd/upcloud 5.44 rather than through the plugin, and asks for four things the plugin never asks for. They are listed apart because they are INFERRED from the provider’s own calls rather than measured against the account — see crate::tf.

methodpathnotes
GET/1.3/planread before EVERY server create; an unknown plan is refused there
GET/1.3/storage/public · /template · /favoritehow an OS template is resolved BY TITLE
PUT · POST/1.3/server/{uuid}/firewall_rulethe rule SET, written whole (PUT) or appended to (POST)
DELETE/1.3/server/{uuid}/firewall_rule/{position}one rule by position

POST /1.3/server takes the same door’s richer body: the machine’s network interfaces, its boot order, its firewall flag, its timezone and every device — the template to clone AND the volumes to attach.

Everything else answers 404 MOCK_UPCLOUD_NOT_IMPLEMENTED naming the path.

§The mock’s own door

/mock/… is not an UpCloud path and cannot collide with one: /mock/estate (everything, for a test’s assertions), /mock/fault/{name}/arm|disarm, /mock/relay (behaviour 12: reshuffle the addresses), /mock/seed.

Structs§

Heard
One credential’s traffic, as the mock heard it (behaviour 63).
Mock
The whole mock: one estate behind one lock. A real UpCloud account is one serialized thing too — two POST /1.3/storage calls do not interleave — so the lock is not a simplification, it is the provider’s own concurrency.

Functions§

probe
One request against a mock, IN PROCESS, with no socket at all.
serve
Bind and serve until the process ends. Returns the bound port, which is what a test needs when it asked for port 0.