From e4949ecf6e98d26bd4fbf2bec7135c70a9563d31 Mon Sep 17 00:00:00 2001 From: BenjiReis Date: Thu, 28 Oct 2021 14:15:08 +0200 Subject: [PATCH] Add `ignore_vdis` to `VM.snapshot` method This allow to snapshot a VM and ignore some VDIs during the snapshot This can lead to a gain of time & space ignoring non essential data See: https://github.com/xapi-project/xen-api/issues/4551 Signed-off-by: BenjiReis --- ocaml/idl/datamodel_vm.ml | 8 +++++--- ocaml/xapi-cli-server/cli_operations.ml | 2 +- ocaml/xapi/message_forwarding.ml | 6 +++--- ocaml/xapi/xapi_vm.ml | 4 ++-- ocaml/xapi/xapi_vm.mli | 6 +++++- ocaml/xapi/xapi_vm_clone.ml | 15 ++++++++++++++- ocaml/xapi/xapi_vm_clone.mli | 1 + ocaml/xapi/xapi_vm_snapshot.ml | 3 ++- 8 files changed, 33 insertions(+), 12 deletions(-) diff --git a/ocaml/idl/datamodel_vm.ml b/ocaml/idl/datamodel_vm.ml index 55e739d860d..627c2738f60 100644 --- a/ocaml/idl/datamodel_vm.ml +++ b/ocaml/idl/datamodel_vm.ml @@ -244,12 +244,14 @@ let power_behaviour = let snapshot = call ~name:"snapshot" + ~lifecycle:[ Published, rel_orlando, ""; Changed, rel_next, "Add `ignore_vdis` params to ignore some VDIs during a snapshot" ] ~in_product_since: rel_orlando ~doc:"Snapshots the specified VM, making a new VM. Snapshot automatically exploits the capabilities of the underlying storage repository in which the VM's disk images are stored (e.g. Copy on Write)." ~result: (Ref _vm, "The reference of the newly created VM.") - ~params:[ - Ref _vm, "vm", "The VM to be snapshotted"; - String, "new_name", "The name of the snapshotted VM" + ~versioned_params: + [{param_type=Ref _vm; param_name="vm"; param_doc="The VM to be snapshotted"; param_release=orlando_release; param_default=None}; + {param_type=String; param_name="new_name"; param_doc="The name of the snapshotted VM"; param_release=orlando_release; param_default=Some (VString "")}; + {param_type=Set(Ref _vdi); param_name="ignore_vdis"; param_doc="A list of VDIs to ignore for the snapshot"; param_release=next_release; param_default=None}; ] ~errs:[Api_errors.vm_bad_power_state; Api_errors.sr_full; Api_errors.operation_not_allowed] ~allowed_roles:_R_VM_POWER_ADMIN diff --git a/ocaml/xapi-cli-server/cli_operations.ml b/ocaml/xapi-cli-server/cli_operations.ml index 5b2396a4cb0..680508b2b3c 100644 --- a/ocaml/xapi-cli-server/cli_operations.ml +++ b/ocaml/xapi-cli-server/cli_operations.ml @@ -4094,7 +4094,7 @@ let vm_clone_aux clone_op cloned_string printer include_template_vms rpc let vm_clone printer = vm_clone_aux Client.VM.clone "Cloned " printer true let vm_snapshot printer = - vm_clone_aux Client.VM.snapshot "Snapshotted " printer false + vm_clone_aux (Client.VM.snapshot ~ignore_vdis:[]) "Snapshotted " printer false let vm_snapshot_with_quiesce printer = vm_clone_aux Client.VM.snapshot_with_quiesce "Snapshotted" printer false diff --git a/ocaml/xapi/message_forwarding.ml b/ocaml/xapi/message_forwarding.ml index c2b7ee979f6..be28f5a8002 100644 --- a/ocaml/xapi/message_forwarding.ml +++ b/ocaml/xapi/message_forwarding.ml @@ -1577,10 +1577,10 @@ functor ~value:transportable_snapshot_id (* almost a copy of the clone function *) - let snapshot ~__context ~vm ~new_name = + let snapshot ?(ignore_vdis = []) ~__context ~vm ~new_name = info "VM.snapshot: VM = '%s'; new_name = '%s'" (vm_uuid ~__context vm) new_name ; - let local_fn = Local.VM.snapshot ~vm ~new_name in + let local_fn = Local.VM.snapshot ~vm ~new_name ~ignore_vdis in (* We mark the VM as snapshoting. We don't mark the disks; the implementation of the snapshot uses the API *) (* to snapshot and lock the individual VDIs. We don't give any atomicity guarantees here but we do prevent *) (* disk corruption. *) @@ -1589,7 +1589,7 @@ functor (fun () -> forward_to_access_srs ~local_fn ~__context ~vm (fun session_id rpc -> - Client.VM.snapshot rpc session_id vm new_name + Client.VM.snapshot rpc session_id vm new_name ignore_vdis ) ) in diff --git a/ocaml/xapi/xapi_vm.ml b/ocaml/xapi/xapi_vm.ml index f89088eb34d..f37a4e923fb 100644 --- a/ocaml/xapi/xapi_vm.ml +++ b/ocaml/xapi/xapi_vm.ml @@ -757,9 +757,9 @@ let clone ~__context ~vm ~new_name = (* We do call wait_in_line for snapshot and snapshot_with_quiesce because the locks are taken at *) (* the VBD level (with pause/unpause mechanism *) -let snapshot ~__context ~vm ~new_name = +let snapshot ?(ignore_vdis = []) ~__context ~vm ~new_name = TaskHelper.set_cancellable ~__context ; - Xapi_vm_snapshot.snapshot ~__context ~vm ~new_name + Xapi_vm_snapshot.snapshot ~__context ~vm ~new_name ~ignore_vdis (* As we will destroy the domain ourself, we grab the vm_lock here in order to tell the event thread to *) (* do not look at this domain. The message forwarding layer already checked that the VM reference we *) diff --git a/ocaml/xapi/xapi_vm.mli b/ocaml/xapi/xapi_vm.mli index ae997dab541..3ceb1b4697b 100644 --- a/ocaml/xapi/xapi_vm.mli +++ b/ocaml/xapi/xapi_vm.mli @@ -211,7 +211,11 @@ val clone : __context:Context.t -> vm:API.ref_VM -> new_name:string -> [`VM] Ref.t val snapshot : - __context:Context.t -> vm:API.ref_VM -> new_name:string -> [`VM] Ref.t + ?ignore_vdis:[`VDI] API.Ref.t list + -> __context:Context.t + -> vm:API.ref_VM + -> new_name:string + -> [`VM] Ref.t val revert : __context:Context.t -> snapshot:[`VM] Ref.t -> unit diff --git a/ocaml/xapi/xapi_vm_clone.ml b/ocaml/xapi/xapi_vm_clone.ml index 85bc84a6838..5e2d36aa2b9 100644 --- a/ocaml/xapi/xapi_vm_clone.ml +++ b/ocaml/xapi/xapi_vm_clone.ml @@ -408,7 +408,8 @@ let make_driver_params () = [(Constants._sm_epoch_hint, Uuid.to_string (Uuid.make_uuid ()))] (* NB this function may be called when the VM is suspended for copy/clone operations. Snapshot can be done in live.*) -let clone ?snapshot_info_record disk_op ~__context ~vm ~new_name = +let clone ?snapshot_info_record ?(ignore_vdis = []) disk_op ~__context ~vm + ~new_name = Helpers.call_api_functions ~__context (fun rpc session_id -> let task_id = Ref.string_of (Context.get_task_id __context) in let vbds = Db.VM.get_VBDs ~__context ~self:vm in @@ -429,6 +430,18 @@ let clone ?snapshot_info_record disk_op ~__context ~vm ~new_name = let is_a_snapshot = disk_op = Disk_op_snapshot || disk_op = Disk_op_checkpoint in + + let vbds = + if is_a_snapshot then + List.filter + (fun x -> + not List.mem (Db.VBD.get_VDI ~__context ~self:x) ignore_vdis + ) + vbds + else + vbds + in + (* Check licence permission before copying disks, since the copy can take a long time. * We always allow snapshotting a VM, but check before clone/copy of an existing snapshot or template. *) if Db.VM.get_has_vendor_device ~__context ~self:vm && not is_a_snapshot diff --git a/ocaml/xapi/xapi_vm_clone.mli b/ocaml/xapi/xapi_vm_clone.mli index df39a09c53e..7105a98106a 100644 --- a/ocaml/xapi/xapi_vm_clone.mli +++ b/ocaml/xapi/xapi_vm_clone.mli @@ -57,6 +57,7 @@ val clone_single_vdi : (* NB this function may be called when the VM is suspended for copy/clone operations. Snapshot can be done in live.*) val clone : ?snapshot_info_record:(string * string) list + -> ?ignore_vdis:[`VDI] API.Ref.t list -> disk_op_t -> __context:Context.t -> vm:[`VM] API.Ref.t diff --git a/ocaml/xapi/xapi_vm_snapshot.ml b/ocaml/xapi/xapi_vm_snapshot.ml index fcff205aa78..abc6100f52c 100644 --- a/ocaml/xapi/xapi_vm_snapshot.ml +++ b/ocaml/xapi/xapi_vm_snapshot.ml @@ -25,12 +25,13 @@ open D (*************************************************************************************************) (* Crash-consistant snapshot *) (*************************************************************************************************) -let snapshot ~__context ~vm ~new_name = +let snapshot ?(ignore_vdis = []) ~__context ~vm ~new_name = debug "Snapshot: begin" ; TaskHelper.set_cancellable ~__context ; Xapi_vmss.show_task_in_xencenter ~__context ~vm ; let res = Xapi_vm_clone.clone Xapi_vm_clone.Disk_op_snapshot ~__context ~vm ~new_name + ~ignore_vdis in debug "Snapshot: end" ; res