Add support for virConnectListAllDomains call.
[ocaml-libvirt.git] / libvirt / libvirt.ml
1 (* OCaml bindings for libvirt.
2    (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
3    http://libvirt.org/
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version,
9    with the OCaml linking exception described in ../COPYING.LIB.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this library; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 *)
20
21 type uuid = string
22
23 type xml = string
24
25 type filename = string
26
27 external get_version : ?driver:string -> unit -> int * int = "ocaml_libvirt_get_version"
28
29 let uuid_length = 16
30 let uuid_string_length = 36
31
32 (* http://caml.inria.fr/pub/ml-archives/caml-list/2004/07/80683af867cce6bf8fff273973f70c95.en.html *)
33 type rw = [`R|`W]
34 type ro = [`R]
35
36 type ('a, 'b) job_t
37
38 module Connect =
39 struct
40   type 'rw t
41
42   type node_info = {
43     model : string;
44     memory : int64;
45     cpus : int;
46     mhz : int;
47     nodes : int;
48     sockets : int;
49     cores : int;
50     threads : int;
51   }
52
53   type list_flag =
54     | ListNoState | ListRunning | ListBlocked
55     | ListPaused | ListShutdown | ListShutoff | ListCrashed
56     | ListActive
57     | ListInactive
58     | ListAll
59
60   external connect : ?name:string -> unit -> rw t = "ocaml_libvirt_connect_open"
61   external connect_readonly : ?name:string -> unit -> ro t = "ocaml_libvirt_connect_open_readonly"
62   external close : [>`R] t -> unit = "ocaml_libvirt_connect_close"
63   external get_type : [>`R] t -> string = "ocaml_libvirt_connect_get_type"
64   external get_version : [>`R] t -> int = "ocaml_libvirt_connect_get_version"
65   external get_hostname : [>`R] t -> string = "ocaml_libvirt_connect_get_hostname"
66   external get_uri : [>`R] t -> string = "ocaml_libvirt_connect_get_uri"
67   external get_max_vcpus : [>`R] t -> ?type_:string -> unit -> int = "ocaml_libvirt_connect_get_max_vcpus"
68   external list_domains : [>`R] t -> int -> int array = "ocaml_libvirt_connect_list_domains"
69   external num_of_domains : [>`R] t -> int = "ocaml_libvirt_connect_num_of_domains"
70   external get_capabilities : [>`R] t -> xml = "ocaml_libvirt_connect_get_capabilities"
71   external num_of_defined_domains : [>`R] t -> int = "ocaml_libvirt_connect_num_of_defined_domains"
72   external list_defined_domains : [>`R] t -> int -> string array = "ocaml_libvirt_connect_list_defined_domains"
73   external num_of_networks : [>`R] t -> int = "ocaml_libvirt_connect_num_of_networks"
74   external list_networks : [>`R] t -> int -> string array = "ocaml_libvirt_connect_list_networks"
75   external num_of_defined_networks : [>`R] t -> int = "ocaml_libvirt_connect_num_of_defined_networks"
76   external list_defined_networks : [>`R] t -> int -> string array = "ocaml_libvirt_connect_list_defined_networks"
77   external num_of_pools : [>`R] t -> int = "ocaml_libvirt_connect_num_of_storage_pools"
78   external list_pools : [>`R] t -> int -> string array = "ocaml_libvirt_connect_list_storage_pools"
79   external num_of_defined_pools : [>`R] t -> int = "ocaml_libvirt_connect_num_of_defined_storage_pools"
80   external list_defined_pools : [>`R] t -> int -> string array = "ocaml_libvirt_connect_list_defined_storage_pools"
81
82   external get_node_info : [>`R] t -> node_info = "ocaml_libvirt_connect_get_node_info"
83   external node_get_free_memory : [> `R] t -> int64 = "ocaml_libvirt_connect_node_get_free_memory"
84   external node_get_cells_free_memory : [> `R] t -> int -> int -> int64 array = "ocaml_libvirt_connect_node_get_cells_free_memory"
85
86   (* See VIR_NODEINFO_MAXCPUS macro defined in <libvirt.h>. *)
87   let maxcpus_of_node_info { nodes = nodes; sockets = sockets;
88                              cores = cores; threads = threads } =
89     nodes * sockets * cores * threads
90
91   (* See VIR_CPU_MAPLEN macro defined in <libvirt.h>. *)
92   let cpumaplen nr_cpus =
93     (nr_cpus + 7) / 8
94
95   (* See VIR_USE_CPU, VIR_UNUSE_CPU, VIR_CPU_USABLE macros defined in <libvirt.h>. *)
96   let use_cpu cpumap cpu =
97     cpumap.[cpu/8] <-
98       Char.chr (Char.code cpumap.[cpu/8] lor (1 lsl (cpu mod 8)))
99   let unuse_cpu cpumap cpu =
100     cpumap.[cpu/8] <-
101       Char.chr (Char.code cpumap.[cpu/8] land (lnot (1 lsl (cpu mod 8))))
102   let cpu_usable cpumaps maplen vcpu cpu =
103     Char.code cpumaps.[vcpu*maplen + cpu/8] land (1 lsl (cpu mod 8)) <> 0
104
105   external const : [>`R] t -> ro t = "%identity"
106 end
107
108 module Domain =
109 struct
110   type 'rw t
111
112   type state =
113     | InfoNoState | InfoRunning | InfoBlocked | InfoPaused
114     | InfoShutdown | InfoShutoff | InfoCrashed
115
116   type info = {
117     state : state;
118     max_mem : int64;
119     memory : int64;
120     nr_virt_cpu : int;
121     cpu_time : int64;
122   }
123
124   type vcpu_state = VcpuOffline | VcpuRunning | VcpuBlocked
125
126   type vcpu_info = {
127     number : int;
128     vcpu_state : vcpu_state;
129     vcpu_time : int64;
130     cpu : int;
131   }
132
133   type sched_param = string * sched_param_value
134   and sched_param_value =
135     | SchedFieldInt32 of int32 | SchedFieldUInt32 of int32
136     | SchedFieldInt64 of int64 | SchedFieldUInt64 of int64
137     | SchedFieldFloat of float | SchedFieldBool of bool
138
139   type migrate_flag = Live
140
141   type memory_flag = Virtual
142
143   type list_flag =
144     | ListNoState | ListRunning | ListBlocked
145     | ListPaused | ListShutdown | ListShutoff | ListCrashed
146     | ListActive
147     | ListInactive
148     | ListAll
149
150   type block_stats = {
151     rd_req : int64;
152     rd_bytes : int64;
153     wr_req : int64;
154     wr_bytes : int64;
155     errs : int64;
156   }
157
158   type interface_stats = {
159     rx_bytes : int64;
160     rx_packets : int64;
161     rx_errs : int64;
162     rx_drop : int64;
163     tx_bytes : int64;
164     tx_packets : int64;
165     tx_errs : int64;
166     tx_drop : int64;
167   }
168
169   (* The maximum size for Domain.memory_peek and Domain.block_peek
170    * supported by libvirt.  This may change with different versions
171    * of libvirt in the future, hence it's a function.
172    *)
173   let max_peek _ = 65536
174
175   external list_all_domains : 'a Connect.t -> ?want_info:bool -> list_flag list -> 'a t array * info array = "ocaml_libvirt_connect_list_all_domains"
176
177   external create_linux : [>`W] Connect.t -> xml -> rw t = "ocaml_libvirt_domain_create_linux"
178   external create_linux_job : [>`W] Connect.t -> xml -> ([`Domain], rw) job_t = "ocaml_libvirt_domain_create_linux_job"
179   external lookup_by_id : 'a Connect.t -> int -> 'a t = "ocaml_libvirt_domain_lookup_by_id"
180   external lookup_by_uuid : 'a Connect.t -> uuid -> 'a t = "ocaml_libvirt_domain_lookup_by_uuid"
181   external lookup_by_uuid_string : 'a Connect.t -> string -> 'a t = "ocaml_libvirt_domain_lookup_by_uuid_string"
182   external lookup_by_name : 'a Connect.t -> string -> 'a t = "ocaml_libvirt_domain_lookup_by_name"
183   external destroy : [>`W] t -> unit = "ocaml_libvirt_domain_destroy"
184   external free : [>`R] t -> unit = "ocaml_libvirt_domain_free"
185   external suspend : [>`W] t -> unit = "ocaml_libvirt_domain_suspend"
186   external resume : [>`W] t -> unit = "ocaml_libvirt_domain_resume"
187   external save : [>`W] t -> filename -> unit = "ocaml_libvirt_domain_save"
188   external save_job : [>`W] t -> filename -> ([`Domain_nocreate], rw) job_t = "ocaml_libvirt_domain_save_job"
189   external restore : [>`W] Connect.t -> filename -> unit = "ocaml_libvirt_domain_restore"
190   external restore_job : [>`W] Connect.t -> filename -> ([`Domain_nocreate], rw) job_t = "ocaml_libvirt_domain_restore_job"
191   external core_dump : [>`W] t -> filename -> unit = "ocaml_libvirt_domain_core_dump"
192   external core_dump_job : [>`W] t -> filename -> ([`Domain_nocreate], rw) job_t = "ocaml_libvirt_domain_core_dump_job"
193   external shutdown : [>`W] t -> unit = "ocaml_libvirt_domain_shutdown"
194   external reboot : [>`W] t -> unit = "ocaml_libvirt_domain_reboot"
195   external get_name : [>`R] t -> string = "ocaml_libvirt_domain_get_name"
196   external get_uuid : [>`R] t -> uuid = "ocaml_libvirt_domain_get_uuid"
197   external get_uuid_string : [>`R] t -> string = "ocaml_libvirt_domain_get_uuid_string"
198   external get_id : [>`R] t -> int = "ocaml_libvirt_domain_get_id"
199   external get_os_type : [>`R] t -> string = "ocaml_libvirt_domain_get_os_type"
200   external get_max_memory : [>`R] t -> int64 = "ocaml_libvirt_domain_get_max_memory"
201   external set_max_memory : [>`W] t -> int64 -> unit = "ocaml_libvirt_domain_set_max_memory"
202   external set_memory : [>`W] t -> int64 -> unit = "ocaml_libvirt_domain_set_memory"
203   external get_info : [>`R] t -> info = "ocaml_libvirt_domain_get_info"
204   external get_xml_desc : [>`R] t -> xml = "ocaml_libvirt_domain_get_xml_desc"
205   external get_scheduler_type : [>`R] t -> string * int = "ocaml_libvirt_domain_get_scheduler_type"
206   external get_scheduler_parameters : [>`R] t -> int -> sched_param array = "ocaml_libvirt_domain_get_scheduler_parameters"
207   external set_scheduler_parameters : [>`W] t -> sched_param array -> unit = "ocaml_libvirt_domain_set_scheduler_parameters"
208   external define_xml : [>`W] Connect.t -> xml -> rw t = "ocaml_libvirt_domain_define_xml"
209   external undefine : [>`W] t -> unit = "ocaml_libvirt_domain_undefine"
210   external create : [>`W] t -> unit = "ocaml_libvirt_domain_create"
211   external create_job : [>`W] t -> ([`Domain_nocreate], rw) job_t = "ocaml_libvirt_domain_create_job"
212   external get_autostart : [>`R] t -> bool = "ocaml_libvirt_domain_get_autostart"
213   external set_autostart : [>`W] t -> bool -> unit = "ocaml_libvirt_domain_set_autostart"
214   external set_vcpus : [>`W] t -> int -> unit = "ocaml_libvirt_domain_set_vcpus"
215   external pin_vcpu : [>`W] t -> int -> string -> unit = "ocaml_libvirt_domain_pin_vcpu"
216   external get_vcpus : [>`R] t -> int -> int -> int * vcpu_info array * string = "ocaml_libvirt_domain_get_vcpus"
217   external get_max_vcpus : [>`R] t -> int = "ocaml_libvirt_domain_get_max_vcpus"
218   external attach_device : [>`W] t -> xml -> unit = "ocaml_libvirt_domain_attach_device"
219   external detach_device : [>`W] t -> xml -> unit = "ocaml_libvirt_domain_detach_device"
220   external migrate : [>`W] t -> [>`W] Connect.t -> migrate_flag list -> ?dname:string -> ?uri:string -> ?bandwidth:int -> unit -> rw t = "ocaml_libvirt_domain_migrate_bytecode" "ocaml_libvirt_domain_migrate_native"
221   external block_stats : [>`R] t -> string -> block_stats = "ocaml_libvirt_domain_block_stats"
222   external interface_stats : [>`R] t -> string -> interface_stats = "ocaml_libvirt_domain_interface_stats"
223   external block_peek : [>`R] t -> string -> int64 -> int -> string -> int -> unit = "ocaml_libvirt_domain_block_peek_bytecode" "ocaml_libvirt_domain_block_peek_native"
224   external memory_peek : [>`R] t -> memory_flag list -> int64 -> int -> string -> int -> unit = "ocaml_libvirt_domain_memory_peek_bytecode" "ocaml_libvirt_domain_memory_peek_native"
225
226   external const : [>`R] t -> ro t = "%identity"
227 end
228
229 module Network =
230 struct
231   type 'rw t
232
233   external lookup_by_name : 'a Connect.t -> string -> 'a t = "ocaml_libvirt_network_lookup_by_name"
234   external lookup_by_uuid : 'a Connect.t -> uuid -> 'a t = "ocaml_libvirt_network_lookup_by_uuid"
235   external lookup_by_uuid_string : 'a Connect.t -> string -> 'a t = "ocaml_libvirt_network_lookup_by_uuid_string"
236   external create_xml : [>`W] Connect.t -> xml -> rw t = "ocaml_libvirt_network_create_xml"
237   external create_xml_job : [>`W] Connect.t -> xml -> ([`Network], rw) job_t = "ocaml_libvirt_network_create_xml_job"
238   external define_xml : [>`W] Connect.t -> xml -> rw t = "ocaml_libvirt_network_define_xml"
239   external undefine : [>`W] t -> unit = "ocaml_libvirt_network_undefine"
240   external create : [>`W] t -> unit = "ocaml_libvirt_network_create"
241   external create_job : [>`W] t -> ([`Network_nocreate], rw) job_t = "ocaml_libvirt_network_create_job"
242   external destroy : [>`W] t -> unit = "ocaml_libvirt_network_destroy"
243   external free : [>`R] t -> unit = "ocaml_libvirt_network_free"
244   external get_name : [>`R] t -> string = "ocaml_libvirt_network_get_name"
245   external get_uuid : [>`R] t -> uuid = "ocaml_libvirt_network_get_uuid"
246   external get_uuid_string : [>`R] t -> string = "ocaml_libvirt_network_get_uuid_string"
247   external get_xml_desc : [>`R] t -> xml = "ocaml_libvirt_network_get_xml_desc"
248   external get_bridge_name : [>`R] t -> string = "ocaml_libvirt_network_get_bridge_name"
249   external get_autostart : [>`R] t -> bool = "ocaml_libvirt_network_get_autostart"
250   external set_autostart : [>`W] t -> bool -> unit = "ocaml_libvirt_network_set_autostart"
251
252   external const : [>`R] t -> ro t = "%identity"
253 end
254
255 module Pool =
256 struct
257   type 'rw t
258   type pool_state = Inactive | Building | Running | Degraded
259   type pool_build_flags = New | Repair | Resize
260   type pool_delete_flags = Normal | Zeroed
261   type pool_info = {
262     state : pool_state;
263     capacity : int64;
264     allocation : int64;
265     available : int64;
266   }
267
268   external lookup_by_name : 'a Connect.t -> string -> 'a t = "ocaml_libvirt_storage_pool_lookup_by_name"
269   external lookup_by_uuid : 'a Connect.t -> uuid -> 'a t = "ocaml_libvirt_storage_pool_lookup_by_uuid"
270   external lookup_by_uuid_string : 'a Connect.t -> string -> 'a t = "ocaml_libvirt_storage_pool_lookup_by_uuid_string"
271   external create_xml : [>`W] Connect.t -> xml -> rw t = "ocaml_libvirt_storage_pool_create_xml"
272   external define_xml : [>`W] Connect.t -> xml -> rw t = "ocaml_libvirt_storage_pool_define_xml"
273   external build : [>`W] t -> pool_build_flags -> unit = "ocaml_libvirt_storage_pool_build"
274   external undefine : [>`W] t -> unit = "ocaml_libvirt_storage_pool_undefine"
275   external create : [>`W] t -> unit = "ocaml_libvirt_storage_pool_create"
276   external destroy : [>`W] t -> unit = "ocaml_libvirt_storage_pool_destroy"
277   external delete : [>`W] t -> unit = "ocaml_libvirt_storage_pool_delete"
278   external free : [>`R] t -> unit = "ocaml_libvirt_storage_pool_free"
279   external refresh : [`R] t -> unit = "ocaml_libvirt_storage_pool_refresh"
280   external get_name : [`R] t -> string = "ocaml_libvirt_storage_pool_get_name"
281   external get_uuid : [`R] t -> uuid = "ocaml_libvirt_storage_pool_get_uuid"
282   external get_uuid_string : [`R] t -> string = "ocaml_libvirt_storage_pool_get_uuid_string"
283   external get_info : [`R] t -> pool_info = "ocaml_libvirt_storage_pool_get_info"
284   external get_xml_desc : [`R] t -> xml = "ocaml_libvirt_storage_pool_get_xml_desc"
285   external get_autostart : [`R] t -> bool = "ocaml_libvirt_storage_pool_get_autostart"
286   external set_autostart : [`W] t -> bool -> unit = "ocaml_libvirt_storage_pool_set_autostart"
287   external num_of_volumes : [`R] t -> int = "ocaml_libvirt_storage_pool_num_of_volumes"
288   external list_volumes : [`R] t -> int -> string array = "ocaml_libvirt_storage_pool_list_volumes"
289   external const : [>`R] t -> ro t = "%identity"
290 end
291
292 module Volume =
293 struct
294   type 'rw t
295   type vol_type = File | Block
296   type vol_delete_flags = Normal | Zeroed
297   type vol_info = {
298     typ : vol_type;
299     capacity : int64;
300     allocation : int64;
301   }
302
303   external lookup_by_name : 'a Pool.t -> string -> 'a t = "ocaml_libvirt_storage_vol_lookup_by_name"
304   external lookup_by_key : 'a Connect.t -> string -> 'a t = "ocaml_libvirt_storage_vol_lookup_by_key"
305   external lookup_by_path : 'a Connect.t -> string -> 'a t = "ocaml_libvirt_storage_vol_lookup_by_path"
306   external pool_of_volume : 'a t -> 'a Pool.t = "ocaml_libvirt_storage_pool_lookup_by_volume"
307   external get_name : [`R] t -> string = "ocaml_libvirt_storage_vol_get_name"
308   external get_key : [`R] t -> string = "ocaml_libvirt_storage_vol_get_key"
309   external get_path : [`R] t -> string = "ocaml_libvirt_storage_vol_get_path"
310   external get_info : [`R] t -> vol_info = "ocaml_libvirt_storage_vol_get_info"
311   external get_xml_desc : [`R] t -> xml = "ocaml_libvirt_storage_vol_get_xml_desc"
312   external create_xml : [`W] Pool.t -> xml -> unit = "ocaml_libvirt_storage_vol_create_xml"
313   external delete : [`W] t -> unit = "ocaml_libvirt_storage_vol_delete"
314   external free : [>`R] t -> unit = "ocaml_libvirt_storage_vol_free"
315   external const : [>`R] t -> ro t = "%identity"
316 end
317
318 module Job =
319 struct
320   type ('jobclass, 'rw) t = ('jobclass, 'rw) job_t
321   type job_type = Bounded | Unbounded
322   type job_state = Running | Complete | Failed | Cancelled
323   type job_info = {
324     typ : job_type;
325     state : job_state;
326     running_time : int;
327     remaining_time : int;
328     percent_complete : int
329   }
330   external get_info : ('a,'b) t -> job_info = "ocaml_libvirt_job_get_info"
331   external get_domain : ([`Domain], 'a) t -> 'a Domain.t = "ocaml_libvirt_job_get_domain"
332   external get_network : ([`Network], 'a) t -> 'a Network.t = "ocaml_libvirt_job_get_network"
333   external cancel : ('a,'b) t -> unit = "ocaml_libvirt_job_cancel"
334   external free : ('a, [>`R]) t -> unit = "ocaml_libvirt_job_free"
335   external const : ('a, [>`R]) t -> ('a, ro) t = "%identity"
336 end
337
338 module Virterror =
339 struct
340   type code =
341     | VIR_ERR_OK
342     | VIR_ERR_INTERNAL_ERROR
343     | VIR_ERR_NO_MEMORY
344     | VIR_ERR_NO_SUPPORT
345     | VIR_ERR_UNKNOWN_HOST
346     | VIR_ERR_NO_CONNECT
347     | VIR_ERR_INVALID_CONN
348     | VIR_ERR_INVALID_DOMAIN
349     | VIR_ERR_INVALID_ARG
350     | VIR_ERR_OPERATION_FAILED
351     | VIR_ERR_GET_FAILED
352     | VIR_ERR_POST_FAILED
353     | VIR_ERR_HTTP_ERROR
354     | VIR_ERR_SEXPR_SERIAL
355     | VIR_ERR_NO_XEN
356     | VIR_ERR_XEN_CALL
357     | VIR_ERR_OS_TYPE
358     | VIR_ERR_NO_KERNEL
359     | VIR_ERR_NO_ROOT
360     | VIR_ERR_NO_SOURCE
361     | VIR_ERR_NO_TARGET
362     | VIR_ERR_NO_NAME
363     | VIR_ERR_NO_OS
364     | VIR_ERR_NO_DEVICE
365     | VIR_ERR_NO_XENSTORE
366     | VIR_ERR_DRIVER_FULL
367     | VIR_ERR_CALL_FAILED
368     | VIR_ERR_XML_ERROR
369     | VIR_ERR_DOM_EXIST
370     | VIR_ERR_OPERATION_DENIED
371     | VIR_ERR_OPEN_FAILED
372     | VIR_ERR_READ_FAILED
373     | VIR_ERR_PARSE_FAILED
374     | VIR_ERR_CONF_SYNTAX
375     | VIR_ERR_WRITE_FAILED
376     | VIR_ERR_XML_DETAIL
377     | VIR_ERR_INVALID_NETWORK
378     | VIR_ERR_NETWORK_EXIST
379     | VIR_ERR_SYSTEM_ERROR
380     | VIR_ERR_RPC
381     | VIR_ERR_GNUTLS_ERROR
382     | VIR_WAR_NO_NETWORK
383     | VIR_ERR_NO_DOMAIN
384     | VIR_ERR_NO_NETWORK
385     | VIR_ERR_INVALID_MAC
386     | VIR_ERR_AUTH_FAILED
387     | VIR_ERR_INVALID_STORAGE_POOL
388     | VIR_ERR_INVALID_STORAGE_VOL
389     | VIR_WAR_NO_STORAGE
390     | VIR_ERR_NO_STORAGE_POOL
391     | VIR_ERR_NO_STORAGE_VOL
392     | VIR_ERR_UNKNOWN of int
393
394   let string_of_code = function
395     | VIR_ERR_OK -> "VIR_ERR_OK"
396     | VIR_ERR_INTERNAL_ERROR -> "VIR_ERR_INTERNAL_ERROR"
397     | VIR_ERR_NO_MEMORY -> "VIR_ERR_NO_MEMORY"
398     | VIR_ERR_NO_SUPPORT -> "VIR_ERR_NO_SUPPORT"
399     | VIR_ERR_UNKNOWN_HOST -> "VIR_ERR_UNKNOWN_HOST"
400     | VIR_ERR_NO_CONNECT -> "VIR_ERR_NO_CONNECT"
401     | VIR_ERR_INVALID_CONN -> "VIR_ERR_INVALID_CONN"
402     | VIR_ERR_INVALID_DOMAIN -> "VIR_ERR_INVALID_DOMAIN"
403     | VIR_ERR_INVALID_ARG -> "VIR_ERR_INVALID_ARG"
404     | VIR_ERR_OPERATION_FAILED -> "VIR_ERR_OPERATION_FAILED"
405     | VIR_ERR_GET_FAILED -> "VIR_ERR_GET_FAILED"
406     | VIR_ERR_POST_FAILED -> "VIR_ERR_POST_FAILED"
407     | VIR_ERR_HTTP_ERROR -> "VIR_ERR_HTTP_ERROR"
408     | VIR_ERR_SEXPR_SERIAL -> "VIR_ERR_SEXPR_SERIAL"
409     | VIR_ERR_NO_XEN -> "VIR_ERR_NO_XEN"
410     | VIR_ERR_XEN_CALL -> "VIR_ERR_XEN_CALL"
411     | VIR_ERR_OS_TYPE -> "VIR_ERR_OS_TYPE"
412     | VIR_ERR_NO_KERNEL -> "VIR_ERR_NO_KERNEL"
413     | VIR_ERR_NO_ROOT -> "VIR_ERR_NO_ROOT"
414     | VIR_ERR_NO_SOURCE -> "VIR_ERR_NO_SOURCE"
415     | VIR_ERR_NO_TARGET -> "VIR_ERR_NO_TARGET"
416     | VIR_ERR_NO_NAME -> "VIR_ERR_NO_NAME"
417     | VIR_ERR_NO_OS -> "VIR_ERR_NO_OS"
418     | VIR_ERR_NO_DEVICE -> "VIR_ERR_NO_DEVICE"
419     | VIR_ERR_NO_XENSTORE -> "VIR_ERR_NO_XENSTORE"
420     | VIR_ERR_DRIVER_FULL -> "VIR_ERR_DRIVER_FULL"
421     | VIR_ERR_CALL_FAILED -> "VIR_ERR_CALL_FAILED"
422     | VIR_ERR_XML_ERROR -> "VIR_ERR_XML_ERROR"
423     | VIR_ERR_DOM_EXIST -> "VIR_ERR_DOM_EXIST"
424     | VIR_ERR_OPERATION_DENIED -> "VIR_ERR_OPERATION_DENIED"
425     | VIR_ERR_OPEN_FAILED -> "VIR_ERR_OPEN_FAILED"
426     | VIR_ERR_READ_FAILED -> "VIR_ERR_READ_FAILED"
427     | VIR_ERR_PARSE_FAILED -> "VIR_ERR_PARSE_FAILED"
428     | VIR_ERR_CONF_SYNTAX -> "VIR_ERR_CONF_SYNTAX"
429     | VIR_ERR_WRITE_FAILED -> "VIR_ERR_WRITE_FAILED"
430     | VIR_ERR_XML_DETAIL -> "VIR_ERR_XML_DETAIL"
431     | VIR_ERR_INVALID_NETWORK -> "VIR_ERR_INVALID_NETWORK"
432     | VIR_ERR_NETWORK_EXIST -> "VIR_ERR_NETWORK_EXIST"
433     | VIR_ERR_SYSTEM_ERROR -> "VIR_ERR_SYSTEM_ERROR"
434     | VIR_ERR_RPC -> "VIR_ERR_RPC"
435     | VIR_ERR_GNUTLS_ERROR -> "VIR_ERR_GNUTLS_ERROR"
436     | VIR_WAR_NO_NETWORK -> "VIR_WAR_NO_NETWORK"
437     | VIR_ERR_NO_DOMAIN -> "VIR_ERR_NO_DOMAIN"
438     | VIR_ERR_NO_NETWORK -> "VIR_ERR_NO_NETWORK"
439     | VIR_ERR_INVALID_MAC -> "VIR_ERR_INVALID_MAC"
440     | VIR_ERR_AUTH_FAILED -> "VIR_ERR_AUTH_FAILED"
441     | VIR_ERR_INVALID_STORAGE_POOL -> "VIR_ERR_INVALID_STORAGE_POOL"
442     | VIR_ERR_INVALID_STORAGE_VOL -> "VIR_ERR_INVALID_STORAGE_VOL"
443     | VIR_WAR_NO_STORAGE -> "VIR_WAR_NO_STORAGE"
444     | VIR_ERR_NO_STORAGE_POOL -> "VIR_ERR_NO_STORAGE_POOL"
445     | VIR_ERR_NO_STORAGE_VOL -> "VIR_ERR_NO_STORAGE_VOL"
446     | VIR_ERR_UNKNOWN i -> "VIR_ERR_" ^ string_of_int i
447
448   type domain =
449     | VIR_FROM_NONE
450     | VIR_FROM_XEN
451     | VIR_FROM_XEND
452     | VIR_FROM_XENSTORE
453     | VIR_FROM_SEXPR
454     | VIR_FROM_XML
455     | VIR_FROM_DOM
456     | VIR_FROM_RPC
457     | VIR_FROM_PROXY
458     | VIR_FROM_CONF
459     | VIR_FROM_QEMU
460     | VIR_FROM_NET
461     | VIR_FROM_TEST
462     | VIR_FROM_REMOTE
463     | VIR_FROM_OPENVZ
464     | VIR_FROM_XENXM
465     | VIR_FROM_STATS_LINUX
466     | VIR_FROM_STORAGE
467     | VIR_FROM_UNKNOWN of int
468
469   let string_of_domain = function
470     | VIR_FROM_NONE -> "VIR_FROM_NONE"
471     | VIR_FROM_XEN -> "VIR_FROM_XEN"
472     | VIR_FROM_XEND -> "VIR_FROM_XEND"
473     | VIR_FROM_XENSTORE -> "VIR_FROM_XENSTORE"
474     | VIR_FROM_SEXPR -> "VIR_FROM_SEXPR"
475     | VIR_FROM_XML -> "VIR_FROM_XML"
476     | VIR_FROM_DOM -> "VIR_FROM_DOM"
477     | VIR_FROM_RPC -> "VIR_FROM_RPC"
478     | VIR_FROM_PROXY -> "VIR_FROM_PROXY"
479     | VIR_FROM_CONF -> "VIR_FROM_CONF"
480     | VIR_FROM_QEMU -> "VIR_FROM_QEMU"
481     | VIR_FROM_NET -> "VIR_FROM_NET"
482     | VIR_FROM_TEST -> "VIR_FROM_TEST"
483     | VIR_FROM_REMOTE -> "VIR_FROM_REMOTE"
484     | VIR_FROM_OPENVZ -> "VIR_FROM_OPENVZ"
485     | VIR_FROM_XENXM -> "VIR_FROM_XENXM"
486     | VIR_FROM_STATS_LINUX -> "VIR_FROM_STATS_LINUX"
487     | VIR_FROM_STORAGE -> "VIR_FROM_STORAGE"
488     | VIR_FROM_UNKNOWN i -> "VIR_FROM_" ^ string_of_int i
489
490   type level =
491     | VIR_ERR_NONE
492     | VIR_ERR_WARNING
493     | VIR_ERR_ERROR
494     | VIR_ERR_UNKNOWN_LEVEL of int
495
496   let string_of_level = function
497     | VIR_ERR_NONE -> "VIR_ERR_NONE"
498     | VIR_ERR_WARNING -> "VIR_ERR_WARNING"
499     | VIR_ERR_ERROR -> "VIR_ERR_ERROR"
500     | VIR_ERR_UNKNOWN_LEVEL i -> "VIR_ERR_LEVEL_" ^ string_of_int i
501
502   type t = {
503     code : code;
504     domain : domain;
505     message : string option;
506     level : level;
507     str1 : string option;
508     str2 : string option;
509     str3 : string option;
510     int1 : int32;
511     int2 : int32;
512   }
513
514   let to_string { code = code; domain = domain; message = message } =
515     let buf = Buffer.create 128 in
516     Buffer.add_string buf "libvirt: ";
517     Buffer.add_string buf (string_of_code code);
518     Buffer.add_string buf ": ";
519     Buffer.add_string buf (string_of_domain domain);
520     Buffer.add_string buf ": ";
521     (match message with Some msg -> Buffer.add_string buf msg | None -> ());
522     Buffer.contents buf
523
524   external get_last_error : unit -> t option = "ocaml_libvirt_virterror_get_last_error"
525   external get_last_conn_error : [>`R] Connect.t -> t option = "ocaml_libvirt_virterror_get_last_conn_error"
526   external reset_last_error : unit -> unit = "ocaml_libvirt_virterror_reset_last_error"
527   external reset_last_conn_error : [>`R] Connect.t -> unit = "ocaml_libvirt_virterror_reset_last_conn_error"
528
529   let no_error () =
530     { code = VIR_ERR_OK; domain = VIR_FROM_NONE;
531       message = None; level = VIR_ERR_NONE;
532       str1 = None; str2 = None; str3 = None;
533       int1 = 0_l; int2 = 0_l }
534 end
535
536 exception Virterror of Virterror.t
537 exception Not_supported of string
538
539 let rec map_ignore_errors f = function
540   | [] -> []
541   | x :: xs ->
542       try f x :: map_ignore_errors f xs
543       with Virterror _ -> map_ignore_errors f xs
544
545 (* First time we are called, we will check if
546  * virConnectListAllDomains is supported.
547  *)
548 let have_list_all_domains = ref None
549
550 let get_domains conn ?(want_info = true) flags =
551   let have_list_all_domains =
552     match !have_list_all_domains with
553     | Some v -> v
554     | None ->
555         (* Check if virConnectListAllDomains is supported
556          * by this version of libvirt.
557          *)
558         let v =
559           (* libvirt has a short-cut which makes this very quick ... *)
560           try ignore (Domain.list_all_domains conn []); true
561           with Not_supported "virConnectListAllDomains" -> false in
562         have_list_all_domains := Some v;
563         v in
564
565   if have_list_all_domains then (
566     (* Good, we can use the shiny new method. *)
567     let doms, infos = Domain.list_all_domains conn ~want_info flags in
568     Array.to_list doms, Array.to_list infos
569   )
570   else (
571     (* Old/slow/inefficient method. *)
572     let get_all, get_active, get_inactive, another_flag =
573       let rec loop ((all, active, inactive, another) as xs) = function
574         | [] -> xs
575         | Domain.ListAll :: _ -> (true, true, true, false)
576         | Domain.ListActive :: fs -> loop (all, true, inactive, another) fs
577         | Domain.ListInactive :: fs -> loop (all, active, true, another) fs
578         | _ -> (true, true, true, true)
579       in
580       loop (false, false, false, false) flags in
581
582     let active_doms =
583       if get_active then (
584         let n = Connect.num_of_domains conn in
585         let ids = Connect.list_domains conn n in
586         let ids = Array.to_list ids in
587         map_ignore_errors (Domain.lookup_by_id conn) ids
588       ) else [] in
589
590     let inactive_doms =
591       if get_inactive then (
592         let n = Connect.num_of_defined_domains conn in
593         let names = Connect.list_defined_domains conn n in
594         let names = Array.to_list names in
595         map_ignore_errors (Domain.lookup_by_name conn) names
596       ) else [] in
597
598     let doms = active_doms @ inactive_doms in
599
600     if not another_flag then (
601       if want_info then
602         List.split (
603           map_ignore_errors (fun dom -> (dom, Domain.get_info dom)) doms
604         )
605       else
606         doms, []
607     ) else (
608       (* Slow method: We have to get the infos and filter on state. *)
609       let flag_is_set =
610         let h = Hashtbl.create 13 in
611         List.iter (fun flag -> Hashtbl.add h flag ()) flags;
612         Hashtbl.mem h
613       in
614
615       let doms =
616         map_ignore_errors (fun dom -> (dom, Domain.get_info dom)) doms in
617       let doms = List.filter (
618         fun (dom, { Domain.state = state }) ->
619           match state with
620           | Domain.InfoNoState -> flag_is_set Domain.ListNoState
621           | Domain.InfoRunning ->
622               flag_is_set Domain.ListActive || flag_is_set Domain.ListRunning
623           | Domain.InfoBlocked ->
624               flag_is_set Domain.ListActive || flag_is_set Domain.ListBlocked
625           | Domain.InfoPaused ->
626               flag_is_set Domain.ListActive || flag_is_set Domain.ListPaused
627           | Domain.InfoShutdown ->
628               flag_is_set Domain.ListActive || flag_is_set Domain.ListShutdown
629           | Domain.InfoShutoff ->
630               flag_is_set Domain.ListInactive
631               || flag_is_set Domain.ListShutoff
632           | Domain.InfoCrashed -> flag_is_set Domain.ListCrashed
633       ) doms in
634       List.split doms
635     )
636   )
637
638 (* Initialization. *)
639 external c_init : unit -> unit = "ocaml_libvirt_init"
640 let () =
641   Callback.register_exception
642     "ocaml_libvirt_virterror" (Virterror (Virterror.no_error ()));
643   Callback.register_exception
644     "ocaml_libvirt_not_supported" (Not_supported "");
645   c_init ()