mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-12-23 00:46:03 +01:00
b66f11a1e8
- removal of the SystemStatusAction launching the individual SingleHostStatusActions, because the connection was set incorrectly to the last one of the selected connections and, if an error occurred to that connection, the data collection for all of them failed. - proper handling of HTTP.CancelledExceptions. - replacement of the FlickerFreeListBox by the more versatile DataGridViewEx. - corrections to reporting progress for individual hosts as well as page totals. - made collection of client side data more obvious. Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
607 lines
20 KiB
C#
607 lines
20 KiB
C#
/* Copyright (c) Citrix Systems, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms,
|
|
* with or without modification, are permitted provided
|
|
* that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above
|
|
* copyright notice, this list of conditions and the
|
|
* following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the
|
|
* following disclaimer in the documentation and/or other
|
|
* materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows.Forms;
|
|
using System.Xml;
|
|
|
|
using XenAdmin.Controls;
|
|
using XenAdmin.Core;
|
|
using XenAPI;
|
|
using XenAdmin.Actions;
|
|
using XenAdmin.Dialogs;
|
|
using XenCenterLib;
|
|
|
|
|
|
namespace XenAdmin.Wizards.BugToolWizardFiles
|
|
{
|
|
public partial class BugToolPageSelectCapabilities : XenTabPage
|
|
{
|
|
#region Private fields
|
|
private List<Host> _hostList = new List<Host>();
|
|
private List<Capability> _capabilities = new List<Capability>();
|
|
|
|
private Dictionary<Host, List<Capability>> hostCapabilities;
|
|
private List<GetSystemStatusCapabilities> actions;
|
|
private ActionProgressDialog dialog;
|
|
private bool cancelled;
|
|
#endregion
|
|
|
|
public BugToolPageSelectCapabilities()
|
|
{
|
|
InitializeComponent();
|
|
this.linkLabel1.Visible = !XenAdmin.Core.HiddenFeatures.LinkLabelHidden;
|
|
}
|
|
|
|
public override string Text{get { return Messages.BUGTOOL_PAGE_CAPABILITIES_TEXT; }}
|
|
|
|
public override string PageTitle { get { return Messages.BUGTOOL_PAGE_CAPABILITIES_PAGETITLE; } }
|
|
|
|
public override string HelpID { get { return "SelectReportContents"; } }
|
|
|
|
public override bool EnableNext()
|
|
{
|
|
return wizardCheckAnyChecked();
|
|
}
|
|
|
|
protected override void PageLoadedCore(PageLoadedDirection direction)
|
|
{
|
|
if (direction == PageLoadedDirection.Forward)
|
|
{
|
|
ClearButton.Enabled = wizardCheckAnyChecked();
|
|
SelectButton.Enabled = wizardCheckAnyUnchecked();
|
|
}
|
|
}
|
|
|
|
private bool wizardCheckAnyChecked()
|
|
{
|
|
foreach (DataGridViewRow row in dataGridViewItems.Rows)
|
|
{
|
|
var capRow = row as CapabilityRow;
|
|
if (capRow != null && capRow.Capability.Checked)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool wizardCheckAnyUnchecked()
|
|
{
|
|
foreach (DataGridViewRow row in dataGridViewItems.Rows)
|
|
{
|
|
var capRow = row as CapabilityRow;
|
|
if (capRow != null && !capRow.Capability.Checked)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="HostList"></param>
|
|
/// <returns>If success of not - false with stop moving to next page</returns>
|
|
public bool GetCommonCapabilities(List<Host> HostList)
|
|
{
|
|
if (!cancelled && Helpers.ListsContentsEqual<Host>(_hostList, HostList))
|
|
return true;
|
|
|
|
_hostList = HostList;
|
|
dataGridViewItems.Rows.Clear();
|
|
|
|
if (dialog != null && dialog.Visible)
|
|
dialog.Close();
|
|
|
|
hostCapabilities = new Dictionary<Host, List<Capability>>();
|
|
actions = new List<GetSystemStatusCapabilities>();
|
|
cancelled = false;
|
|
dialog = new ActionProgressDialog(Messages.SERVER_STATUS_REPORT_GET_CAPABILITIES);
|
|
dialog.ShowCancel = true;
|
|
dialog.CancelClicked += new EventHandler(dialog_CancelClicked);
|
|
|
|
foreach (Host host in _hostList)
|
|
{
|
|
GetSystemStatusCapabilities action = new GetSystemStatusCapabilities(host);
|
|
actions.Add(action);
|
|
action.Completed += Common_action_Completed;
|
|
action.RunAsync();
|
|
}
|
|
|
|
if (_hostList.Count > 0)
|
|
dialog.ShowDialog(this);
|
|
|
|
return !cancelled;
|
|
}
|
|
|
|
private void dialog_CancelClicked(object sender, EventArgs e)
|
|
{
|
|
dialog.Close();
|
|
cancelled = true;
|
|
|
|
// Need to unhook events on current actions, to stop them
|
|
// interfeering when they return in 20mins
|
|
foreach (GetSystemStatusCapabilities action in actions)
|
|
action.Completed -= Common_action_Completed;
|
|
}
|
|
|
|
private void Common_action_Completed(ActionBase sender)
|
|
{
|
|
Program.Invoke(this, delegate()
|
|
{
|
|
if (cancelled)
|
|
return;
|
|
|
|
GetSystemStatusCapabilities caps = sender as GetSystemStatusCapabilities;
|
|
if (caps == null)
|
|
return;
|
|
|
|
hostCapabilities[caps.Host] =
|
|
caps.Succeeded ? parseXMLToList(caps) : null;
|
|
|
|
if (hostCapabilities.Count >= _hostList.Count)
|
|
{
|
|
dialog.Close();
|
|
CombineCapabilitiesLists();
|
|
}
|
|
});
|
|
}
|
|
|
|
private List<Capability> parseXMLToList(Actions.GetSystemStatusCapabilities action)
|
|
{
|
|
List<Capability> capabilities = new List<Capability>();
|
|
|
|
XmlDocument doc = new XmlDocument();
|
|
doc.LoadXml(action.Result);
|
|
foreach (XmlNode node in doc.GetElementsByTagName("capability"))
|
|
{
|
|
Capability c = new Capability();
|
|
foreach (XmlAttribute a in node.Attributes)
|
|
{
|
|
string name = a.Name;
|
|
string value = a.Value;
|
|
|
|
if (name == "content-type")
|
|
c.ContentType = value == "text/plain" ? ContentType.text_plain : ContentType.application_data;
|
|
else if (name == "default-checked")
|
|
c.DefaultChecked = value == "yes" ? true : false;
|
|
else if (name == "key")
|
|
c.Key = value;
|
|
else if (name == "max-size")
|
|
c.MaxSize = Int64.Parse(value);
|
|
else if (name == "min-size")
|
|
c.MinSize = Int64.Parse(value);
|
|
else if (name == "pii")
|
|
c.PII = value == "yes" ? PrivateInformationIncluded.yes :
|
|
value == "no" ? PrivateInformationIncluded.no :
|
|
value == "maybe" ? PrivateInformationIncluded.maybe : PrivateInformationIncluded.customized;
|
|
}
|
|
|
|
capabilities.Add(c);
|
|
}
|
|
|
|
return capabilities;
|
|
}
|
|
|
|
private void CombineCapabilitiesLists()
|
|
{
|
|
List<Capability> combination = null;
|
|
|
|
foreach (List<Capability> capabilities in hostCapabilities.Values)
|
|
{
|
|
if (capabilities == null)
|
|
continue;
|
|
|
|
if (combination == null)
|
|
{
|
|
combination = capabilities;
|
|
continue;
|
|
}
|
|
|
|
combination = Helpers.ListsCommonItems<Capability>(combination, capabilities);
|
|
}
|
|
|
|
if (combination == null || combination.Count <= 0)
|
|
{
|
|
using (var dlg = new ThreeButtonDialog(
|
|
new ThreeButtonDialog.Details(
|
|
SystemIcons.Error,
|
|
Messages.SERVER_STATUS_REPORT_CAPABILITIES_FAILED,
|
|
Messages.SERVER_STATUS_REPORT)))
|
|
{
|
|
dlg.ShowDialog(this);
|
|
}
|
|
|
|
cancelled = true;
|
|
return;
|
|
}
|
|
|
|
_capabilities = combination;
|
|
|
|
_capabilities.Add(GetClientCapability());
|
|
|
|
Sort_capabilities();
|
|
|
|
buildList();
|
|
}
|
|
|
|
private Capability GetClientCapability()
|
|
{
|
|
Capability clientCap = new Capability();
|
|
clientCap.ContentType = ContentType.text_plain;
|
|
clientCap.DefaultChecked = true;
|
|
clientCap.Key = "client-logs";
|
|
clientCap.MaxSize = getLogSize();
|
|
clientCap.MinSize = clientCap.MaxSize;
|
|
clientCap.PII = PrivateInformationIncluded.yes;
|
|
|
|
return clientCap;
|
|
}
|
|
|
|
private void Sort_capabilities()
|
|
{
|
|
_capabilities.Sort(new Comparison<Capability>(delegate(Capability obj1, Capability obj2)
|
|
{
|
|
int piicompare = obj1.PII.CompareTo(obj2.PII);
|
|
if (piicompare == 0)
|
|
return StringUtility.NaturalCompare(obj1.ToString(), obj2.ToString());
|
|
else
|
|
return piicompare;
|
|
}));
|
|
}
|
|
|
|
private void OnCheckedCapabilitiesChanged()
|
|
{
|
|
string totalSize;
|
|
CalculateTotalSize(out totalSize);
|
|
TotalSizeValue.Text = totalSize;
|
|
ClearButton.Enabled = wizardCheckAnyChecked();
|
|
SelectButton.Enabled = wizardCheckAnyUnchecked();
|
|
OnPageUpdated();
|
|
}
|
|
|
|
private void buildList()
|
|
{
|
|
try
|
|
{
|
|
dataGridViewItems.SuspendLayout();
|
|
dataGridViewItems.Rows.Clear();
|
|
|
|
var list = new List<DataGridViewRow>();
|
|
foreach (Capability c in _capabilities)
|
|
list.Add(new CapabilityRow(c));
|
|
|
|
dataGridViewItems.Rows.AddRange(list.ToArray());
|
|
}
|
|
finally
|
|
{
|
|
dataGridViewItems.ResumeLayout();
|
|
}
|
|
|
|
OnCheckedCapabilitiesChanged();
|
|
}
|
|
|
|
private long getLogSize()
|
|
{
|
|
String path = Program.GetLogFile_();
|
|
if (path != null)
|
|
{
|
|
// Size of XenCenter.log
|
|
FileInfo logFileInfo = new FileInfo(path);
|
|
long total = logFileInfo.Length;
|
|
|
|
// Add size of any XenCenter.log.x
|
|
DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(path));
|
|
Regex regex = new Regex(Regex.Escape(Path.GetFileName(path)) + @"\.\d+");
|
|
foreach (FileInfo file in di.GetFiles())
|
|
{
|
|
if (regex.IsMatch(file.Name))
|
|
total += file.Length;
|
|
}
|
|
return total;
|
|
}
|
|
else
|
|
{
|
|
return 50 * Util.BINARY_MEGA;
|
|
}
|
|
}
|
|
|
|
private void CalculateTotalSize(out string totalSize)
|
|
{
|
|
var sizeMinList = new List<long>();
|
|
var sizeMaxList = new List<long>();
|
|
|
|
foreach (var row in dataGridViewItems.Rows)
|
|
{
|
|
var capRow = row as CapabilityRow;
|
|
if (capRow != null && capRow.Capability.Checked)
|
|
{
|
|
var c = capRow.Capability;
|
|
int m = c.Key == "client-logs" ? 1 : _hostList.Count;
|
|
|
|
sizeMinList.Add(c.MinSize * m);
|
|
sizeMaxList.Add(c.MaxSize * m);
|
|
}
|
|
}
|
|
totalSize = Helpers.StringFromMaxMinSizeList(sizeMinList, sizeMaxList);
|
|
}
|
|
|
|
public List<Capability> Capabilities
|
|
{
|
|
get
|
|
{
|
|
return (from DataGridViewRow row in dataGridViewItems.Rows
|
|
let capRow = row as CapabilityRow
|
|
where capRow != null && capRow.Capability.Checked
|
|
select capRow.Capability).ToList();
|
|
}
|
|
}
|
|
|
|
#region Control event handlers
|
|
|
|
private void dataGridViewItems_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
|
|
{
|
|
var row1 = dataGridViewItems.Rows[e.RowIndex1] as CapabilityRow;
|
|
var row2 = dataGridViewItems.Rows[e.RowIndex2] as CapabilityRow;
|
|
|
|
if (row1 != null && row2 != null && e.Column.Index == columnImage.Index)
|
|
{
|
|
e.SortResult = row1.Capability.PII.CompareTo(row2.Capability.PII);
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
|
|
private void dataGridViewItems_SelectionChanged(object sender, EventArgs e)
|
|
{
|
|
if (dataGridViewItems.SelectedRows.Count > 0)
|
|
{
|
|
var row = dataGridViewItems.SelectedRows[0] as CapabilityRow;
|
|
if (row == null)
|
|
return;
|
|
|
|
DescriptionValue.Text = row.Capability.Description;
|
|
SizeValue.Text = row.Capability.EstimatedSize;
|
|
}
|
|
}
|
|
|
|
private void dataGridViewItems_CellClick(object sender, DataGridViewCellEventArgs e)
|
|
{
|
|
if (e.ColumnIndex != columnCheck.Index)
|
|
return;
|
|
if (e.RowIndex < 0 || e.RowIndex >= dataGridViewItems.RowCount)
|
|
return;
|
|
|
|
var row = dataGridViewItems.Rows[e.RowIndex] as CapabilityRow;
|
|
if (row == null)
|
|
return;
|
|
|
|
row.Capability.Checked = !row.Capability.Checked;
|
|
row.Update();
|
|
OnCheckedCapabilitiesChanged();
|
|
}
|
|
|
|
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
System.Diagnostics.Process.Start(InvisibleMessages.PRIVACY);
|
|
}
|
|
catch
|
|
{
|
|
using (var dlg = new ThreeButtonDialog(
|
|
new ThreeButtonDialog.Details(
|
|
SystemIcons.Error,
|
|
Messages.HOMEPAGE_ERROR_MESSAGE,
|
|
Messages.XENCENTER)))
|
|
{
|
|
dlg.ShowDialog(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SelectButton_Click(object sender, EventArgs e)
|
|
{
|
|
foreach (DataGridViewRow row in dataGridViewItems.Rows)
|
|
{
|
|
var capRow = row as CapabilityRow;
|
|
if (capRow != null && !capRow.Capability.Checked)
|
|
{
|
|
capRow.Capability.Checked = true;
|
|
capRow.Update();
|
|
}
|
|
}
|
|
OnCheckedCapabilitiesChanged();
|
|
}
|
|
|
|
private void ClearButton_Click(object sender, EventArgs e)
|
|
{
|
|
foreach (DataGridViewRow row in dataGridViewItems.Rows)
|
|
{
|
|
var capRow = row as CapabilityRow;
|
|
if (capRow != null && capRow.Capability.Checked)
|
|
{
|
|
capRow.Capability.Checked = false;
|
|
capRow.Update();
|
|
}
|
|
}
|
|
OnCheckedCapabilitiesChanged();
|
|
}
|
|
|
|
#endregion
|
|
|
|
private class CapabilityRow : DataGridViewRow
|
|
{
|
|
public readonly Capability Capability;
|
|
|
|
private readonly DataGridViewCheckBoxCell cellCheck = new DataGridViewCheckBoxCell();
|
|
private readonly DataGridViewTextBoxCell cellItem = new DataGridViewTextBoxCell();
|
|
private readonly DataGridViewImageCell cellImage = new DataGridViewImageCell();
|
|
|
|
public CapabilityRow(Capability capability)
|
|
{
|
|
Capability = capability;
|
|
Cells.AddRange(cellCheck, cellItem, cellImage);
|
|
Update();
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
cellCheck.Value = Capability.Checked;
|
|
cellItem.Value = Capability.Name;
|
|
|
|
switch(Capability.PII)
|
|
{
|
|
case PrivateInformationIncluded.maybe:
|
|
cellImage.Value = Properties.Resources.alert2_16;
|
|
break;
|
|
case PrivateInformationIncluded.customized:
|
|
cellImage.Value = Properties.Resources.alert3_16;
|
|
break;
|
|
case PrivateInformationIncluded.no:
|
|
cellImage.Value = Properties.Resources.alert4_16;
|
|
break;
|
|
case PrivateInformationIncluded.yes:
|
|
default:
|
|
cellImage.Value = Properties.Resources.alert1_16;
|
|
break;
|
|
}
|
|
|
|
cellImage.ToolTipText = Capability.PiiText;
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum ContentType { text_plain, application_data };
|
|
|
|
public enum PrivateInformationIncluded { yes, maybe, customized, no};
|
|
|
|
public class Capability : IComparable<Capability>, IEquatable<Capability>
|
|
{
|
|
public ContentType ContentType;
|
|
bool _defaultChecked;
|
|
public long MaxSize;
|
|
public long MinSize;
|
|
public PrivateInformationIncluded PII;
|
|
private string _key;
|
|
private string _name;
|
|
private string _description;
|
|
|
|
public bool Checked;
|
|
|
|
public bool DefaultChecked
|
|
{
|
|
get
|
|
{
|
|
return _defaultChecked;
|
|
}
|
|
set
|
|
{
|
|
_defaultChecked = value;
|
|
Checked = value;
|
|
}
|
|
}
|
|
|
|
public string PiiText
|
|
{
|
|
get
|
|
{
|
|
switch (PII)
|
|
{
|
|
case PrivateInformationIncluded.yes:
|
|
return Messages.PII_YES;
|
|
case PrivateInformationIncluded.maybe:
|
|
return Messages.PII_MAYBE;
|
|
case PrivateInformationIncluded.customized:
|
|
return Messages.PII_CUSTOMISED;
|
|
case PrivateInformationIncluded.no:
|
|
default:
|
|
return Messages.PII_NO;
|
|
}
|
|
}
|
|
}
|
|
|
|
public string Key
|
|
{
|
|
get
|
|
{
|
|
return _key;
|
|
}
|
|
set
|
|
{
|
|
_key = value;
|
|
|
|
_name = Core.PropertyManager.GetFriendlyName(string.Format("Label-host.system_status-{0}", _key));
|
|
|
|
if (string.IsNullOrEmpty(_name))
|
|
_name = _key;
|
|
|
|
_description = Core.PropertyManager.GetFriendlyName(string.Format("Description-host.system_status-{0}", _key));
|
|
}
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get { return _name; }
|
|
}
|
|
|
|
public string Description
|
|
{
|
|
get { return _description; }
|
|
}
|
|
|
|
public string EstimatedSize
|
|
{
|
|
get
|
|
{
|
|
return Helpers.StringFromMaxMinSize(MinSize, MaxSize);
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return _name;
|
|
}
|
|
|
|
public int CompareTo(Capability other)
|
|
{
|
|
return StringUtility.NaturalCompare(this.Key, other.Key);
|
|
}
|
|
|
|
public bool Equals(Capability other)
|
|
{
|
|
return this.Key.Equals(other.Key);
|
|
}
|
|
}
|
|
}
|