Skip to content

Commit

Permalink
CA-62302: Add an API call to declare a host dead
Browse files Browse the repository at this point in the history
Also execute the post_declare_dead script on host.destroy

Signed-off-by: Jon Ludlam <jonathan.ludlam@eu.citrix.com>
  • Loading branch information
Jon Ludlam committed Mar 29, 2013
1 parent df98fbe commit c8a9425
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 15 deletions.
9 changes: 9 additions & 0 deletions ocaml/idl/datamodel.ml
Expand Up @@ -2712,6 +2712,14 @@ let host_detach_static_vdis = call
~allowed_roles:_R_LOCAL_ROOT_ONLY
()

let host_declare_dead = call
~name:"declare_dead"
~in_product_since:rel_clearwater
~doc:"Declare that a host is dead. This is a dangerous operation, and should only be called if the administrator is absolutely sure the host is definitely dead"
~params:[Ref _host, "host", "The Host to declare is dead"]
~allowed_roles:_R_POOL_OP
()

let host_forget_data_source_archives = call
~name:"forget_data_source_archives"
~in_oss_since:None
Expand Down Expand Up @@ -4185,6 +4193,7 @@ let host =
host_sync_tunnels;
host_sync_pif_currently_attached;
host_migrate_receive;
host_declare_dead;
]
~contents:
([ uid _host;
Expand Down
5 changes: 5 additions & 0 deletions ocaml/xapi/message_forwarding.ml
Expand Up @@ -2107,6 +2107,11 @@ module Forward = functor(Local: Custom_actions.CUSTOM_ACTIONS) -> struct
do_op_on ~local_fn ~__context ~host (fun session_id rpc -> Client.Host.disable rpc session_id host);
Xapi_host_helpers.update_allowed_operations ~__context ~self:host

let declare_dead ~__context ~host =
info "Host.declare_dead: host = '%s'" (host_uuid ~__context host);
Local.Host.declare_dead ~__context ~host;
Xapi_host_helpers.update_allowed_operations ~__context ~self:host

let enable ~__context ~host =
info "Host.enable: host = '%s'" (host_uuid ~__context host);
let local_fn = Local.Host.enable ~host in
Expand Down
2 changes: 2 additions & 0 deletions ocaml/xapi/xapi_hooks.ml
Expand Up @@ -37,6 +37,8 @@ let scriptname__host_post_declare_dead = "host-post-declare-dead"
(* Host Script hook reason codes *)
let reason__assume_failed = "assume-failed"
let reason__fenced = "fenced"
let reason__dbdestroy = "dbdestroy"
let reason__user = "user"
(* or clean-shutdown or clean-reboot *)

(* Names of Pool script hooks *)
Expand Down
34 changes: 29 additions & 5 deletions ocaml/xapi/xapi_host.ml
Expand Up @@ -615,34 +615,58 @@ let create ~__context ~uuid ~name_label ~name_description ~hostname ~address ~ex
Db.Host_metrics.set_live ~__context ~self:metrics ~value:(uuid=(Helpers.get_localhost_uuid ()));
host

let destroy ~__context ~self =
let precheck_destroy_declare_dead ~__context ~self call =
(* Fail if the host is still online: the user should either isolate the machine from the network
or use Pool.eject. *)
let hostname = Db.Host.get_hostname ~__context ~self in
if is_host_alive ~__context ~host:self then begin
error "Host.destroy successfully contacted host %s; host is not offline; refusing to destroy record" hostname;
error "Host.%s successfully contacted host %s; host is not offline; refusing to %s" call hostname call;
raise (Api_errors.Server_error(Api_errors.host_is_live, [ Ref.string_of self ]))
end;

(* This check is probably redundant since the Pool master should always be 'alive': *)
(* It doesn't make any sense to destroy the master's own record *)
let me = Helpers.get_localhost ~__context in
if self=me then raise (Api_errors.Server_error(Api_errors.host_cannot_destroy_self, [ Ref.string_of self ]));
if self=me then raise (Api_errors.Server_error(Api_errors.host_is_live, [ Ref.string_of self ]))


(* Returns a tuple of lists: The first containing the control domains, and the second containing the regular VMs *)
let get_resident_vms ~__context ~self =
let my_resident_vms = Db.Host.get_resident_VMs ~__context ~self in
List.partition (fun vm -> Db.VM.get_is_control_domain ~__context ~self:vm) my_resident_vms

let destroy ~__context ~self =
precheck_destroy_declare_dead ~__context ~self "destroy";

(* CA-23732: Block if HA is enabled *)
let pool = Helpers.get_pool ~__context in
if Db.Pool.get_ha_enabled ~__context ~self:pool
then raise (Api_errors.Server_error(Api_errors.ha_is_enabled, []));

let my_resident_vms = Db.Host.get_resident_VMs ~__context ~self in
let my_control_domains, my_regular_vms = List.partition (fun vm -> Db.VM.get_is_control_domain ~__context ~self:vm) my_resident_vms in
let my_control_domains, my_regular_vms = get_resident_vms ~__context ~self in

if List.length my_regular_vms > 0
then raise (Api_errors.Server_error(Api_errors.host_has_resident_vms, [ Ref.string_of self ]));

(* Call the hook before we destroy the stuff as it will likely need the
database records *)
Xapi_hooks.host_post_declare_dead ~__context ~host:self ~reason:Xapi_hooks.reason__dbdestroy;

Db.Host.destroy ~__context ~self;
List.iter (fun vm -> Db.VM.destroy ~__context ~self:vm) my_control_domains

let declare_dead ~__context ~host =
precheck_destroy_declare_dead ~__context ~self:host "declare_dead";

let my_control_domains, my_regular_vms = get_resident_vms ~__context ~self:host in

Helpers.call_api_functions ~__context (fun rpc session_id ->
List.iter (fun vm -> Client.Client.VM.power_state_reset rpc session_id vm) my_regular_vms);

Db.Host.set_enabled ~__context ~self:host ~value:false;

Xapi_hooks.host_post_declare_dead ~__context ~host ~reason:Xapi_hooks.reason__user

let ha_disable_failover_decisions ~__context ~host = Xapi_ha.ha_disable_failover_decisions __context host
let ha_disarm_fencing ~__context ~host = Xapi_ha.ha_disarm_fencing __context host
let ha_stop_daemon ~__context ~host = Xapi_ha.ha_stop_daemon __context host
Expand Down
1 change: 1 addition & 0 deletions ocaml/xapi/xapi_host.mli
Expand Up @@ -89,6 +89,7 @@ val create :
chipset_info:(string * string) list ->
[ `host ] Ref.t
val destroy : __context:Context.t -> self:API.ref_host -> unit
val declare_dead : __context:Context.t -> host:API.ref_host -> unit
val ha_disable_failover_decisions : __context:'a -> host:'b -> unit
val ha_disarm_fencing : __context:'a -> host:'b -> unit
val ha_stop_daemon : __context:'a -> host:'b -> unit
Expand Down
33 changes: 23 additions & 10 deletions scripts/10resetvdis
Expand Up @@ -6,15 +6,28 @@
HOSTUUID=$2
REASON=$4

# Only reset the VDIs if the host is actually fenced!
if [ ! $REASON = "fenced" ]; then
exit 0
function reset {
echo Resetting VDIs on host $HOSTUUID
IFS=","
for i in `xe pbd-list host-uuid=$HOSTUUID --minimal`
do
SR=`xe pbd-param-get uuid=$i param-name=sr-uuid`
"@OPTDIR@/sm/resetvdis.py" $HOSTUUID $SR
done
}

# Only reset the VDIs if the host is actually fenced, or the user has requested it.
if [ $REASON = "fenced" ]; then
reset
fi

if [ $REASON = "user" ]; then
reset
fi

echo Resetting VDIs on host $HOSTUUID
IFS=","
for i in `xe pbd-list host-uuid=$HOSTUUID --minimal`
do
SR=`xe pbd-param-get uuid=$i param-name=sr-uuid`
"@OPTDIR@/sm/resetvdis.py" $HOSTUUID $SR
done
if [ $REASON = "dbdestroy" ]; then
reset
fi



0 comments on commit c8a9425

Please sign in to comment.