2017-01-16 20:59:50 +01:00
|
|
|
|
/* Copyright (c) Citrix Systems, Inc.
|
2013-06-24 13:41:48 +02:00
|
|
|
|
* 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.Windows.Forms;
|
|
|
|
|
using XenAdmin.Network;
|
|
|
|
|
using XenAPI;
|
|
|
|
|
using XenAdmin.Core;
|
|
|
|
|
using XenAdmin.Controls.DataGridViewEx;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace XenAdmin.Controls
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This control is used by both the New VM Wizard and the Import VM Wizard.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public partial class AffinityPicker : UserControl
|
|
|
|
|
{
|
|
|
|
|
private IXenConnection Connection;
|
|
|
|
|
private Host SrHost;
|
|
|
|
|
private Host Affinity;
|
|
|
|
|
|
2014-01-31 11:58:05 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Should always be true if the AffinityPicker is used to create a VM.
|
|
|
|
|
/// If set to false (e.g. on Edit VM) and Affinity is null, then the "no home server" radio button remains enabled,
|
|
|
|
|
/// meaning that the VM already has no affinity and should not try to automatically select one.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal bool AutoSelectAffinity = true;
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
public event EventHandler SelectedAffinityChanged = new EventHandler(OnSelectedAffinityChanged);
|
|
|
|
|
|
|
|
|
|
private static void OnSelectedAffinityChanged(object obj, EventArgs e) { }
|
|
|
|
|
|
|
|
|
|
public AffinityPicker()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetAffinity(IXenConnection connection, Host affinity, Host srhost)
|
|
|
|
|
{
|
|
|
|
|
Connection = connection;
|
|
|
|
|
Affinity = affinity;
|
|
|
|
|
SrHost = srhost;
|
|
|
|
|
tableLayoutPanelWlbWarning.Visible = Helpers.WlbEnabledAndConfigured(connection);
|
|
|
|
|
LoadServers();
|
|
|
|
|
_UpdateControl();
|
|
|
|
|
SelectRadioButtons();
|
|
|
|
|
SelectedAffinityChanged(SelectedAffinity, new EventArgs());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LoadServers()
|
|
|
|
|
{
|
|
|
|
|
ServersGridView.Rows.Clear();
|
|
|
|
|
|
|
|
|
|
List<Host> hosts = new List<Host>(Connection.Cache.Hosts);
|
|
|
|
|
hosts.Sort();
|
|
|
|
|
foreach (Host host in hosts)
|
|
|
|
|
ServersGridView.Rows.Add(new ServerGridRow(host, true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateControl()
|
|
|
|
|
{
|
|
|
|
|
_UpdateControl();
|
|
|
|
|
|
|
|
|
|
SelectedAffinityChanged(SelectedAffinity, new EventArgs());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// does not fire selected affinity changed event
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void _UpdateControl()
|
|
|
|
|
{
|
|
|
|
|
if (Connection == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Update enablement
|
2014-01-31 11:58:05 +01:00
|
|
|
|
DynamicRadioButton.Enabled = (Helpers.HasFullyConnectedSharedStorage(Connection) && SrHost == null) ||
|
|
|
|
|
(Affinity == null && !AutoSelectAffinity);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
ServersGridView.Enabled = StaticRadioButton.Checked;
|
2013-09-27 14:33:57 +02:00
|
|
|
|
DynamicRadioButton.Text = Helpers.HasFullyConnectedSharedStorage(Connection)
|
|
|
|
|
? Messages.AFFINITY_PICKER_DYNAMIC_SHARED_SR
|
|
|
|
|
: Messages.AFFINITY_PICKER_DYNAMIC_NOT_SHARED_SR;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SelectRadioButtons()
|
|
|
|
|
{
|
2013-10-18 11:02:25 +02:00
|
|
|
|
if (!SelectAffinityServer() && DynamicRadioButton.Enabled)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
//Trace.Assert(DynamicRadioButton.Enabled, "Could not select any hosts or find shared storage");
|
|
|
|
|
DynamicRadioButton.Checked = true; // always set dynamic check state before static because static check has an event handler
|
|
|
|
|
StaticRadioButton.Checked = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DynamicRadioButton.Checked = false; // always set dynamic check state before static because static check has an event handler
|
|
|
|
|
StaticRadioButton.Checked = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Host SelectedAffinity
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return DynamicRadioButton.Checked ? null : SelectedServer();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Host SelectedServer()
|
|
|
|
|
{
|
|
|
|
|
if (ServersGridView.SelectedRows.Count == 0)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
Host h = ((ServerGridRow)ServersGridView.SelectedRows[0]).Server;
|
|
|
|
|
if (h == null)
|
|
|
|
|
return null;
|
|
|
|
|
return h;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool SelectServer(Host host)
|
|
|
|
|
{
|
|
|
|
|
foreach (ServerGridRow row in ServersGridView.Rows)
|
|
|
|
|
{
|
|
|
|
|
if (row.Server.opaque_ref != host.opaque_ref)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (row.Enabled)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
row.Selected = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-18 11:02:25 +02:00
|
|
|
|
private bool SelectAffinityServer()
|
|
|
|
|
{
|
|
|
|
|
return Affinity != null && SelectServer(Affinity);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
private bool SelectSomething()
|
|
|
|
|
{
|
|
|
|
|
//Now decide if we want to select anything.
|
|
|
|
|
bool selected = false;
|
|
|
|
|
|
|
|
|
|
if (Affinity != null)
|
|
|
|
|
selected = SelectServer(Affinity);
|
|
|
|
|
|
|
|
|
|
if (!selected && SrHost != null)
|
|
|
|
|
selected = SelectServer(SrHost);
|
|
|
|
|
|
|
|
|
|
/* if (!selected)
|
|
|
|
|
selected = SelectAnyServer();*/
|
|
|
|
|
|
|
|
|
|
return selected;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool ValidState()
|
|
|
|
|
{
|
|
|
|
|
return SelectedAffinity != null || DynamicRadioButton.Checked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void affinityListBox_SelectedValueChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
UpdateControl();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we dont need to bother firing events if the other radio button gets checked or unchecked
|
|
|
|
|
private void StaticRadioButton_CheckedChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (StaticRadioButton.Checked && SelectedServer() == null)
|
|
|
|
|
SelectSomething();
|
|
|
|
|
UpdateControl();
|
|
|
|
|
|
|
|
|
|
if (StaticRadioButton.Checked)
|
|
|
|
|
ServersGridView.Select();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnEnter(EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (DynamicRadioButton.Checked)
|
|
|
|
|
DynamicRadioButton.Select();
|
|
|
|
|
else
|
|
|
|
|
ServersGridView.Select();
|
|
|
|
|
}
|
2016-07-25 12:51:33 +02:00
|
|
|
|
|
|
|
|
|
bool selectedOnVisibleChanged = false;
|
|
|
|
|
|
|
|
|
|
private void ServersGridView_VisibleChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (!selectedOnVisibleChanged)
|
|
|
|
|
{
|
|
|
|
|
selectedOnVisibleChanged = true;
|
|
|
|
|
SelectSomething();//CA-213728
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal class ServerGridRow : DataGridViewExRow
|
|
|
|
|
{
|
|
|
|
|
public readonly Host Server;
|
|
|
|
|
|
|
|
|
|
private readonly DataGridViewExImageCell ImageCell = new DataGridViewExImageCell();
|
|
|
|
|
private readonly DataGridViewTextBoxCell NameCell = new DataGridViewTextBoxCell();
|
|
|
|
|
private readonly DataGridViewTextBoxCell ReasonCell = new DataGridViewTextBoxCell();
|
|
|
|
|
|
|
|
|
|
private readonly bool showReason;
|
|
|
|
|
|
|
|
|
|
public ServerGridRow(Host server, bool showReason)
|
|
|
|
|
{
|
|
|
|
|
Server = server;
|
|
|
|
|
this.showReason = showReason;
|
|
|
|
|
|
|
|
|
|
Cells.Add(ImageCell);
|
|
|
|
|
Cells.Add(NameCell);
|
|
|
|
|
|
|
|
|
|
if (showReason)
|
|
|
|
|
{
|
|
|
|
|
Cells.Add(ReasonCell);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpdateDetails();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateDetails()
|
|
|
|
|
{
|
|
|
|
|
ImageCell.Value = Images.GetImage16For(Server);
|
2017-09-03 04:33:29 +02:00
|
|
|
|
NameCell.Value = Server.Name();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
bool isLiveHost = Server.IsLive();
|
|
|
|
|
Enabled = isLiveHost;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
if (showReason)
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
ReasonCell.Value = isLiveHost ? Server.HostMemoryString() : Messages.HOMESERVER_PICKER_HOST_NOT_LIVE;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|