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.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
2016-02-06 08:18:07 +01:00
|
|
|
|
using System.Diagnostics;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
using System.Drawing;
|
2016-02-06 08:18:07 +01:00
|
|
|
|
using System.IO;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
using System.Linq;
|
2016-02-06 08:18:07 +01:00
|
|
|
|
using System.Text;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
using System.Windows.Forms;
|
2016-02-06 08:18:07 +01:00
|
|
|
|
using XenAdmin.Commands;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
using XenAdmin.Controls;
|
|
|
|
|
using XenAdmin.Core;
|
2016-02-06 08:18:07 +01:00
|
|
|
|
using XenAdmin.CustomFields;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
using XenAdmin.Dialogs;
|
2016-02-06 08:18:07 +01:00
|
|
|
|
using XenAdmin.Model;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
using XenAdmin.Network;
|
2016-02-06 08:18:07 +01:00
|
|
|
|
using XenAdmin.SettingsPanels;
|
|
|
|
|
using XenAPI;
|
2017-11-17 02:04:45 +01:00
|
|
|
|
using XenCenterLib;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
namespace XenAdmin.TabPages
|
|
|
|
|
{
|
|
|
|
|
public partial class GeneralTabPage : BaseTabPage
|
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
#region Private fields
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private readonly List<PDSection> sections= new List<PDSection>();
|
2018-09-27 15:36:08 +02:00
|
|
|
|
private readonly Dictionary<Type, List<PDSection>> _expandedSections = new Dictionary<Type, List<PDSection>>();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private IXenObject xenObject;
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
/// <summary>
|
2020-03-13 16:22:45 +01:00
|
|
|
|
/// Indicates whether rebuild requests have been queued,
|
|
|
|
|
/// in which case rebuilding the section list is necessary
|
2013-06-24 13:41:48 +02:00
|
|
|
|
/// </summary>
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private bool refreshNeeded;
|
|
|
|
|
|
|
|
|
|
private readonly CollectionChangeEventHandler VM_guest_metrics_CollectionChangedWithInvoke;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
private LicenseStatus licenseStatus;
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
#endregion
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
public LicenseManagerLauncher LicenseLauncher { private get; set; }
|
|
|
|
|
|
|
|
|
|
public GeneralTabPage()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
2018-12-04 14:02:56 +01:00
|
|
|
|
VM_guest_metrics_CollectionChangedWithInvoke = Program.ProgramInvokeHandler(VM_guest_metrics_CollectionChanged);
|
2016-10-13 23:59:06 +02:00
|
|
|
|
OtherConfigAndTagsWatcher.TagsChanged += OtherConfigAndTagsWatcher_TagsChanged;
|
2020-03-13 16:22:45 +01:00
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
foreach (Control control in panel2.Controls)
|
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
if (!(control is Panel p))
|
2013-06-24 13:41:48 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
foreach (Control c in p.Controls)
|
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
if (!(c is PDSection s))
|
2013-06-24 13:41:48 +02:00
|
|
|
|
continue;
|
|
|
|
|
sections.Add(s);
|
2020-03-13 16:22:45 +01:00
|
|
|
|
s.ContentChangedSelection += s_ContentChangedSelection;
|
|
|
|
|
s.ContentReceivedFocus += s_ContentReceivedFocus;
|
|
|
|
|
s.ExpandedChanged += s_ExpandedChanged;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-13 18:47:27 +02:00
|
|
|
|
public override string HelpID => "TabPageSettings";
|
|
|
|
|
|
2019-11-28 01:44:19 +01:00
|
|
|
|
private void licenseStatus_ItemUpdated()
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2015-11-23 15:35:20 +01:00
|
|
|
|
if (pdSectionLicense == null || licenseStatus == null)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
return;
|
|
|
|
|
|
2018-12-04 14:02:56 +01:00
|
|
|
|
var ss = new GeneralTabLicenseStatusStringifier(licenseStatus);
|
2015-11-23 15:35:20 +01:00
|
|
|
|
Program.Invoke(Program.MainWindow, () =>
|
|
|
|
|
{
|
2018-12-04 14:02:56 +01:00
|
|
|
|
pdSectionLicense.UpdateEntryValueWithKey(FriendlyName("host.license_params-expiry"),
|
|
|
|
|
ss.ExpiryDate, ss.ShowExpiryDate);
|
2017-10-10 18:02:17 +02:00
|
|
|
|
|
2018-12-04 14:02:56 +01:00
|
|
|
|
pdSectionLicense.UpdateEntryValueWithKey(Messages.LICENSE_STATUS, ss.ExpiryStatus, true);
|
|
|
|
|
|
2019-11-28 01:44:19 +01:00
|
|
|
|
if (xenObject is Pool p)
|
2017-10-10 18:02:17 +02:00
|
|
|
|
{
|
|
|
|
|
var additionalString = PoolAdditionalLicenseString();
|
|
|
|
|
pdSectionGeneral.UpdateEntryValueWithKey(
|
|
|
|
|
Messages.POOL_LICENSE,
|
|
|
|
|
additionalString != string.Empty
|
2018-10-05 12:57:16 +02:00
|
|
|
|
? string.Format(Messages.MAINWINDOW_CONTEXT_REASON, Helpers.GetFriendlyLicenseName(p), additionalString)
|
|
|
|
|
: Helpers.GetFriendlyLicenseName(p),
|
2017-10-10 18:02:17 +02:00
|
|
|
|
true);
|
2018-12-04 14:02:56 +01:00
|
|
|
|
}
|
|
|
|
|
});
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void ScrollToSelectionIfNeeded(PDSection s)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
if (s.HasNoSelection())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Rectangle selectedRowBounds = s.SelectedRowBounds;
|
|
|
|
|
|
|
|
|
|
// translate to the coordinates of the pdsection container panel (the one added for padding purposes)
|
|
|
|
|
selectedRowBounds.Offset(s.Parent.Location);
|
|
|
|
|
|
|
|
|
|
// Top edge visible?
|
|
|
|
|
if (panel2.ClientRectangle.Height - selectedRowBounds.Top > 0 && selectedRowBounds.Top > 0)
|
|
|
|
|
{
|
|
|
|
|
// Bottom edge visible?
|
|
|
|
|
if (panel2.ClientRectangle.Height - selectedRowBounds.Bottom > 0 && selectedRowBounds.Bottom > 0)
|
|
|
|
|
{
|
|
|
|
|
// The entire selected row is in view, no need to move
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
panel2.ForceScrollTo(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IXenObject XenObject
|
|
|
|
|
{
|
|
|
|
|
set
|
|
|
|
|
{
|
2014-09-25 18:49:55 +02:00
|
|
|
|
if (value == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-11-28 01:44:19 +01:00
|
|
|
|
if (value.Equals(xenObject))
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
BuildList();
|
2019-11-28 01:44:19 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2018-12-04 13:58:54 +01:00
|
|
|
|
|
2019-11-28 01:44:19 +01:00
|
|
|
|
if (licenseStatus != null)
|
|
|
|
|
{
|
|
|
|
|
licenseStatus.ItemUpdated -= licenseStatus_ItemUpdated;
|
|
|
|
|
licenseStatus.Dispose();
|
|
|
|
|
//set this to null to prevent updates if the object is not a host or pool
|
|
|
|
|
licenseStatus = null;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
2019-11-28 01:44:19 +01:00
|
|
|
|
|
|
|
|
|
if (value.Connection != null && value.Connection.IsConnected && (value is Host || value is Pool))
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2019-11-28 01:44:19 +01:00
|
|
|
|
licenseStatus = new LicenseStatus(value);
|
|
|
|
|
licenseStatus.ItemUpdated += licenseStatus_ItemUpdated;
|
|
|
|
|
licenseStatus.BeginUpdate();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-28 01:44:19 +01:00
|
|
|
|
UnregisterHandlers();
|
2015-11-25 13:32:04 +01:00
|
|
|
|
|
2019-11-28 01:44:19 +01:00
|
|
|
|
xenObject = value;
|
|
|
|
|
RegisterHandlers();
|
|
|
|
|
BuildList();
|
2018-05-11 17:38:46 +02:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
List<PDSection> expandedSections = null;
|
2015-11-23 15:35:20 +01:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
if (xenObject != null && !_expandedSections.TryGetValue(xenObject.GetType(), out expandedSections))
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
expandedSections = new List<PDSection> {pdSectionGeneral};
|
|
|
|
|
_expandedSections[xenObject.GetType()] = expandedSections;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
2018-09-27 15:36:08 +02:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
ToggleExpandedState(s => expandedSections == null && s == pdSectionGeneral ||
|
|
|
|
|
expandedSections != null && expandedSections.Contains(s));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UnregisterHandlers()
|
|
|
|
|
{
|
|
|
|
|
if (xenObject != null)
|
|
|
|
|
xenObject.PropertyChanged -= PropertyChanged;
|
|
|
|
|
|
|
|
|
|
if (xenObject is Host)
|
|
|
|
|
{
|
|
|
|
|
Host host = xenObject as Host;
|
|
|
|
|
|
|
|
|
|
Host_metrics metric = xenObject.Connection.Resolve<Host_metrics>(host.metrics);
|
|
|
|
|
if (metric != null)
|
|
|
|
|
metric.PropertyChanged -= PropertyChanged;
|
|
|
|
|
}
|
|
|
|
|
else if (xenObject is VM)
|
|
|
|
|
{
|
|
|
|
|
VM vm = xenObject as VM;
|
|
|
|
|
|
|
|
|
|
VM_metrics metric = vm.Connection.Resolve(vm.metrics);
|
|
|
|
|
if (metric != null)
|
|
|
|
|
metric.PropertyChanged -= PropertyChanged;
|
|
|
|
|
|
|
|
|
|
VM_guest_metrics guestmetric = xenObject.Connection.Resolve(vm.guest_metrics);
|
|
|
|
|
if (guestmetric != null)
|
|
|
|
|
guestmetric.PropertyChanged -= PropertyChanged;
|
|
|
|
|
|
|
|
|
|
vm.Connection.Cache.DeregisterCollectionChanged<VM_guest_metrics>(VM_guest_metrics_CollectionChangedWithInvoke);
|
|
|
|
|
}
|
|
|
|
|
else if (xenObject is SR)
|
|
|
|
|
{
|
|
|
|
|
SR sr = xenObject as SR;
|
|
|
|
|
|
|
|
|
|
foreach (PBD pbd in sr.Connection.ResolveAll(sr.PBDs))
|
|
|
|
|
{
|
|
|
|
|
pbd.PropertyChanged -= PropertyChanged;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (xenObject is Pool)
|
|
|
|
|
{
|
|
|
|
|
xenObject.Connection.Cache.DeregisterBatchCollectionChanged<Pool_patch>(Pool_patch_BatchCollectionChanged);
|
2016-10-05 13:55:34 +02:00
|
|
|
|
xenObject.Connection.Cache.DeregisterBatchCollectionChanged<Pool_update>(Pool_update_BatchCollectionChanged);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void VM_guest_metrics_CollectionChanged(object sender, CollectionChangeEventArgs e)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
if (!this.Visible)
|
|
|
|
|
return;
|
|
|
|
|
// Required to refresh the panel when the vm boots so we show the correct pv driver state and version
|
|
|
|
|
// Note this does NOT get called every 2s, just when the vm power state changes (hopefully!)
|
|
|
|
|
BuildList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RegisterHandlers()
|
|
|
|
|
{
|
|
|
|
|
if (xenObject != null)
|
|
|
|
|
xenObject.PropertyChanged += new PropertyChangedEventHandler(PropertyChanged);
|
|
|
|
|
|
|
|
|
|
if (xenObject is Host)
|
|
|
|
|
{
|
|
|
|
|
Host host = xenObject as Host;
|
|
|
|
|
Host_metrics metric = xenObject.Connection.Resolve(host.metrics);
|
|
|
|
|
if (metric != null)
|
|
|
|
|
metric.PropertyChanged += new PropertyChangedEventHandler(PropertyChanged);
|
|
|
|
|
}
|
|
|
|
|
else if (xenObject is VM)
|
|
|
|
|
{
|
|
|
|
|
VM vm = xenObject as VM;
|
|
|
|
|
|
|
|
|
|
VM_metrics metric = vm.Connection.Resolve(vm.metrics);
|
|
|
|
|
if (metric != null)
|
|
|
|
|
metric.PropertyChanged += new PropertyChangedEventHandler(PropertyChanged);
|
|
|
|
|
|
|
|
|
|
VM_guest_metrics guestmetric = xenObject.Connection.Resolve(vm.guest_metrics);
|
|
|
|
|
if (guestmetric != null)
|
|
|
|
|
guestmetric.PropertyChanged += new PropertyChangedEventHandler(PropertyChanged);
|
|
|
|
|
|
|
|
|
|
xenObject.Connection.Cache.RegisterCollectionChanged<VM_guest_metrics>(VM_guest_metrics_CollectionChangedWithInvoke);
|
|
|
|
|
}
|
|
|
|
|
else if (xenObject is Pool)
|
|
|
|
|
{
|
|
|
|
|
xenObject.Connection.Cache.RegisterBatchCollectionChanged<Pool_patch>(Pool_patch_BatchCollectionChanged);
|
2016-10-05 13:55:34 +02:00
|
|
|
|
xenObject.Connection.Cache.RegisterBatchCollectionChanged<Pool_update>(Pool_update_BatchCollectionChanged);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void Pool_patch_BatchCollectionChanged(object sender, EventArgs e)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
Program.BeginInvoke(this, BuildList);
|
|
|
|
|
}
|
2017-01-16 20:59:50 +01:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void Pool_update_BatchCollectionChanged(object sender, EventArgs e)
|
2016-10-05 13:55:34 +02:00
|
|
|
|
{
|
|
|
|
|
Program.BeginInvoke(this, BuildList);
|
|
|
|
|
}
|
2017-01-16 20:59:50 +01:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void OtherConfigAndTagsWatcher_TagsChanged()
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
BuildList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnVisibleChanged(EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (Visible && refreshNeeded)
|
|
|
|
|
{
|
|
|
|
|
BuildList();
|
|
|
|
|
refreshNeeded = false;
|
|
|
|
|
}
|
|
|
|
|
base.OnVisibleChanged(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
|
|
|
{
|
2019-11-28 01:44:19 +01:00
|
|
|
|
if (e.PropertyName == "state" || e.PropertyName == "last_updated")
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-16 15:17:02 +02:00
|
|
|
|
Program.Invoke(this, delegate
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
if (e.PropertyName == "PBDs")
|
|
|
|
|
{
|
|
|
|
|
SR sr = xenObject as SR;
|
|
|
|
|
if (sr == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
foreach (PBD pbd in xenObject.Connection.ResolveAll(sr.PBDs))
|
|
|
|
|
{
|
|
|
|
|
pbd.PropertyChanged -= PropertyChanged;
|
|
|
|
|
pbd.PropertyChanged += PropertyChanged;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
// At the moment we are rebuilding on almost any property changed event.
|
2019-11-28 01:44:19 +01:00
|
|
|
|
// As long as we are just clearing and re-adding the rows in the PDSections this seems to be super quick.
|
2013-06-24 13:41:48 +02:00
|
|
|
|
// If it gets slower we should update specific boxes for specific property changes.
|
2015-11-23 15:35:20 +01:00
|
|
|
|
if (licenseStatus != null && licenseStatus.Updated)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
licenseStatus.BeginUpdate();
|
|
|
|
|
}
|
2020-03-13 16:22:45 +01:00
|
|
|
|
|
|
|
|
|
BuildList();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
public void UpdateButtons()
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
if (xenObject is DockerContainer container)
|
2016-02-03 11:12:05 +01:00
|
|
|
|
{
|
CA-162989: Container Management GUI use-ability/homogeneity fixes
Implemented changes as follows (copied from ticket):
"I'd suggest the following use-ability/homogeneity fixes for the new container management tabs, if they are quick and easy:
Combine "Docker Version" and "Docker Information" on the VM-General-tab into "Container Management - Docker Status" with the following fields only:
API version
Version
Git Commit
Driver
Index Server Address
Execution Driver
IPv4 Forwarding
In the "Processes" tab, change the name from "Docker Processes" to "Container Processes"
In the "Details" tab, change the name from "Docker Detail" to "Container Details"
In the "Details" tab, drop the top level element "docker_inspect" (XML requires a single root-node, afaik the Windows form treenode does not), or alternatively open the root node by default and rename it to "Inspect Result"
In the "Details" tab, add the "Details"-headline in black on white - just like on the "Processes"-tab
Also, on the container's General tab, show Properties button disabled, instead on hiding it (to be consistent to other cases, e.g. disconnected servers)
"
Signed-off-by: Gabor Apati-Nagy <gabor.apati-nagy@citrix.com>
2015-03-05 20:10:54 +01:00
|
|
|
|
buttonProperties.Enabled = false;
|
2016-02-03 11:12:05 +01:00
|
|
|
|
buttonViewConsole.Visible = true;
|
|
|
|
|
buttonViewLog.Visible = true;
|
|
|
|
|
|
|
|
|
|
// Grey out the buttons if the Container management VM is Windows.
|
|
|
|
|
// For Linux VM, enable the buttons only when the docker is running.
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (container.Parent.IsWindows())
|
2016-02-03 11:12:05 +01:00
|
|
|
|
{
|
|
|
|
|
buttonViewConsole.Enabled = false;
|
|
|
|
|
buttonViewLog.Enabled = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
buttonViewConsole.Enabled = buttonViewLog.Enabled = container.power_state == vm_power_state.Running;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
buttonProperties.Enabled = xenObject != null && !xenObject.Locked && xenObject.Connection != null && xenObject.Connection.IsConnected;
|
2016-02-03 11:12:05 +01:00
|
|
|
|
buttonViewConsole.Visible = false;
|
|
|
|
|
buttonViewLog.Visible = false;
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void BuildList()
|
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
if (!Visible)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
refreshNeeded = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-03-13 16:22:45 +01:00
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
if (xenObject == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (xenObject is Host && !xenObject.Connection.IsConnected)
|
|
|
|
|
base.Text = Messages.CONNECTION_GENERAL_TAB_TITLE;
|
|
|
|
|
else if (xenObject is Host)
|
|
|
|
|
base.Text = Messages.HOST_GENERAL_TAB_TITLE;
|
|
|
|
|
else if (xenObject is VM)
|
|
|
|
|
{
|
|
|
|
|
VM vm = (VM)xenObject;
|
|
|
|
|
if (vm.is_a_snapshot)
|
|
|
|
|
base.Text = Messages.SNAPSHOT_GENERAL_TAB_TITLE;
|
|
|
|
|
else if (vm.is_a_template)
|
|
|
|
|
base.Text = Messages.TEMPLATE_GENERAL_TAB_TITLE;
|
|
|
|
|
else
|
|
|
|
|
base.Text = Messages.VM_GENERAL_TAB_TITLE;
|
|
|
|
|
}
|
|
|
|
|
else if (xenObject is SR)
|
|
|
|
|
base.Text = Messages.SR_GENERAL_TAB_TITLE;
|
|
|
|
|
else if (xenObject is Pool)
|
|
|
|
|
base.Text = Messages.POOL_GENERAL_TAB_TITLE;
|
2015-02-10 04:03:53 +01:00
|
|
|
|
else if (xenObject is DockerContainer)
|
|
|
|
|
base.Text = Messages.CONTAINER_GENERAL_TAB_TITLE;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
panel2.SuspendLayout();
|
|
|
|
|
// Clear all the data from the sections (visible and non visible)
|
|
|
|
|
foreach (PDSection s in sections)
|
|
|
|
|
{
|
|
|
|
|
s.PauseLayout();
|
|
|
|
|
s.ClearData();
|
|
|
|
|
}
|
|
|
|
|
// Generate the content of each box, each method performs a cast and only populates if XenObject is the relevant type
|
|
|
|
|
|
|
|
|
|
if (xenObject is Host && (xenObject.Connection == null || !xenObject.Connection.IsConnected))
|
|
|
|
|
{
|
|
|
|
|
generateDisconnectedHostBox();
|
|
|
|
|
}
|
2014-12-05 15:16:58 +01:00
|
|
|
|
else if (xenObject is DockerContainer)
|
|
|
|
|
{
|
|
|
|
|
generateDockerContainerGeneralBox();
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
generateGeneralBox();
|
2020-03-12 13:59:32 +01:00
|
|
|
|
GenerateCertificateBox();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
generateCustomFieldsBox();
|
|
|
|
|
generateInterfaceBox();
|
|
|
|
|
generateMemoryBox();
|
|
|
|
|
generateVersionBox();
|
|
|
|
|
generateLicenseBox();
|
|
|
|
|
generateCPUBox();
|
|
|
|
|
generateHostPatchesBox();
|
|
|
|
|
generateBootBox();
|
|
|
|
|
generateHABox();
|
|
|
|
|
generateStatusBox();
|
|
|
|
|
generateMultipathBox();
|
|
|
|
|
generatePoolPatchesBox();
|
|
|
|
|
generateMultipathBootBox();
|
2014-07-14 16:17:47 +02:00
|
|
|
|
generateVCPUsBox();
|
2015-02-15 03:52:12 +01:00
|
|
|
|
generateDockerInfoBox();
|
2015-02-19 15:09:08 +01:00
|
|
|
|
generateReadCachingBox();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// hide all the sections which haven't been populated, those that have make sure are visible
|
|
|
|
|
foreach (PDSection s in sections)
|
|
|
|
|
{
|
|
|
|
|
if (s.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
s.Parent.Visible = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s.Parent.Visible = true;
|
|
|
|
|
if (s.ContainsFocus)
|
|
|
|
|
s.RestoreSelection();
|
|
|
|
|
}
|
|
|
|
|
s.StartLayout();
|
|
|
|
|
}
|
|
|
|
|
panel2.ResumeLayout();
|
2020-03-13 16:22:45 +01:00
|
|
|
|
UpdateButtons();
|
2021-03-10 11:22:51 +01:00
|
|
|
|
|
|
|
|
|
SetupDeprecationBanner();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateInterfaceBox()
|
|
|
|
|
{
|
|
|
|
|
Host Host = xenObject as Host;
|
|
|
|
|
Pool Pool = xenObject as Pool;
|
|
|
|
|
if (Host != null)
|
|
|
|
|
{
|
|
|
|
|
fillInterfacesForHost(Host, false);
|
|
|
|
|
}
|
|
|
|
|
else if (Pool != null)
|
|
|
|
|
{
|
|
|
|
|
// Here we tell fillInterfacesForHost to prefix each entry with the hosts name label, so we know which entry belongs to which host
|
|
|
|
|
// and also to better preserve uniqueness for keys in the PDSection
|
|
|
|
|
|
|
|
|
|
foreach (Host h in Pool.Connection.Cache.Hosts)
|
|
|
|
|
fillInterfacesForHost(h, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillInterfacesForHost(Host Host, bool includeHostSuffix)
|
|
|
|
|
{
|
|
|
|
|
PDSection s = pdSectionManagementInterfaces;
|
|
|
|
|
|
2020-06-18 02:20:29 +02:00
|
|
|
|
var editValue = new ToolStripMenuItem(Messages.EDIT) { Image = Images.StaticImages.edit_16 };
|
2013-08-22 17:48:16 +02:00
|
|
|
|
editValue.Click += delegate
|
|
|
|
|
{
|
|
|
|
|
NetworkingProperties p = new NetworkingProperties(Host, null);
|
|
|
|
|
p.ShowDialog(Program.MainWindow);
|
|
|
|
|
};
|
2013-12-13 11:51:08 +01:00
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
if (!string.IsNullOrEmpty(Host.hostname))
|
|
|
|
|
{
|
|
|
|
|
if (!includeHostSuffix)
|
2013-12-22 18:33:13 +01:00
|
|
|
|
s.AddEntry(FriendlyName("host.hostname"), Host.hostname, editValue);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
else
|
|
|
|
|
s.AddEntry(
|
|
|
|
|
string.Format(Messages.PROPERTY_ON_OBJECT, FriendlyName("host.hostname"), Helpers.GetName(Host)),
|
|
|
|
|
Host.hostname,
|
2013-12-22 18:33:13 +01:00
|
|
|
|
editValue);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
foreach (PIF pif in xenObject.Connection.ResolveAll<PIF>(Host.PIFs))
|
|
|
|
|
{
|
|
|
|
|
if (pif.management)
|
|
|
|
|
{
|
|
|
|
|
if (!includeHostSuffix)
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Messages.MANAGEMENT_INTERFACE, pif.FriendlyIPAddress(), editValue);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
else
|
|
|
|
|
s.AddEntry(
|
|
|
|
|
string.Format(Messages.PROPERTY_ON_OBJECT, Messages.MANAGEMENT_INTERFACE, Helpers.GetName(Host)),
|
2017-09-03 04:33:29 +02:00
|
|
|
|
pif.FriendlyIPAddress(),
|
2013-12-22 18:33:13 +01:00
|
|
|
|
editValue);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (PIF pif in xenObject.Connection.ResolveAll<PIF>(Host.PIFs))
|
|
|
|
|
{
|
|
|
|
|
if (pif.IsSecondaryManagementInterface(Properties.Settings.Default.ShowHiddenVMs))
|
|
|
|
|
{
|
|
|
|
|
if (!includeHostSuffix)
|
2017-09-05 03:15:38 +02:00
|
|
|
|
s.AddEntry(pif.GetManagementPurpose().Ellipsise(30), pif.FriendlyIPAddress(), editValue);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
else
|
|
|
|
|
s.AddEntry(
|
2017-09-05 03:15:38 +02:00
|
|
|
|
string.Format(Messages.PROPERTY_ON_OBJECT, pif.GetManagementPurpose().Ellipsise(30), Helpers.GetName(Host)),
|
2017-09-03 04:33:29 +02:00
|
|
|
|
pif.FriendlyIPAddress(),
|
2013-12-22 18:33:13 +01:00
|
|
|
|
editValue);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateCustomFieldsBox()
|
|
|
|
|
{
|
|
|
|
|
List<CustomField> customFields = CustomFieldsManager.CustomFieldValues(xenObject);
|
|
|
|
|
if (customFields.Count <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionCustomFields;
|
|
|
|
|
|
|
|
|
|
foreach (CustomField customField in customFields)
|
|
|
|
|
{
|
2020-06-18 02:20:29 +02:00
|
|
|
|
var editValue = new ToolStripMenuItem(Messages.EDIT) {Image = Images.StaticImages.edit_16};
|
2013-08-22 17:48:16 +02:00
|
|
|
|
editValue.Click += delegate
|
|
|
|
|
{
|
2013-12-22 18:17:04 +01:00
|
|
|
|
using (PropertiesDialog dialog = new PropertiesDialog(xenObject))
|
|
|
|
|
{
|
|
|
|
|
dialog.SelectCustomFieldsEditPage();
|
|
|
|
|
dialog.ShowDialog();
|
|
|
|
|
}
|
2013-08-22 17:48:16 +02:00
|
|
|
|
};
|
2013-12-13 11:51:08 +01:00
|
|
|
|
|
|
|
|
|
var menuItems = new[] { editValue };
|
2013-06-24 13:41:48 +02:00
|
|
|
|
CustomFieldWrapper cfWrapper = new CustomFieldWrapper(xenObject, customField.Definition);
|
|
|
|
|
|
|
|
|
|
s.AddEntry(customField.Definition.Name.Ellipsise(30), cfWrapper.ToString(), menuItems, customField.Definition.Name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generatePoolPatchesBox()
|
|
|
|
|
{
|
|
|
|
|
Pool pool = xenObject as Pool;
|
|
|
|
|
if (pool == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionUpdates;
|
|
|
|
|
|
|
|
|
|
List<KeyValuePair<String, String>> messages = CheckPoolUpdate(pool);
|
|
|
|
|
if (messages.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
foreach (KeyValuePair<String, String> kvp in messages)
|
|
|
|
|
{
|
|
|
|
|
s.AddEntry(kvp.Key, kvp.Value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Host master = Helpers.GetMaster(xenObject.Connection);
|
|
|
|
|
if (master == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var poolAppPatches = poolAppliedPatches();
|
|
|
|
|
if (!string.IsNullOrEmpty(poolAppPatches))
|
|
|
|
|
{
|
|
|
|
|
s.AddEntry(FriendlyName("Pool_patch.fully_applied"), poolAppPatches);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var poolPartPatches = poolPartialPatches();
|
|
|
|
|
if (!string.IsNullOrEmpty(poolPartPatches))
|
|
|
|
|
{
|
2017-03-22 18:47:06 +01:00
|
|
|
|
CommandToolStripMenuItem applypatch = new CommandToolStripMenuItem(
|
|
|
|
|
new InstallNewUpdateCommand(Program.MainWindow), true);
|
|
|
|
|
var menuItems = new[] { applypatch };
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
s.AddEntry(FriendlyName("Pool_patch.partially_applied"), poolPartPatches, menuItems, Color.Red);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateHostPatchesBox()
|
|
|
|
|
{
|
|
|
|
|
Host host = xenObject as Host;
|
|
|
|
|
if (host == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionUpdates;
|
2016-08-17 11:45:11 +02:00
|
|
|
|
List<KeyValuePair<String, String>> messages;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2016-10-05 13:55:34 +02:00
|
|
|
|
bool elyOrGreater = Helpers.ElyOrGreater(host);
|
|
|
|
|
|
|
|
|
|
if (elyOrGreater)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2016-10-12 15:48:17 +02:00
|
|
|
|
// As of Ely we use host.updates_requiring_reboot to generate the list of reboot required messages
|
|
|
|
|
messages = CheckHostUpdatesRequiringReboot(host);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
2016-08-17 10:29:39 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// For older versions no change to how messages are generated
|
2016-08-17 11:45:11 +02:00
|
|
|
|
messages = CheckServerUpdates(host);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (messages.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
foreach (KeyValuePair<String, String> kvp in messages)
|
2016-08-17 10:29:39 +02:00
|
|
|
|
{
|
2016-08-17 11:45:11 +02:00
|
|
|
|
s.AddEntry(kvp.Key, kvp.Value);
|
2016-08-17 10:29:39 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-08 13:25:18 +02:00
|
|
|
|
var appliedPatchesList = Helpers.HostAppliedPatchesList(host);
|
|
|
|
|
var appliedPatches = string.Join(Environment.NewLine, appliedPatchesList.ToArray());
|
2017-03-22 18:29:11 +01:00
|
|
|
|
if (!string.IsNullOrEmpty(appliedPatches))
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2017-03-22 18:29:11 +01:00
|
|
|
|
s.AddEntry(FriendlyName("Pool_patch.applied"), appliedPatches);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
2015-01-28 14:17:58 +01:00
|
|
|
|
|
2016-06-08 14:34:59 +02:00
|
|
|
|
var recommendedPatches = RecommendedPatchesForHost(host);
|
|
|
|
|
if (!string.IsNullOrEmpty(recommendedPatches))
|
|
|
|
|
{
|
2016-06-08 17:16:01 +02:00
|
|
|
|
s.AddEntry(FriendlyName("Pool_patch.required-updates"), recommendedPatches);
|
2016-06-08 14:34:59 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-05 13:56:26 +02:00
|
|
|
|
if (!elyOrGreater)
|
2015-01-28 14:17:58 +01:00
|
|
|
|
{
|
2016-10-05 13:56:26 +02:00
|
|
|
|
// add supplemental packs
|
|
|
|
|
var suppPacks = hostInstalledSuppPacks(host);
|
|
|
|
|
if (!string.IsNullOrEmpty(suppPacks))
|
|
|
|
|
{
|
|
|
|
|
s.AddEntry(FriendlyName("Supplemental_packs.installed"), suppPacks);
|
|
|
|
|
}
|
2015-01-28 14:17:58 +01:00
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateHABox()
|
|
|
|
|
{
|
|
|
|
|
VM vm = xenObject as VM;
|
|
|
|
|
if (vm == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Pool pool = Helpers.GetPoolOfOne(xenObject.Connection);
|
|
|
|
|
if (pool == null || !pool.ha_enabled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionHighAvailability;
|
|
|
|
|
|
2017-09-05 03:15:38 +02:00
|
|
|
|
s.AddEntry(FriendlyName("VM.ha_restart_priority"), Helpers.RestartPriorityI18n(vm.HARestartPriority()),
|
2014-01-22 13:39:32 +01:00
|
|
|
|
new PropertiesToolStripMenuItem(new VmEditHaCommand(Program.MainWindow, xenObject)));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateStatusBox()
|
|
|
|
|
{
|
|
|
|
|
SR sr = xenObject as SR;
|
|
|
|
|
if (sr == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionStatus;
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
bool broken = sr.IsBroken() || !sr.MultipathAOK();
|
|
|
|
|
bool detached = !sr.HasPBDs();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2020-06-18 02:20:29 +02:00
|
|
|
|
var repair = new ToolStripMenuItem
|
2013-08-22 17:48:16 +02:00
|
|
|
|
{
|
2015-11-30 12:53:54 +01:00
|
|
|
|
Text = Messages.GENERAL_SR_CONTEXT_REPAIR,
|
2020-06-18 02:20:29 +02:00
|
|
|
|
Image = Images.StaticImages._000_StorageBroken_h32bit_16
|
2013-08-22 17:48:16 +02:00
|
|
|
|
};
|
|
|
|
|
repair.Click += delegate
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2015-11-30 12:53:54 +01:00
|
|
|
|
Program.MainWindow.ShowPerConnectionWizard(xenObject.Connection, new RepairSRDialog(sr));
|
2013-08-22 17:48:16 +02:00
|
|
|
|
};
|
2013-12-13 11:51:08 +01:00
|
|
|
|
|
|
|
|
|
var menuItems = new[] { repair };
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
if (broken && !detached)
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(FriendlyName("SR.state"), sr.StatusString(), menuItems);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
else
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(FriendlyName("SR.state"), sr.StatusString());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
foreach (Host host in xenObject.Connection.Cache.Hosts)
|
|
|
|
|
{
|
|
|
|
|
PBD pbdToSR = null;
|
|
|
|
|
foreach (PBD pbd in xenObject.Connection.ResolveAll(host.PBDs))
|
|
|
|
|
{
|
|
|
|
|
if (pbd.SR.opaque_ref != xenObject.opaque_ref)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
pbdToSR = pbd;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (pbdToSR == null)
|
|
|
|
|
{
|
|
|
|
|
if (!sr.shared)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!detached)
|
|
|
|
|
s.AddEntry(" " + Helpers.GetName(host).Ellipsise(30),
|
|
|
|
|
Messages.REPAIR_SR_DIALOG_CONNECTION_MISSING, menuItems, Color.Red);
|
|
|
|
|
else
|
|
|
|
|
s.AddEntry(" " + Helpers.GetName(host).Ellipsise(30),
|
|
|
|
|
Messages.REPAIR_SR_DIALOG_CONNECTION_MISSING, Color.Red);
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pbdToSR.PropertyChanged -= new PropertyChangedEventHandler(PropertyChanged);
|
|
|
|
|
pbdToSR.PropertyChanged += new PropertyChangedEventHandler(PropertyChanged);
|
|
|
|
|
|
|
|
|
|
if (!pbdToSR.currently_attached)
|
|
|
|
|
{
|
|
|
|
|
if (!detached)
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Helpers.GetName(host).Ellipsise(30), pbdToSR.StatusString(), menuItems, Color.Red);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
else
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Helpers.GetName(host).Ellipsise(30), pbdToSR.StatusString(), Color.Red);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Helpers.GetName(host).Ellipsise(30), pbdToSR.StatusString());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateMultipathBox()
|
|
|
|
|
{
|
|
|
|
|
SR sr = xenObject as SR;
|
|
|
|
|
if (sr == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionMultipathing;
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (!sr.MultipathCapable())
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
s.AddEntry(Messages.MULTIPATH_CAPABLE, Messages.NO);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (sr.LunPerVDI())
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
Dictionary<VM, Dictionary<VDI, String>>
|
|
|
|
|
pathStatus = sr.GetMultiPathStatusLunPerVDI();
|
|
|
|
|
|
|
|
|
|
foreach (Host host in xenObject.Connection.Cache.Hosts)
|
|
|
|
|
{
|
|
|
|
|
PBD pbd = sr.GetPBDFor(host);
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (pbd == null || !pbd.MultipathActive())
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(host.Name(), Messages.MULTIPATH_NOT_ACTIVE);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(host.Name(), Messages.MULTIPATH_ACTIVE);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
foreach (KeyValuePair<VM, Dictionary<VDI, String>> kvp in pathStatus)
|
|
|
|
|
{
|
|
|
|
|
VM vm = kvp.Key;
|
|
|
|
|
if (vm.resident_on == null ||
|
|
|
|
|
vm.resident_on.opaque_ref != host.opaque_ref)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
bool renderOnOneLine = false;
|
|
|
|
|
int lastMax = -1;
|
|
|
|
|
int lastCurrent = -1;
|
|
|
|
|
|
|
|
|
|
foreach (KeyValuePair<VDI, String> kvp2 in kvp.Value)
|
|
|
|
|
{
|
|
|
|
|
int current;
|
|
|
|
|
int max;
|
|
|
|
|
if (!PBD.ParsePathCounts(kvp2.Value, out current, out max))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!renderOnOneLine)
|
|
|
|
|
{
|
|
|
|
|
lastMax = max;
|
|
|
|
|
lastCurrent = current;
|
|
|
|
|
renderOnOneLine = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lastMax == max && lastCurrent == current)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
renderOnOneLine = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (renderOnOneLine)
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
AddMultipathLine(s, String.Format(" {0}", vm.Name()),
|
|
|
|
|
lastCurrent, lastMax, pbd.ISCSISessions());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(String.Format(" {0}", vm.Name()), "");
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
foreach (KeyValuePair<VDI, String> kvp2 in kvp.Value)
|
|
|
|
|
{
|
|
|
|
|
int current;
|
|
|
|
|
int max;
|
|
|
|
|
if (!PBD.ParsePathCounts(kvp2.Value, out current, out max))
|
|
|
|
|
continue;
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
AddMultipathLine(s, String.Format(" {0}", kvp2.Key.Name()),
|
|
|
|
|
current, max, pbd.ISCSISessions());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Dictionary<PBD, String> pathStatus = sr.GetMultiPathStatusLunPerSR();
|
|
|
|
|
|
|
|
|
|
foreach (Host host in xenObject.Connection.Cache.Hosts)
|
|
|
|
|
{
|
|
|
|
|
PBD pbd = sr.GetPBDFor(host);
|
|
|
|
|
if (pbd == null || !pathStatus.ContainsKey(pbd))
|
|
|
|
|
{
|
2019-03-22 15:06:27 +01:00
|
|
|
|
if (pbd == null)
|
|
|
|
|
s.AddEntry(host.Name(), Messages.MULTIPATH_NOT_ACTIVE);
|
|
|
|
|
else if (pbd.MultipathActive())
|
|
|
|
|
s.AddEntry(host.Name(), Messages.MULTIPATH_ACTIVE);
|
|
|
|
|
else if (sr.GetSRType(true) == SR.SRTypes.gfs2)
|
|
|
|
|
s.AddEntry(host.Name(), Messages.MULTIPATH_NOT_ACTIVE_GFS2, Color.Red);
|
|
|
|
|
else
|
|
|
|
|
s.AddEntry(host.Name(), Messages.MULTIPATH_NOT_ACTIVE);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String status = pathStatus[pbd];
|
|
|
|
|
|
|
|
|
|
int current;
|
|
|
|
|
int max;
|
|
|
|
|
PBD.ParsePathCounts(status, out current, out max); //Guaranteed to work if PBD is in pathStatus
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
AddMultipathLine(s, host.Name(), current, max, pbd.ISCSISessions());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddMultipathLine(PDSection s, String title, int current, int max, int iscsiSessions)
|
|
|
|
|
{
|
|
|
|
|
bool bad = current < max || (iscsiSessions != -1 && max < iscsiSessions);
|
|
|
|
|
string row = string.Format(Messages.MULTIPATH_STATUS, current, max);
|
|
|
|
|
if (iscsiSessions != -1)
|
|
|
|
|
row += string.Format(Messages.MULTIPATH_STATUS_ISCSI_SESSIONS, iscsiSessions);
|
|
|
|
|
|
|
|
|
|
if (bad)
|
|
|
|
|
s.AddEntry(title, row, Color.Red);
|
|
|
|
|
else
|
|
|
|
|
s.AddEntry(title, row);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateMultipathBootBox()
|
|
|
|
|
{
|
|
|
|
|
Host host = xenObject as Host;
|
|
|
|
|
if (host == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int current, max;
|
|
|
|
|
if (!host.GetBootPathCounts(out current, out max))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionMultipathBoot;
|
|
|
|
|
string text = string.Format(Messages.MULTIPATH_STATUS, current, max);
|
|
|
|
|
bool bad = current < max;
|
|
|
|
|
if (bad)
|
|
|
|
|
s.AddEntry(Messages.STATUS, text, Color.Red);
|
|
|
|
|
else
|
|
|
|
|
s.AddEntry(Messages.STATUS, text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateBootBox()
|
|
|
|
|
{
|
|
|
|
|
VM vm = xenObject as VM;
|
|
|
|
|
if (vm == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionBootOptions;
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (vm.IsHVM())
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2013-12-13 11:51:08 +01:00
|
|
|
|
s.AddEntry(FriendlyName("VM.BootOrder"), HVMBootOrder(vm),
|
2019-02-11 19:38:27 +01:00
|
|
|
|
new PropertiesToolStripMenuItem(new VmEditStartupOptionsCommand(Program.MainWindow, vm)));
|
|
|
|
|
if (Helpers.NaplesOrGreater(vm.Connection))
|
|
|
|
|
s.AddEntry(FriendlyName("VM.BootMode"), HVMBootMode(vm));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-12-13 11:51:08 +01:00
|
|
|
|
s.AddEntry(FriendlyName("VM.PV_args"), vm.PV_args,
|
2014-01-22 13:39:32 +01:00
|
|
|
|
new PropertiesToolStripMenuItem(new VmEditStartupOptionsCommand(Program.MainWindow, vm)));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateLicenseBox()
|
|
|
|
|
{
|
|
|
|
|
Host host = xenObject as Host;
|
|
|
|
|
if (host == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionLicense;
|
|
|
|
|
|
2017-05-31 17:58:52 +02:00
|
|
|
|
if (host.license_params == null)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Dictionary<string, string> info = new Dictionary<string, string>(host.license_params);
|
|
|
|
|
|
2018-12-04 14:02:56 +01:00
|
|
|
|
// This field is now suppressed as it has no meaning under the current license scheme, and was never
|
2013-06-24 13:41:48 +02:00
|
|
|
|
// enforced anyway.
|
|
|
|
|
info.Remove("sockets");
|
|
|
|
|
|
2016-01-21 13:31:33 +01:00
|
|
|
|
// Remove "expiry" field for "basic" license
|
|
|
|
|
if (!string.IsNullOrEmpty(host.edition) && host.edition == "basic")
|
|
|
|
|
info.Remove("expiry");
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
if (info.ContainsKey("expiry"))
|
|
|
|
|
{
|
2013-08-22 17:48:16 +02:00
|
|
|
|
ToolStripMenuItem editItem = new ToolStripMenuItem(Messages.LAUNCH_LICENSE_MANAGER);
|
|
|
|
|
editItem.Click += delegate
|
2018-12-04 14:21:04 +01:00
|
|
|
|
{
|
|
|
|
|
if (LicenseLauncher != null)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2018-12-04 14:21:04 +01:00
|
|
|
|
LicenseLauncher.Parent = Program.MainWindow;
|
|
|
|
|
LicenseLauncher.LaunchIfRequired(false, ConnectionsManager.XenConnections);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (licenseStatus != null)
|
|
|
|
|
{
|
|
|
|
|
var ss = new GeneralTabLicenseStatusStringifier(licenseStatus);
|
|
|
|
|
s.AddEntry(Messages.LICENSE_STATUS,
|
|
|
|
|
licenseStatus.Updated ? ss.ExpiryStatus : Messages.GENERAL_LICENSE_QUERYING, editItem);
|
|
|
|
|
s.AddEntry(FriendlyName("host.license_params-expiry"),
|
|
|
|
|
licenseStatus.Updated ? ss.ExpiryDate : Messages.GENERAL_LICENSE_QUERYING,
|
|
|
|
|
editItem, ss.ShowExpiryDate);
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
info.Remove("expiry");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(host.edition))
|
|
|
|
|
{
|
2014-11-14 18:29:01 +01:00
|
|
|
|
s.AddEntry(FriendlyName("host.edition"), Helpers.GetFriendlyLicenseName(host));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Messages.NUMBER_OF_SOCKETS, host.CpuSockets().ToString());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
if (host.license_server.ContainsKey("address"))
|
|
|
|
|
{
|
2014-11-14 18:29:01 +01:00
|
|
|
|
var licenseServerAddress = host.license_server["address"].Trim();
|
|
|
|
|
if (licenseServerAddress == "" || licenseServerAddress.ToLower() == "localhost")
|
2018-12-04 14:02:56 +01:00
|
|
|
|
s.AddEntry(FriendlyName("host.license_server-address"), host.license_server["address"]);
|
2014-10-31 13:16:45 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
2020-04-08 01:57:39 +02:00
|
|
|
|
void OpenWebConsole()
|
|
|
|
|
{
|
|
|
|
|
Program.OpenURL(string.Format(Messages.LICENSE_SERVER_WEB_CONSOLE_FORMAT, licenseServerAddress, Host.LicenseServerWebConsolePort));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var openUrl = new ToolStripMenuItem(Messages.LICENSE_SERVER_WEB_CONSOLE_GOTO, null,
|
|
|
|
|
(sender, e) => OpenWebConsole());
|
|
|
|
|
|
|
|
|
|
s.AddEntryLink(FriendlyName("host.license_server-address"), host.license_server["address"],
|
|
|
|
|
new[] {openUrl}, OpenWebConsole);
|
2014-10-31 13:16:45 +01:00
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
if (host.license_server.ContainsKey("port"))
|
|
|
|
|
{
|
2018-12-04 14:02:56 +01:00
|
|
|
|
s.AddEntry(FriendlyName("host.license_server-port"), host.license_server["port"]);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (string key in new string[] { "productcode", "serialnumber" })
|
|
|
|
|
{
|
|
|
|
|
if (info.ContainsKey(key))
|
|
|
|
|
{
|
|
|
|
|
string row_name = string.Format("host.license_params-{0}", key);
|
|
|
|
|
string k = key;
|
|
|
|
|
if (host.license_params[k] != string.Empty)
|
|
|
|
|
s.AddEntry(FriendlyName(row_name), host.license_params[k]);
|
|
|
|
|
info.Remove(key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string restrictions = Helpers.GetHostRestrictions(host);
|
|
|
|
|
if (restrictions != "")
|
|
|
|
|
{
|
|
|
|
|
s.AddEntry(Messages.RESTRICTIONS, restrictions);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateVersionBox()
|
|
|
|
|
{
|
|
|
|
|
Host host = xenObject as Host;
|
|
|
|
|
|
|
|
|
|
if (host == null || host.software_version == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (host.software_version.ContainsKey("date"))
|
2017-05-31 17:58:52 +02:00
|
|
|
|
pdSectionVersion.AddEntry(Messages.SOFTWARE_VERSION_DATE, host.software_version["date"]);
|
2017-07-27 15:47:12 +02:00
|
|
|
|
if (!Helpers.ElyOrGreater(host) && host.software_version.ContainsKey("build_number"))
|
2017-05-31 17:58:52 +02:00
|
|
|
|
pdSectionVersion.AddEntry(Messages.SOFTWARE_VERSION_BUILD_NUMBER, host.software_version["build_number"]);
|
|
|
|
|
if (host.software_version.ContainsKey("product_version"))
|
2019-08-21 12:43:11 +02:00
|
|
|
|
{
|
|
|
|
|
var hotfixEligibilityString = AdditionalVersionString(host);
|
|
|
|
|
if (string.IsNullOrEmpty(hotfixEligibilityString))
|
|
|
|
|
pdSectionVersion.AddEntry(Messages.SOFTWARE_VERSION_PRODUCT_VERSION, host.ProductVersionText());
|
|
|
|
|
else
|
|
|
|
|
pdSectionVersion.AddEntry(Messages.SOFTWARE_VERSION_PRODUCT_VERSION,
|
|
|
|
|
string.Format(Messages.MAINWINDOW_CONTEXT_REASON, host.ProductVersionText(), hotfixEligibilityString),
|
|
|
|
|
Color.Red);
|
|
|
|
|
}
|
2015-12-07 19:03:20 +01:00
|
|
|
|
if (host.software_version.ContainsKey("dbv"))
|
|
|
|
|
pdSectionVersion.AddEntry("DBV", host.software_version["dbv"]);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateCPUBox()
|
|
|
|
|
{
|
|
|
|
|
Host host = xenObject as Host;
|
|
|
|
|
if (host == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionCPU;
|
|
|
|
|
|
|
|
|
|
SortedDictionary<long, Host_cpu> d = new SortedDictionary<long, Host_cpu>();
|
|
|
|
|
foreach (Host_cpu cpu in xenObject.Connection.ResolveAll(host.host_CPUs))
|
|
|
|
|
{
|
|
|
|
|
d.Add(cpu.number, cpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool cpusIdentical = CPUsIdentical(d.Values);
|
|
|
|
|
|
|
|
|
|
foreach (Host_cpu cpu in d.Values)
|
|
|
|
|
{
|
|
|
|
|
String label = String.Format(Messages.GENERAL_DETAILS_CPU_NUMBER,
|
|
|
|
|
cpusIdentical && d.Values.Count > 1 ? String.Format("0 - {0}", d.Values.Count - 1)
|
|
|
|
|
: cpu.number.ToString());
|
|
|
|
|
|
|
|
|
|
s.AddEntry(label, Helpers.GetCPUProperties(cpu));
|
|
|
|
|
if (cpusIdentical)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-14 16:17:47 +02:00
|
|
|
|
private void generateVCPUsBox()
|
|
|
|
|
{
|
|
|
|
|
VM vm = xenObject as VM;
|
|
|
|
|
if (vm == null)
|
|
|
|
|
return;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2014-07-14 16:17:47 +02:00
|
|
|
|
PDSection s = pdSectionVCPUs;
|
|
|
|
|
|
|
|
|
|
s.AddEntry(FriendlyName("VM.VCPUs"), vm.VCPUs_at_startup.ToString());
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (vm.VCPUs_at_startup != vm.VCPUs_max || vm.SupportsVcpuHotplug())
|
2014-07-16 15:55:22 +02:00
|
|
|
|
s.AddEntry(FriendlyName("VM.MaxVCPUs"), vm.VCPUs_max.ToString());
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(FriendlyName("VM.Topology"), vm.Topology());
|
2014-07-14 16:17:47 +02:00
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
private void generateDisconnectedHostBox()
|
|
|
|
|
{
|
|
|
|
|
IXenConnection conn = xenObject.Connection;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionGeneral;
|
|
|
|
|
|
|
|
|
|
string name = Helpers.GetName(xenObject);
|
|
|
|
|
s.AddEntry(FriendlyName("host.name_label"), name);
|
|
|
|
|
if (conn != null && conn.Hostname != name)
|
|
|
|
|
s.AddEntry(FriendlyName("host.address"), conn.Hostname);
|
|
|
|
|
|
|
|
|
|
if (conn != null && conn.PoolMembers.Count > 1)
|
|
|
|
|
s.AddEntry(FriendlyName("host.pool_members"), string.Join(", ", conn.PoolMembers.ToArray()));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-12 13:59:32 +01:00
|
|
|
|
private void GenerateCertificateBox()
|
|
|
|
|
{
|
|
|
|
|
if (xenObject is Host host && Helpers.StockholmOrGreater(host) && host.certificates != null && host.certificates.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
var certificate = host.Connection.Resolve(host.certificates[0]);
|
|
|
|
|
if (certificate == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var cmdItem = new CommandToolStripMenuItem(new InstallCertificateCommand(Program.MainWindow, host), true);
|
|
|
|
|
|
|
|
|
|
pdSectionCertificate.AddEntry(Messages.CERTIFICATE_VALIDITY_PERIOD_KEY,
|
|
|
|
|
string.Format(Messages.CERTIFICATE_VALIDITY_PERIOD_VALUE,
|
|
|
|
|
HelpersGUI.DateTimeToString(certificate.not_before.ToLocalTime(), Messages.DATEFORMAT_DMY_HM, true),
|
|
|
|
|
HelpersGUI.DateTimeToString(certificate.not_after.ToLocalTime(), Messages.DATEFORMAT_DMY_HM, true)),
|
|
|
|
|
new[] {cmdItem});
|
|
|
|
|
|
|
|
|
|
pdSectionCertificate.AddEntry(Messages.CERTIFICATE_THUMBPRINT_KEY, certificate.fingerprint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
private void generateGeneralBox()
|
|
|
|
|
{
|
|
|
|
|
PDSection s = pdSectionGeneral;
|
|
|
|
|
|
|
|
|
|
s.AddEntry(FriendlyName("host.name_label"), Helpers.GetName(xenObject),
|
2014-01-22 13:39:32 +01:00
|
|
|
|
new PropertiesToolStripMenuItem(new PropertiesCommand(Program.MainWindow, xenObject)));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2015-10-27 19:11:53 +01:00
|
|
|
|
VM vm = xenObject as VM;
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (vm == null || vm.DescriptionType() != VM.VmDescriptionType.None)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(FriendlyName("host.name_description"), xenObject.Description(),
|
2015-10-27 19:11:53 +01:00
|
|
|
|
new PropertiesToolStripMenuItem(new DescriptionPropertiesCommand(Program.MainWindow, xenObject)));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-27 19:11:53 +01:00
|
|
|
|
GenTagRow(s);
|
|
|
|
|
GenFolderRow(s);
|
|
|
|
|
|
2020-03-12 13:59:32 +01:00
|
|
|
|
if (xenObject is Host host)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
if (Helpers.GetPool(xenObject.Connection) != null)
|
|
|
|
|
s.AddEntry(Messages.POOL_MASTER, host.IsMaster() ? Messages.YES : Messages.NO);
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (!host.IsLive())
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
s.AddEntry(FriendlyName("host.enabled"), Messages.HOST_NOT_LIVE, Color.Red);
|
|
|
|
|
}
|
|
|
|
|
else if (!host.enabled)
|
|
|
|
|
{
|
2013-08-22 17:48:16 +02:00
|
|
|
|
var item = new ToolStripMenuItem(Messages.EXIT_MAINTENANCE_MODE);
|
|
|
|
|
item.Click += delegate
|
|
|
|
|
{
|
2014-01-22 13:39:32 +01:00
|
|
|
|
new HostMaintenanceModeCommand(Program.MainWindow, host,
|
2013-08-22 17:48:16 +02:00
|
|
|
|
HostMaintenanceModeCommandParameter.Exit).Execute();
|
|
|
|
|
};
|
2013-06-24 13:41:48 +02:00
|
|
|
|
s.AddEntry(FriendlyName("host.enabled"),
|
2017-09-03 04:33:29 +02:00
|
|
|
|
host.MaintenanceMode() ? Messages.HOST_IN_MAINTENANCE_MODE : Messages.DISABLED,
|
2013-12-13 11:51:08 +01:00
|
|
|
|
new[] { item },
|
2013-06-24 13:41:48 +02:00
|
|
|
|
Color.Red);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-08-22 17:48:16 +02:00
|
|
|
|
var item = new ToolStripMenuItem(Messages.ENTER_MAINTENANCE_MODE);
|
|
|
|
|
item.Click += delegate
|
|
|
|
|
{
|
2014-01-22 13:39:32 +01:00
|
|
|
|
new HostMaintenanceModeCommand(Program.MainWindow, host,
|
2013-08-22 17:48:16 +02:00
|
|
|
|
HostMaintenanceModeCommandParameter.Enter).Execute();
|
|
|
|
|
};
|
2013-12-22 18:33:13 +01:00
|
|
|
|
s.AddEntry(FriendlyName("host.enabled"), Messages.YES, item);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-05 03:15:38 +02:00
|
|
|
|
s.AddEntry(FriendlyName("host.iscsi_iqn"), host.GetIscsiIqn(),
|
2014-01-22 13:39:32 +01:00
|
|
|
|
new PropertiesToolStripMenuItem(new IqnPropertiesCommand(Program.MainWindow, xenObject)));
|
2019-03-21 14:35:26 +01:00
|
|
|
|
|
|
|
|
|
var sysLog = host.GetSysLogDestination();
|
|
|
|
|
var sysLogDisplay = string.IsNullOrEmpty(sysLog)
|
|
|
|
|
? Messages.HOST_LOG_DESTINATION_LOCAL
|
|
|
|
|
: string.Format(Messages.HOST_LOG_DESTINATION_LOCAL_AND_REMOTE, sysLog);
|
|
|
|
|
|
|
|
|
|
s.AddEntry(FriendlyName("host.log_destination"), sysLogDisplay,
|
2014-01-22 13:39:32 +01:00
|
|
|
|
new PropertiesToolStripMenuItem(new HostEditLogDestinationCommand(Program.MainWindow, xenObject)));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
PrettyTimeSpan uptime = host.Uptime();
|
|
|
|
|
PrettyTimeSpan agentUptime = host.AgentUptime();
|
|
|
|
|
s.AddEntry(FriendlyName("host.uptime"), uptime == null ? "" : uptime.ToString());
|
|
|
|
|
s.AddEntry(FriendlyName("host.agentUptime"), agentUptime == null ? "" : agentUptime.ToString());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2015-10-26 17:01:55 +01:00
|
|
|
|
if (host.external_auth_type == Auth.AUTH_TYPE_AD)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
s.AddEntry(FriendlyName("host.external_auth_service_name"), host.external_auth_service_name);
|
|
|
|
|
}
|
2016-10-14 14:51:51 +02:00
|
|
|
|
|
|
|
|
|
if (vm != null)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
s.AddEntry(FriendlyName("VM.OSName"), vm.GetOSName());
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(FriendlyName("VM.OperatingMode"), vm.IsHVM() ? Messages.VM_OPERATING_MODE_HVM : Messages.VM_OPERATING_MODE_PV);
|
2015-06-09 13:34:13 +02:00
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (!vm.DefaultTemplate())
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Messages.BIOS_STRINGS_COPIED, vm.BiosStringsCopied() ? Messages.YES : Messages.NO);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-26 17:01:55 +01:00
|
|
|
|
if (vm.Connection != null)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
var appl = vm.Connection.Resolve(vm.appliance);
|
|
|
|
|
if (appl != null)
|
|
|
|
|
{
|
2020-04-08 01:57:39 +02:00
|
|
|
|
void LaunchProperties()
|
|
|
|
|
{
|
|
|
|
|
using (PropertiesDialog propertiesDialog = new PropertiesDialog(appl))
|
|
|
|
|
propertiesDialog.ShowDialog(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var applProperties = new ToolStripMenuItem(Messages.VM_APPLIANCE_PROPERTIES, null,
|
|
|
|
|
(sender, e) => LaunchProperties());
|
|
|
|
|
|
|
|
|
|
s.AddEntryLink(Messages.VM_APPLIANCE, appl.Name(), new[] {applProperties}, LaunchProperties);
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm.is_a_snapshot)
|
|
|
|
|
{
|
|
|
|
|
VM snapshotOf = vm.Connection.Resolve(vm.snapshot_of);
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Messages.SNAPSHOT_OF, snapshotOf == null ? string.Empty : snapshotOf.Name());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
s.AddEntry(Messages.CREATION_TIME, HelpersGUI.DateTimeToString(vm.snapshot_time.ToLocalTime() + vm.Connection.ServerTimeOffset, Messages.DATEFORMAT_DMY_HMS, true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!vm.is_a_template)
|
|
|
|
|
{
|
2015-08-13 18:41:15 +02:00
|
|
|
|
GenerateVirtualisationStatusForGeneralBox(s, vm);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
var runningTime = vm.RunningTime();
|
|
|
|
|
if (runningTime != null)
|
|
|
|
|
s.AddEntry(FriendlyName("VM.uptime"), runningTime.ToString());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (vm.IsP2V())
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(FriendlyName("VM.P2V_SourceMachine"), vm.P2V_SourceMachine());
|
|
|
|
|
s.AddEntry(FriendlyName("VM.P2V_ImportDate"), HelpersGUI.DateTimeToString(vm.P2V_ImportDate().ToLocalTime(), Messages.DATEFORMAT_DMY_HMS, true));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dont show if WLB is enabled.
|
|
|
|
|
if (VMCanChooseHomeServer(vm))
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(FriendlyName("VM.affinity"), vm.AffinityServerString(),
|
2016-10-14 14:51:51 +02:00
|
|
|
|
new PropertiesToolStripMenuItem(new VmEditHomeServerCommand(Program.MainWindow, xenObject)));
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-14 14:51:51 +02:00
|
|
|
|
|
|
|
|
|
SR sr = xenObject as SR;
|
|
|
|
|
if (sr != null)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Messages.TYPE, sr.FriendlyTypeName());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
if (sr.content_type != SR.Content_Type_ISO && sr.GetSRType(false) != SR.SRTypes.udev)
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(FriendlyName("SR.size"), sr.SizeString());
|
2015-08-26 18:54:03 +02:00
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
if (sr.GetScsiID() != null)
|
|
|
|
|
s.AddEntry(FriendlyName("SR.scsiid"), sr.GetScsiID() ?? Messages.UNKNOWN);
|
|
|
|
|
|
|
|
|
|
// if in folder-view or if looking at SR on storagelink then display
|
|
|
|
|
// location here
|
|
|
|
|
if (Program.MainWindow.SelectionManager.Selection.HostAncestor == null && Program.MainWindow.SelectionManager.Selection.PoolAncestor == null)
|
|
|
|
|
{
|
|
|
|
|
IXenObject belongsTo = Helpers.GetPool(sr.Connection);
|
|
|
|
|
|
|
|
|
|
if (belongsTo != null)
|
|
|
|
|
{
|
|
|
|
|
s.AddEntry(Messages.POOL, Helpers.GetName(belongsTo));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
belongsTo = Helpers.GetMaster(sr.Connection);
|
|
|
|
|
|
|
|
|
|
if (belongsTo != null)
|
|
|
|
|
{
|
|
|
|
|
s.AddEntry(Messages.SERVER, Helpers.GetName(belongsTo));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-14 14:51:51 +02:00
|
|
|
|
|
|
|
|
|
Pool p = xenObject as Pool;
|
|
|
|
|
if (p != null)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2017-10-10 18:02:17 +02:00
|
|
|
|
var additionalString = PoolAdditionalLicenseString();
|
|
|
|
|
s.AddEntry(Messages.POOL_LICENSE,
|
|
|
|
|
additionalString != string.Empty
|
2018-10-05 12:57:16 +02:00
|
|
|
|
? string.Format(Messages.MAINWINDOW_CONTEXT_REASON, Helpers.GetFriendlyLicenseName(p), additionalString)
|
|
|
|
|
: Helpers.GetFriendlyLicenseName(p));
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Messages.NUMBER_OF_SOCKETS, p.CpuSockets().ToString());
|
2013-12-13 18:35:40 +01:00
|
|
|
|
|
2016-10-14 14:51:51 +02:00
|
|
|
|
var master = p.Connection.Resolve(p.master);
|
|
|
|
|
if (master != null)
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (p.IsPoolFullyUpgraded())
|
2013-12-19 13:41:07 +01:00
|
|
|
|
{
|
2019-08-21 12:43:11 +02:00
|
|
|
|
var hotfixEligibilityString = AdditionalVersionString(master);
|
|
|
|
|
if (string.IsNullOrEmpty(hotfixEligibilityString))
|
|
|
|
|
s.AddEntry(Messages.SOFTWARE_VERSION_PRODUCT_VERSION, master.ProductVersionText());
|
|
|
|
|
else
|
|
|
|
|
s.AddEntry(Messages.SOFTWARE_VERSION_PRODUCT_VERSION,
|
|
|
|
|
string.Format(Messages.MAINWINDOW_CONTEXT_REASON, master.ProductVersionText(), hotfixEligibilityString),
|
|
|
|
|
Color.Red);
|
2016-10-14 14:51:51 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var cmd = new RollingUpgradeCommand(Program.MainWindow);
|
|
|
|
|
var runRpuWizard = new ToolStripMenuItem(Messages.ROLLING_POOL_UPGRADE_ELLIPSIS,
|
|
|
|
|
null,
|
|
|
|
|
(sender, args) => cmd.Execute());
|
|
|
|
|
|
|
|
|
|
s.AddEntryLink(Messages.SOFTWARE_VERSION_PRODUCT_VERSION,
|
2021-03-16 02:50:45 +01:00
|
|
|
|
string.Format(Messages.POOL_VERSIONS_LINK_TEXT, BrandManager.ProductBrand, master.ProductVersionText()),
|
2016-10-14 14:51:51 +02:00
|
|
|
|
new[] {runRpuWizard},
|
|
|
|
|
cmd);
|
2013-12-13 18:35:40 +01:00
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-14 14:51:51 +02:00
|
|
|
|
VDI vdi = xenObject as VDI;
|
|
|
|
|
if (vdi != null)
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Messages.SIZE, vdi.SizeText(),
|
2016-10-14 14:51:51 +02:00
|
|
|
|
new PropertiesToolStripMenuItem(new VdiEditSizeLocationCommand(Program.MainWindow, xenObject)));
|
|
|
|
|
|
|
|
|
|
SR vdiSr = vdi.Connection.Resolve(vdi.SR);
|
2017-09-03 04:33:29 +02:00
|
|
|
|
if (vdiSr != null && !vdiSr.IsToolsSR())
|
|
|
|
|
s.AddEntry(Messages.DATATYPE_STORAGE, vdiSr.NameWithLocation());
|
2016-10-14 14:51:51 +02:00
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
string vdiVms = vdi.VMsOfVDI();
|
2016-10-14 14:51:51 +02:00
|
|
|
|
if (!string.IsNullOrEmpty(vdiVms))
|
|
|
|
|
s.AddEntry(Messages.VIRTUAL_MACHINE, vdiVms);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
s.AddEntry(FriendlyName("host.uuid"), xenObject.Get("uuid") as string);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-10 18:02:17 +02:00
|
|
|
|
private string PoolAdditionalLicenseString()
|
|
|
|
|
{
|
2018-09-27 15:36:08 +02:00
|
|
|
|
if (licenseStatus == null)
|
2017-10-10 18:02:17 +02:00
|
|
|
|
return string.Empty;
|
2018-09-27 15:36:08 +02:00
|
|
|
|
|
|
|
|
|
switch (licenseStatus.CurrentState)
|
|
|
|
|
{
|
|
|
|
|
case LicenseStatus.HostState.Expired:
|
|
|
|
|
return Messages.LICENSE_EXPIRED;
|
|
|
|
|
case LicenseStatus.HostState.Free:
|
|
|
|
|
return Messages.LICENSE_UNLICENSED;
|
|
|
|
|
default:
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
2017-10-10 18:02:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-21 12:43:11 +02:00
|
|
|
|
private string AdditionalVersionString(Host host)
|
|
|
|
|
{
|
|
|
|
|
var hotfixEligibility = Updates.HotfixEligibility(host, out var xenServerVersion);
|
2019-08-30 14:05:22 +02:00
|
|
|
|
var unlicensed = host.IsFreeLicenseOrExpired();
|
2019-08-21 12:43:11 +02:00
|
|
|
|
|
|
|
|
|
switch (hotfixEligibility)
|
|
|
|
|
{
|
2019-08-30 14:05:22 +02:00
|
|
|
|
// premium
|
|
|
|
|
case hotfix_eligibility.premium when unlicensed && xenServerVersion.HotfixEligibilityPremiumDate != DateTime.MinValue:
|
|
|
|
|
return string.Format(Messages.HOTFIX_ELIGIBILITY_WARNING_FREE, HelpersGUI.DateTimeToString(xenServerVersion.HotfixEligibilityPremiumDate.ToLocalTime(), Messages.DATEFORMAT_DMY, true));
|
|
|
|
|
case hotfix_eligibility.premium when unlicensed:
|
|
|
|
|
return Messages.HOTFIX_ELIGIBILITY_WARNING_FREE_NO_DATE;
|
|
|
|
|
|
|
|
|
|
// cu
|
|
|
|
|
case hotfix_eligibility.cu when unlicensed && xenServerVersion.HotfixEligibilityPremiumDate != DateTime.MinValue:
|
|
|
|
|
return string.Format(Messages.HOTFIX_ELIGIBILITY_WARNING_FREE, HelpersGUI.DateTimeToString(xenServerVersion.HotfixEligibilityPremiumDate.ToLocalTime(), Messages.DATEFORMAT_DMY, true));
|
|
|
|
|
case hotfix_eligibility.cu when unlicensed:
|
|
|
|
|
return Messages.HOTFIX_ELIGIBILITY_WARNING_FREE_NO_DATE;
|
|
|
|
|
|
|
|
|
|
case hotfix_eligibility.cu when xenServerVersion.HotfixEligibilityNoneDate != DateTime.MinValue:
|
|
|
|
|
return string.Format(Messages.HOTFIX_ELIGIBILITY_WARNING_CU, HelpersGUI.DateTimeToString(xenServerVersion.HotfixEligibilityNoneDate.ToLocalTime(), Messages.DATEFORMAT_DMY, true));
|
2019-08-21 12:43:11 +02:00
|
|
|
|
case hotfix_eligibility.cu:
|
2019-08-30 14:05:22 +02:00
|
|
|
|
return Messages.HOTFIX_ELIGIBILITY_WARNING_CU_NO_DATE;
|
|
|
|
|
|
|
|
|
|
// none
|
2019-09-10 16:03:17 +02:00
|
|
|
|
case hotfix_eligibility.none when unlicensed && xenServerVersion.EolDate != DateTime.MinValue:
|
|
|
|
|
return string.Format(Messages.HOTFIX_ELIGIBILITY_WARNING_EOL_FREE, HelpersGUI.DateTimeToString(xenServerVersion.EolDate.ToLocalTime(), Messages.DATEFORMAT_DMY, true));
|
2019-08-30 14:05:22 +02:00
|
|
|
|
case hotfix_eligibility.none when xenServerVersion.EolDate != DateTime.MinValue:
|
2019-08-21 12:43:11 +02:00
|
|
|
|
return string.Format(Messages.HOTFIX_ELIGIBILITY_WARNING_EOL, HelpersGUI.DateTimeToString(xenServerVersion.EolDate.ToLocalTime(), Messages.DATEFORMAT_DMY, true));
|
2019-09-10 16:03:17 +02:00
|
|
|
|
case hotfix_eligibility.none when unlicensed:
|
|
|
|
|
return Messages.HOTFIX_ELIGIBILITY_WARNING_EOL_FREE_NO_DATE;
|
2019-08-30 14:05:22 +02:00
|
|
|
|
case hotfix_eligibility.none:
|
|
|
|
|
return Messages.HOTFIX_ELIGIBILITY_WARNING_EOL_NO_DATE;
|
|
|
|
|
|
|
|
|
|
// default
|
2019-08-21 12:43:11 +02:00
|
|
|
|
default:
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-13 18:41:15 +02:00
|
|
|
|
private static void GenerateVirtualisationStatusForGeneralBox(PDSection s, VM vm)
|
|
|
|
|
{
|
2015-12-15 15:32:11 +01:00
|
|
|
|
if (vm != null && vm.Connection != null)
|
2015-08-13 18:41:15 +02:00
|
|
|
|
{
|
|
|
|
|
//For Dundee or higher Windows VMs
|
2020-04-25 05:50:51 +02:00
|
|
|
|
if (vm.HasNewVirtualisationStates())
|
2015-08-13 18:41:15 +02:00
|
|
|
|
{
|
2020-04-25 05:50:51 +02:00
|
|
|
|
var status = vm.GetVirtualisationStatus(out var statusString);
|
2015-08-13 18:41:15 +02:00
|
|
|
|
|
2015-12-15 15:32:11 +01:00
|
|
|
|
var sb = new StringBuilder();
|
2015-08-13 18:41:15 +02:00
|
|
|
|
|
2015-12-15 15:32:11 +01:00
|
|
|
|
if (vm.power_state == vm_power_state.Running)
|
|
|
|
|
{
|
2020-04-25 05:50:51 +02:00
|
|
|
|
if (status.HasFlag(VM.VirtualisationStatus.UNKNOWN))
|
2015-08-13 18:41:15 +02:00
|
|
|
|
{
|
2020-04-25 05:50:51 +02:00
|
|
|
|
sb.AppendLine(statusString);
|
2015-08-13 18:41:15 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-12-15 15:32:11 +01:00
|
|
|
|
//Row 1 : I/O Drivers
|
2020-04-25 05:50:51 +02:00
|
|
|
|
sb.AppendLine(status.HasFlag(VM.VirtualisationStatus.IO_DRIVERS_INSTALLED)
|
2020-04-08 01:57:39 +02:00
|
|
|
|
? Messages.VIRTUALIZATION_STATE_VM_IO_OPTIMIZED
|
|
|
|
|
: Messages.VIRTUALIZATION_STATE_VM_IO_NOT_OPTIMIZED);
|
2015-12-15 15:32:11 +01:00
|
|
|
|
|
|
|
|
|
//Row 2: Management Agent
|
2020-04-25 05:50:51 +02:00
|
|
|
|
sb.AppendLine(status.HasFlag(VM.VirtualisationStatus.MANAGEMENT_INSTALLED)
|
2020-04-08 01:57:39 +02:00
|
|
|
|
? Messages.VIRTUALIZATION_STATE_VM_MANAGEMENT_AGENT_INSTALLED
|
|
|
|
|
: Messages.VIRTUALIZATION_STATE_VM_MANAGEMENT_AGENT_NOT_INSTALLED);
|
2015-08-13 18:41:15 +02:00
|
|
|
|
}
|
2015-12-15 15:32:11 +01:00
|
|
|
|
}
|
2015-08-13 18:41:15 +02:00
|
|
|
|
|
2015-12-15 15:32:11 +01:00
|
|
|
|
//Row 3 : vendor device - Windows Update
|
2016-10-28 13:58:23 +02:00
|
|
|
|
if(!HiddenFeatures.WindowsUpdateHidden)
|
|
|
|
|
sb.Append(vm.has_vendor_device ? Messages.VIRTUALIZATION_STATE_VM_RECEIVING_UPDATES : Messages.VIRTUALIZATION_STATE_VM_NOT_RECEIVING_UPDATES);
|
2015-08-13 18:41:15 +02:00
|
|
|
|
|
2015-12-15 15:32:11 +01:00
|
|
|
|
// displaying Row1 - Row3
|
|
|
|
|
s.AddEntry(FriendlyName("VM.VirtualizationState"), sb.ToString());
|
2015-08-13 18:41:15 +02:00
|
|
|
|
|
2015-12-15 15:32:11 +01:00
|
|
|
|
if (vm.power_state == vm_power_state.Running)
|
|
|
|
|
{
|
2015-08-13 18:41:15 +02:00
|
|
|
|
//Row 4: Install Tools
|
|
|
|
|
string installMessage = string.Empty;
|
2020-04-25 05:50:51 +02:00
|
|
|
|
var canInstall = InstallToolsCommand.CanExecute(vm);
|
|
|
|
|
|
|
|
|
|
if (canInstall && !status.HasFlag(VM.VirtualisationStatus.IO_DRIVERS_INSTALLED))
|
2015-08-13 18:41:15 +02:00
|
|
|
|
{
|
|
|
|
|
installMessage = Messages.VIRTUALIZATION_STATE_VM_INSTALL_IO_DRIVERS_AND_MANAGEMENT_AGENT;
|
|
|
|
|
}
|
2020-04-25 05:50:51 +02:00
|
|
|
|
else if (canInstall && status.HasFlag(VM.VirtualisationStatus.IO_DRIVERS_INSTALLED) &&
|
|
|
|
|
!status.HasFlag(VM.VirtualisationStatus.MANAGEMENT_INSTALLED))
|
2015-08-13 18:41:15 +02:00
|
|
|
|
{
|
|
|
|
|
installMessage = Messages.VIRTUALIZATION_STATE_VM_INSTALL_MANAGEMENT_AGENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(installMessage))
|
|
|
|
|
{
|
2020-04-08 01:57:39 +02:00
|
|
|
|
if (Helpers.StockholmOrGreater(vm.Connection))
|
|
|
|
|
{
|
|
|
|
|
void GoToHelp()
|
|
|
|
|
{
|
|
|
|
|
Help.HelpManager.Launch("InstallToolsWarningDialog");
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 02:50:45 +01:00
|
|
|
|
var toolsItem = new ToolStripMenuItem(string.Format(Messages.INSTALLTOOLS_READ_MORE, BrandManager.VmTools), null,
|
2020-04-08 01:57:39 +02:00
|
|
|
|
(sender, args) => GoToHelp());
|
2021-03-16 02:50:45 +01:00
|
|
|
|
s.AddEntryLink(string.Empty, string.Format(Messages.INSTALLTOOLS_READ_MORE, BrandManager.VmTools), new[] {toolsItem}, GoToHelp);
|
2020-04-08 01:57:39 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
2015-08-13 18:41:15 +02:00
|
|
|
|
{
|
2020-04-08 01:57:39 +02:00
|
|
|
|
var cmd = new InstallToolsCommand(Program.MainWindow, vm);
|
|
|
|
|
var toolsItem = new ToolStripMenuItem(installMessage, null, (sender, args) => cmd.Execute());
|
|
|
|
|
s.AddEntryLink(string.Empty, installMessage, new[] {toolsItem}, cmd);
|
|
|
|
|
}
|
2015-08-13 18:41:15 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-15 15:32:11 +01:00
|
|
|
|
|
2015-08-14 13:11:02 +02:00
|
|
|
|
//for everything else (All VMs on pre-Dundee hosts & All non-Windows VMs on any host)
|
2015-12-15 15:32:11 +01:00
|
|
|
|
else if (vm.power_state == vm_power_state.Running)
|
2015-08-13 18:41:15 +02:00
|
|
|
|
{
|
2020-04-25 05:50:51 +02:00
|
|
|
|
var status = vm.GetVirtualisationStatus(out var statusString);
|
|
|
|
|
|
2020-07-03 17:23:52 +02:00
|
|
|
|
if (status == VM.VirtualisationStatus.NOT_INSTALLED || status.HasFlag(VM.VirtualisationStatus.PV_DRIVERS_OUT_OF_DATE))
|
2015-08-13 18:41:15 +02:00
|
|
|
|
{
|
|
|
|
|
if (InstallToolsCommand.CanExecute(vm))
|
|
|
|
|
{
|
2020-04-08 01:57:39 +02:00
|
|
|
|
if (Helpers.StockholmOrGreater(vm.Connection))
|
|
|
|
|
{
|
|
|
|
|
void GoToHelp()
|
|
|
|
|
{
|
|
|
|
|
Help.HelpManager.Launch("InstallToolsWarningDialog");
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 02:50:45 +01:00
|
|
|
|
var toolsItem = new ToolStripMenuItem(string.Format(Messages.INSTALLTOOLS_READ_MORE, BrandManager.VmTools), null, (sender, args) => GoToHelp());
|
2020-04-25 05:50:51 +02:00
|
|
|
|
|
|
|
|
|
s.AddEntry(FriendlyName("VM.VirtualizationState"), statusString);
|
2021-03-16 02:50:45 +01:00
|
|
|
|
s.AddEntryLink("", string.Format(Messages.INSTALLTOOLS_READ_MORE, BrandManager.VmTools), new[] {toolsItem}, GoToHelp);
|
2020-04-08 01:57:39 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
2015-08-13 18:41:15 +02:00
|
|
|
|
{
|
2020-04-08 01:57:39 +02:00
|
|
|
|
var cmd = new InstallToolsCommand(Program.MainWindow, vm);
|
2021-03-16 02:50:45 +01:00
|
|
|
|
var toolsItem = new ToolStripMenuItem(string.Format(Messages.INSTALL_XENSERVER_TOOLS, BrandManager.VmTools), null,
|
2020-04-08 01:57:39 +02:00
|
|
|
|
(sender, args) => cmd.Execute());
|
|
|
|
|
|
2020-04-25 05:50:51 +02:00
|
|
|
|
s.AddEntryLink(FriendlyName("VM.VirtualizationState"), statusString,
|
2020-04-08 01:57:39 +02:00
|
|
|
|
new[] {toolsItem}, cmd);
|
|
|
|
|
}
|
2015-08-13 18:41:15 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-04-25 05:50:51 +02:00
|
|
|
|
s.AddEntry(FriendlyName("VM.VirtualizationState"), statusString, Color.Red);
|
2015-08-13 18:41:15 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-04-25 05:50:51 +02:00
|
|
|
|
s.AddEntry(FriendlyName("VM.VirtualizationState"), statusString);
|
2015-08-13 18:41:15 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-05 15:16:58 +01:00
|
|
|
|
private void generateDockerContainerGeneralBox()
|
|
|
|
|
{
|
2018-12-04 14:02:56 +01:00
|
|
|
|
var dockerContainer = xenObject as DockerContainer;
|
|
|
|
|
if (dockerContainer != null)
|
2014-12-05 15:16:58 +01:00
|
|
|
|
{
|
|
|
|
|
PDSection s = pdSectionGeneral;
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(Messages.NAME, dockerContainer.Name().Length != 0 ? dockerContainer.Name() : Messages.NONE);
|
2015-02-10 04:03:53 +01:00
|
|
|
|
s.AddEntry(Messages.STATUS, dockerContainer.status.Length != 0 ? dockerContainer.status : Messages.NONE);
|
2015-02-13 10:25:13 +01:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
DateTime created = Util.FromUnixTime(double.Parse(dockerContainer.created)).ToLocalTime();
|
|
|
|
|
s.AddEntry(Messages.CONTAINER_CREATED, HelpersGUI.DateTimeToString(created, Messages.DATEFORMAT_DMY_HMS, true));
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
s.AddEntry(Messages.CONTAINER_CREATED, dockerContainer.created.Length != 0 ? dockerContainer.created : Messages.NONE);
|
|
|
|
|
}
|
2015-02-10 04:03:53 +01:00
|
|
|
|
s.AddEntry(Messages.CONTAINER_IMAGE, dockerContainer.image.Length != 0 ? dockerContainer.image : Messages.NONE);
|
|
|
|
|
s.AddEntry(Messages.CONTAINER, dockerContainer.container.Length != 0 ? dockerContainer.container : Messages.NONE);
|
|
|
|
|
s.AddEntry(Messages.CONTAINER_COMMAND, dockerContainer.command.Length != 0 ? dockerContainer.command : Messages.NONE);
|
2015-03-06 12:43:47 +01:00
|
|
|
|
var ports = dockerContainer.PortList.Select(p => p.Description);
|
2015-03-09 16:43:49 +01:00
|
|
|
|
if (ports.Count() > 0)
|
|
|
|
|
{
|
|
|
|
|
s.AddEntry(Messages.CONTAINER_PORTS, string.Join(Environment.NewLine, ports));
|
|
|
|
|
}
|
2015-02-10 04:03:53 +01:00
|
|
|
|
s.AddEntry(Messages.UUID, dockerContainer.uuid.Length != 0 ? dockerContainer.uuid : Messages.NONE);
|
2014-12-05 15:16:58 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-19 15:09:08 +01:00
|
|
|
|
private void generateReadCachingBox()
|
|
|
|
|
{
|
|
|
|
|
VM vm = xenObject as VM;
|
2019-01-31 00:00:56 +01:00
|
|
|
|
if (vm == null || !vm.IsRunning())
|
2015-02-19 15:09:08 +01:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionReadCaching;
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
var pvsProxy = vm.PvsProxy();
|
2016-10-13 13:32:56 +02:00
|
|
|
|
if (pvsProxy != null)
|
|
|
|
|
s.AddEntry(FriendlyName("VM.pvs_read_caching_status"), pvs_proxy_status_extensions.ToFriendlyString(pvsProxy.status));
|
2017-09-03 04:33:29 +02:00
|
|
|
|
else if (vm.ReadCachingEnabled())
|
2015-02-19 15:09:08 +01:00
|
|
|
|
{
|
|
|
|
|
s.AddEntry(FriendlyName("VM.read_caching_status"), Messages.VM_READ_CACHING_ENABLED);
|
2017-09-03 04:33:29 +02:00
|
|
|
|
var vdiList = vm.ReadCachingVDIs().Select(vdi => vdi.NameWithLocation()).ToArray();
|
2015-02-19 15:09:08 +01:00
|
|
|
|
s.AddEntry(FriendlyName("VM.read_caching_disks"), string.Join("\n", vdiList));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s.AddEntry(FriendlyName("VM.read_caching_status"), Messages.VM_READ_CACHING_DISABLED);
|
2017-09-03 04:33:29 +02:00
|
|
|
|
var reason = vm.ReadCachingDisabledReason();
|
2015-03-16 20:54:55 +01:00
|
|
|
|
if (reason != null)
|
|
|
|
|
s.AddEntry(FriendlyName("VM.read_caching_reason"), reason);
|
2015-02-19 15:09:08 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
private static bool VMCanChooseHomeServer(VM vm)
|
|
|
|
|
{
|
|
|
|
|
if (vm != null && !vm.is_a_template)
|
|
|
|
|
{
|
|
|
|
|
String ChangeHomeReason = vm.IsOnSharedStorage();
|
|
|
|
|
|
|
|
|
|
return !Helpers.WlbEnabledAndConfigured(vm.Connection) &&
|
2017-09-05 03:15:38 +02:00
|
|
|
|
(String.IsNullOrEmpty(ChangeHomeReason) || vm.HasNoDisksAndNoLocalCD());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void GenTagRow(PDSection s)
|
|
|
|
|
{
|
|
|
|
|
string[] tags = Tags.GetTags(xenObject);
|
2013-12-13 11:51:08 +01:00
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
if (tags != null && tags.Length > 0)
|
|
|
|
|
{
|
2013-08-22 17:48:16 +02:00
|
|
|
|
ToolStripMenuItem goToTag = new ToolStripMenuItem(Messages.VIEW_TAG_MENU_OPTION);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
foreach (string tag in tags)
|
|
|
|
|
{
|
2013-08-22 17:48:16 +02:00
|
|
|
|
var item = new ToolStripMenuItem(tag.Ellipsise(30));
|
|
|
|
|
item.Click += delegate { Program.MainWindow.SearchForTag(tag); };
|
|
|
|
|
goToTag.DropDownItems.Add(item);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
2013-12-13 11:51:08 +01:00
|
|
|
|
|
2014-01-22 13:39:32 +01:00
|
|
|
|
s.AddEntry(Messages.TAGS, TagsString(), new[] { goToTag, new PropertiesToolStripMenuItem(new PropertiesCommand(Program.MainWindow, xenObject)) });
|
2013-06-24 13:41:48 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2013-12-13 11:51:08 +01:00
|
|
|
|
|
2014-01-22 13:39:32 +01:00
|
|
|
|
s.AddEntry(Messages.TAGS, Messages.NONE, new PropertiesToolStripMenuItem(new PropertiesCommand(Program.MainWindow, xenObject)));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string TagsString()
|
|
|
|
|
{
|
|
|
|
|
string[] tags = Tags.GetTags(xenObject);
|
|
|
|
|
if (tags == null || tags.Length == 0)
|
|
|
|
|
return Messages.NONE;
|
|
|
|
|
|
2013-12-13 11:51:08 +01:00
|
|
|
|
return string.Join(", ", tags.OrderBy(s => s).ToArray());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void GenFolderRow(PDSection s)
|
|
|
|
|
{
|
|
|
|
|
List<ToolStripMenuItem> menuItems = new List<ToolStripMenuItem>();
|
|
|
|
|
if (xenObject.Path != "")
|
|
|
|
|
{
|
2013-08-22 17:48:16 +02:00
|
|
|
|
var item = new ToolStripMenuItem(Messages.VIEW_FOLDER_MENU_OPTION);
|
|
|
|
|
item.Click += delegate { Program.MainWindow.SearchForFolder(xenObject.Path); };
|
|
|
|
|
menuItems.Add(item);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
2014-01-22 13:39:32 +01:00
|
|
|
|
menuItems.Add(new PropertiesToolStripMenuItem(new PropertiesCommand(Program.MainWindow, xenObject)));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
s.AddEntry(
|
|
|
|
|
Messages.FOLDER,
|
|
|
|
|
new FolderListItem(xenObject.Path, FolderListItem.AllowSearch.None, false),
|
|
|
|
|
menuItems
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateMemoryBox()
|
|
|
|
|
{
|
|
|
|
|
Host host = xenObject as Host;
|
|
|
|
|
if (host == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PDSection s = pdSectionMemory;
|
|
|
|
|
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
s.AddEntry(FriendlyName("host.ServerMemory"), host.HostMemoryString());
|
|
|
|
|
s.AddEntry(FriendlyName("host.VMMemory"), host.ResidentVMMemoryUsageString());
|
|
|
|
|
s.AddEntry(FriendlyName("host.XenMemory"), host.XenMemoryString());
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-15 03:52:12 +01:00
|
|
|
|
private void addStringEntry(PDSection s, string key, string value)
|
|
|
|
|
{
|
2015-02-18 10:50:55 +01:00
|
|
|
|
s.AddEntry(key, string.IsNullOrEmpty(value) ? Messages.NONE : value);
|
2015-02-15 03:52:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void generateDockerInfoBox()
|
|
|
|
|
{
|
|
|
|
|
VM vm = xenObject as VM;
|
|
|
|
|
if (vm == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
VM_Docker_Info info = vm.DockerInfo();
|
2015-02-15 03:52:12 +01:00
|
|
|
|
if (info == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-09-03 04:33:29 +02:00
|
|
|
|
VM_Docker_Version version = vm.DockerVersion();
|
2015-02-15 03:52:12 +01:00
|
|
|
|
if (version == null)
|
|
|
|
|
return;
|
|
|
|
|
|
CA-162989: Container Management GUI use-ability/homogeneity fixes
Implemented changes as follows (copied from ticket):
"I'd suggest the following use-ability/homogeneity fixes for the new container management tabs, if they are quick and easy:
Combine "Docker Version" and "Docker Information" on the VM-General-tab into "Container Management - Docker Status" with the following fields only:
API version
Version
Git Commit
Driver
Index Server Address
Execution Driver
IPv4 Forwarding
In the "Processes" tab, change the name from "Docker Processes" to "Container Processes"
In the "Details" tab, change the name from "Docker Detail" to "Container Details"
In the "Details" tab, drop the top level element "docker_inspect" (XML requires a single root-node, afaik the Windows form treenode does not), or alternatively open the root node by default and rename it to "Inspect Result"
In the "Details" tab, add the "Details"-headline in black on white - just like on the "Processes"-tab
Also, on the container's General tab, show Properties button disabled, instead on hiding it (to be consistent to other cases, e.g. disconnected servers)
"
Signed-off-by: Gabor Apati-Nagy <gabor.apati-nagy@citrix.com>
2015-03-05 20:10:54 +01:00
|
|
|
|
PDSection s = pdSectionDockerInfo;
|
|
|
|
|
|
2015-02-15 03:52:12 +01:00
|
|
|
|
addStringEntry(s, Messages.DOCKER_INFO_API_VERSION, version.ApiVersion);
|
|
|
|
|
addStringEntry(s, Messages.DOCKER_INFO_VERSION, version.Version);
|
|
|
|
|
addStringEntry(s, Messages.DOCKER_INFO_GIT_COMMIT, version.GitCommit);
|
CA-162989: Container Management GUI use-ability/homogeneity fixes
Implemented changes as follows (copied from ticket):
"I'd suggest the following use-ability/homogeneity fixes for the new container management tabs, if they are quick and easy:
Combine "Docker Version" and "Docker Information" on the VM-General-tab into "Container Management - Docker Status" with the following fields only:
API version
Version
Git Commit
Driver
Index Server Address
Execution Driver
IPv4 Forwarding
In the "Processes" tab, change the name from "Docker Processes" to "Container Processes"
In the "Details" tab, change the name from "Docker Detail" to "Container Details"
In the "Details" tab, drop the top level element "docker_inspect" (XML requires a single root-node, afaik the Windows form treenode does not), or alternatively open the root node by default and rename it to "Inspect Result"
In the "Details" tab, add the "Details"-headline in black on white - just like on the "Processes"-tab
Also, on the container's General tab, show Properties button disabled, instead on hiding it (to be consistent to other cases, e.g. disconnected servers)
"
Signed-off-by: Gabor Apati-Nagy <gabor.apati-nagy@citrix.com>
2015-03-05 20:10:54 +01:00
|
|
|
|
addStringEntry(s, Messages.DOCKER_INFO_DRIVER, info.Driver);
|
|
|
|
|
addStringEntry(s, Messages.DOCKER_INFO_INDEX_SERVER_ADDRESS, info.IndexServerAddress);
|
|
|
|
|
addStringEntry(s, Messages.DOCKER_INFO_EXECUTION_DRIVER, info.ExecutionDriver);
|
|
|
|
|
addStringEntry(s, Messages.DOCKER_INFO_IPV4_FORWARDING, info.IPv4Forwarding);
|
2015-02-15 03:52:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
private bool CPUsIdentical(IEnumerable<Host_cpu> cpus)
|
|
|
|
|
{
|
|
|
|
|
String cpuText = null;
|
|
|
|
|
foreach (Host_cpu cpu in cpus)
|
|
|
|
|
{
|
|
|
|
|
if (cpuText == null)
|
|
|
|
|
{
|
|
|
|
|
cpuText = Helpers.GetCPUProperties(cpu);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (Helpers.GetCPUProperties(cpu) != cpuText)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-08 14:34:59 +02:00
|
|
|
|
private string RecommendedPatchesForHost(Host host)
|
|
|
|
|
{
|
|
|
|
|
var result = new List<string>();
|
|
|
|
|
var recommendedPatches = Updates.RecommendedPatchesForHost(host);
|
|
|
|
|
|
2017-08-24 12:54:16 +02:00
|
|
|
|
if (recommendedPatches == null)
|
|
|
|
|
return String.Empty;
|
|
|
|
|
|
2016-06-08 14:34:59 +02:00
|
|
|
|
foreach (var patch in recommendedPatches)
|
|
|
|
|
result.Add(patch.Name);
|
|
|
|
|
|
|
|
|
|
return string.Join(Environment.NewLine, result.ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 14:17:58 +01:00
|
|
|
|
private string hostInstalledSuppPacks(Host host)
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
var result = host.SuppPacks().Select(suppPack => suppPack.LongDescription).ToList();
|
2015-01-28 14:17:58 +01:00
|
|
|
|
result.Sort(StringUtility.NaturalCompare);
|
|
|
|
|
return string.Join("\n", result.ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
#region VM delegates
|
|
|
|
|
|
|
|
|
|
private static string HVMBootOrder(VM vm)
|
|
|
|
|
{
|
2017-09-05 03:15:38 +02:00
|
|
|
|
var order = vm.GetBootOrder().ToUpper().Union(new[] { 'D', 'C', 'N' });
|
2013-06-24 13:41:48 +02:00
|
|
|
|
return string.Join("\n", order.Select(c => new BootDevice(c).ToString()).ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-11 19:38:27 +01:00
|
|
|
|
private static string HVMBootMode(VM vm)
|
|
|
|
|
{
|
|
|
|
|
if (vm.IsSecureBootEnabled())
|
|
|
|
|
return Messages.UEFI_SECURE_BOOT;
|
|
|
|
|
if (vm.IsUEFIEnabled())
|
|
|
|
|
return Messages.UEFI_BOOT;
|
|
|
|
|
return Messages.BIOS_BOOT;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Pool delegates
|
|
|
|
|
|
|
|
|
|
private string poolAppliedPatches()
|
|
|
|
|
{
|
2016-10-05 13:55:34 +02:00
|
|
|
|
return
|
|
|
|
|
Helpers.ElyOrGreater(xenObject.Connection)
|
2017-09-03 04:33:29 +02:00
|
|
|
|
? poolUpdateString(update => update.AppliedOnHosts().Count == xenObject.Connection.Cache.HostCount)
|
2016-10-05 13:55:34 +02:00
|
|
|
|
: poolPatchString(patch => patch.host_patches.Count == xenObject.Connection.Cache.HostCount);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string poolPartialPatches()
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
return Helpers.ElyOrGreater(xenObject.Connection)
|
|
|
|
|
? poolUpdateString(update =>
|
|
|
|
|
{
|
|
|
|
|
var appliedOnHosts = update.AppliedOnHosts();
|
|
|
|
|
return appliedOnHosts.Count > 0 && appliedOnHosts.Count != xenObject.Connection.Cache.HostCount;
|
|
|
|
|
})
|
2016-10-05 13:55:34 +02:00
|
|
|
|
: poolPatchString(patch => patch.host_patches.Count > 0 && patch.host_patches.Count != xenObject.Connection.Cache.HostCount);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string poolPatchString(Predicate<Pool_patch> predicate)
|
|
|
|
|
{
|
|
|
|
|
Pool_patch[] patches = xenObject.Connection.Cache.Pool_patches;
|
|
|
|
|
|
|
|
|
|
List<String> output = new List<String>();
|
|
|
|
|
|
|
|
|
|
foreach (Pool_patch patch in patches)
|
|
|
|
|
if (predicate(patch))
|
|
|
|
|
output.Add(patch.name_label);
|
|
|
|
|
|
|
|
|
|
output.Sort(StringUtility.NaturalCompare);
|
|
|
|
|
|
2019-05-21 12:58:26 +02:00
|
|
|
|
return string.Join(Environment.NewLine, output);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-05 13:55:34 +02:00
|
|
|
|
private string poolUpdateString(Predicate<Pool_update> predicate)
|
|
|
|
|
{
|
|
|
|
|
Pool_update[] updates = xenObject.Connection.Cache.Pool_updates;
|
|
|
|
|
|
|
|
|
|
List<String> output = new List<String>();
|
|
|
|
|
|
|
|
|
|
foreach (var update in updates)
|
|
|
|
|
if (predicate(update))
|
2017-08-08 13:25:18 +02:00
|
|
|
|
output.Add(Helpers.UpdatesFriendlyNameAndVersion(update));
|
2016-10-05 13:55:34 +02:00
|
|
|
|
|
|
|
|
|
output.Sort(StringUtility.NaturalCompare);
|
|
|
|
|
|
2019-05-21 12:58:26 +02:00
|
|
|
|
return string.Join(Environment.NewLine, output);
|
2016-10-05 13:55:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks for reboot warnings on all hosts in the pool and returns them as a list
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="pool"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private List<KeyValuePair<String, String>> CheckPoolUpdate(Pool pool)
|
|
|
|
|
{
|
|
|
|
|
List<KeyValuePair<String, String>> warnings = new List<KeyValuePair<string, string>>();
|
2016-08-17 11:45:11 +02:00
|
|
|
|
|
|
|
|
|
if (Helpers.ElyOrGreater(pool.Connection))
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2016-10-13 15:59:20 +02:00
|
|
|
|
// As of Ely we use CheckHostUpdatesRequiringReboot to get reboot messages for a host
|
2016-08-17 11:45:11 +02:00
|
|
|
|
foreach (Host host in xenObject.Connection.Cache.Hosts)
|
|
|
|
|
{
|
2016-10-12 15:48:17 +02:00
|
|
|
|
warnings.AddRange(CheckHostUpdatesRequiringReboot(host));
|
2016-08-17 11:45:11 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Earlier versions use the old server updates method
|
|
|
|
|
foreach (Host host in xenObject.Connection.Cache.Hosts)
|
|
|
|
|
{
|
|
|
|
|
warnings.AddRange(CheckServerUpdates(host));
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
return warnings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks the server has been restarted after any patches that require a restart were applied and returns a list of reboot warnings
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="host"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private List<KeyValuePair<String, String>> CheckServerUpdates(Host host)
|
|
|
|
|
{
|
|
|
|
|
List<Pool_patch> patches = host.AppliedPatches();
|
|
|
|
|
List<KeyValuePair<String, String>> warnings = new List<KeyValuePair<String, String>>();
|
2017-09-03 04:33:29 +02:00
|
|
|
|
double bootTime = host.BootTime();
|
|
|
|
|
double agentStart = host.AgentStartTime();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
if (bootTime == 0.0 || agentStart == 0.0)
|
|
|
|
|
return warnings;
|
|
|
|
|
|
|
|
|
|
foreach (Pool_patch patch in patches)
|
|
|
|
|
{
|
|
|
|
|
double applyTime = Util.ToUnixTime(patch.AppliedOn(host));
|
|
|
|
|
|
2016-10-27 15:27:20 +02:00
|
|
|
|
if (patch.after_apply_guidance.Contains(after_apply_guidance.restartHost) && applyTime > bootTime
|
|
|
|
|
|| patch.after_apply_guidance.Contains(after_apply_guidance.restartXAPI) && applyTime > agentStart)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2016-08-17 11:45:11 +02:00
|
|
|
|
warnings.Add(CreateWarningRow(host, patch));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return warnings;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-17 11:45:11 +02:00
|
|
|
|
/// <summary>
|
2016-10-13 15:59:20 +02:00
|
|
|
|
/// Creates a list of warnings for updates that require the host to be rebooted
|
2016-08-17 11:45:11 +02:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="host"></param>
|
|
|
|
|
/// <returns></returns>
|
2016-10-12 15:48:17 +02:00
|
|
|
|
private List<KeyValuePair<String, String>> CheckHostUpdatesRequiringReboot(Host host)
|
2016-08-17 11:45:11 +02:00
|
|
|
|
{
|
|
|
|
|
var warnings = new List<KeyValuePair<String, String>>();
|
2016-10-27 15:27:20 +02:00
|
|
|
|
|
|
|
|
|
// Updates that require host restart
|
2016-10-12 15:48:17 +02:00
|
|
|
|
var updateRefs = host.updates_requiring_reboot;
|
|
|
|
|
foreach (var updateRef in updateRefs)
|
2016-08-17 11:45:11 +02:00
|
|
|
|
{
|
2016-10-12 15:48:17 +02:00
|
|
|
|
var update = host.Connection.Resolve(updateRef);
|
2018-05-17 12:25:07 +02:00
|
|
|
|
if (update != null)
|
|
|
|
|
warnings.Add(CreateWarningRow(host, update));
|
2016-08-17 11:45:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-27 15:27:20 +02:00
|
|
|
|
// For Toolstack restart, legacy code has to be used to determine this - pool_patches are still populated for backward compatibility
|
|
|
|
|
List<Pool_patch> patches = host.AppliedPatches();
|
2017-09-03 04:33:29 +02:00
|
|
|
|
double bootTime = host.BootTime();
|
|
|
|
|
double agentStart = host.AgentStartTime();
|
2016-10-27 15:27:20 +02:00
|
|
|
|
|
|
|
|
|
if (bootTime == 0.0 || agentStart == 0.0)
|
|
|
|
|
return warnings;
|
|
|
|
|
|
|
|
|
|
foreach (Pool_patch patch in patches)
|
|
|
|
|
{
|
|
|
|
|
double applyTime = Util.ToUnixTime(patch.AppliedOn(host));
|
|
|
|
|
|
|
|
|
|
if (patch.after_apply_guidance.Contains(after_apply_guidance.restartXAPI)
|
|
|
|
|
&& applyTime > agentStart)
|
|
|
|
|
{
|
|
|
|
|
warnings.Add(CreateWarningRow(host, patch));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-17 11:45:11 +02:00
|
|
|
|
return warnings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private KeyValuePair<string, string> CreateWarningRow(Host host, Pool_patch patch)
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
var key = String.Format(Messages.GENERAL_PANEL_UPDATE_KEY, patch.Name(), host.Name());
|
2016-10-27 15:27:20 +02:00
|
|
|
|
string value = string.Empty;
|
2016-08-17 11:45:11 +02:00
|
|
|
|
|
2016-10-27 15:27:20 +02:00
|
|
|
|
if (patch.after_apply_guidance.Contains(after_apply_guidance.restartHost))
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
value = string.Format(Messages.GENERAL_PANEL_UPDATE_REBOOT_WARNING, host.Name(), patch.Name());
|
2016-10-27 15:27:20 +02:00
|
|
|
|
}
|
|
|
|
|
else if (patch.after_apply_guidance.Contains(after_apply_guidance.restartXAPI))
|
|
|
|
|
{
|
2017-09-03 04:33:29 +02:00
|
|
|
|
value = string.Format(Messages.GENERAL_PANEL_UPDATE_RESTART_TOOLSTACK_WARNING, host.Name(), patch.Name());
|
2016-10-27 15:27:20 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-17 11:45:11 +02:00
|
|
|
|
return new KeyValuePair<string, string>(key, value);
|
|
|
|
|
}
|
2016-10-12 15:48:17 +02:00
|
|
|
|
|
|
|
|
|
private KeyValuePair<string, string> CreateWarningRow(Host host, Pool_update update)
|
|
|
|
|
{
|
2017-08-08 13:25:18 +02:00
|
|
|
|
var key = String.Format(Messages.GENERAL_PANEL_UPDATE_KEY, Helpers.UpdatesFriendlyName(update.Name()), host.Name());
|
|
|
|
|
var value = string.Format(Messages.GENERAL_PANEL_UPDATE_REBOOT_WARNING, host.Name(), Helpers.UpdatesFriendlyName(update.Name()));
|
2016-10-12 15:48:17 +02:00
|
|
|
|
|
|
|
|
|
return new KeyValuePair<string, string>(key, value);
|
|
|
|
|
}
|
2016-08-17 11:45:11 +02:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private static string FriendlyName(string propertyName)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
return FriendlyNameManager.GetFriendlyName(string.Format("Label-{0}", propertyName)) ?? propertyName;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
|
|
|
|
|
#region Control Event Handlers
|
|
|
|
|
|
|
|
|
|
private void s_ContentChangedSelection(PDSection s)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
ScrollToSelectionIfNeeded(s);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void s_ContentReceivedFocus(PDSection s)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
ScrollToSelectionIfNeeded(s);
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void s_ExpandedChanged(PDSection pdSection)
|
|
|
|
|
{
|
|
|
|
|
if (xenObject != null)
|
|
|
|
|
_expandedSections[xenObject.GetType()] = sections.Where(s => s.Parent.Visible && s.IsExpanded).ToList();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
linkLabelExpand.Enabled = sections.Any(s => s.Parent.Visible && !s.IsExpanded);
|
|
|
|
|
linkLabelCollapse.Enabled = sections.Any(s => s.Parent.Visible && s.IsExpanded);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void linkLabelExpand_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
ToggleExpandedState(s => true);
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void linkLabelCollapse_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
ToggleExpandedState(s => false);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
private void buttonProperties_Click(object sender, EventArgs e)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
new PropertiesCommand(Program.MainWindow, xenObject).Execute();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
2016-02-03 11:12:05 +01:00
|
|
|
|
|
|
|
|
|
private void buttonViewConsole_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
//Set command 'docker attach' to attach to the container.
|
|
|
|
|
StartPutty("env docker attach --sig-proxy=false");
|
2016-02-03 11:12:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void buttonViewLog_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
//Set command 'docker logs' to retrieve the logs of the container.
|
|
|
|
|
StartPutty( "env docker logs --tail=50 --follow --timestamps");
|
2016-02-06 08:18:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-10 15:13:11 +02:00
|
|
|
|
private void panel2_Paint(object sender, PaintEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
//Force scrollbar to be repainted to avoid occasional pixel glitch.
|
|
|
|
|
panel2.AutoScroll = sections.Sum(s => s.Parent?.Height ?? s.Height) > panel2.ClientRectangle.Height;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 16:22:45 +01:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
private void StartPutty(string dockerCmd)
|
2016-02-06 08:18:07 +01:00
|
|
|
|
{
|
2020-03-13 16:22:45 +01:00
|
|
|
|
if (!(xenObject is DockerContainer dockerContainer))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
string ipAddr = dockerContainer.Parent.IPAddressForSSH();
|
|
|
|
|
string command = $"{dockerCmd} {dockerContainer.uuid}";
|
|
|
|
|
|
2016-02-06 08:18:07 +01:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//Write docker command to a temp file.
|
2016-02-15 09:47:49 +01:00
|
|
|
|
string cmdFile = Path.Combine(Path.GetTempPath(), "ContainerManagementCommand.txt");
|
2016-02-06 08:18:07 +01:00
|
|
|
|
File.WriteAllText(cmdFile, command);
|
2016-02-03 11:12:05 +01:00
|
|
|
|
|
2016-02-06 08:18:07 +01:00
|
|
|
|
//Invoke Putty, SSH to VM and execute docker command.
|
|
|
|
|
var puttyPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "putty.exe");
|
2016-02-15 09:47:49 +01:00
|
|
|
|
string args = "-m " + cmdFile + " -t " + ipAddr;
|
|
|
|
|
|
|
|
|
|
//Specify the key for SSH connection.
|
|
|
|
|
var keyFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "ContainerManagement.ppk");
|
|
|
|
|
if (File.Exists(keyFile))
|
|
|
|
|
{
|
|
|
|
|
args = args + " -i " + keyFile;
|
|
|
|
|
}
|
|
|
|
|
var startInfo = new ProcessStartInfo(puttyPath, args);
|
|
|
|
|
|
2016-02-06 08:18:07 +01:00
|
|
|
|
Process.Start(startInfo);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
log.Error("Error starting PuTTY.", ex);
|
2020-04-22 15:47:03 +02:00
|
|
|
|
using (var dlg = new ErrorDialog(Messages.ERROR_PUTTY_LAUNCHING))
|
2016-06-20 11:49:12 +02:00
|
|
|
|
dlg.ShowDialog(Parent);
|
2016-02-06 08:18:07 +01:00
|
|
|
|
}
|
2016-02-03 11:12:05 +01:00
|
|
|
|
}
|
2020-03-13 16:22:45 +01:00
|
|
|
|
|
|
|
|
|
private void ToggleExpandedState(Func<PDSection, bool> expand)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
panel2.SuspendLayout();
|
|
|
|
|
|
|
|
|
|
foreach (PDSection s in sections)
|
|
|
|
|
{
|
|
|
|
|
if (!s.Parent.Visible)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
s.DisableFocusEvent = true;
|
|
|
|
|
|
|
|
|
|
if (expand(s))
|
|
|
|
|
s.Expand();
|
|
|
|
|
else
|
|
|
|
|
s.Contract();
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
s.DisableFocusEvent = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
panel2.ResumeLayout();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-10 11:22:51 +01:00
|
|
|
|
|
|
|
|
|
private void SetupDeprecationBanner()
|
|
|
|
|
{
|
2021-05-21 16:13:45 +02:00
|
|
|
|
if (Helpers.PostStockholm(xenObject.Connection))
|
2021-03-10 11:22:51 +01:00
|
|
|
|
{
|
|
|
|
|
Banner.Visible = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Banner.BannerType = DeprecationBanner.Type.Warning;
|
|
|
|
|
Banner.WarningMessage = string.Format(Messages.WARNING_PRE_CLOUD_VERSION_CONNECTION, BrandManager.BrandConsole, BrandManager.ProductBrand, BrandManager.ProductVersion82, BrandManager.LegacyConsole);
|
|
|
|
|
Banner.LinkText = Messages.PATCHING_WIZARD_WEBPAGE_CELL;
|
|
|
|
|
Banner.LinkUri = new Uri(InvisibleMessages.OUT_OF_DATE_WEBSITE);
|
|
|
|
|
Banner.Visible = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|