CA-110160: Fixed uncaught exception in VM migrate wizard observed while concurrent migrate operation is triggered on same VM

- before leaving each page of the wizard, check if all selected VMs are still available for migration

Signed-off-by: Mihaela Stoica <mihaela.stoica@citrix.com>
This commit is contained in:
Mihaela Stoica 2013-11-19 17:02:02 +00:00
parent 8c9502e4ba
commit 739c3d4837
9 changed files with 162 additions and 33 deletions

View File

@ -103,13 +103,6 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
return filters;
}
private void ShowWarningMessageBox(string message)
{
new ThreeButtonDialog(
new ThreeButtonDialog.Details(SystemIcons.Warning, message, Messages.CPM_WIZARD_TITLE)).ShowDialog(
Program.MainWindow);
}
public override void PageLeave(XenAdmin.Controls.PageLoadedDirection direction, ref bool cancel)
{
if (!cancel)
@ -120,12 +113,19 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
{
if (Connection == null || !Connection.IsConnected)
{
ShowWarningMessageBox(Messages.CPM_WIZARD_ERROR_TARGET_DISCONNECTED);
CrossPoolMigrateWizard.ShowWarningMessageBox(Messages.CPM_WIZARD_ERROR_TARGET_DISCONNECTED);
targetDisconnected = true;
}
});
cancel = targetDisconnected;
}
if (!cancel && !CrossPoolMigrateWizard.AllVMsAvailable(selectedVMs))
{
cancel = true;
SetButtonNextEnabled(false);
}
base.PageLeave(direction, ref cancel);
}
}

View File

@ -29,7 +29,10 @@
* SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using XenAdmin.Controls;
using XenAdmin.Wizards.GenericPages;
using XenAPI;
@ -66,5 +69,17 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
List<VIF> vifs = Connection.ResolveAll(vm.VIFs);
return new CrossPoolMigrationNetworkResourceContainer(vifs);
}
public override void PageLeave(PageLoadedDirection direction, ref bool cancel)
{
if (!CrossPoolMigrateWizard.AllVMsAvailable(VmMappings, Connection))
{
cancel = true;
SetButtonNextEnabled(false);
SetButtonPreviousEnabled(false);
}
base.PageLeave(direction, ref cancel);
}
}
}

View File

@ -29,8 +29,10 @@
* SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using XenAdmin.Controls;
using XenAdmin.Wizards.GenericPages;
using XenAPI;
@ -75,9 +77,25 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
public override StorageResourceContainer ResourceData(string sysId)
{
VM vm = Connection.Resolve(new XenRef<VM>(sysId));
if (vm == null)
return null;
List<VDI> vdis = Connection.ResolveAll(vm.VBDs).Select(v => vm.Connection.Resolve(v.VDI)).ToList();
vdis.RemoveAll(vdi => vdi == null || Connection.Resolve(vdi.SR).GetSRType(true) == SR.SRTypes.iso);
return new CrossPoolMigrationStorageResourceContainer(vdis);
}
public override void PageLeave(PageLoadedDirection direction, ref bool cancel)
{
if (!CrossPoolMigrateWizard.AllVMsAvailable(VmMappings, Connection))
{
cancel = true;
SetButtonNextEnabled(false);
SetButtonPreviousEnabled(false);
}
base.PageLeave(direction, ref cancel);
}
}
}

View File

@ -31,13 +31,17 @@
using System.Collections.Generic;
using XenAdmin.Controls;
using XenAPI;
namespace XenAdmin.Wizards.CrossPoolMigrateWizard
{
public partial class CrossPoolMigrateTransferNetworkPage : XenTabPage
{
public CrossPoolMigrateTransferNetworkPage()
private List<VM> selectedVMs;
public CrossPoolMigrateTransferNetworkPage(List<VM> selectedVMs)
{
this.selectedVMs = selectedVMs;
InitializeComponent();
InitializeCustomPageElements();
}
@ -49,6 +53,9 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
networkComboBox.IncludeOnlyNetworksWithIPAddresses = true;
}
private bool m_buttonNextEnabled;
private bool m_buttonPreviousEnabled;
#region Base class (XenTabPage) overrides
/// <summary>
@ -74,7 +81,7 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
public override void PageLoaded(PageLoadedDirection direction)
{
base.PageLoaded(direction);//call first so the page gets populated
OnPageUpdated();
SetButtonsEnabled(true);
}
public override void PopulatePage()
@ -89,7 +96,33 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
get { return networkComboBox.SelectedNetworkUuid; }
}
public override bool EnableNext()
{
return m_buttonNextEnabled;
}
public override bool EnablePrevious()
{
return m_buttonPreviousEnabled;
}
public override void PageLeave(PageLoadedDirection direction, ref bool cancel)
{
if (!CrossPoolMigrateWizard.AllVMsAvailable(selectedVMs))
{
cancel = true;
SetButtonsEnabled(false);
}
base.PageLeave(direction, ref cancel);
}
#endregion
protected void SetButtonsEnabled(bool enabled)
{
m_buttonNextEnabled = enabled;
m_buttonPreviousEnabled = enabled;
OnPageUpdated();
}
}
}

View File

@ -128,7 +128,7 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
m_pageStorage = new CrossPoolMigrateStoragePage();
m_pageNetwork = new CrossPoolMigrateNetworkingPage();
m_pageTransferNetwork = new CrossPoolMigrateTransferNetworkPage();
m_pageTransferNetwork = new CrossPoolMigrateTransferNetworkPage(VmsFromSelection(selection));
m_pageFinish = new CrossPoolMigrateFinishPage {SummaryRetreiver = GetVMMappingSummary};
m_pageTargetRbac = new RBACWarningPage();
@ -143,6 +143,12 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
protected override void FinishWizard()
{
if (!AllVMsAvailable(m_vmMappings, xenConnection))
{
base.FinishWizard();
return;
}
foreach (KeyValuePair<string, VmMapping> pair in m_vmMappings)
{
VM vm = xenConnection.Resolve(new XenRef<VM>(pair.Key));
@ -314,5 +320,58 @@ namespace XenAdmin.Wizards.CrossPoolMigrateWizard
}
return summary.Details;
}
/// <summary>
/// Checks if all VMs are still available for migration and shows a warning message if the check fails
/// </summary>
/// <returns>true if check succeded, false if failed</returns>
internal static bool AllVMsAvailable(List<VM> vms)
{
Func<bool> vmCheck = delegate
{
if (vms == null || vms.Count == 0 || vms[0] == null || vms[0].Connection == null)
return false;
var connection = vms[0].Connection; // the connection on which to check VM availability
return vms.All(vm => connection.Resolve(new XenRef<VM>(vm.opaque_ref)) != null);
};
return PerformCheck(vmCheck);
}
/// <summary>
/// Checks if all VMs are still available for migration and shows a warning message if the check fails
/// </summary>
/// <returns>true if check succeded, false if failed</returns>
internal static bool AllVMsAvailable(Dictionary<string, VmMapping> vmMappings, IXenConnection connection)
{
Func<bool> vmCheck = delegate
{
if (vmMappings == null || vmMappings.Count == 0 || connection == null)
return false;
return vmMappings.All(kvp => connection.Resolve(new XenRef<VM>(kvp.Key)) != null);
};
return PerformCheck(vmCheck);
}
/// <summary>
/// Performs a certain check and shows a warning message if the check fails
/// </summary>
/// <param name="check">The check to perform</param>
/// <returns>true if check succeded, false if failed</returns>
private static bool PerformCheck(Func<bool> check)
{
if (check())
return true;
ShowWarningMessageBox(Messages.CPM_WIZARD_VM_MISSING_ERROR);
return false;
}
internal static void ShowWarningMessageBox(string message)
{
new ThreeButtonDialog(
new ThreeButtonDialog.Details(SystemIcons.Warning, message, Messages.CPM_WIZARD_TITLE)).ShowDialog(
Program.MainWindow);
}
}
}

View File

@ -204,8 +204,8 @@ namespace XenAdmin.Wizards.GenericPages
public abstract DelayLoadingOptionComboBoxItem CreateDelayLoadingOptionComboBoxItem(IXenObject xenItem);
#region Private methods
private void SetButtonNextEnabled(bool enabled)
protected void SetButtonNextEnabled(bool enabled)
{
m_buttonNextEnabled = enabled;
OnPageUpdated();

View File

@ -95,15 +95,6 @@ namespace XenAdmin.Wizards.GenericPages
public override void PageLeave(PageLoadedDirection direction, ref bool cancel)
{
targetConnection = null;
if (VmMappings.Select(kvp => kvp.Key).Any(sysId => NetworkData(sysId) == null))
{
ShowWarningMessageBox(Messages.CPM_WIZARD_VM_MISSING_ERROR);
cancel = true;
SetButtonNextEnabled(false);
SetButtonPreviousEnabled(false);
}
base.PageLeave(direction, ref cancel);
}
@ -288,13 +279,5 @@ namespace XenAdmin.Wizards.GenericPages
m_dataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
IsDirty = true;
}
private void ShowWarningMessageBox(string message)
{
new ThreeButtonDialog(
new ThreeButtonDialog.Details(SystemIcons.Warning, message, Messages.CPM_WIZARD_TITLE)).ShowDialog(
Program.MainWindow);
}
}
}

View File

@ -101,6 +101,7 @@ namespace XenAdmin.Wizards.GenericPages
private ulong m_totalSpaceRequired;
private Dictionary<string, VmMapping> m_vmMappings;
private bool m_buttonNextEnabled;
private bool m_buttonPreviousEnabled;
#endregion
@ -142,11 +143,17 @@ namespace XenAdmin.Wizards.GenericPages
{
TargetConnection = null;
if (direction == PageLoadedDirection.Forward && IsDirty && ImplementsIsDirty())
if (!cancel && direction == PageLoadedDirection.Forward && IsDirty && ImplementsIsDirty())
cancel = !PerformCheck(CheckStorageRequirements);
base.PageLeave(direction, ref cancel);
}
}
public override void PageLoaded(PageLoadedDirection direction)
{
base.PageLoaded(direction);//call first so the page gets populated
SetButtonPreviousEnabled(true);
}
public abstract StorageResourceContainer ResourceData(string sysId);
@ -292,6 +299,11 @@ namespace XenAdmin.Wizards.GenericPages
return m_buttonNextEnabled;
}
public override bool EnablePrevious()
{
return m_buttonPreviousEnabled;
}
#endregion
#region Accessors
@ -341,12 +353,18 @@ namespace XenAdmin.Wizards.GenericPages
return success;
}
private void SetButtonNextEnabled(bool enabled)
protected void SetButtonNextEnabled(bool enabled)
{
m_buttonNextEnabled = enabled;
OnPageUpdated();
}
protected void SetButtonPreviousEnabled(bool enabled)
{
m_buttonPreviousEnabled = enabled;
OnPageUpdated();
}
private bool CheckStorageRequirements(out string error)
{
error = string.Empty;

View File

@ -204,6 +204,9 @@ namespace XenAdmin.Wizards.GenericPages
foreach (var pair in mapping.Storage)
{
VDI vdi = connection.Resolve(new XenRef<VDI>(pair.Key));
if (vdi == null)
continue;
string valueToAdd = vdi.Name + separatorText + pair.Value.Name;
if (pair.Key == mapping.Storage.First().Key)