mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-11-23 20:36:33 +01:00
CP-18012: Use extended precheck information in Update Wizard
This commit implements the check for LiveUpdate capability of a patch. If the patch is completely live-updatable, XenCenter will not restart the host (but will do further checks once it has finished installing the update - separate ticket) Signed-off-by: Gabor Apati-Nagy <gabor.apati-nagy@citrix.com>
This commit is contained in:
parent
90c4e79c8c
commit
7ee2e605ee
@ -40,12 +40,20 @@ using XenAdmin.Diagnostics.Problems.VMProblem;
|
||||
using XenAdmin.Diagnostics.Problems.HostProblem;
|
||||
|
||||
using System.Linq;
|
||||
using XenAdmin.Wizards.PatchingWizard;
|
||||
|
||||
namespace XenAdmin.Diagnostics.Checks
|
||||
{
|
||||
public class AssertCanEvacuateCheck : Check
|
||||
{
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private readonly Dictionary<string, LivePatchCode> livePatchCodesByHost;
|
||||
|
||||
public AssertCanEvacuateCheck(Host host, Dictionary<string, LivePatchCode> livePatchCodesByHost)
|
||||
: base(host)
|
||||
{
|
||||
this.livePatchCodesByHost = livePatchCodesByHost;
|
||||
}
|
||||
|
||||
public AssertCanEvacuateCheck(Host host)
|
||||
: base(host)
|
||||
@ -54,6 +62,13 @@ namespace XenAdmin.Diagnostics.Checks
|
||||
|
||||
protected List<Problem> CheckHost()
|
||||
{
|
||||
// when livepatching is available, no restart is expected, so this check is not needed
|
||||
if (livePatchCodesByHost != null && livePatchCodesByHost.ContainsKey(Host.uuid) && livePatchCodesByHost[Host.uuid] == LivePatchCode.PATCH_PRECHECK_LIVEPATCH_COMPLETE)
|
||||
{
|
||||
log.DebugFormat("Check not needed for host {0}, because pool_patch.Precheck() returned PATCH_PRECHECK_LIVEPATCH_COMPLETE for update.", Host);
|
||||
return new List<Problem>();
|
||||
}
|
||||
|
||||
var problems = new List<Problem>();
|
||||
|
||||
var restrictMigration = Helpers.FeatureForbidden(Host.Connection, Host.RestrictIntraPoolMigrate);
|
||||
|
@ -39,6 +39,7 @@ using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using System.Collections.Generic;
|
||||
using XenAdmin.Actions;
|
||||
using XenAdmin.Wizards.PatchingWizard;
|
||||
|
||||
|
||||
namespace XenAdmin.Diagnostics.Checks
|
||||
@ -48,12 +49,15 @@ namespace XenAdmin.Diagnostics.Checks
|
||||
private readonly Pool_patch _patch;
|
||||
|
||||
private static Regex PrecheckErrorRegex = new Regex("(<error).+(</error>)");
|
||||
private static Regex LivePatchResponseRegex = new Regex("(<livepatch).+(</livepatch>)");
|
||||
|
||||
private readonly Dictionary<string, LivePatchCode> livePatchCodesByHost;
|
||||
|
||||
public PatchPrecheckCheck(Host host, Pool_patch patch)
|
||||
public PatchPrecheckCheck(Host host, Pool_patch patch, Dictionary<string, LivePatchCode> livePatchCodesByHost)
|
||||
: base(host)
|
||||
{
|
||||
_patch = patch;
|
||||
this.livePatchCodesByHost = livePatchCodesByHost;
|
||||
}
|
||||
|
||||
|
||||
@ -78,7 +82,13 @@ namespace XenAdmin.Diagnostics.Checks
|
||||
|
||||
try
|
||||
{
|
||||
return FindProblem(Pool_patch.precheck(session, Patch.opaque_ref, Host.opaque_ref));
|
||||
var result = Pool_patch.precheck(session, Patch.opaque_ref, Host.opaque_ref);
|
||||
var livePatchCode = TryToFindLivePatchCode(result);
|
||||
|
||||
if (livePatchCodesByHost != null)
|
||||
livePatchCodesByHost[Host.uuid] = livePatchCode;
|
||||
|
||||
return FindProblem(result);
|
||||
|
||||
}
|
||||
catch (Failure f)
|
||||
@ -98,6 +108,38 @@ namespace XenAdmin.Diagnostics.Checks
|
||||
}
|
||||
}
|
||||
|
||||
private LivePatchCode TryToFindLivePatchCode(string result)
|
||||
{
|
||||
LivePatchCode livePatchCodeResult = LivePatchCode.UNKNOWN;
|
||||
|
||||
if (Helpers.ElyOrGreater(Host.Connection))
|
||||
{
|
||||
result = result.Replace("\n", "");
|
||||
|
||||
if (LivePatchResponseRegex.IsMatch(result))
|
||||
{
|
||||
var m = LivePatchResponseRegex.Match(result);
|
||||
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(m.ToString());
|
||||
var firstNode = doc.FirstChild;
|
||||
|
||||
if (firstNode == null)
|
||||
return LivePatchCode.UNKNOWN;
|
||||
|
||||
var livePatchCodeNode = firstNode.Attributes["code"];
|
||||
|
||||
if (livePatchCodeNode == null)
|
||||
return LivePatchCode.UNKNOWN;
|
||||
|
||||
if (Enum.TryParse(livePatchCodeNode.Value, out livePatchCodeResult))
|
||||
return livePatchCodeResult;
|
||||
}
|
||||
}
|
||||
|
||||
return LivePatchCode.UNKNOWN;
|
||||
}
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get { return Messages.SERVER_SIDE_CHECK_DESCRIPTION; }
|
||||
|
@ -173,6 +173,8 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
else if (prevPageType == typeof(PatchingWizard_PrecheckPage))
|
||||
{
|
||||
PatchingWizard_PatchingPage.ProblemsResolvedPreCheck = PatchingWizard_PrecheckPage.ProblemsResolvedPreCheck;
|
||||
PatchingWizard_PatchingPage.LivePatchCodesByHost = PatchingWizard_PrecheckPage.LivePatchCodesByHost;
|
||||
PatchingWizard_ModePage.LivePatchCodesByHost = PatchingWizard_PrecheckPage.LivePatchCodesByHost;
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,4 +325,12 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
base.FinishWizard();
|
||||
}
|
||||
}
|
||||
|
||||
public enum LivePatchCode
|
||||
{
|
||||
UNKNOWN,
|
||||
PATCH_PRECHECK_LIVEPATCH_COMPLETE, // An applicable live patch exists for every required component
|
||||
PATCH_PRECHECK_LIVEPATCH_INCOMPLETE, // An applicable live patch exists but it is not sufficient
|
||||
PATCH_PRECHECK_LIVEPATCH_MISSING, // There is no applicable live patch
|
||||
}
|
||||
}
|
@ -38,9 +38,9 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
{
|
||||
public class PatchingWizardModeGuidanceBuilder
|
||||
{
|
||||
public static string ModeRetailPatch(List<Host> servers, Pool_patch patch)
|
||||
public static string ModeRetailPatch(List<Host> servers, Pool_patch patch, Dictionary<string, LivePatchCode> LivePatchCodesByHost)
|
||||
{
|
||||
return Build(servers, patch != null ? patch.after_apply_guidance : new List<after_apply_guidance>());
|
||||
return Build(servers, patch != null ? patch.after_apply_guidance : new List<after_apply_guidance>(), LivePatchCodesByHost);
|
||||
}
|
||||
|
||||
public static string ModeSuppPack(List<Host> servers)
|
||||
@ -50,11 +50,20 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
}
|
||||
|
||||
private static string Build(List<Host> servers, List<after_apply_guidance> guidance)
|
||||
{
|
||||
return Build(servers, guidance);
|
||||
}
|
||||
|
||||
private static string Build(List<Host> servers, List<after_apply_guidance> guidance, Dictionary<string, LivePatchCode> LivePatchCodesByHost)
|
||||
{
|
||||
StringBuilder sbLog = new StringBuilder();
|
||||
|
||||
foreach (after_apply_guidance guide in guidance)
|
||||
{
|
||||
if (guide == after_apply_guidance.restartHost
|
||||
&& (LivePatchCodesByHost != null && servers.TrueForAll(h => LivePatchCodesByHost.ContainsKey(h.uuid) && LivePatchCodesByHost[h.uuid] == LivePatchCode.PATCH_PRECHECK_LIVEPATCH_COMPLETE)))
|
||||
break;
|
||||
|
||||
sbLog.AppendLine(GetGuideMessage(guide));
|
||||
|
||||
switch (guide)
|
||||
@ -63,6 +72,9 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
case after_apply_guidance.restartXAPI:
|
||||
foreach (Host host in servers)
|
||||
{
|
||||
if (LivePatchCodesByHost != null && LivePatchCodesByHost.ContainsKey(host.uuid) && LivePatchCodesByHost[host.uuid] == LivePatchCode.PATCH_PRECHECK_LIVEPATCH_COMPLETE)
|
||||
continue;
|
||||
|
||||
if (host.IsMaster())
|
||||
sbLog.AppendFormat("\t{0} ({1})\r\n", host.Name, Messages.MASTER);
|
||||
else
|
||||
@ -89,7 +101,7 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
}
|
||||
}
|
||||
|
||||
if (guidance.Count == 0)
|
||||
if (sbLog.Length == 0)
|
||||
sbLog.Append(Messages.PATCHINGWIZARD_MODEPAGE_NOACTION);
|
||||
|
||||
return sbLog.ToString();
|
||||
|
@ -77,6 +77,12 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
{
|
||||
return Messages.UPDATES_WIZARD_APPLY_UPDATE;
|
||||
}
|
||||
|
||||
public Dictionary<string, LivePatchCode> LivePatchCodesByHost
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public override void PageLoaded(PageLoadedDirection direction)
|
||||
{
|
||||
@ -88,7 +94,7 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
{
|
||||
case UpdateType.NewRetail:
|
||||
case UpdateType.Existing:
|
||||
textBoxLog.Text = PatchingWizardModeGuidanceBuilder.ModeRetailPatch(SelectedServers, Patch);
|
||||
textBoxLog.Text = PatchingWizardModeGuidanceBuilder.ModeRetailPatch(SelectedServers, Patch, LivePatchCodesByHost);
|
||||
AutomaticRadioButton.Enabled = true;
|
||||
AutomaticRadioButton.Checked = true;
|
||||
break;
|
||||
|
@ -50,6 +50,12 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
{
|
||||
protected static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public Dictionary<string, LivePatchCode> LivePatchCodesByHost
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private AsyncAction actionManualMode = null;
|
||||
private bool _thisPageHasBeenCompleted = false;
|
||||
private BackgroundWorker actionsWorker = null;
|
||||
@ -318,7 +324,8 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
|
||||
actions.Add(new ApplyPatchPlanAction(host, patch));
|
||||
|
||||
if (patch.after_apply_guidance.Contains(after_apply_guidance.restartHost))
|
||||
if (patch.after_apply_guidance.Contains(after_apply_guidance.restartHost)
|
||||
&& !(LivePatchCodesByHost !=null && LivePatchCodesByHost.ContainsKey(host.uuid) && LivePatchCodesByHost[host.uuid] == LivePatchCode.PATCH_PRECHECK_LIVEPATCH_COMPLETE))
|
||||
{
|
||||
actions.Add(new EvacuateHostPlanAction(host));
|
||||
actions.Add(new RebootHostPlanAction(host));
|
||||
|
@ -303,9 +303,16 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, LivePatchCode> LivePatchCodesByHost
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
protected virtual List<KeyValuePair<string, List<Check>>> GenerateChecks(Pool_patch patch)
|
||||
{
|
||||
List<KeyValuePair<string, List<Check>>> checks = new List<KeyValuePair<string, List<Check>>>();
|
||||
LivePatchCodesByHost = new Dictionary<string, LivePatchCode>();
|
||||
|
||||
//HostLivenessCheck checks
|
||||
checks.Add(new KeyValuePair<string, List<Check>>(Messages.CHECKING_HOST_LIVENESS_STATUS, new List<Check>()));
|
||||
@ -324,19 +331,6 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
checkGroup.Add(new HAOffCheck(host));
|
||||
}
|
||||
|
||||
//Checking can evacuate host
|
||||
//CA-97061 - evacuate host -> suspended VMs. This is only needed for restartHost
|
||||
//Also include this check for the supplemental packs (patch == null), as their guidance is restartHost
|
||||
if (patch == null || patch.after_apply_guidance.Contains(after_apply_guidance.restartHost))
|
||||
{
|
||||
checks.Add(new KeyValuePair<string, List<Check>>(Messages.CHECKING_CANEVACUATE_STATUS, new List<Check>()));
|
||||
checkGroup = checks[checks.Count - 1].Value;
|
||||
foreach (Host host in SelectedServers)
|
||||
{
|
||||
checkGroup.Add(new AssertCanEvacuateCheck(host));
|
||||
}
|
||||
}
|
||||
|
||||
//PBDsPluggedCheck
|
||||
checks.Add(new KeyValuePair<string, List<Check>>(Messages.CHECKING_STORAGE_CONNECTIONS_STATUS, new List<Check>()));
|
||||
checkGroup = checks[checks.Count - 1].Value;
|
||||
@ -354,9 +348,23 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
{
|
||||
List<Pool_patch> poolPatches = new List<Pool_patch>(host.Connection.Cache.Pool_patches);
|
||||
Pool_patch poolPatchFromHost = poolPatches.Find(otherPatch => string.Equals(otherPatch.uuid, patch.uuid, StringComparison.OrdinalIgnoreCase));
|
||||
checkGroup.Add(new PatchPrecheckCheck(host, poolPatchFromHost));
|
||||
checkGroup.Add(new PatchPrecheckCheck(host, poolPatchFromHost, LivePatchCodesByHost));
|
||||
}
|
||||
}
|
||||
|
||||
//Checking can evacuate host
|
||||
//CA-97061 - evacuate host -> suspended VMs. This is only needed for restartHost
|
||||
//Also include this check for the supplemental packs (patch == null), as their guidance is restartHost
|
||||
if (patch == null || patch.after_apply_guidance.Contains(after_apply_guidance.restartHost))
|
||||
{
|
||||
checks.Add(new KeyValuePair<string, List<Check>>(Messages.CHECKING_CANEVACUATE_STATUS, new List<Check>()));
|
||||
checkGroup = checks[checks.Count - 1].Value;
|
||||
foreach (Host host in SelectedServers)
|
||||
{
|
||||
checkGroup.Add(new AssertCanEvacuateCheck(host, LivePatchCodesByHost));
|
||||
}
|
||||
}
|
||||
|
||||
return checks;
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ namespace XenAdminTests.WizardTests
|
||||
host.Setup(h => h.IsMaster()).Returns(true);
|
||||
host.Setup(h => h.Name).Returns("MyHost");
|
||||
patch.Setup(p => p.after_apply_guidance).Returns(new List<after_apply_guidance> { guidance });
|
||||
msg = PatchingWizardModeGuidanceBuilder.ModeRetailPatch(new List<Host> { host.Object }, patch.Object);
|
||||
msg = PatchingWizardModeGuidanceBuilder.ModeRetailPatch(new List<Host> { host.Object }, patch.Object, new Dictionary<string,LivePatchCode>());
|
||||
return patch;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user