pub struct Session { /* private fields */ }Expand description
The control API of one running MicroVM.
Clone shares the transport, including the cached proxy token, so a clone moved into a
background task (a keepalive) sees the same refresh a resume triggers.
Implementations§
Source§impl Session
impl Session
Sourcepub async fn run_to_completion(
&self,
request: StartRequest,
options: CompletionOptions,
on_output: Option<OutputSink>,
) -> Result<ExecResult, Error>
pub async fn run_to_completion( &self, request: StartRequest, options: CompletionOptions, on_output: Option<OutputSink>, ) -> Result<ExecResult, Error>
Starts request and drives it to exactly one result. See the module docs.
Source§impl Session
impl Session
Sourcepub fn agent_token(&self) -> &str
pub fn agent_token(&self) -> &str
The bearer this session authenticates with.
Public because a caller who launched with a minted token needs to read it back
to reattach later (the Python oracle’s Session.agent_token property, and what
the CLI’s run envelope publishes for microvm exec --agent-token). The value is
still kept out of Debug — readable on purpose is different from printed by
accident.
Sourcepub fn builder(
endpoint: impl Into<String>,
agent_token: impl Into<String>,
) -> SessionBuilder
pub fn builder( endpoint: impl Into<String>, agent_token: impl Into<String>, ) -> SessionBuilder
A builder, for the cases that need a port, a timeout, or a custom backend.
Session::connect, Session::attach and Session::direct are in
microvms_core::prelude, because they build the production HTTP backend (and attach a
signed control plane), which is I/O this module leaves to its caller.
Sourcepub fn egress_posture(&self) -> EgressPosture
pub fn egress_posture(&self) -> EgressPosture
The egress posture of the launch this session addresses (BIND-12).
The value the CLI envelope’s egressPosture reports for the same launch options, set
by crate::sandbox::Sandbox::run from crate::control::egress_posture_for. A
session that does not hold its launch options (attached, direct, or adopted) reports
unsealed, the weakest true claim. Never sealed: see
crate::control::egress_posture_for for the evidence that needs.
Sourcepub fn proxy_auth(&self) -> Option<&Arc<ProxyAuth>>
pub fn proxy_auth(&self) -> Option<&Arc<ProxyAuth>>
The proxy auth, for a caller that needs the mint count or an invalidation.
Sourcepub async fn connect_headers(
&self,
port: u16,
) -> Result<Vec<(String, String)>, Error>
pub async fn connect_headers( &self, port: u16, ) -> Result<Vec<(String, String)>, Error>
Both proxy headers for port, minted through this session’s token cache.
The {url, headers} half of a port-endpoint resolution: pair these with
Self::endpoint and a caller can open its own connection with no knowledge of how
the token is minted or when it refreshes.
Empty for a direct session, which is the correct answer rather than a missing one:
a daemon reached directly takes no proxy headers, so an empty set is exactly what its
requests carry today (see Transport::proxy).
The auth value is a bearer credential and this returns it. Nothing in this crate logs or stores the result.
Sourcepub async fn connect_subprotocols(
&self,
port: u16,
) -> Result<Option<[String; 3]>, Error>
pub async fn connect_subprotocols( &self, port: u16, ) -> Result<Option<[String; 3]>, Error>
The three WebSocket subprotocols for port, minted through this session’s token
cache.
None for a direct session, and that is deliberately not an empty list: the
subprotocol form exists only because a request through the endpoint proxy cannot set
headers, so there is nothing for a directly-reached daemon to offer, and a caller
handed ["lambda-microvms"] with no token would open a handshake that is refused for a
reason naming neither.
See ProxyAuth::subprotocols for the wire format and for the platform’s stripping
behaviour. The middle value carries the credential.
Sourcepub fn rebind(&mut self, endpoint: String)
pub fn rebind(&mut self, endpoint: String)
Points the session at a new endpoint and drops the cached proxy token (STATE-8).
The measured behaviour is that the endpoint URL does not change across suspend/resume, so this is usually a no-op on the URL — but the token drop is not: a token minted against the pre-suspend instance may no longer validate, and that rejection reads exactly like a dead daemon.
Takes &mut self because it changes where the session points, which is not
something a shared reference should be able to do mid-request. The invalidation
itself is &self on ProxyAuth, so a resume path holding only the auth can
still drop the token.
Sourcepub async fn health(&self) -> Result<Health, Error>
pub async fn health(&self) -> Result<Health, Error>
Unauthenticated liveness. bootstrapped is the useful field.
Reachable through the endpoint at all implies bootstrapped in practice — the platform forwards no external traffic until the run hook returns 200 — but a caller inside the VM, or one talking to the daemon directly, can observe the pre-bootstrap state.
Sourcepub async fn keep_awake(
&self,
policy: &KeepAwake,
stop: impl Future<Output = ()>,
) -> Result<KeepAwakeReport, Error>
pub async fn keep_awake( &self, policy: &KeepAwake, stop: impl Future<Output = ()>, ) -> Result<KeepAwakeReport, Error>
Keeps the VM awake by polling health until stop resolves or the policy ends it.
See keepalive: idleness is inbound traffic only, so this is the supported way to
hold a VM up while an exec works without client traffic.
Sourcepub async fn wait_until_ready(&self, timeout: Duration) -> Result<Health, Error>
pub async fn wait_until_ready(&self, timeout: Duration) -> Result<Health, Error>
Polls health until the daemon reports bootstrapped.
Connection errors are expected here rather than exceptional: a VM that has just reached RUNNING commonly refuses a connection or two before the proxy path is wired up, and a mint failure is retryable by construction. A fatal error ends the wait immediately — retrying a 401 until the deadline is one of the two mistakes the retryable split exists to prevent.
Sourcepub async fn run(&self, req: StartRequest) -> Result<ExecHandle, Error>
pub async fn run(&self, req: StartRequest) -> Result<ExecHandle, Error>
Starts a command and returns its handle. Does not wait.
The exec_id on the request is the idempotency key. The daemon returns success
for a known id without spawning a second child, so a caller whose retry must be
safe across its own restart supplies a stable one.
Sourcepub fn exec(&self, exec_id: impl Into<String>) -> ExecHandle
pub fn exec(&self, exec_id: impl Into<String>) -> ExecHandle
A handle for an exec started earlier, possibly by another process.
Sourcepub async fn run_sync(
&self,
req: StartRequest,
timeout: Duration,
) -> Result<ExecResult, Error>
pub async fn run_sync( &self, req: StartRequest, timeout: Duration, ) -> Result<ExecResult, Error>
Start, wait, ack. The one-shot shape, for when output is all you want.
Sourcepub async fn kill(&self, exec_id: &str) -> Result<bool, Error>
pub async fn kill(&self, exec_id: &str) -> Result<bool, Error>
Signals an exec’s whole process group. Returns whether anything was signalled.
Sourcepub async fn procs(&self) -> Result<ProcsResponse, Error>
pub async fn procs(&self) -> Result<ProcsResponse, Error>
Process accounting: every registered exec with its group’s live pids.
The daemon reads /proc itself, so this works against a guest with no ps.
child_exited: true beside a non-empty pids is a command that finished while
something it backgrounded did not; the exec_id beside it is what Self::kill
takes. Bearer-guarded, unlike Self::health: the answer names every pid in the
guest, and a caller without the token has no business with it.
Sourcepub async fn upload_file(
&self,
path: &str,
data: &[u8],
mode: Option<&str>,
) -> Result<(), Error>
pub async fn upload_file( &self, path: &str, data: &[u8], mode: Option<&str>, ) -> Result<(), Error>
Writes one file, creating parents. mode is octal as a string.
Sourcepub async fn download_file_lines(
&self,
path: &str,
start_line: Option<u64>,
end_line: Option<u64>,
) -> Result<Vec<u8>, Error>
pub async fn download_file_lines( &self, path: &str, start_line: Option<u64>, end_line: Option<u64>, ) -> Result<Vec<u8>, Error>
Reads lines start_line through end_line of one file, 1-based and inclusive, sliced
by the daemon. Either bound may be absent (line 1, through EOF), and both absent is
Self::download_file’s request. Line 0 and an inverted range are refused with
ERR_INVALID_ARG before any request.
Sourcepub async fn file_exists(&self, path: &str) -> Result<bool, Error>
pub async fn file_exists(&self, path: &str) -> Result<bool, Error>
Whether a path exists, distinguishing absence from every other refusal.
Source§impl Session
impl Session
Sourcepub async fn sync_manifest(&self) -> Result<Option<Manifest>, Error>
pub async fn sync_manifest(&self) -> Result<Option<Manifest>, Error>
The manifest the last sync left in the guest, or None when there’s none.
A manifest that doesn’t parse reads as None too: a different version, or a workload,
wrote that path, and the safe reading of “can’t tell what’s over there” is the same as
“nothing is”: a full upload, which writes a manifest this build understands.
Sourcepub async fn sync_dir(
&self,
tree: &dyn LocalTree,
dir: &Path,
full: bool,
delete_timeout: Duration,
) -> Result<SyncPass, Error>
pub async fn sync_dir( &self, tree: &dyn LocalTree, dir: &Path, full: bool, delete_timeout: Duration, ) -> Result<SyncPass, Error>
Syncs dir into REMOTE_WORKDIR once: against the guest’s own manifest, or with
full against none, so everything travels. Self::sync_manifest then
Self::sync_pass, the whole of a one-shot sync.
Sourcepub async fn sync_pass(
&self,
tree: &dyn LocalTree,
dir: &Path,
baseline: Option<Manifest>,
delete_timeout: Duration,
) -> Result<SyncPass, Error>
pub async fn sync_pass( &self, tree: &dyn LocalTree, dir: &Path, baseline: Option<Manifest>, delete_timeout: Duration, ) -> Result<SyncPass, Error>
One incremental pass of dir into REMOTE_WORKDIR: hash, diff against baseline,
upload what changed, delete what vanished, and rewrite the guest manifest.
baseline is what the guest holds, usually Self::sync_manifest’s answer or the
last pass’s SyncPass::manifest; None uploads everything. The deletions run as one
rm -rf -- in the guest with delete_timeout as the daemon’s deadline, and a failed
one fails the pass with the guest manifest left as it was, so the next pass orders the
deletions again. Only deletable paths are removed.
Sourcepub async fn download_dir(
&self,
tree: &dyn LocalTree,
remote: &str,
globs: &[String],
dir: &Path,
) -> Result<Vec<Artifact>, Error>
pub async fn download_dir( &self, tree: &dyn LocalTree, remote: &str, globs: &[String], dir: &Path, ) -> Result<Vec<Artifact>, Error>
The tree at remote in the guest, written under dir through LocalTree::extract:
only the regular files globs select, never under .git, never outside dir.
The daemon packs the tree (GET /v1/fs/tar), so members are relative to remote.