# HG changeset patch
# User Jon Ludlam <Jonathan.Ludlam@xxxxxxxxxxxxx>
# Date 1285345650 -3600
# Node ID 243ef81d48f72655dc409b127eb39785e4a5f5c0
# Parent e8da99c62c3e9ae692285a3b5d016547bc503192
Local disk caching API work. Added pool-level API calls to enable/disable
caching, host-level API calls for same, per VDI on_boot and allow_caching
parameters, and CLI calls for all.
Signed-off-by: Jon Ludlam <Jonathan.Ludlam@xxxxxxxxxxxxx>
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/client_records/record_util.ml
--- a/ocaml/client_records/record_util.ml
+++ b/ocaml/client_records/record_util.ml
@@ -324,6 +324,11 @@
let i642sm_to_string sep x =
String.concat sep (List.map (fun (a,b) -> Printf.sprintf "%Ld %s" a b) x)
+let on_boot_to_string onboot =
+ match onboot with
+ | `reset -> "reset"
+ | `persist -> "persist"
+
(** Parse a string which might have a units suffix on the end *)
let bytes_of_string field x =
let isdigit c = c >= '0' && c <= '9' in
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/client_records/records.ml
--- a/ocaml/client_records/records.ml
+++ b/ocaml/client_records/records.ml
@@ -1057,6 +1057,7 @@
make_field ~name:"power-on-mode" ~get:(fun () -> (x
()).API.host_power_on_mode) ();
make_field ~name:"power-on-config" ~get:(fun () ->
Record_util.s2sm_to_string "; " (x ()).API.host_power_on_config)
~get_map:(fun () -> (x ()).API.host_power_on_config) ();
+ make_field ~name:"local-cache-sr" ~get:(fun () -> get_uuid_from_ref (x
()).API.host_local_cache_sr) ();
]}
let vdi_record rpc session_id vdi =
@@ -1113,6 +1114,10 @@
~get_map:(fun () -> (x ()).API.vDI_xenstore_data) ();
make_field ~name:"sm-config" ~get:(fun () -> Record_util.s2sm_to_string ";
" (x ()).API.vDI_sm_config)
~get_map:(fun () -> (x ()).API.vDI_sm_config) ();
+ make_field ~name:"on-boot" ~get:(fun () ->
Record_util.on_boot_to_string (x ()).API.vDI_on_boot)
+ ~set:(fun onboot -> Client.VDI.set_on_boot rpc session_id vdi
(match onboot with "persist" -> `persist | "reset" -> `reset)) ();
+ make_field ~name:"allow-caching" ~get:(fun () -> string_of_bool
(x ()).API.vDI_allow_caching)
+ ~set:(fun b -> Client.VDI.set_allow_caching rpc session_id vdi
(bool_of_string b)) ();
]}
let vbd_record rpc session_id vbd =
@@ -1272,6 +1277,7 @@
make_field ~name:"sm-config" ~get:(fun () -> Record_util.s2sm_to_string ";
" (x ()).API.sR_sm_config)
~get_map:(fun () -> (x ()).API.sR_sm_config) ();
make_field ~name:"blobs" ~get:(fun () -> Record_util.s2brm_to_string
get_uuid_from_ref "; " (x ()).API.sR_blobs) ();
+ make_field ~name:"local-cache-enabled" ~get:(fun () -> string_of_bool
(x ()).API.sR_local_cache_enabled) ();
]}
let pbd_record rpc session_id pbd =
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/idl/api_errors.ml
--- a/ocaml/idl/api_errors.ml
+++ b/ocaml/idl/api_errors.ml
@@ -62,6 +62,9 @@
let host_is_slave = "HOST_IS_SLAVE"
let host_name_invalid = "HOST_NAME_INVALID"
let host_has_resident_vms = "HOST_HAS_RESIDENT_VMS"
+let hosts_failed_to_enable_caching = "HOSTS_FAILED_TO_ENABLE_CACHING"
+let hosts_failed_to_disable_caching = "HOSTS_FAILED_TO_DISABLE_CACHING"
+let host_cannot_see_SR = "HOST_CANNOT_SEE_SR"
(* Host errors which explain why the host is in emergency mode *)
let host_its_own_slave = "HOST_ITS_OWN_SLAVE"
@@ -181,6 +184,7 @@
let vdi_incompatible_type = "VDI_INCOMPATIBLE_TYPE"
let vdi_not_managed = "VDI_NOT_MANAGED"
let vdi_io_error = "VDI_IO_ERROR"
+let vdi_on_boot_mode_incompatable_with_operation =
"VDI_ON_BOOT_MODE_INCOMPATABLE_WITH_OPERATION"
let cannot_create_state_file = "CANNOT_CREATE_STATE_FILE"
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/idl/datamodel.ml
--- a/ocaml/idl/datamodel.ml
+++ b/ocaml/idl/datamodel.ml
@@ -3653,6 +3653,28 @@
~hide_from_docs:true
()
+let host_enable_local_storage_caching = call ~flags:[`Session]
+ ~name:"enable_local_storage_caching"
+ ~in_product_since:rel_cowley
+ ~doc:"Enable the use of a local SR for caching purposes"
+ ~params:[
+ Ref _host, "host", "The host";
+ Ref _sr, "sr", "The SR to use as a local cache"
+ ]
+ ~allowed_roles:_R_POOL_OP
+ ()
+
+let host_disable_local_storage_caching = call ~flags:[`Session]
+ ~name:"disable_local_storage_caching"
+ ~in_product_since:rel_cowley
+ ~doc:"Disable the use of a local SR for caching purposes"
+ ~params:[
+ Ref _host, "host", "The host"
+ ]
+ ~allowed_roles:_R_POOL_OP
+ ()
+
+
(** Hosts *)
let host =
create_obj ~in_db:true ~in_product_since:rel_rio
~in_oss_since:oss_since_303 ~internal_deprecated_since:None
~persist:PersistEverything ~gen_constructor_destructor:false ~name:_host
~descr:"A physical host" ~gen_events:true
@@ -3726,6 +3748,8 @@
host_set_cpu_features;
host_reset_cpu_features;
host_reset_networking;
+ host_enable_local_storage_caching;
+ host_disable_local_storage_caching;
]
~contents:
([ uid _host;
@@ -3767,7 +3791,7 @@
field ~qualifier:DynamicRO ~in_product_since:rel_midnight_ride
~default_value:(Some (VMap [])) ~ty:(Map (String,String)) "bios_strings" "BIOS
strings";
field ~qualifier:DynamicRO ~in_product_since:rel_midnight_ride
~default_value:(Some (VString "")) ~ty:String "power_on_mode" "The power on
mode";
field ~qualifier:DynamicRO ~in_product_since:rel_midnight_ride
~default_value:(Some (VMap [])) ~ty:(Map(String, String)) "power_on_config"
"The power on config";
-
+ field ~qualifier:DynamicRO ~in_product_since:rel_cowley
~default_value:(Some (VRef (Ref.string_of Ref.null))) ~ty:(Ref _sr)
"local_cache_sr" "The SR that is used as a local cache";
])
()
@@ -4430,6 +4454,7 @@
field ~ty:Bool ~qualifier:DynamicRO ~in_oss_since:None
~internal_only:true "default_vdi_visibility" "";
field ~in_oss_since:None ~ty:(Map(String, String))
~in_product_since:rel_miami ~qualifier:RW "sm_config" "SM dependent data"
~default_value:(Some (VMap []));
field ~qualifier:DynamicRO ~in_product_since:rel_orlando
~ty:(Map(String, Ref _blob)) ~default_value:(Some (VMap [])) "blobs" "Binary
blobs associated with this SR";
+ field ~qualifier:DynamicRO ~in_product_since:rel_cowley ~ty:Bool
~default_value:(Some (VBool false)) "local_cache_enabled" "True if this SR is
assigned to be the local cache for its host";
])
()
@@ -4665,6 +4690,31 @@
~allowed_roles:_R_VM_ADMIN
()
+let on_boot = Enum ("on_boot", [ "reset", "The VDI will be reset to the state
it was in at the last clone";
+"persist", "The VDIs contents are persistent" ])
+
+ let vdi_set_on_boot = call
+ ~name:"set_on_boot"
+ ~in_oss_since:None
+ ~in_product_since:rel_cowley
+ ~params:[Ref _vdi, "self", "The VDI to modify";
+ on_boot, "value", "The value to set"]
+ ~doc:"Set the value of the on_boot parameter"
+ ~hide_from_docs:true
+ ~allowed_roles:_R_VM_ADMIN
+ ()
+
+let vdi_set_allow_caching = call
+ ~name:"set_allow_caching"
+ ~in_oss_since:None
+ ~in_product_since:rel_cowley
+ ~params:[Ref _vdi, "self", "The VDI to modify";
+ Bool, "value", "The value to set"]
+ ~doc:"Set the value of the allow_caching parameter"
+ ~hide_from_docs:true
+ ~allowed_roles:_R_VM_ADMIN
+ ()
+
(** A virtual disk *)
let vdi =
create_obj ~in_db:true ~in_product_since:rel_rio
~in_oss_since:oss_since_303 ~internal_deprecated_since:None
~persist:PersistEverything ~gen_constructor_destructor:true ~name:_vdi
~descr:"A virtual disk image"
@@ -4685,6 +4735,8 @@
vdi_set_virtual_size;
vdi_set_physical_utilisation;
vdi_generate_config;
+ vdi_set_on_boot;
+ vdi_set_allow_caching;
]
~contents:
([ uid _vdi;
@@ -4713,6 +4765,9 @@
field ~in_product_since:rel_orlando
~qualifier:DynamicRO ~ty:(Set (Ref _vdi)) "snapshots" "List pointing
to all the VDIs snapshots.";
field ~in_product_since:rel_orlando ~default_value:(Some (VDateTime
Date.never)) ~qualifier:DynamicRO ~ty:DateTime "snapshot_time"
"Date/time when this snapshot was created.";
field ~writer_roles:_R_VM_OP ~in_product_since:rel_orlando
~default_value:(Some (VSet [])) ~ty:(Set String) "tags" "user-specified tags
for categorization purposes";
+ field ~in_product_since:rel_cowley ~qualifier:DynamicRO ~ty:Bool
~default_value:(Some (VBool false)) "allow_caching" "true if this VDI is to be
cached in the local cache SR";
+ field ~in_product_since:rel_cowley ~qualifier:DynamicRO ~ty:on_boot
~default_value:(Some (VEnum "persist")) "on_boot" "The behaviour of this VDI on
a VM boot";
+
])
()
@@ -5294,6 +5349,24 @@
~result:(String, "An XMLRPC result")
()
+let pool_enable_local_storage_caching = call
+ ~name:"enable_local_storage_caching"
+ ~in_oss_since:None
+ ~in_product_since:rel_cowley
+ ~params:[Ref _pool, "self", "Reference to the pool"]
+ ~doc:"This call attempts to enable pool-wide local storage caching"
+ ~allowed_roles:_R_POOL_OP
+ ()
+
+let pool_disable_local_storage_caching = call
+ ~name:"disable_local_storage_caching"
+ ~in_oss_since:None
+ ~in_product_since:rel_cowley
+ ~params:[Ref _pool, "self", "Reference to the pool"]
+ ~doc:"This call disables pool-wide local storage caching"
+ ~allowed_roles:_R_POOL_OP
+ ()
+
(** A pool class *)
let pool =
create_obj
@@ -5356,6 +5429,8 @@
; pool_audit_log_append
; pool_set_vswitch_controller
; pool_test_archive_target
+ ; pool_enable_local_storage_caching
+ ; pool_disable_local_storage_caching
]
~contents:
[uid ~in_oss_since:None _pool
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/cli_frontend.ml
--- a/ocaml/xapi/cli_frontend.ml
+++ b/ocaml/xapi/cli_frontend.ml
@@ -450,6 +450,42 @@
flags=[Host_selectors];
};
+ "host-enable-local-storage-caching",
+ {
+ reqd=["sr-uuid"];
+ optn=[];
+ help="Enable local storage caching on the specified host";
+ implementation=No_fd
Cli_operations.host_enable_local_storage_caching;
+ flags=[Host_selectors];
+ };
+
+ "host-disable-local-storage-caching",
+ {
+ reqd=[];
+ optn=[];
+ help="Disable local storage caching on the specified host";
+ implementation=No_fd
Cli_operations.host_disable_local_storage_caching;
+ flags=[Host_selectors];
+ };
+
+ "pool-enable-local-storage-caching",
+ {
+ reqd=["uuid"];
+ optn=[];
+ help="Enable local storage caching across the pool";
+ implementation=No_fd
Cli_operations.pool_enable_local_storage_caching;
+ flags=[];
+ };
+
+ "pool-disable-local-storage-caching",
+ {
+ reqd=["uuid"];
+ optn=[];
+ help="Disable local storage caching across the pool";
+ implementation=No_fd
Cli_operations.pool_disable_local_storage_caching;
+ flags=[];
+ };
+
"host-shutdown",
{
reqd=[];
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/cli_operations.ml
--- a/ocaml/xapi/cli_operations.ml
+++ b/ocaml/xapi/cli_operations.ml
@@ -3338,6 +3338,23 @@
in
ignore(do_host_op rpc session_id op params [])
+let host_enable_local_storage_caching printer rpc session_id params =
+ ignore(do_host_op rpc session_id (fun _ host ->
+ let sr_uuid = List.assoc "sr-uuid" params in
+ let sr = Client.SR.get_by_uuid rpc session_id sr_uuid in
+ Client.Host.enable_local_storage_caching rpc session_id
(host.getref ()) sr
+ ) params ["sr-uuid"])
+
+let host_disable_local_storage_caching printer rpc session_id params =
+ ignore(do_host_op rpc session_id (fun _ host ->
Client.Host.disable_local_storage_caching rpc session_id (host.getref ()))
params [])
+
+let pool_enable_local_storage_caching printer rpc session_id params =
+ let pool = List.hd (Client.Pool.get_all rpc session_id) in
+ Client.Pool.enable_local_storage_caching rpc session_id pool
+
+let pool_disable_local_storage_caching printer rpc session_id params =
+ let pool = List.hd (Client.Pool.get_all rpc session_id) in
+ Client.Pool.disable_local_storage_caching rpc session_id pool
let host_set_power_on_mode printer rpc session_id params =
let power_on_mode = List.assoc "power-on-mode" params in
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/message_forwarding.ml
--- a/ocaml/xapi/message_forwarding.ml
+++ b/ocaml/xapi/message_forwarding.ml
@@ -2184,6 +2184,14 @@
let reset_networking ~__context ~host =
info "Host.reset_networking: host = '%s'" (host_uuid ~__context host);
Local.Host.reset_networking ~__context ~host
+
+ let enable_local_storage_caching ~__context ~host ~sr =
+ let local_fn = Local.Host.enable_local_storage_caching ~host
~sr in
+ do_op_on ~local_fn ~__context ~host (fun session_id rpc ->
Client.Host.enable_local_storage_caching rpc session_id host sr)
+
+ let disable_local_storage_caching ~__context ~host =
+ let local_fn = Local.Host.disable_local_storage_caching ~host in
+ do_op_on ~local_fn ~__context ~host (fun session_id rpc ->
Client.Host.disable_local_storage_caching rpc session_id host)
end
module Host_crashdump = struct
@@ -2793,6 +2801,24 @@
Sm.assert_session_has_internal_sr_access ~__context ~sr;
Local.VDI.set_physical_utilisation ~__context ~self ~value
+ let ensure_vdi_not_on_running_vm ~__context ~self =
+ let vbds = Db.VDI.get_VBDs ~__context ~self in
+ List.iter (fun vbd ->
+ let vm = Db.VBD.get_VM ~__context ~self:vbd in
+ let state = Db.VM.get_power_state ~__context ~self:vm in
+ match state with
+ | `Halted -> ()
+ | _ -> raise
(Api_errors.Server_error(Api_errors.vm_bad_power_state,
+ [Ref.string_of vm; "halted";
Record_util.power_to_string state]))) vbds
+
+ let set_on_boot ~__context ~self ~value =
+ ensure_vdi_not_on_running_vm ~__context ~self;
+ Local.VDI.set_on_boot ~__context ~self ~value
+
+ let set_allow_caching ~__context ~self ~value =
+ ensure_vdi_not_on_running_vm ~__context ~self;
+ Local.VDI.set_allow_caching ~__context ~self ~value
+
(* know sr so just use SR forwarding policy direct here *)
let create ~__context ~name_label ~name_description ~sR ~virtual_size
~_type ~sharable ~read_only ~other_config ~xenstore_data ~sm_config ~tags =
info "VDI.create: SR = '%s'; name label = '%s'" (sr_uuid ~__context sR)
name_label;
@@ -2912,7 +2938,7 @@
(fun () ->
forward_vdi_op ~local_fn ~__context ~self:vdi
(fun session_id rpc -> Client.VDI.force_unlock rpc session_id vdi))
-
+
end
module VBD = struct
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/sm_exec.ml
--- a/ocaml/xapi/sm_exec.ml
+++ b/ocaml/xapi/sm_exec.ml
@@ -57,10 +57,14 @@
vdi_ref: API.ref_VDI option;
vdi_location: string option;
vdi_uuid: string option;
+ vdi_on_boot: string option;
+ vdi_allow_caching : string option;
(* Reference to the task which performs the call *)
subtask_of: API.ref_task option;
+ local_cache_sr: string option;
+
cmd: string;
args: string list;
}
@@ -73,6 +77,10 @@
then vdi_location
else may (fun self -> Db.VDI.get_location ~__context ~self) vdi_ref in
let vdi_uuid = may (fun self -> Db.VDI.get_uuid ~__context ~self)
vdi_ref in
+ let vdi_on_boot = may (fun self ->
+ match Db.VDI.get_on_boot ~__context ~self with `persist ->
"persist" | `reset -> "reset") vdi_ref in
+ let vdi_allow_caching = may (fun self -> string_of_bool
(Db.VDI.get_allow_caching ~__context ~self)) vdi_ref in
+ let local_cache_sr = try Some (Db.SR.get_uuid ~__context
~self:(Db.Host.get_local_cache_sr ~__context ~self:(Helpers.get_localhost
__context))) with _ -> None in
let sr_uuid = may (fun self -> Db.SR.get_uuid ~__context ~self) sr_ref
in
{ host_ref = !Xapi_globs.localhost_ref;
session_ref = None; (* filled in at the last minute *)
@@ -85,8 +93,11 @@
vdi_ref = vdi_ref;
vdi_location = vdi_location;
vdi_uuid = vdi_uuid;
+ vdi_on_boot = vdi_on_boot;
+ vdi_allow_caching = vdi_allow_caching;
new_uuid = new_uuid;
subtask_of = subtask_of;
+ local_cache_sr = local_cache_sr;
cmd = cmd;
args = args
})
@@ -108,13 +119,15 @@
let vdi_ref = default [] (may (fun x -> [ "vdi_ref", XMLRPC.To.string
(Ref.string_of x) ]) call.vdi_ref) in
let vdi_location = default [] (may (fun x -> [ "vdi_location",
XMLRPC.To.string x ]) call.vdi_location) in
let vdi_uuid = default [] (may (fun x -> [ "vdi_uuid", XMLRPC.To.string x ])
call.vdi_uuid) in
+ let vdi_on_boot = default [] (may (fun x -> [ "vdi_on_boot",
XMLRPC.To.string x ]) call.vdi_on_boot) in
+ let vdi_allow_caching = default [] (may (fun x -> [ "vdi_allow_caching",
XMLRPC.To.string x ]) call.vdi_allow_caching) in
let new_uuid = default [] (may (fun x -> [ "new_uuid", XMLRPC.To.string x ])
call.new_uuid) in
let driver_params = default [] (may (fun x -> [ "driver_params", kvpairs x
]) call.driver_params) in
let vdi_sm_config = default [] (may (fun x -> [ "vdi_sm_config", kvpairs x
]) call.vdi_sm_config) in
let subtask_of = default [] (may (fun x -> [ "subtask_of", XMLRPC.To.string
(Ref.string_of x) ]) call.subtask_of) in
-
- let all = common @ dc @ session_ref @ sr_sm_config @ sr_ref @ sr_uuid @
vdi_ref @ vdi_location @ vdi_uuid @ driver_params @ vdi_sm_config @ new_uuid @
subtask_of in
+ let local_cache_sr = default [] (may (fun x -> ["local_cache_sr",
XMLRPC.To.string x]) call.local_cache_sr) in
+ let all = common @ dc @ session_ref @ sr_sm_config @ sr_ref @ sr_uuid @
vdi_ref @ vdi_location @ vdi_uuid @ driver_params @ vdi_sm_config @ new_uuid @
subtask_of @ vdi_on_boot @ vdi_allow_caching @ local_cache_sr in
XMLRPC.To.methodCall call.cmd [ XMLRPC.To.structure all ]
let methodResponse xml =
@@ -260,6 +273,7 @@
let lookup_table =
[ "SR_PROBE", Sr_probe;
"SR_UPDATE", Sr_update;
+ "SR_SUPPORTS_LOCAL_CACHING", Sr_supports_local_caching;
"VDI_CREATE", Vdi_create;
"VDI_DELETE", Vdi_delete;
"VDI_ATTACH", Vdi_attach;
@@ -273,6 +287,7 @@
"VDI_UPDATE", Vdi_update;
"VDI_INTRODUCE", Vdi_introduce;
"VDI_GENERATE_CONFIG", Vdi_generate_config;
+ "VDI_RESET_ON_BOOT", Vdi_reset_on_boot;
] in
let strings = XMLRPC.From.array XMLRPC.From.string (safe_assoc
"capabilities" info) in
List.iter (fun s ->
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/smint.ml
--- a/ocaml/xapi/smint.ml
+++ b/ocaml/xapi/smint.ml
@@ -32,15 +32,18 @@
(** Very primitive first attempt at a set of backend capabilities *)
type capability =
- | Sr_create | Sr_delete | Sr_attach | Sr_detach | Sr_scan | Sr_probe |
Sr_update
+ | Sr_create | Sr_delete | Sr_attach | Sr_detach | Sr_scan | Sr_probe |
Sr_update
+ | Sr_supports_local_caching
| Vdi_create | Vdi_delete | Vdi_attach | Vdi_detach
| Vdi_clone | Vdi_snapshot | Vdi_resize | Vdi_activate | Vdi_deactivate
| Vdi_update | Vdi_introduce
| Vdi_resize_online
| Vdi_generate_config
+ | Vdi_reset_on_boot
let all_capabilities =
[ Sr_create; Sr_delete; Sr_attach; Sr_detach; Sr_scan; Sr_probe; Sr_update;
+ Sr_supports_local_caching;
Vdi_create; Vdi_delete; Vdi_attach; Vdi_detach;
Vdi_clone; Vdi_resize; Vdi_activate; Vdi_deactivate;
Vdi_update; Vdi_introduce;
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_host.ml
--- a/ocaml/xapi/xapi_host.ml
+++ b/ocaml/xapi/xapi_host.ml
@@ -96,8 +96,14 @@
end
(** Check that a) there are no running VMs present on the host, b) there are
no VBDs currently
- attached to dom0, and c) that there are no tasks running *)
-let assert_can_shutdown ~__context ~host =
+ attached to dom0, c) host is disabled.
+
+ This is approximately maintainance mode as defined by the gui. However,
since
+ we haven't agreed on an exact definition of this mode, we'll not call
this maintainance mode here, but we'll
+ use a synonym. According to http://thesaurus.com/browse/maintenance,
bacon is a synonym
+ for maintainance, hence the name of the following function.
+*)
+let assert_bacon_mode ~__context ~host =
if Db.Host.get_enabled ~__context ~self:host
then raise (Api_errors.Server_error (Api_errors.host_not_disabled, []));
@@ -107,14 +113,14 @@
(* We always expect a control domain to be resident on a host *)
if List.length vms > 1 then
raise (Api_errors.Server_error (Api_errors.host_in_use, [ selfref; "vm";
List.hd (List.map Ref.string_of vms) ]));
- debug "Shutdown test: VMs OK - %d running VMs" (List.length vms);
+ debug "Bacon test: VMs OK - %d running VMs" (List.length vms);
let controldomain = List.find (fun vm -> Db.VM.get_resident_on ~__context
~self:vm = host &&
Db.VM.get_is_control_domain ~__context ~self:vm) (Db.VM.get_all
~__context) in
let vbds = List.filter (fun vbd -> Db.VBD.get_VM ~__context ~self:vbd =
controldomain &&
Db.VBD.get_currently_attached ~__context ~self:vbd) (Db.VBD.get_all
~__context) in
if List.length vbds > 0 then
raise (Api_errors.Server_error (Api_errors.host_in_use, [ selfref; "vbd";
List.hd (List.map Ref.string_of vbds) ]));
- debug "Shutdown test: VBDs OK"
+ debug "Bacon test: VBDs OK"
let pif_update_dhcp_address ~__context ~self =
let network = Db.PIF.get_network ~__context ~self in
@@ -463,7 +469,7 @@
end
let shutdown_and_reboot_common ~__context ~host label description operation
cmd =
- assert_can_shutdown ~__context ~host;
+ assert_bacon_mode ~__context ~host;
Xapi_ha.before_clean_shutdown_or_reboot ~__context ~host;
Remote_requests.stop_request_thread();
@@ -648,6 +654,7 @@
~bios_strings:[]
~power_on_mode:""
~power_on_config:[]
+ ~local_cache_sr:Ref.null
;
(* If the host we're creating is us, make sure its set to live *)
Db.Host_metrics.set_last_updated ~__context ~self:metrics
~value:(Date.of_float (Unix.gettimeofday ()));
@@ -1354,3 +1361,31 @@
let physical_features = List.assoc "physical_features" cpu_info in
let cpu_info = List.replace_assoc "features_after_reboot"
physical_features cpu_info in
Db.Host.set_cpu_info ~__context ~self:host ~value:cpu_info
+
+let enable_local_storage_caching ~__context ~host ~sr =
+ assert_bacon_mode ~__context ~host;
+ let ty = Db.SR.get_type ~__context ~self:sr in
+ let pbds = Db.SR.get_PBDs ~__context ~self:sr in
+ let shared = Db.SR.get_shared ~__context ~self:sr in
+ let has_required_capability =
+ let caps = Sm.capabilities_of_driver ty in
+ List.mem Smint.Sr_supports_local_caching caps
+ in
+ debug "shared: %b. List.length pbds: %d. has_required_capability: %b"
shared (List.length pbds) has_required_capability;
+ if (shared=false) && (List.length pbds = 1) && has_required_capability
then begin
+ let pbd_host = Db.PBD.get_host ~__context ~self:(List.hd pbds)
in
+ if pbd_host <> host then raise (Api_errors.Server_error
(Api_errors.host_cannot_see_SR,[Ref.string_of host; Ref.string_of sr]));
+ Db.Host.set_local_cache_sr ~__context ~self:host ~value:sr;
+ Db.SR.set_local_cache_enabled ~__context ~self:sr ~value:true
+ end else begin
+ raise (Api_errors.Server_error
(Api_errors.sr_operation_not_supported,[]))
+ end
+
+let disable_local_storage_caching ~__context ~host =
+ assert_bacon_mode ~__context ~host;
+ let sr = Db.Host.get_local_cache_sr ~__context ~self:host in
+ Db.Host.set_local_cache_sr ~__context ~self:host ~value:Ref.null;
+ try Db.SR.set_local_cache_enabled ~__context ~self:sr ~value:false with
_ -> ()
+
+
+
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_host.mli
--- a/ocaml/xapi/xapi_host.mli
+++ b/ocaml/xapi/xapi_host.mli
@@ -252,6 +252,10 @@
(** Remove the feature mask, such that after a reboot all features of the CPU
are enabled. *)
val reset_cpu_features : __context:Context.t -> host:API.ref_host -> unit
+(** Control the local caching behaviour of the host *)
+val enable_local_storage_caching : __context:Context.t -> host:API.ref_host ->
sr:API.ref_SR -> unit
+val disable_local_storage_caching : __context:Context.t -> host:API.ref_host
-> unit
+
(** Purge all network-related metadata associated with the given host. *)
val reset_networking : __context:Context.t -> host:API.ref_host -> unit
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_pool.ml
--- a/ocaml/xapi/xapi_pool.ml
+++ b/ocaml/xapi/xapi_pool.ml
@@ -16,6 +16,7 @@
open Pervasiveext
open Threadext
open Stringext
+open Listext
module L = Debug.Debugger(struct let name="license" end)
module D=Debug.Debugger(struct let name="xapi" end)
@@ -1464,4 +1465,50 @@
"test_archive_target"
config
-
+let enable_local_storage_caching ~__context ~self =
+ let srs = Db.SR.get_all_records ~__context in
+ let pbds = Db.PBD.get_all_records ~__context in
+ let hosts = Db.Host.get_all ~__context in
+
+ (* Exception handler is to cope with transient PBDs with invalid
references *)
+ let hosts_and_srs = List.filter_map (fun (pbdref,pbdrec) ->
+ try Some (pbdrec.API.pBD_host, pbdrec.API.pBD_SR, List.assoc
pbdrec.API.pBD_SR srs) with _ -> None) pbds
+ in
+
+ let acceptable = List.filter (fun (href,srref,srrec) ->
+ (not srrec.API.sR_shared) &&
+ (List.length srrec.API.sR_PBDs = 1) &&
+ (List.mem Smint.Sr_supports_local_caching
(Sm.capabilities_of_driver srrec.API.sR_type))
+ ) hosts_and_srs in
+
+ let failed_hosts =
+ Helpers.call_api_functions ~__context
+ (fun rpc session_id ->
+ let failed = List.filter_map (fun host ->
+ let result = ref (Some host) in
+ let acceptable_srs = List.filter (fun
(href,srref,srrec) -> href=host) acceptable in
+ List.iter (fun (href,ref,sr) ->
+ try
Client.Host.enable_local_storage_caching rpc session_id host ref; result :=
None with _ -> ()) acceptable_srs;
+ !result
+ ) hosts in
+ failed)
+ in
+ if List.length failed_hosts > 0 then
+ raise (Api_errors.Server_error
(Api_errors.hosts_failed_to_enable_caching, List.map Ref.string_of
failed_hosts))
+ else ()
+
+
+let disable_local_storage_caching ~__context ~self =
+ let hosts = Db.Host.get_all ~__context in
+ let failed_hosts = Helpers.call_api_functions ~__context
+ (fun rpc session_id ->
+ List.filter_map (fun host ->
+ try
+
Client.Host.disable_local_storage_caching ~rpc ~session_id ~host;
+ None
+ with _ ->
+ Some host) hosts)
+ in
+ if List.length failed_hosts > 0 then
+ raise (Api_errors.Server_error
(Api_errors.hosts_failed_to_disable_caching, List.map Ref.string_of
failed_hosts))
+ else ()
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_pool.mli
--- a/ocaml/xapi/xapi_pool.mli
+++ b/ocaml/xapi/xapi_pool.mli
@@ -194,3 +194,5 @@
val audit_log_append : __context:Context.t -> line:string -> unit
val test_archive_target : __context:Context.t -> self:API.ref_pool ->
config:API.string_to_string_map -> string
+val enable_local_storage_caching : __context:Context.t -> self:API.ref_pool ->
unit
+val disable_local_storage_caching : __context:Context.t -> self:API.ref_pool
-> unit
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_sr.ml
--- a/ocaml/xapi/xapi_sr.ml
+++ b/ocaml/xapi/xapi_sr.ml
@@ -232,7 +232,7 @@
~physical_size: (-1L)
~content_type
~_type ~shared ~other_config:[] ~default_vdi_visibility:true
- ~sm_config ~blobs:[] ~tags:[] in
+ ~sm_config ~blobs:[] ~tags:[] ~local_cache_enabled:false in
update_allowed_operations ~__context ~self:sr_ref;
(* Return ref of newly created sr *)
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_vdi.ml
--- a/ocaml/xapi/xapi_vdi.ml
+++ b/ocaml/xapi/xapi_vdi.ml
@@ -30,6 +30,9 @@
let _ref = Ref.string_of _ref' in
let current_ops = record.Db_actions.vDI_current_operations in
let vdi_is_sharable = record.Db_actions.vDI_sharable in
+
+ let reset_on_boot = record.Db_actions.vDI_on_boot = `reset in
+
(* Policy:
1. any current_operation implies exclusivity; fail everything else
2. if doing a VM start then assume the sharing check is done elsewhere
@@ -111,6 +114,8 @@
else None
| `snapshot when record.Db_actions.vDI_sharable ->
Some (Api_errors.vdi_is_sharable, [ _ref ])
+ | `snapshot when reset_on_boot ->
+ Some
(Api_errors.vdi_on_boot_mode_incompatable_with_operation, [])
| _ -> None
)
@@ -236,7 +241,8 @@
~physical_utilisation:(-1L) ~_type
~sharable ~read_only
~xenstore_data ~sm_config
- ~other_config ~storage_lock:false ~location ~managed:true ~missing:false
~parent:Ref.null ~tags:[];
+ ~other_config ~storage_lock:false ~location ~managed:true ~missing:false
~parent:Ref.null ~tags:[]
+ ~on_boot:`persist ~allow_caching:false;
ref
let internal_db_introduce ~__context ~uuid ~name_label ~name_description ~sR
~_type ~sharable ~read_only ~other_config ~location ~xenstore_data ~sm_config =
@@ -330,6 +336,9 @@
Db.VDI.set_sharable ~__context ~self:newvdi ~value:a.Db_actions.vDI_sharable;
Db.VDI.set_other_config ~__context ~self:newvdi
~value:a.Db_actions.vDI_other_config;
Db.VDI.set_xenstore_data ~__context ~self:newvdi
~value:a.Db_actions.vDI_xenstore_data;
+ Db.VDI.set_on_boot ~__context ~self:newvdi ~value:a.Db_actions.vDI_on_boot;
+ Db.VDI.set_allow_caching ~__context ~self:newvdi
~value:a.Db_actions.vDI_allow_caching;
+
(* Record the fact this is a snapshot *)
(*(try Db.VDI.remove_from_other_config ~__context ~self:newvdi
~key:Xapi_globs.snapshot_of with _ -> ());
@@ -421,6 +430,8 @@
Db.VDI.set_sharable ~__context ~self:newvdi
~value:a.Db_actions.vDI_sharable;
Db.VDI.set_other_config ~__context ~self:newvdi
~value:a.Db_actions.vDI_other_config;
Db.VDI.set_xenstore_data ~__context ~self:newvdi
~value:a.Db_actions.vDI_xenstore_data;
+ Db.VDI.set_on_boot ~__context ~self:newvdi
~value:a.Db_actions.vDI_on_boot;
+ Db.VDI.set_allow_caching ~__context ~self:newvdi
~value:a.Db_actions.vDI_allow_caching;
update_allowed_operations ~__context ~self:newvdi;
newvdi
@@ -467,7 +478,7 @@
let dst =
Helpers.call_api_functions ~__context
(fun rpc session_id ->
- Client.VDI.create ~rpc ~session_id
+ let result = Client.VDI.create ~rpc ~session_id
~name_label:src.API.vDI_name_label
~name_description:src.API.vDI_name_description
~sR:sr
@@ -477,9 +488,15 @@
~read_only:src.API.vDI_read_only
~other_config:src.API.vDI_other_config
~xenstore_data:src.API.vDI_xenstore_data
- ~sm_config:src.API.vDI_sm_config ~tags:[]
+ ~sm_config:src.API.vDI_sm_config ~tags:[] in
+ if src.API.vDI_on_boot = `reset then begin
+ try Client.VDI.set_on_boot ~rpc ~session_id ~self:result
~value:(`reset) with _ -> ()
+ end;
+ result
) in
try
+ Db.VDI.set_allow_caching ~__context ~self:dst
~value:src.API.vDI_allow_caching;
+
Sm_fs_ops.copy_vdi ~__context vdi dst;
Db.VDI.remove_from_current_operations ~__context ~self:dst ~key:task_id;
@@ -514,3 +531,24 @@
let set_physical_utilisation ~__context ~self ~value =
Db.VDI.set_physical_utilisation ~__context ~self ~value
+
+let set_on_boot ~__context ~self ~value =
+ let sr = Db.VDI.get_SR ~__context ~self in
+ let ty = Db.SR.get_type ~__context ~self:sr in
+ let caps = Sm.capabilities_of_driver ty in
+ if not (List.mem Smint.Vdi_reset_on_boot caps) then
+ raise
(Api_errors.Server_error(Api_errors.sr_operation_not_supported,[Ref.string_of
sr]));
+ Sm.assert_pbd_is_plugged ~__context ~sr;
+ Sm.call_sm_vdi_functions ~__context ~vdi:self
+ (fun srconf srtype sr ->
+ let vdi_info = Sm.vdi_clone srconf srtype [] __context
sr self in
+ let uuid = require_uuid vdi_info in
+ let ref = Db.VDI.get_by_uuid ~__context ~uuid in
+ Sm.vdi_delete srconf srtype sr ref);
+ Db.VDI.set_on_boot ~__context ~self ~value
+
+let set_allow_caching ~__context ~self ~value =
+ Db.VDI.set_allow_caching ~__context ~self ~value
+
+
+
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_vm_lifecycle.ml
--- a/ocaml/xapi/xapi_vm_lifecycle.ml
+++ b/ocaml/xapi/xapi_vm_lifecycle.ml
@@ -16,6 +16,7 @@
*)
open Xapi_pv_driver_version
+open Listext
module D = Debug.Debugger(struct let name="xapi" end)
open D
@@ -202,7 +203,7 @@
(** Take an internal VM record and a proposed operation, return true if the
operation
would be acceptable *)
-let check_operation_error ~vmr ~vmgmr ~ref ~clone_suspended_vm_enabled ~op =
+let check_operation_error ~vmr ~vmgmr ~ref ~clone_suspended_vm_enabled
vdis_reset_and_caching ~op =
let ref_str = Ref.string_of ref in
let power_state = vmr.Db_actions.vM_power_state in
let current_ops = vmr.Db_actions.vM_current_operations in
@@ -245,6 +246,18 @@
&& op <> `changing_dynamic_range
then Some (Api_errors.operation_not_allowed, ["Operations on domain 0
are not allowed"])
+ (* Check for an error due to VDI caching/reset behaviour *)
+ else if op = `checkpoint || op = `snapshot || op = `suspend || op =
`snapshot_with_quiesce
+ then (* If any vdi exists with on_boot=reset, then disallow checkpoint,
snapshot, suspend *)
+ if List.exists fst vdis_reset_and_caching
+ then Some
(Api_errors.vdi_on_boot_mode_incompatable_with_operation,[])
+ else None
+ else if op = `pool_migrate then
+ (* If any vdi exists with on_boot=reset and caching is enabled,
disallow migrate *)
+ if List.exists (fun (reset,caching) -> reset && caching)
vdis_reset_and_caching
+ then Some
(Api_errors.vdi_on_boot_mode_incompatable_with_operation,[])
+ else None
+
(* check PV drivers constraints if needed *)
else if need_pv_drivers_check ~power_state ~op
then check_drivers ~vmr ~vmgmr ~op ~ref
@@ -271,24 +284,32 @@
let all = Db.VM.get_record_internal ~__context ~self in
let gm = maybe_get_guest_metrics ~__context
~ref:(all.Db_actions.vM_guest_metrics) in
let clone_suspended_vm_enabled = Helpers.clone_suspended_vm_enabled
~__context in
- all, gm, clone_suspended_vm_enabled
+ let vdis_reset_and_caching = List.filter_map (fun vbd ->
+ try
+ let vdi = Db.VBD.get_VDI ~__context ~self:vbd in
+ let sm_config = Db.VDI.get_sm_config ~__context ~self:vdi in
+ Some
+ ((try List.assoc "on_boot" sm_config = "reset"
with _ -> false),
+ (try String.lowercase (List.assoc "caching"
sm_config) = "true" with _ -> false))
+ with _ -> None) all.Db_actions.vM_VBDs in
+ all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching
let is_operation_valid ~__context ~self ~op =
- let all, gm, clone_suspended_vm_enabled = get_info ~__context ~self in
- match check_operation_error all gm self clone_suspended_vm_enabled op
with
+ let all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching =
get_info ~__context ~self in
+ match check_operation_error all gm self clone_suspended_vm_enabled
vdis_reset_and_caching op with
| None -> true
| Some _ -> false
let assert_operation_valid ~__context ~self ~op =
- let all, gm, clone_suspended_vm_enabled = get_info ~__context ~self in
- match check_operation_error all gm self clone_suspended_vm_enabled op
with
+ let all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching =
get_info ~__context ~self in
+ match check_operation_error all gm self clone_suspended_vm_enabled
vdis_reset_and_caching op with
| None -> ()
| Some (a,b) -> raise (Api_errors.Server_error (a,b))
let update_allowed_operations ~__context ~self =
- let all, gm, clone_suspended_vm_enabled = get_info ~__context ~self in
+ let all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching =
get_info ~__context ~self in
let check accu op =
- match check_operation_error all gm self
clone_suspended_vm_enabled op with
+ match check_operation_error all gm self
clone_suspended_vm_enabled vdis_reset_and_caching op with
| None -> op :: accu
| _ -> accu
in
xen-api2.hg-1.patch
Description: Text Data
_______________________________________________
xen-api mailing list
xen-api@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/mailman/listinfo/xen-api
|