xenadmin/XenAdmin/Controls/NetworkingTab/NetworkList.cs
Gabor Apati-Nagy 92f0499911 CA-149867: Invoke on MainWindow instead of various controls
We observed that some threads can reach deadlock-ish state after they have Invoked into a control's UI thread. When it happens they are all in a waiting for join or in sleep state for very long time, although there should not be any deadlock situations.
It seems this has something to do with multiple parent controls and with which control we invoked on. This should not make a difference, because we have got one UI thread (for MainWindow) they should wait for, but we have seen it does.

The solution that fixed this issue was to invoke on the MainWindow instead of various controls (see a4fe507adf ).

This changeset is changing all our Invokes to invoke into MainWindow
instead of a control itself. (MainWindow's UI thread is the only UI thread
all Control is using in XenCenter)
This changeset should be in place until we have found the root cause or the exact reason for the above.
2015-04-08 15:16:10 +01:00

1038 lines
43 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.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using XenAdmin.Commands;
using XenAdmin.Model;
using XenAPI;
using XenAdmin.Core;
using XenAdmin.Wizards;
using XenAdmin.Actions;
using XenAdmin.Dialogs;
using XenAdmin.Controls.DataGridViewEx;
namespace XenAdmin.Controls.NetworkingTab
{
public partial class NetworkList : UserControl
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public NetworkList()
{
InitializeComponent();
Properties.Settings.Default.PropertyChanged += Default_PropertyChanged;
}
private IXenObject _xenObject = null;
private bool QoSRestricted = false;
public IXenObject XenObject
{
get
{
Program.AssertOnEventThread();
return _xenObject;
}
set
{
Program.AssertOnEventThread();
// Remove all old property change listeners. They will get added back in the
// population of the DataGridView that follows (see BuildList).
DegregisterEventsOnXmo();
DeregisterEventsOnGridRows();
if (_xenObject is Host || _xenObject is Pool)
{
_xenObject.Connection.Cache.DeregisterBatchCollectionChanged<XenAPI.Network>(NetworkCollectionChanged);
_xenObject.Connection.Cache.DeregisterBatchCollectionChanged<PIF>(PIFCollectionChanged);
}
else if (_xenObject is VM)
{
_xenObject.Connection.Cache.DeregisterBatchCollectionChanged<VIF>(CollectionChanged);
_xenObject.Connection.Cache.DeregisterBatchCollectionChanged<VM_guest_metrics>(VM_guest_metrics_BatchCollectionChanged);
}
_xenObject = value;
if (_xenObject != null)
_xenObject.PropertyChanged += Server_PropertyChanged;
if (_xenObject is Host || _xenObject is Pool)
{
AddNetworkColumns();
_xenObject.Connection.Cache.RegisterBatchCollectionChanged<XenAPI.Network>(NetworkCollectionChanged);
_xenObject.Connection.Cache.RegisterBatchCollectionChanged<PIF>(PIFCollectionChanged);
AddNetworkButton.Text = Messages.HOST_NETWORK_TAB_ADD_BUTTON_LABEL;
EditNetworkButton.Text = Messages.HOST_NETWORK_TAB_EDIT_BUTTON_LABEL;
RemoveNetworkButton.Text = Messages.HOST_NETWORK_TAB_REMOVE_BUTTON_LABEL;
// This is the divider for the activate button, hide this as well as the button
groupBox1.Visible = false;
buttonActivateToggle.Visible = false;
}
else if (_xenObject is VM)
{
AddVifColumns();
_xenObject.Connection.Cache.RegisterBatchCollectionChanged<VIF>(CollectionChanged);
// update the list when we get new metrics
_xenObject.Connection.Cache.RegisterBatchCollectionChanged<VM_guest_metrics>(VM_guest_metrics_BatchCollectionChanged);
// Check if QoS is enabled for this VM
Host currentHost = Helpers.GetMaster(_xenObject.Connection);
QoSRestricted = currentHost != null && currentHost.RestrictQoS;
AddNetworkButton.Text = Messages.VM_NETWORK_TAB_ADD_BUTTON_LABEL;
EditNetworkButton.Text = Messages.VM_NETWORK_TAB_EDIT_BUTTON_LABEL;
RemoveNetworkButton.Text = Messages.VM_NETWORK_TAB_REMOVE_BUTTON_LABEL;
groupBox1.Visible = true;
buttonActivateToggle.Visible = true;
}
BuildList();
}
}
private void DegregisterEventsOnXmo()
{
if (XenObject == null)
return;
XenObject.PropertyChanged -= Server_PropertyChanged;
if (XenObject is VM)
{
VM vm = (VM)XenObject;
VM_guest_metrics vmGuestMetrics = vm.Connection.Resolve(vm.guest_metrics);
if (vmGuestMetrics != null)
vmGuestMetrics.PropertyChanged -= Server_PropertyChanged;
}
}
private void AddNetworkColumns()
{
// catch the sorting column and sorting order, so they could be restored after the columns are added to the grid (SCTX-501)
DataGridViewColumn previousSortColumn = NetworksGridView.SortedColumn;
SortOrder previousSortOrder = NetworksGridView.SortOrder == SortOrder.None ? SortOrder.Ascending : NetworksGridView.SortOrder;
try
{
NetworksGridView.SuspendLayout();
NetworksGridView.Columns.Clear();
NetworksGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.ImageColumn,
this.NameColumn,
this.DescriptionColumn,
this.NicColumn,
this.VlanColumn,
this.AutoColumn,
this.LinkStatusColumn,
this.NetworkMacColumn});
//CA-47050: the Description column should be autosized to Fill, but should not become smaller than a minimum
//width, which here is chosen to be the column header width. To find what this width is set temporarily the
//column's autosize mode to ColumnHeader.
this.DescriptionColumn.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;
int storedWidth = this.DescriptionColumn.Width;
this.DescriptionColumn.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
this.DescriptionColumn.MinimumWidth = storedWidth;
// add MTU to grid view on Network tab for pools and hosts, for Cowley or greater only (CA-45643)
if (Helpers.CowleyOrGreater(_xenObject.Connection))
NetworksGridView.Columns.Add(this.MtuColumn);
}
finally
{
NetworksGridView.ResumeLayout();
}
// restore the sorting column (SCTX-501)
RestoreSortingColumn(previousSortColumn, previousSortOrder, NicColumn);
}
private void AddVifColumns()
{
// catch the sorting column and sorting order, so they could be restored after the columns are added to the grid (SCTX-501)
DataGridViewColumn previousSortColumn = NetworksGridView.SortedColumn;
SortOrder previousSortOrder = NetworksGridView.SortOrder == SortOrder.None ? SortOrder.Ascending : NetworksGridView.SortOrder;
NetworksGridView.Columns.Clear();
NetworksGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.ImageColumn,
this.DeviceColumn,
this.VifMacColumn,
this.LimitColumn,
this.NetworkColumn,
this.IpColumn,
this.ActiveColumn});
//the IP column should be autosized to Fill, but should not become smaller than a minimum
//width, which here is chosen to be the column header width. To find what this width is set temporarily the
//column's autosize mode to ColumnHeader.
this.IpColumn.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;
int storedWidth = this.DescriptionColumn.Width;
this.IpColumn.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
this.IpColumn.MinimumWidth = storedWidth;
// restore the sorting column (SCTX-501)
RestoreSortingColumn(previousSortColumn, previousSortOrder, DeviceColumn);
}
private void RestoreSortingColumn(DataGridViewColumn previousSortColumn, SortOrder previousSortOrder, DataGridViewColumn defaultSortColumn)
{
// SCTX-501 preserve the sorting column
if ((previousSortColumn == null) || !NetworksGridView.Columns.Contains(previousSortColumn))
{
previousSortColumn = defaultSortColumn;
previousSortOrder = SortOrder.Ascending;
// try to get the old sort order from the SortGlyph
foreach (System.Windows.Forms.DataGridViewColumn column in NetworksGridView.Columns)
if (column.HeaderCell.SortGlyphDirection != SortOrder.None)
{
previousSortColumn = column;
previousSortOrder = column.HeaderCell.SortGlyphDirection;
break;
}
}
if (previousSortColumn != null)
{
// clear any old sort glyphs; this is necessary as a result of the
// change for CA-45643 (MTU column only added for Cowley or greater pools)
foreach (System.Windows.Forms.DataGridViewColumn column in NetworksGridView.Columns)
column.HeaderCell.SortGlyphDirection = SortOrder.None;
NetworksGridView.Sort(
previousSortColumn,
previousSortOrder == SortOrder.Ascending ? ListSortDirection.Ascending : ListSortDirection.Descending);
}
}
void VM_guest_metrics_BatchCollectionChanged(object sender, EventArgs e)
{
Program.Invoke(Program.MainWindow, BuildList);
}
void Default_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "ShowHiddenVMs")
{
BuildList();
}
}
public bool InBuildList = false;
public void BuildList()
{
Program.AssertOnEventThread();
if (!this.Visible)
return;
if (InBuildList)
return;
InBuildList = true;
try
{
if (XenObject == null || XenObject.Locked)
return;
if (!XenObject.Connection.CacheIsPopulated)
return;
if (XenObject is VM)
{
DeregisterEventsOnGridRows();
VIF selectedVIF = SelectedVif;
VM vm = XenObject as VM;
NetworksGridView.SuspendLayout();
NetworksGridView.Rows.Clear();
List<VIF> vifs = vm.Connection.ResolveAll(vm.VIFs);
vifs.Sort();
// CA-8981 - Listen for guest metric changes which is necessary for IP Address updates
VM_guest_metrics vmGuestMetrics = vm.Connection.Resolve(vm.guest_metrics);
if (vmGuestMetrics != null)
vmGuestMetrics.PropertyChanged += Server_PropertyChanged;
var vifRowsToAdd = new List<VifRow>();
foreach (var vif in vifs)
{
var network = vif.Connection.Resolve(vif.network);
if (network != null && network.IsGuestInstallerNetwork)
continue; // Don't show the guest installer network in the network tab (CA-73056)
vifRowsToAdd.Add(new VifRow(vif));
}
NetworksGridView.Rows.AddRange(vifRowsToAdd.ToArray());
bool selected = true;
if (selectedVIF != null)
{
foreach (VifRow row in NetworksGridView.Rows)
{
// Cannot compare opaque_ref as VIFs get destroyed / recreated on each edit.
if (row.Vif.device == selectedVIF.device)
{
row.Selected = true;
break;
}
}
}
if (!selected && NetworksGridView.Rows.Count > 0)
{
NetworksGridView.Rows[0].Selected = true;
}
}
else if (XenObject is Host || XenObject is Pool)
{
DeregisterEventsOnGridRows();
XenAPI.Network selectedNetwork = SelectedNetwork;
NetworksGridView.SuspendLayout();
NetworksGridView.Rows.Clear();
XenAPI.Network[] networks = XenObject.Connection.Cache.Networks;
Array.Sort < XenAPI.Network>(networks);
List<NetworkRow> networkRowsToAdd = new List<NetworkRow>();
for (int i = 0; i < networks.Length; i++)
{
if (!networks[i].Show(XenAdmin.Properties.Settings.Default.ShowHiddenVMs))
continue;
networkRowsToAdd.Add(new NetworkRow(networks[i], XenObject));
}
NetworksGridView.Rows.AddRange(networkRowsToAdd.ToArray());
// The following update causes this to be a lot slower with many networks. Alot! CA-43944
//foreach(NetworkRow r in NetworksGridView.Rows)
//r.UpdateDefaultCellStyle(); // Has to be done again after adding to the grid view, even though it's already called in the constructor
if (selectedNetwork != null)
{
foreach (NetworkRow row in NetworksGridView.Rows)
{
if (row.Network.opaque_ref == selectedNetwork.opaque_ref && selectedNetwork.Show(XenAdmin.Properties.Settings.Default.ShowHiddenVMs))
{
row.Selected = true;
break;
}
}
}
}
}
finally
{
if (NetworksGridView.SortedColumn != null)
{
NetworksGridView.Sort(
NetworksGridView.SortedColumn,
NetworksGridView.SortOrder == SortOrder.Ascending
? ListSortDirection.Ascending : ListSortDirection.Descending);
}
NetworksGridView.ResumeLayout();
InBuildList = false;
}
}
public void DeregisterEventsOnGridRows()
{
foreach (DataGridViewExRow row in NetworksGridView.Rows)
{
if (row is VifRow)
((VifRow)row).DeregisterEvents();
else if (row is NetworkRow)
((NetworkRow)row).DeregisterEvents();
}
}
private void NetworksGridView_SelectionChanged(object sender, EventArgs e)
{
UpdateEnablement();
}
private void UpdateEnablement()
{
bool locked = _xenObject.Locked;
if (SelectedNetwork != null)
{
XenAPI.Network TheNetwork = SelectedNetwork;
AddNetworkButton.Enabled = !locked;
EditNetworkButton.Enabled = !locked && !TheNetwork.Locked && !TheNetwork.IsSlave && !TheNetwork.CreateInProgress;
if (HasPhysicalNonBondNIC(TheNetwork))
{
RemoveNetworkButton.Enabled = false;
RemoveButtonContainer.SetToolTip(Messages.TOOLTIP_REMOVE_PIF);
}
else
{
RemoveNetworkButton.Enabled = !locked && !TheNetwork.Locked && !TheNetwork.IsSlave && !TheNetwork.CreateInProgress;
RemoveButtonContainer.SetToolTip("");
}
}
else if (SelectedVif != null)
{
VIF vif = SelectedVif;
AddNetworkButton.Enabled = !locked;
// In this case read vif.currently_attached as is-it-plugged
RemoveNetworkButton.Enabled = !locked && (vif.allowed_operations.Contains(vif_operations.unplug) || !vif.currently_attached);
EditNetworkButton.Enabled = !locked && (vif.allowed_operations.Contains(vif_operations.unplug) || !vif.currently_attached);
buttonActivateToggle.Enabled = !locked && (
vif.currently_attached && vif.allowed_operations.Contains(vif_operations.unplug)
|| !vif.currently_attached && vif.allowed_operations.Contains(vif_operations.plug));
buttonActivateToggle.Text = vif.currently_attached ? Messages.VM_NETWORK_TAB_DEACTIVATE_BUTTON_LABEL : Messages.VM_NETWORK_TAB_ACTIVATE_BUTTON_LABEL;
VM vm = (VM)XenObject;
if (vm.power_state == vm_power_state.Suspended)
{
RemoveButtonContainer.SetToolTip(Messages.TOOLTIP_REMOVE_NETWORK_SUSPENDED);
EditButtonContainer.SetToolTip(Messages.TOOLTIP_EDIT_NETWORK_TOOLS);
toolTipContainerActivateToggle.SetToolTip(vif.currently_attached
? Messages.TOOLTIP_DEACTIVATE_VIF_SUSPENDED : Messages.TOOLTIP_ACTIVATE_VIF_SUSPENDED);
}
else
{
if (vm.power_state == vm_power_state.Running && vm.GetVirtualisationStatus != XenAPI.VM.VirtualisationStatus.OPTIMIZED)
{
RemoveButtonContainer.SetToolTip(Messages.TOOLTIP_REMOVE_NETWORK_TOOLS);
EditButtonContainer.SetToolTip(Messages.TOOLTIP_EDIT_NETWORK_TOOLS);
toolTipContainerActivateToggle.SetToolTip(vif.currently_attached
? Messages.TOOLTIP_DEACTIVATE_VIF_TOOLS : Messages.TOOLTIP_ACTIVATE_VIF_TOOLS);
}
else
{
RemoveButtonContainer.RemoveAll();
EditButtonContainer.RemoveAll();
toolTipContainerActivateToggle.RemoveAll();
}
}
}
else
{
AddNetworkButton.Enabled = !locked;
RemoveNetworkButton.Enabled = false;
EditNetworkButton.Enabled = false;
buttonActivateToggle.Enabled = false;
}
}
/// <summary>
/// Return true if the given network has a PIF that represents a physical NIC -- i.e.
/// IsPhysical == true and IsBondNIC == false.
/// </summary>
/// <param name="network"></param>
/// <returns></returns>
private static bool HasPhysicalNonBondNIC(XenAPI.Network network)
{
foreach (PIF pif in network.Connection.ResolveAll(network.PIFs))
{
if (pif.IsPhysical && !pif.IsBondNIC)
return true;
}
return false;
}
private void AddNetworkButton_Click(object sender, EventArgs e)
{
if (XenObject is VM)
{
VM vm = (VM)_xenObject;
if (NetworksGridView.Rows.Count >= vm.MaxVIFsAllowed)
{
new ThreeButtonDialog(
new ThreeButtonDialog.Details(
SystemIcons.Error,
FriendlyErrorNames.VIFS_MAX_ALLOWED,
FriendlyErrorNames.VIFS_MAX_ALLOWED_TITLE)).ShowDialog(Program.MainWindow);
return;
}
Host master = Helpers.GetMaster(vm.Connection);
if (master == null)
{
// Cache populating?
return;
}
VIFDialog d = new VIFDialog(vm.Connection, null, VIF.GetDeviceId(vm));
if (d.ShowDialog(this) != DialogResult.OK)
return;
Proxy_VIF pVif = d.GetNewSettings();
pVif.VM = vm.opaque_ref;
CreateVIFCommand action = new CreateVIFCommand(Program.MainWindow, vm, pVif);
action.Execute();
}
else if (XenObject is Host)
{
Host host = (Host)_xenObject;
Program.MainWindow.ShowPerConnectionWizard(_xenObject.Connection,
new NewNetworkWizard(_xenObject.Connection, null, host));
}
else if (XenObject is Pool)
{
Pool pool = (Pool)_xenObject;
Host host = pool.Connection.Resolve(pool.master);
if (host != null)
{
Program.MainWindow.ShowPerConnectionWizard(_xenObject.Connection,
new NewNetworkWizard(_xenObject.Connection, pool, host));
}
}
}
private XenAPI.Network SelectedNetwork
{
get
{
if (NetworksGridView.SelectedRows.Count == 0)
return null;
NetworkRow row = NetworksGridView.SelectedRows[0] as NetworkRow;
if (row == null)
return null;
return row.Network;
}
}
private VIF SelectedVif
{
get
{
if (NetworksGridView.SelectedRows.Count == 0)
return null;
VifRow row = NetworksGridView.SelectedRows[0] as VifRow;
if (row == null)
return null;
return row.Vif;
}
}
private void RemoveNetworkButton_Click(object sender, EventArgs e)
{
if (NetworksGridView.SelectedRows.Count == 0)
return;
XenAPI.Network network = SelectedNetwork;
if (network != null && network.IsBond)
{
var destroyBondCommand = new DestroyBondCommand(Program.MainWindow, network);
destroyBondCommand.Execute();
}
else
{
// Check and see if the system is running in automation test mode. If so, then
// do not launch the popup Y/N dialog.
DialogResult result;
if (Program.RunInAutomatedTestMode)
{
result = DialogResult.Yes;
}
else if (XenObject is VM)
{
// Deleting a VIF, not a Network.
result = new ThreeButtonDialog(
new ThreeButtonDialog.Details(SystemIcons.Warning, Messages.MESSAGEBOX_VIF_DELETE, Messages.MESSAGEBOX_VIF_DELETE_TITLE),
ThreeButtonDialog.ButtonYes,
ThreeButtonDialog.ButtonNo).ShowDialog(Program.MainWindow);
}
else
{
result = new ThreeButtonDialog(
new ThreeButtonDialog.Details(SystemIcons.Warning, Messages.MESSAGEBOX_NETWORK_DELETE, Messages.MESSAGEBOX_NETWORK_DELETE_TITLE),
ThreeButtonDialog.ButtonYes,
ThreeButtonDialog.ButtonNo).ShowDialog(Program.MainWindow);
}
if (result == DialogResult.Yes)
{
DoRemoveNetwork();
}
}
}
private void DoRemoveNetwork()
{
if (SelectedVif != null)
{
VM vm = XenObject as VM;
var action = new DeleteVIFAction(SelectedVif);
action.Completed += action_Completed;
action.RunAsync();
}
else if(SelectedNetwork != null)
{
NetworkAction action = new NetworkAction(XenObject.Connection, SelectedNetwork,false);
action.Completed += action_Completed;
action.RunAsync();
}
}
private void buttonActivateToggle_Click(object sender, EventArgs e)
{
if (SelectedVif != null)
{
VM vm = XenObject as VM;
AsyncAction action;
if (SelectedVif.currently_attached)
action = new UnplugVIFAction(SelectedVif);
else
action = new PlugVIFAction(SelectedVif);
action.Completed += action_Completed;
action.RunAsync();
}
}
void NetworkCollectionChanged(object sender, EventArgs e)
{
Program.Invoke(Program.MainWindow, BuildList);
}
void PIFCollectionChanged(object sender, EventArgs e)
{
Program.Invoke(Program.MainWindow, BuildList);
}
void CollectionChanged(object sender, EventArgs e)
{
Program.Invoke(Program.MainWindow, BuildList);
}
void action_Completed(ActionBase sender)
{
Program.Invoke(Program.MainWindow, BuildList);
}
void Server_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// JJN- Provide a temporary fix to the bug reported in CA-9322 where the
// editing of the MAC and Limit fields is barely usable due to the continuous
// reconstruction of the list within this view. Ensure the button enablement
// does not digress with this fix.
if (shouldRefreshBuildList(e))
{
Program.Invoke(Program.MainWindow, RefreshAllItems);
}
}
private void RefreshAllItems()
{
foreach (DataGridViewExRow row in NetworksGridView.Rows)
{
if (row is VifRow)
((VifRow)row).UpdateDetails();
else if (row is NetworkRow)
((NetworkRow)row).UpdateDetails();
}
}
public static bool shouldRefreshBuildList(PropertyChangedEventArgs e)
{
return (e.PropertyName != "allowed_operations"
&& e.PropertyName != "current_operations"
&& e.PropertyName != "io_read_kbs"
&& e.PropertyName != "io_write_kbs"
&& e.PropertyName != "last_updated");
}
private void EditNetworkButton_Click(object sender, EventArgs e)
{
if (NetworksGridView.SelectedRows.Count > 0)
{
if (XenObject is VM)
{
launchVmNetworkSettingsDialog();
}
else
{
launchHostOrPoolNetworkSettingsDialog();
}
}
}
private void launchVmNetworkSettingsDialog()
{
VM vm = XenObject as VM;
VIF vif = SelectedVif;
if (vm == null || vif == null)
return;
int device;
VIFDialog d;
if (int.TryParse(vif.device, out device))
{
d = new VIFDialog(vm.Connection, vif, device);
}
else
{
log.ErrorFormat("Aborting vif edit. Could not parse existing vif device to int. Value is: '{0}'", vif.device);
return;
}
if (d.ShowDialog() != DialogResult.OK)
return;
Proxy_VIF proxyVIF = d.GetNewSettings();
UpdateVIFCommand command = new UpdateVIFCommand(Program.MainWindow, vm, vif, proxyVIF);
InBuildList = true;
command.Completed += new EventHandler((s, f) => Program.Invoke(Program.MainWindow, () =>
{
InBuildList = false;
BuildList();
}));
command.Execute();
}
private void launchHostOrPoolNetworkSettingsDialog()
{
XenAPI.Network network = SelectedNetwork;
if (network == null)
return;
new PropertiesDialog(network).ShowDialog(this);
}
private void EditMenuItemHandler(object sender, EventArgs e)
{
EditNetworkButton_Click(null, null);
}
private void AddMenuItemHandler(object sender, EventArgs e)
{
AddNetworkButton_Click(null, null);
}
private void RemoveMenuItemHandler(object sender, EventArgs e)
{
RemoveNetworkButton_Click(null, null);
}
private void NetworksGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
UpdateEnablement();
}
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
Point pt = NetworksGridView.PointToClient(new Point(contextMenuStrip1.Left, contextMenuStrip1.Top));
DataGridView.HitTestInfo info = NetworksGridView.HitTest(pt.X, pt.Y);
if (info != null && info.RowIndex >= 0 && info.RowIndex < NetworksGridView.Rows.Count)
{
DataGridViewRow row = NetworksGridView.Rows[info.RowIndex];
if (row != null)
{
row.Selected = true;
copyToolStripMenuItem.Visible = true;
addToolStripMenuItem.Visible = AddNetworkButton.Visible && AddNetworkButton.Enabled;
propertiesToolStripMenuItem.Visible = EditNetworkButton.Visible && EditNetworkButton.Enabled;
removeToolStripMenuItem.Visible = RemoveNetworkButton.Visible && RemoveNetworkButton.Enabled;
return;
}
}
// else just show add button
copyToolStripMenuItem.Visible = false;
addToolStripMenuItem.Visible = AddNetworkButton.Visible && AddNetworkButton.Enabled;
propertiesToolStripMenuItem.Visible = false;
removeToolStripMenuItem.Visible = false;
}
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
{
Point pt = NetworksGridView.PointToClient(new Point(contextMenuStrip1.Left, contextMenuStrip1.Top));
DataGridView.HitTestInfo info = NetworksGridView.HitTest(pt.X, pt.Y);
if (info != null && info.RowIndex >= 0 && info.RowIndex < NetworksGridView.Rows.Count)
{
DataGridViewRow row = NetworksGridView.Rows[info.RowIndex];
if (row != null)
{
string t = row.Cells[info.ColumnIndex].Value.ToString();
if (String.IsNullOrEmpty(t))
return;
Clipboard.SetText(t);
}
}
}
class VifRow : DataGridViewExRow
{
public VIF Vif;
private DataGridViewExImageCell ImageCell = new DataGridViewExImageCell();
private DataGridViewTextBoxCell DeviceCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell MacCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell LimitCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell NetworkCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell IpCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell AttachedCell = new DataGridViewTextBoxCell();
private VIF_metrics Metrics;
public VifRow(VIF vif)
{
Vif = vif;
Cells.AddRange(ImageCell,
DeviceCell,
MacCell,
LimitCell,
NetworkCell,
IpCell,
AttachedCell);
Vif.PropertyChanged += Server_PropertyChanged;
UpdateDetails();
}
public void UpdateDetails()
{
if(Metrics != null)
Metrics.PropertyChanged -= Server_PropertyChanged;
Metrics = Vif.Connection.Resolve(Vif.metrics);
if (Metrics != null)
Metrics.PropertyChanged += Server_PropertyChanged;
ImageCell.Value = Properties.Resources._000_Network_h32bit_16;
DeviceCell.Value = Vif.device;
MacCell.Value = Helpers.GetMacString(Vif.MAC);
LimitCell.Value = Vif.qos_algorithm_type != ""? Vif.LimitString:"";
NetworkCell.Value = Vif.NetworkName();
IpCell.Value = Vif.IPAddress();
AttachedCell.Value = Vif.currently_attached ? Messages.YES : Messages.NO;
}
public void DeregisterEvents()
{
Vif.PropertyChanged -= Server_PropertyChanged;
if (Metrics != null)
Metrics.PropertyChanged -= Server_PropertyChanged;
}
private void Server_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (NetworkList.shouldRefreshBuildList(e))
Program.Invoke(Program.MainWindow, UpdateDetails);
}
}
class NetworkRow : DataGridViewExRow
{
public XenAPI.Network Network;
private DataGridViewExImageCell ImageCell = new DataGridViewExImageCell();
private DataGridViewTextBoxCell NameCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell DescriptionCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell NicCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell VlanCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell AutoCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell LinkStatusCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell MacCell = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell MtuCell = new DataGridViewTextBoxCell();
private IXenObject Xmo;
PIF Pif;
public NetworkRow(XenAPI.Network network, IXenObject xmo)
{
Network = network;
Xmo = xmo;
Cells.AddRange(ImageCell,
NameCell,
DescriptionCell,
NicCell,
VlanCell,
AutoCell,
LinkStatusCell,
MacCell);
// add MTU to grid view on Network tab for pools and hosts, for Cowley or greater only (CA-45643)
if (Helpers.CowleyOrGreater(Xmo.Connection))
Cells.Add(this.MtuCell);
Network.PropertyChanged += Server_PropertyChanged;
Program.Invoke(Program.MainWindow, UpdateDetails);
}
public void UpdateDetails()
{
Enabled = !Network.IsSlave;
DeregisterPifEvents();
Pif = Helpers.FindPIF(Network, Xmo as Host);
RegisterPifEvents();
ImageCell.Value = Properties.Resources._000_Network_h32bit_16;
NameCell.Value = NetworkName();
DescriptionCell.Value = Network.Description;
NicCell.Value = Helpers.GetName(Pif);
VlanCell.Value = Helpers.VlanString(Pif);
AutoCell.Value = Network.AutoPlug ? Messages.YES : Messages.NO;
LinkStatusCell.Value = Xmo is Pool ? Network.LinkStatusString :
Pif == null ? Messages.NONE : Pif.LinkStatusString;
MacCell.Value = Pif != null && Pif.IsPhysical ? Pif.MAC : Messages.SPACED_HYPHEN;
MtuCell.Value = Network.CanUseJumboFrames ? Network.MTU.ToString() : Messages.SPACED_HYPHEN;
}
public void DeregisterEvents()
{
Network.PropertyChanged -= Server_PropertyChanged;
DeregisterPifEvents();
}
private object NetworkName()
{
if (Network.Show(XenAdmin.Properties.Settings.Default.ShowHiddenVMs) && !Network.IsSlave)
return Helpers.GetName(Network);
else if (Network.IsSlave && Properties.Settings.Default.ShowHiddenVMs)
return string.Format(Messages.NIC_SLAVE, Helpers.GetName(Network));
else if (Properties.Settings.Default.ShowHiddenVMs)
return string.Format(Messages.NIC_HIDDEN, Helpers.GetName(Network));
else
return string.Empty;
}
private void Server_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(NetworkList.shouldRefreshBuildList(e))
Program.Invoke(Program.MainWindow, UpdateDetails);
}
private void RegisterPifEvents()
{
if (Pif != null)
{
Pif.PropertyChanged += Server_PropertyChanged;
// Listen for Tunnel and PIF_metrics changes which is necessary for Link Status updates (CA-46103)
if (Pif.IsTunnelAccessPIF)
{
Tunnel tunnel = Pif.Connection.Resolve(Pif.tunnel_access_PIF_of[0]);
if (tunnel != null)
tunnel.PropertyChanged += Pif_PropertyChanged;
}
else
{
PIF_metrics metrics = Pif.PIFMetrics;
if (metrics != null)
metrics.PropertyChanged += Pif_PropertyChanged;
}
}
}
private void DeregisterPifEvents()
{
if (Pif != null)
{
Pif.PropertyChanged -= Server_PropertyChanged;
// Remove Tunnel and PIF_metrics property change listeners (CA-46103)
if (Pif.IsTunnelAccessPIF)
{
Tunnel tunnel = Pif.Connection.Resolve(Pif.tunnel_access_PIF_of[0]);
if (tunnel != null)
tunnel.PropertyChanged -= Pif_PropertyChanged;
}
else
{
PIF_metrics metrics = Pif.PIFMetrics;
if (metrics != null)
metrics.PropertyChanged -= Pif_PropertyChanged;
}
}
}
private void Pif_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Tunnel.status or PIF_metrics.carrier (CA-46103)
if (e.PropertyName == "status" || e.PropertyName == "carrier")
Program.Invoke(Program.MainWindow, UpdateDetails);
}
}
private void NetworksGridView_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
{
if (XenObject != null && XenObject is VM && e.Column.Index == DeviceColumn.Index)
{
int val1 = 0;
int val2 = 0;
if (int.TryParse(e.CellValue1.ToString(), out val1)
&& int.TryParse(e.CellValue2.ToString(), out val2))
{
e.SortResult = val1.CompareTo(val2);
e.Handled = true;
return;
}
}
e.SortResult = StringUtility.NaturalCompare(e.CellValue1.ToString(), e.CellValue2.ToString());
e.Handled = true;
}
}
}