/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using XenAPI; using XenAdmin.Core; using XenAdmin.Dialogs; using XenAdmin.Actions; namespace XenAdmin.Commands { class DeactivateVBDCommand : Command { /// /// Deactivates a selection of VBDs /// /// /// public DeactivateVBDCommand(IMainWindow mainWindow, IEnumerable selection) : base(mainWindow, selection) { } /// /// Deactivates a single VBD /// /// /// public DeactivateVBDCommand(IMainWindow mainWindow, VBD vbd) : base(mainWindow, vbd) { } public override string ContextMenuText => Messages.MESSAGEBOX_DEACTIVATE_VD_TITLE; public override string ButtonText => Messages.DEACTIVATE; protected override bool CanExecuteCore(SelectedItemCollection selection) { return selection.AllItemsAre() && selection.AtLeastOneXenObjectCan(CanExecute); } // We only need to check for IO Drivers for hosts before Ely private bool AreIODriversNeededAndMissing(VM vm) { if (Helpers.ElyOrGreater(vm.Connection)) { return false; } return !vm.GetVirtualisationStatus(out _).HasFlag(VM.VirtualisationStatus.IO_DRIVERS_INSTALLED); } private bool CanExecute(VBD vbd) { VDI vdi = vbd.Connection.Resolve(vbd.VDI); VM vm = vbd.Connection.Resolve(vbd.VM); if (vm == null || !vm.is_a_real_vm() || vdi == null || vdi.Locked || vbd.Locked) return false; if (vm.power_state != vm_power_state.Running) return false; if (vdi.type == vdi_type.system && vbd.GetIsOwner()) return false; if (AreIODriversNeededAndMissing(vm)) return false; if (!vbd.currently_attached) return false; return vbd.allowed_operations.Contains(vbd_operations.unplug); } protected override string GetCantExecuteReasonCore(IXenObject item) { VBD vbd = item as VBD; if (vbd == null) return base.GetCantExecuteReasonCore(item); VDI vdi = vbd.Connection.Resolve(vbd.VDI); VM vm = vbd.Connection.Resolve(vbd.VM); if (vm == null || vdi == null) return base.GetCantExecuteReasonCore(item); if (vm.is_a_template) return Messages.CANNOT_ACTIVATE_TEMPLATE_DISK; if (!vm.is_a_real_vm()) return base.GetCantExecuteReasonCore(item); SR sr = vdi.Connection.Resolve(vdi.SR); if (sr == null) return Messages.SR_COULD_NOT_BE_CONTACTED; if (vdi.Locked) { var vdiType = vdi.VDIType(); return vdiType == VDI.FriendlyType.SNAPSHOT ? Messages.CANNOT_DEACTIVATE_SNAPSHOT_IN_USE : vdiType == VDI.FriendlyType.ISO ? Messages.CANNOT_DEACTIVATE_ISO_IN_USE : Messages.CANNOT_DEACTIVATE_VDI_IN_USE; } if (vm.power_state != vm_power_state.Running) return string.Format( Messages.CANNOT_DEACTIVATE_VDI_VM_NOT_RUNNING, Helpers.GetName(vm).Ellipsise(50)); if (vdi.type == vdi_type.system && vbd.GetIsOwner()) return Messages.TOOLTIP_DEACTIVATE_SYSVDI; if (AreIODriversNeededAndMissing(vm)) return string.Format( vm.HasNewVirtualisationStates() ? Messages.CANNOT_DEACTIVATE_VDI_NEEDS_IO_DRIVERS : Messages.CANNOT_DEACTIVATE_VDI_NEEDS_TOOLS, Helpers.GetName(vm).Ellipsise(50)); if (!vbd.currently_attached) return string.Format(Messages.CANNOT_DEACTIVATE_NOT_ACTIVE, Helpers.GetName(vm).Ellipsise(50)); return base.GetCantExecuteReasonCore(item); } protected override CommandErrorDialog GetErrorDialogCore(IDictionary cantExecuteReasons) { return new CommandErrorDialog(Messages.ERROR_DEACTIVATING_MULTIPLE_VDIS_TITLE, Messages.ERROR_DEACTIVATING_MULTIPLE_VDIS_MESSAGE, cantExecuteReasons); } protected override void ExecuteCore(SelectedItemCollection selection) { List actionsToComplete = new List(); foreach (VBD vbd in selection.AsXenObjects()) { if (vbd.Locked) continue; actionsToComplete.Add(getDeactivateVBDAction(vbd)); } if (actionsToComplete.Count == 0) return; if (actionsToComplete.Count > 1) RunMultipleActions(actionsToComplete, Messages.ACTION_DEACTIVATING_MULTIPLE_VDIS_TITLE, Messages.ACTION_DEACTIVATING_MULTIPLE_VDIS_STATUS, Messages.COMPLETED, true); else actionsToComplete[0].RunAsync(); } private AsyncAction getDeactivateVBDAction(VBD vbd) { VDI vdi = vbd.Connection.Resolve(vbd.VDI); VM vm = vbd.Connection.Resolve(vbd.VM); String title = String.Format(Messages.ACTION_DISK_DEACTIVATING_TITLE, vdi.Name(), vm.Name()); String startDesc = Messages.ACTION_DISK_DEACTIVATING; String endDesc = Messages.ACTION_DISK_DEACTIVATED; AsyncAction action = new DelegatedAsyncAction(vbd.Connection, title, startDesc, endDesc,session => VBD.unplug(session, vbd.opaque_ref), "vbd.unplug"); action.VM = vm; return action; } } }