CP-15719: UI: Implement error handling/reporting on Upload & Install page

Implemented error handling.
If there has been an error in a pool, we stop executing actions in that pool immediately, and report the error once every other actions have finished. Error in one pool will not affect the upgrade process of other pools.

Signed-off-by: Gabor Apati-Nagy <gabor.apati-nagy@citrix.com>
This commit is contained in:
Gabor Apati-Nagy 2016-05-18 13:43:34 +01:00
parent a05e92d001
commit 73d67f407d
5 changed files with 223 additions and 103 deletions

View File

@ -66,9 +66,6 @@ namespace XenAdmin.Wizards.PatchingWizard
private List<BackgroundWorker> backgroundWorkers = new List<BackgroundWorker>();
private List<UpgradeProgressDescriptor> upgradeProgressDescriptors = new List<UpgradeProgressDescriptor>();
public PatchingWizard_AutoUpdatingPage()
{
InitializeComponent();
@ -118,7 +115,8 @@ namespace XenAdmin.Wizards.PatchingWizard
if (_thisPageHasBeenCompleted)
{
actionsWorker = null;
backgroundWorkers.ForEach(bgw => bgw.CancelAsync());
backgroundWorkers.Clear();
return;
}
@ -128,6 +126,7 @@ namespace XenAdmin.Wizards.PatchingWizard
{
Dictionary<Host, List<PlanAction>> planActionsByHost = new Dictionary<Host, List<PlanAction>>();
Dictionary<Host, List<PlanAction>> delayedActionsByHost = new Dictionary<Host, List<PlanAction>>();
planActionsPerPool.Add(master, new List<PlanAction>());
foreach (var host in master.Connection.Cache.Hosts)
{
@ -135,7 +134,6 @@ namespace XenAdmin.Wizards.PatchingWizard
delayedActionsByHost.Add(host, new List<PlanAction>());
}
//var master = Helpers.GetMaster(pool.Connection);
var hosts = master.Connection.Cache.Hosts;
var us = Updates.GetUpgradeSequence(master.Connection);
@ -163,15 +161,10 @@ namespace XenAdmin.Wizards.PatchingWizard
UpdateDelayedAfterPatchGuidanceActionListForHost(delayedActionsByHost[host], host, patch);
}
// now add all non-delayed actions to the pool action list
// now add all non-delayed actions to the pool action list
foreach (var kvp in planActionsByHost)
{
if (!planActionsPerPool.ContainsKey(master))
{
planActionsPerPool.Add(master, new List<PlanAction>());
}
planActionsPerPool[master].AddRange(kvp.Value);
kvp.Value.Clear();
}
@ -188,47 +181,40 @@ namespace XenAdmin.Wizards.PatchingWizard
delayedActions.AddRange(kvp.Value);
}
var upd = new UpgradeProgressDescriptor(master, planActionsPerPool[master], delayedActions);
upgradeProgressDescriptors.Add(upd);
if (planActionsPerPool.ContainsKey(master) && planActionsPerPool[master].Count > 0)
{
var bgw = new UpdateProgressBackgroundWorker(master, planActionsPerPool[master], delayedActions);
backgroundWorkers.Add(bgw);
}
} //foreach in SelectedMasters
//var planActions = new List<PlanAction>();
//actions list for serial execution
foreach (var desc in upgradeProgressDescriptors)
foreach (var bgw in backgroundWorkers)
{
//planActions.AddRange(actionListPerPool.Value);
var bgw = new BackgroundWorker();
backgroundWorkers.Add(bgw);
bgw.DoWork += new DoWorkEventHandler(PatchingWizardAutomaticPatchWork);
bgw.DoWork += new DoWorkEventHandler(WorkerDoWork);
bgw.WorkerReportsProgress = true;
bgw.ProgressChanged += new ProgressChangedEventHandler(actionsWorker_ProgressChanged);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(actionsWorker_RunWorkerCompleted);
bgw.ProgressChanged += new ProgressChangedEventHandler(WorkerProgressChanged);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
bgw.WorkerSupportsCancellation = true;
bgw.RunWorkerAsync(desc);
bgw.RunWorkerAsync();
}
//planActions.Add(new UnwindProblemsAction(ProblemsResolvedPreCheck));
if (backgroundWorkers.Count == 0)
{
_thisPageHasBeenCompleted = true;
_nextEnabled = true;
//actionsWorker = new BackgroundWorker();
//actionsWorker.DoWork += new DoWorkEventHandler(PatchingWizardAutomaticPatchWork);
//actionsWorker.WorkerReportsProgress = true;
//actionsWorker.ProgressChanged += new ProgressChangedEventHandler(actionsWorker_ProgressChanged);
//actionsWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(actionsWorker_RunWorkerCompleted);
//actionsWorker.WorkerSupportsCancellation = true;
//actionsWorker.RunWorkerAsync(planActions);
OnPageUpdated();
}
}
#region automatic_mode
private List<PlanAction> doneActions = new List<PlanAction>();
private List<PlanAction> inProgressActions = new List<PlanAction>();
private List<PlanAction> errorActions = new List<PlanAction>();
private void actionsWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
private void WorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
var actionsWorker = sender as BackgroundWorker;
@ -247,90 +233,91 @@ namespace XenAdmin.Wizards.PatchingWizard
progressBar.Value += (int)((float)e.ProgressPercentage / (float)backgroundWorkers.Count); //extend with error handling related numbers
}
var sb = new StringBuilder();
foreach (var pa in doneActions)
{
sb.Append(pa);
sb.AppendLine(Messages.DONE);
}
foreach (var pa in inProgressActions)
{
sb.Append(pa);
sb.AppendLine();
}
textBoxLog.Text = sb.ToString();
UpdateStatusTextBox();
}
}
private void PatchingWizardAutomaticPatchWork(object sender, DoWorkEventArgs doWorkEventArgs)
private void UpdateStatusTextBox()
{
var actionsWorker = sender as BackgroundWorker;
var sb = new StringBuilder();
UpgradeProgressDescriptor descriptor = (UpgradeProgressDescriptor)doWorkEventArgs.Argument;
foreach (var pa in doneActions)
{
sb.Append(pa);
sb.AppendLine(Messages.DONE);
}
var actionList = descriptor.planActions.Concat(descriptor.delayedActions).ToList();
foreach (var pa in inProgressActions)
{
sb.Append(pa);
sb.AppendLine();
}
foreach (PlanAction action in actionList)
textBoxLog.Text = sb.ToString();
}
private void WorkerDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
var bgw = sender as UpdateProgressBackgroundWorker;
foreach (PlanAction action in bgw.AllActions)
{
try
{
if (actionsWorker.CancellationPending)
if (bgw.CancellationPending)
{
//descriptor.InProgressAction = null;
doWorkEventArgs.Cancel = true;
return;
}
//descriptor.InProgressAction = action;
actionsWorker.ReportProgress(0, action);
bgw.ReportProgress(0, action);
action.Run();
Thread.Sleep(1000);
//descriptor.doneActions.Add(action);
bgw.doneActions.Add(action);
actionsWorker.ReportProgress((int)((1.0 / (double)actionList.Count) * 100), action);
bgw.ReportProgress((int)((1.0 / (double)bgw.AllActions.Count) * 100), action);
}
catch (Exception e)
{
//descriptor.FailedWithExceptionAction = action;
bgw.FailedWithExceptionAction = action;
errorActions.Add(action);
log.Error("Failed to carry out plan.", e);
log.Debug(actionList);
log.Debug(bgw.AllActions);
doWorkEventArgs.Result = new Exception(action.Title, e);
break;
}
finally
{
//descriptor.InProgressAction = null;
}
}
}
private void actionsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var bgw = (UpdateProgressBackgroundWorker)sender;
if (!e.Cancelled)
{
Exception exception = e.Result as Exception;
if (exception != null)
{
FinishedWithErrors(exception);
}
else
{
FinishedSuccessfully();
//not showing exceptions in the meantime
}
//if all finished
if (backgroundWorkers.All(w => !w.IsBusy))
{
AllWorkersFinished();
ShowErrors();
progressBar.Value = 100;
_thisPageHasBeenCompleted = true;
}
progressBar.Value = 100;
_cancelEnabled = false;
_nextEnabled = true;
}
OnPageUpdated();
_thisPageHasBeenCompleted = true;
OnPageUpdated();
}
private void UpdateDelayedAfterPatchGuidanceActionListForHost(List<PlanAction> delayedGuidances, Host host, XenServerPatch patch)
@ -447,37 +434,66 @@ namespace XenAdmin.Wizards.PatchingWizard
#endregion
private void FinishedWithErrors(Exception exception)
private void ShowErrors()
{
//labelTitle.Text = string.Format(Messages.UPDATE_WAS_NOT_COMPLETED, GetUpdateName());
string errorMessage = null;
if (exception != null && exception.InnerException != null && exception.InnerException is Failure)
if (ErrorMessages != null)
{
var innerEx = exception.InnerException as Failure;
errorMessage = innerEx.Message;
labelTitle.Text = Messages.PATCHINGWIZARD_AUTOUPDATINGPAGE_FAILED;
labelError.Text = Messages.PATCHINGWIZARD_AUTOUPDATINGPAGE_ERROR;
if (innerEx.ErrorDescription != null && innerEx.ErrorDescription.Count > 0)
log.Error(string.Concat(innerEx.ErrorDescription.ToArray()));
textBoxLog.Text += ErrorMessages;
log.ErrorFormat("Error message displayed: {0}", labelError.Text);
pictureBox1.Image = SystemIcons.Error.ToBitmap();
panel1.Visible = true;
}
labelError.Text = errorMessage ?? string.Format(Messages.PATCHING_WIZARD_ERROR, exception.Message);
log.ErrorFormat("Error message displayed: {0}", labelError.Text);
pictureBox1.Image = SystemIcons.Error.ToBitmap();
if (exception.InnerException is SupplementalPackInstallFailedException)
{
errorLinkLabel.Visible = true;
errorLinkLabel.Tag = exception.InnerException;
}
panel1.Visible = true;
}
private void FinishedSuccessfully()
private string ErrorMessages
{
get
{
if (errorActions.Count == 0)
return null;
var sb = new StringBuilder();
sb.AppendLine(errorActions.Count > 1 ? Messages.PATCHINGWIZARD_AUTOUPDATINGPAGE_ERRORS_OCCURED : Messages.PATCHINGWIZARD_AUTOUPDATINGPAGE_ERROR_OCCURED);
foreach (var action in errorActions)
{
var exception = action.Error;
if (exception == null)
{
log.ErrorFormat("An action has failed with an empty exception. Action: {0}", action.ToString());
continue;
}
if (exception != null && exception.InnerException != null && exception.InnerException is Failure)
{
var innerEx = exception.InnerException as Failure;
sb.AppendLine(innerEx.Message);
if (innerEx.ErrorDescription != null && innerEx.ErrorDescription.Count > 0)
sb.AppendLine(string.Concat(innerEx.ErrorDescription.ToArray()));
}
else
{
if (exception is Failure && ((Failure)exception).ErrorDescription != null)
sb.AppendLine(string.Concat(((Failure)exception).ErrorDescription.ToArray()));
else
sb.AppendLine(exception.Message);
}
}
return sb.ToString();
}
}
private void AllWorkersFinished()
{
labelTitle.Text = Messages.PATCHINGWIZARD_UPDATES_DONE_AUTOMATIC_MODE;
pictureBox1.Image = null;
labelError.Text = Messages.CLOSE_WIZARD_CLICK_FINISH;
}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XenAdmin.Wizards.PatchingWizard.PlanActions;
using XenAPI;
namespace XenAdmin.Wizards.PatchingWizard
{
class UpdateProgressBackgroundWorker : BackgroundWorker
{
public List<PlanAction> PlanActions { get; private set; }
public List<PlanAction> DelayedActions { get; private set; }
private Host master;
public List<PlanAction> FinsihedActions = new List<PlanAction>();
public PlanAction FailedWithExceptionAction = null;
public List<PlanAction> doneActions = new List<PlanAction>();
public UpdateProgressBackgroundWorker(Host master, List<PlanAction> planActions, List<PlanAction> delayedActions)
{
this.master = master;
this.PlanActions = planActions;
this.DelayedActions = delayedActions;
}
public List<PlanAction> AllActions
{
get
{
return PlanActions.Concat(DelayedActions).ToList();
}
}
public int TotalNumberOfActions
{
get
{
return PlanActions.Count + DelayedActions.Count;
}
}
public int ProgressPercent
{
get
{
return (int)(1.0 / (double)TotalNumberOfActions * (double)(FinsihedActions.Count));
}
}
}
}

View File

@ -869,6 +869,9 @@
<Compile Include="Wizards\PatchingWizard\PlanActions\RemoveUpdateFilesFromMaster.cs" />
<Compile Include="Wizards\PatchingWizard\PlanActions\RemoveUpdateFile.cs" />
<Compile Include="Wizards\PatchingWizard\PlanActions\InstallSupplementalPackPlanAction.cs" />
<Compile Include="Wizards\PatchingWizard\UpdateProgressBackgroundWorker.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Wizards\PatchingWizard\UpgradeProgressDescriptor.cs" />
<Compile Include="XenSearch\TreeNodeGroupAcceptor.cs">
</Compile>

View File

@ -25594,6 +25594,42 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to Update was not completed successfully.
/// </summary>
public static string PATCHINGWIZARD_AUTOUPDATINGPAGE_ERROR {
get {
return ResourceManager.GetString("PATCHINGWIZARD_AUTOUPDATINGPAGE_ERROR", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Following error occured while automatic upgrade was in progress: .
/// </summary>
public static string PATCHINGWIZARD_AUTOUPDATINGPAGE_ERROR_OCCURED {
get {
return ResourceManager.GetString("PATCHINGWIZARD_AUTOUPDATINGPAGE_ERROR_OCCURED", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Following errors occured while automatic upgrade was in progress:.
/// </summary>
public static string PATCHINGWIZARD_AUTOUPDATINGPAGE_ERRORS_OCCURED {
get {
return ResourceManager.GetString("PATCHINGWIZARD_AUTOUPDATINGPAGE_ERRORS_OCCURED", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Update was not completed successfully.
/// </summary>
public static string PATCHINGWIZARD_AUTOUPDATINGPAGE_FAILED {
get {
return ResourceManager.GetString("PATCHINGWIZARD_AUTOUPDATINGPAGE_FAILED", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Upload and Install.
/// </summary>
@ -25964,7 +26000,7 @@ namespace XenAdmin {
}
/// <summary>
/// Looks up a localized string similar to a.
/// Looks up a localized string similar to This server is not licensed for automatic updating.
/// </summary>
public static string PATCHINGWIZARD_SELECTSERVERPAGE_HOST_UNLICENSED_FOR_BATCH_UPDATING {
get {

View File

@ -8853,6 +8853,18 @@ However, there is not enough space to perform the repartitioning, so the current
<data name="PASTE" xml:space="preserve">
<value>Paste</value>
</data>
<data name="PATCHINGWIZARD_AUTOUPDATINGPAGE_ERROR" xml:space="preserve">
<value>Update was not completed successfully</value>
</data>
<data name="PATCHINGWIZARD_AUTOUPDATINGPAGE_ERRORS_OCCURED" xml:space="preserve">
<value>Following errors occured while automatic upgrade was in progress:</value>
</data>
<data name="PATCHINGWIZARD_AUTOUPDATINGPAGE_ERROR_OCCURED" xml:space="preserve">
<value>Following error occured while automatic upgrade was in progress: </value>
</data>
<data name="PATCHINGWIZARD_AUTOUPDATINGPAGE_FAILED" xml:space="preserve">
<value>Update was not completed successfully</value>
</data>
<data name="PATCHINGWIZARD_AUTOUPDATINGPAGE_TEXT" xml:space="preserve">
<value>Upload and Install</value>
</data>