mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-12-22 08:26:03 +01:00
749518e94c
(either when cancelling the wizard itself or exiting the application). Implemented in the first instance for compiling the server status report. Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
468 lines
16 KiB
C#
468 lines
16 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.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
|
|
}
|
|
|
|
}
|