xenadmin/XenAdmin/Wizards/BugToolWizardFiles/BugToolPageRetrieveData.cs

468 lines
16 KiB
C#
Raw Normal View History

/* 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.Windows.Forms;
using XenAdmin.Controls;
using XenAdmin.Dialogs;
using XenAPI;
using XenAdmin.Actions;
using XenAdmin.Controls.DataGridViewEx;
namespace XenAdmin.Wizards.BugToolWizardFiles
{
public partial class BugToolPageRetrieveData : XenTabPage
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public BugToolPageRetrieveData()
{
InitializeComponent();
}
#region XenTabPage overrides
public override string Text { get { return Messages.BUGTOOL_PAGE_RETRIEVEDATA_TEXT; } }
public override string PageTitle { get { return Messages.BUGTOOL_PAGE_RETRIEVEDATA_PAGE_TITLE; } }
public override string HelpID { get { return "CompileReport"; } }
public override bool EnableNext()
{
var allCompleted = AllActionsCompleted(out bool successExists, out _);
return allCompleted && successExists;
}
protected override void PageLoadedCore(PageLoadedDirection direction)
{
if (direction == PageLoadedDirection.Forward)
RunActions();
}
protected override void PageLeaveCore(PageLoadedDirection direction, ref bool cancel)
{
if (direction == PageLoadedDirection.Forward)
return;
CancelActions(ref cancel);
}
public override void PageCancelled(ref bool cancel)
{
CancelActions(ref cancel);
}
#endregion
#region Properties
public List<Host> SelectedHosts { private get; set; }
public List<Capability> CapabilityList { private get; set; }
public string OutputFolder { get; private set; }
private bool AllActionsCompleted(out bool successExists, out bool failureExists)
{
successExists = false;
failureExists = false;
foreach (var row in dataGridViewEx1.Rows)
{
var srRow = (StatusReportRow)row;
if (!srRow.IsCompleted)
return false;
if (srRow.IsSuccessful)
successExists = true;
else
failureExists = true;
}
return true;
}
#endregion
private void CancelActions(ref bool cancel)
{
var allCompleted = AllActionsCompleted(out _, out _);
if (allCompleted)
return;
using (var dlog = new ThreeButtonDialog(
new ThreeButtonDialog.Details(SystemIcons.Warning, Messages.BUGTOOL_PAGE_RETRIEVEDATA_CONFIRM_CANCEL, Messages.BUGTOOL_PAGE_RETRIEVEDATA_PAGE_TITLE),
ThreeButtonDialog.ButtonYes,
ThreeButtonDialog.ButtonNo))
{
if (dlog.ShowDialog(this) != DialogResult.Yes)
{
cancel = true;
return;
}
}
foreach (var r in dataGridViewEx1.Rows)
{
if (r is StatusReportRow row)
{
row.DeRegisterEvents();
DeRegisterRowEvents(row);
row.CancelAction();
}
}
}
private void RunActions()
{
try
{
labelError.Text = "";
progressBar1.Value = 0;
dataGridViewEx1.SuspendLayout();
dataGridViewEx1.Rows.Clear();
var capabilityKeys = new List<string>();
long size = 0;
foreach (Capability c in CapabilityList)
{
if (c.Key != "client-logs")
size += c.MaxSize;
capabilityKeys.Add(c.Key);
}
var rowList = new List<DataGridViewRow>();
var includeClientLogs = capabilityKeys.Contains("client-logs");
if (includeClientLogs || SelectedHosts.Count > 0)
rowList.Add(new ClientSideDataRow(SelectedHosts, includeClientLogs));
foreach (Host host in SelectedHosts)
rowList.Add(new HostStatusRow(host, size, capabilityKeys));
dataGridViewEx1.Rows.AddRange(rowList.ToArray());
}
finally
{
dataGridViewEx1.ResumeLayout();
}
OutputFolder = CreateOutputFolder();
string timeString = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss");
foreach (var r in dataGridViewEx1.Rows)
{
var row = (StatusReportRow)r;
RegisterRowEvents(row);
row.RunAction(OutputFolder, timeString);
}
OnPageUpdated();
}
private void Row_RowStatusChanged(StatusReportRow row)
{
UpdateTotalPercentComplete();
OnPageUpdated();
}
private void Row_RowStatusCompleted(StatusReportRow row)
{
DeRegisterRowEvents(row);
UpdateTotalPercentComplete();
var allCompleted = AllActionsCompleted(out bool successExists, out bool failureExists);
if (allCompleted)
{
if (!successExists)
labelError.Text = Messages.ACTION_SYSTEM_STATUS_FAILED;
else if (!failureExists)
labelError.Text = Messages.ACTION_SYSTEM_STATUS_SUCCESSFUL;
else
labelError.Text = Messages.ACTION_SYSTEM_STATUS_SUCCESSFUL_PARTIAL;
}
OnPageUpdated();
}
private void RegisterRowEvents(StatusReportRow row)
{
row.RowStatusChanged += Row_RowStatusChanged;
row.RowStatusCompleted += Row_RowStatusCompleted;
}
private void DeRegisterRowEvents(StatusReportRow row)
{
row.RowStatusChanged -= Row_RowStatusChanged;
row.RowStatusCompleted -= Row_RowStatusCompleted;
}
private void UpdateTotalPercentComplete()
{
int total = 0;
foreach (var r in dataGridViewEx1.Rows)
{
var row = (StatusReportRow)r;
total += row.PercentComplete;
}
var percentage = total / dataGridViewEx1.RowCount;
if (percentage < 0)
percentage = 0;
if (percentage > 100)
percentage = 100;
if (percentage > progressBar1.Value)
progressBar1.Value = percentage;
}
private static string CreateOutputFolder()
{
var folder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
if (Directory.Exists(folder))
Directory.Delete(folder);
Directory.CreateDirectory(folder);
return folder;
}
#region Nested classes
private abstract class StatusReportRow : DataGridViewRow
{
protected readonly DataGridViewExImageCell cellHostImg = new DataGridViewExImageCell();
protected readonly DataGridViewTextBoxCell cellHost = new DataGridViewTextBoxCell();
private readonly DataGridViewTextBoxCell cellStatus = new DataGridViewTextBoxCell();
private readonly DataGridViewExImageCell cellResultImg = new DataGridViewExImageCell();
public event Action<StatusReportRow> RowStatusChanged;
public event Action<StatusReportRow> RowStatusCompleted;
protected StatusReportRow()
{
Cells.AddRange(cellHostImg, cellHost, cellStatus, cellResultImg);
cellResultImg.Value = new Bitmap(1, 1);
}
public abstract StatusReportAction Action { get; }
public int PercentComplete { get; private set; }
public bool IsCompleted
{
get { return Action != null && Action.IsCompleted; }
}
public bool IsSuccessful
{
get
{
return Action != null && Action.IsCompleted && Action.Status == ReportStatus.succeeded;
}
}
public void CancelAction()
{
if (Action != null && !Action.IsCompleted)
Action.Cancel();
}
public void RunAction(string path, string time)
{
CreateAction(path, time);
Action.Changed += Action_Changed;
Action.Completed += Action_Completed;
UpdateCells(0);
Action.RunAsync();
}
public void DeRegisterEvents()
{
if (Action == null)
return;
Action.Changed -= Action_Changed;
Action.Completed -= Action_Completed;
}
private void Action_Changed(ActionBase action)
{
Program.Invoke(DataGridView, () =>
{
UpdateCells(action.PercentComplete);
if (RowStatusChanged != null)
RowStatusChanged(this);
});
}
private void Action_Completed(ActionBase action)
{
DeRegisterEvents();
Program.Invoke(DataGridView, () =>
{
UpdateCells(100);
if (RowStatusCompleted != null)
RowStatusCompleted(this);
});
}
protected abstract void CreateAction(string path, string time);
protected virtual void UpdateCells(int percentComplete)
{
var statusString = GetStatus(out Image statusImage);
cellStatus.Value = statusString;
PercentComplete = percentComplete;
if (statusImage != null)
cellResultImg.Value = statusImage;
}
protected virtual string GetStatus(out Image img)
{
img = null;
if (Action == null)
return string.Empty;
switch (Action.Status)
{
case ReportStatus.compiling:
return Messages.BUGTOOL_REPORTSTATUS_COMPILING;
case ReportStatus.succeeded:
img = Images.StaticImages._000_Tick_h32bit_16;
return Messages.COMPLETED;
case ReportStatus.failed:
img = Images.StaticImages._000_Abort_h32bit_16;
return Messages.BUGTOOL_REPORTSTATUS_FAILED;
case ReportStatus.cancelled:
img = Images.StaticImages.cancelled_action_16;
return Messages.BUGTOOL_REPORTSTATUS_CANCELLED;
case ReportStatus.queued:
return Messages.BUGTOOL_REPORTSTATUS_QUEUED;
default:
return string.Empty;
}
}
}
private class ClientSideDataRow : StatusReportRow
{
private readonly List<Host> hosts;
private readonly bool includeClientLogs;
private StatusReportClientSideAction _action;
public ClientSideDataRow(List<Host> hosts, bool includeClientLogs)
{
this.hosts = hosts;
this.includeClientLogs = includeClientLogs;
cellHostImg.Value = Images.StaticImages._000_GetServerReport_h32bit_16;
cellHost.Value = includeClientLogs ? Messages.BUGTOOL_CLIENT_LOGS_META : Messages.BUGTOOL_CLIENT_META;
}
public override StatusReportAction Action
{
get { return _action; }
}
protected override void CreateAction(string path, string time)
{
_action = new StatusReportClientSideAction(hosts, includeClientLogs, path, time);
}
}
private class HostStatusRow : StatusReportRow
{
private readonly long size;
private readonly List<string> capabilityKeys;
private readonly Host Host;
private SingleHostStatusAction _action;
public HostStatusRow(Host host, long size, List<string> capabilityKeys)
{
Host = host;
this.size = size;
this.capabilityKeys = capabilityKeys;
}
protected override void UpdateCells(int percentComplete)
{
cellHostImg.Value = Images.GetImage16For(Host);
cellHost.Value = Host.Name();
base.UpdateCells(percentComplete);
}
public override StatusReportAction Action
{
get { return _action; }
}
protected override void CreateAction(string path, string time)
{
_action = new SingleHostStatusAction(Host, size, capabilityKeys, path, time);
}
protected override string GetStatus(out Image img)
{
img = null;
if (_action == null)
return string.Empty;
switch (_action.Status)
{
case ReportStatus.downloading:
return string.Format(Messages.BUGTOOL_REPORTSTATUS_DOWNLOADING,
Util.MemorySizeStringSuitableUnits(_action.DataTransferred, false));
default:
return base.GetStatus(out img);
}
}
}
#endregion
}
}