From 2ac69bbbd428a8f8a5d9a8a5c5870248eb9b3fa9 Mon Sep 17 00:00:00 2001 From: David Scott Date: Wed, 3 Jun 2015 20:12:53 +0000 Subject: [PATCH 1/3] xenvmd: when shutting down, flush the LVM redo log This will allow us to downgrade the labels if we want. Signed-off-by: David Scott --- xenvmd/xenvmd.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xenvmd/xenvmd.ml b/xenvmd/xenvmd.ml index bdad97f..31c887c 100644 --- a/xenvmd/xenvmd.ml +++ b/xenvmd/xenvmd.ml @@ -430,6 +430,8 @@ module VolumeManager = struct (fun (host, _) -> Host.disconnect host ) !from_LVMs + >>= fun () -> + sync () end module FreePool = struct From a8ef604224f2f43f84a655f583f97b36f3104b3a Mon Sep 17 00:00:00 2001 From: David Scott Date: Wed, 3 Jun 2015 20:13:34 +0000 Subject: [PATCH 2/3] Add `xenvm lvchange --offline` to attach a device without a running xenvmd This will allow us to attach XenServer HA 'static' VDIs. Fixes #116 Signed-off-by: David Scott --- xenvm/lvchange.ml | 34 ++++++++++++++++++++++++---------- xenvm/lvcreate.ml | 2 +- xenvm/vgchange.ml | 2 +- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/xenvm/lvchange.ml b/xenvm/lvchange.ml index 6582f80..659d6cd 100644 --- a/xenvm/lvchange.ml +++ b/xenvm/lvchange.ml @@ -26,18 +26,28 @@ let activate vg lv local_device = Devmapper.mknod name path 0o0600; return () -let lvchange_activate copts vg_name lv_name physical_device = +let lvchange_activate copts vg_name lv_name physical_device (offline:bool) : unit = let open Xenvm_common in Lwt_main.run ( get_vg_info_t copts vg_name >>= fun info -> set_uri copts info; - Client.get_lv ~name:lv_name >>= fun (vg, lv) -> - if vg.Lvm.Vg.name <> vg_name then failwith "Invalid URI"; - let local_device = match (info,physical_device) with + let local_device : string = match (info,physical_device) with | _, Some d -> d (* cmdline overrides default for the VG *) | Some info, None -> info.local_device (* If we've got a default, use that *) - | None, None -> failwith "Need to know the local device!" - in + | None, None -> failwith "Need to know the local device!" in + ( if offline then begin + with_block local_device + (fun x -> + let module Vg_IO = Lvm.Vg.Make(Log)(Block)(Time)(Clock) in + Vg_IO.connect [ x ] `RO >>|= fun vg -> + match Vg_IO.find vg lv_name with + | None -> failwith (Printf.sprintf "Failed to find LV %s" lv_name) + | Some vol -> + return (Vg_IO.metadata_of vg, Vg_IO.Volume.metadata_of vol) + ) + end else Client.get_lv ~name:lv_name + ) >>= fun (vg, lv) -> + if vg.Lvm.Vg.name <> vg_name then failwith "Invalid URI"; activate vg lv local_device ) @@ -105,10 +115,10 @@ let lvchange_refresh copts vg_name lv_name physical_device = reload vg lv local_device ) -let lvchange copts (vg_name,lv_name_opt) physical_device action perm refresh add_tag del_tag = +let lvchange copts (vg_name,lv_name_opt) physical_device action perm refresh add_tag del_tag offline = let lv_name = match lv_name_opt with Some l -> l | None -> failwith "Need LV name" in (match action with - | Some Activate -> lvchange_activate copts vg_name lv_name physical_device + | Some Activate -> lvchange_activate copts vg_name lv_name physical_device offline | Some Deactivate -> lvchange_deactivate copts vg_name lv_name | None -> ()); (if refresh then lvchange_refresh copts vg_name lv_name physical_device); @@ -158,12 +168,16 @@ let add_tag_arg = let del_tag_arg = let doc = "Remove the given tag from the LV" in Arg.(value & opt (some string) None & info ["deltag"] ~docv:"DELTAG" ~doc) - + +let offline_arg = + let doc = "Assume xenvmd is offline and read metadata from the disk" in + Arg.(value & flag & info [ "offline" ] ~docv:"OFFLINE" ~doc) + let lvchange_cmd = let doc = "Change the attributes of a logical volume" in let man = [ `S "DESCRIPTION"; `P "lvchange allows you to change the attributes of a logical volume including making them known to the kernel ready for use." ] in - Term.(pure lvchange $ Xenvm_common.copts_t $ Xenvm_common.name_arg $ Xenvm_common.physical_device_arg $ action_arg $ perm_arg $ refresh_arg $ add_tag_arg $ del_tag_arg), + Term.(pure lvchange $ Xenvm_common.copts_t $ Xenvm_common.name_arg $ Xenvm_common.physical_device_arg $ action_arg $ perm_arg $ refresh_arg $ add_tag_arg $ del_tag_arg $ offline_arg), Term.info "lvchange" ~sdocs:"COMMON OPTIONS" ~doc ~man diff --git a/xenvm/lvcreate.ml b/xenvm/lvcreate.ml index 640b8c5..11f6cb2 100644 --- a/xenvm/lvcreate.ml +++ b/xenvm/lvcreate.ml @@ -35,7 +35,7 @@ let lvcreate copts lv_name real_size percent_size tags vg_name = | e -> fail e ) >>= fun () -> return info) in - match info with | Some i -> Lvchange.lvchange_activate copts vg_name lv_name (Some i.local_device) | None -> () + match info with | Some i -> Lvchange.lvchange_activate copts vg_name lv_name (Some i.local_device) false | None -> () let lv_name_arg = let doc = "Gives the name of the LV to be created. This must be unique within the volume group. " in diff --git a/xenvm/vgchange.ml b/xenvm/vgchange.ml index 9176525..62ae12b 100644 --- a/xenvm/vgchange.ml +++ b/xenvm/vgchange.ml @@ -13,7 +13,7 @@ let vgchange copts (vg_name,_) physical_device action = let names = List.map (fun (_, lv) -> lv.Lvm.Lv.name) @@ Lvm.Vg.LVs.bindings vg.Lvm.Vg.lvs in Lwt_list.iter_s (fun lv_name -> (match action with - | Some Activate -> Lvchange.lvchange_activate copts vg_name lv_name physical_device + | Some Activate -> Lvchange.lvchange_activate copts vg_name lv_name physical_device false | Some Deactivate -> Lvchange.lvchange_deactivate copts vg_name lv_name | None -> ()); return () From 9b92df331d33943d72c4cb4183edf45ce1dd4227 Mon Sep 17 00:00:00 2001 From: David Scott Date: Wed, 3 Jun 2015 20:14:07 +0000 Subject: [PATCH 3/3] test: add a test for 'lvchange --offline' Signed-off-by: David Scott --- test/test.ml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/test.ml b/test/test.ml index bf19409..5311958 100644 --- a/test/test.ml +++ b/test/test.ml @@ -47,6 +47,27 @@ let vgs_offline = ) ) +let lvchange_offline = + "lvchange vg/lv --offline: check that we can activate volumes offline" >:: + fun () -> + with_temp_file (fun filename' -> + with_loop_device filename' (fun loop -> + xenvm [ "vgcreate"; vg; loop ] |> ignore_string; + xenvm [ "set-vg-info"; "--pvpath"; loop; "-S"; "/tmp/xenvmd"; vg; "--local-allocator-path"; "/tmp/xenvm-local-allocator"; "--uri"; "file://local/services/xenvmd/"^vg ] |> ignore_string; + file_of_string "test.xenvmd.conf" ("( (listenPort ()) (listenPath (Some \"/tmp/xenvmd\")) (host_allocation_quantum 128) (host_low_water_mark 8) (vg "^vg^") (devices ("^loop^")))"); + xenvmd [ "--config"; "./test.xenvmd.conf"; "--daemon" ] |> ignore_string; + Xenvm_client.Rpc.uri := "file://local/services/xenvmd/" ^ vg; + Xenvm_client.unix_domain_socket_path := "/tmp/xenvmd"; + finally + (fun () -> + xenvm [ "lvcreate"; "-n"; "test"; "-L"; "3"; vg ] |> ignore_string; + ) (fun () -> + xenvm [ "shutdown"; "/dev/"^vg ] |> ignore_string + ); + xenvm [ "lvchange"; "-ay"; vg ^ "/test"; "--offline" ] |> ignore_string; + ) + ) + let pvremove = "pvremove : check that we can make a PV unrecognisable" >:: (fun () -> @@ -69,6 +90,7 @@ let pvremove = let no_xenvmd_suite = "Commands which should work without xenvmd" >::: [ vgcreate; vgs_offline; + lvchange_offline; pvremove; ]