diff --git a/XenAdmin/Alerts/NewVersionPriorityAlertComparer.cs b/XenAdmin/Alerts/NewVersionPriorityAlertComparer.cs new file mode 100644 index 000000000..3eb64ba99 --- /dev/null +++ b/XenAdmin/Alerts/NewVersionPriorityAlertComparer.cs @@ -0,0 +1,68 @@ +/* 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.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace XenAdmin.Alerts +{ + public class NewVersionPriorityAlertComparer : IComparer + { + public int Compare(Alert alert1, Alert alert2) + { + if (alert1 == null || alert2 == null) + return 0; + + int sortResult = 0; + + if (IsVersionOrVersionUpdateAlert(alert1) && !IsVersionOrVersionUpdateAlert(alert2)) + sortResult = 1; + + if (!IsVersionOrVersionUpdateAlert(alert1) && IsVersionOrVersionUpdateAlert(alert2)) + sortResult = -1; + + if (sortResult == 0) + sortResult = Alert.CompareOnDate(alert1, alert2); + + return -sortResult; + } + + private bool IsVersionOrVersionUpdateAlert(Alert alert) + { + return alert is XenServerPatchAlert && (alert as XenServerPatchAlert).ShowAsNewVersion + || alert is XenServerVersionAlert + || alert is XenCenterUpdateAlert; + } + } +} diff --git a/XenAdmin/Alerts/Types/XenCenterUpdateAlert.cs b/XenAdmin/Alerts/Types/XenCenterUpdateAlert.cs index edebaf76a..da6392fa9 100644 --- a/XenAdmin/Alerts/Types/XenCenterUpdateAlert.cs +++ b/XenAdmin/Alerts/Types/XenCenterUpdateAlert.cs @@ -61,7 +61,7 @@ namespace XenAdmin.Alerts public override string Title { - get { return Messages.ALERT_NEW_VERSION; } + get { return string.Format(Messages.ALERT_NEW_VERSION, NewVersion.Name); } } public override string Description @@ -101,16 +101,25 @@ namespace XenAdmin.Alerts } } + static int DISMISSED_XC_VERSIONS_LIMIT = 5; + public override void Dismiss() - { - Properties.Settings.Default.LatestXenCenterSeen = NewVersion.VersionAndLang; + { + List current = new List(Properties.Settings.Default.LatestXenCenterSeen.Split(',')); + if (current.Contains(NewVersion.VersionAndLang)) + return; + if (current.Count >= DISMISSED_XC_VERSIONS_LIMIT) + current.RemoveRange(0, current.Count - DISMISSED_XC_VERSIONS_LIMIT + 1); + current.Add(NewVersion.VersionAndLang); + Properties.Settings.Default.LatestXenCenterSeen = string.Join(",", current.ToArray()); Settings.TrySaveSettings(); Updates.RemoveUpdate(this); } public override bool IsDismissed() { - return Properties.Settings.Default.LatestXenCenterSeen == NewVersion.VersionAndLang; + List current = new List(Properties.Settings.Default.LatestXenCenterSeen.Split(',')); + return current.Contains(NewVersion.VersionAndLang); } public override bool Equals(Alert other) diff --git a/XenAdmin/Alerts/Types/XenServerPatchAlert.cs b/XenAdmin/Alerts/Types/XenServerPatchAlert.cs index 02f2c4da9..23cf8f318 100644 --- a/XenAdmin/Alerts/Types/XenServerPatchAlert.cs +++ b/XenAdmin/Alerts/Types/XenServerPatchAlert.cs @@ -36,6 +36,7 @@ using XenAdmin.Network; using XenAdmin.Actions; using XenAdmin.Core; using XenAPI; +using System.Text; namespace XenAdmin.Alerts @@ -43,7 +44,8 @@ namespace XenAdmin.Alerts public class XenServerPatchAlert : XenServerUpdateAlert { public XenServerPatch Patch; - + public XenServerVersion NewServerVersion; + /// /// Can we apply this alert. Calling this sets the CannotApplyReason where applicable /// @@ -83,9 +85,17 @@ namespace XenAdmin.Alerts return !host.CanApplyHotfixes(); } - public XenServerPatchAlert(XenServerPatch patch) + /// + /// Creates a patch alert + /// + /// The patch + /// The version that the patch installs, or null if the patch doesn't update the server version + public XenServerPatchAlert(XenServerPatch patch, XenServerVersion newServerVersion = null) { Patch = patch; + NewServerVersion = newServerVersion; + if (NewServerVersion != null) + RequiredXenCenterVersion = Updates.GetRequiredXenCenterVersion(NewServerVersion); _priority = patch.Priority; _timestamp = Patch.TimeStamp; } @@ -114,15 +124,30 @@ namespace XenAdmin.Alerts { get { + StringBuilder sb = new StringBuilder(); + sb.Append(Patch.Description); if (Patch.InstallationSize != 0) - return string.Format(Messages.PATCH_DESCRIPTION_AND_INSTALLATION_SIZE, Patch.Description, Util.DiskSizeString(Patch.InstallationSize)); - return Patch.Description; + { + sb.AppendLine(); + sb.AppendFormat(Messages.PATCH_INSTALLATION_SIZE, Util.DiskSizeString(Patch.InstallationSize)); + } + if (RequiredXenCenterVersion != null) + { + sb.AppendLine(); + sb.AppendFormat(Messages.PATCH_NEEDS_NEW_XENCENTER, RequiredXenCenterVersion.Version); + } + return sb.ToString(); } } public override string Name { - get { return Patch.Name; } + get + { + if (ShowAsNewVersion) + return NewServerVersion.Name; + return Patch.Name; + } } public override Action FixLinkAction @@ -148,7 +173,12 @@ namespace XenAdmin.Alerts public override string Title { - get { return string.Format(Messages.NEW_UPDATE_AVAILABLE, Patch.Name); } + get + { + if (ShowAsNewVersion) + return string.Format(Messages.DOWLOAD_LATEST_XS_TITLE, NewServerVersion.Name); + return string.Format(Messages.NEW_UPDATE_AVAILABLE, Patch.Name); + } } public override bool IsDismissed() @@ -185,5 +215,13 @@ namespace XenAdmin.Alerts } return base.Equals(other); } + + public bool ShowAsNewVersion + { + get + { + return NewServerVersion != null && !NewServerVersion.PresentAsUpdate; + } + } } } diff --git a/XenAdmin/Alerts/Types/XenServerUpdateAlert.cs b/XenAdmin/Alerts/Types/XenServerUpdateAlert.cs index 1eff35c0d..42b4ca27c 100644 --- a/XenAdmin/Alerts/Types/XenServerUpdateAlert.cs +++ b/XenAdmin/Alerts/Types/XenServerUpdateAlert.cs @@ -45,6 +45,8 @@ namespace XenAdmin.Alerts protected readonly List connections = new List(); private readonly List hosts = new List(); + public XenCenterVersion RequiredXenCenterVersion; + public bool CanIgnore { get { return (connections.Count == 0 && hosts.Count == 0) || IsDismissed(); } diff --git a/XenAdmin/Alerts/Types/XenServerVersionAlert.cs b/XenAdmin/Alerts/Types/XenServerVersionAlert.cs index caa0a676a..4851393b4 100644 --- a/XenAdmin/Alerts/Types/XenServerVersionAlert.cs +++ b/XenAdmin/Alerts/Types/XenServerVersionAlert.cs @@ -47,6 +47,7 @@ namespace XenAdmin.Alerts public XenServerVersionAlert(XenServerVersion version) { Version = version; + RequiredXenCenterVersion = Updates.GetRequiredXenCenterVersion(Version); _timestamp = version.TimeStamp; } diff --git a/XenAdmin/Core/Updates.cs b/XenAdmin/Core/Updates.cs index 850614e8a..f6608a288 100644 --- a/XenAdmin/Core/Updates.cs +++ b/XenAdmin/Core/Updates.cs @@ -305,13 +305,13 @@ namespace XenAdmin.Core XenServerPatches = action.XenServerPatches; } - var xenCenterAlert = NewXenCenterUpdateAlert(XenCenterVersions, Program.Version); - if (xenCenterAlert != null && !xenCenterAlert.IsDismissed()) - updateAlerts.Add(xenCenterAlert); + var xenCenterAlerts = NewXenCenterUpdateAlerts(XenCenterVersions, Program.Version); + if (xenCenterAlerts != null) + updateAlerts.AddRange(xenCenterAlerts.Where(a=>!a.IsDismissed())); - var xenServerUpdateAlert = NewXenServerVersionAlert(XenServerVersionsForAutoCheck); - if (xenServerUpdateAlert != null && !xenServerUpdateAlert.CanIgnore) - updateAlerts.Add(xenServerUpdateAlert); + var xenServerUpdateAlerts = NewXenServerVersionAlerts(XenServerVersionsForAutoCheck); + if (xenServerUpdateAlerts != null) + updateAlerts.AddRange(xenServerUpdateAlerts.Where(a=>!a.CanIgnore)); var xenServerPatchAlerts = NewXenServerPatchAlerts(XenServerVersions, XenServerPatches); if (xenServerPatchAlerts != null) @@ -354,33 +354,47 @@ namespace XenAdmin.Core } - public static XenCenterUpdateAlert NewXenCenterUpdateAlert(List xenCenterVersions, Version currentProgramVersion) + public static List NewXenCenterUpdateAlerts(List xenCenterVersions, + Version currentProgramVersion) { if (Helpers.CommonCriteriaCertificationRelease) return null; - - XenCenterVersion toUse = null; + var alerts = new List(); + XenCenterVersion latest = null, latestCr = null; if (xenCenterVersions.Count != 0 && currentProgramVersion != new Version(0, 0, 0, 0)) { - var latest = from v in xenCenterVersions where v.IsLatest select v; + var latestVersions = from v in xenCenterVersions where v.Latest select v; + latest = latestVersions.FirstOrDefault(xcv => xcv.Lang == Program.CurrentLanguage) ?? + latestVersions.FirstOrDefault(xcv => string.IsNullOrEmpty(xcv.Lang)); - toUse = latest.FirstOrDefault(xcv => xcv.Lang == Program.CurrentLanguage) ?? - latest.FirstOrDefault(xcv => string.IsNullOrEmpty(xcv.Lang)); + if (IsSuitableForXenCenterAlert(latest, currentProgramVersion)) + alerts.Add(new XenCenterUpdateAlert(latest)); + + var latestCrVersions = from v in xenCenterVersions where v.LatestCr select v; + latestCr = latestCrVersions.FirstOrDefault(xcv => xcv.Lang == Program.CurrentLanguage) ?? + latestCrVersions.FirstOrDefault(xcv => string.IsNullOrEmpty(xcv.Lang)); + + if (latestCr != latest && IsSuitableForXenCenterAlert(latestCr, currentProgramVersion)) + alerts.Add(new XenCenterUpdateAlert(latestCr)); } - if (toUse == null) - return null; - - if (toUse.Version > currentProgramVersion || - (toUse.Version == currentProgramVersion && toUse.Lang == Program.CurrentLanguage && - !PropertyManager.IsCultureLoaded(Program.CurrentCulture))) + if (alerts.Count == 0) { - return new XenCenterUpdateAlert(toUse); + log.Info(string.Format("Not alerting XenCenter update - latest = {0}, latestcr = {1}, detected = {2}", + latest != null ? latest.VersionAndLang : "", latestCr != null ? latestCr.VersionAndLang : "", Program.VersionAndLanguage)); } - log.Info(string.Format("Not alerting XenCenter update - lastest = {0}, detected = {1}", - toUse.VersionAndLang, Program.VersionAndLanguage)); - return null; + return alerts; + } + + private static bool IsSuitableForXenCenterAlert(XenCenterVersion toUse, Version currentProgramVersion) + { + if (toUse == null) + return false; + + return toUse.Version > currentProgramVersion || + (toUse.Version == currentProgramVersion && toUse.Lang == Program.CurrentLanguage && + !PropertyManager.IsCultureLoaded(Program.CurrentCulture)); } public static List NewXenServerPatchAlerts(List xenServerVersions, @@ -391,6 +405,8 @@ namespace XenAdmin.Core var alerts = new List(); + var xenServerVersionsAsUpdates = xenServerVersions.Where(v => v.IsVersionAvailableAsAnUpdate); + foreach (IXenConnection xenConnection in ConnectionsManager.XenConnectionsCopy) { Host master = Helpers.GetMaster(xenConnection); @@ -399,15 +415,7 @@ namespace XenAdmin.Core if (master == null || pool == null) continue; - var serverVersions = xenServerVersions.FindAll(version => - { - if (version.BuildNumber != string.Empty) - return (master.BuildNumberRaw() == version.BuildNumber); - - return Helpers.HostProductVersionWithOEM(master) == version.VersionAndOEM - || (version.Oem != null && Helpers.OEMName(master).StartsWith(version.Oem) - && Helpers.HostProductVersion(master) == version.Version.ToString()); - }); + var serverVersions = GetServerVersions(master, xenServerVersions); if (serverVersions.Count == 0) continue; @@ -422,7 +430,9 @@ namespace XenAdmin.Core foreach (XenServerPatch xenServerPatch in patches) { - var alert = new XenServerPatchAlert(xenServerPatch); + XenServerVersion newServerVersion = xenServerVersionsAsUpdates.FirstOrDefault(newVersion => newVersion.PatchUuid.Equals(xenServerPatch.Uuid, StringComparison.OrdinalIgnoreCase)); + + var alert = new XenServerPatchAlert(xenServerPatch, newServerVersion); var existingAlert = alerts.Find(al => al.Equals(alert)); if (existingAlert != null) @@ -435,46 +445,8 @@ namespace XenAdmin.Core XenServerPatch serverPatch = xenServerPatch; - // A patch can be installed on a host if: - // 1. it is not already installed and - // 2. the host has all the required patches installed and - // 3. the host doesn't have any of the conflicting patches installed - - var noPatchHosts = hosts.Where(host => - { - bool elyOrGreater = Helpers.ElyOrGreater(host); - var appliedUpdates = host.AppliedUpdates(); - var appliedPatches = host.AppliedPatches(); - - // 1. patch is not already installed - if (elyOrGreater && appliedUpdates.Any(update => string.Equals(update.uuid, serverPatch.Uuid, StringComparison.OrdinalIgnoreCase))) - return false; - else if (!elyOrGreater && appliedPatches.Any(patch => string.Equals(patch.uuid, serverPatch.Uuid, StringComparison.OrdinalIgnoreCase))) - return false; - - // 2. the host has all the required patches installed - if (serverPatch.RequiredPatches != null && serverPatch.RequiredPatches.Count > 0 && - !serverPatch.RequiredPatches - .All(requiredPatchUuid => - elyOrGreater && appliedUpdates.Any(update => string.Equals(update.uuid, requiredPatchUuid, StringComparison.OrdinalIgnoreCase)) - || !elyOrGreater && appliedPatches.Any(patch => string.Equals(patch.uuid, requiredPatchUuid, StringComparison.OrdinalIgnoreCase)) - ) - ) - return false; - - // 3. the host doesn't have any of the conflicting patches installed - if (serverPatch.ConflictingPatches != null && serverPatch.ConflictingPatches.Count > 0 && - serverPatch.ConflictingPatches - .Any(conflictingPatchUuid => - elyOrGreater && appliedUpdates.Any(update => string.Equals(update.uuid, conflictingPatchUuid, StringComparison.OrdinalIgnoreCase)) - || !elyOrGreater && appliedPatches.Any(patch => string.Equals(patch.uuid, conflictingPatchUuid, StringComparison.OrdinalIgnoreCase)) - ) - ) - return false; - - return true; - }); - + var noPatchHosts = hosts.Where(host => PatchCanBeInstalledOnHost(serverPatch, host)); + if (noPatchHosts.Count() == hosts.Count) alert.IncludeConnection(xenConnection); else @@ -485,6 +457,78 @@ namespace XenAdmin.Core return alerts; } + + private static bool PatchCanBeInstalledOnHost(XenServerPatch serverPatch, Host host) + { + Debug.Assert(serverPatch != null); + Debug.Assert(host != null); + // A patch can be installed on a host if: + // 1. it is not already installed and + // 2. the host has all the required patches installed and + // 3. the host doesn't have any of the conflicting patches installed + + bool elyOrGreater = Helpers.ElyOrGreater(host); + var appliedUpdates = host.AppliedUpdates(); + var appliedPatches = host.AppliedPatches(); + + // 1. patch is not already installed + if (elyOrGreater && appliedUpdates.Any(update => string.Equals(update.uuid, serverPatch.Uuid, StringComparison.OrdinalIgnoreCase))) + return false; + if (!elyOrGreater && appliedPatches.Any(patch => string.Equals(patch.uuid, serverPatch.Uuid, StringComparison.OrdinalIgnoreCase))) + return false; + + // 2. the host has all the required patches installed + if (serverPatch.RequiredPatches != null && serverPatch.RequiredPatches.Count > 0 && + !serverPatch.RequiredPatches + .All(requiredPatchUuid => + elyOrGreater && appliedUpdates.Any(update => string.Equals(update.uuid, requiredPatchUuid, StringComparison.OrdinalIgnoreCase)) + || !elyOrGreater && appliedPatches.Any(patch => string.Equals(patch.uuid, requiredPatchUuid, StringComparison.OrdinalIgnoreCase)) + ) + ) + return false; + + // 3. the host doesn't have any of the conflicting patches installed + if (serverPatch.ConflictingPatches != null && serverPatch.ConflictingPatches.Count > 0 && + serverPatch.ConflictingPatches + .Any(conflictingPatchUuid => + elyOrGreater && appliedUpdates.Any(update => string.Equals(update.uuid, conflictingPatchUuid, StringComparison.OrdinalIgnoreCase)) + || !elyOrGreater && appliedPatches.Any(patch => string.Equals(patch.uuid, conflictingPatchUuid, StringComparison.OrdinalIgnoreCase)) + ) + ) + return false; + + return true; + } + + + /// + /// Returns the latest XenCenter version or null, if the current version is the latest. + /// If a server version is provided, it returns the XenCenter version that is required to work with that server. + /// If no server version is provided it will return the latestCr XenCenter. + /// + /// + /// + public static XenCenterVersion GetRequiredXenCenterVersion(XenServerVersion serverVersion) + { + if (XenCenterVersions.Count == 0) + return null; + + var currentProgramVersion = Program.Version; + if (currentProgramVersion == new Version(0, 0, 0, 0)) + return null; + + var latestVersions = from v in XenCenterVersions where v.Latest select v; + var latest = latestVersions.FirstOrDefault(xcv => xcv.Lang == Program.CurrentLanguage) ?? + latestVersions.FirstOrDefault(xcv => string.IsNullOrEmpty(xcv.Lang)); + + var latestCrVersions = from v in XenCenterVersions where v.LatestCr select v; + var latestCr = latestCrVersions.FirstOrDefault(xcv => xcv.Lang == Program.CurrentLanguage) ?? + latestCrVersions.FirstOrDefault(xcv => string.IsNullOrEmpty(xcv.Lang)); + + if (serverVersion != null && serverVersion.Latest && latest != null) + return latest.Version > currentProgramVersion ? latest : null; + return latestCr != null && latestCr.Version > currentProgramVersion ? latestCr : null; + } /// /// This method returns the minimal set of patches for a host if this class already has information about them. Otherwise it returns empty list. @@ -499,15 +543,7 @@ namespace XenAdmin.Core if (XenServerVersions == null) return null; - var serverVersions = XenServerVersions.FindAll(version => - { - if (version.BuildNumber != string.Empty) - return (host.BuildNumberRaw() == version.BuildNumber); - - return Helpers.HostProductVersionWithOEM(host) == version.VersionAndOEM - || (version.Oem != null && Helpers.OEMName(host).StartsWith(version.Oem) - && Helpers.HostProductVersion(host) == version.Version.ToString()); - }); + var serverVersions = GetServerVersions(host, XenServerVersions); if (serverVersions.Count != 0) { @@ -545,14 +581,27 @@ namespace XenAdmin.Core return null; var version = GetCommonServerVersionOfHostsInAConnection(conn, XenServerVersions); - + if (version != null) { if (version.MinimalPatches == null) return null; var uSeq = new UpgradeSequence(); - uSeq.MinimalPatches = version.MinimalPatches; + uSeq.MinimalPatches = new List(version.MinimalPatches); + + // if there is a "new version" update in the update sequence, also add the minimal patches of this new version + if (uSeq.MinimalPatches.Count > 0) + { + // assuming that the new version update (if there is one) is the last one in the minimal patches list + var lastUpdate = uSeq.MinimalPatches[uSeq.MinimalPatches.Count - 1]; + + var newServerVersion = XenServerVersions.FirstOrDefault( + v => v.IsVersionAvailableAsAnUpdate && v.PatchUuid.Equals(lastUpdate.Uuid, StringComparison.OrdinalIgnoreCase)); + + if (newServerVersion != null && newServerVersion.MinimalPatches != null) + uSeq.MinimalPatches.AddRange(newServerVersion.MinimalPatches); + } List hosts = conn.Cache.Hosts.ToList(); @@ -569,6 +618,52 @@ namespace XenAdmin.Core } } + /// + /// Gets an upgrade sequence that contains a version upgrade, optionally followed by the minimal patches for the new version + /// + /// Connection for the pool + /// The alert that refers the version-update + /// Also add the minimum patches for the new version (true) or not (false). + /// + public static UpgradeSequence GetUpgradeSequence(IXenConnection conn, XenServerPatchAlert alert, bool updateTheNewVersion) + { + Debug.Assert(conn != null); + Debug.Assert(alert != null); + + var uSeq = new UpgradeSequence(); + + if (XenServerVersions == null) + return null; + + Host master = Helpers.GetMaster(conn); + if (master == null) + return null; + + var version = GetCommonServerVersionOfHostsInAConnection(conn, XenServerVersions); + + // the pool has to be homogeneous + if (version != null) + { + uSeq.MinimalPatches = new List(); + uSeq.MinimalPatches.Add(alert.Patch); + + // if it's a version updgrade the min sequence will be this patch (the upgrade) and the min patches for the new version + if (updateTheNewVersion && alert.NewServerVersion != null && alert.NewServerVersion.MinimalPatches != null) + { + uSeq.MinimalPatches.AddRange(alert.NewServerVersion.MinimalPatches); + } + + conn.Cache.Hosts.ToList().ForEach(h => + uSeq[h] = GetUpgradeSequenceForHost(h, uSeq.MinimalPatches) + ); + + return uSeq; + } + + return null; + } + + /// /// Returns a XenServerVersion if all hosts of the pool have the same version /// Returns null if it is unknown or they don't match @@ -585,15 +680,7 @@ namespace XenAdmin.Core foreach (Host host in hosts) { - var hostVersions = xsVersions.FindAll(version => - { - if (version.BuildNumber != string.Empty) - return (host.BuildNumberRaw() == version.BuildNumber); - - return Helpers.HostProductVersionWithOEM(host) == version.VersionAndOEM - || (version.Oem != null && Helpers.OEMName(host).StartsWith(version.Oem) - && Helpers.HostProductVersion(host) == version.Version.ToString()); - }); + var hostVersions = GetServerVersions(host, xsVersions); var foundVersion = hostVersions.FirstOrDefault(); @@ -726,16 +813,31 @@ namespace XenAdmin.Core } } - public static XenServerVersionAlert NewXenServerVersionAlert(List xenServerVersions) + public static List NewXenServerVersionAlerts(List xenServerVersions) { if (Helpers.CommonCriteriaCertificationRelease) return null; var latestVersion = xenServerVersions.FindAll(item => item.Latest).OrderByDescending(v => v.Version).FirstOrDefault(); - if (latestVersion == null) - return null; + var latestCrVersion = xenServerVersions.FindAll(item => item.LatestCr).OrderByDescending(v => v.Version).FirstOrDefault(); - var alert = new XenServerVersionAlert(latestVersion); + List alerts = new List(); + + if (latestVersion != null) + alerts.Add(CreateAlertForXenServerVersion(latestVersion)); + + if (latestCrVersion != null && latestCrVersion != latestVersion) + alerts.Add(CreateAlertForXenServerVersion(latestCrVersion)); + + return alerts; + } + + private static XenServerVersionAlert CreateAlertForXenServerVersion(XenServerVersion version) + { + var alert = new XenServerVersionAlert(version); + + // the patch that installs this version, if any + var patch = XenServerPatches.FirstOrDefault(p => p.Uuid.Equals(version.PatchUuid, StringComparison.OrdinalIgnoreCase)); foreach (IXenConnection xc in ConnectionsManager.XenConnectionsCopy) { @@ -748,7 +850,12 @@ namespace XenAdmin.Core if (master == null || pool == null) continue; - var outOfDateHosts = hosts.Where(host => new Version(Helpers.HostProductVersion(host)) < latestVersion.Version); + // Show the Upgrade alert for a host if: + // - the host version is older than this version AND + // - there is no patch (amongst the current version patches) that can update to this version OR, if there is a patch, the patch cannot be installed + var patchApplicable = patch != null && GetServerVersions(master, XenServerVersions).Any(v => v.Patches.Contains(patch)); + var outOfDateHosts = hosts.Where(host => new Version(Helpers.HostProductVersion(host)) < version.Version + && (!patchApplicable || !PatchCanBeInstalledOnHost(patch, host))); if (outOfDateHosts.Count() == hosts.Count) alert.IncludeConnection(xc); @@ -759,14 +866,27 @@ namespace XenAdmin.Core return alert; } + private static List GetServerVersions(Host host, List xenServerVersions) + { + var serverVersions = xenServerVersions.FindAll(version => + { + if (version.BuildNumber != string.Empty) + return (host.BuildNumberRaw() == version.BuildNumber); + + return Helpers.HostProductVersionWithOEM(host) == version.VersionAndOEM + || (version.Oem != null && Helpers.OEMName(host).StartsWith(version.Oem) + && Helpers.HostProductVersion(host) == version.Version.ToString()); + }); + return serverVersions; + } public static void CheckServerVersion() { - var alert = NewXenServerVersionAlert(XenServerVersionsForAutoCheck); - if (alert == null) + var alerts = NewXenServerVersionAlerts(XenServerVersionsForAutoCheck); + if (alerts == null || alerts.Count == 0) return; - CheckUpdate(alert); + alerts.ForEach(a => CheckUpdate(a)); } public static void CheckServerPatches() @@ -775,8 +895,7 @@ namespace XenAdmin.Core if (alerts == null) return; - foreach (var alert in alerts) - CheckUpdate(alert); + alerts.ForEach(a => CheckUpdate(a)); } private static void CheckUpdate(XenServerUpdateAlert alert) diff --git a/XenAdmin/Diagnostics/Checks/XenCenterVersionCheck.cs b/XenAdmin/Diagnostics/Checks/XenCenterVersionCheck.cs new file mode 100644 index 000000000..2b017be1f --- /dev/null +++ b/XenAdmin/Diagnostics/Checks/XenCenterVersionCheck.cs @@ -0,0 +1,67 @@ +/* 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 XenAPI; +using XenAdmin.Diagnostics.Problems; +using XenAdmin.Core; +using XenAdmin.Diagnostics.Problems.PoolProblem; +using XenAdmin.Alerts; + + +namespace XenAdmin.Diagnostics.Checks +{ + public class XenCenterVersionCheck : Check + { + private XenServerVersion _newServerVersion; + + public XenCenterVersionCheck(XenServerVersion newServerVersion) + : base(null) + { + _newServerVersion = newServerVersion; + } + + protected override Problem RunCheck() + { + var requiredXenCenterVersion = Updates.GetRequiredXenCenterVersion(_newServerVersion); + if (requiredXenCenterVersion == null) + return null; + if (_newServerVersion != null) + return new XenCenterVersionProblem(this, requiredXenCenterVersion); + else + return new XenCenterVersionWarning(this, requiredXenCenterVersion); + } + + public override string Description + { + get { return Messages.XENCENTER_VERSION_CHECK_DESCRIPTION; } + } + } +} diff --git a/XenAdmin/Diagnostics/Problems/XenCenterVersionProblem.cs b/XenAdmin/Diagnostics/Problems/XenCenterVersionProblem.cs new file mode 100644 index 000000000..d18a02dd8 --- /dev/null +++ b/XenAdmin/Diagnostics/Problems/XenCenterVersionProblem.cs @@ -0,0 +1,109 @@ +/* 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 XenAdmin.Core; +using XenAdmin.Diagnostics.Checks; + +namespace XenAdmin.Diagnostics.Problems +{ + public class XenCenterVersionProblem : ProblemWithInformationUrl + { + private XenCenterVersion _requiredXenCenterVersion; + + public XenCenterVersionProblem(Check check, XenCenterVersion requiredXenCenterVersion) + : base(check) + { + _requiredXenCenterVersion = requiredXenCenterVersion; + } + + public override string Title + { + get { return Messages.PROBLEM_XENCENTER_VERSION_TITLE; } + } + + public override string Description + { + get { return string.Format(Messages.UPDATES_WIZARD_NEWER_XENCENTER_REQUIRED, _requiredXenCenterVersion.Version); } + } + + public override string HelpMessage + { + get { return LinkText; } + } + + public override string LinkText + { + get { return Messages.PATCHING_WIZARD_WEBPAGE_CELL; } + } + + public override Uri UriToLaunch + { + get { return new Uri(_requiredXenCenterVersion.Url); } + } + } + + public class XenCenterVersionWarning : WarningWithInformationUrl + { + private XenCenterVersion _requiredXenCenterVersion; + + public XenCenterVersionWarning(Check check, XenCenterVersion requiredXenCenterVersion) + : base(check) + { + _requiredXenCenterVersion = requiredXenCenterVersion; + } + + public override string Title + { + get { return Messages.PROBLEM_XENCENTER_VERSION_TITLE; } + } + + public override string Description + { + get { return string.Format(Messages.UPDATES_WIZARD_NEWER_XENCENTER_WARNING, _requiredXenCenterVersion.Version); } + } + + public override string HelpMessage + { + get { return LinkText; } + } + + public override string LinkText + { + get { return Messages.PATCHING_WIZARD_WEBPAGE_CELL; } + } + + public override Uri UriToLaunch + { + get { return new Uri(_requiredXenCenterVersion.Url); } + } + } +} diff --git a/XenAdmin/TabPages/ManageUpdatesPage.cs b/XenAdmin/TabPages/ManageUpdatesPage.cs index ec16f9a3f..ba6e82e01 100644 --- a/XenAdmin/TabPages/ManageUpdatesPage.cs +++ b/XenAdmin/TabPages/ManageUpdatesPage.cs @@ -39,7 +39,6 @@ using System.IO; using System.Linq; using System.Text; using System.Windows.Forms; - using XenAdmin.Actions; using XenAdmin.Alerts; using XenAdmin.Controls; @@ -75,7 +74,6 @@ namespace XenAdmin.TabPages InitializeProgressControls(); tableLayoutPanel1.Visible = false; UpdateButtonEnablement(); - dataGridViewUpdates.Sort(ColumnDate, ListSortDirection.Descending); informationLabel.Click += informationLabel_Click; m_updateCollectionChangedWithInvoke = Program.ProgramInvokeHandler(UpdatesCollectionChanged); Updates.RegisterCollectionChanged(m_updateCollectionChangedWithInvoke); @@ -584,19 +582,8 @@ namespace XenAdmin.TabPages updates.RemoveAll(FilterAlert); tableLayoutPanel3.Visible = false; ToggleWarningVisibility(SomeButNotAllUpdatesDisabled()); - - if (dataGridViewUpdates.SortedColumn != null) - { - if (dataGridViewUpdates.SortedColumn.Index == ColumnMessage.Index) - updates.Sort(Alert.CompareOnTitle); - else if (dataGridViewUpdates.SortedColumn.Index == ColumnDate.Index) - updates.Sort(Alert.CompareOnDate); - else if (dataGridViewUpdates.SortedColumn.Index == ColumnLocation.Index) - updates.Sort(Alert.CompareOnAppliesTo); - - if (dataGridViewUpdates.SortOrder == SortOrder.Descending) - updates.Reverse(); - } + + sortUpdates(updates); var rowList = new List(); @@ -829,13 +816,22 @@ namespace XenAdmin.TabPages items.Add(dismiss); } - if (patchAlert != null && patchAlert.CanApply && !string.IsNullOrEmpty(patchAlert.Patch.PatchUrl)) + if (patchAlert != null && patchAlert.CanApply && !string.IsNullOrEmpty(patchAlert.Patch.PatchUrl) && patchAlert.RequiredXenCenterVersion == null) { var download = new ToolStripMenuItem(Messages.UPDATES_DOWNLOAD_AND_INSTALL); download.Click += ToolStripMenuItemDownload_Click; items.Add(download); } + var updateAlert = alert as XenServerUpdateAlert; + + if (updateAlert != null && updateAlert.RequiredXenCenterVersion != null) + { + var downloadNewXenCenter = new ToolStripMenuItem(Messages.UPDATES_DOWNLOAD_REQUIRED_XENCENTER); + downloadNewXenCenter.Click += ToolStripMenuItemDownloadNewXenCenter_Click; + items.Add(downloadNewXenCenter); + } + if (!string.IsNullOrEmpty(alert.WebPageLabel)) { var fix = new ToolStripMenuItem(alert.FixLinkText); @@ -1091,6 +1087,24 @@ namespace XenAdmin.TabPages } } + private void ToolStripMenuItemDownloadNewXenCenter_Click(object sender, EventArgs e) + { + DataGridViewRow clickedRow = FindAlertRow(sender as ToolStripMenuItem); + if (clickedRow == null) + return; + + XenServerUpdateAlert updateAlert = (XenServerUpdateAlert)clickedRow.Tag; + + if (updateAlert == null || updateAlert.RequiredXenCenterVersion == null) + return; + + string xenCenterUrl = updateAlert.RequiredXenCenterVersion.Url; + if (string.IsNullOrEmpty(xenCenterUrl)) + return; + + Program.Invoke(Program.MainWindow, () => Program.OpenURL(xenCenterUrl)); + } + private void ToolStripMenuItemCopy_Click(object sender, EventArgs e) { DataGridViewRow clickedRow = FindAlertRow(sender as ToolStripMenuItem); @@ -1396,6 +1410,26 @@ namespace XenAdmin.TabPages } } } + + private void sortUpdates(List updatesList) + { + if (dataGridViewUpdates.SortedColumn != null) + { + if (dataGridViewUpdates.SortedColumn.Index == ColumnMessage.Index) + updatesList.Sort(Alert.CompareOnTitle); + else if (dataGridViewUpdates.SortedColumn.Index == ColumnDate.Index) + updatesList.Sort(Alert.CompareOnDate); + else if (dataGridViewUpdates.SortedColumn.Index == ColumnLocation.Index) + updatesList.Sort(Alert.CompareOnAppliesTo); + + if (dataGridViewUpdates.SortOrder == SortOrder.Descending) + updatesList.Reverse(); + } + else + { + updatesList.Sort(new NewVersionPriorityAlertComparer()); + } + } private void checkForUpdatesNowButton_Click(object sender, EventArgs e) { diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard.cs b/XenAdmin/Wizards/PatchingWizard/PatchingWizard.cs index 9b2c33adf..bb8776496 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard.cs +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard.cs @@ -42,6 +42,8 @@ using XenAdmin.Core; namespace XenAdmin.Wizards.PatchingWizard { + public enum WizardMode { SingleUpdate, AutomatedUpdates, NewVersion } + /// /// Remember that equals for patches dont work across connections because /// we are not allow to override equals. YOU SHOULD NOT USE ANY OPERATION THAT IMPLIES CALL EQUALS OF Pool_path or Host_patch @@ -85,6 +87,7 @@ namespace XenAdmin.Wizards.PatchingWizard PatchingWizard_SelectPatchPage.SelectDownloadAlert(alert); PatchingWizard_SelectPatchPage.SelectedUpdateAlert = alert; PatchingWizard_SelectServers.SelectedUpdateAlert = alert; + PatchingWizard_PrecheckPage.UpdateAlert = alert; PatchingWizard_UploadPage.SelectedUpdateAlert = alert; } @@ -105,7 +108,8 @@ namespace XenAdmin.Wizards.PatchingWizard if (prevPageType == typeof(PatchingWizard_SelectPatchPage)) { - var wizardIsInAutomatedUpdatesMode = PatchingWizard_SelectPatchPage.IsInAutomatedUpdatesMode; + var wizardMode = PatchingWizard_SelectPatchPage.WizardMode; + var wizardIsInAutomatedUpdatesMode = wizardMode == WizardMode.AutomatedUpdates; var updateType = wizardIsInAutomatedUpdatesMode ? UpdateType.NewRetail : PatchingWizard_SelectPatchPage.SelectedUpdateType; var newPatch = wizardIsInAutomatedUpdatesMode ? null : PatchingWizard_SelectPatchPage.SelectedNewPatch; @@ -113,7 +117,7 @@ namespace XenAdmin.Wizards.PatchingWizard var alertPatch = wizardIsInAutomatedUpdatesMode ? null : PatchingWizard_SelectPatchPage.SelectedUpdateAlert; var fileFromDiskAlertPatch = wizardIsInAutomatedUpdatesMode ? null : PatchingWizard_SelectPatchPage.FileFromDiskAlert; - PatchingWizard_SelectServers.IsInAutomaticMode = wizardIsInAutomatedUpdatesMode; + PatchingWizard_SelectServers.WizardMode = wizardMode; PatchingWizard_SelectServers.SelectedUpdateType = updateType; PatchingWizard_SelectServers.Patch = existPatch; PatchingWizard_SelectServers.SelectedUpdateAlert = alertPatch; @@ -123,13 +127,13 @@ namespace XenAdmin.Wizards.PatchingWizard RemovePage(PatchingWizard_ModePage); RemovePage(PatchingWizard_PatchingPage); RemovePage(PatchingWizard_AutomatedUpdatesPage); - if (!wizardIsInAutomatedUpdatesMode) + if (wizardMode == WizardMode.SingleUpdate) { AddAfterPage(PatchingWizard_SelectServers, PatchingWizard_UploadPage); AddAfterPage(PatchingWizard_PrecheckPage, PatchingWizard_ModePage); AddAfterPage(PatchingWizard_ModePage, PatchingWizard_PatchingPage); } - else + else // AutomatedUpdates or NewVersion { AddAfterPage(PatchingWizard_PrecheckPage, PatchingWizard_AutomatedUpdatesPage); } @@ -140,19 +144,19 @@ namespace XenAdmin.Wizards.PatchingWizard PatchingWizard_UploadPage.SelectedUpdateAlert = alertPatch; PatchingWizard_ModePage.Patch = existPatch; - PatchingWizard_ModePage.SelectedUpdateAlert = alertPatch; - - PatchingWizard_PrecheckPage.IsInAutomatedUpdatesMode = wizardIsInAutomatedUpdatesMode; - PatchingWizard_PrecheckPage.Patch = existPatch; - PatchingWizard_PrecheckPage.PoolUpdate = null; //reset the PoolUpdate property; it will be updated on leaving the Upload page, if this page is visible - - PatchingWizard_PatchingPage.Patch = existPatch; - - PatchingWizard_PrecheckPage.SelectedUpdateType = updateType; - PatchingWizard_ModePage.SelectedUpdateType = updateType; + PatchingWizard_PrecheckPage.WizardMode = wizardMode; + PatchingWizard_PrecheckPage.Patch = existPatch; + PatchingWizard_PrecheckPage.PoolUpdate = null; //reset the PoolUpdate property; it will be updated on leaving the Upload page, if this page is visible + PatchingWizard_PrecheckPage.SelectedUpdateType = updateType; + PatchingWizard_PrecheckPage.UpdateAlert = alertPatch ?? fileFromDiskAlertPatch; + + PatchingWizard_AutomatedUpdatesPage.WizardMode = wizardMode; + PatchingWizard_AutomatedUpdatesPage.UpdateAlert = alertPatch ?? fileFromDiskAlertPatch; + PatchingWizard_PatchingPage.SelectedUpdateType = updateType; + PatchingWizard_PatchingPage.Patch = existPatch; PatchingWizard_PatchingPage.SelectedNewPatch = newPatch; } else if (prevPageType == typeof(PatchingWizard_SelectServers)) @@ -160,8 +164,10 @@ namespace XenAdmin.Wizards.PatchingWizard var selectedServers = PatchingWizard_SelectServers.SelectedServers; var selectedPools = PatchingWizard_SelectServers.SelectedPools; var selectedMasters = PatchingWizard_SelectServers.SelectedMasters; + var applyUpdatesToNewVersion = PatchingWizard_SelectServers.ApplyUpdatesToNewVersion; PatchingWizard_PrecheckPage.SelectedServers = selectedServers; + PatchingWizard_PrecheckPage.ApplyUpdatesToNewVersion = applyUpdatesToNewVersion; PatchingWizard_ModePage.SelectedServers = selectedServers; @@ -173,6 +179,7 @@ namespace XenAdmin.Wizards.PatchingWizard PatchingWizard_UploadPage.SelectedServers = selectedServers; PatchingWizard_AutomatedUpdatesPage.SelectedPools = selectedPools; + PatchingWizard_AutomatedUpdatesPage.ApplyUpdatesToNewVersion = applyUpdatesToNewVersion; } else if (prevPageType == typeof(PatchingWizard_UploadPage)) { @@ -328,11 +335,9 @@ namespace XenAdmin.Wizards.PatchingWizard private void RemoveDownloadedPatches() { - var isInAutomaticMode = PatchingWizard_SelectPatchPage.IsInAutomatedUpdatesMode; - List listOfDownloadedFiles = new List(); - if (isInAutomaticMode) + if (PatchingWizard_SelectPatchPage.WizardMode != WizardMode.SingleUpdate) // AutomatedUpdates or NewVersion { listOfDownloadedFiles.AddRange(PatchingWizard_AutomatedUpdatesPage.AllDownloadedPatches.Values); } diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.cs b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.cs index 5d3e8334f..e44937623 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.cs +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.cs @@ -48,6 +48,7 @@ using XenAdmin.Core; using XenAdmin.Network; using System.Text; using System.Diagnostics; +using XenAdmin.Alerts; namespace XenAdmin.Wizards.PatchingWizard { @@ -62,6 +63,10 @@ namespace XenAdmin.Wizards.PatchingWizard public List SelectedPools { private get; set; } + public XenServerPatchAlert UpdateAlert { private get; set; } + public WizardMode WizardMode { private get; set; } + public bool ApplyUpdatesToNewVersion { private get; set; } + private List patchMappings = new List(); public Dictionary AllDownloadedPatches = new Dictionary(); @@ -135,6 +140,17 @@ namespace XenAdmin.Wizards.PatchingWizard return; } + Debug.Assert(WizardMode == WizardMode.AutomatedUpdates || WizardMode == WizardMode.NewVersion && UpdateAlert != null); + + if (WizardMode == WizardMode.AutomatedUpdates) + { + 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; + } + foreach (var pool in SelectedPools) { var master = Helpers.GetMaster(pool.Connection); @@ -150,7 +166,12 @@ namespace XenAdmin.Wizards.PatchingWizard var hosts = pool.Connection.Cache.Hosts; - var us = Updates.GetUpgradeSequence(pool.Connection); + //if any host is not licensed for automated updates + bool automatedUpdatesRestricted = pool.Connection.Cache.Hosts.Any(Host.RestrictBatchHotfixApply); + + var us = WizardMode == WizardMode.NewVersion + ? Updates.GetUpgradeSequence(pool.Connection, UpdateAlert, ApplyUpdatesToNewVersion && !automatedUpdatesRestricted) + : Updates.GetUpgradeSequence(pool.Connection); Debug.Assert(us != null, "Update sequence should not be null."); @@ -627,7 +648,15 @@ namespace XenAdmin.Wizards.PatchingWizard private void AllWorkersFinished() { - labelTitle.Text = Messages.PATCHINGWIZARD_UPDATES_DONE_AUTOMATED_UPDATES_MODE; + if (WizardMode == WizardMode.AutomatedUpdates) + { + labelTitle.Text = Messages.PATCHINGWIZARD_UPDATES_DONE_AUTOMATED_UPDATES_MODE; + } + else if (WizardMode == WizardMode.NewVersion) + { + labelTitle.Text = Messages.PATCHINGWIZARD_UPDATES_DONE_AUTOMATED_NEW_VERSION_MODE; + } + progressBar.Value = 100; pictureBox1.Image = null; labelError.Text = Messages.CLOSE_WIZARD_CLICK_FINISH; diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.designer.cs b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.designer.cs index ff3e62b60..5e050846b 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.designer.cs +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.designer.cs @@ -86,7 +86,7 @@ namespace XenAdmin.Wizards.PatchingWizard this.errorLinkLabel.Name = "errorLinkLabel"; this.errorLinkLabel.TabStop = true; // - // PatchingWizard_AutoUpdatingPage + // PatchingWizard_AutomatedUpdatesPage // resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; @@ -94,7 +94,7 @@ namespace XenAdmin.Wizards.PatchingWizard this.Controls.Add(this.progressBar); this.Controls.Add(this.textBoxLog); this.Controls.Add(this.labelTitle); - this.Name = "PatchingWizard_AutoUpdatingPage"; + this.Name = "PatchingWizard_AutomatedUpdatesPage"; ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.resx b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.resx index 4d228a90d..0a85152a6 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.resx +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_AutomatedUpdatesPage.resx @@ -126,14 +126,11 @@ 3, 13 - 92, 13 + 0, 13 0 - - Installing updates: - labelTitle @@ -355,7 +352,7 @@ 511, 335 - PatchingWizard_AutoUpdatingPage + PatchingWizard_AutomatedUpdatesPage XenAdmin.Controls.XenTabPage, XenCenterMain, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_ModePage.cs b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_ModePage.cs index 5ca8298c7..b0d98f64d 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_ModePage.cs +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_ModePage.cs @@ -45,8 +45,6 @@ namespace XenAdmin.Wizards.PatchingWizard { private bool _tooltipShowing; - public XenServerPatchAlert SelectedUpdateAlert { private get; set; } - public PatchingWizard_ModePage() { InitializeComponent(); diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_PrecheckPage.cs b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_PrecheckPage.cs index 1899af844..09801c586 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_PrecheckPage.cs +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_PrecheckPage.cs @@ -37,6 +37,7 @@ using System.Linq; using System.Threading; using System.Windows.Forms; using XenAdmin.Actions; +using XenAdmin.Alerts; using XenAdmin.Controls; using XenAdmin.Core; using XenAdmin.Diagnostics.Checks; @@ -55,7 +56,6 @@ namespace XenAdmin.Wizards.PatchingWizard private BackgroundWorker _worker = null; public List SelectedServers = new List(); public List ProblemsResolvedPreCheck = new List(); - public bool IsInAutomatedUpdatesMode { get; set; } private AsyncAction resolvePrechecksAction = null; protected List SelectedPools @@ -66,6 +66,10 @@ namespace XenAdmin.Wizards.PatchingWizard } } + public XenServerPatchAlert UpdateAlert { private get; set; } + public WizardMode WizardMode { private get; set; } + public bool ApplyUpdatesToNewVersion { private get; set; } + public PatchingWizard_PrecheckPage() { InitializeComponent(); @@ -123,7 +127,7 @@ namespace XenAdmin.Wizards.PatchingWizard if (direction == PageLoadedDirection.Back) return; - if (IsInAutomatedUpdatesMode) + if (WizardMode == WizardMode.AutomatedUpdates) { labelPrechecksFirstLine.Text = Messages.PATCHINGWIZARD_PRECHECKPAGE_FIRSTLINE_AUTOMATED_UPDATES_MODE; } @@ -346,10 +350,19 @@ namespace XenAdmin.Wizards.PatchingWizard protected virtual List>> GenerateCommonChecks(List applicableServers) { List>> checks = new List>>(); + List checkGroup; + + //XenCenter version check + if (UpdateAlert != null && UpdateAlert.NewServerVersion != null) + { + checks.Add(new KeyValuePair>(Messages.CHECKING_XENCENTER_VERSION, new List())); + checkGroup = checks[checks.Count - 1].Value; + checkGroup.Add(new XenCenterVersionCheck(UpdateAlert.NewServerVersion)); + } //HostLivenessCheck checks checks.Add(new KeyValuePair>(Messages.CHECKING_HOST_LIVENESS_STATUS, new List())); - List checkGroup = checks[checks.Count - 1].Value; + checkGroup = checks[checks.Count - 1].Value; foreach (Host host in applicableServers) { checkGroup.Add(new HostLivenessCheck(host)); @@ -373,14 +386,24 @@ namespace XenAdmin.Wizards.PatchingWizard } //Disk space check for automated updates - if (IsInAutomatedUpdatesMode) + if (WizardMode != WizardMode.SingleUpdate) { checks.Add(new KeyValuePair>(Messages.PATCHINGWIZARD_PRECHECKPAGE_CHECKING_DISK_SPACE, new List())); checkGroup = checks[checks.Count - 1].Value; foreach (Pool pool in SelectedPools) { - var us = Updates.GetUpgradeSequence(pool.Connection); + //if any host is not licensed for automated updates + bool automatedUpdatesRestricted = pool.Connection.Cache.Hosts.Any(Host.RestrictBatchHotfixApply); + + var us = WizardMode == WizardMode.NewVersion + ? Updates.GetUpgradeSequence(pool.Connection, UpdateAlert, ApplyUpdatesToNewVersion && !automatedUpdatesRestricted) + : Updates.GetUpgradeSequence(pool.Connection); + + log.InfoFormat("Minimal patches for {0}: {1}", pool.Name(), us != null && us.MinimalPatches != null ? string.Join(",", us.MinimalPatches.Select(p => p.Name)) : ""); + + if (us == null) + continue; bool elyOrGreater = Helpers.ElyOrGreater(pool.Connection); @@ -399,6 +422,26 @@ namespace XenAdmin.Wizards.PatchingWizard } } + //Checking reboot required and can evacuate host for version updates + if (WizardMode == Wizards.PatchingWizard.WizardMode.NewVersion && UpdateAlert != null && UpdateAlert.Patch != null && UpdateAlert.Patch.after_apply_guidance == after_apply_guidance.restartHost) + { + checks.Add(new KeyValuePair>(Messages.CHECKING_SERVER_NEEDS_REBOOT, new List())); + checkGroup = checks[checks.Count - 1].Value; + var guidance = new List() { UpdateAlert.Patch.after_apply_guidance }; + + foreach (var host in SelectedServers) + { + checkGroup.Add(new HostNeedsRebootCheck(host, guidance, LivePatchCodesByHost)); + } + + checks.Add(new KeyValuePair>(Messages.CHECKING_CANEVACUATE_STATUS, new List())); + checkGroup = checks[checks.Count - 1].Value; + foreach (Host host in SelectedServers) + { + checkGroup.Add(new AssertCanEvacuateCheck(host, LivePatchCodesByHost)); + } + } + return checks; } @@ -424,7 +467,7 @@ namespace XenAdmin.Wizards.PatchingWizard } //Checking if the host needs a reboot - if (!IsInAutomatedUpdatesMode) + if (WizardMode == WizardMode.SingleUpdate) { checks.Add(new KeyValuePair>(Messages.CHECKING_SERVER_NEEDS_REBOOT, new List())); checkGroup = checks[checks.Count - 1].Value; @@ -440,7 +483,7 @@ namespace XenAdmin.Wizards.PatchingWizard //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)) + if (WizardMode != WizardMode.NewVersion && (patch == null || patch.after_apply_guidance.Contains(after_apply_guidance.restartHost))) { checks.Add(new KeyValuePair>(Messages.CHECKING_CANEVACUATE_STATUS, new List())); checkGroup = checks[checks.Count - 1].Value; @@ -474,7 +517,7 @@ namespace XenAdmin.Wizards.PatchingWizard } //Checking if the host needs a reboot - if (!IsInAutomatedUpdatesMode) + if (WizardMode == WizardMode.SingleUpdate) { checks.Add(new KeyValuePair>(Messages.CHECKING_SERVER_NEEDS_REBOOT, new List())); checkGroup = checks[checks.Count - 1].Value; @@ -649,7 +692,9 @@ namespace XenAdmin.Wizards.PatchingWizard { description = _check.SuccessfulCheckDescription; if (string.IsNullOrEmpty(description)) - description = String.Format(Messages.PATCHING_WIZARD_HOST_CHECK_OK, _check.Host.Name(), _check.Description); + description = _check.Host != null + ? String.Format(Messages.PATCHING_WIZARD_HOST_CHECK_OK, _check.Host.Name(), _check.Description) + : String.Format(Messages.PATCHING_WIZARD_CHECK_OK, _check.Description); } if (description != string.Empty) diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.Designer.cs b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.Designer.cs index 26109778d..227d48c68 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.Designer.cs +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.Designer.cs @@ -31,12 +31,13 @@ namespace XenAdmin.Wizards.PatchingWizard private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PatchingWizard_SelectPatchPage)); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle7 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.labelWithoutAutomatedUpdates = new System.Windows.Forms.Label(); this.labelWithAutomatedUpdates = new System.Windows.Forms.Label(); @@ -213,28 +214,28 @@ namespace XenAdmin.Wizards.PatchingWizard this.ColumnDescription, this.ColumnDate, this.webPageColumn}); - dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle4.BackColor = System.Drawing.SystemColors.Window; - dataGridViewCellStyle4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - dataGridViewCellStyle4.ForeColor = System.Drawing.SystemColors.ControlText; - dataGridViewCellStyle4.SelectionBackColor = System.Drawing.SystemColors.Window; - dataGridViewCellStyle4.SelectionForeColor = System.Drawing.SystemColors.ControlText; - dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.False; - this.dataGridViewPatches.DefaultCellStyle = dataGridViewCellStyle4; + dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle5.BackColor = System.Drawing.SystemColors.Window; + dataGridViewCellStyle5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + dataGridViewCellStyle5.ForeColor = System.Drawing.SystemColors.ControlText; + dataGridViewCellStyle5.SelectionBackColor = System.Drawing.SystemColors.Window; + dataGridViewCellStyle5.SelectionForeColor = System.Drawing.SystemColors.ControlText; + dataGridViewCellStyle5.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dataGridViewPatches.DefaultCellStyle = dataGridViewCellStyle5; resources.ApplyResources(this.dataGridViewPatches, "dataGridViewPatches"); this.dataGridViewPatches.HideSelection = true; this.dataGridViewPatches.Name = "dataGridViewPatches"; this.dataGridViewPatches.ReadOnly = true; - dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle5.BackColor = System.Drawing.SystemColors.Control; - dataGridViewCellStyle5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - dataGridViewCellStyle5.ForeColor = System.Drawing.SystemColors.WindowText; - dataGridViewCellStyle5.SelectionBackColor = System.Drawing.SystemColors.Highlight; - dataGridViewCellStyle5.SelectionForeColor = System.Drawing.SystemColors.HighlightText; - dataGridViewCellStyle5.WrapMode = System.Windows.Forms.DataGridViewTriState.False; - this.dataGridViewPatches.RowHeadersDefaultCellStyle = dataGridViewCellStyle5; - dataGridViewCellStyle6.WrapMode = System.Windows.Forms.DataGridViewTriState.True; - this.dataGridViewPatches.RowsDefaultCellStyle = dataGridViewCellStyle6; + dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle6.BackColor = System.Drawing.SystemColors.Control; + dataGridViewCellStyle6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + dataGridViewCellStyle6.ForeColor = System.Drawing.SystemColors.WindowText; + dataGridViewCellStyle6.SelectionBackColor = System.Drawing.SystemColors.Highlight; + dataGridViewCellStyle6.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle6.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dataGridViewPatches.RowHeadersDefaultCellStyle = dataGridViewCellStyle6; + dataGridViewCellStyle7.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.dataGridViewPatches.RowsDefaultCellStyle = dataGridViewCellStyle7; this.dataGridViewPatches.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.True; this.dataGridViewPatches.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridViewPatches_CellContentClick); this.dataGridViewPatches.CellMouseClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.dataGridViewPatches_CellMouseClick); @@ -279,6 +280,9 @@ namespace XenAdmin.Wizards.PatchingWizard // webPageColumn // this.webPageColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; + dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.TopLeft; + dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.webPageColumn.DefaultCellStyle = dataGridViewCellStyle4; this.webPageColumn.FillWeight = 60F; resources.ApplyResources(this.webPageColumn, "webPageColumn"); this.webPageColumn.Name = "webPageColumn"; @@ -317,10 +321,6 @@ namespace XenAdmin.Wizards.PatchingWizard private System.Windows.Forms.RadioButton downloadUpdateRadioButton; private System.Windows.Forms.Label labelWithAutomatedUpdates; private System.Windows.Forms.Button RestoreDismUpdatesButton; - private System.Windows.Forms.DataGridViewTextBoxColumn ColumnUpdate; - private System.Windows.Forms.DataGridViewTextBoxColumn ColumnDescription; - private System.Windows.Forms.DataGridViewTextBoxColumn ColumnDate; - private System.Windows.Forms.DataGridViewLinkColumn webPageColumn; private System.Windows.Forms.Label automatedUpdatesOptionLabel; private System.Windows.Forms.RadioButton AutomatedUpdatesRadioButton; private System.Windows.Forms.Label labelWithoutAutomatedUpdates; @@ -329,5 +329,9 @@ namespace XenAdmin.Wizards.PatchingWizard private System.Windows.Forms.TableLayoutPanel tableLayoutPanelSpinner; private System.Windows.Forms.PictureBox pictureBox1; private System.Windows.Forms.Label label1; + private System.Windows.Forms.DataGridViewTextBoxColumn ColumnUpdate; + private System.Windows.Forms.DataGridViewTextBoxColumn ColumnDescription; + private System.Windows.Forms.DataGridViewTextBoxColumn ColumnDate; + private System.Windows.Forms.DataGridViewLinkColumn webPageColumn; } } diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.cs b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.cs index d55b63888..6e38a761c 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.cs +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.cs @@ -64,8 +64,6 @@ namespace XenAdmin.Wizards.PatchingWizard labelWithAutomatedUpdates.Visible = automatedUpdatesOptionLabel.Visible = AutomatedUpdatesRadioButton.Visible = false; downloadUpdateRadioButton.Checked = true; - - dataGridViewPatches.Sort(ColumnDate, ListSortDirection.Descending); } private void CheckForUpdates_CheckForUpdatesStarted() @@ -170,7 +168,24 @@ namespace XenAdmin.Wizards.PatchingWizard firstLoad = false; } - public bool IsInAutomatedUpdatesMode { get { return AutomatedUpdatesRadioButton.Visible && AutomatedUpdatesRadioButton.Checked; } } + private bool IsInAutomatedUpdatesMode { get { return AutomatedUpdatesRadioButton.Visible && AutomatedUpdatesRadioButton.Checked; } } + + public WizardMode WizardMode + { + get + { + if (AutomatedUpdatesRadioButton.Visible && AutomatedUpdatesRadioButton.Checked) + return WizardMode.AutomatedUpdates; + var updateAlert = downloadUpdateRadioButton.Checked && dataGridViewPatches.SelectedRows.Count > 0 + ? (XenServerPatchAlert) ((PatchGridViewRow) dataGridViewPatches.SelectedRows[0]).UpdateAlert + : selectFromDiskRadioButton.Checked + ? GetAlertFromFileName(fileNameTextBox.Text.ToLowerInvariant()) + : null; + if (updateAlert != null && updateAlert.NewServerVersion != null) + return WizardMode.NewVersion; + return WizardMode.SingleUpdate; + } + } public override void PageLeave(PageLoadedDirection direction, ref bool cancel) { @@ -260,9 +275,9 @@ namespace XenAdmin.Wizards.PatchingWizard { foreach (PatchGridViewRow row in dataGridViewPatches.Rows) { - if (string.Equals(row.UpdateAlert.Name, Path.GetFileNameWithoutExtension(fileName), StringComparison.OrdinalIgnoreCase)) + if (string.Equals(row.UpdateAlert.Patch.Name, Path.GetFileNameWithoutExtension(fileName), StringComparison.OrdinalIgnoreCase)) { - return (XenServerPatchAlert)row.UpdateAlert; + return row.UpdateAlert; } } return null; @@ -282,7 +297,9 @@ namespace XenAdmin.Wizards.PatchingWizard private void PopulatePatchesBox() { dataGridViewPatches.Rows.Clear(); - var updates = new List(Updates.UpdateAlerts); + + var updates = Updates.UpdateAlerts.ToList(); + if (dataGridViewPatches.SortedColumn != null) { if (dataGridViewPatches.SortedColumn.Index == ColumnUpdate.Index) @@ -295,16 +312,29 @@ namespace XenAdmin.Wizards.PatchingWizard if (dataGridViewPatches.SortOrder == SortOrder.Descending) updates.Reverse(); } - foreach (Alert alert in updates) - { - if (alert is XenServerPatchAlert) - { - PatchGridViewRow row = new PatchGridViewRow(alert); - if (!dataGridViewPatches.Rows.Contains(row)) - { - dataGridViewPatches.Rows.Add(row); - } - } + else + { + updates.Sort(new NewVersionPriorityAlertComparer()); + } + + foreach (Alert alert in updates) + { + var patchAlert = alert as XenServerPatchAlert; + + if (patchAlert != null) + { + PatchGridViewRow row = new PatchGridViewRow(patchAlert); + if (!dataGridViewPatches.Rows.Contains(row)) + { + dataGridViewPatches.Rows.Add(row); + + if (patchAlert.RequiredXenCenterVersion != null) + { + row.Enabled = false; + row.SetToolTip(string.Format(Messages.UPDATES_WIZARD_NEWER_XENCENTER_REQUIRED, patchAlert.RequiredXenCenterVersion.Version)); + } + } + } } } @@ -535,7 +565,7 @@ namespace XenAdmin.Wizards.PatchingWizard private class PatchGridViewRow : DataGridViewExRow, IEquatable { - private readonly Alert _alert; + private readonly XenServerPatchAlert _alert; private bool expanded = false; @@ -549,7 +579,7 @@ namespace XenAdmin.Wizards.PatchingWizard private DataGridViewTextBoxCell _statusCell; private DataGridViewLinkCell _webPageCell; - public PatchGridViewRow(Alert alert) + public PatchGridViewRow(XenServerPatchAlert alert) { _alert = alert; _nameCell = new DataGridViewTextBoxCell(); @@ -575,7 +605,7 @@ namespace XenAdmin.Wizards.PatchingWizard SetupCells(); } - public Alert UpdateAlert + public XenServerPatchAlert UpdateAlert { get { return _alert; } } @@ -656,6 +686,19 @@ namespace XenAdmin.Wizards.PatchingWizard return this.Equals((PatchGridViewRow)obj); return false; } + + public void SetToolTip(string toolTip) + { + foreach (var c in Cells) + { + if (c is DataGridViewLinkCell) + continue; + + var cell = c as DataGridViewCell; + if (c != null) + ((DataGridViewCell)c).ToolTipText = toolTip; + } + } } #endregion diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.resx b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.resx index c0a4ebbf3..d4e913091 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.resx +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectPatchPage.resx @@ -241,13 +241,14 @@ 23, 83 - 575, 13 + 575, 26 3 - [XenCenter] will download and install all current updates from [Citrix], usually with only a single reboot at the end. + [XenCenter] will download and install all released updates on the current version from [Citrix], usually with only a single reboot at the end. + automatedUpdatesOptionLabel @@ -268,19 +269,19 @@ NoControl - 3, 108 + 3, 121 3, 12, 3, 3 - 163, 17 + 235, 17 4 - &Download update from [Citrix] + &Download update or new version from [Citrix] downloadUpdateRadioButton @@ -583,7 +584,7 @@ 1 - 178, 81 + 178, 75 1 @@ -664,7 +665,7 @@ Vertical - 575, 189 + 575, 176 0 @@ -685,10 +686,10 @@ Fill - 23, 131 + 23, 144 - 575, 189 + 575, 176 5 diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.Designer.cs b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.Designer.cs index e5c7d33d0..8192e5beb 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.Designer.cs +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.Designer.cs @@ -34,8 +34,7 @@ namespace XenAdmin.Wizards.PatchingWizard private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PatchingWizard_SelectServers)); - this.label1 = new System.Windows.Forms.Label(); - this.buttonSelectAll = new System.Windows.Forms.Button(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.buttonClearAll = new System.Windows.Forms.Button(); this.dataGridViewHosts = new XenAdmin.Wizards.PatchingWizard.PatchingWizard_SelectServers.PatchingHostsDataGridView(); this.ColumnPoolCheckBox = new System.Windows.Forms.DataGridViewCheckBoxColumn(); @@ -43,20 +42,22 @@ namespace XenAdmin.Wizards.PatchingWizard this.ColumnPoolIconHostCheck = new System.Windows.Forms.DataGridViewImageColumn(); this.ColumnName = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.ColumnVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.label1 = new System.Windows.Forms.Label(); + this.applyUpdatesCheckBox = new System.Windows.Forms.CheckBox(); + this.buttonSelectAll = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.dataGridViewHosts)).BeginInit(); this.SuspendLayout(); // - // label1 + // tableLayoutPanel1 // - resources.ApplyResources(this.label1, "label1"); - this.label1.Name = "label1"; - // - // buttonSelectAll - // - resources.ApplyResources(this.buttonSelectAll, "buttonSelectAll"); - this.buttonSelectAll.Name = "buttonSelectAll"; - this.buttonSelectAll.UseVisualStyleBackColor = true; - this.buttonSelectAll.Click += new System.EventHandler(this.buttonSelectAll_Click); + resources.ApplyResources(this.tableLayoutPanel1, "tableLayoutPanel1"); + this.tableLayoutPanel1.Controls.Add(this.buttonClearAll, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.dataGridViewHosts, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.applyUpdatesCheckBox, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.buttonSelectAll, 0, 2); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; // // buttonClearAll // @@ -77,6 +78,7 @@ namespace XenAdmin.Wizards.PatchingWizard this.ColumnPoolIconHostCheck, this.ColumnName, this.ColumnVersion}); + this.tableLayoutPanel1.SetColumnSpan(this.dataGridViewHosts, 2); this.dataGridViewHosts.Name = "dataGridViewHosts"; this.dataGridViewHosts.Updating = false; // @@ -115,15 +117,36 @@ namespace XenAdmin.Wizards.PatchingWizard resources.ApplyResources(this.ColumnVersion, "ColumnVersion"); this.ColumnVersion.Name = "ColumnVersion"; // + // label1 + // + this.tableLayoutPanel1.SetColumnSpan(this.label1, 2); + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // applyUpdatesCheckBox + // + resources.ApplyResources(this.applyUpdatesCheckBox, "applyUpdatesCheckBox"); + this.applyUpdatesCheckBox.Checked = true; + this.applyUpdatesCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.tableLayoutPanel1.SetColumnSpan(this.applyUpdatesCheckBox, 2); + this.applyUpdatesCheckBox.Name = "applyUpdatesCheckBox"; + this.applyUpdatesCheckBox.UseVisualStyleBackColor = true; + // + // buttonSelectAll + // + resources.ApplyResources(this.buttonSelectAll, "buttonSelectAll"); + this.buttonSelectAll.Name = "buttonSelectAll"; + this.buttonSelectAll.UseVisualStyleBackColor = true; + this.buttonSelectAll.Click += new System.EventHandler(this.buttonSelectAll_Click); + // // PatchingWizard_SelectServers // resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.Controls.Add(this.dataGridViewHosts); - this.Controls.Add(this.buttonClearAll); - this.Controls.Add(this.buttonSelectAll); - this.Controls.Add(this.label1); + this.Controls.Add(this.tableLayoutPanel1); this.Name = "PatchingWizard_SelectServers"; + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.dataGridViewHosts)).EndInit(); this.ResumeLayout(false); @@ -131,14 +154,16 @@ namespace XenAdmin.Wizards.PatchingWizard #endregion - private Label label1; private Button buttonSelectAll; private Button buttonClearAll; - private XenAdmin.Wizards.PatchingWizard.PatchingWizard_SelectServers.PatchingHostsDataGridView dataGridViewHosts; + private TableLayoutPanel tableLayoutPanel1; + private CheckBox applyUpdatesCheckBox; + private PatchingWizard_SelectServers.PatchingHostsDataGridView dataGridViewHosts; private DataGridViewCheckBoxColumn ColumnPoolCheckBox; private DataGridViewImageColumn ColumnExpander; private DataGridViewImageColumn ColumnPoolIconHostCheck; private DataGridViewTextBoxColumn ColumnName; private DataGridViewTextBoxColumn ColumnVersion; + private Label label1; } } diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.cs b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.cs index 774515958..9b4fbd314 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.cs +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.cs @@ -43,6 +43,7 @@ using XenAdmin.Properties; using XenAPI; using XenAdmin.Alerts; using System.Linq; +using System.Diagnostics; namespace XenAdmin.Wizards.PatchingWizard { @@ -61,8 +62,8 @@ namespace XenAdmin.Wizards.PatchingWizard private bool poolSelectionOnly; public XenServerPatchAlert SelectedUpdateAlert { private get; set; } - public XenServerPatchAlert FileFromDiskAlert { private get; set; } + public WizardMode WizardMode { private get; set; } public PatchingWizard_SelectServers() { @@ -96,10 +97,20 @@ namespace XenAdmin.Wizards.PatchingWizard base.PageLoaded(direction); try { - poolSelectionOnly = IsInAutomaticMode || SelectedUpdateAlert != null || FileFromDiskAlert != null; - label1.Text = IsInAutomaticMode - ? Messages.PATCHINGWIZARD_SELECTSERVERPAGE_RUBRIC_AUTOMATED_MODE - : poolSelectionOnly ? Messages.PATCHINGWIZARD_SELECTSERVERPAGE_RUBRIC_POOL_SELECTION : Messages.PATCHINGWIZARD_SELECTSERVERPAGE_RUBRIC_DEFAULT; + poolSelectionOnly = WizardMode == WizardMode.AutomatedUpdates || SelectedUpdateAlert != null || FileFromDiskAlert != null; + + switch (WizardMode) + { + case WizardMode.AutomatedUpdates : + label1.Text = Messages.PATCHINGWIZARD_SELECTSERVERPAGE_RUBRIC_AUTOMATED_MODE; + break; + case WizardMode.NewVersion : + label1.Text = Messages.PATCHINGWIZARD_SELECTSERVERPAGE_RUBRIC_NEW_VERSION_MODE; + break; + case WizardMode.SingleUpdate : + label1.Text = poolSelectionOnly ? Messages.PATCHINGWIZARD_SELECTSERVERPAGE_RUBRIC_POOL_SELECTION : Messages.PATCHINGWIZARD_SELECTSERVERPAGE_RUBRIC_DEFAULT; + break; + } // catch selected servers, in order to restore selection after the dataGrid is reloaded List selectedServers = SelectedServers; @@ -108,6 +119,8 @@ namespace XenAdmin.Wizards.PatchingWizard List xenConnections = ConnectionsManager.XenConnectionsCopy; xenConnections.Sort(); + int licensedPoolCount = 0; + int poolCount = 0; foreach (IXenConnection xenConnection in xenConnections) { // add pools, their members and standalone hosts @@ -121,6 +134,15 @@ namespace XenAdmin.Wizards.PatchingWizard } Host[] hosts = xenConnection.Cache.Hosts; + + if (hosts.Length > 0) + { + poolCount++; + var automatedUpdatesRestricted = hosts.Any(Host.RestrictBatchHotfixApply); //if any host is not licensed for automated updates + if (!automatedUpdatesRestricted) + licensedPoolCount++; + } + Array.Sort(hosts); foreach (Host host in hosts) { @@ -129,6 +151,18 @@ namespace XenAdmin.Wizards.PatchingWizard } } + if (WizardMode == WizardMode.NewVersion && licensedPoolCount > 0) // in NewVersion mode and at least one pool licensed for automated updates + { + applyUpdatesCheckBox.Visible = true; + applyUpdatesCheckBox.Text = poolCount == licensedPoolCount + ? Messages.PATCHINGWIZARD_SELECTSERVERPAGE_APPLY_UPDATES + : Messages.PATCHINGWIZARD_SELECTSERVERPAGE_APPLY_UPDATES_MIXED; + } + else // not in NewVersion mode or all pools unlicensed + { + applyUpdatesCheckBox.Visible = false; + } + // restore server selection SelectServers(selectedServers); } @@ -143,16 +177,14 @@ namespace XenAdmin.Wizards.PatchingWizard { dataGridViewHosts.Select(); } - - public bool IsInAutomaticMode { set; get; } - + private void EnabledRow(Host host, UpdateType type, int index) { var row = (PatchingHostsDataGridViewRow)dataGridViewHosts.Rows[index]; var poolOfOne = Helpers.GetPoolOfOne(host.Connection); - if (IsInAutomaticMode) + if (WizardMode == WizardMode.AutomatedUpdates) { // This check is first because it generally can't be fixed, it's a property of the host if (poolOfOne != null && poolOfOne.IsAutoUpdateRestartsForbidden()) // Forbids update auto restarts @@ -476,7 +508,7 @@ namespace XenAdmin.Wizards.PatchingWizard { if (poolSelectionOnly) { - if (IsInAutomaticMode) + if (WizardMode != WizardMode.SingleUpdate) //prechecks will fail in automated updates mode if one of the hosts is unreachable return SelectedPools.SelectMany(p => p.Connection.Cache.Hosts).ToList(); //prechecks will issue warning but allow updates to be installed on the reachable hosts only @@ -525,6 +557,14 @@ namespace XenAdmin.Wizards.PatchingWizard } } + public bool ApplyUpdatesToNewVersion + { + get + { + return applyUpdatesCheckBox.Visible && applyUpdatesCheckBox.Checked; + } + } + public UpdateType SelectedUpdateType { private get; set; } public void SelectServers(List selectedServers) diff --git a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.resx b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.resx index ac4a4e422..ce0fc1298 100644 --- a/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.resx +++ b/XenAdmin/Wizards/PatchingWizard/PatchingWizard_SelectServers.resx @@ -117,68 +117,20 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Top - - - - 0, 0 - - - 608, 37 - - - 1 - - - rubric - - - label1 - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 3 - - - Bottom, Left - - - 0, 382 - - - 75, 23 - - - 2 - - - &Select All - - - buttonSelectAll - - - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - + 2 + Bottom, Left + + NoControl + + - 81, 382 + 84, 359 75, 23 @@ -196,10 +148,10 @@ System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - $this + tableLayoutPanel1 - 1 + 0 Top, Bottom, Left, Right @@ -214,7 +166,7 @@ 16 - 16 + 5 True @@ -226,7 +178,7 @@ 16 - 16 + 5 True @@ -238,7 +190,7 @@ 16 - 16 + 5 True @@ -256,10 +208,10 @@ 67 - 0, 40 + 3, 40 - 608, 336 + 602, 313 1 @@ -271,11 +223,122 @@ XenAdmin.Wizards.PatchingWizard.PatchingWizard_SelectServers+PatchingHostsDataGridView, XenCenterMain, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - $this + tableLayoutPanel1 + 1 + + + NoControl + + + 3, 0 + + + 602, 37 + + + 1 + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 2 + + + True + + + NoControl + + + 3, 388 + + + 15, 14 + + + 4 + + + applyUpdatesCheckBox + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 3 + + + Bottom, Left + + + NoControl + + + 3, 359 + + + 75, 23 + + + 2 + + + &Select All + + + buttonSelectAll + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 4 + + + Fill + + + 0, 0 + + + 4 + + + 608, 405 + + + 4 + + + tableLayoutPanel1 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + 0 + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="buttonClearAll" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="dataGridViewHosts" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="label1" Row="0" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="applyUpdatesCheckBox" Row="3" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="buttonSelectAll" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,Percent,100,AutoSize,0,AutoSize,0" /></TableLayoutSettings> + True diff --git a/XenAdmin/Wizards/RollingUpgradeWizard/RollingUpgradeWizardPrecheckPage.cs b/XenAdmin/Wizards/RollingUpgradeWizard/RollingUpgradeWizardPrecheckPage.cs index 6e580b9cc..c3cc955d5 100644 --- a/XenAdmin/Wizards/RollingUpgradeWizard/RollingUpgradeWizardPrecheckPage.cs +++ b/XenAdmin/Wizards/RollingUpgradeWizard/RollingUpgradeWizardPrecheckPage.cs @@ -141,10 +141,21 @@ namespace XenAdmin.Wizards.RollingUpgradeWizard protected override List>> GenerateChecks(Pool_patch patch) { List>> checks = new List>>(); + List checkGroup; + + //XenCenter version check (if any of the selected server version is not the latest) + var latestCrVersion = Updates.XenServerVersions.FindAll(item => item.LatestCr).OrderByDescending(v => v.Version).FirstOrDefault(); + if (latestCrVersion != null && + SelectedServers.Any(host => new Version(Helpers.HostProductVersion(host)) < latestCrVersion.Version)) + { + checks.Add(new KeyValuePair>(Messages.CHECKING_XENCENTER_VERSION, new List())); + checkGroup = checks[checks.Count - 1].Value; + checkGroup.Add(new XenCenterVersionCheck(null)); + } //HostMaintenanceModeCheck checks checks.Add(new KeyValuePair>(Messages.CHECKING_HOST_LIVENESS_STATUS, new List())); - List checkGroup = checks[checks.Count - 1].Value; + checkGroup = checks[checks.Count - 1].Value; foreach (Host host in SelectedServers) { checkGroup.Add(new HostMaintenanceModeCheck(host)); diff --git a/XenAdmin/XenAdmin.csproj b/XenAdmin/XenAdmin.csproj index e8b1589b6..d71f483ad 100644 --- a/XenAdmin/XenAdmin.csproj +++ b/XenAdmin/XenAdmin.csproj @@ -107,6 +107,7 @@ + @@ -225,6 +226,7 @@ + @@ -235,6 +237,7 @@ + Form @@ -6882,4 +6885,4 @@ copy "$(ProjectDir)\..\packages\putty.exe" "$(TargetDir)" - \ No newline at end of file + diff --git a/XenAdminTests/UnitTests/AlertTests/XenCenterUpdateAlertTests.cs b/XenAdminTests/UnitTests/AlertTests/XenCenterUpdateAlertTests.cs index 359f71e50..f37cba6f7 100644 --- a/XenAdminTests/UnitTests/AlertTests/XenCenterUpdateAlertTests.cs +++ b/XenAdminTests/UnitTests/AlertTests/XenCenterUpdateAlertTests.cs @@ -43,7 +43,7 @@ namespace XenAdminTests.UnitTests.AlertTests [Test] public void VerifyStoredDataWithDefaultConstructor() { - IUnitTestVerifier validator = new VerifyGetters(new XenCenterUpdateAlert(new XenCenterVersion("6.0.2", "xc", true, "http://url", new DateTime(2011, 12, 09).ToString()))); + IUnitTestVerifier validator = new VerifyGetters(new XenCenterUpdateAlert(new XenCenterVersion("6.0.2", "xc", true, false, "http://url", new DateTime(2011, 12, 09).ToString()))); validator.Verify(new AlertClassUnitTestData { @@ -52,7 +52,7 @@ namespace XenAdminTests.UnitTests.AlertTests HelpID = "XenCenterUpdateAlert", Description = "xc is now available. Download the new version from the " + XenAdmin.Branding.COMPANY_NAME_SHORT + " website.", HelpLinkText = "Help", - Title = "New " + XenAdmin.Branding.BRAND_CONSOLE + " Available", + Title = "xc is now available", Priority = "Priority5" }); } diff --git a/XenAdminTests/UnitTests/AlertTests/XenServerUpdateAlertTests.cs b/XenAdminTests/UnitTests/AlertTests/XenServerUpdateAlertTests.cs index f9cc8b250..8f411f8c9 100644 --- a/XenAdminTests/UnitTests/AlertTests/XenServerUpdateAlertTests.cs +++ b/XenAdminTests/UnitTests/AlertTests/XenServerUpdateAlertTests.cs @@ -55,7 +55,7 @@ namespace XenAdminTests.UnitTests.AlertTests [Test] public void TestAlertWithConnectionAndHosts() { - XenServerVersion ver = new XenServerVersion("1.2.3", "name", true, "http://url", new List(), new List(), new DateTime(2011, 4, 1).ToString(), "123"); + XenServerVersion ver = new XenServerVersion("1.2.3", "name", true, false, "http://url", new List(), new List(), new DateTime(2011, 4, 1).ToString(), "123", "", false); var alert = new XenServerVersionAlert(ver); alert.IncludeConnection(connA.Object); alert.IncludeConnection(connB.Object); @@ -83,7 +83,7 @@ namespace XenAdminTests.UnitTests.AlertTests [Test] public void TestAlertWithHostsAndNoConnection() { - XenServerVersion ver = new XenServerVersion("1.2.3", "name", true, "http://url", new List(), new List(), new DateTime(2011, 4, 1).ToString(), "123"); + XenServerVersion ver = new XenServerVersion("1.2.3", "name", true, false, "http://url", new List(), new List(), new DateTime(2011, 4, 1).ToString(), "123", "", false); var alert = new XenServerVersionAlert(ver); alert.IncludeHosts(new List { hostA.Object, hostB.Object }); @@ -109,7 +109,7 @@ namespace XenAdminTests.UnitTests.AlertTests [Test] public void TestAlertWithConnectionAndNoHosts() { - XenServerVersion ver = new XenServerVersion("1.2.3", "name", true, "http://url", new List(), new List(), new DateTime(2011, 4, 1).ToString(), "123"); + XenServerVersion ver = new XenServerVersion("1.2.3", "name", true, false, "http://url", new List(), new List(), new DateTime(2011, 4, 1).ToString(), "123", "", false); var alert = new XenServerVersionAlert(ver); alert.IncludeConnection(connA.Object); alert.IncludeConnection(connB.Object); @@ -136,7 +136,7 @@ namespace XenAdminTests.UnitTests.AlertTests [Test] public void TestAlertWithNoConnectionAndNoHosts() { - XenServerVersion ver = new XenServerVersion("1.2.3", "name", true, "http://url", new List(), new List(), new DateTime(2011, 4, 1).ToString(), "123"); + XenServerVersion ver = new XenServerVersion("1.2.3", "name", true, false, "http://url", new List(), new List(), new DateTime(2011, 4, 1).ToString(), "123", "", false); var alert = new XenServerVersionAlert(ver); IUnitTestVerifier validator = new VerifyGetters(alert); diff --git a/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs b/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs index cad90e607..91ba5b8b9 100644 --- a/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs +++ b/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs @@ -76,7 +76,7 @@ namespace XenAdminTests.UnitTests { var serverVersions = new List(); - var version = new XenServerVersion("7.0.0", "XenServer Test 7", true, "", new List(), new List(), DateTime.MinValue.ToString(), "buildNo"); + var version = new XenServerVersion("7.0.0", "XenServer Test 7", true, false, "", new List(), new List(), DateTime.MinValue.ToString(), "buildNo", "", false); for (int ii = 0; ii < numberOfPatches; ii++) { var patch = new XenServerPatch("patch_uuid_" + ii, "patch name " + ii, "patch description" + ii, "", "", "1.0", "", "", "1970-01-01T00:00:00Z", "", "1000"); diff --git a/XenModel/Actions/Updates/DownloadUpdatesXmlAction.cs b/XenModel/Actions/Updates/DownloadUpdatesXmlAction.cs index 9cab23847..b26fc9f7d 100644 --- a/XenModel/Actions/Updates/DownloadUpdatesXmlAction.cs +++ b/XenModel/Actions/Updates/DownloadUpdatesXmlAction.cs @@ -119,7 +119,8 @@ namespace XenAdmin.Actions { string version_lang = ""; string name = ""; - bool is_latest = false; + bool latest = false; + bool latest_cr = false; string url = ""; string timestamp = ""; @@ -130,14 +131,16 @@ namespace XenAdmin.Actions else if (attrib.Name == "name") name = attrib.Value; else if (attrib.Name == "latest") - is_latest = attrib.Value.ToUpperInvariant() == bool.TrueString.ToUpperInvariant(); + latest = attrib.Value.ToUpperInvariant() == bool.TrueString.ToUpperInvariant(); + else if (attrib.Name == "latestcr") + latest_cr = attrib.Value.ToUpperInvariant() == bool.TrueString.ToUpperInvariant(); else if (attrib.Name == "url") url = attrib.Value; else if (attrib.Name == "timestamp") timestamp = attrib.Value; } - XenCenterVersions.Add(new XenCenterVersion(version_lang, name, is_latest, url, timestamp)); + XenCenterVersions.Add(new XenCenterVersion(version_lang, name, latest, latest_cr, url, timestamp)); } } } @@ -236,9 +239,12 @@ namespace XenAdmin.Actions string version_oem = ""; string name = ""; bool is_latest = false; + bool is_latest_cr = false; string url = ""; string timestamp = ""; string buildNumber = ""; + string patchUuid = ""; + bool presentAsUpdate = false; foreach (XmlAttribute attrib in version.Attributes) { @@ -248,12 +254,18 @@ namespace XenAdmin.Actions name = attrib.Value; else if (attrib.Name == "latest") is_latest = attrib.Value.ToUpperInvariant() == bool.TrueString.ToUpperInvariant(); + else if (attrib.Name == "latestcr") + is_latest_cr = attrib.Value.ToUpperInvariant() == bool.TrueString.ToUpperInvariant(); else if (attrib.Name == "url") url = attrib.Value; else if (attrib.Name == "timestamp") timestamp = attrib.Value; else if (attrib.Name == "build-number") buildNumber = attrib.Value; + else if (attrib.Name == "patch-uuid") + patchUuid = attrib.Value; + else if (attrib.Name == "present-as-update") + presentAsUpdate = attrib.Value.ToUpperInvariant() == bool.TrueString.ToUpperInvariant(); } List patches = new List(); @@ -288,8 +300,8 @@ namespace XenAdmin.Actions } - XenServerVersions.Add(new XenServerVersion(version_oem, name, is_latest, url, patches, minimalPatches, timestamp, - buildNumber)); + XenServerVersions.Add(new XenServerVersion(version_oem, name, is_latest, is_latest_cr, url, patches, minimalPatches, timestamp, + buildNumber, patchUuid, presentAsUpdate)); } } } diff --git a/XenModel/Actions/Updates/XenCenterVersion.cs b/XenModel/Actions/Updates/XenCenterVersion.cs index c3c78c157..a87ae2cac 100644 --- a/XenModel/Actions/Updates/XenCenterVersion.cs +++ b/XenModel/Actions/Updates/XenCenterVersion.cs @@ -38,16 +38,18 @@ namespace XenAdmin.Core { public Version Version; public string Name; - public bool IsLatest; + public bool Latest; + public bool LatestCr; public string Url; public string Lang; public DateTime TimeStamp; - public XenCenterVersion(string version_lang, string name, bool is_latest, string url, string timestamp) + public XenCenterVersion(string version_lang, string name, bool latest, bool latest_cr, string url, string timestamp) { ParseVersion(version_lang); Name = name; - IsLatest = is_latest; + Latest = latest; + LatestCr = latest_cr; Url = url; DateTime.TryParse(timestamp, out TimeStamp); } diff --git a/XenModel/Actions/Updates/XenServerVersion.cs b/XenModel/Actions/Updates/XenServerVersion.cs index eb382987a..248685884 100644 --- a/XenModel/Actions/Updates/XenServerVersion.cs +++ b/XenModel/Actions/Updates/XenServerVersion.cs @@ -41,9 +41,12 @@ namespace XenAdmin.Core public Version Version; public string Name; public bool Latest; + public bool LatestCr; public string Url; public string Oem; public List Patches; + public string PatchUuid; + public bool PresentAsUpdate; /// /// A host of this version is considered up-to-date when it has all the patches in this list installed on it @@ -60,22 +63,28 @@ namespace XenAdmin.Core /// /// /// + /// /// /// /// can be null (see /// /// - public XenServerVersion(string version_oem, string name, bool latest, string url, List patches, List minimumPatches, - string timestamp, string buildNumber) + /// + /// Indicates that the new version (usually a CU) should be presented as an update where possible + public XenServerVersion(string version_oem, string name, bool latest, bool latestCr, string url, List patches, List minimumPatches, + string timestamp, string buildNumber, string patchUuid, bool presentAsUpdate) { ParseVersion(version_oem); Name = name; Latest = latest; + LatestCr = latestCr; Url = url; Patches = patches; MinimalPatches = minimumPatches; DateTime.TryParse(timestamp, out TimeStamp); BuildNumber = buildNumber; + PatchUuid = patchUuid; + PresentAsUpdate = presentAsUpdate; } private void ParseVersion(string version_oem) @@ -103,7 +112,13 @@ namespace XenAdmin.Core } } - + public bool IsVersionAvailableAsAnUpdate + { + get + { + return !string.IsNullOrEmpty(PatchUuid); + } + } } } \ No newline at end of file diff --git a/XenModel/Messages.Designer.cs b/XenModel/Messages.Designer.cs index 8b7c7b763..582627d90 100755 --- a/XenModel/Messages.Designer.cs +++ b/XenModel/Messages.Designer.cs @@ -4806,7 +4806,7 @@ namespace XenAdmin { } /// - /// Looks up a localized string similar to New [XenCenter] Available. + /// Looks up a localized string similar to {0} is now available. /// public static string ALERT_NEW_VERSION { get { @@ -6830,6 +6830,15 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to Checking [XenCenter] version. + /// + public static string CHECKING_XENCENTER_VERSION { + get { + return ResourceManager.GetString("CHECKING_XENCENTER_VERSION", resourceCulture); + } + } + /// /// Looks up a localized string similar to Cross-server private network. /// @@ -23375,6 +23384,15 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to New [XenCenter] version required. + /// + public static string NEW_XENCENTER_REQUIRED_INFO { + get { + return ResourceManager.GetString("NEW_XENCENTER_REQUIRED_INFO", resourceCulture); + } + } + /// /// Looks up a localized string similar to You need to shutdown and then restart the VM before it can access the new disk.. /// @@ -26236,6 +26254,24 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to Installation size: {0}. + /// + public static string PATCH_INSTALLATION_SIZE { + get { + return ResourceManager.GetString("PATCH_INSTALLATION_SIZE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This version requires [XenCenter] {0} or newer. + /// + public static string PATCH_NEEDS_NEW_XENCENTER { + get { + return ResourceManager.GetString("PATCH_NEEDS_NEW_XENCENTER", resourceCulture); + } + } + /// /// Looks up a localized string similar to Not found. /// @@ -26282,6 +26318,15 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to {0} ok.. + /// + public static string PATCHING_WIZARD_CHECK_OK { + get { + return ResourceManager.GetString("PATCHING_WIZARD_CHECK_OK", resourceCulture); + } + } + /// /// Looks up a localized string similar to The patch {0} is going to be deleted. Do you want to continue?. /// @@ -26823,6 +26868,24 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to Also apply all released updates on the new version. + /// + public static string PATCHINGWIZARD_SELECTSERVERPAGE_APPLY_UPDATES { + get { + return ResourceManager.GetString("PATCHINGWIZARD_SELECTSERVERPAGE_APPLY_UPDATES", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Also apply all released updates on the new version (only on pools licensed for automated updates). + /// + public static string PATCHINGWIZARD_SELECTSERVERPAGE_APPLY_UPDATES_MIXED { + get { + return ResourceManager.GetString("PATCHINGWIZARD_SELECTSERVERPAGE_APPLY_UPDATES_MIXED", resourceCulture); + } + } + /// /// Looks up a localized string similar to Automated updates are not supported on this [XenServer] version. /// @@ -26925,6 +26988,16 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to Select one or more pools or standalone servers that you want to update to the new version. + ///Servers where this update cannot be applied appear disabled in this list.. + /// + public static string PATCHINGWIZARD_SELECTSERVERPAGE_RUBRIC_NEW_VERSION_MODE { + get { + return ResourceManager.GetString("PATCHINGWIZARD_SELECTSERVERPAGE_RUBRIC_NEW_VERSION_MODE", resourceCulture); + } + } + /// /// Looks up a localized string similar to Select one or more pools or standalone servers where you want to apply the selected update. ///Servers where this update cannot be applied appear disabled in this list.. @@ -26971,6 +27044,15 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to The new version has been installed.. + /// + public static string PATCHINGWIZARD_UPDATES_DONE_AUTOMATED_NEW_VERSION_MODE { + get { + return ResourceManager.GetString("PATCHINGWIZARD_UPDATES_DONE_AUTOMATED_NEW_VERSION_MODE", resourceCulture); + } + } + /// /// Looks up a localized string similar to Automated updates have finished.. /// @@ -26980,6 +27062,24 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to Installing updates:. + /// + public static string PATCHINGWIZARD_UPLOAD_AND_INSTALL_TITLE_AUTOMATED_MODE { + get { + return ResourceManager.GetString("PATCHINGWIZARD_UPLOAD_AND_INSTALL_TITLE_AUTOMATED_MODE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Installing new version:. + /// + public static string PATCHINGWIZARD_UPLOAD_AND_INSTALL_TITLE_NEW_VERSION_AUTOMATED_MODE { + get { + return ResourceManager.GetString("PATCHINGWIZARD_UPLOAD_AND_INSTALL_TITLE_NEW_VERSION_AUTOMATED_MODE", resourceCulture); + } + } + /// /// Looks up a localized string similar to [XenCenter] is now downloading your update and uploading it to the servers specified in the previous step. ///Please wait for these operations to complete, then click Next to continue with the installation.. @@ -28001,6 +28101,15 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to [XenCenter] version. + /// + public static string PROBLEM_XENCENTER_VERSION_TITLE { + get { + return ResourceManager.GetString("PROBLEM_XENCENTER_VERSION_TITLE", resourceCulture); + } + } + /// /// Looks up a localized string similar to &Proceed. /// @@ -33328,6 +33437,15 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to Download [XenCenter]. + /// + public static string UPDATES_DOWNLOAD_REQUIRED_XENCENTER { + get { + return ResourceManager.GetString("UPDATES_DOWNLOAD_REQUIRED_XENCENTER", resourceCulture); + } + } + /// /// Looks up a localized string similar to Install Update. /// @@ -33701,6 +33819,24 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to [XenCenter] version {0} or newer is required.. + /// + public static string UPDATES_WIZARD_NEWER_XENCENTER_REQUIRED { + get { + return ResourceManager.GetString("UPDATES_WIZARD_NEWER_XENCENTER_REQUIRED", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ensure you have upgraded [XenCenter] before upgrading [XenServer].. + /// + public static string UPDATES_WIZARD_NEWER_XENCENTER_WARNING { + get { + return ResourceManager.GetString("UPDATES_WIZARD_NEWER_XENCENTER_WARNING", resourceCulture); + } + } + /// /// Looks up a localized string similar to No further action is required for this update.. /// @@ -38758,6 +38894,15 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to [XenCenter] version check. + /// + public static string XENCENTER_VERSION_CHECK_DESCRIPTION { + get { + return ResourceManager.GetString("XENCENTER_VERSION_CHECK_DESCRIPTION", resourceCulture); + } + } + /// /// Looks up a localized string similar to Saved Searches (*.{0})|*.{0}. /// diff --git a/XenModel/Messages.resx b/XenModel/Messages.resx index c36c67a10..99aea23bf 100755 --- a/XenModel/Messages.resx +++ b/XenModel/Messages.resx @@ -1782,7 +1782,7 @@ Note that if RBAC is enabled, only alerts which you have privileges to dismiss w Go to Web Page - New [XenCenter] Available + {0} is now available {0} is now available. Download the new version from the [Citrix] website. @@ -2480,6 +2480,9 @@ Do you want to assign it to the schedule '{2}' instead? Checking upgrade hotfix status + + Checking [XenCenter] version + Pool '{0}' cannot have WLB enabled @@ -8766,6 +8769,9 @@ It is strongly recommended that you Cancel and apply the latest version of the p YinheKylin + + New [XenCenter] version required + This NFS ISO storage is already attached to '{0}' @@ -9263,6 +9269,12 @@ However, there is not enough space to perform the repartitioning, so the current [XenServer] Updates and Supplemental Packs (*.{0}, *.iso,*.zip)|*.{0};*.iso;*.zip + + Also apply all released updates on the new version + + + Also apply all released updates on the new version (only on pools licensed for automated updates) + Automated updates are not supported on this [XenServer] version @@ -9296,6 +9308,10 @@ Servers that cannot be updated with automated updates appear disabled in this li Select one or more servers where you want to apply the selected update. +Servers where this update cannot be applied appear disabled in this list. + + + Select one or more pools or standalone servers that you want to update to the new version. Servers where this update cannot be applied appear disabled in this list. @@ -9314,6 +9330,9 @@ Servers where this update cannot be applied appear disabled in this list. Select the servers you want to update + + The new version has been installed. + Automated updates have finished. @@ -9334,12 +9353,21 @@ Please wait for this operation to complete, then click Next to continue with the Uploading the selected file to your servers + + Installing updates: + + + Installing new version: + Eject any virtual CDs from your VMs Disable HA until after all the hosts have been rebooted + + {0} ok. + The patch {0} is going to be deleted. Do you want to continue? @@ -9401,6 +9429,12 @@ Size: {3} {0}: This patch is for servers with version matching the regular expression '{1}'. + + Installation size: {0} + + + This version requires [XenCenter] {0} or newer + Not found @@ -9737,6 +9771,9 @@ Please reconnect the host and try again VM '{0}' + + [XenCenter] version + &Proceed @@ -11506,6 +11543,9 @@ Verify that the file is a valid {1} export. Download and Install + + Download [XenCenter] + Install Update @@ -11633,6 +11673,12 @@ Check your settings and try again. {0}: The VM '{1}' uses local storage and cannot be migrated. + + [XenCenter] version {0} or newer is required. + + + Ensure you have upgraded [XenCenter] before upgrading [XenServer]. + The selected file does not have a valid extension. Valid extensions are: *.{0} and *.iso @@ -13381,6 +13427,9 @@ Are you sure you want to enable automated power management for this Host? Newer [XenCenter] Available + + [XenCenter] version check + Saved Searches (*.{0})|*.{0}