mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-12-30 07:40:13 +01:00
8091a9bc63
Now we set Increment exactly as on other pages when the unit is MB: the increment it will be calculated dynamically (1, 2, 4,...) when GB, increment will be 1 GB for values >=10GB, 0.1GB otherwise Signed-off-by: Gabor Apati-Nagy <gabor.apati-nagy@citrix.com>
350 lines
13 KiB
C#
350 lines
13 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 XenAPI;
|
|
using XenAdmin.Controls;
|
|
using XenAdmin.Controls.Ballooning;
|
|
using XenAdmin.Core;
|
|
|
|
|
|
namespace XenAdmin.Wizards.NewVMWizard
|
|
{
|
|
public partial class Page_CpuMem : XenTabPage
|
|
{
|
|
private VM Template;
|
|
int memoryMode = 1; // number of spinners to show: 1 for just "memory", 2 for "minimum" and "maximum", 3 for "static max" too
|
|
double memoryRatio = 0.0; // the permitted ratio of dynamic_min / static_max
|
|
bool initialising = true;
|
|
|
|
public Page_CpuMem()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
public override string Text
|
|
{
|
|
get { return Messages.NEWVMWIZARD_CPUMEMPAGE_NAME; }
|
|
}
|
|
|
|
public override string PageTitle
|
|
{
|
|
get { return Messages.NEWVMWIZARD_CPUMEMPAGE_TITLE; }
|
|
}
|
|
|
|
public override string HelpID
|
|
{
|
|
get { return "CPU&Memory"; }
|
|
}
|
|
|
|
public override void PageLoaded(PageLoadedDirection direction)
|
|
{
|
|
base.PageLoaded(direction);
|
|
|
|
if (SelectedTemplate == Template)
|
|
return;
|
|
|
|
initialising = true;
|
|
|
|
Template = SelectedTemplate;
|
|
if (Template.has_ballooning && !Helpers.FeatureForbidden(Template, Host.RestrictDMC))
|
|
memoryMode = (Template.memory_dynamic_max == Template.memory_static_max ? 2 : 3);
|
|
else
|
|
memoryMode = 1;
|
|
|
|
memoryRatio = VMMemoryControlsEdit.GetMemoryRatio(Template);
|
|
|
|
FreeSpinnerLimits();
|
|
|
|
if (memoryMode == 1)
|
|
{
|
|
spinnerDynMin.Initialize(Messages.MEMORY_COLON, null, Template.memory_static_max, Template.memory_static_max);
|
|
spinnerDynMax.Visible = spinnerStatMax.Visible = false;
|
|
}
|
|
else
|
|
{
|
|
spinnerDynMax.Visible = true;
|
|
spinnerDynMin.Initialize(Messages.DYNAMIC_MIN_COLON, null, Template.memory_dynamic_min, Template.memory_static_max);
|
|
FreeSpinnerLimits(); // same as CA-33831
|
|
spinnerDynMax.Initialize(Messages.DYNAMIC_MAX_COLON, null, Template.memory_dynamic_max, Template.memory_static_max);
|
|
if (memoryMode == 3)
|
|
{
|
|
FreeSpinnerLimits();
|
|
spinnerStatMax.Initialize(Messages.STATIC_MAX_COLON, null, Template.memory_static_max, Template.memory_static_max);
|
|
}
|
|
else
|
|
spinnerStatMax.Visible = false;
|
|
}
|
|
|
|
comboBoxTopology.Populate(Template.VCPUs_at_startup, Template.VCPUs_max, Template.CoresPerSocket, Template.MaxCoresPerSocket);
|
|
PopulateVCPUs(Template.MaxVCPUsAllowed, Template.VCPUs_at_startup);
|
|
|
|
SetSpinnerLimitsAndIncrement();
|
|
|
|
ValuesUpdated();
|
|
|
|
initialising = false;
|
|
}
|
|
|
|
private void PopulateVCPUs(long maxVCPUs, long currentVCPUs)
|
|
{
|
|
comboBoxVCPUs.BeginUpdate();
|
|
comboBoxVCPUs.Items.Clear();
|
|
for (long i = 1; i <= maxVCPUs; ++i)
|
|
{
|
|
if (i == currentVCPUs || comboBoxTopology.IsValidVCPU(i))
|
|
comboBoxVCPUs.Items.Add(i);
|
|
}
|
|
if (currentVCPUs > maxVCPUs)
|
|
comboBoxVCPUs.Items.Add(currentVCPUs);
|
|
comboBoxVCPUs.SelectedItem = currentVCPUs;
|
|
comboBoxVCPUs.EndUpdate();
|
|
}
|
|
|
|
public VM SelectedTemplate { private get; set; }
|
|
|
|
// Return the larger of the template's MaxMemAllowed and the template's static max,
|
|
// to avoid crashes in the spinners (CA-40041).
|
|
private long MaxMemAllowed
|
|
{
|
|
get
|
|
{
|
|
long msm = Template.memory_static_max;
|
|
long mma = Template.MaxMemAllowed;
|
|
return (msm > mma ? msm : mma);
|
|
}
|
|
}
|
|
|
|
private void FreeSpinnerLimits()
|
|
{
|
|
long maxMemAllowed = MaxMemAllowed;
|
|
spinnerDynMin.SetRange(0, maxMemAllowed);
|
|
spinnerDynMax.SetRange(0, maxMemAllowed);
|
|
spinnerStatMax.SetRange(0, maxMemAllowed);
|
|
}
|
|
|
|
private void SetSpinnerLimitsAndIncrement()
|
|
{
|
|
spinnerDynMin.Increment = spinnerDynMax.Increment = spinnerStatMax.Increment = VMMemoryControlsEdit.CalcIncrement(Template.memory_static_max, spinnerDynMin.Units);
|
|
|
|
long maxMemAllowed = MaxMemAllowed;
|
|
double min = Template.memory_static_min;
|
|
if (memoryMode == 1)
|
|
{
|
|
spinnerDynMin.SetRange(min, maxMemAllowed);
|
|
return;
|
|
}
|
|
long min2 = (long)(SelectedMemoryStaticMax * memoryRatio);
|
|
if (min < min2)
|
|
min = min2;
|
|
double max = SelectedMemoryDynamicMax;
|
|
if (max < min)
|
|
max = min;
|
|
spinnerDynMin.SetRange(min, max);
|
|
spinnerDynMax.SetRange(SelectedMemoryDynamicMin,
|
|
memoryMode == 2 ? maxMemAllowed : SelectedMemoryStaticMax);
|
|
spinnerStatMax.SetRange(SelectedMemoryDynamicMax, maxMemAllowed);
|
|
}
|
|
|
|
public void DisableMemoryControls()
|
|
{
|
|
spinnerDynMin.Enabled = false;
|
|
spinnerDynMax.Enabled = false;
|
|
spinnerStatMax.Enabled = false;
|
|
}
|
|
|
|
public double SelectedMemoryDynamicMin
|
|
{
|
|
get
|
|
{
|
|
return spinnerDynMin.Value;
|
|
}
|
|
}
|
|
|
|
public double SelectedMemoryDynamicMax
|
|
{
|
|
get
|
|
{
|
|
return memoryMode == 1 ? spinnerDynMin.Value : spinnerDynMax.Value;
|
|
}
|
|
}
|
|
|
|
public double SelectedMemoryStaticMax
|
|
{
|
|
get
|
|
{
|
|
return
|
|
memoryMode == 1 ? spinnerDynMin.Value :
|
|
memoryMode == 2 ? spinnerDynMax.Value :
|
|
spinnerStatMax.Value;
|
|
}
|
|
}
|
|
|
|
public long SelectedVcpus
|
|
{
|
|
get
|
|
{
|
|
return (long)comboBoxVCPUs.SelectedItem;
|
|
}
|
|
}
|
|
|
|
public long SelectedCoresPerSocket
|
|
{
|
|
get
|
|
{
|
|
return comboBoxTopology.CoresPerSocket;
|
|
}
|
|
}
|
|
|
|
public override List<KeyValuePair<string, string>> PageSummary
|
|
{
|
|
get
|
|
{
|
|
List<KeyValuePair<string, string>> sum = new List<KeyValuePair<string, string>>();
|
|
sum.Add(new KeyValuePair<string, string>(Messages.NEWVMWIZARD_CPUMEMPAGE_VCPUS, SelectedVcpus.ToString()));
|
|
sum.Add(new KeyValuePair<string, string>(Messages.NEWVMWIZARD_CPUMEMPAGE_TOPOLOGY, comboBoxTopology.Text));
|
|
if (memoryMode == 1)
|
|
sum.Add(new KeyValuePair<string, string>(Messages.MEMORY, Util.MemorySizeStringSuitableUnits(SelectedMemoryStaticMax, false)));
|
|
else
|
|
{
|
|
sum.Add(new KeyValuePair<string, string>(Messages.DYNAMIC_MIN, Util.MemorySizeStringSuitableUnits(SelectedMemoryDynamicMin, false)));
|
|
sum.Add(new KeyValuePair<string, string>(Messages.DYNAMIC_MAX, Util.MemorySizeStringSuitableUnits(SelectedMemoryDynamicMax, false)));
|
|
if (memoryMode == 3)
|
|
sum.Add(new KeyValuePair<string, string>(Messages.STATIC_MAX, Util.MemorySizeStringSuitableUnits(SelectedMemoryStaticMax, false)));
|
|
}
|
|
return sum;
|
|
}
|
|
}
|
|
|
|
private void ValuesUpdated()
|
|
{
|
|
CheckForError();
|
|
OnPageUpdated();
|
|
}
|
|
|
|
private void CheckForError()
|
|
{
|
|
long max_mem_total = 0;
|
|
long max_mem_free = 0;
|
|
long max_vcpus = 0;
|
|
Host max_mem_total_host = null;
|
|
Host max_mem_free_host = null;
|
|
Host max_vcpus_host = null;
|
|
|
|
foreach (Host host in Connection.Cache.Hosts)
|
|
{
|
|
long host_cpus = 0;
|
|
|
|
foreach (Host_cpu cpu in Connection.Cache.Host_cpus)
|
|
{
|
|
if (cpu.host.opaque_ref.Equals(host.opaque_ref))
|
|
host_cpus++;
|
|
}
|
|
|
|
Host_metrics metrics = Connection.Resolve(host.metrics);
|
|
|
|
if (host_cpus > max_vcpus)
|
|
{
|
|
max_vcpus = host_cpus;
|
|
max_vcpus_host = host;
|
|
}
|
|
|
|
if (metrics != null && metrics.memory_total > max_mem_total)
|
|
{
|
|
max_mem_total = metrics.memory_total;
|
|
max_mem_total_host = host;
|
|
}
|
|
|
|
// The available memory of a server is taken to be the current memory_free,
|
|
// plus however much we can squeeze down the existing VMs. This assumes
|
|
// that the overhead won't increase when we create the new VM, so it
|
|
// has false negatives.
|
|
long memory_free = host.memory_available_calc;
|
|
|
|
if (metrics != null && memory_free > max_mem_free)
|
|
{
|
|
max_mem_free = memory_free;
|
|
max_mem_free_host = host;
|
|
}
|
|
}
|
|
|
|
if (max_mem_total_host != null && SelectedMemoryDynamicMin > max_mem_total)
|
|
{
|
|
ErrorPanel.Visible = true;
|
|
ErrorLabel.Text = string.Format(Messages.NEWVMWIZARD_CPUMEMPAGE_MEMORYWARN1, Helpers.GetName(max_mem_total_host), Util.MemorySizeStringSuitableUnits(max_mem_total, false));
|
|
}
|
|
else if (max_mem_free_host != null && SelectedMemoryDynamicMin > max_mem_free)
|
|
{
|
|
ErrorPanel.Visible = true;
|
|
ErrorLabel.Text = string.Format(Messages.NEWVMWIZARD_CPUMEMPAGE_MEMORYWARN2, Helpers.GetName(max_mem_free_host), Util.MemorySizeStringSuitableUnits(max_mem_free, false));
|
|
}
|
|
else if (max_vcpus_host != null && SelectedVcpus > max_vcpus)
|
|
{
|
|
ErrorPanel.Visible = true;
|
|
ErrorLabel.Text = string.Format(Messages.NEWVMWIZARD_CPUMEMPAGE_VCPUSWARN, Helpers.GetName(max_vcpus_host), max_vcpus);
|
|
}
|
|
else
|
|
{
|
|
ErrorPanel.Visible = false;
|
|
}
|
|
}
|
|
|
|
private void vCPU_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
comboBoxTopology.Update((long)comboBoxVCPUs.SelectedItem);
|
|
ValuesUpdated();
|
|
ValidateVCPUSettings();
|
|
}
|
|
|
|
private void memory_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
if (initialising)
|
|
return;
|
|
|
|
SetSpinnerLimitsAndIncrement();
|
|
ValuesUpdated();
|
|
}
|
|
|
|
private void ValidateVCPUSettings()
|
|
{
|
|
if (comboBoxVCPUs.SelectedItem != null)
|
|
labelInvalidVCPUWarning.Text = VM.ValidVCPUConfiguration((long)comboBoxVCPUs.SelectedItem, comboBoxTopology.CoresPerSocket);
|
|
}
|
|
|
|
private void comboBoxTopology_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
ValidateVCPUSettings();
|
|
}
|
|
}
|
|
}
|