Move programming information to libvirt generated doc.
authorRichard W.M. Jones <rjones@redhat.com>
Tue, 8 Jan 2008 13:26:23 +0000 (13:26 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Tue, 8 Jan 2008 13:26:23 +0000 (13:26 +0000)
* README, libvirt/libvirt.mli: Moved programming information to
  libvirt generated documentation, greatly expanded examples and
  other issues.
* examples/Makefile.in, examples/node_info.ml, examples/.depend:
  Added node_info example program.
* .hgignore, Makefile.in: Ignore, clean up node_info binary.
* examples/list_domains.ml: Make a read-only connection.

.hgignore
ChangeLog
Makefile.in
README
examples/.depend [changed mode: 0755->0644]
examples/Makefile.in
examples/list_domains.ml [changed mode: 0755->0644]
examples/node_info.ml [new file with mode: 0644]
libvirt/libvirt.mli [changed mode: 0755->0644]

index 229202f..050ed49 100644 (file)
--- a/.hgignore
+++ b/.hgignore
@@ -27,6 +27,7 @@ core.*
 *~
 libvirt/libvirt_version.ml
 examples/list_domains
+examples/node_info
 mlvirsh/mlvirsh
 virt-ctrl/virt-ctrl
 virt-top/virt-top
index 71c4927..cfa95b5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2008-01-08  Richard Jones  <rjones@redhat.com>
 
+       Move programming information to libvirt generated doc.
+       * README, libvirt/libvirt.mli: Moved programming information to
+         libvirt generated documentation, greatly expanded examples and
+         other issues.
+       * examples/Makefile.in, examples/node_info.ml, examples/.depend:
+         Added node_info example program.
+       * .hgignore, Makefile.in: Ignore, clean up node_info binary.
+       * examples/list_domains.ml: Make a read-only connection.
+
        Clean up *.exe files.
        * Makefile.in: Clean up *.exe files.
 
index 1538d71..52776e0 100644 (file)
@@ -38,6 +38,7 @@ clean:
          (cd $$d; rm -f *.cmi *.cmo *.cmx *.cma *.cmxa *.o *.a *.so *.opt *~ *.dll *.exe core); \
        done
        rm -f examples/list_domains
+       rm -f examples/node_info
        rm -f mlvirsh/mlvirsh
        rm -f virt-ctrl/virt-ctrl
        rm -f virt-top/virt-top
diff --git a/README b/README
index 67e5ab4..627853e 100644 (file)
--- a/README
+++ b/README
@@ -152,33 +152,6 @@ domains, or show the machine console.
 Programming
 ----------------------------------------------------------------------
 
-The interface is described in 'libvirt.mli'.  The main modules are
-Libvirt.Connect, Libvirt.Domain and Libvirt.Network, corresponding
-respectively to the virConnect*, virDomain*, and virNetwork*
-functions.  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, do:
-
-  let name = "xen:///"
-  let conn = C.connect ~name ()
-
-To list domains, do:
-
-  let n = C.num_of_domains conn
-  let ids = C.list_domains conn n
-  let domains = Array.map (D.lookup_by_id conn) ids
-  let () =
-    Array.iter (
-      fun dom ->
-        printf "%5d %s\n" (D.get_id dom) (D.get_name dom)
-    ) domains
-
-(See also the program list_domains.ml).
-
 For documentation on these bindings, read libvirt.mli and/or 'make
 doc' and browse the HTML documentation in the html/ subdirectory.
 
old mode 100755 (executable)
new mode 100644 (file)
index bc5cec2..334ba5d
@@ -1,2 +1,4 @@
 list_domains.cmo: ../libvirt/libvirt.cmi 
 list_domains.cmx: ../libvirt/libvirt.cmx 
+node_info.cmo: ../libvirt/libvirt.cmi 
+node_info.cmx: ../libvirt/libvirt.cmx 
index 0f0c527..75a98eb 100644 (file)
@@ -36,8 +36,8 @@ endif
 export LIBRARY_PATH=../libvirt
 export LD_LIBRARY_PATH=../libvirt
 
-BYTE_TARGETS   := list_domains
-OPT_TARGETS    := list_domains.opt
+BYTE_TARGETS   := list_domains node_info
+OPT_TARGETS    := list_domains.opt node_info.opt
 
 all: $(BYTE_TARGETS)
 
@@ -53,6 +53,16 @@ list_domains.opt: list_domains.cmx
        $(OCAMLFIND) ocamlopt \
          $(OCAMLOPTPACKAGES) $(OCAMLOPTFLAGS) $(OCAMLOPTLIBS) \
          ../libvirt/mllibvirt.cmxa -o $@ $<
+
+node_info: node_info.cmo
+       $(OCAMLFIND) ocamlc \
+         $(OCAMLCPACKAGES) $(OCAMLCFLAGS) $(OCAMLCLIBS) \
+         ../libvirt/mllibvirt.cma -o $@ $<
+
+node_info.opt: node_info.cmx
+       $(OCAMLFIND) ocamlopt \
+         $(OCAMLOPTPACKAGES) $(OCAMLOPTFLAGS) $(OCAMLOPTLIBS) \
+         ../libvirt/mllibvirt.cmxa -o $@ $<
 else
 list_domains: list_domains.cmo
        $(OCAMLC) \
@@ -63,6 +73,16 @@ list_domains.opt: list_domains.cmx
        $(OCAMLOPT) \
          $(OCAMLOPTINCS) $(OCAMLOPTFLAGS) $(OCAMLOPTLIBS) \
          ../libvirt/mllibvirt.cmxa -o $@ $<
+
+node_info: node_info.cmo
+       $(OCAMLC) \
+         $(OCAMLCINCS) $(OCAMLCFLAGS) $(OCAMLCLIBS) \
+         ../libvirt/mllibvirt.cma -o $@ $<
+
+node_info.opt: node_info.cmx
+       $(OCAMLOPT) \
+         $(OCAMLOPTINCS) $(OCAMLOPTFLAGS) $(OCAMLOPTLIBS) \
+         ../libvirt/mllibvirt.cmxa -o $@ $<
 endif
 
 install:
old mode 100755 (executable)
new mode 100644 (file)
index 9451ab2..c97432c
@@ -17,7 +17,7 @@ let () =
        Some (Sys.argv.(1))
       else
        None in
-    let conn = C.connect ?name () in
+    let conn = C.connect_readonly ?name () in
 
     (* List running domains. *)
     let n = C.num_of_domains conn in
diff --git a/examples/node_info.ml b/examples/node_info.ml
new file mode 100644 (file)
index 0000000..c52615e
--- /dev/null
@@ -0,0 +1,48 @@
+(* Simple demo program showing node info.
+   Usage: node_info [URI]
+   (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
+   http://libvirt.org/
+ *)
+
+open Printf
+
+module C = Libvirt.Connect
+
+let () =
+  try
+    let name =
+      if Array.length Sys.argv >= 2 then
+       Some (Sys.argv.(1))
+      else
+       None in
+    let conn = C.connect_readonly ?name () in
+
+    (* Get node_info, hostname, etc. *)
+    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
+
+  with
+    Libvirt.Virterror err ->
+      eprintf "error: %s\n" (Libvirt.Virterror.to_string err)
+
+let () =
+  (* Run the garbage collector which is a good way to check for
+   * memory corruption errors and reference counting issues in libvirt.
+   *)
+  Gc.compact ()
old mode 100755 (executable)
new mode 100644 (file)
index 58198c8..0ccaf92
@@ -1,6 +1,6 @@
-(** OCaml bindings for libvirt.
-    (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
-    http://libvirt.org/
+(** OCaml bindings for libvirt. *)
+(* (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
+   http://libvirt.org/
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *)
 
+(**
+   {2 Introduction and examples}
+
+   This is a set of bindings for writing OCaml programs to
+   manage virtual machines through {{:http://libvirt.org/}libvirt}.
+
+   {3 Using libvirt interactively}
+
+   Using the interactive toplevel:
+
+{v
+$ 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}
+v}
+
+   {3 Compiling libvirt programs}
+
+   This command compiles a program to native code:
+
+{v
+ocamlopt -I +libvirt mllibvirt.cmxa list_domains.ml -o list_domains
+v}
+
+   {3 Example: Connect to the hypervisor}
+
+   The main modules are {!Libvirt.Connect}, {!Libvirt.Domain} and
+   {!Libvirt.Network} corresponding respectively to the
+   {{: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 (
+  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}
+
+   {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;
+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
+v}
+
+*)
+
+
+(** {2 Programming issues}
+
+    {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.
+
+    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.
+
+    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.
+
+    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.
+
+    {3 Threads}
+
+    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, {i 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.)
+
+    {3 Initialisation}
+
+    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.
+
+    {2 Reference}
+*)
+
 type uuid = string
-(** This is a "raw" UUID, ie. a packed string of bytes. *)
+    (** This is a "raw" UUID, ie. a packed string of bytes. *)
 
 type xml = string
-(** Type of XML (an uninterpreted string of bytes).  Use PXP, expat,
-    xml-light, etc. if you want to do anything useful with the XML.
-*)
+    (** Type of XML (an uninterpreted string of bytes).  Use PXP, expat,
+       xml-light, etc. if you want to do anything useful with the XML.
+    *)
 
 type filename = string
-(** A filename. *)
+    (** A filename. *)
 
 val get_version : ?driver:string -> unit -> int * int
   (** [get_version ()] returns the library version in the first part
@@ -46,12 +215,34 @@ val uuid_length : int
 val uuid_string_length : int
   (** Length of UUID strings. *)
 
-(* These phantom types are used to ensure the type-safety of read-only
- * versus read-write connections.  For more information see:
- * http://caml.inria.fr/pub/ml-archives/caml-list/2004/07/80683af867cce6bf8fff273973f70c95.en.html
- *)
 type rw = [`R|`W]
 type ro = [`R]
+    (** These
+       {{:http://caml.inria.fr/pub/ml-archives/caml-list/2004/07/80683af867cce6bf8fff273973f70c95.en.html}phantom types}
+       are used to ensure the type-safety of read-only
+       versus read-write connections.
+
+       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:
+{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].
+    *)
+
+(** {3 Connections} *)
 
 module Connect :
 sig
@@ -185,6 +376,8 @@ end
       connection object.
   *)
 
+(** {3 Domains} *)
+
 module Domain :
 sig
   type 'rw t
@@ -361,6 +554,8 @@ end
       domain object.
   *)
 
+(** {3 Networks} *)
+
 module Network : 
 sig
   type 'rw t
@@ -416,6 +611,8 @@ end
       network object.
   *)
 
+(** {3 Error handling and exceptions} *)
+
 module Virterror :
 sig
   type code =
@@ -560,6 +757,6 @@ exception Not_supported of string
     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]
+    See also {{:http://libvirt.org/hvsupport.html}http://libvirt.org/hvsupport.html}
 *)