From 83cd558967845a885ef0ae792a8dd8b5113ad433 Mon Sep 17 00:00:00 2001 From: John Else Date: Wed, 6 Jul 2011 23:09:59 +0100 Subject: [PATCH] [CA-60540] Fix forced SR/VDI import. When doing a forced VM metadata import, xapi will now skip over any missing SRs and their VDIs instead of causing the import to fail. Signed-off-by: John Else --- ocaml/xapi/import.ml | 71 ++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/ocaml/xapi/import.ml b/ocaml/xapi/import.ml index 703e5d3b53..5156a8628a 100644 --- a/ocaml/xapi/import.ml +++ b/ocaml/xapi/import.ml @@ -331,12 +331,14 @@ let handle_sr __context config rpc session_id (state: state) (x: obj) : unit = let sr = Client.SR.get_by_uuid rpc session_id sr_record.API.sR_uuid in state.table <- (x.cls, x.id, Ref.string_of sr) :: state.table with e -> + let msg, fail = match sr_record.API.sR_content_type, config.force with + | "iso", _ -> "- will eject disk", false (* Will be handled specially in handle_vdi *) + | _, false -> "- this is fatal", true + | _, true -> "- skipping SR as import was forced", false + in warn "Failed to find SR with UUID: %s content-type: %s %s" - sr_record.API.sR_uuid sr_record.API.sR_content_type - (if sr_record.API.sR_content_type = "iso" then " will eject disk" else "-- this is fatal"); - if sr_record.API.sR_content_type = "iso" - then () (* this one will be handled specially in handle_vdi *) - else raise e (* fatal error *) + sr_record.API.sR_uuid sr_record.API.sR_content_type msg; + if fail then raise e end else begin if sr_record.API.sR_content_type = "iso" then () (* this one will be ejected *) @@ -373,35 +375,38 @@ let handle_vdi __context config rpc session_id (state: state) (x: obj) : unit = | _ -> warn "Found no ISO VDI with location = %s; attempting to eject" vdi_record.API.vDI_location end else begin - let sr = lookup vdi_record.API.vDI_SR state.table in - if config.vm_metadata_only then begin - (* Look up the existing VDI record by location *) - match List.filter (fun (_, vdir) -> - vdir.API.vDI_location = vdi_record.API.vDI_location && vdir.API.vDI_SR = sr) - (Client.VDI.get_all_records rpc session_id) with - | (vdi, _) :: [] -> - (* perfect, found exactly one *) - state.table <- (x.cls, x.id, Ref.string_of vdi) :: state.table - | (vdi, _) :: _ -> - (* hmm, wasn't expecting to have to choose! *) - warn "Found multiple VDIs with location = %s (location should be unique per-SR); choosing at random" vdi_record.API.vDI_location; + if exists vdi_record.API.vDI_SR state.table then begin + let sr = lookup vdi_record.API.vDI_SR state.table in + if config.vm_metadata_only then begin + (* Look up the existing VDI record by location *) + match List.filter (fun (_, vdir) -> + vdir.API.vDI_location = vdi_record.API.vDI_location && vdir.API.vDI_SR = sr) + (Client.VDI.get_all_records rpc session_id) with + | (vdi, _) :: [] -> + (* perfect, found exactly one *) + state.table <- (x.cls, x.id, Ref.string_of vdi) :: state.table + | (vdi, _) :: _ -> + (* hmm, wasn't expecting to have to choose! *) + warn "Found multiple VDIs with location = %s (location should be unique per-SR); choosing at random" vdi_record.API.vDI_location; + state.table <- (x.cls, x.id, Ref.string_of vdi) :: state.table + | _ -> + error "Found no VDI with location = %s: %s" vdi_record.API.vDI_location + (if config.force + then "ignoring error because '--force' is set" + else "treating as fatal and abandoning import"); + if not(config.force) + then raise (Api_errors.Server_error(Api_errors.vdi_location_missing, [ Ref.string_of sr; vdi_record.API.vDI_location ])) + end else begin + (* Make a new VDI for streaming data into; adding task-id to sm-config on VDI.create so SM backend can see this is an import *) + let task_id = Ref.string_of (Context.get_task_id __context) in + let sm_config = List.filter (fun (k,_)->k<>Xapi_globs.import_task) vdi_record.API.vDI_sm_config in + let sm_config = (Xapi_globs.import_task, task_id)::sm_config in + let vdi = Client.VDI.create_from_record rpc session_id { vdi_record with API.vDI_SR = sr; API.vDI_sm_config = sm_config } in + state.cleanup <- (fun __context rpc session_id -> Client.VDI.destroy rpc session_id vdi) :: state.cleanup; state.table <- (x.cls, x.id, Ref.string_of vdi) :: state.table - | _ -> - error "Found no VDI with location = %s: %s" vdi_record.API.vDI_location - (if config.force - then "ignoring error because '--force' is set" - else "treating as fatal and abandoning import"); - if not(config.force) - then raise (Api_errors.Server_error(Api_errors.vdi_location_missing, [ Ref.string_of sr; vdi_record.API.vDI_location ])) - end else begin - (* Make a new VDI for streaming data into; adding task-id to sm-config on VDI.create so SM backend can see this is an import *) - let task_id = Ref.string_of (Context.get_task_id __context) in - let sm_config = List.filter (fun (k,_)->k<>Xapi_globs.import_task) vdi_record.API.vDI_sm_config in - let sm_config = (Xapi_globs.import_task, task_id)::sm_config in - let vdi = Client.VDI.create_from_record rpc session_id { vdi_record with API.vDI_SR = sr; API.vDI_sm_config = sm_config } in - state.cleanup <- (fun __context rpc session_id -> Client.VDI.destroy rpc session_id vdi) :: state.cleanup; - state.table <- (x.cls, x.id, Ref.string_of vdi) :: state.table - end + end + end else + warn "Skipping VDI %s as its SR was not imported." vdi_record.API.vDI_uuid end