pub struct Client(/* private fields */);Expand description
The Incus API client. Cheap to clone (Arc-backed) - share one instance
across tasks rather than constructing a new one per call.
Implementations§
Source§impl Client
impl Client
Sourcepub async fn wait_for_operation(
&self,
id: Uuid,
timeout: Option<Duration>,
) -> Result<Operation>
pub async fn wait_for_operation( &self, id: Uuid, timeout: Option<Duration>, ) -> Result<Operation>
Waits for operation id to reach a terminal status, using Incus’s
.../wait?timeout=<seconds> long-poll endpoint.
timeout = Some(duration): bounds a single long-poll call. If the operation is still in-progress when that window elapses, this returnsOk(Operation)with the in-progress snapshot - it does not re-poll, since the caller explicitly chose how long they’re willing to wait.timeout = None: waits indefinitely by transparently re-issuing the long-poll call as many times as needed until a terminal status is reached. Each individual call is still bounded server-side; this just means the method as a whole doesn’t return until completion.
A terminal status in the 400-599 (failure) range returns
Err(Error::OperationFailed { .. }), not Ok(Operation) - callers
don’t need to inspect status_code themselves to detect failure.
Sourcepub async fn cancel_operation(&self, op: &Operation) -> Result<()>
pub async fn cancel_operation(&self, op: &Operation) -> Result<()>
Cancels operation op if it’s cancellable. Short-circuits with
Error::NotCancellable (no network call) when op.may_cancel is
false, since the server would reject it anyway and there’s no reason
to round-trip to find that out.
Source§impl Client
impl Client
Sourcepub async fn list_images(&self, recursion: bool) -> Result<Vec<Value>>
pub async fn list_images(&self, recursion: bool) -> Result<Vec<Value>>
recursion = true fetches every image’s full object in one call;
recursion = false returns lightweight fingerprint/URL references.
Sourcepub async fn get_image(&self, fingerprint: &str) -> Result<WithEtag<Image>>
pub async fn get_image(&self, fingerprint: &str) -> Result<WithEtag<Image>>
Fetches one image by fingerprint, along with its ETag for use as a
later If-Match precondition.
Sourcepub async fn create_image(&self, params: &Value) -> Result<Operation>
pub async fn create_image(&self, params: &Value) -> Result<Operation>
Always async: image import/creation is documented as a long-running operation (fetching/unpacking a source, which can be a remote URL or a large upload).
Sourcepub async fn update_image(
&self,
fingerprint: &str,
new_definition: &Value,
etag: Option<&str>,
) -> Result<Operation>
pub async fn update_image( &self, fingerprint: &str, new_definition: &Value, etag: Option<&str>, ) -> Result<Operation>
Full replacement update (PUT). etag, if provided, is sent as
If-Match for optimistic concurrency; a stale ETag surfaces as
Error::PreconditionFailed, not the generic Error::Api.
Sourcepub async fn update_image_guarded(
&self,
fetched: &WithEtag<Image>,
new_definition: &Value,
) -> Result<Operation>
pub async fn update_image_guarded( &self, fetched: &WithEtag<Image>, new_definition: &Value, ) -> Result<Operation>
Same as Client::update_image, but takes the WithEtag from a
prior Client::get_image call directly instead of a bare
etag: Option<&str> - see instances::Client::update_instance_guarded’s
doc comment for why this exists alongside the raw-etag version.
pub async fn delete_image(&self, fingerprint: &str) -> Result<Operation>
Source§impl Client
impl Client
Sourcepub async fn list_instances(&self, recursion: bool) -> Result<Vec<Value>>
pub async fn list_instances(&self, recursion: bool) -> Result<Vec<Value>>
Lists instances. recursion = true fetches every instance’s full
object (config/devices/state) in one call and can be expensive on
hosts with many instances; recursion = false returns lightweight
name/URL references only.
Sourcepub async fn get_instance(&self, name: &str) -> Result<WithEtag<Instance>>
pub async fn get_instance(&self, name: &str) -> Result<WithEtag<Instance>>
Fetches one instance by name, along with its ETag for use as a later
If-Match precondition.
Sourcepub async fn create_instance(
&self,
params: &CreateInstanceParams,
) -> Result<Operation>
pub async fn create_instance( &self, params: &CreateInstanceParams, ) -> Result<Operation>
Creates an instance. Always async, per Incus’s documented behavior for instance creation.
Sourcepub async fn update_instance(
&self,
name: &str,
new_definition: &Value,
etag: Option<&str>,
) -> Result<Operation>
pub async fn update_instance( &self, name: &str, new_definition: &Value, etag: Option<&str>, ) -> Result<Operation>
Full replacement update (PUT). etag, if provided, is sent as
If-Match for optimistic concurrency; a stale ETag surfaces as
Error::PreconditionFailed, not the generic Error::Api.
Sourcepub async fn update_instance_guarded(
&self,
fetched: &WithEtag<Instance>,
new_definition: &Value,
) -> Result<Operation>
pub async fn update_instance_guarded( &self, fetched: &WithEtag<Instance>, new_definition: &Value, ) -> Result<Operation>
Same as Client::update_instance, but takes the WithEtag from a
prior Client::get_instance call directly instead of a bare
etag: Option<&str> - the “pit of success” version of the
fetch-then-guarded-update workflow, since it makes threading a
genuinely-fetched ETag the natural path rather than something a
caller has to remember to do by hand. update_instance remains
available directly for callers with a legitimate reason to supply
their own ETag (e.g. one persisted from a previous process).
Sourcepub async fn patch_instance(
&self,
name: &str,
patch: &Value,
etag: Option<&str>,
) -> Result<Operation>
pub async fn patch_instance( &self, name: &str, patch: &Value, etag: Option<&str>, ) -> Result<Operation>
Partial update (PATCH) - use this instead of update_instance for
small config changes, to avoid a GET-then-PUT round trip.
Sourcepub async fn patch_instance_guarded(
&self,
fetched: &WithEtag<Instance>,
patch: &Value,
) -> Result<Operation>
pub async fn patch_instance_guarded( &self, fetched: &WithEtag<Instance>, patch: &Value, ) -> Result<Operation>
Same as Client::patch_instance, but takes the WithEtag from a
prior Client::get_instance call directly - see
Client::update_instance_guarded’s doc comment for why this
exists alongside the raw-etag version.
pub async fn delete_instance(&self, name: &str) -> Result<Operation>
pub async fn start_instance(&self, name: &str) -> Result<Operation>
pub async fn stop_instance(&self, name: &str) -> Result<Operation>
pub async fn restart_instance(&self, name: &str) -> Result<Operation>
pub async fn pause_instance(&self, name: &str) -> Result<Operation>
pub async fn list_snapshots( &self, instance_name: &str, recursion: bool, ) -> Result<Vec<Value>>
pub async fn create_snapshot( &self, instance_name: &str, snapshot_name: &str, ) -> Result<Operation>
pub async fn delete_snapshot( &self, instance_name: &str, snapshot_name: &str, ) -> Result<Operation>
Source§impl Client
impl Client
pub async fn list_networks(&self, recursion: bool) -> Result<Vec<Value>>
Sourcepub async fn get_network(&self, name: &str) -> Result<WithEtag<Network>>
pub async fn get_network(&self, name: &str) -> Result<WithEtag<Network>>
Fetches one network by name, along with its ETag for use as a later
If-Match precondition.
Sourcepub async fn create_network(&self, params: &Value) -> Result<()>
pub async fn create_network(&self, params: &Value) -> Result<()>
Creates a network. Synchronous: the network exists by the time this
returns, with no operation to wait on. Verified against
cmd/incusd/networks.go’s networksPost on the lxc/incus main
branch, which always returns response.SyncResponseLocation -
there is no code path that returns an async operation response, for
any network type/backend.
Sourcepub async fn update_network(
&self,
name: &str,
new_definition: &Value,
etag: Option<&str>,
) -> Result<()>
pub async fn update_network( &self, name: &str, new_definition: &Value, etag: Option<&str>, ) -> Result<()>
Full replacement update (PUT). etag, if provided, is sent as
If-Match for optimistic concurrency; a stale ETag surfaces as
Error::PreconditionFailed, not the generic Error::Api.
Synchronous, like Client::create_network - verified against
cmd/incusd/networks.go’s doNetworkUpdate, which always returns
response.EmptySyncResponse.
Sourcepub async fn update_network_guarded(
&self,
fetched: &WithEtag<Network>,
new_definition: &Value,
) -> Result<()>
pub async fn update_network_guarded( &self, fetched: &WithEtag<Network>, new_definition: &Value, ) -> Result<()>
Same as Client::update_network, but takes the WithEtag from a
prior Client::get_network call directly instead of a bare
etag: Option<&str> - see instances::Client::update_instance_guarded’s
doc comment for why this exists alongside the raw-etag version.
Sourcepub async fn delete_network(&self, name: &str) -> Result<()>
pub async fn delete_network(&self, name: &str) -> Result<()>
Synchronous - verified against cmd/incusd/networks.go’s
networkDelete, which always returns response.EmptySyncResponse.
Source§impl Client
impl Client
pub async fn list_projects(&self, recursion: bool) -> Result<Vec<Value>>
Sourcepub async fn get_project(&self, name: &str) -> Result<WithEtag<Project>>
pub async fn get_project(&self, name: &str) -> Result<WithEtag<Project>>
Fetches one project by name, along with its ETag for use as a later
If-Match precondition.
Sourcepub async fn create_project(&self, params: &Value) -> Result<()>
pub async fn create_project(&self, params: &Value) -> Result<()>
Creates a project. Synchronous: the project exists by the time this
returns, with no operation to wait on. Verified against
cmd/incusd/api_project.go’s projectsPost on the lxc/incus
main branch, which always returns response.SyncResponseLocation.
Sourcepub async fn update_project(
&self,
name: &str,
new_definition: &Value,
etag: Option<&str>,
) -> Result<()>
pub async fn update_project( &self, name: &str, new_definition: &Value, etag: Option<&str>, ) -> Result<()>
Full replacement update (PUT). etag, if provided, is sent as
If-Match for optimistic concurrency; a stale ETag surfaces as
Error::PreconditionFailed, not the generic Error::Api.
Synchronous, like Client::create_project - verified against
cmd/incusd/api_project.go’s projectChange, which always returns
response.EmptySyncResponse.
Sourcepub async fn update_project_guarded(
&self,
fetched: &WithEtag<Project>,
new_definition: &Value,
) -> Result<()>
pub async fn update_project_guarded( &self, fetched: &WithEtag<Project>, new_definition: &Value, ) -> Result<()>
Same as Client::update_project, but takes the WithEtag from a
prior Client::get_project call directly instead of a bare
etag: Option<&str> - see instances::Client::update_instance_guarded’s
doc comment for why this exists alongside the raw-etag version.
Sourcepub async fn delete_project(&self, name: &str) -> Result<()>
pub async fn delete_project(&self, name: &str) -> Result<()>
Synchronous - verified against cmd/incusd/api_project.go’s
projectDelete, which always returns response.EmptySyncResponse.
Source§impl Client
impl Client
pub async fn list_storage_pools(&self, recursion: bool) -> Result<Vec<Value>>
Sourcepub async fn get_storage_pool(
&self,
name: &str,
) -> Result<WithEtag<StoragePool>>
pub async fn get_storage_pool( &self, name: &str, ) -> Result<WithEtag<StoragePool>>
Fetches one storage pool by name, along with its ETag for use as a
later If-Match precondition.
Sourcepub async fn create_storage_pool(&self, params: &Value) -> Result<()>
pub async fn create_storage_pool(&self, params: &Value) -> Result<()>
Creates a storage pool. Synchronous: the pool exists by the time
this returns, with no operation to wait on. Verified against
cmd/incusd/storage_pools.go’s storagePoolsPost on the
lxc/incus main branch, which always returns
response.SyncResponseLocation.
Sourcepub async fn update_storage_pool(
&self,
name: &str,
new_definition: &Value,
etag: Option<&str>,
) -> Result<()>
pub async fn update_storage_pool( &self, name: &str, new_definition: &Value, etag: Option<&str>, ) -> Result<()>
Full replacement update (PUT). etag, if provided, is sent as
If-Match for optimistic concurrency; a stale ETag surfaces as
Error::PreconditionFailed, not the generic Error::Api.
Synchronous, like Client::create_storage_pool - verified against
cmd/incusd/storage_pools.go’s doStoragePoolUpdate, which always
returns response.EmptySyncResponse.
Sourcepub async fn update_storage_pool_guarded(
&self,
fetched: &WithEtag<StoragePool>,
new_definition: &Value,
) -> Result<()>
pub async fn update_storage_pool_guarded( &self, fetched: &WithEtag<StoragePool>, new_definition: &Value, ) -> Result<()>
Same as Client::update_storage_pool, but takes the WithEtag
from a prior Client::get_storage_pool call directly instead of a
bare etag: Option<&str> - see
instances::Client::update_instance_guarded’s doc comment for why
this exists alongside the raw-etag version.
Sourcepub async fn delete_storage_pool(&self, name: &str) -> Result<()>
pub async fn delete_storage_pool(&self, name: &str) -> Result<()>
Synchronous - verified against cmd/incusd/storage_pools.go’s
storagePoolDelete, which always returns response.EmptySyncResponse.
Sourcepub async fn list_storage_volumes(
&self,
pool_name: &str,
recursion: bool,
) -> Result<Vec<Value>>
pub async fn list_storage_volumes( &self, pool_name: &str, recursion: bool, ) -> Result<Vec<Value>>
Lists volumes within one pool. See the module doc comment for why there’s no “list all volumes across all pools” convenience method.
Per the Incus REST API, recursion = false returns an array of bare
URL strings (not typed volume objects), so - like every other
list_* method in this crate - this returns untyped
serde_json::Values rather than Vec<StorageVolume>. Use
recursion = true to get full volume objects in one call, or
get_storage_volume to fetch one volume’s full object by name.
Sourcepub async fn create_storage_volume(
&self,
pool_name: &str,
params: &Value,
) -> Result<Option<Operation>>
pub async fn create_storage_volume( &self, pool_name: &str, params: &Value, ) -> Result<Option<Operation>>
Creates a volume. Unlike every other create/update/delete method in
this crate, volume creation is genuinely conditional on the request
payload: creating a blank volume (params has no source.name) is
synchronous, but creating one by copying another volume (params
has a source.name) is asynchronous. Verified against
cmd/incusd/storage_volumes.go’s doVolumeCreateOrCopy on the
lxc/incus main branch: it returns response.EmptySyncResponse
when req.Source.Name == "", and operations.OperationResponse(op)
otherwise. Returns None for the synchronous case (nothing to wait
for) and Some(operation) for the asynchronous one.
Sourcepub async fn get_storage_volume(
&self,
pool_name: &str,
volume_type: &str,
volume_name: &str,
) -> Result<WithEtag<StorageVolume>>
pub async fn get_storage_volume( &self, pool_name: &str, volume_type: &str, volume_name: &str, ) -> Result<WithEtag<StorageVolume>>
Fetches one volume’s full object by pool, type, and name, along with
its ETag for use as a later If-Match precondition.
Sourcepub async fn update_storage_volume(
&self,
pool_name: &str,
volume_type: &str,
volume_name: &str,
new_definition: &Value,
etag: Option<&str>,
) -> Result<()>
pub async fn update_storage_volume( &self, pool_name: &str, volume_type: &str, volume_name: &str, new_definition: &Value, etag: Option<&str>, ) -> Result<()>
Full replacement update (PUT). etag, if provided, is sent as
If-Match for optimistic concurrency; a stale ETag surfaces as
Error::PreconditionFailed, not the generic Error::Api.
Synchronous - verified against cmd/incusd/storage_volumes.go’s
storagePoolVolumePut, which always returns
response.EmptySyncResponse.
Sourcepub async fn update_storage_volume_guarded(
&self,
pool_name: &str,
fetched: &WithEtag<StorageVolume>,
new_definition: &Value,
) -> Result<()>
pub async fn update_storage_volume_guarded( &self, pool_name: &str, fetched: &WithEtag<StorageVolume>, new_definition: &Value, ) -> Result<()>
Same as Client::update_storage_volume, but takes the WithEtag
from a prior Client::get_storage_volume call directly instead of
a bare etag: Option<&str> - volume_type and the volume’s own
name are derived from the fetched value; pool_name is still
required explicitly since a volume’s pool isn’t part of its own
returned object. See instances::Client::update_instance_guarded’s
doc comment for why this exists alongside the raw-etag version.
Source§impl Client
impl Client
Sourcepub fn new(config: ClientConfig) -> Self
pub fn new(config: ClientConfig) -> Self
Builds a client from config. No I/O happens here - connection
attempts happen lazily, once per request, when a method is called.
Source§impl Client
impl Client
Sourcepub async fn subscribe_events(&self, filter: EventFilter) -> Result<EventStream>
pub async fn subscribe_events(&self, filter: EventFilter) -> Result<EventStream>
Subscribes to Incus’s /1.0/events WebSocket stream, filtered per
filter. The connection is made over the same Unix socket as every
other request - see the module doc comment for why the resulting
stream is exposed directly rather than through a buffering channel.