From 2583c9e669e69eb799c16b9d72241297ec6744d4 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Fri, 1 Nov 2013 14:16:34 +0000
Subject: [PATCH] builder: Allow multiple source paths to be specified.
Users can now specify multiple source paths, eg:
virt-builder --source http://example.com/foo \
--source http://example.com/bar
to get templates from multiple places.
There is still only one built-in path, but we can add more later.
(cherry picked from commit bb4e882d61b49045aabd35912ae7e3a18cd6028b)
---
builder/builder.ml | 32 +++++++++++-------
builder/cmdline.ml | 69 ++++++++++++++++++++++++++++++---------
builder/index_parser.ml | 5 ++-
builder/index_parser.mli | 2 ++
builder/list_entries.ml | 10 ++++--
builder/list_entries.mli | 2 +-
builder/sigchecker.ml | 7 ++--
builder/sigchecker.mli | 4 ++-
builder/test-virt-builder-list.sh | 1 +
builder/virt-builder.pod | 57 ++++++++++++++++++++++++++------
10 files changed, 143 insertions(+), 46 deletions(-)
diff --git a/builder/builder.ml b/builder/builder.ml
index 8c8e2d4..6a4ef70 100644
--- a/builder/builder.ml
+++ b/builder/builder.ml
@@ -35,22 +35,27 @@ let prog = Filename.basename Sys.executable_name
let main () =
(* Command line argument parsing - see cmdline.ml. *)
let mode, arg,
- attach, cache, check_signature, curl, debug, delete, edit, fingerprint,
+ attach, cache, check_signature, curl, debug, delete, edit,
firstboot, run, format, gpg, hostname, install, list_long, memsize, mkdirs,
network, output, password_crypto, quiet, root_password, scrub,
- scrub_logfile, size, smp, source, sync, upload, writes =
+ scrub_logfile, size, smp, sources, sync, upload, writes =
parse_cmdline () in
(* Timestamped messages in ordinary, non-debug non-quiet mode. *)
let msg fs = make_message_function ~quiet fs in
- (* If debugging, echo the command line arguments. *)
+ (* If debugging, echo the command line arguments and the sources. *)
if debug then (
eprintf "command line:";
List.iter (eprintf " %s") (Array.to_list Sys.argv);
- prerr_newline ()
+ prerr_newline ();
+ List.iteri (
+ fun i (source, fingerprint) ->
+ eprintf "source[%d] = (%S, %S)\n" i source fingerprint
+ ) sources
);
+
(* Handle some modes here, some later on. *)
let mode =
match mode with
@@ -125,19 +130,23 @@ let main () =
)
in
- (* Make the downloader and signature checker abstract data types. *)
+ (* Download the sources. *)
let downloader = Downloader.create ~debug ~curl ~cache in
- let sigchecker =
- Sigchecker.create ~debug ~gpg ?fingerprint ~check_signature in
-
- (* Download the source (index) file. *)
- let index = Index_parser.get_index ~debug ~downloader ~sigchecker source in
+ let index : Index_parser.index =
+ List.concat (
+ List.map (
+ fun (source, fingerprint) ->
+ let sigchecker =
+ Sigchecker.create ~debug ~gpg ~fingerprint ~check_signature in
+ Index_parser.get_index ~debug ~downloader ~sigchecker source
+ ) sources
+ ) in
(* Now handle the remaining modes. *)
let mode =
match mode with
| `List -> (* --list *)
- List_entries.list_entries ~list_long ~source index;
+ List_entries.list_entries ~list_long ~sources index;
exit 0
| `Print_cache -> (* --print-cache *)
@@ -184,6 +193,7 @@ let main () =
eprintf (f_"%s: cannot find os-version '%s'.\nUse --list to list available guest types.\n")
prog arg;
exit 1 in
+ let sigchecker = entry.Index_parser.sigchecker in
(match mode with
| `Notes -> (* --notes *)
diff --git a/builder/cmdline.ml b/builder/cmdline.ml
index aaeb763..632b227 100644
--- a/builder/cmdline.ml
+++ b/builder/cmdline.ml
@@ -37,6 +37,8 @@ let default_cachedir =
with Not_found ->
None (* no cache directory *)
+let default_source = "http://libguestfs.org/download/builder/index.asc"
+
let parse_cmdline () =
let display_version () =
printf "virt-builder %s\n" Config.package_version;
@@ -83,11 +85,8 @@ let parse_cmdline () =
edit := (file, expr) :: !edit
in
- let fingerprint =
- try Some (Sys.getenv "VIRT_BUILDER_FINGERPRINT")
- with Not_found -> None in
- let fingerprint = ref fingerprint in
- let set_fingerprint fp = fingerprint := Some fp in
+ let fingerprints = ref [] in
+ let add_fingerprint arg = fingerprints := arg :: !fingerprints in
let firstboot = ref [] in
let add_firstboot s =
@@ -166,10 +165,8 @@ let parse_cmdline () =
let smp = ref None in
let set_smp arg = smp := Some arg in
- let source =
- try Sys.getenv "VIRT_BUILDER_SOURCE"
- with Not_found -> "http://libguestfs.org/download/builder/index.asc" in
- let source = ref source in
+ let sources = ref [] in
+ let add_source arg = sources := arg :: !sources in
let sync = ref true in
@@ -223,7 +220,7 @@ let parse_cmdline () =
"--delete-cache", Arg.Unit delete_cache_mode,
" " ^ s_"Delete the template cache";
"--edit", Arg.String add_edit, "file:expr" ^ " " ^ s_"Edit file with Perl expr";
- "--fingerprint", Arg.String set_fingerprint,
+ "--fingerprint", Arg.String add_fingerprint,
"AAAA.." ^ " " ^ s_"Fingerprint of valid signing key";
"--firstboot", Arg.String add_firstboot, "script" ^ " " ^ s_"Run script at first guest boot";
"--firstboot-command", Arg.String add_firstboot_cmd, "cmd+args" ^ " " ^ s_"Run command at first guest boot";
@@ -260,7 +257,7 @@ let parse_cmdline () =
"--scrub", Arg.String add_scrub, "name" ^ " " ^ s_"Scrub a file";
"--size", Arg.String set_size, "size" ^ " " ^ s_"Set output disk size";
"--smp", Arg.Int set_smp, "vcpus" ^ " " ^ s_"Set number of vCPUs";
- "--source", Arg.Set_string source, "URL" ^ " " ^ s_"Set source URL";
+ "--source", Arg.String add_source, "URL" ^ " " ^ s_"Set source URL";
"--no-sync", Arg.Clear sync, " " ^ s_"Do not fsync output file on exit";
"--upload", Arg.String add_upload, "file:dest" ^ " " ^ s_"Upload file to dest";
"-v", Arg.Set debug, " " ^ s_"Enable debugging messages";
@@ -301,7 +298,7 @@ read the man page virt-builder(1).
let debug = !debug in
let delete = List.rev !delete in
let edit = List.rev !edit in
- let fingerprint = !fingerprint in
+ let fingerprints = List.rev !fingerprints in
let firstboot = List.rev !firstboot in
let run = List.rev !run in
let format = match !format with "" -> None | s -> Some s in
@@ -320,7 +317,7 @@ read the man page virt-builder(1).
let scrub_logfile = !scrub_logfile in
let size = !size in
let smp = !smp in
- let source = !source in
+ let sources = List.rev !sources in
let sync = !sync in
let upload = List.rev !upload in
let writes = List.rev !writes in
@@ -375,8 +372,50 @@ read the man page virt-builder(1).
exit 1
) in
+ (* Check source(s) and fingerprint(s), or use environment or default. *)
+ let sources =
+ let list_split = function "" -> [] | str -> string_nsplit "," str in
+ let rec repeat x = function
+ | 0 -> [] | 1 -> [x]
+ | n -> x :: repeat x (n-1)
+ in
+
+ let sources =
+ if sources <> [] then sources
+ else (
+ try list_split (Sys.getenv "VIRT_BUILDER_SOURCE")
+ with Not_found -> [ default_source ]
+ ) in
+ let fingerprints =
+ if fingerprints <> [] then fingerprints
+ else (
+ try list_split (Sys.getenv "VIRT_BUILDER_FINGERPRINT")
+ with Not_found -> [ Sigchecker.default_fingerprint ]
+ ) in
+
+ let nr_sources = List.length sources in
+ let fingerprints =
+ match fingerprints with
+ | [fingerprint] ->
+ (* You're allowed to have multiple sources and one fingerprint: it
+ * means that the same fingerprint is used for all sources.
+ *)
+ repeat fingerprint nr_sources
+ | xs -> xs in
+
+ if List.length fingerprints <> nr_sources then (
+ eprintf (f_"%s: source and fingerprint lists are not the same length\n")
+ prog;
+ exit 1
+ );
+
+ assert (nr_sources > 0);
+
+ (* Combine the sources and fingerprints into a single list of pairs. *)
+ List.combine sources fingerprints in
+
mode, arg,
- attach, cache, check_signature, curl, debug, delete, edit, fingerprint,
+ attach, cache, check_signature, curl, debug, delete, edit,
firstboot, run, format, gpg, hostname, install, list_long, memsize, mkdirs,
network, output, password_crypto, quiet, root_password, scrub,
- scrub_logfile, size, smp, source, sync, upload, writes
+ scrub_logfile, size, smp, sources, sync, upload, writes
diff --git a/builder/index_parser.ml b/builder/index_parser.ml
index b5a0cf0..dc039fe 100644
--- a/builder/index_parser.ml
+++ b/builder/index_parser.ml
@@ -37,6 +37,8 @@ and entry = {
lvexpand : string option;
notes : string option;
hidden : bool;
+
+ sigchecker : Sigchecker.t;
}
let print_entry chan (name, { printable_name = printable_name;
@@ -348,7 +350,8 @@ let get_index ~debug ~downloader ~sigchecker source =
expand = expand;
lvexpand = lvexpand;
notes = notes;
- hidden = hidden } in
+ hidden = hidden;
+ sigchecker = sigchecker } in
n, entry
) sections in
diff --git a/builder/index_parser.mli b/builder/index_parser.mli
index 79df5ef..0b6317d 100644
--- a/builder/index_parser.mli
+++ b/builder/index_parser.mli
@@ -31,6 +31,8 @@ and entry = {
lvexpand : string option;
notes : string option;
hidden : bool;
+
+ sigchecker : Sigchecker.t;
}
val get_index : debug:bool -> downloader:Downloader.t -> sigchecker:Sigchecker.t -> string -> index
diff --git a/builder/list_entries.ml b/builder/list_entries.ml
index b233f0e..04a65ca 100644
--- a/builder/list_entries.ml
+++ b/builder/list_entries.ml
@@ -21,10 +21,14 @@ open Common_utils
open Printf
-let list_entries ?(list_long = false) ~source index =
+let list_entries ?(list_long = false) ~sources index =
if list_long then (
- printf (f_"Source URI: %s\n") source;
- printf "\n"
+ List.iter (
+ fun (source, fingerprint) ->
+ printf (f_"Source URI: %s\n") source;
+ printf (f_"Fingerprint: %s\n") fingerprint;
+ printf "\n"
+ ) sources
);
List.iter (
diff --git a/builder/list_entries.mli b/builder/list_entries.mli
index e1d5c06..d9486b0 100644
--- a/builder/list_entries.mli
+++ b/builder/list_entries.mli
@@ -16,4 +16,4 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
-val list_entries : ?list_long:bool -> source:string -> Index_parser.index -> unit
+val list_entries : ?list_long:bool -> sources:(string * string) list -> Index_parser.index -> unit
diff --git a/builder/sigchecker.ml b/builder/sigchecker.ml
index 2bd3c11..b20a186 100644
--- a/builder/sigchecker.ml
+++ b/builder/sigchecker.ml
@@ -104,7 +104,7 @@ type t = {
check_signature : bool;
}
-let create ~debug ~gpg ?(fingerprint = default_fingerprint) ~check_signature =
+let create ~debug ~gpg ~fingerprint ~check_signature =
{
debug = debug;
gpg = gpg;
@@ -188,10 +188,9 @@ and do_verify t args =
exit 1
)
-(* Import the default public key, if it's the default fingerprint. *)
+(* Import the default public key. *)
and import_key t =
- if not !key_imported && equal_fingerprints t.fingerprint default_fingerprint
- then (
+ if not !key_imported then (
let filename, chan = Filename.open_temp_file "vbpubkey" ".asc" in
unlink_on_exit filename;
output_string chan default_pubkey;
diff --git a/builder/sigchecker.mli b/builder/sigchecker.mli
index 4d89129..cdd800e 100644
--- a/builder/sigchecker.mli
+++ b/builder/sigchecker.mli
@@ -16,9 +16,11 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
+val default_fingerprint : string
+
type t
-val create : debug:bool -> gpg:string -> ?fingerprint:string -> check_signature:bool -> t
+val create : debug:bool -> gpg:string -> fingerprint:string -> check_signature:bool -> t
val verify : t -> string -> unit
(** Verify the file is signed (if check_signature is true). *)
diff --git a/builder/test-virt-builder-list.sh b/builder/test-virt-builder-list.sh
index 134ca7c..256d993 100755
--- a/builder/test-virt-builder-list.sh
+++ b/builder/test-virt-builder-list.sh
@@ -39,6 +39,7 @@ fi
long_list=$(./virt-builder --no-check-signature --no-cache --list --long)
if [ "$long_list" != "Source URI: $VIRT_BUILDER_SOURCE
+Fingerprint: F777 4FB1 AD07 4A7E 8C87 67EA 9173 8F73 E1B7 68A0
os-version: phony-debian
Full name: Phony Debian
diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod
index 3905880..fb99d7c 100644
--- a/builder/virt-builder.pod
+++ b/builder/virt-builder.pod
@@ -264,10 +264,14 @@ Check that the index and templates are signed by the key with the
given fingerprint. (The fingerprint is a long string, usually written
as 10 groups of 4 hexadecimal digits).
-If signature checking is enabled and the I<--fingerprint> option is
-not given, then this checks the download was signed by
-S<F777 4FB1 AD07 4A7E 8C87 67EA 9173 8F73 E1B7 68A0> (which is
-S<Richard W.M. Jones's> key).
+You can give this option multiple times. If you have multiple source
+URLs, then you can have either no fingerprint, one fingerprint or
+multiple fingerprints. If you have multiple, then each must
+correspond 1-1 with a source URL.
+
+The default fingerprint (if none are supplied) is
+S<F777 4FB1 AD07 4A7E 8C87 67EA 9173 8F73 E1B7 68A0>
+(which is S<Richard W.M. Jones's> key).
You can also set the C<VIRT_BUILDER_FINGERPRINT> environment variable.
@@ -559,8 +563,11 @@ Enable N E<ge> 2 virtual CPUs for I<--run> scripts to use.
=item B<--source> URL
-Set the source URL to look for templates. If not specified it
-defaults to L<http://libguestfs.org/download/builder/index.asc>
+Set the source URL to look for indexes.
+
+You can give this option multiple times to specify multiple sources.
+If not specified it defaults to
+L<http://libguestfs.org/download/builder/index.asc>
See also L</CREATING YOUR OWN TEMPLATES> below.
@@ -1201,6 +1208,36 @@ Now run virt-builder commands as normal, eg:
To debug problems, add the C<-v> option to these commands.
+=head3 Running virt-builder against multiple sources
+
+It is possible to use multiple sources with virt-builder. Use either
+multiple I<--source> and/or I<--fingerprint> options, or a
+comma-separated list in the C<VIRT_BUILDER_SOURCE> /
+C<VIRT_BUILDER_FINGERPRINT> environment variables:
+
+ virt-builder \
+ --source http://example.com/s1/index.asc \
+ --source http://example.com/s2/index.asc
+
+or equivalently:
+
+ export VIRT_BUILDER_SOURCE=http://example.com/s1/index.asc,http://example.com/s2/index.asc
+ virt-builder [...]
+
+You can provide N, 1 or 0 fingerprints. In the case where you
+provide N fingerprints, N = number of sources and there is a 1-1
+correspondence between each source and each fingerprint:
+
+ virt-builder \
+ --source http://example.com/s1/index.asc --fingerprint '0123 ...' \
+ --source http://example.com/s2/index.asc --fingerprint '9876 ...'
+
+In the case where you provide 1 fingerprint, the same fingerprint
+is used for all sources.
+
+In the case where you provide no fingerprints, the default fingerprint
+built into virt-builder is used for all sources.
+
=head3 Licensing of templates
You should be aware of the licensing of images that you distribute.
@@ -1384,13 +1421,13 @@ Used to determine the location of the template cache. See L</CACHING>.
=item C<VIRT_BUILDER_FINGERPRINT>
-Set the default value for the GPG signature fingerprint (see
-I<--fingerprint> option).
+Set the default value for the GPG signature fingerprint or
+comma-separated list of fingerprints (see I<--fingerprint> option).
=item C<VIRT_BUILDER_SOURCE>
-Set the default value for the source URL for the template repository
-(see I<--source> option).
+Set the default value for the source URL (or comma-separated list of
+URLs) for the template repository (see I<--source> option).
=item C<XDG_CACHE_HOME>
--
1.8.3.1