From 9b4bab1fe618affd0e69666ec6467b414cee325e Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 8 Jan 2008 13:26:23 +0000 Subject: 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. --- .hgignore | 1 + ChangeLog | 9 ++ Makefile.in | 1 + README | 27 ------ examples/.depend | 2 + examples/Makefile.in | 24 ++++- examples/list_domains.ml | 2 +- examples/node_info.ml | 48 ++++++++++ libvirt/libvirt.mli | 223 ++++++++++++++++++++++++++++++++++++++++++++--- 9 files changed, 294 insertions(+), 43 deletions(-) mode change 100755 => 100644 examples/.depend mode change 100755 => 100644 examples/list_domains.ml create mode 100644 examples/node_info.ml mode change 100755 => 100644 libvirt/libvirt.mli diff --git a/.hgignore b/.hgignore index 229202f..050ed49 100644 --- 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 diff --git a/ChangeLog b/ChangeLog index 71c4927..cfa95b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2008-01-08 Richard Jones + 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. diff --git a/Makefile.in b/Makefile.in index 1538d71..52776e0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 --- 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. diff --git a/examples/.depend b/examples/.depend old mode 100755 new mode 100644 index bc5cec2..334ba5d --- a/examples/.depend +++ b/examples/.depend @@ -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 diff --git a/examples/Makefile.in b/examples/Makefile.in index 0f0c527..75a98eb 100644 --- a/examples/Makefile.in +++ b/examples/Makefile.in @@ -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: diff --git a/examples/list_domains.ml b/examples/list_domains.ml old mode 100755 new mode 100644 index 9451ab2..c97432c --- a/examples/list_domains.ml +++ b/examples/list_domains.ml @@ -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 index 0000000..c52615e --- /dev/null +++ b/examples/node_info.ml @@ -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 () diff --git a/libvirt/libvirt.mli b/libvirt/libvirt.mli old mode 100755 new mode 100644 index 58198c8..0ccaf92 --- a/libvirt/libvirt.mli +++ b/libvirt/libvirt.mli @@ -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 @@ -17,16 +17,185 @@ 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 = +# 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} *) -- cgit