Current section
Files
Jump to
Current section
Files
lib/ex_incus/operation.ex
defmodule ExIncus.Operation do
@moduledoc """
A background operation.
Most state-changing Incus calls (create/delete instance, state changes,
exec, ...) are asynchronous: the server replies immediately with an
operation that runs in the background. Functions in this library wait for
those operations to finish by default (pass `wait: false` to get the
running operation back instead) - see `ExIncus.Operations.wait/3`.
## Status codes
* `100..199` - in progress (100 created, 101 started, 103 running, ...)
* `200` - success
* `400` - failure (see `:err`)
* `401` - cancelled
"""
defstruct [
:id,
:class,
:description,
:created_at,
:updated_at,
:status,
:status_code,
:resources,
:metadata,
:may_cancel,
:err,
:location
]
@type t :: %__MODULE__{
id: String.t() | nil,
class: String.t() | nil,
description: String.t() | nil,
created_at: String.t() | nil,
updated_at: String.t() | nil,
status: String.t() | nil,
status_code: integer() | nil,
resources: map() | nil,
metadata: map() | nil,
may_cancel: boolean() | nil,
err: String.t() | nil,
location: String.t() | nil
}
@doc false
def from_response(%{"metadata" => metadata} = body) when is_map(metadata) do
%{from_map(metadata) | location: body["operation"]}
end
def from_response(%{"operation" => location}) do
%__MODULE__{location: location, id: id_from_path(location)}
end
@doc false
def from_map(map) when is_map(map) do
%__MODULE__{
id: map["id"],
class: map["class"],
description: map["description"],
created_at: map["created_at"],
updated_at: map["updated_at"],
status: map["status"],
status_code: map["status_code"],
resources: map["resources"],
metadata: map["metadata"],
may_cancel: map["may_cancel"],
err: map["err"]
}
end
@doc """
Extracts the operation UUID from an operation struct, a UUID string or an
API path such as `"/1.0/operations/<uuid>"`.
"""
@spec id(t() | String.t()) :: String.t()
def id(%__MODULE__{id: id}) when is_binary(id), do: id
def id(%__MODULE__{location: location}) when is_binary(location), do: id_from_path(location)
def id(id) when is_binary(id), do: id_from_path(id)
@doc "Returns true if the operation completed successfully."
@spec success?(t()) :: boolean()
def success?(%__MODULE__{status_code: 200}), do: true
def success?(%__MODULE__{}), do: false
@doc "Returns true if the operation is still in progress."
@spec running?(t()) :: boolean()
def running?(%__MODULE__{status_code: code}) when code in 100..199, do: true
def running?(%__MODULE__{}), do: false
defp id_from_path(path) do
path
|> String.trim_leading("/1.0/operations/")
|> String.split("?")
|> hd()
end
end