X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=libvirt%2Flibvirt.mli;h=36cd1137b50b474e6498db8992225005cf106216;hb=21ac993da0a187821e812fe7b5b31a426121a546;hp=af372aff24ef4d80b1018e13e042bafb87be0c80;hpb=9b1c8e53eaa6fb79ee801e3014793618b977857d;p=ocaml-libvirt.git diff --git a/libvirt/libvirt.mli b/libvirt/libvirt.mli index af372af..36cd113 100644 --- a/libvirt/libvirt.mli +++ b/libvirt/libvirt.mli @@ -5,7 +5,8 @@ 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 @@ -60,47 +61,44 @@ v} {{: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; @@ -116,7 +114,7 @@ printf "hostname = %s\n%!" hostname; let uri = C.get_uri conn in printf "uri = %s\n%!" uri -v} +]} *) @@ -126,9 +124,8 @@ v} {3 General safety issues} Memory allocation / automatic garbage collection of all libvirt - objects should be completely safe (except in the specific - virterror case noted below). If you find any safety issues or if your - pure OCaml program ever segfaults, please contact the author. + objects should be completely safe. If you find any safety issues + or if your pure OCaml program ever segfaults, please contact the author. You can force a libvirt object to be freed early by calling the [close] function on the object. This shouldn't affect @@ -140,29 +137,25 @@ 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. - Virterror has a specific design error which means that the - objects embedded in a virterror exception message are only - valid as long as the connection handle is still open. This - is a design flaw in the C code of libvirt and we cannot fix - or work around it in the OCaml bindings. - {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} @@ -233,17 +226,19 @@ type ro = [`R] 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} *) @@ -299,7 +294,12 @@ sig 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. *) @@ -311,7 +311,12 @@ sig (** [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. *) @@ -379,6 +384,14 @@ sig (** [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. @@ -401,7 +414,7 @@ sig | 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 *) @@ -423,8 +436,22 @@ sig | 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; @@ -444,12 +471,15 @@ sig 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 @@ -474,16 +504,10 @@ sig (** 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 @@ -495,12 +519,8 @@ sig 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 @@ -525,8 +545,6 @@ sig (** 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 @@ -542,6 +560,10 @@ sig 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 @@ -566,14 +588,411 @@ sig val interface_stats : [>`R] t -> string -> interface_stats (** Returns network interface stats. *) + 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. + + 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. + + 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 : @@ -591,16 +1010,12 @@ sig (** 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 @@ -698,7 +1113,7 @@ sig (** 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 @@ -751,9 +1166,9 @@ sig 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. @@ -770,70 +1185,6 @@ sig 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 : @@ -938,14 +1289,11 @@ sig domain : domain; (** Origin of the error. *) message : string option; (** Human-readable message. *) level : level; (** Error or warning. *) - conn : ro Connect.t option; (** Associated connection. *) - dom : ro Domain.t option; (** Associated domain. *) str1 : string option; (** Informational string. *) str2 : string option; (** Informational string. *) str3 : string option; (** Informational string. *) int1 : int32; (** Informational integer. *) int2 : int32; (** Informational integer. *) - net : ro Network.t option; (** Associated network. *) } (** An error object. *) @@ -992,3 +1340,16 @@ exception Not_supported of string 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. +*)