module Libvirt:OCaml bindings for libvirt.sig
..end
This is a set of bindings for writing OCaml programs to manage virtual machines through libvirt.
Using the interactive toplevel:
$ ocaml -I +libvirt Objective Caml version 3.10.0 # #load "unix.cma";; # #load "mllibvirt.cma";; # let name = "test:///default";; val name : string = "test:///default" # let conn = Libvirt.Connect.connect_readonly ~name () ;; val conn : Libvirt.ro Libvirt.Connect.t = <abstr> # Libvirt.Connect.get_node_info conn;; : Libvirt.Connect.node_info = {Libvirt.Connect.model = "i686"; Libvirt.Connect.memory = 3145728L; Libvirt.Connect.cpus = 16; Libvirt.Connect.mhz = 1400; Libvirt.Connect.nodes = 2; Libvirt.Connect.sockets = 2; Libvirt.Connect.cores = 2; Libvirt.Connect.threads = 2}
This command compiles a program to native code:
ocamlopt -I +libvirt mllibvirt.cmxa list_domains.ml -o list_domains
The main modules are Libvirt.Connect
, Libvirt.Domain
and
Libvirt.Network
corresponding respectively to the
virConnect*, virDomain* and virNetwork* functions from libvirt.
For brevity I usually rename these modules like this:
module C = Libvirt.Connect module D = Libvirt.Domain module N = Libvirt.Network
To get a connection handle, assuming a Xen hypervisor:
let name = "xen:///" let conn = C.connect_readonly ~name ()
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 ( fun dom -> printf "%8d %s\n%!" (D.get_id dom) (D.get_name dom) ) domains;
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;
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; printf "cpus = %d\n" node_info.C.cpus; printf "mhz = %d\n" node_info.C.mhz; printf "nodes = %d\n" node_info.C.nodes; printf "sockets = %d\n" node_info.C.sockets; printf "cores = %d\n" node_info.C.cores; printf "threads = %d\n%!" node_info.C.threads; let hostname = C.get_hostname conn in printf "hostname = %s\n%!" hostname; let uri = C.get_uri conn in printf "uri = %s\n%!" uri
Memory allocation / automatic garbage collection of all libvirt 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
the safety of garbage collection and should only be used when
you want to explicitly free memory. Note that explicitly
closing a connection object does nothing if there are still
unclosed domain or network objects referencing it.
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. This is just the nature of virtualisation.
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 newer version of libvirt than it was compiled with, and it should still work.
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.
We don't support libvirt < 0.2.1, and never will so don't ask us.
You can issue multiple concurrent libvirt requests in different threads. However you must follow this rule: Each thread must have its own separate libvirt connection, or you must implement your own mutex scheme to ensure that no two threads can ever make concurrent calls using the same libvirt connection.
(Note that multithreaded code is not well tested. If you find bugs please report them.)
Libvirt requires all callers to call virInitialize before using the library. This is done automatically for you by these bindings when the program starts up, and we believe that the way this is done is safe.
typeuuid =
string
typexml =
string
typefilename =
string
val get_version : ?driver:string -> unit -> int * int
get_version ()
returns the library version in the first part
of the tuple, and 0
in the second part.
get_version ~driver ()
returns the library version in the first
part of the tuple, and the version of the driver called driver
in the second part.
The version numbers are encoded as
1,000,000 * major + 1,000 * minor + release.
val uuid_length : int
val uuid_string_length : int
typerw =
[ `R | `W ]
typero =
[ `R ]
All connection/domain/etc. objects are marked with a phantom read-write or read-only type, and trying to pass a read-only object into a function which could mutate the object will cause a compile time error.
Each module provides a function like Libvirt.Connect.const
to demote a read-write object into a read-only object. The
opposite operation is, of course, not allowed.
If you want to handle both read-write and read-only connections at runtime, use a variant similar to this:
type conn_t = | No_connection | Read_only of Libvirt.ro Libvirt.Connect.t | Read_write of Libvirt.rw Libvirt.Connect.tSee also the source of
mlvirsh
.type ('a, 'b)
job_t
Libvirt.Job.t
to avoid recursive module dependencies.module Connect:sig
..end
module Domain:sig
..end
module Network:sig
..end
module Pool:sig
..end
module Volume:sig
..end
module Job:sig
..end
module Virterror:sig
..end
exception Virterror of Virterror.t
Libvirt.Virterror.to_string
on the content of this exception.exception Not_supported of string
Not_supported "virFoo"
(where virFoo
is the libvirt function name) if a function is
not supported at either compile or run time. This applies to
any libvirt function added after version 0.2.1.
See also http://libvirt.org/hvsupport.html