# HG changeset patch # User Thomas Sanders # Date 1286306824 -3600 # Node ID 3e9d27f796957dff0942ad3b12b54036356669a2 # Parent 8095e7b9208492ce7584f2a0ba61209afc4479db CA-32077 Gracefully handle missing /etc/xensource-inventory file xapi was failing nastily on start-up if the xensource-inventory file was missing. Now it generates a minimal one if none exists. This does not include a build number, so version.ml now falls back to using a build number from the Make environment if one is not available from the inventory, i.e. it falls back to the behaviour from before Matthias's commit for CA-43574 (build number from xensource-inventory). Signed-off-by: Thomas Sanders diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -107,11 +107,11 @@ import-v6: version: echo "(* This file is autogenerated. Grep for e17512ce-ba7c-11df-887b-0026b9799147 (random uuid) to see where it comes from. ;o) *)" > ocaml/util/version.ml echo "let hg_id = \"$(shell hg id | sed -r 's/(.+)\s.*/\1/g')\"" >> ocaml/util/version.ml - echo "let hostname = \"$(shell hostname)\"" >> ocaml/util/version.ml - echo "let date = \"$(shell date -u +%Y-%m-%d)\"" >> ocaml/util/version.ml + echo "let hostname = \"$(shell hostname)\"" >> ocaml/util/version.ml + echo "let date = \"$(shell date -u +%Y-%m-%d)\"" >> ocaml/util/version.ml echo "let product_version = \"$(PRODUCT_VERSION)\"" >> ocaml/util/version.ml - echo "let product_brand = \"$(PRODUCT_BRAND)\"" >> ocaml/util/version.ml - echo "let build_number = Util_inventory.lookup \"BUILD_NUMBER\" (* \"$(BUILD_NUMBER)\" *)" >> ocaml/util/version.ml + echo "let product_brand = \"$(PRODUCT_BRAND)\"" >> ocaml/util/version.ml + echo "let build_number = Util_inventory.lookup ~default:\"$(BUILD_NUMBER)\" \"BUILD_NUMBER\"" >> ocaml/util/version.ml .PHONY: clean clean: diff --git a/ocaml/util/util_inventory.ml b/ocaml/util/util_inventory.ml --- a/ocaml/util/util_inventory.ml +++ b/ocaml/util/util_inventory.ml @@ -1,5 +1,5 @@ (* - * Copyright (C) 2006-2009 Citrix Systems Inc. + * Copyright (C) 2006-2010 Citrix Systems Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -20,10 +20,33 @@ open Threadext module D = Debug.Debugger(struct let name="xapi" end) open D +let inventory_filename = Util_globs_inventory.inventory_filename + +(* Keys which must exist: *) +let _installation_uuid = "INSTALLATION_UUID" +let _control_domain_uuid = "CONTROL_DOMAIN_UUID" +let _management_interface = "MANAGEMENT_INTERFACE" + +(* Optional keys: *) +let _current_interfaces = "CURRENT_INTERFACES" +let _oem_manufacturer = "OEM_MANUFACTURER" +let _oem_model = "OEM_MODEL" +let _oem_build_number = "OEM_BUILD_NUMBER" +let _machine_serial_number = "MACHINE_SERIAL_NUMBER" +let _machine_serial_name = "MACHINE_SERIAL_NAME" + let loaded_inventory = ref false let inventory = Hashtbl.create 10 let inventory_m = Mutex.create () +(* Compute the minimum necessary inventory file contents *) +let minimum_default_entries () = + let host_uuid = Uuid.string_of_uuid (Uuid.make_uuid ()) in + let dom0_uuid = Uuid.string_of_uuid (Uuid.make_uuid ()) in + [ _installation_uuid, host_uuid; + _control_domain_uuid, dom0_uuid; + _management_interface, "" ] + (* trim any quotes off the ends *) let strip_quotes v = if String.length v >= 2 @@ -39,7 +62,17 @@ let parse_inventory_entry line = Some (k, strip_quotes ++ String.strip String.isspace $ v) | _ -> None +let string_of_table h = + let lines = List.fold_left (fun acc (k, v) -> + Printf.sprintf "%s='%s'\n" k v :: acc) [] h in + String.concat "" lines + let read_inventory_contents () = + if not (Sys.file_exists inventory_filename) then begin + warn "%s does not exist: generating a minimal one" inventory_filename; + Unixext.write_string_to_file inventory_filename ( + string_of_table (minimum_default_entries ())) + end; (* Perhaps we should blank the old inventory before we read the new one? What is the desired behaviour? *) Unixext.file_lines_iter (fun line -> @@ -47,7 +80,7 @@ let read_inventory_contents () = | Some (k, v) -> Hashtbl.add inventory k v | None -> warn "Failed to parse line from xensource-inventory file: %s" line) - Util_globs_inventory.inventory_filename; + inventory_filename; loaded_inventory := true let read_inventory () = Mutex.execute inventory_m read_inventory_contents @@ -57,18 +90,19 @@ let reread_inventory () = Mutex.execute exception Missing_inventory_key of string -let lookup key = - if not (!loaded_inventory) then read_inventory(); - if not (Hashtbl.mem inventory key) - then raise (Missing_inventory_key key); - Hashtbl.find inventory key +let lookup ?default key = + (if not (!loaded_inventory) then read_inventory()); + if (Hashtbl.mem inventory key) + then + Hashtbl.find inventory key + else + match default with + | None -> raise (Missing_inventory_key key) + | Some v -> v let flush_to_disk_locked () = - let lines = Hashtbl.fold - (fun k v acc -> Printf.sprintf "%s='%s'\n" k v :: acc) - inventory [] in - Unixext.write_string_to_file Util_globs_inventory.inventory_filename - $ String.concat "" lines + let h = Hashtbl.fold (fun k v acc -> (k, v) :: acc) inventory [] in + Unixext.write_string_to_file inventory_filename (string_of_table h) let update key value = Mutex.execute inventory_m (fun () -> Hashtbl.clear inventory; @@ -81,25 +115,3 @@ let remove key = Mutex.execute inventory read_inventory_contents (); Hashtbl.remove inventory key; flush_to_disk_locked ()) - -let _product_brand = "PRODUCT_BRAND" -let _product_name = "PRODUCT_NAME" -let _product_version = "PRODUCT_VERSION='0.5.1'" -let _build_number = "BUILD_NUMBER" -let _kernel_version = "KERNEL_VERSION" -let _xen_version = "XEN_VERSION" -let _installation_date = "INSTALLATION_DATE" -let _default_sr = "DEFAULT_SR" -let _primary_disk = "PRIMARY_DISK" -let _backup_partition = "BACKUP_PARTITION" -let _installation_uuid = "INSTALLATION_UUID" -let _default_sr_physdevs = "DEFAULT_SR_PHYSDEVS" -let _control_domain_uuid = "CONTROL_DOMAIN_UUID" -let _management_interface = "MANAGEMENT_INTERFACE" -let _current_interfaces = "CURRENT_INTERFACES" -let _dom0_mem = "DOM0_MEM" -let _oem_manufacturer = "OEM_MANUFACTURER" -let _oem_model = "OEM_MODEL" -let _oem_build_number = "OEM_BUILD_NUMBER" -let _machine_serial_number = "MACHINE_SERIAL_NUMBER" -let _machine_serial_name = "MACHINE_SERIAL_NAME" diff --git a/ocaml/util/util_inventory.mli b/ocaml/util/util_inventory.mli --- a/ocaml/util/util_inventory.mli +++ b/ocaml/util/util_inventory.mli @@ -1,5 +1,5 @@ (* - * Copyright (C) 2006-2009 Citrix Systems Inc. + * Copyright (C) 2006-2010 Citrix Systems Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -25,9 +25,9 @@ val read_inventory: unit -> unit (** Clears the copy of the inventory file in memory and reads the file from disk. *) val reread_inventory: unit -> unit -(** Return the value of key [key] in the inventory file. Throws {!Missing_inventory_key} - * if the key does not exist. *) -val lookup: string -> string +(** Return the value of key [key] in the inventory file. If the key does not exist, + * returns the default if supplied, or throws {!Missing_inventory_key} otherwise. *) +val lookup: ?default:string -> string -> string (** Remove the key with the given name from the inventory file, if it exists. *) val remove: string -> unit @@ -40,6 +40,9 @@ val update: string -> string -> unit val parse_inventory_entry: string -> (string * string) option (* Keys defined in Geneva *) +(** UUID of the Host object in the xapi database *) +val _installation_uuid : string +(* (** Brand name, such as "XenServer" *) val _product_brand : string @@ -70,15 +73,12 @@ val _primary_disk : string (** Device path of backup partition *) val _backup_partition : string -(** UUID of the Host object in the xapi database *) -val _installation_uuid : string - (** Device path of the default SR used for local storage *) val _default_sr_physdevs : string (** Memory size of dom0 (?) *) val _dom0_mem : string - +*) (* Keys defined in Rio *) (** UUID of the control domain (dom0) *)