xenadmin/XenAdmin/Controls/NetworkingTab/NetworkList.cs
Konstantina Chremmou ae22560ce8 Converted all extension get properties of the API classes to methods in order to
prevent them from being serialised alongside the API properties. This will also
be useful for moving the API bindings out of XenModel.

Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
2017-09-03 03:35:30 +01:00

1048 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;
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).
UnregisterHandlers();
_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);
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;
}
}
internal void UnregisterHandlers()
{
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);
}
}
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,
this.MtuColumn});
//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;
}
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(this, 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 &&
// CA-218956 - Expose HIMN when showing hidden objects
(network.IsGuestInstallerNetwork() && !XenAdmin.Properties.Settings.Default.ShowHiddenVMs))
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()
&& !TheNetwork.IsGuestInstallerNetwork();
// CA-218956 - Expose HIMN when showing hidden objects
// HIMN should not be editable
if (HasPhysicalNonBondNIC(TheNetwork))
{
RemoveNetworkButton.Enabled = false;
RemoveButtonContainer.SetToolTip(Messages.TOOLTIP_REMOVE_PIF);
}
else
{
RemoveNetworkButton.Enabled = EditNetworkButton.Enabled;
// CA-218956 - Expose HIMN when showing hidden objects
// HIMN should not be removable
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(vm.HasNewVirtualisationStates() ? Messages.TOOLTIP_EDIT_NETWORK_IO_DRIVERS : 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().HasFlag(VM.VirtualisationStatus.IO_DRIVERS_INSTALLED))
{
RemoveButtonContainer.SetToolTip(vm.HasNewVirtualisationStates() ? Messages.TOOLTIP_REMOVE_NETWORK_IO_DRIVERS : Messages.TOOLTIP_REMOVE_NETWORK_TOOLS);
EditButtonContainer.SetToolTip(vm.HasNewVirtualisationStates() ? Messages.TOOLTIP_EDIT_NETWORK_IO_DRIVERS : 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())
{
using (var dlg = new ThreeButtonDialog(
new ThreeButtonDialog.Details(
SystemIcons.Error,
FriendlyErrorNames.VIFS_MAX_ALLOWED,
FriendlyErrorNames.VIFS_MAX_ALLOWED_TITLE)))
{
dlg.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.
using (var dlg = new ThreeButtonDialog(
new ThreeButtonDialog.Details(SystemIcons.Warning, Messages.MESSAGEBOX_VIF_DELETE, Messages.MESSAGEBOX_VIF_DELETE_TITLE),
ThreeButtonDialog.ButtonYes,
ThreeButtonDialog.ButtonNo))
{
result = dlg.ShowDialog(Program.MainWindow);
}
}
else
{
using (var dlg = new ThreeButtonDialog(
new ThreeButtonDialog.Details(SystemIcons.Warning, Messages.MESSAGEBOX_NETWORK_DELETE, Messages.MESSAGEBOX_NETWORK_DELETE_TITLE),
ThreeButtonDialog.ButtonYes,
ThreeButtonDialog.ButtonNo))
{
result = dlg.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(this, BuildList);
}
void PIFCollectionChanged(object sender, EventArgs e)
{
Program.Invoke(this, BuildList);
}
void CollectionChanged(object sender, EventArgs e)
{
Program.Invoke(this, BuildList);
}
void action_Completed(ActionBase sender)
{
Program.Invoke(this, 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(this, 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(this, () =>
{
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;
Clip.SetClipboardText(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.IPAddressesAsString();
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,
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()
{
bool isSlave = Network.IsSlave();
if (Network.Show(XenAdmin.Properties.Settings.Default.ShowHiddenVMs) && !isSlave)
return Helpers.GetName(Network);
else if (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;
}
}
}