This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
+ version 2 of the License, or (at your option) any later version,
+ with the OCaml linking exception described in ../COPYING.LIB.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
- Please see the file ../COPYING.LIB.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*)
(**
{{:http://libvirt.org/html/libvirt-libvirt.html}virConnect*, virDomain* and virNetwork* functions from libvirt}.
For brevity I usually rename these modules like this:
-{v
+{[
module C = Libvirt.Connect
module D = Libvirt.Domain
module N = Libvirt.Network
-v}
+]}
To get a connection handle, assuming a Xen hypervisor:
-{v
+{[
let name = "xen:///"
let conn = C.connect_readonly ~name ()
-v}
+]}
{3 Example: List running domains}
-{v
+{[
open Printf
-let n = C.num_of_domains conn in
-let ids = C.list_domains conn n in
-let domains = Array.map (D.lookup_by_id conn) ids in
-Array.iter (
+let domains = D.get_domains conn [D.ListActive] in
+List.iter (
fun dom ->
printf "%8d %s\n%!" (D.get_id dom) (D.get_name dom)
) domains;
-v}
+]}
{3 Example: List inactive domains}
-{v
-let n = C.num_of_defined_domains conn in
-let names = C.list_defined_domains conn n in
-Array.iter (
- fun name ->
- printf "inactive %s\n%!" name
-) names;
-v}
+{[
+let domains = D.get_domains conn [D.ListInactive] in
+List.iter (
+ fun dom ->
+ printf "inactive %s\n%!" (D.get_name dom)
+) domains;
+]}
{3 Example: Print node info}
-{v
+{[
let node_info = C.get_node_info conn in
printf "model = %s\n" node_info.C.model;
printf "memory = %Ld K\n" node_info.C.memory;
let uri = C.get_uri conn in
printf "uri = %s\n%!" uri
-v}
+]}
*)
Note that even though you hold open (eg) a domain object, that
doesn't mean that the domain (virtual machine) actually exists.
The domain could have been shut down or deleted by another user.
- Thus domain objects can through odd exceptions at any time.
+ Thus domain objects can raise odd exceptions at any time.
This is just the nature of virtualisation.
{3 Backwards and forwards compatibility}
- OCaml-libvirt is backwards and forwards compatible with
- any libvirt >= 0.2.1. One consequence of this is that
- your program can dynamically link to a {i newer} version of
- libvirt than it was compiled with, and it should still
- work.
+ OCaml-libvirt requires libvirt version 1.0.2 or later. Future
+ releases of OCaml-libvirt will use newer features of libvirt
+ and therefore will require later versions of libvirt. It is always
+ possible to dynamically link your application against a newer
+ libvirt than OCaml-libvirt was originally compiled against.
- When we link to an older version of libvirt.so, there may
- be missing functions. If ocaml-libvirt was compiled with
- gcc, then these are turned into OCaml {!Libvirt.Not_supported}
- exceptions.
+ {3 Get list of domains and domain infos}
- We don't support libvirt < 0.2.1, and never will so don't ask us.
+ This is a very common operation, and libvirt supports various
+ different methods to do it. We have hidden the complexity in a
+ flexible {!Libvirt.Domain.get_domains} and
+ {!Libvirt.Domain.get_domains_and_infos} calls which is easy to use and
+ automatically chooses the most efficient method depending on the
+ version of libvirt in use.
{3 Threads}
If you want to handle both read-write and read-only
connections at runtime, use a variant similar to this:
-{v
+{[
type conn_t =
| No_connection
| Read_only of Libvirt.ro Libvirt.Connect.t
| Read_write of Libvirt.rw Libvirt.Connect.t
-v}
- See also the source of [mlvirsh].
+]}
*)
-type ('a, 'b) job_t
-(** Forward definition of {!Job.t} to avoid recursive module dependencies. *)
+(** {3 Forward definitions}
+
+ These definitions are placed here to avoid the need to
+ use recursive module dependencies.
+*)
(** {3 Connections} *)
val list_domains : [>`R] t -> int -> int array
(** [list_domains conn max] returns the running domain IDs,
up to a maximum of [max] entries.
+
Call {!num_of_domains} first to get a value for [max].
+
+ See also:
+ {!Libvirt.Domain.get_domains},
+ {!Libvirt.Domain.get_domains_and_infos}.
*)
val num_of_domains : [>`R] t -> int
(** Returns the number of running domains. *)
(** [list_defined_domains conn max]
returns the names of the inactive domains, up to
a maximum of [max] entries.
+
Call {!num_of_defined_domains} first to get a value for [max].
+
+ See also:
+ {!Libvirt.Domain.get_domains},
+ {!Libvirt.Domain.get_domains_and_infos}.
*)
val num_of_networks : [>`R] t -> int
(** Returns the number of networks. *)
(** [cpu_usable cpumaps maplen vcpu cpu] checks returns true iff the
[cpu] is usable by [vcpu]. *)
+ val set_keep_alive : [>`R] t -> int -> int -> unit
+ (** [set_keep_alive conn interval count] starts sending keepalive
+ messages after [interval] seconds of inactivity and consider the
+ connection to be broken when no response is received after [count]
+ keepalive messages.
+ Note: the client has to implement and run an event loop to
+ be able to use keep-alive messages. *)
+
external const : [>`R] t -> ro t = "%identity"
(** [const conn] turns a read/write connection into a read-only
connection. Note that the opposite operation is impossible.
| InfoShutdown | InfoShutoff | InfoCrashed
type info = {
- state : state; (** running state *)
+ state : state; (** running state *)
max_mem : int64; (** maximum memory in kilobytes *)
memory : int64; (** memory used in kilobytes *)
nr_virt_cpu : int; (** number of virtual CPUs *)
| SchedFieldInt64 of int64 | SchedFieldUInt64 of int64
| SchedFieldFloat of float | SchedFieldBool of bool
+ type typed_param = string * typed_param_value
+ and typed_param_value =
+ | TypedFieldInt32 of int32 | TypedFieldUInt32 of int32
+ | TypedFieldInt64 of int64 | TypedFieldUInt64 of int64
+ | TypedFieldFloat of float | TypedFieldBool of bool
+ | TypedFieldString of string
+
type migrate_flag = Live
type memory_flag = Virtual
+ type list_flag =
+ | ListActive
+ | ListInactive
+ | ListAll
+
type block_stats = {
rd_req : int64;
rd_bytes : int64;
tx_drop : int64;
}
+ val max_peek : [>`R] t -> int
+ (** Maximum size supported by the {!block_peek} and {!memory_peek}
+ functions. If you want to peek more than this then you must
+ break your request into chunks. *)
+
val create_linux : [>`W] Connect.t -> xml -> rw t
(** Create a new guest domain (not necessarily a Linux one)
from the given XML.
*)
- val create_linux_job : [>`W] Connect.t -> xml -> ([`Domain], rw) job_t
- (** Asynchronous domain creation. *)
val lookup_by_id : 'a Connect.t -> int -> 'a t
(** Lookup a domain by ID. *)
val lookup_by_uuid : 'a Connect.t -> uuid -> 'a t
(** Resume a domain. *)
val save : [>`W] t -> filename -> unit
(** Suspend a domain, then save it to the file. *)
- val save_job : [>`W] t -> filename -> ([`Domain_nocreate], rw) job_t
- (** Asynchronous domain suspend. *)
val restore : [>`W] Connect.t -> filename -> unit
(** Restore a domain from a file. *)
- val restore_job : [>`W] Connect.t -> filename -> ([`Domain_nocreate], rw) job_t
- (** Asynchronous domain restore. *)
val core_dump : [>`W] t -> filename -> unit
(** Force a domain to core dump to the named file. *)
- val core_dump_job : [>`W] t -> filename -> ([`Domain_nocreate], rw) job_t
- (** Asynchronous core dump. *)
val shutdown : [>`W] t -> unit
(** Shutdown a domain. *)
val reboot : [>`W] t -> unit
val get_uuid_string : [>`R] t -> string
(** Get the domain UUID (as a printable string). *)
val get_id : [>`R] t -> int
- (** [getid dom] returns the ID of the domain.
-
- Do not call this on a defined but not running domain. Those
- domains don't have IDs, and you'll get an error here.
- *)
-
+ (** [get_id dom] returns the ID of the domain. In most cases
+ this returns [-1] if the domain is not running. *)
val get_os_type : [>`R] t -> string
(** Get the operating system type. *)
val get_max_memory : [>`R] t -> int64
(** Undefine a domain - removes its configuration. *)
val create : [>`W] t -> unit
(** Launch a defined (inactive) domain. *)
- val create_job : [>`W] t -> ([`Domain_nocreate], rw) job_t
- (** Asynchronous launch domain. *)
val get_autostart : [>`R] t -> bool
(** Get the autostart flag for a domain. *)
val set_autostart : [>`W] t -> bool -> unit
for a domain. See the libvirt documentation for details
of the array and bitmap returned from this function.
*)
+ val get_cpu_stats : [>`R] t -> typed_param list array
+ (** [get_pcpu_stats dom] returns the physical CPU stats
+ for a domain. See the libvirt documentation for details.
+ *)
val get_max_vcpus : [>`R] t -> int
(** Returns the maximum number of vCPUs supported for this domain. *)
val attach_device : [>`W] t -> xml -> unit
val interface_stats : [>`R] t -> string -> interface_stats
(** Returns network interface stats. *)
- val block_peek : [>`R] t -> string -> int64 -> int -> string -> int -> unit
+ val block_peek : [>`W] t -> string -> int64 -> int -> string -> int -> unit
(** [block_peek dom path offset size buf boff] reads [size] bytes at
[offset] in the domain's [path] block device.
If successful then the data is written into [buf] starting
- at offset [boff], for [size] bytes. *)
- val memory_peek : [>`R] t -> memory_flag list -> int64 -> int ->
+ at offset [boff], for [size] bytes.
+
+ See also {!max_peek}. *)
+ val memory_peek : [>`W] t -> memory_flag list -> int64 -> int ->
string -> int -> unit
(** [memory_peek dom Virtual offset size] reads [size] bytes
at [offset] in the domain's virtual memory.
If successful then the data is written into [buf] starting
- at offset [boff], for [size] bytes. *)
+ at offset [boff], for [size] bytes.
+
+ See also {!max_peek}. *)
external const : [>`R] t -> ro t = "%identity"
(** [const dom] turns a read/write domain handle into a read-only
domain handle. Note that the opposite operation is impossible.
*)
+
+ val get_domains : ([>`R] as 'a) Connect.t -> list_flag list -> 'a t list
+ (** Get the active and/or inactive domains using the most
+ efficient method available.
+
+ See also:
+ {!get_domains_and_infos},
+ {!Connect.list_domains},
+ {!Connect.list_defined_domains}.
+ *)
+
+ val get_domains_and_infos : ([>`R] as 'a) Connect.t -> list_flag list ->
+ ('a t * info) list
+ (** This gets the active and/or inactive domains and the
+ domain info for each one using the most efficient
+ method available.
+
+ See also:
+ {!get_domains},
+ {!Connect.list_domains},
+ {!Connect.list_defined_domains},
+ {!get_info}.
+ *)
+
end
(** Module dealing with domains. [Domain.t] is the
domain object. *)
+module Event :
+sig
+
+ module Defined : sig
+ type t = [
+ | `Added (** Newly created config file *)
+ | `Updated (** Changed config file *)
+ | `Unknown of int
+ ]
+
+ val to_string: t -> string
+ end
+
+ module Undefined : sig
+ type t = [
+ | `Removed (** Deleted the config file *)
+ | `Unknown of int
+ ]
+
+ val to_string: t -> string
+ end
+
+ module Started : sig
+ type t = [
+ | `Booted (** Normal startup from boot *)
+ | `Migrated (** Incoming migration from another host *)
+ | `Restored (** Restored from a state file *)
+ | `FromSnapshot (** Restored from snapshot *)
+ | `Wakeup (** Started due to wakeup event *)
+ | `Unknown of int
+ ]
+
+ val to_string: t -> string
+ end
+
+ module Suspended : sig
+ type t = [
+ | `Paused (** Normal suspend due to admin pause *)
+ | `Migrated (** Suspended for offline migration *)
+ | `IOError (** Suspended due to a disk I/O error *)
+ | `Watchdog (** Suspended due to a watchdog firing *)
+ | `Restored (** Restored from paused state file *)
+ | `FromSnapshot (** Restored from paused snapshot *)
+ | `APIError (** suspended after failure during libvirt API call *)
+ | `Unknown of int
+ ]
+
+ val to_string: t -> string
+ end
+
+ module Resumed : sig
+ type t = [
+ | `Unpaused (** Normal resume due to admin unpause *)
+ | `Migrated (** Resumed for completion of migration *)
+ | `FromSnapshot (** Resumed from snapshot *)
+ | `Unknown of int
+ ]
+
+ val to_string: t -> string
+ end
+
+ module Stopped : sig
+ type t = [
+ | `Shutdown (** Normal shutdown *)
+ | `Destroyed (** Forced poweroff from host *)
+ | `Crashed (** Guest crashed *)
+ | `Migrated (** Migrated off to another host *)
+ | `Saved (** Saved to a state file *)
+ | `Failed (** Host emulator/mgmt failed *)
+ | `FromSnapshot (** offline snapshot loaded *)
+ | `Unknown of int
+ ]
+
+ val to_string: t -> string
+ end
+
+ module PM_suspended : sig
+ type t = [
+ | `Memory (** Guest was PM suspended to memory *)
+ | `Disk (** Guest was PM suspended to disk *)
+ | `Unknown of int
+ ]
+
+ val to_string: t -> string
+ end
+
+ module Lifecycle : sig
+ type t = [
+ | `Defined of Defined.t
+ | `Undefined of Undefined.t
+ | `Started of Started.t
+ | `Suspended of Suspended.t
+ | `Resumed of Resumed.t
+ | `Stopped of Stopped.t
+ | `Shutdown (* no detail defined yet *)
+ | `PMSuspended of PM_suspended.t
+ | `Unknown of int
+ ]
+
+ val to_string: t -> string
+ end
+
+ module Reboot : sig
+ type t = unit
+
+ val to_string: t -> string
+ end
+
+ module Rtc_change : sig
+ type t = int64
+
+ val to_string: t -> string
+ end
+
+ module Watchdog : sig
+ type t = [
+ | `None (** No action, watchdog ignored *)
+ | `Pause (** Guest CPUs are paused *)
+ | `Reset (** Guest CPUs are reset *)
+ | `Poweroff (** Guest is forcably powered off *)
+ | `Shutdown (** Guest is requested to gracefully shutdown *)
+ | `Debug (** No action, a debug message logged *)
+ | `Unknown of int (** newer libvirt *)
+ ]
+
+ val to_string: t -> string
+ end
+
+ module Io_error : sig
+ (** Represents both IOError and IOErrorReason *)
+ type action = [
+ | `None (** No action, IO error ignored *)
+ | `Pause (** Guest CPUs are paused *)
+ | `Report (** IO error reported to guest OS *)
+ | `Unknown of int (** newer libvirt *)
+ ]
+
+ type t = {
+ src_path: string option; (** The host file on which the I/O error occurred *)
+ dev_alias: string option; (** The guest device alias associated with the path *)
+ action: action; (** The action that is to be taken due to the IO error *)
+ reason: string option; (** The cause of the IO error *)
+ }
+
+ val to_string: t -> string
+ end
+
+ module Graphics_address : sig
+ type family = [
+ | `Ipv4 (** IPv4 address *)
+ | `Ipv6 (** IPv6 address *)
+ | `Unix (** UNIX socket path *)
+ | `Unknown of int (** newer libvirt *)
+ ]
+
+ type t = {
+ family: family; (** Address family *)
+ node: string option; (** Address of node (eg IP address, or UNIX path *)
+ service: string option; (** Service name/number (eg TCP port, or NULL) *)
+ }
+
+ val to_string: t -> string
+ end
+
+ module Graphics_subject : sig
+ type identity = {
+ ty: string option; (** Type of identity *)
+ name: string option; (** Identity value *)
+ }
+
+ type t = identity list
+
+ val to_string: t -> string
+ end
+
+ module Graphics : sig
+ type phase = [
+ | `Connect (** Initial socket connection established *)
+ | `Initialize (** Authentication & setup completed *)
+ | `Disconnect (** Final socket disconnection *)
+ | `Unknown of int (** newer libvirt *)
+ ]
+
+ type t = {
+ phase: phase; (** the phase of the connection *)
+ local: Graphics_address.t; (** the local server address *)
+ remote: Graphics_address.t; (** the remote client address *)
+ auth_scheme: string option; (** the authentication scheme activated *)
+ subject: Graphics_subject.t; (** the authenticated subject (user) *)
+ }
+
+ val to_string: t -> string
+ end
+
+ module Control_error : sig
+ type t = unit
+
+ val to_string: t -> string
+ end
+
+ module Block_job : sig
+ type ty = [
+ | `KnownUnknown (** explicitly named UNKNOWN in the spec *)
+ | `Pull
+ | `Copy
+ | `Commit
+ | `Unknown of int
+ ]
+
+ type status = [
+ | `Completed
+ | `Failed
+ | `Cancelled
+ | `Ready
+ | `Unknown of int
+ ]
+
+ type t = {
+ disk: string option; (** fully-qualified name of the affected disk *)
+ ty: ty; (** type of block job *)
+ status: status; (** final status of the operation *)
+ }
+
+ val to_string: t -> string
+ end
+
+ module Disk_change : sig
+ type reason = [
+ | `MissingOnStart
+ | `Unknown of int
+ ]
+
+ type t = {
+ old_src_path: string option; (** old source path *)
+ new_src_path: string option; (** new source path *)
+ dev_alias: string option; (** device alias name *)
+ reason: reason; (** reason why this callback was called *)
+ }
+
+ val to_string: t -> string
+ end
+
+ module Tray_change : sig
+ type reason = [
+ | `Open
+ | `Close
+ | `Unknown of int
+ ]
+
+ type t = {
+ dev_alias: string option; (** device alias *)
+ reason: reason; (** why the tray status was changed *)
+ }
+
+ val to_string: t -> string
+ end
+
+ module PM_wakeup : sig
+ type reason = [
+ | `Unknown of int
+ ]
+
+ type t = reason
+
+ val to_string: t -> string
+ end
+
+ module PM_suspend : sig
+ type reason = [
+ | `Unknown of int
+ ]
+
+ type t = reason
+
+ val to_string: t -> string
+ end
+
+ module Balloon_change : sig
+ type t = int64
+
+ val to_string: t -> string
+ end
+
+ module PM_suspend_disk : sig
+ type reason = [
+ | `Unknown of int
+ ]
+
+ type t = reason
+
+ val to_string: t -> string
+ end
+
+
+ type callback =
+ | Lifecycle of ([`R] Domain.t -> Lifecycle.t -> unit)
+ | Reboot of ([`R] Domain.t -> Reboot.t -> unit)
+ | RtcChange of ([`R] Domain.t -> Rtc_change.t -> unit)
+ | Watchdog of ([`R] Domain.t -> Watchdog.t -> unit)
+ | IOError of ([`R] Domain.t -> Io_error.t -> unit)
+ | Graphics of ([`R] Domain.t -> Graphics.t -> unit)
+ | IOErrorReason of ([`R] Domain.t -> Io_error.t -> unit)
+ | ControlError of ([`R] Domain.t -> Control_error.t -> unit)
+ | BlockJob of ([`R] Domain.t -> Block_job.t -> unit)
+ | DiskChange of ([`R] Domain.t -> Disk_change.t -> unit)
+ | TrayChange of ([`R] Domain.t -> Tray_change.t -> unit)
+ | PMWakeUp of ([`R] Domain.t -> PM_wakeup.t -> unit)
+ | PMSuspend of ([`R] Domain.t -> PM_suspend.t -> unit)
+ | BalloonChange of ([`R] Domain.t -> Balloon_change.t -> unit)
+ | PMSuspendDisk of ([`R] Domain.t -> PM_suspend_disk.t -> unit)
+
+ (** type of a registered call back function *)
+
+ val register_default_impl : unit -> unit
+ (** Registers the default event loop based on poll(). This
+ must be done before connections are opened.
+
+ Once registered call run_default_impl in a loop. *)
+
+ val run_default_impl : unit -> unit
+ (** Runs one iteration of the event loop. Applications will
+ generally want to have a thread which invokes this in an
+ infinite loop. *)
+
+ type callback_id
+ (** an individual event registration *)
+
+ val register_any : 'a Connect.t -> ?dom:'a Domain.t -> callback -> callback_id
+ (** [register_any con ?dom callback] registers [callback]
+ to receive notification of arbitrary domain events. Return
+ a registration id which can be used in [deregister_any].
+
+ If [?dom] is None then register for this kind of event on
+ all domains. If [dom] is [Some d] then register for this
+ kind of event only on [d].
+ *)
+
+ val deregister_any : 'a Connect.t -> callback_id -> unit
+ (** [deregister_any con id] deregisters the previously registered
+ callback with id [id]. *)
+
+ type timer_id
+ (** an individual timer event *)
+
+ val add_timeout : 'a Connect.t -> int -> (unit -> unit) -> timer_id
+ (** [add_timeout con ms cb] registers [cb] as a timeout callback
+ which will be called every [ms] milliseconds *)
+
+ val remove_timeout : 'a Connect.t -> timer_id -> unit
+ (** [remove_timeout con t] deregisters timeout callback [t]. *)
+
+end
+ (** Module dealing with events generated by domain
+ state changes. *)
+
(** {3 Networks} *)
module Network :
(** Lookup a network by UUID string. *)
val create_xml : [>`W] Connect.t -> xml -> rw t
(** Create a network. *)
- val create_xml_job : [>`W] Connect.t -> xml -> ([`Network], rw) job_t
- (** Asynchronous create network. *)
val define_xml : [>`W] Connect.t -> xml -> rw t
(** Define but don't activate a network. *)
val undefine : [>`W] t -> unit
(** Undefine configuration of a network. *)
val create : [>`W] t -> unit
(** Start up a defined (inactive) network. *)
- val create_job : [>`W] t -> ([`Network_nocreate], rw) job_t
- (** Asynchronous start network. *)
val destroy : [>`W] t -> unit
(** Destroy a network. *)
val free : [>`R] t -> unit
(** Get the XML description. *)
val get_autostart : [`R] t -> bool
(** Get the autostart flag for the storage pool. *)
- val set_autostart : [`W] t -> bool -> unit
+ val set_autostart : [>`W] t -> bool -> unit
(** Set the autostart flag for the storage pool. *)
val num_of_volumes : [`R] t -> int
val get_xml_desc : [`R] t -> xml
(** Get the XML description. *)
- val create_xml : [`W] Pool.t -> xml -> unit
+ val create_xml : [>`W] Pool.t -> xml -> unit
(** Create a storage volume. *)
- val delete : [`W] t -> unit
+ val delete : [>`W] t -> vol_delete_flags -> unit
(** Delete a storage volume. *)
val free : [>`R] t -> unit
(** Free a storage volume object in memory.
end
(** Module dealing with storage volumes. *)
-(** {3 Jobs and asynchronous processing} *)
-
-module Job :
-sig
- type ('jobclass, 'rw) t = ('jobclass, 'rw) job_t
- (** A background asynchronous job.
-
- Jobs represent a pending operation such as domain creation.
- The possible types for a job are:
-
-{v
-(`Domain, `W) Job.t Job creating a new domain
-(`Domain_nocreate, `W) Job.t Job acting on an existing domain
-(`Network, `W) Job.t Job creating a new network
-(`Network_nocreate, `W) Job.t Job acting on an existing network
-v}
- *)
-
- type job_type = Bounded | Unbounded
- (** A Bounded job is one where we can estimate time to completion. *)
-
- type job_state = Running | Complete | Failed | Cancelled
- (** State of the job. *)
-
- type job_info = {
- typ : job_type; (** Job type (Bounded, Unbounded) *)
- state : job_state; (** Job state (Running, etc.) *)
- running_time : int; (** Actual running time (seconds) *)
- (** The following fields are only available in Bounded jobs: *)
- remaining_time : int; (** Estimated time left (seconds) *)
- percent_complete : int (** Estimated percent complete *)
- }
-
- val get_info : ('a,'b) t -> job_info
- (** Get information and status about the job. *)
-
- val get_domain : ([`Domain], 'a) t -> 'a Domain.t
- (** Get the completed domain from a job.
-
- You should only call it on a job in state Complete. *)
-
- val get_network : ([`Network], 'a) t -> 'a Network.t
- (** Get the completed network from a job.
-
- You should only call it on a job in state Complete. *)
-
- val cancel : ('a,'b) t -> unit
- (** Cancel a job. *)
-
- val free : ('a, [>`R]) t -> unit
- (** Free a job object in memory.
-
- The job object is automatically freed if it is garbage
- collected. This function just forces it to be freed right
- away.
- *)
-
- external const : ('a, [>`R]) t -> ('a, ro) t = "%identity"
- (** [const conn] turns a read/write job into a read-only
- job. Note that the opposite operation is impossible.
- *)
-end
- (** Module dealing with asynchronous jobs. *)
-
(** {3 Error handling and exceptions} *)
module Virterror :
See also {{:http://libvirt.org/hvsupport.html}http://libvirt.org/hvsupport.html}
*)
+(** {3 Utility functions} *)
+
+val map_ignore_errors : ('a -> 'b) -> 'a list -> 'b list
+(** [map_ignore_errors f xs] calls function [f] for each element of [xs].
+
+ This is just like [List.map] except that if [f x] throws a
+ {!Virterror.t} exception, the error is ignored and [f x]
+ is not returned in the final list.
+
+ This function is primarily useful when dealing with domains which
+ might 'disappear' asynchronously from the currently running
+ program.
+*)