mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-11-25 14:27:26 +01:00
73eaed6af8
- Fixed button enablement on the IntraPoolCopy page.
- Regression on the NewDiskDialog were selection was considered valid
even if the SR was disabled.The SrSelectionChanged and SelectedIndexChanged
were fired in the wrong order. To fix this the event SrSelectionChanged
is removed (in reality after the refactoring in 5b79b1dc94
it became obsolete).
Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
518 lines
19 KiB
C#
518 lines
19 KiB
C#
/* 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 System.Windows.Forms;
|
|
using System.Linq;
|
|
using XenAdmin.Controls;
|
|
using XenAdmin.Core;
|
|
using XenAdmin.Network;
|
|
using XenAPI;
|
|
using XenAdmin.Actions;
|
|
using System.Drawing;
|
|
|
|
|
|
namespace XenAdmin.Dialogs
|
|
{
|
|
public partial class NewDiskDialog : XenDialogBase
|
|
{
|
|
private enum DiskSizeUnits { MB, GB }
|
|
|
|
#region Private fields
|
|
|
|
private readonly VM TheVM;
|
|
private readonly SR TheSR;
|
|
|
|
private VDI DiskTemplate;
|
|
private bool CanResize;
|
|
private long MinSize;
|
|
private decimal min;
|
|
private decimal max;
|
|
|
|
private readonly IEnumerable<VDI> _VDINamesInUse = new List<VDI>();
|
|
|
|
private const int DecimalPlacesGB = 3; // show 3 decimal places for GB (CA-91322)
|
|
private const int DecimalPlacesMB = 0;
|
|
private const int IncrementGB = 1;
|
|
private const int IncrementMB = 256;
|
|
|
|
private const decimal MinimumDiskSizeGB = 0.001m;
|
|
private const int MinimumDiskSizeMB = 1;
|
|
private DiskSizeUnits currentSelectedUnits = DiskSizeUnits.GB;
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
private NewDiskDialog(IXenConnection connection, IEnumerable<VDI> vdiNamesInUse)
|
|
: base(connection)
|
|
{
|
|
if (connection == null)
|
|
throw new ArgumentNullException("connection");
|
|
|
|
InitializeComponent();
|
|
|
|
_VDINamesInUse = vdiNamesInUse;
|
|
SrListBox.Connection = connection;
|
|
NameTextBox.Text = GetDefaultVDIName();
|
|
max = (decimal)Math.Pow(1024, 4);//1 Petabit
|
|
min = 0;
|
|
comboBoxUnits.SelectedItem = comboBoxUnits.Items[0];
|
|
SetNumUpDownIncrementAndDecimals(DiskSizeNumericUpDown, comboBoxUnits.SelectedItem.ToString());
|
|
updateErrorsAndButtons();
|
|
}
|
|
|
|
public NewDiskDialog(IXenConnection connection, SR sr)
|
|
: this(connection, new List<VDI>())
|
|
{
|
|
TheSR = sr;
|
|
SrListBox.Usage = SrPicker.SRPickerType.InstallFromTemplate;
|
|
SrListBox.SetAffinity(null);
|
|
SrListBox.selectSRorNone(TheSR);
|
|
}
|
|
|
|
public NewDiskDialog(IXenConnection connection, VM vm)
|
|
: this(connection, vm, SrPicker.SRPickerType.VM, null, vm.Home(), true, 0, new List<VDI>())
|
|
{ }
|
|
|
|
public NewDiskDialog(IXenConnection connection, VM vm, SrPicker.SRPickerType pickerUsage, VDI diskTemplate,
|
|
Host affinity, bool canResize, long minSize, IEnumerable<VDI> vdiNamesInUse)
|
|
: this(connection, vdiNamesInUse)
|
|
{
|
|
TheVM = vm;
|
|
DiskTemplate = diskTemplate;
|
|
CanResize = canResize;
|
|
MinSize = minSize;
|
|
SrListBox.Usage = pickerUsage;
|
|
SrListBox.SetAffinity(affinity);
|
|
|
|
Pool pool_sr = Helpers.GetPoolOfOne(connection);
|
|
if (pool_sr != null)
|
|
{
|
|
SrListBox.DefaultSR = connection.Resolve(pool_sr.default_SR); //if default sr resolves to null the first sr in the list will be selected
|
|
}
|
|
SrListBox.selectDefaultSROrAny();
|
|
|
|
LoadValues();
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void LoadValues()
|
|
{
|
|
if (DiskTemplate == null)
|
|
return;
|
|
|
|
NameTextBox.Text = DiskTemplate.Name();
|
|
DescriptionTextBox.Text = DiskTemplate.Description();
|
|
SrListBox.selectSRorDefaultorAny(connection.Resolve(DiskTemplate.SR));
|
|
|
|
// select the appropriate unit, based on size (CA-45905)
|
|
currentSelectedUnits = DiskTemplate.virtual_size >= Util.BINARY_GIGA ? DiskSizeUnits.GB : DiskSizeUnits.MB;
|
|
SelectedUnits = currentSelectedUnits;
|
|
SetNumUpDownIncrementAndDecimals(DiskSizeNumericUpDown, SelectedUnits.ToString());
|
|
decimal newValue = (decimal)Math.Round((double)DiskTemplate.virtual_size / GetUnits(), DiskSizeNumericUpDown.DecimalPlaces);
|
|
DiskSizeNumericUpDown.Value = newValue >= DiskSizeNumericUpDown.Minimum && newValue <= DiskSizeNumericUpDown.Maximum ?
|
|
newValue : DiskSizeNumericUpDown.Maximum;
|
|
|
|
if (MinSize > 0)
|
|
min = (decimal)((double)MinSize / GetUnits());
|
|
DiskSizeNumericUpDown.Enabled = CanResize;
|
|
|
|
Text = Messages.EDIT_DISK;
|
|
OkButton.Text = Messages.OK;
|
|
}
|
|
|
|
private string GetDefaultVDIName()
|
|
{
|
|
List<string> usedNames = new List<string>();
|
|
foreach (VDI v in connection.Cache.VDIs.Concat(_VDINamesInUse))
|
|
{
|
|
usedNames.Add(v.Name());
|
|
}
|
|
return Helpers.MakeUniqueName(Messages.DEFAULT_VDI_NAME, usedNames);
|
|
}
|
|
|
|
private void srListBox_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
updateErrorsAndButtons();
|
|
}
|
|
|
|
private void OkButton_Click(object sender, EventArgs e)
|
|
{
|
|
if (SrListBox.SR == null || NameTextBox.Text == "" || !connection.IsConnected)
|
|
return;
|
|
|
|
if (DontCreateVDI)
|
|
{
|
|
DialogResult = DialogResult.OK;
|
|
Close();
|
|
return;
|
|
}
|
|
XenAPI.SR sr = SrListBox.SR;
|
|
if (!sr.shared && TheVM != null && TheVM.HaPriorityIsRestart())
|
|
{
|
|
DialogResult dialogResult;
|
|
using (var dlg = new ThreeButtonDialog(
|
|
new ThreeButtonDialog.Details(SystemIcons.Warning, Messages.NEW_SR_DIALOG_ATTACH_NON_SHARED_DISK_HA, Messages.XENCENTER),
|
|
ThreeButtonDialog.ButtonYes,
|
|
ThreeButtonDialog.ButtonNo))
|
|
{
|
|
dialogResult = dlg.ShowDialog(Program.MainWindow);
|
|
}
|
|
if (dialogResult != DialogResult.Yes)
|
|
return;
|
|
new HAUnprotectVMAction(TheVM).RunExternal(TheVM.Connection.Session);
|
|
}
|
|
|
|
VDI vdi = NewDisk();
|
|
|
|
|
|
if (TheVM != null)
|
|
{
|
|
var alreadyHasBootableDisk = HasBootableDisk(TheVM);
|
|
|
|
Actions.DelegatedAsyncAction action = new Actions.DelegatedAsyncAction(connection,
|
|
string.Format(Messages.ACTION_DISK_ADDING_TITLE, NameTextBox.Text, sr.NameWithoutHost()),
|
|
Messages.ACTION_DISK_ADDING, Messages.ACTION_DISK_ADDED,
|
|
delegate(XenAPI.Session session)
|
|
{
|
|
// Get legitimate unused userdevice numbers
|
|
string[] uds = XenAPI.VM.get_allowed_VBD_devices(session, TheVM.opaque_ref);
|
|
if (uds.Length == 0)
|
|
{
|
|
throw new Exception(FriendlyErrorNames.VBDS_MAX_ALLOWED);
|
|
}
|
|
string ud = uds[0];
|
|
string vdiref = VDI.create(session, vdi);
|
|
XenAPI.VBD vbd = NewDevice();
|
|
vbd.VDI = new XenAPI.XenRef<XenAPI.VDI>(vdiref);
|
|
vbd.VM = new XenAPI.XenRef<XenAPI.VM>(TheVM);
|
|
|
|
// CA-44959: only make bootable if there aren't other bootable VBDs.
|
|
vbd.bootable = ud == "0" && !alreadyHasBootableDisk;
|
|
vbd.userdevice = ud;
|
|
|
|
// Now try to plug the VBD.
|
|
var plugAction = new VbdSaveAndPlugAction(TheVM, vbd, vdi.Name(), session, false);
|
|
plugAction.ShowUserInstruction += PlugAction_ShowUserInstruction;
|
|
plugAction.RunAsync();
|
|
});
|
|
|
|
action.VM = TheVM;
|
|
using (var dialog = new ActionProgressDialog(action, ProgressBarStyle.Blocks))
|
|
dialog.ShowDialog();
|
|
if (!action.Succeeded)
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
CreateDiskAction action = new CreateDiskAction(vdi);
|
|
using (var dialog = new ActionProgressDialog(action, ProgressBarStyle.Marquee))
|
|
dialog.ShowDialog();
|
|
if (!action.Succeeded)
|
|
return;
|
|
}
|
|
DialogResult = DialogResult.OK;
|
|
Close();
|
|
}
|
|
|
|
private void PlugAction_ShowUserInstruction(string message)
|
|
{
|
|
Program.Invoke(Program.MainWindow, () =>
|
|
{
|
|
if (!Program.RunInAutomatedTestMode)
|
|
{
|
|
using (var dlg = new ThreeButtonDialog(
|
|
new ThreeButtonDialog.Details(SystemIcons.Information, message)))
|
|
{
|
|
dlg.ShowDialog(Program.MainWindow);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private static bool HasBootableDisk(VM vm)
|
|
{
|
|
var c = vm.Connection;
|
|
foreach (XenRef<VBD> vbdRef in vm.VBDs)
|
|
{
|
|
var vbd = c.Resolve(vbdRef);
|
|
|
|
if (vbd != null && !vbd.IsCDROM() && !vbd.IsFloppyDrive() && vbd.bootable)
|
|
{
|
|
VDI vdi = c.Resolve(vbd.VDI);
|
|
|
|
if (vdi != null)
|
|
{
|
|
SR sr = c.Resolve(vdi.SR);
|
|
if (sr != null && sr.IsToolsSR())
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void SetNumUpDownIncrementAndDecimals(NumericUpDown upDown, string units)
|
|
{
|
|
if (units == Messages.VAL_GIGB)
|
|
{
|
|
upDown.DecimalPlaces = DecimalPlacesGB;
|
|
upDown.Increment = IncrementGB;
|
|
}
|
|
else
|
|
{
|
|
upDown.DecimalPlaces = DecimalPlacesMB;
|
|
upDown.Increment = IncrementMB;
|
|
}
|
|
}
|
|
|
|
public VDI NewDisk()
|
|
{
|
|
VDI vdi = new VDI();
|
|
vdi.Connection = connection;
|
|
vdi.read_only = DiskTemplate != null ? DiskTemplate.read_only : false;
|
|
vdi.SR = new XenAPI.XenRef<XenAPI.SR>(SrListBox.SR);
|
|
|
|
vdi.virtual_size = Convert.ToInt64(DiskSizeNumericUpDown.Value * GetUnits());
|
|
vdi.name_label = NameTextBox.Text;
|
|
vdi.name_description = DescriptionTextBox.Text;
|
|
vdi.sharable = DiskTemplate != null ? DiskTemplate.sharable : false;
|
|
vdi.type = DiskTemplate != null ? DiskTemplate.type : vdi_type.user;
|
|
vdi.SetVmHint(TheVM != null ? TheVM.uuid : "");
|
|
return vdi;
|
|
}
|
|
|
|
private long GetUnits()
|
|
{
|
|
return (SelectedUnits == DiskSizeUnits.GB ? Util.BINARY_GIGA : Util.BINARY_MEGA);
|
|
}
|
|
|
|
public VBD NewDevice()
|
|
{
|
|
|
|
VBD vbd = new VBD();
|
|
vbd.Connection = connection;
|
|
vbd.device = "";
|
|
vbd.empty = false;
|
|
vbd.type = XenAPI.vbd_type.Disk;
|
|
vbd.mode = XenAPI.vbd_mode.RW;
|
|
vbd.SetIsOwner(true);
|
|
vbd.unpluggable = true;
|
|
return vbd;
|
|
|
|
}
|
|
|
|
private void NameTextBox_TextChanged(object sender, EventArgs e)
|
|
{
|
|
updateErrorsAndButtons();
|
|
}
|
|
|
|
private DiskSizeUnits SelectedUnits
|
|
{
|
|
get { return comboBoxUnits.SelectedIndex == 0 ? DiskSizeUnits.GB : DiskSizeUnits.MB; }
|
|
set { comboBoxUnits.SelectedIndex = value == DiskSizeUnits.GB ? 0 : 1; }
|
|
}
|
|
|
|
private decimal GetDiskTooSmallMessageMinSize()
|
|
{
|
|
return min == 0 ? SelectedUnits == DiskSizeUnits.GB ? MinimumDiskSizeGB : MinimumDiskSizeMB : min;
|
|
}
|
|
|
|
private void updateErrorsAndButtons()
|
|
{
|
|
// Ordering is important here, we want to show the most relevant message
|
|
|
|
if (comboBoxUnits.SelectedItem == null)
|
|
return;
|
|
|
|
if (!SrListBox.ValidSelectionExists)
|
|
{
|
|
OkButton.Enabled = false;
|
|
setError(Messages.NO_VALID_DISK_LOCATION);
|
|
return;
|
|
}
|
|
if (SrListBox.SR == null)
|
|
{
|
|
OkButton.Enabled = false;
|
|
// shouldn't happen I think, previous if block should catch this, just to be safe
|
|
setError(null);
|
|
return;
|
|
}
|
|
if (DiskSizeNumericUpDown.Text.Trim() == string.Empty)
|
|
{
|
|
OkButton.Enabled = false;
|
|
// too minor for scary error to be displayed, plus it's obvious as they have to
|
|
// delete the default entry and can see the OK button disable as they do so
|
|
setError(null);
|
|
return;
|
|
}
|
|
if (!DiskSizeValidNumber())
|
|
{
|
|
OkButton.Enabled = false;
|
|
setError(Messages.INVALID_NUMBER);
|
|
return;
|
|
}
|
|
if (!DiskSizeValid())
|
|
{
|
|
OkButton.Enabled = false;
|
|
setError(string.Format(Messages.DISK_TOO_SMALL, GetDiskTooSmallMessageMinSize(),
|
|
comboBoxUnits.SelectedItem.ToString()));
|
|
return;
|
|
}
|
|
if (string.IsNullOrEmpty(NameTextBox.Text.Trim()))
|
|
{
|
|
OkButton.Enabled = false;
|
|
// too minor for scary error to be displayed, plus it's obvious as they have to
|
|
// delete the default entry and can see the OK button disable as they do so
|
|
setError(null);
|
|
return;
|
|
}
|
|
|
|
OkButton.Enabled = true;
|
|
setError(null);
|
|
}
|
|
|
|
private void setError(string error)
|
|
{
|
|
if (string.IsNullOrEmpty(error))
|
|
tableLayoutPanelError.Visible = false;
|
|
else
|
|
{
|
|
tableLayoutPanelError.Visible = true;
|
|
labelError.Text = error;
|
|
}
|
|
}
|
|
|
|
private bool DiskSizeValidNumber()
|
|
{
|
|
decimal val;
|
|
return decimal.TryParse(DiskSizeNumericUpDown.Text.Trim(), out val);
|
|
}
|
|
|
|
private bool DiskSizeValid()
|
|
{
|
|
decimal val;
|
|
if (decimal.TryParse(DiskSizeNumericUpDown.Text.Trim(), out val))
|
|
{
|
|
if (min == 0)
|
|
return val > min && val <= max;
|
|
return val >= min && val <= max;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void CloseButton_Click(object sender, EventArgs e)
|
|
{
|
|
DialogResult = DialogResult.Cancel;
|
|
Close();
|
|
}
|
|
|
|
public bool DontCreateVDI { get; set; }
|
|
|
|
private void DiskSizeNumericUpDown_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateDiskSize();
|
|
}
|
|
|
|
private void DiskSizeNumericUpDown_TextChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateDiskSize();
|
|
}
|
|
|
|
private void DiskSizeNumericUpDown_KeyUp(object sender, KeyEventArgs e)
|
|
{
|
|
UpdateDiskSize();
|
|
}
|
|
|
|
private void UpdateDiskSize()
|
|
{
|
|
// Don't use DiskSizeNumericUpDown.Value here, as it will fire the NumericUpDown built-in validation. Use Text property instead. (CA-46028)
|
|
decimal newValue;
|
|
if (decimal.TryParse(DiskSizeNumericUpDown.Text.Trim(), out newValue))
|
|
{
|
|
try
|
|
{
|
|
SrListBox.DiskSize = (long)(Math.Round(newValue * GetUnits()));
|
|
}
|
|
catch (OverflowException)
|
|
{
|
|
//CA-71312
|
|
SrListBox.DiskSize = newValue < 0 ? long.MinValue : long.MaxValue;
|
|
}
|
|
SrListBox.UpdateDiskSize();
|
|
}
|
|
RefreshMinSize();
|
|
updateErrorsAndButtons();
|
|
}
|
|
|
|
private void RefreshMinSize()
|
|
{
|
|
if (DiskTemplate == null)
|
|
return;
|
|
if (MinSize > 0)
|
|
min = (decimal)((double)MinSize / GetUnits());
|
|
}
|
|
|
|
private void comboBoxUnits_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
//Check if the new unit is different than the previous one otherwise discard the change
|
|
if (currentSelectedUnits != SelectedUnits)
|
|
{
|
|
currentSelectedUnits = SelectedUnits;
|
|
//Convert the current value to the new units
|
|
decimal newValue = (decimal)Math.Round(SelectedUnits == DiskSizeUnits.GB ? ((double)DiskSizeNumericUpDown.Value / 1024) : ((double)DiskSizeNumericUpDown.Value * 1024), DiskSizeNumericUpDown.DecimalPlaces);
|
|
DiskSizeNumericUpDown.Value = newValue >= DiskSizeNumericUpDown.Minimum && newValue <= DiskSizeNumericUpDown.Maximum ?
|
|
newValue : DiskSizeNumericUpDown.Maximum;
|
|
SetNumUpDownIncrementAndDecimals(DiskSizeNumericUpDown, comboBoxUnits.SelectedItem.ToString());
|
|
UpdateDiskSize();
|
|
}
|
|
}
|
|
|
|
internal override string HelpName
|
|
{
|
|
get
|
|
{
|
|
if (DiskTemplate != null)
|
|
return "EditNewDiskDialog";
|
|
else
|
|
return "NewDiskDialog";
|
|
}
|
|
}
|
|
}
|
|
}
|