CP-28284: Updates wizard: Add a "pause and resume" mechanism to handle failures

Signed-off-by: Mihaela Stoica <mihaela.stoica@citrix.com>
This commit is contained in:
Mihaela Stoica 2018-06-11 15:14:07 +01:00 committed by Konstantina Chremmou
parent da2c96ad1c
commit 7fa9d0b94f
5 changed files with 152 additions and 18 deletions

View File

@ -55,6 +55,7 @@ namespace XenAdmin.Wizards.PatchingWizard
protected static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private bool _thisPageIsCompleted = false;
private bool _someWorkersFailed = false;
public List<Problem> ProblemsResolvedPreCheck { private get; set; }
@ -69,6 +70,7 @@ namespace XenAdmin.Wizards.PatchingWizard
public KeyValuePair<XenServerPatch, string> PatchFromDisk { private get; set; }
private List<UpdateProgressBackgroundWorker> backgroundWorkers = new List<UpdateProgressBackgroundWorker>();
private List<UpdateProgressBackgroundWorker> failedWorkers = new List<UpdateProgressBackgroundWorker>();
public PatchingWizard_AutomatedUpdatesPage()
{
@ -136,6 +138,8 @@ namespace XenAdmin.Wizards.PatchingWizard
labelTitle.Text = Messages.PATCHINGWIZARD_UPLOAD_AND_INSTALL_TITLE_AUTOMATED_MODE;
else if (WizardMode == WizardMode.NewVersion)
labelTitle.Text = Messages.PATCHINGWIZARD_UPLOAD_AND_INSTALL_TITLE_NEW_VERSION_AUTOMATED_MODE;
ToggleRetryButton();
if (!StartUpgradeWorkers())
{
@ -213,17 +217,18 @@ namespace XenAdmin.Wizards.PatchingWizard
if (action != null && delayedActionsPerHost.All(a => a.GetType() != action.GetType()))
delayedActionsPerHost.Add(action);
}
var isLastHostInPool = hosts.IndexOf(host) == hosts.Count - 1;
if (isLastHostInPool)
{
// add cleanup action for current patch at the end of the update seuence for the last host in the pool
planActionsPerHost.Add(new RemoveUpdateFileFromMasterPlanAction(master, patchMappings, patch));
}
}
planActions.Add(new HostActionTuple(host, planActionsPerHost, delayedActionsPerHost));
}
var finalActions = new List<PlanAction>();
//clean up master at the end
foreach (var patch in uploadedPatches)
finalActions.Add(new RemoveUpdateFileFromMasterPlanAction(master, patchMappings, patch));
//add a revert pre-check action for this pool
var problemsToRevert = ProblemsResolvedPreCheck.Where(p => hosts.ToList().Select(h => h.uuid).ToList().Contains(p.Check.Host.uuid)).ToList();
if (problemsToRevert.Count > 0)
@ -271,7 +276,14 @@ namespace XenAdmin.Wizards.PatchingWizard
actionsWorker.DoneActions.Add(action);
actionsWorker.InProgressActions.Remove(action);
progressBar.Value += e.ProgressPercentage / backgroundWorkers.Count; //extend with error handling related numbers
if (action.Error == null)
{
// remove the successful action from the cleanup actions (we are running the cleanup actions in case of failures or if the user cancelled the process, but we shouldn't re-run the actions that have already been run)
actionsWorker.CleanupActions.Remove(action);
// only increase the progress if the action succeeded
progressBar.Value += e.ProgressPercentage/backgroundWorkers.Count;
}
}
}
@ -455,8 +467,12 @@ namespace XenAdmin.Wizards.PatchingWizard
doWorkEventArgs.Result = new Exception(action.Title, e);
failedWorkers.Add(sender as UpdateProgressBackgroundWorker);
bgw.ReportProgress(0);
//this pool failed, we will stop here, but try to remove update files at least
try
/*try
{
if (action is DownloadPatchPlanAction || action is UploadPatchToMasterPlanAction)
return;
@ -487,14 +503,20 @@ namespace XenAdmin.Wizards.PatchingWizard
finally
{
bgw.ReportProgress(0);
}
}*/
}
}
private void RunPlanAction(UpdateProgressBackgroundWorker bgw, PlanAction action)
{
action.OnProgressChange += action_OnProgressChange;
if (bgw.DoneActions.Contains(action) && action.Error == null) // this action was completed successfully, do not run it again
return;
// if we retry a failed action, we need to firstly remove it from DoneActions and reset it's Error
bgw.DoneActions.Remove(action);
action.Error = null;
action.OnProgressChange += action_OnProgressChange;
bgw.ReportProgress(0, action);
action.Run();
@ -523,6 +545,8 @@ namespace XenAdmin.Wizards.PatchingWizard
: Messages.PATCHINGWIZARD_AUTOUPDATINGPAGE_ERROR_ONE;
pictureBox1.Image = Images.StaticImages._000_error_h32bit_16;
panel1.Visible = true;
_someWorkersFailed = true;
}
}
@ -536,9 +560,12 @@ namespace XenAdmin.Wizards.PatchingWizard
: Messages.PATCHINGWIZARD_AUTOUPDATINGPAGE_SUCCESS_ONE;
pictureBox1.Image = Images.StaticImages._000_Tick_h32bit_16;
panel1.Visible = true;
progressBar.Value = 100;
}
progressBar.Value = 100;
// show the retry button, if needed
ToggleRetryButton();
_thisPageIsCompleted = true;
_cancelEnabled = false;
_nextEnabled = true;
@ -566,7 +593,32 @@ namespace XenAdmin.Wizards.PatchingWizard
}
}
private void RetryFailedActions()
{
_someWorkersFailed = false;
panel1.Visible = false;
ToggleRetryButton();
var workers = new List<UpdateProgressBackgroundWorker>(failedWorkers);
failedWorkers.Clear();
foreach (var failedWorker in workers)
{
failedWorker.RunWorkerAsync();
}
}
private void ToggleRetryButton()
{
labelRetry.Visible = buttonRetry.Visible = _someWorkersFailed;
}
#endregion
private void retryButton_Click(object sender, EventArgs e)
{
RetryFailedActions();
}
}
}

View File

@ -35,6 +35,8 @@ namespace XenAdmin.Wizards.PatchingWizard
this.labelError = new System.Windows.Forms.Label();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.panel1 = new System.Windows.Forms.TableLayoutPanel();
this.buttonRetry = new System.Windows.Forms.Button();
this.labelRetry = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.panel1.SuspendLayout();
this.SuspendLayout();
@ -75,8 +77,24 @@ namespace XenAdmin.Wizards.PatchingWizard
this.panel1.BackColor = System.Drawing.SystemColors.Control;
this.panel1.Controls.Add(this.pictureBox1, 0, 0);
this.panel1.Controls.Add(this.labelError, 1, 0);
this.panel1.Controls.Add(this.buttonRetry, 2, 0);
this.panel1.Controls.Add(this.labelRetry, 1, 1);
this.panel1.Name = "panel1";
//
// buttonRetry
//
resources.ApplyResources(this.buttonRetry, "buttonRetry");
this.buttonRetry.Name = "buttonRetry";
this.panel1.SetRowSpan(this.buttonRetry, 2);
this.buttonRetry.UseVisualStyleBackColor = true;
this.buttonRetry.Click += new System.EventHandler(this.retryButton_Click);
//
// labelRetry
//
resources.ApplyResources(this.labelRetry, "labelRetry");
this.labelRetry.BackColor = System.Drawing.SystemColors.Control;
this.labelRetry.Name = "labelRetry";
//
// PatchingWizard_AutomatedUpdatesPage
//
resources.ApplyResources(this, "$this");
@ -102,6 +120,8 @@ namespace XenAdmin.Wizards.PatchingWizard
private System.Windows.Forms.Label labelError;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.TableLayoutPanel panel1;
private System.Windows.Forms.Button buttonRetry;
private System.Windows.Forms.Label labelRetry;
}
}

View File

@ -163,7 +163,7 @@
<value>Both</value>
</data>
<data name="textBoxLog.Size" type="System.Drawing.Size, System.Drawing">
<value>502, 235</value>
<value>502, 222</value>
</data>
<data name="textBoxLog.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
@ -223,7 +223,7 @@
<value>25, 4</value>
</data>
<data name="labelError.Size" type="System.Drawing.Size, System.Drawing">
<value>483, 13</value>
<value>426, 13</value>
</data>
<data name="labelError.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
@ -271,19 +271,79 @@
<value>True</value>
</data>
<data name="panel1.ColumnCount" type="System.Int32, mscorlib">
<value>3</value>
</data>
<data name="buttonRetry.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="buttonRetry.Location" type="System.Drawing.Point, System.Drawing">
<value>457, 3</value>
</data>
<data name="buttonRetry.Size" type="System.Drawing.Size, System.Drawing">
<value>51, 23</value>
</data>
<data name="buttonRetry.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="buttonRetry.Text" xml:space="preserve">
<value>&amp;Retry</value>
</data>
<data name="&gt;&gt;buttonRetry.Name" xml:space="preserve">
<value>buttonRetry</value>
</data>
<data name="&gt;&gt;buttonRetry.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;buttonRetry.Parent" xml:space="preserve">
<value>panel1</value>
</data>
<data name="&gt;&gt;buttonRetry.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="labelRetry.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Left, Right</value>
</data>
<data name="labelRetry.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="labelRetry.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="labelRetry.Location" type="System.Drawing.Point, System.Drawing">
<value>25, 25</value>
</data>
<data name="labelRetry.Size" type="System.Drawing.Size, System.Drawing">
<value>426, 13</value>
</data>
<data name="labelRetry.TabIndex" type="System.Int32, mscorlib">
<value>3</value>
</data>
<data name="labelRetry.Text" xml:space="preserve">
<value>The update process has been paused. Press Retry to resume the update process.</value>
</data>
<data name="&gt;&gt;labelRetry.Name" xml:space="preserve">
<value>labelRetry</value>
</data>
<data name="&gt;&gt;labelRetry.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;labelRetry.Parent" xml:space="preserve">
<value>panel1</value>
</data>
<data name="&gt;&gt;labelRetry.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="panel1.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Bottom</value>
</data>
<data name="panel1.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 313</value>
<value>0, 293</value>
</data>
<data name="panel1.RowCount" type="System.Int32, mscorlib">
<value>1</value>
<value>2</value>
</data>
<data name="panel1.Size" type="System.Drawing.Size, System.Drawing">
<value>511, 22</value>
<value>511, 42</value>
</data>
<data name="panel1.TabIndex" type="System.Int32, mscorlib">
<value>5</value>
@ -301,7 +361,7 @@
<value>0</value>
</data>
<data name="panel1.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="pictureBox1" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="labelError" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100,Absolute,20" /&gt;&lt;Rows Styles="Percent,100" /&gt;&lt;/TableLayoutSettings&gt;</value>
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="pictureBox1" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="labelError" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="buttonRetry" Row="0" RowSpan="2" Column="2" ColumnSpan="1" /&gt;&lt;Control Name="labelRetry" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100,AutoSize,0" /&gt;&lt;Rows Styles="Percent,100,Absolute,20" /&gt;&lt;/TableLayoutSettings&gt;</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>

View File

@ -46,7 +46,7 @@ namespace XenAdmin.Wizards.PatchingWizard.PlanActions
private readonly Host host;
public PatchPrecheckOnHostPlanAction(IXenConnection connection, XenServerPatch patch, Host host, List<PoolPatchMapping> mappings)
: base(connection, string.Format(Messages.UPDATES_WIZARD_RUNNING_PRECHECK, patch.Name, connection.Name))
: base(connection, string.Format(Messages.UPDATES_WIZARD_RUNNING_PRECHECK, patch.Name, host.Name()))
{
this.patch = patch;
this.host = host;

View File

@ -43,6 +43,7 @@ namespace XenAdmin.Wizards.PatchingWizard
private readonly int _actionsCount;
public List<HostActionTuple> HostActions { get; private set; }
public List<PlanAction> FinalActions { get; private set; }
public List<PlanAction> CleanupActions { get; private set; }
public readonly List<PlanAction> DoneActions = new List<PlanAction>();
public readonly List<PlanAction> InProgressActions = new List<PlanAction>();
public string Name { get; set; }
@ -51,6 +52,7 @@ namespace XenAdmin.Wizards.PatchingWizard
{
HostActions = planActions;
FinalActions = finalActions;
CleanupActions = finalActions.Where(a => a is RemoveUpdateFileFromMasterPlanAction).ToList();
_actionsCount = HostActions.Sum(t => t.Item2.Count + t.Item3.Count) + FinalActions.Count;
}