Add new MenuItem to Force Migrate a VM

This commit is contained in:
Alexander Schulz 2018-07-16 23:06:58 +02:00
parent 2f33754792
commit 70f61c0cd7
15 changed files with 81 additions and 53 deletions

View File

@ -59,10 +59,15 @@ namespace XenAdmin.Commands
{
if (selection.ToList().All(item => !Helpers.CrossPoolMigrationRestrictedWithWlb(item.Connection)))
{
VMOperationCommand cmd = new CrossPoolMigrateCommand(Command.MainWindowCommandInterface, selection);
DropDownItems.Add(new ToolStripSeparator());
VMOperationCommand cmd = new CrossPoolMigrateCommand(Command.MainWindowCommandInterface, selection, false);
VMOperationToolStripMenuSubItem lastItem = new VMOperationToolStripMenuSubItem(cmd);
DropDownItems.Add(lastItem);
DropDownItems.Add(lastItem);
VMOperationCommand cmdForce = new CrossPoolMigrateCommand(Command.MainWindowCommandInterface, selection, true);
VMOperationToolStripMenuSubItem lastItemForce = new VMOperationToolStripMenuSubItem(cmdForce);
DropDownItems.Add(lastItemForce);
}
}

View File

@ -299,8 +299,8 @@ namespace XenAdmin.Commands
else
{
var cpmCmd = isHomeServer
? new CrossPoolMigrateToHomeCommand(menu.Command.MainWindowCommandInterface, selection, host)
: new CrossPoolMigrateCommand(menu.Command.MainWindowCommandInterface, selection, host, menu._resumeAfter);
? new CrossPoolMigrateToHomeCommand(menu.Command.MainWindowCommandInterface, selection, host, false)
: new CrossPoolMigrateCommand(menu.Command.MainWindowCommandInterface, selection, host, false, menu._resumeAfter);
var crossPoolMigrateCmdCanRun = cpmCmd.CanExecute();
if (Stopped)

View File

@ -66,7 +66,7 @@ namespace XenAdmin.Commands
{
VM template = (VM)selection[0].XenObject;
if (CrossPoolCopyTemplateCommand.CanExecute(template, null))
if (CrossPoolCopyTemplateCommand.CanExecute(template, null, false))
new CrossPoolCopyTemplateCommand(MainWindowCommandInterface, selection).Execute();
else
MainWindowCommandInterface.ShowPerXenModelObjectWizard(template, new CopyVMDialog(template));
@ -81,7 +81,7 @@ namespace XenAdmin.Commands
{
if (vm != null && vm.is_a_template && !vm.is_a_snapshot && !vm.Locked && vm.allowed_operations != null && !vm.InternalTemplate())
{
if (CrossPoolCopyTemplateCommand.CanExecute(vm, null))
if (CrossPoolCopyTemplateCommand.CanExecute(vm, null, false))
return true;
if (vm.allowed_operations.Contains(vm_operations.clone) || vm.allowed_operations.Contains(vm_operations.copy))
return true;

View File

@ -66,7 +66,7 @@ namespace XenAdmin.Commands
{
VM vm = (VM)selection[0].XenObject;
if (CrossPoolCopyVMCommand.CanExecute(vm, null))
if (CrossPoolCopyVMCommand.CanExecute(vm, null, false))
new CrossPoolCopyVMCommand(MainWindowCommandInterface, selection).Execute();
else
MainWindowCommandInterface.ShowPerXenModelObjectWizard(vm, new CopyVMDialog(vm));
@ -79,7 +79,7 @@ namespace XenAdmin.Commands
private static bool CanExecute(VM vm)
{
return vm != null && (CrossPoolCopyVMCommand.CanExecute(vm, null) || vm.CanBeCopied());
return vm != null && (CrossPoolCopyVMCommand.CanExecute(vm, null, false) || vm.CanBeCopied());
}
public override string MenuText

View File

@ -40,11 +40,11 @@ namespace XenAdmin.Commands
internal class CrossPoolCopyVMCommand : CrossPoolMigrateCommand
{
public CrossPoolCopyVMCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection)
: this(mainWindow, selection, null)
: this(mainWindow, selection, null, false)
{ }
public CrossPoolCopyVMCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost)
: base(mainWindow, selection, preSelectedHost)
public CrossPoolCopyVMCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost, bool force)
: base(mainWindow, selection, preSelectedHost, force)
{
}
@ -58,31 +58,31 @@ namespace XenAdmin.Commands
var con = selection.GetConnectionOfFirstItem();
MainWindowCommandInterface.ShowPerConnectionWizard(con,
new CrossPoolMigrateWizard(con, selection, preSelectedHost, WizardMode.Copy));
new CrossPoolMigrateWizard(con, selection, preSelectedHost, WizardMode.Copy, false));
}
protected override bool CanExecute(VM vm)
{
return CanExecute(vm, preSelectedHost);
return CanExecute(vm, preSelectedHost, _force);
}
public static bool CanExecute(VM vm, Host preSelectedHost)
public static bool CanExecute(VM vm, Host preSelectedHost, bool force)
{
if (vm == null || vm.is_a_template || vm.Locked || vm.power_state != vm_power_state.Halted)
return false;
return CrossPoolMigrateCommand.CanExecute(vm, preSelectedHost);
return CrossPoolMigrateCommand.CanExecute(vm, preSelectedHost, force);
}
}
internal class CrossPoolCopyTemplateCommand : CrossPoolCopyVMCommand
{
public CrossPoolCopyTemplateCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection)
: this(mainWindow, selection, null)
: this(mainWindow, selection, null, false)
{ }
public CrossPoolCopyTemplateCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost)
: base(mainWindow, selection, preSelectedHost)
public CrossPoolCopyTemplateCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost, bool force)
: base(mainWindow, selection, preSelectedHost, force)
{
}
@ -91,12 +91,12 @@ namespace XenAdmin.Commands
get { return Messages.MAINWINDOW_COPY_TEMPLATE; }
}
public new static bool CanExecute(VM vm, Host preSelectedHost)
public new static bool CanExecute(VM vm, Host preSelectedHost, bool force)
{
if (vm == null || !vm.is_a_template || vm.DefaultTemplate() || vm.Locked)
return false;
return CrossPoolMigrateCommand.CanExecute(vm, preSelectedHost);
return CrossPoolMigrateCommand.CanExecute(vm, preSelectedHost, force);
}
}
}

View File

@ -48,17 +48,21 @@ namespace XenAdmin.Commands
internal class CrossPoolMigrateCommand : VMOperationCommand
{
private bool _resumeAfter;
internal bool _force = false;
public CrossPoolMigrateCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection)
public CrossPoolMigrateCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, bool force)
: base(mainWindow, selection)
{ }
{
_force = force;
}
protected Host preSelectedHost = null;
public CrossPoolMigrateCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost, bool resumeAfter=false)
public CrossPoolMigrateCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost, bool force, bool resumeAfter=false)
: base(mainWindow, selection)
{
this.preSelectedHost = preSelectedHost;
_resumeAfter = resumeAfter;
_force = force;
}
public override string MenuText
@ -66,7 +70,11 @@ namespace XenAdmin.Commands
get
{
if (preSelectedHost == null)
{
if (_force)
return "Force " + Messages.HOST_MENU_CPM_TEXT;
return Messages.HOST_MENU_CPM_TEXT;
}
var cantExecuteReason = CantExecuteReason;
return string.IsNullOrEmpty(cantExecuteReason)
@ -92,7 +100,7 @@ namespace XenAdmin.Commands
}
else
{
var wizard = new CrossPoolMigrateWizard(con, selection, preSelectedHost, WizardMode.Migrate, _resumeAfter);
var wizard = new CrossPoolMigrateWizard(con, selection, preSelectedHost, WizardMode.Migrate, _force, _resumeAfter);
MainWindowCommandInterface.ShowPerConnectionWizard(con, wizard);
}
}
@ -114,10 +122,10 @@ namespace XenAdmin.Commands
protected override bool CanExecute(VM vm)
{
if (preSelectedHost == null)
return CanExecute(vm, preSelectedHost);
return CanExecute(vm, preSelectedHost, _force);
var filter = new CrossPoolMigrateCanMigrateFilter(preSelectedHost, new List<VM> {vm}, WizardMode.Migrate);
var canExecute = CanExecute(vm, preSelectedHost, filter);
var filter = new CrossPoolMigrateCanMigrateFilter(preSelectedHost, new List<VM> {vm}, WizardMode.Migrate, _force);
var canExecute = CanExecute(vm, preSelectedHost, _force, filter);
if (string.IsNullOrEmpty(filter.Reason))
cantExecuteReasons.Remove(vm);
else
@ -125,14 +133,14 @@ namespace XenAdmin.Commands
return canExecute;
}
public static bool CanExecute(VM vm, Host preselectedHost, CrossPoolMigrateCanMigrateFilter filter = null)
public static bool CanExecute(VM vm, Host preselectedHost, bool force, CrossPoolMigrateCanMigrateFilter filter = null)
{
bool failureFound = false;
if (preselectedHost != null)
{
failureFound = filter == null
? new CrossPoolMigrateCanMigrateFilter(preselectedHost, new List<VM> {vm}, WizardMode.Migrate).FailureFound
? new CrossPoolMigrateCanMigrateFilter(preselectedHost, new List<VM> {vm}, WizardMode.Migrate, force).FailureFound
: filter.FailureFound;
}

View File

@ -42,8 +42,8 @@ namespace XenAdmin.Commands
/// </summary>
internal class CrossPoolMigrateToHomeCommand : CrossPoolMigrateCommand
{
public CrossPoolMigrateToHomeCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost)
: base(mainWindow, selection, preSelectedHost)
public CrossPoolMigrateToHomeCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost, bool force)
: base(mainWindow, selection, preSelectedHost, force)
{
}

View File

@ -40,11 +40,11 @@ namespace XenAdmin.Commands
internal class CrossPoolMoveVMCommand : CrossPoolMigrateCommand
{
public CrossPoolMoveVMCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection)
: this(mainWindow, selection, null)
: this(mainWindow, selection, null, false)
{ }
public CrossPoolMoveVMCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost)
: base(mainWindow, selection, preSelectedHost)
public CrossPoolMoveVMCommand(IMainWindow mainWindow, IEnumerable<SelectedItem> selection, Host preSelectedHost, bool force)
: base(mainWindow, selection, preSelectedHost, force)
{
}
@ -64,22 +64,22 @@ namespace XenAdmin.Commands
else
{
MainWindowCommandInterface.ShowPerConnectionWizard(con,
new CrossPoolMigrateWizard(con, selection, preSelectedHost, GetWizardMode(selection)));
new CrossPoolMigrateWizard(con, selection, preSelectedHost, GetWizardMode(selection), _force));
}
}
protected override bool CanExecute(VM vm)
{
return CanExecute(vm, preSelectedHost);
return CanExecute(vm, preSelectedHost, _force);
}
public static bool CanExecute(VM vm, Host preSelectedHost)
public static bool CanExecute(VM vm, Host preSelectedHost, bool force)
{
if (vm == null || vm.is_a_template || vm.Locked || vm.power_state == vm_power_state.Running)
return false;
return CrossPoolMigrateCommand.CanExecute(vm, preSelectedHost);
return CrossPoolMigrateCommand.CanExecute(vm, preSelectedHost, force);
}
public static WizardMode GetWizardMode(SelectedItemCollection selection)

View File

@ -180,7 +180,7 @@ namespace XenAdmin.Commands
List<SelectedItem> selectedItems = new List<SelectedItem>();
draggedVMs.ForEach(vm => selectedItems.Add(new SelectedItem(vm)));
new CrossPoolMoveVMCommand(MainWindowCommandInterface, selectedItems, targetHost)
new CrossPoolMoveVMCommand(MainWindowCommandInterface, selectedItems, targetHost, false)
.Execute();
}
}

View File

@ -230,7 +230,7 @@ namespace XenAdmin.Commands
{
List<SelectedItem> selectedItems = new List<SelectedItem>();
draggedVMs.ForEach(vm => selectedItems.Add(new SelectedItem(vm)));
new CrossPoolMigrateCommand(MainWindowCommandInterface, selectedItems, targetHost).Execute();
new CrossPoolMigrateCommand(MainWindowCommandInterface, selectedItems, targetHost, false).Execute();
return;
}
}

View File

@ -95,7 +95,7 @@ namespace XenAdmin.Commands
private static bool CanExecute(VM vm)
{
return vm != null && (CrossPoolMoveVMCommand.CanExecute(vm, null) || vm.CanBeMoved());
return vm != null && (CrossPoolMoveVMCommand.CanExecute(vm, null, false) || vm.CanBeMoved());
}
public override string MenuText

View File

@ -43,6 +43,8 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
{
private List<VM> selectedVMs;
private WizardMode wizardMode;
private bool force = false;
// A 2-level cache to store the result of CrossPoolMigrateCanMigrateFilter.
// Cache structure is like: <vm-ref, <host-ref, fault-reason>>.
private IDictionary<string, IDictionary<string, string>> migrateFilterCache =
@ -50,14 +52,15 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
public CrossPoolMigrateDestinationPage()
: this(null, WizardMode.Migrate, null)
: this(null, WizardMode.Migrate, null, false)
{
}
public CrossPoolMigrateDestinationPage(List<VM> selectedVMs, WizardMode wizardMode, List<IXenConnection> ignoredConnections)
public CrossPoolMigrateDestinationPage(List<VM> selectedVMs, WizardMode wizardMode, List<IXenConnection> ignoredConnections, bool force)
{
this.selectedVMs = selectedVMs;
this.wizardMode = wizardMode;
this.force = force;
this.ignoredConnections = ignoredConnections ?? new List<IXenConnection>();
InitializeText();
@ -134,7 +137,7 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
var filters = new List<ReasoningFilter>
{
new ResidentHostIsSameAsSelectionFilter(xenItem, selectedVMs),
new CrossPoolMigrateCanMigrateFilter(xenItem, selectedVMs, wizardMode, migrateFilterCache),
new CrossPoolMigrateCanMigrateFilter(xenItem, selectedVMs, wizardMode, force, migrateFilterCache),
new WlbEnabledFilter(xenItem, selectedVMs)
};
return new DelayLoadingOptionComboBoxItem(xenItem, filters);
@ -151,7 +154,7 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
vmList.Add(selectedVMs.Find(vm => vm.opaque_ref == opaqueRef));
filters.Add(new ResidentHostIsSameAsSelectionFilter(selectedItem.Item, vmList));
filters.Add(new CrossPoolMigrateCanMigrateFilter(selectedItem.Item, vmList, wizardMode, migrateFilterCache));
filters.Add(new CrossPoolMigrateCanMigrateFilter(selectedItem.Item, vmList, wizardMode, force, migrateFilterCache));
filters.Add(new WlbEnabledFilter(selectedItem.Item, vmList));
}

View File

@ -69,15 +69,17 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
private WizardMode wizardMode;
private bool _force;
private bool _resumeAfterMigrate;
// Note that resumeAfter is currently only implemented for Migrate mode, used for resume on server functionality
public CrossPoolMigrateWizard(IXenConnection con, SelectedItemCollection selection, Host targetHostPreSelection, WizardMode mode, bool resumeAfterMigrate = false)
public CrossPoolMigrateWizard(IXenConnection con, SelectedItemCollection selection, Host targetHostPreSelection, WizardMode mode, bool force, bool resumeAfterMigrate = false)
: base(con)
{
InitializeComponent();
hostPreSelection = targetHostPreSelection;
wizardMode = mode;
_force = force;
InitialiseWizard(selection);
_resumeAfterMigrate = resumeAfterMigrate;
}
@ -184,7 +186,7 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
UpdateWindowTitle();
m_pageDestination = new CrossPoolMigrateDestinationPage(vmsFromSelection,
wizardMode, GetSourceConnectionsForSelection(selection))
wizardMode, GetSourceConnectionsForSelection(selection), _force)
{
VmMappings = m_vmMappings,
Connection = selection.GetConnectionOfFirstItem()
@ -271,14 +273,14 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
}
}
if (moveStorage)
new VMMoveAction(vm, pair.Value.Storage, target).RunAsync();
new VMMoveAction(vm, pair.Value.Storage, target).RunAsync();
}
else
{
var isCopy = wizardMode == WizardMode.Copy;
AsyncAction migrateAction;
if (isCopy || IsStorageMotion(pair))
migrateAction = new VMCrossPoolMigrateAction(vm, target, SelectedTransferNetwork, pair.Value, isCopy);
migrateAction = new VMCrossPoolMigrateAction(vm, target, SelectedTransferNetwork, pair.Value, isCopy, _force);
else
migrateAction = new VMMigrateAction(vm, target);
@ -340,6 +342,11 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
: wizardMode == WizardMode.Move
? Messages.MOVE_VM_WIZARD_TITLE
: IsCopyTemplate() ? Messages.COPY_TEMPLATE_WIZARD_TITLE : Messages.COPY_VM_WIZARD_TITLE;
if (_force)
{
Text = "Force " + Text;
}
}
protected override void UpdateWizardContent(XenTabPage page)

View File

@ -48,9 +48,10 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard.Filters
private readonly List<VM> preSelectedVMs;
private IDictionary<string, IDictionary<string, string>> cache;
private bool canceled = false;
private readonly bool force = false;
private static readonly Object cacheLock = new Object();
public CrossPoolMigrateCanMigrateFilter(IXenObject itemAddedToComboBox, List<VM> preSelectedVMs, WizardMode wizardMode, IDictionary<string, IDictionary<string, string>> cache = null)
public CrossPoolMigrateCanMigrateFilter(IXenObject itemAddedToComboBox, List<VM> preSelectedVMs, WizardMode wizardMode, bool force, IDictionary<string, IDictionary<string, string>> cache = null)
: base(itemAddedToComboBox)
{
_wizardMode = wizardMode;
@ -59,6 +60,8 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard.Filters
else
this.cache = cache;
this.force = force;
if (preSelectedVMs == null)
throw new ArgumentNullException("Pre-selected VMs are null");
this.preSelectedVMs = preSelectedVMs;
@ -147,14 +150,16 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard.Filters
Session session = host.Connection.DuplicateSession();
Dictionary<string, string> receiveMapping = Host.migrate_receive(session, host.opaque_ref, network.opaque_ref, new Dictionary<string, string>());
Dictionary<string, string> options = new Dictionary<string, string>();
if (force)
options.Add("force", "true");
VM.assert_can_migrate(vm.Connection.Session,
vm.opaque_ref,
receiveMapping,
true,
GetVdiMap(vm, targetSrs),
vm.Connection == host.Connection ? new Dictionary<XenRef<VIF>, XenRef<XenAPI.Network>>() : GetVifMap(vm, targetNetwork),
//TODO: Implement force=true as general option
new Dictionary<string, string>(){{ "force", "true" }});
options);
lock (cacheLock)
{
vmCache.Add(host.opaque_ref, string.Empty);

View File

@ -52,7 +52,7 @@ namespace XenAdmin.Actions.VMActions
/// <param name="mapping">the storage and networking mappings</param>
/// <param name="copy">weather this should be a cross-pool copy (true) or migrate (false) operation</param>
/// <param name="force">weather this should be forced</param>
public VMCrossPoolMigrateAction(VM vm, Host destinationHost, XenAPI.Network transferNetwork, VmMapping mapping, bool copy, bool force=true)
public VMCrossPoolMigrateAction(VM vm, Host destinationHost, XenAPI.Network transferNetwork, VmMapping mapping, bool copy, bool force)
: base(vm.Connection, GetTitle(vm, destinationHost, copy))
{
Session = vm.Connection.Session;