(* mclu: Mini Cloud * Copyright (C) 2014-2015 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) (* Templates. *) open Utils open Printf let template_dir = try Sys.getenv "MCLU_PATH" with Not_found -> Config.pkgdatadir // "templates" let templates () = let files = Sys.readdir template_dir in let files = Array.to_list files in let files = List.map ((//) template_dir) files in let files = List.filter (fun name -> Filename.check_suffix name ".template") files in let templates = List.map ( fun filename -> let name = Filename.basename filename in let name = Filename.chop_suffix name ".template" in (name, filename) ) files in List.sort compare templates let template_names () = List.map fst (templates ()) let run_template ~verbose filename subcmd args = let cmd = sprintf "%s %s %s" (quote filename) (quote subcmd) (String.concat " " (List.map quote args)) in if verbose then printf "%s\n%!" cmd; let chan = Unix.open_process_in cmd in let lines = ref [] in (try while true do lines := input_line chan :: !lines done with End_of_file -> ()); let lines = List.rev !lines in let stat = Unix.close_process_in chan in (match stat with | Unix.WEXITED 0 -> Some lines | Unix.WEXITED 2 -> None | Unix.WEXITED i -> eprintf "mclu: template '%s' subcmd '%s' exited with error %d\n" filename subcmd i; exit 1 | Unix.WSIGNALED i -> eprintf "mclu: template '%s' subcmd '%s' killed by signal %d\n" filename subcmd i; exit 1 | Unix.WSTOPPED i -> eprintf "mclu: template '%s' subcmd '%s' stopped by signal %d\n" filename subcmd i; exit 1 ) type template_info = { base_image : string; guest_arch : string option; minimum_memory : int64 option; recommended_memory : int64 option; minimum_size : int64 option; disk_bus : string option; network_model : string option; has_xml_target : bool; needs_external_kernel : bool; cmdline : string option; } let probe ?(verbose = false) filename = (* Check the template is a template. *) (match run_template ~verbose filename "probe" [] with | Some ["hello"] -> () | _ -> eprintf "mclu: file %s is not an mclu template\n" filename; exit 1 ); (* Probe for various properties. *) let base_image = match run_template ~verbose filename "base-image" [] with | Some [answer] -> answer | _ -> eprintf "mclu: cannot parse '%s base-image'\n" filename; exit 1 in let guest_arch = match run_template ~verbose filename "guest-arch" [] with | Some [arch] -> Some arch | _ -> None in let minimum_memory = match run_template ~verbose filename "minimum-memory" [] with | Some [memory] -> (try Some (bytes_of_human_size memory) with Not_found -> eprintf "mclu: cannot parse output of '%s minimum-memory'\n" filename; exit 1 ); | _ -> None in let recommended_memory = match run_template ~verbose filename "recommended-memory" [] with | Some [memory] -> (try Some (bytes_of_human_size memory) with Not_found -> eprintf "mclu: cannot parse output of '%s recommended-memory'\n" filename; exit 1 ); | _ -> None in let minimum_size = match run_template ~verbose filename "minimum-size" [] with | Some [size] -> (try Some (bytes_of_human_size size) with Not_found -> eprintf "mclu: cannot parse output of '%s minimum-size'\n" filename; exit 1 ); | _ -> None in let disk_bus = match run_template ~verbose filename "disk-bus" [] with | Some [answer] -> Some answer | _ -> None in let network_model = match run_template ~verbose filename "network-model" [] with | Some [answer] -> Some answer | _ -> None in let has_xml_target = run_template ~verbose filename "xml" [] <> None in let needs_external_kernel = match run_template ~verbose filename "needs-external-kernel" [] with | None -> false | Some ["1"|"yes"] -> true | Some _ -> false in let cmdline = match run_template ~verbose filename "cmdline" [] with | Some [cmdline] -> Some cmdline | _ -> None in if not needs_external_kernel && cmdline <> None then ( eprintf "mclu: template cannot set 'cmdline' unless 'needs-external-kernel' is 'yes'.\n"; exit 1 ); { base_image = base_image; guest_arch = guest_arch; minimum_memory = minimum_memory; recommended_memory = recommended_memory; minimum_size = minimum_size; disk_bus = disk_bus; network_model = network_model; has_xml_target = has_xml_target; needs_external_kernel = needs_external_kernel; cmdline = cmdline }