mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-11-23 20:36:33 +01:00
CA-339305: XenCenter was hanging when update alerts were removed very fast, and other issues:
- Use a plain list to store update alerts and, where possible, fire a collection change event only after a bulk change and not every time a single object is added or removed. - Fixed issue where dismissed updates were stored in the config of all connected pools, even of those where the update did not apply. - Corrected RBAC checks for update dismissal. - Fixed enabled state of dismiss buttons. Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
This commit is contained in:
parent
f05b512ca4
commit
e3896239df
@ -29,29 +29,23 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Network;
|
||||
using XenAdmin.Core;
|
||||
using XenAPI;
|
||||
|
||||
|
||||
namespace XenAdmin.Actions
|
||||
{
|
||||
public class DeleteAllAlertsAction : AsyncAction
|
||||
{
|
||||
private readonly IEnumerable<Alert> Alerts;
|
||||
private readonly List<Alert> _alerts;
|
||||
|
||||
/// <param name="connection">May be null; this is expected for client-side alerts.</param>
|
||||
/// <param name="alerts"></param>
|
||||
public DeleteAllAlertsAction(IXenConnection connection, IEnumerable<Alert> alerts)
|
||||
: base(connection,
|
||||
GetActionTitle(connection, alerts.Count()),
|
||||
Messages.ACTION_REMOVE_ALERTS_DESCRIPTION)
|
||||
public DeleteAllAlertsAction(List<Alert> alerts, IXenConnection connection = null)
|
||||
: base(connection, GetActionTitle(connection, alerts.Count),
|
||||
Messages.ACTION_REMOVE_ALERTS_DESCRIPTION)
|
||||
{
|
||||
this.Alerts = alerts;
|
||||
_alerts = new List<Alert>(alerts);
|
||||
|
||||
if (connection != null)
|
||||
{
|
||||
@ -73,58 +67,25 @@ namespace XenAdmin.Actions
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
int i = 0;
|
||||
int max = Alerts.Count();
|
||||
Exception e = null;
|
||||
LogDescriptionChanges = false;
|
||||
List<Alert> toBeDismissed = new List<Alert>();
|
||||
|
||||
try
|
||||
{
|
||||
var myList = new List<Alert>(Alerts);
|
||||
foreach (Alert a in myList)
|
||||
for (var i = 0; i < _alerts.Count; i++)
|
||||
{
|
||||
PercentComplete = (i * 100) / max;
|
||||
i++;
|
||||
Description = string.Format(Messages.ACTION_REMOVE_ALERTS_PROGRESS_DESCRIPTION, i, max);
|
||||
|
||||
Alert a1 = a;
|
||||
BestEffort(ref e, delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
if (a1 is XenServerPatchAlert || a1 is XenServerVersionAlert)
|
||||
{
|
||||
toBeDismissed.Add(a1);
|
||||
}
|
||||
else if(a1 is XenCenterUpdateAlert)
|
||||
{
|
||||
a1.Dismiss();
|
||||
}
|
||||
else
|
||||
{
|
||||
a1.DismissSingle(Session);
|
||||
}
|
||||
}
|
||||
catch (Failure exn)
|
||||
{
|
||||
if (exn.ErrorDescription[0] != Failure.HANDLE_INVALID)
|
||||
throw;
|
||||
//remove alert from XenCenterAlerts; this will trigger the CollectionChanged event, on which we update the alert count
|
||||
if (Alert.FindAlert(a1) != null)
|
||||
Alert.RemoveAlert(a1);
|
||||
}
|
||||
});
|
||||
Description = string.Format(Messages.ACTION_REMOVE_ALERTS_PROGRESS_DESCRIPTION, i, _alerts.Count);
|
||||
_alerts[i].Dismiss();
|
||||
PercentComplete = i * 100 / _alerts.Count;
|
||||
}
|
||||
|
||||
Updates.DismissUpdates(toBeDismissed);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogDescriptionChanges = true;
|
||||
}
|
||||
|
||||
Description = max == 1 ? Messages.ACTION_REMOVE_ALERTS_DONE_ONE : string.Format(Messages.ACTION_REMOVE_ALERTS_DONE, max);
|
||||
Description = _alerts.Count == 1
|
||||
? Messages.ACTION_REMOVE_ALERTS_DONE_ONE
|
||||
: string.Format(Messages.ACTION_REMOVE_ALERTS_DONE, _alerts.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Network;
|
||||
using XenAdmin.Core;
|
||||
using XenAPI;
|
||||
@ -56,11 +57,11 @@ namespace XenAdmin.Actions
|
||||
|
||||
Dictionary<string, string> other_config = pool.other_config;
|
||||
|
||||
if (other_config.ContainsKey(Updates.IgnorePatchKey))
|
||||
other_config.Remove(Updates.IgnorePatchKey);
|
||||
if (other_config.ContainsKey(XenServerPatchAlert.IgnorePatchKey))
|
||||
other_config.Remove(XenServerPatchAlert.IgnorePatchKey);
|
||||
|
||||
if (other_config.ContainsKey(Updates.LAST_SEEN_SERVER_VERSION_KEY))
|
||||
other_config.Remove(Updates.LAST_SEEN_SERVER_VERSION_KEY);
|
||||
if (other_config.ContainsKey(XenServerVersionAlert.LAST_SEEN_SERVER_VERSION_KEY))
|
||||
other_config.Remove(XenServerVersionAlert.LAST_SEEN_SERVER_VERSION_KEY);
|
||||
|
||||
|
||||
XenAPI.Pool.set_other_config(Connection.Session, pool.opaque_ref, other_config);
|
||||
|
@ -44,7 +44,7 @@ namespace XenAdmin.Alerts
|
||||
{
|
||||
public class MessageAlert : Alert
|
||||
{
|
||||
public XenAPI.Message Message;
|
||||
public readonly Message Message;
|
||||
public IXenObject XenObject;
|
||||
|
||||
private const int DEFAULT_PRIORITY = 0;
|
||||
@ -438,14 +438,28 @@ namespace XenAdmin.Alerts
|
||||
|
||||
public override void Dismiss()
|
||||
{
|
||||
new DestroyMessageAction(Message.Connection, Message.opaque_ref).RunAsync();
|
||||
base.Dismiss();
|
||||
new DestroyMessageAction(Message).RunExternal(Connection.Session);
|
||||
RemoveAlert(this);
|
||||
}
|
||||
|
||||
public override void DismissSingle(Session s)
|
||||
public override bool AllowedToDismiss()
|
||||
{
|
||||
Message.destroy(s, Message.opaque_ref);
|
||||
base.Dismiss();
|
||||
if (Dismissing)
|
||||
return false;
|
||||
|
||||
// this shouldn't happen for this type of alert, but check for safety
|
||||
if (Connection == null)
|
||||
return true;
|
||||
|
||||
// if we are disconnected do not dismiss as the alert will disappear soon
|
||||
if (Connection.Session == null)
|
||||
return false;
|
||||
|
||||
if (Connection.Session.IsLocalSuperuser)
|
||||
return true;
|
||||
|
||||
var allowedRoles = Role.ValidRoleList("Message.destroy", Connection);
|
||||
return allowedRoles.Any(r => Connection.Session.Roles.Contains(r));
|
||||
}
|
||||
|
||||
public static void RemoveAlert(Message m)
|
||||
|
@ -42,6 +42,8 @@ namespace XenAdmin.Alerts
|
||||
{
|
||||
public class XenServerPatchAlert : XenServerUpdateAlert
|
||||
{
|
||||
public const string IgnorePatchKey = "XenCenter.IgnorePatches";
|
||||
|
||||
public readonly XenServerPatch Patch;
|
||||
public readonly XenServerVersion NewServerVersion;
|
||||
|
||||
@ -169,15 +171,32 @@ namespace XenAdmin.Alerts
|
||||
|
||||
Dictionary<string, string> other_config = pool.other_config;
|
||||
|
||||
if (other_config.ContainsKey(Updates.IgnorePatchKey))
|
||||
if (other_config.ContainsKey(IgnorePatchKey))
|
||||
{
|
||||
List<string> current = new List<string>(other_config[Updates.IgnorePatchKey].Split(','));
|
||||
List<string> current = new List<string>(other_config[IgnorePatchKey].Split(','));
|
||||
if (current.Contains(Patch.Uuid, StringComparer.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Dismiss(Dictionary<string, string> otherConfig)
|
||||
{
|
||||
if (otherConfig.ContainsKey(IgnorePatchKey))
|
||||
{
|
||||
var current = new List<string>(otherConfig[IgnorePatchKey].Split(','));
|
||||
if (current.Contains(Patch.Uuid, StringComparer.OrdinalIgnoreCase))
|
||||
return;
|
||||
|
||||
current.Add(Patch.Uuid);
|
||||
otherConfig[IgnorePatchKey] = string.Join(",", current.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
otherConfig.Add(IgnorePatchKey, Patch.Uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(Alert other)
|
||||
{
|
||||
if (other is XenServerPatchAlert patchAlert)
|
||||
|
@ -147,6 +147,50 @@ namespace XenAdmin.Alerts
|
||||
}
|
||||
}
|
||||
|
||||
private bool AllowedToDismiss(IXenConnection connection)
|
||||
{
|
||||
if (connection == null)
|
||||
return true;
|
||||
|
||||
// if we are disconnected do not dismiss as the alert will disappear soon
|
||||
if (connection.Session == null)
|
||||
return false;
|
||||
|
||||
// prevent dismissal if the alert is not relevant to the current connection
|
||||
if (!Connections.Contains(connection) && DistinctHosts.All(h => h.Connection != connection))
|
||||
return false;
|
||||
|
||||
if (connection.Session.IsLocalSuperuser)
|
||||
return true;
|
||||
|
||||
var allowedRoles = Role.ValidRoleList("pool.set_other_config", connection);
|
||||
return allowedRoles.Any(r => connection.Session.Roles.Contains(r));
|
||||
}
|
||||
|
||||
public override bool AllowedToDismiss()
|
||||
{
|
||||
return !Dismissing && ConnectionsManager.XenConnectionsCopy.Any(AllowedToDismiss);
|
||||
}
|
||||
|
||||
public override void Dismiss()
|
||||
{
|
||||
foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
|
||||
{
|
||||
if (!AllowedToDismiss(connection))
|
||||
continue;
|
||||
|
||||
Pool pool = Helpers.GetPoolOfOne(connection);
|
||||
if (pool == null)
|
||||
continue;
|
||||
|
||||
var otherConfig = pool.other_config;
|
||||
Dismiss(otherConfig);
|
||||
Pool.set_other_config(connection.Session, pool.opaque_ref, otherConfig);
|
||||
}
|
||||
|
||||
Updates.RemoveUpdate(this);
|
||||
}
|
||||
|
||||
public override bool IsDismissed()
|
||||
{
|
||||
lock (connectionsLock)
|
||||
@ -155,6 +199,8 @@ namespace XenAdmin.Alerts
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void Dismiss(Dictionary<string, string> otherConfig);
|
||||
|
||||
protected abstract bool IsDismissed(IXenConnection connection);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using XenAdmin.Core;
|
||||
using XenAdmin.Network;
|
||||
using XenAPI;
|
||||
@ -40,6 +41,8 @@ namespace XenAdmin.Alerts
|
||||
{
|
||||
public class XenServerVersionAlert : XenServerUpdateAlert
|
||||
{
|
||||
public const string LAST_SEEN_SERVER_VERSION_KEY = "XenCenter.LastSeenServerVersion";
|
||||
|
||||
public readonly XenServerVersion Version;
|
||||
|
||||
public XenServerVersionAlert(XenServerVersion version)
|
||||
@ -76,15 +79,31 @@ namespace XenAdmin.Alerts
|
||||
|
||||
Dictionary<string, string> other_config = pool.other_config;
|
||||
|
||||
if (other_config.ContainsKey(Updates.LAST_SEEN_SERVER_VERSION_KEY))
|
||||
if (other_config.ContainsKey(LAST_SEEN_SERVER_VERSION_KEY))
|
||||
{
|
||||
List<string> current = new List<string>(other_config[Updates.LAST_SEEN_SERVER_VERSION_KEY].Split(','));
|
||||
List<string> current = new List<string>(other_config[LAST_SEEN_SERVER_VERSION_KEY].Split(','));
|
||||
if (current.Contains(Version.Version.ToString()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Dismiss(Dictionary<string, string> otherConfig)
|
||||
{
|
||||
if (otherConfig.ContainsKey(LAST_SEEN_SERVER_VERSION_KEY))
|
||||
{
|
||||
List<string> current = new List<string>(otherConfig[LAST_SEEN_SERVER_VERSION_KEY].Split(','));
|
||||
if (current.Contains(Version.Version.ToString()))
|
||||
return;
|
||||
current.Add(Version.Version.ToString());
|
||||
otherConfig[LAST_SEEN_SERVER_VERSION_KEY] = string.Join(",", current.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
otherConfig.Add(LAST_SEEN_SERVER_VERSION_KEY, Version.Version.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(Alert other)
|
||||
{
|
||||
if (other is XenServerVersionAlert versionAlert)
|
||||
|
@ -32,17 +32,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using XenAdmin.Actions;
|
||||
using XenAPI;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Network;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using XenAdmin.Dialogs;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using XenAdmin.Actions;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Alerts.Types;
|
||||
using XenCenterLib;
|
||||
using XenAdmin.Dialogs;
|
||||
using XenAdmin.Network;
|
||||
using XenAPI;
|
||||
|
||||
|
||||
namespace XenAdmin.Core
|
||||
{
|
||||
@ -50,9 +50,12 @@ namespace XenAdmin.Core
|
||||
{
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private static readonly string CheckForUpdatesUrl = Registry.CustomUpdatesXmlLocation ?? BrandManager.UpdatesUrl;
|
||||
|
||||
public static event Action<bool, string> CheckForUpdatesCompleted;
|
||||
public static event Action CheckForUpdatesStarted;
|
||||
public static event Action RestoreDismissedUpdatesStarted;
|
||||
public static event Action<CollectionChangeEventArgs> UpdateAlertCollectionChanged;
|
||||
|
||||
private static readonly object downloadedUpdatesLock = new object();
|
||||
private static List<XenServerVersion> XenServerVersionsForAutoCheck = new List<XenServerVersion>();
|
||||
@ -61,119 +64,27 @@ namespace XenAdmin.Core
|
||||
public static List<XenServerVersion> XenServerVersions = new List<XenServerVersion>();
|
||||
|
||||
private static readonly object updateAlertsLock = new object();
|
||||
private static readonly ChangeableList<Alert> updateAlerts = new ChangeableList<Alert>();
|
||||
private static readonly List<Alert> updateAlerts = new List<Alert>();
|
||||
|
||||
public const string IgnorePatchKey = "XenCenter.IgnorePatches";
|
||||
public const string LAST_SEEN_SERVER_VERSION_KEY = "XenCenter.LastSeenServerVersion";
|
||||
|
||||
public static IEnumerable<Alert> UpdateAlerts => updateAlerts;
|
||||
|
||||
public static int UpdateAlertsCount => updateAlerts.Count;
|
||||
|
||||
private static void AddUpdate(Alert update)
|
||||
/// <summary>
|
||||
/// Locks and creates a new list of the update alerts
|
||||
/// </summary>
|
||||
public static List<Alert> UpdateAlerts
|
||||
{
|
||||
try
|
||||
get
|
||||
{
|
||||
lock (updateAlertsLock)
|
||||
{
|
||||
if(!updateAlerts.Contains(update))
|
||||
{
|
||||
updateAlerts.Add(update);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("Failed to add update", e);
|
||||
return updateAlerts.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveUpdate(Alert update)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (updateAlertsLock)
|
||||
{
|
||||
if(updateAlerts.Contains(update))
|
||||
{
|
||||
updateAlerts.Remove(update);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("Failed to remove update", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dismisses the updates in the given list i.e. they are added in the
|
||||
/// other_config list of each pool and removed from the Updates.UpdateAlerts list.
|
||||
/// </summary>
|
||||
public static void DismissUpdates(List<Alert> toBeDismissed)
|
||||
{
|
||||
if (toBeDismissed.Count == 0)
|
||||
return;
|
||||
|
||||
foreach(IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
|
||||
{
|
||||
if (!Alert.AllowedToDismiss(connection))
|
||||
continue;
|
||||
|
||||
Pool pool = Helpers.GetPoolOfOne(connection);
|
||||
if (pool == null)
|
||||
continue;
|
||||
|
||||
Dictionary<string, string> other_config = pool.other_config;
|
||||
|
||||
foreach (Alert alert in toBeDismissed)
|
||||
{
|
||||
if (alert is XenServerPatchAlert patchAlert)
|
||||
{
|
||||
if (other_config.ContainsKey(IgnorePatchKey))
|
||||
{
|
||||
List<string> current = new List<string>(other_config[IgnorePatchKey].Split(','));
|
||||
if (current.Contains(patchAlert.Patch.Uuid, StringComparer.OrdinalIgnoreCase))
|
||||
continue;
|
||||
current.Add(patchAlert.Patch.Uuid);
|
||||
other_config[IgnorePatchKey] = string.Join(",", current.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
other_config.Add(IgnorePatchKey, patchAlert.Patch.Uuid);
|
||||
}
|
||||
}
|
||||
|
||||
if (alert is XenServerVersionAlert versionAlert)
|
||||
{
|
||||
|
||||
if (other_config.ContainsKey(LAST_SEEN_SERVER_VERSION_KEY))
|
||||
{
|
||||
List<string> current = new List<string>(other_config[LAST_SEEN_SERVER_VERSION_KEY].Split(','));
|
||||
if (current.Contains(versionAlert.Version.Version.ToString()))
|
||||
continue;
|
||||
current.Add(versionAlert.Version.Version.ToString());
|
||||
other_config[LAST_SEEN_SERVER_VERSION_KEY] = string.Join(",", current.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
other_config.Add(LAST_SEEN_SERVER_VERSION_KEY, versionAlert.Version.Version.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
RemoveUpdate(alert);
|
||||
}
|
||||
|
||||
Pool.set_other_config(connection.Session, pool.opaque_ref, other_config);
|
||||
}
|
||||
}
|
||||
|
||||
private static Alert FindUpdate(Predicate<Alert> predicate)
|
||||
{
|
||||
lock (updateAlertsLock)
|
||||
return updateAlerts.Find(predicate);
|
||||
}
|
||||
updateAlerts.Remove(update);
|
||||
|
||||
UpdateAlertCollectionChanged?.Invoke(new CollectionChangeEventArgs(CollectionChangeAction.Remove, update));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If AutomaticCheck is enabled it checks for updates regardless the
|
||||
@ -270,46 +181,25 @@ namespace XenAdmin.Core
|
||||
return action.Succeeded;
|
||||
}
|
||||
|
||||
public static string CheckForUpdatesUrl => Registry.CustomUpdatesXmlLocation ?? BrandManager.UpdatesUrl;
|
||||
|
||||
private static void actionCompleted(ActionBase sender)
|
||||
{
|
||||
Program.AssertOffEventThread();
|
||||
|
||||
DownloadUpdatesXmlAction action = sender as DownloadUpdatesXmlAction;
|
||||
if (action == null)
|
||||
if (!(sender is DownloadUpdatesXmlAction action))
|
||||
return;
|
||||
|
||||
bool succeeded = action.Succeeded;
|
||||
string errorMessage = string.Empty;
|
||||
|
||||
lock (updateAlertsLock)
|
||||
updateAlerts.Clear();
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
lock (downloadedUpdatesLock)
|
||||
{
|
||||
XenCenterVersions = action.XenCenterVersions;
|
||||
|
||||
XenServerVersionsForAutoCheck = action.XenServerVersionsForAutoCheck;
|
||||
|
||||
XenServerVersions = action.XenServerVersions;
|
||||
|
||||
XenServerPatches = action.XenServerPatches;
|
||||
}
|
||||
|
||||
var xenCenterAlerts = NewXenCenterUpdateAlerts(XenCenterVersions, Program.Version);
|
||||
if (xenCenterAlerts != null)
|
||||
updateAlerts.AddRange(xenCenterAlerts.Where(a=>!a.IsDismissed()));
|
||||
|
||||
var xenServerUpdateAlerts = NewXenServerVersionAlerts(XenServerVersionsForAutoCheck);
|
||||
if (xenServerUpdateAlerts != null)
|
||||
updateAlerts.AddRange(xenServerUpdateAlerts.Where(a=>!a.CanIgnore));
|
||||
|
||||
var xenServerPatchAlerts = NewXenServerPatchAlerts(XenServerVersions, XenServerPatches);
|
||||
if (xenServerPatchAlerts != null)
|
||||
updateAlerts.AddRange(xenServerPatchAlerts.Where(alert => !alert.CanIgnore));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -332,29 +222,37 @@ namespace XenAdmin.Core
|
||||
errorMessage = Messages.AVAILABLE_UPDATES_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (CheckForUpdatesCompleted != null)
|
||||
CheckForUpdatesCompleted(succeeded, errorMessage);
|
||||
lock (updateAlertsLock)
|
||||
{
|
||||
updateAlerts.Clear();
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
var xenCenterAlerts = NewXenCenterUpdateAlerts(XenCenterVersions, Program.Version);
|
||||
updateAlerts.AddRange(xenCenterAlerts.Where(a => !a.IsDismissed()));
|
||||
|
||||
var xenServerUpdateAlerts = NewXenServerVersionAlerts(XenServerVersionsForAutoCheck);
|
||||
updateAlerts.AddRange(xenServerUpdateAlerts.Where(a => !a.CanIgnore));
|
||||
|
||||
var xenServerPatchAlerts = NewXenServerPatchAlerts(XenServerVersions, XenServerPatches);
|
||||
updateAlerts.AddRange(xenServerPatchAlerts.Where(a => !a.CanIgnore));
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAlertCollectionChanged?.Invoke(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, UpdateAlerts));
|
||||
|
||||
CheckForUpdatesCompleted?.Invoke(succeeded, errorMessage);
|
||||
}
|
||||
|
||||
|
||||
public static void RegisterCollectionChanged(CollectionChangeEventHandler handler)
|
||||
{
|
||||
updateAlerts.CollectionChanged += handler;
|
||||
}
|
||||
|
||||
public static void DeregisterCollectionChanged(CollectionChangeEventHandler handler)
|
||||
{
|
||||
updateAlerts.CollectionChanged -= handler;
|
||||
}
|
||||
|
||||
|
||||
public static List<XenCenterUpdateAlert> NewXenCenterUpdateAlerts(List<XenCenterVersion> xenCenterVersions,
|
||||
Version currentProgramVersion)
|
||||
{
|
||||
if (Helpers.CommonCriteriaCertificationRelease)
|
||||
return null;
|
||||
return new List<XenCenterUpdateAlert>();
|
||||
|
||||
var alerts = new List<XenCenterUpdateAlert>();
|
||||
XenCenterVersion latest = null, latestCr = null;
|
||||
|
||||
if (xenCenterVersions.Count != 0 && currentProgramVersion != new Version(0, 0, 0, 0))
|
||||
{
|
||||
var latestVersions = from v in xenCenterVersions where v.Latest select v;
|
||||
@ -395,7 +293,7 @@ namespace XenAdmin.Core
|
||||
List<XenServerPatch> xenServerPatches)
|
||||
{
|
||||
if (Helpers.CommonCriteriaCertificationRelease)
|
||||
return null;
|
||||
return new List<XenServerPatchAlert>();
|
||||
|
||||
var alerts = new List<XenServerPatchAlert>();
|
||||
|
||||
@ -778,7 +676,7 @@ namespace XenAdmin.Core
|
||||
public static List<XenServerVersionAlert> NewXenServerVersionAlerts(List<XenServerVersion> xenServerVersions)
|
||||
{
|
||||
if (Helpers.CommonCriteriaCertificationRelease)
|
||||
return null;
|
||||
return new List<XenServerVersionAlert>();
|
||||
|
||||
var latestVersion = xenServerVersions.FindAll(item => item.Latest).OrderByDescending(v => v.Version).FirstOrDefault();
|
||||
var latestCrVersion = xenServerVersions.FindAll(item => item.LatestCr).OrderByDescending(v => v.Version).FirstOrDefault();
|
||||
@ -840,38 +738,54 @@ namespace XenAdmin.Core
|
||||
return serverVersions;
|
||||
}
|
||||
|
||||
public static void CheckServerVersion()
|
||||
public static void RefreshUpdateAlerts(UpdateType flags)
|
||||
{
|
||||
var alerts = NewXenServerVersionAlerts(XenServerVersionsForAutoCheck);
|
||||
if (alerts == null)
|
||||
return;
|
||||
var alerts = new List<XenServerUpdateAlert>();
|
||||
|
||||
alerts.ForEach(CheckUpdate);
|
||||
}
|
||||
if (flags.HasFlag(UpdateType.ServerVersion))
|
||||
alerts.AddRange(NewXenServerVersionAlerts(XenServerVersionsForAutoCheck));
|
||||
|
||||
public static void CheckServerPatches()
|
||||
{
|
||||
var alerts = NewXenServerPatchAlerts(XenServerVersions, XenServerPatches);
|
||||
if (alerts == null)
|
||||
return;
|
||||
if (flags.HasFlag(UpdateType.ServerPatches))
|
||||
alerts.AddRange(NewXenServerPatchAlerts(XenServerVersions, XenServerPatches));
|
||||
|
||||
alerts.ForEach(CheckUpdate);
|
||||
}
|
||||
bool changed = false;
|
||||
|
||||
private static void CheckUpdate(XenServerUpdateAlert alert)
|
||||
{
|
||||
var existingAlert = FindUpdate(a => a.Equals(alert));
|
||||
|
||||
if (existingAlert != null && alert.CanIgnore)
|
||||
RemoveUpdate(existingAlert);
|
||||
else if (existingAlert is XenServerUpdateAlert updAlert)
|
||||
try
|
||||
{
|
||||
RemoveUpdate(updAlert);
|
||||
updAlert.CopyConnectionsAndHosts(alert);
|
||||
AddUpdate(updAlert);
|
||||
lock (updateAlertsLock)
|
||||
{
|
||||
foreach (var alert in alerts)
|
||||
{
|
||||
var existingAlert = updateAlerts.FirstOrDefault(a => a.Equals(alert));
|
||||
|
||||
if (existingAlert != null && alert.CanIgnore)
|
||||
{
|
||||
updateAlerts.Remove(existingAlert);
|
||||
changed = true;
|
||||
}
|
||||
else if (existingAlert is XenServerUpdateAlert updAlert)
|
||||
{
|
||||
updateAlerts.Remove(updAlert);
|
||||
updAlert.CopyConnectionsAndHosts(alert);
|
||||
if (!updateAlerts.Contains(updAlert))
|
||||
updateAlerts.Add(updAlert);
|
||||
changed = true;
|
||||
}
|
||||
else if (!alert.CanIgnore && !updateAlerts.Contains(alert))
|
||||
{
|
||||
updateAlerts.Add(alert);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
UpdateAlertCollectionChanged?.Invoke(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, UpdateAlerts));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("Failed to refresh the updates", e);
|
||||
}
|
||||
else if (!alert.CanIgnore)
|
||||
AddUpdate(alert);
|
||||
}
|
||||
|
||||
public static void RestoreDismissedUpdates()
|
||||
@ -883,8 +797,7 @@ namespace XenAdmin.Core
|
||||
var action = new ParallelAction(Messages.RESTORE_DISMISSED_UPDATES, Messages.RESTORING, Messages.COMPLETED, actions, true, false);
|
||||
action.Completed += action_Completed;
|
||||
|
||||
if (RestoreDismissedUpdatesStarted != null)
|
||||
RestoreDismissedUpdatesStarted();
|
||||
RestoreDismissedUpdatesStarted?.Invoke();
|
||||
|
||||
action.RunAsync();
|
||||
}
|
||||
@ -902,7 +815,7 @@ namespace XenAdmin.Core
|
||||
|
||||
private static XenServerPatchAlert FindPatchAlert(Predicate<XenServerPatch> predicate)
|
||||
{
|
||||
var existingAlert = FindUpdate(a => a is XenServerPatchAlert patchAlert && predicate(patchAlert.Patch));
|
||||
var existingAlert = UpdateAlerts.FirstOrDefault(a => a is XenServerPatchAlert patchAlert && predicate(patchAlert.Patch));
|
||||
if (existingAlert != null)
|
||||
return existingAlert as XenServerPatchAlert;
|
||||
|
||||
@ -991,5 +904,14 @@ namespace XenAdmin.Core
|
||||
Alert.RemoveAlert(a => a is HotfixEligibilityAlert);
|
||||
Alert.AddAlertRange(alerts);
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum UpdateType : short
|
||||
{
|
||||
None = 0,
|
||||
ServerPatches = 1,
|
||||
ServerVersion = 2,
|
||||
XenCenterVersion = 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ namespace XenAdmin
|
||||
//ClipboardViewer is registered in OnHandleCreated
|
||||
OtherConfigAndTagsWatcher.RegisterEventHandlers();
|
||||
Alert.RegisterAlertCollectionChanged(XenCenterAlerts_CollectionChanged);
|
||||
Updates.RegisterCollectionChanged(Updates_CollectionChanged);
|
||||
Updates.UpdateAlertCollectionChanged += Updates_CollectionChanged;
|
||||
ConnectionsManager.History.CollectionChanged += History_CollectionChanged;
|
||||
//ConnectionsManager.XenConnections.CollectionChanged is registered in OnShown
|
||||
Properties.Settings.Default.SettingChanging += Default_SettingChanging;
|
||||
@ -266,7 +266,7 @@ namespace XenAdmin
|
||||
Clip.UnregisterClipboardViewer();
|
||||
OtherConfigAndTagsWatcher.DeregisterEventHandlers();
|
||||
Alert.DeregisterAlertCollectionChanged(XenCenterAlerts_CollectionChanged);
|
||||
Updates.DeregisterCollectionChanged(Updates_CollectionChanged);
|
||||
Updates.UpdateAlertCollectionChanged -= Updates_CollectionChanged;
|
||||
ConnectionsManager.History.CollectionChanged -= History_CollectionChanged;
|
||||
ConnectionsManager.XenConnections.CollectionChanged -= XenConnection_CollectionChanged;
|
||||
Properties.Settings.Default.SettingChanging -= Default_SettingChanging;
|
||||
@ -873,8 +873,7 @@ namespace XenAdmin
|
||||
{
|
||||
CloseActiveWizards(connection);
|
||||
Alert.RemoveAlert(alert => alert.Connection != null && alert.Connection.Equals(connection));
|
||||
Updates.CheckServerPatches();
|
||||
Updates.CheckServerVersion();
|
||||
Updates.RefreshUpdateAlerts(Updates.UpdateType.ServerPatches | Updates.UpdateType.ServerVersion);
|
||||
|
||||
RequestRefreshTreeView();
|
||||
}
|
||||
@ -996,9 +995,8 @@ namespace XenAdmin
|
||||
ThreadPool.QueueUserWorkItem(CheckHealthCheckEnrollment, connection);
|
||||
ThreadPool.QueueUserWorkItem(HealthCheck.CheckForAnalysisResults, connection);
|
||||
ThreadPool.QueueUserWorkItem(InformHealthCheckEnrollment, connection);
|
||||
|
||||
Updates.CheckServerPatches();
|
||||
Updates.CheckServerVersion();
|
||||
|
||||
Updates.RefreshUpdateAlerts(Updates.UpdateType.ServerPatches | Updates.UpdateType.ServerVersion);
|
||||
Updates.CheckHotfixEligibility(connection);
|
||||
|
||||
HealthCheck.SendMetadataToHealthCheck();
|
||||
@ -1122,8 +1120,7 @@ namespace XenAdmin
|
||||
// other_config may contain HideFromXenCenter
|
||||
UpdateToolbars();
|
||||
// other_config contains which patches to ignore
|
||||
Updates.CheckServerPatches();
|
||||
Updates.CheckServerVersion();
|
||||
Updates.RefreshUpdateAlerts(Updates.UpdateType.ServerPatches | Updates.UpdateType.ServerVersion);
|
||||
break;
|
||||
|
||||
case "name_label":
|
||||
@ -1169,17 +1166,11 @@ namespace XenAdmin
|
||||
|
||||
case "patches":
|
||||
if (!Helpers.ElyOrGreater(host))
|
||||
{
|
||||
Updates.CheckServerPatches();
|
||||
Updates.CheckServerVersion();
|
||||
}
|
||||
Updates.RefreshUpdateAlerts(Updates.UpdateType.ServerPatches | Updates.UpdateType.ServerVersion);
|
||||
break;
|
||||
case "updates":
|
||||
if (Helpers.ElyOrGreater(host))
|
||||
{
|
||||
Updates.CheckServerPatches();
|
||||
Updates.CheckServerVersion();
|
||||
}
|
||||
Updates.RefreshUpdateAlerts(Updates.UpdateType.ServerPatches | Updates.UpdateType.ServerVersion);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2571,11 +2562,11 @@ namespace XenAdmin
|
||||
navigationPane.SelectObject(obj);
|
||||
}
|
||||
|
||||
private void Updates_CollectionChanged(object sender, CollectionChangeEventArgs e)
|
||||
private void Updates_CollectionChanged(CollectionChangeEventArgs e)
|
||||
{
|
||||
Program.Invoke(this, () =>
|
||||
{
|
||||
int updatesCount = Updates.UpdateAlertsCount;
|
||||
int updatesCount = Updates.UpdateAlerts.Count;
|
||||
navigationPane.UpdateNotificationsButton(NotificationsSubMode.Updates, updatesCount);
|
||||
|
||||
statusLabelUpdates.Text = string.Format(Messages.NOTIFICATIONS_SUBMODE_UPDATES_STATUS, updatesCount);
|
||||
|
@ -522,7 +522,7 @@ namespace XenAdmin.TabPages
|
||||
}
|
||||
}
|
||||
|
||||
DismissAlerts(new List<Alert> {(Alert) clickedRow.Tag});
|
||||
DismissAlerts((Alert)clickedRow.Tag);
|
||||
}
|
||||
|
||||
private void tsmiDismissAll_Click(object sender, EventArgs e)
|
||||
@ -559,7 +559,7 @@ namespace XenAdmin.TabPages
|
||||
return;
|
||||
|
||||
var alerts = result == DialogResult.No
|
||||
? (from DataGridViewRow row in GridViewAlerts.Rows select row.Tag as Alert)
|
||||
? (from DataGridViewRow row in GridViewAlerts.Rows select row.Tag as Alert).ToArray()
|
||||
: Alert.Alerts;
|
||||
|
||||
DismissAlerts(alerts);
|
||||
@ -588,7 +588,7 @@ namespace XenAdmin.TabPages
|
||||
if (GridViewAlerts.SelectedRows.Count > 0)
|
||||
{
|
||||
var selectedAlerts = from DataGridViewRow row in GridViewAlerts.SelectedRows select row.Tag as Alert;
|
||||
DismissAlerts(selectedAlerts);
|
||||
DismissAlerts(selectedAlerts.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@ -621,7 +621,7 @@ namespace XenAdmin.TabPages
|
||||
{
|
||||
toolStripButtonExportAll.Enabled = Alert.NonDismissingAlertCount > 0;
|
||||
|
||||
tsmiDismissAll.Enabled = Alert.AllowedToDismiss(Alert.Alerts);
|
||||
tsmiDismissAll.Enabled = Alert.Alerts.Any(a => a.AllowedToDismiss());
|
||||
tsmiDismissAll.AutoToolTip = !tsmiDismissAll.Enabled;
|
||||
tsmiDismissAll.ToolTipText = tsmiDismissAll.Enabled
|
||||
? string.Empty
|
||||
@ -629,16 +629,25 @@ namespace XenAdmin.TabPages
|
||||
? Messages.DELETE_ANY_MESSAGE_RBAC_BLOCKED
|
||||
: Messages.NO_MESSAGES_TO_DISMISS;
|
||||
|
||||
var selectedAlerts = from DataGridViewRow row in GridViewAlerts.SelectedRows
|
||||
select row.Tag as Alert;
|
||||
var selectedAlerts = (from DataGridViewRow row in GridViewAlerts.SelectedRows
|
||||
select row.Tag as Alert).ToArray();
|
||||
|
||||
tsmiDismissSelected.Enabled = Alert.AllowedToDismiss(selectedAlerts);
|
||||
tsmiDismissSelected.Enabled = selectedAlerts.Any(a => a.AllowedToDismiss());
|
||||
tsmiDismissSelected.AutoToolTip = !tsmiDismissSelected.Enabled;
|
||||
tsmiDismissSelected.ToolTipText = tsmiDismissSelected.Enabled
|
||||
? string.Empty
|
||||
: Messages.DELETE_MESSAGE_RBAC_BLOCKED;
|
||||
|
||||
toolStripSplitButtonDismiss.Enabled = tsmiDismissAll.Enabled || tsmiDismissSelected.Enabled;
|
||||
toolStripSplitButtonDismiss.AutoToolTip = tsmiDismissAll.AutoToolTip || tsmiDismissSelected.AutoToolTip;
|
||||
|
||||
if (toolStripSplitButtonDismiss.AutoToolTip)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tsmiDismissAll.ToolTipText))
|
||||
toolStripSplitButtonDismiss.ToolTipText = tsmiDismissAll.ToolTipText;
|
||||
else if (!string.IsNullOrEmpty(tsmiDismissSelected.ToolTipText))
|
||||
toolStripSplitButtonDismiss.ToolTipText = tsmiDismissSelected.ToolTipText;
|
||||
}
|
||||
|
||||
if (toolStripSplitButtonDismiss.DefaultItem != null && !toolStripSplitButtonDismiss.DefaultItem.Enabled)
|
||||
{
|
||||
@ -656,23 +665,20 @@ namespace XenAdmin.TabPages
|
||||
|
||||
#region Alert dismissal
|
||||
|
||||
private void DismissAlerts(IEnumerable<Alert> alerts)
|
||||
private void DismissAlerts(params Alert[] alerts)
|
||||
{
|
||||
var groups = from Alert alert in alerts
|
||||
where alert != null && !alert.Dismissing
|
||||
where alert != null && alert.AllowedToDismiss()
|
||||
group alert by alert.Connection
|
||||
into g
|
||||
select new { Connection = g.Key, Alerts = g };
|
||||
|
||||
foreach (var g in groups)
|
||||
{
|
||||
if (Alert.AllowedToDismiss(g.Connection))
|
||||
{
|
||||
foreach (var alert in g.Alerts)
|
||||
alert.Dismissing = true;
|
||||
Rebuild();
|
||||
new DeleteAllAlertsAction(g.Connection, g.Alerts).RunAsync();
|
||||
}
|
||||
foreach (var alert in g.Alerts)
|
||||
alert.Dismissing = true;
|
||||
|
||||
new DeleteAllAlertsAction(g.Alerts.ToList(), g.Connection).RunAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@ -682,7 +688,7 @@ namespace XenAdmin.TabPages
|
||||
{
|
||||
var items = new List<ToolStripItem>();
|
||||
|
||||
if (Alert.AllowedToDismiss(alert))
|
||||
if (alert.AllowedToDismiss())
|
||||
{
|
||||
var dismiss = new ToolStripMenuItem(Messages.ALERT_DISMISS);
|
||||
dismiss.Click += ToolStripMenuItemDismiss_Click;
|
||||
@ -797,8 +803,7 @@ namespace XenAdmin.TabPages
|
||||
{
|
||||
foreach (DataGridViewRow row in GridViewAlerts.Rows)
|
||||
{
|
||||
var a = row.Tag as Alert;
|
||||
if (a != null && !a.Dismissing)
|
||||
if (row.Tag is Alert a && !a.Dismissing)
|
||||
stream.WriteLine(a.GetAlertDetailsCSVQuotes());
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,6 @@ namespace XenAdmin.TabPages
|
||||
InitializeComponent();
|
||||
spinner.SuccessImage = SystemIcons.Information.ToBitmap();
|
||||
tableLayoutPanel1.Visible = false;
|
||||
UpdateButtonEnablement();
|
||||
toolStripSplitButtonDismiss.DefaultItem = dismissAllToolStripMenuItem;
|
||||
toolStripSplitButtonDismiss.Text = dismissAllToolStripMenuItem.Text;
|
||||
|
||||
@ -86,6 +85,8 @@ namespace XenAdmin.TabPages
|
||||
{
|
||||
checksQueue--;
|
||||
}
|
||||
|
||||
UpdateButtonEnablement();
|
||||
}
|
||||
|
||||
#region NotificationPage overrides
|
||||
@ -99,7 +100,7 @@ namespace XenAdmin.TabPages
|
||||
|
||||
protected override void RegisterEventHandlers()
|
||||
{
|
||||
Updates.RegisterCollectionChanged(UpdatesCollectionChanged);
|
||||
Updates.UpdateAlertCollectionChanged += UpdatesCollectionChanged;
|
||||
Updates.RestoreDismissedUpdatesStarted += Updates_RestoreDismissedUpdatesStarted;
|
||||
Updates.CheckForUpdatesStarted += CheckForUpdates_CheckForUpdatesStarted;
|
||||
Updates.CheckForUpdatesCompleted += CheckForUpdates_CheckForUpdatesCompleted;
|
||||
@ -107,7 +108,7 @@ namespace XenAdmin.TabPages
|
||||
|
||||
protected override void DeregisterEventHandlers()
|
||||
{
|
||||
Updates.DeregisterCollectionChanged(UpdatesCollectionChanged);
|
||||
Updates.UpdateAlertCollectionChanged -= UpdatesCollectionChanged;
|
||||
Updates.RestoreDismissedUpdatesStarted -= Updates_RestoreDismissedUpdatesStarted;
|
||||
Updates.CheckForUpdatesStarted -= CheckForUpdates_CheckForUpdatesStarted;
|
||||
Updates.CheckForUpdatesCompleted -= CheckForUpdates_CheckForUpdatesCompleted;
|
||||
@ -117,12 +118,12 @@ namespace XenAdmin.TabPages
|
||||
|
||||
#endregion
|
||||
|
||||
private void UpdatesCollectionChanged(object sender, CollectionChangeEventArgs e)
|
||||
private void UpdatesCollectionChanged(CollectionChangeEventArgs e)
|
||||
{
|
||||
switch (e.Action)
|
||||
{
|
||||
case CollectionChangeAction.Add:
|
||||
Rebuild(); // rebuild entire alert list to ensure filtering and sorting
|
||||
case CollectionChangeAction.Refresh:
|
||||
Rebuild();
|
||||
break;
|
||||
case CollectionChangeAction.Remove:
|
||||
if (e.Element is Alert a)
|
||||
@ -422,7 +423,7 @@ namespace XenAdmin.TabPages
|
||||
{
|
||||
// versions with no minimum patches
|
||||
var updatesList = new List<string>();
|
||||
var alerts = new List<Alert>(Updates.UpdateAlerts);
|
||||
var alerts = Updates.UpdateAlerts;
|
||||
if (alerts.Count == 0)
|
||||
return String.Empty;
|
||||
|
||||
@ -581,7 +582,7 @@ namespace XenAdmin.TabPages
|
||||
|
||||
ToggleCentreWarningVisibility();
|
||||
|
||||
var updates = new List<Alert>(Updates.UpdateAlerts);
|
||||
var updates = Updates.UpdateAlerts;
|
||||
if (updates.Count == 0)
|
||||
return;
|
||||
|
||||
@ -610,7 +611,7 @@ namespace XenAdmin.TabPages
|
||||
|
||||
private void ToggleCentreWarningVisibility()
|
||||
{
|
||||
if (byUpdateToolStripMenuItem.Checked && Updates.UpdateAlertsCount == 0)
|
||||
if (byUpdateToolStripMenuItem.Checked && Updates.UpdateAlerts.Count == 0)
|
||||
{
|
||||
spinner.ShowSuccessImage();
|
||||
labelProgress.Text = Messages.AVAILABLE_UPDATES_NOT_FOUND;
|
||||
@ -691,7 +692,29 @@ namespace XenAdmin.TabPages
|
||||
{
|
||||
if (byUpdateToolStripMenuItem.Checked)
|
||||
{
|
||||
toolStripButtonExportAll.Enabled = toolStripSplitButtonDismiss.Enabled = Updates.UpdateAlertsCount > 0;
|
||||
var allAlerts = Updates.UpdateAlerts;
|
||||
toolStripButtonExportAll.Enabled = allAlerts.Count > 0;
|
||||
|
||||
dismissSelectedToolStripMenuItem.Enabled = (from DataGridViewRow row in dataGridViewUpdates.SelectedRows
|
||||
select row.Tag as Alert).Any(a => a.AllowedToDismiss());
|
||||
|
||||
dismissAllToolStripMenuItem.Enabled = allAlerts.Any(a => a.AllowedToDismiss());
|
||||
toolStripSplitButtonDismiss.Enabled = dismissAllToolStripMenuItem.Enabled || dismissSelectedToolStripMenuItem.Enabled;
|
||||
|
||||
if (toolStripSplitButtonDismiss.DefaultItem != null && !toolStripSplitButtonDismiss.DefaultItem.Enabled)
|
||||
{
|
||||
foreach (ToolStripItem item in toolStripSplitButtonDismiss.DropDownItems)
|
||||
{
|
||||
if (item.Enabled)
|
||||
{
|
||||
toolStripSplitButtonDismiss.DefaultItem = item;
|
||||
toolStripSplitButtonDismiss.Text = item.Text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShowInformationHelper();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -700,8 +723,19 @@ namespace XenAdmin.TabPages
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowInformationHelper(string reason)
|
||||
private void ShowInformationHelper()
|
||||
{
|
||||
string reason = null;
|
||||
|
||||
foreach (DataGridViewRow row in dataGridViewUpdates.SelectedRows)
|
||||
{
|
||||
if (row.Tag is XenServerPatchAlert alert)
|
||||
{
|
||||
reason = alert.CannotApplyReason;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(reason))
|
||||
{
|
||||
tableLayoutPanel1.Visible = false;
|
||||
@ -758,25 +792,22 @@ namespace XenAdmin.TabPages
|
||||
{
|
||||
var items = new List<ToolStripItem>();
|
||||
|
||||
var patchAlert = alert as XenServerPatchAlert;
|
||||
|
||||
if (Alert.AllowedToDismiss(alert))
|
||||
if (alert.AllowedToDismiss())
|
||||
{
|
||||
var dismiss = new ToolStripMenuItem(Messages.ALERT_DISMISS);
|
||||
dismiss.Click += ToolStripMenuItemDismiss_Click;
|
||||
items.Add(dismiss);
|
||||
}
|
||||
|
||||
if (patchAlert != null && patchAlert.CanApply && !string.IsNullOrEmpty(patchAlert.Patch.PatchUrl) && patchAlert.RequiredXenCenterVersion == null)
|
||||
if (alert is XenServerPatchAlert patchAlert && 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)
|
||||
if (alert is XenServerUpdateAlert updateAlert && updateAlert.RequiredXenCenterVersion != null)
|
||||
{
|
||||
var downloadNewXenCenter = new ToolStripMenuItem(Messages.UPDATES_DOWNLOAD_REQUIRED_XENCENTER);
|
||||
downloadNewXenCenter.Click += ToolStripMenuItemDownloadNewXenCenter_Click;
|
||||
@ -803,28 +834,17 @@ namespace XenAdmin.TabPages
|
||||
|
||||
#region Update dismissal
|
||||
|
||||
private void DismissUpdates(IEnumerable<Alert> alerts)
|
||||
private void DismissUpdates(List<Alert> alerts)
|
||||
{
|
||||
var groups = from Alert alert in alerts
|
||||
where alert != null && !alert.Dismissing
|
||||
group alert by alert.Connection
|
||||
into g
|
||||
select new { Connection = g.Key, Alerts = g };
|
||||
var filtered = alerts.Where(a => a.AllowedToDismiss()).ToList();
|
||||
|
||||
foreach (var g in groups)
|
||||
{
|
||||
if (Alert.AllowedToDismiss(g.Connection))
|
||||
{
|
||||
foreach (Alert alert in g.Alerts)
|
||||
{
|
||||
alert.Dismissing = true;
|
||||
}
|
||||
toolStripButtonRestoreDismissed.Enabled = false;
|
||||
DeleteAllAlertsAction action = new DeleteAllAlertsAction(g.Connection, g.Alerts);
|
||||
action.Completed += DeleteAllAlertsAction_Completed;
|
||||
action.RunAsync();
|
||||
}
|
||||
}
|
||||
foreach (Alert alert in filtered)
|
||||
alert.Dismissing = true;
|
||||
|
||||
toolStripButtonRestoreDismissed.Enabled = false;
|
||||
var action = new DeleteAllAlertsAction(filtered);
|
||||
action.Completed += DeleteAllAlertsAction_Completed;
|
||||
action.RunAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -890,7 +910,7 @@ namespace XenAdmin.TabPages
|
||||
return;
|
||||
|
||||
var alerts = result == DialogResult.No
|
||||
? from DataGridViewRow row in dataGridViewUpdates.Rows select row.Tag as Alert
|
||||
? (from DataGridViewRow row in dataGridViewUpdates.Rows select row.Tag as Alert).ToList()
|
||||
: Updates.UpdateAlerts;
|
||||
|
||||
DismissUpdates(alerts);
|
||||
@ -923,7 +943,7 @@ namespace XenAdmin.TabPages
|
||||
if (dataGridViewUpdates.SelectedRows.Count > 0)
|
||||
{
|
||||
var selectedAlerts = from DataGridViewRow row in dataGridViewUpdates.SelectedRows select row.Tag as Alert;
|
||||
DismissUpdates(selectedAlerts);
|
||||
DismissUpdates(selectedAlerts.ToList());
|
||||
}
|
||||
}
|
||||
|
||||
@ -961,7 +981,7 @@ namespace XenAdmin.TabPages
|
||||
}
|
||||
}
|
||||
|
||||
DismissUpdates(new List<Alert> { (Alert)clickedRow.Tag });
|
||||
DismissUpdates(new List<Alert> {(Alert)clickedRow.Tag});
|
||||
}
|
||||
|
||||
private DataGridViewRow FindAlertRow(ToolStripMenuItem toolStripMenuItem)
|
||||
@ -1071,17 +1091,10 @@ namespace XenAdmin.TabPages
|
||||
|
||||
private void dataGridViewUpdates_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
string reason = null;
|
||||
if (_buildInProgress)
|
||||
return;
|
||||
|
||||
if (dataGridViewUpdates.SelectedRows.Count > 0)
|
||||
{
|
||||
var alert = dataGridViewUpdates.SelectedRows[0].Tag as XenServerPatchAlert;
|
||||
|
||||
if (alert != null)
|
||||
reason = alert.CannotApplyReason;
|
||||
}
|
||||
|
||||
ShowInformationHelper(reason);
|
||||
UpdateButtonEnablement();
|
||||
}
|
||||
|
||||
private void dataGridViewUpdates_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
|
||||
@ -1249,15 +1262,15 @@ namespace XenAdmin.TabPages
|
||||
|
||||
if (exportAll)
|
||||
{
|
||||
foreach (Alert a in Updates.UpdateAlerts)
|
||||
var alerts = Updates.UpdateAlerts;
|
||||
foreach (Alert a in alerts)
|
||||
stream.WriteLine(a.GetUpdateDetailsCSVQuotes());
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (DataGridViewRow row in dataGridViewUpdates.Rows)
|
||||
{
|
||||
var a = row.Tag as Alert;
|
||||
if (a != null)
|
||||
if (row.Tag is Alert a)
|
||||
stream.WriteLine(a.GetUpdateDetailsCSVQuotes());
|
||||
}
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
{
|
||||
CleanUploadedPatches();
|
||||
RemoveDownloadedPatches();
|
||||
Updates.CheckServerPatches();
|
||||
Updates.RefreshUpdateAlerts(Updates.UpdateType.ServerPatches);
|
||||
base.FinishWizard();
|
||||
}
|
||||
|
||||
|
@ -364,7 +364,7 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
{
|
||||
try
|
||||
{
|
||||
var updates = Updates.UpdateAlerts.ToList();
|
||||
var updates = Updates.UpdateAlerts;
|
||||
|
||||
if (dataGridViewPatches.SortedColumn != null)
|
||||
{
|
||||
@ -484,7 +484,7 @@ namespace XenAdmin.Wizards.PatchingWizard
|
||||
|
||||
private void _backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
|
||||
{
|
||||
Updates.CheckServerPatches();
|
||||
Updates.RefreshUpdateAlerts(Updates.UpdateType.ServerPatches);
|
||||
}
|
||||
|
||||
private void _backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
|
||||
|
@ -29,24 +29,35 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using XenAdmin.Network;
|
||||
using XenAPI;
|
||||
|
||||
namespace XenAdmin.Actions
|
||||
{
|
||||
public class DestroyMessageAction : PureAsyncAction
|
||||
{
|
||||
private readonly string OpaqueRef;
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public DestroyMessageAction(IXenConnection connection, string messageopaqueref)
|
||||
: base(connection, "destroying message", string.Format("message opaque_ref = {0}", messageopaqueref), true)
|
||||
private readonly string _opaqueRef;
|
||||
|
||||
public DestroyMessageAction(Message message)
|
||||
: base(message.Connection, "destroying message", string.Format("message opaque_ref = {0}", message.opaque_ref), true)
|
||||
{
|
||||
OpaqueRef = messageopaqueref;
|
||||
_opaqueRef = message.opaque_ref;
|
||||
}
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
Message.destroy(Session, OpaqueRef);
|
||||
try
|
||||
{
|
||||
Message.destroy(Session, _opaqueRef);
|
||||
}
|
||||
catch (Failure exn)
|
||||
{
|
||||
if (exn.ErrorDescription[0] != Failure.HANDLE_INVALID)
|
||||
throw;
|
||||
|
||||
log.Error(exn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -216,24 +216,14 @@ namespace XenAdmin.Alerts
|
||||
/// </summary>
|
||||
public DateTime Timestamp => _timestamp;
|
||||
|
||||
/// <summary>
|
||||
/// Dismisses the Alert: marks it as dealt with in some way. May only be called once.
|
||||
/// </summary>
|
||||
public virtual void Dismiss()
|
||||
{
|
||||
RemoveAlert(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dismiss the alert, making a single API call if this is a remote message (Dismiss will launch a complete
|
||||
/// action).
|
||||
///
|
||||
/// The normal behaviour here is the same as Dismiss() -- it's only when overridden by MessageAlert that there
|
||||
/// is a difference.
|
||||
/// </summary>
|
||||
public virtual void DismissSingle(Session s)
|
||||
public virtual bool AllowedToDismiss()
|
||||
{
|
||||
Dismiss();
|
||||
return !Dismissing;
|
||||
}
|
||||
|
||||
public virtual bool IsDismissed()
|
||||
@ -278,7 +268,7 @@ namespace XenAdmin.Alerts
|
||||
/// </summary>
|
||||
public abstract string HelpID { get; }
|
||||
|
||||
public IXenConnection Connection;
|
||||
public IXenConnection Connection { get; protected set; }
|
||||
|
||||
public virtual bool Equals(Alert other)
|
||||
{
|
||||
@ -358,52 +348,8 @@ namespace XenAdmin.Alerts
|
||||
sortResult = string.Compare(alert1.uuid, alert2.uuid);
|
||||
return sortResult;
|
||||
}
|
||||
|
||||
|
||||
#region Update dismissal
|
||||
|
||||
public static bool AllowedToDismiss(Alert alert)
|
||||
{
|
||||
return AllowedToDismiss(new[] { alert });
|
||||
}
|
||||
|
||||
public static bool AllowedToDismiss(IEnumerable<Alert> alerts)
|
||||
{
|
||||
var alertConnections = (from Alert alert in alerts
|
||||
where alert != null && !alert.Dismissing
|
||||
let con = alert.Connection
|
||||
select con).Distinct();
|
||||
|
||||
return alertConnections.Any(AllowedToDismiss);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the user has sufficient RBAC privileges to clear updates on a given connection
|
||||
/// </summary>
|
||||
public static bool AllowedToDismiss(IXenConnection c)
|
||||
{
|
||||
// check if local alert
|
||||
if (c == null)
|
||||
return true;
|
||||
|
||||
// have we disconnected? Alert will disappear soon, but for now block dismissal.
|
||||
if (c.Session == null)
|
||||
return false;
|
||||
|
||||
if (c.Session.IsLocalSuperuser)
|
||||
return true;
|
||||
|
||||
List<Role> rolesAbleToCompleteAction = Role.ValidRoleList("Message.destroy", c);
|
||||
foreach (Role possibleRole in rolesAbleToCompleteAction)
|
||||
{
|
||||
if (c.Session.Roles.Contains(possibleRole))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum AlertPriority
|
||||
{
|
||||
/// <summary>
|
||||
|
2
XenModel/Messages.Designer.cs
generated
2
XenModel/Messages.Designer.cs
generated
@ -11954,7 +11954,7 @@ namespace XenAdmin {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to There are no alerts remaining which you have permission to dismiss..
|
||||
/// Looks up a localized string similar to You have no permission to dismiss the selected alerts..
|
||||
/// </summary>
|
||||
public static string DELETE_MESSAGE_RBAC_BLOCKED {
|
||||
get {
|
||||
|
@ -4278,7 +4278,7 @@ This will also delete its subfolders.</value>
|
||||
<value>Are you sure you want to delete '{0}'? This operation cannot be undone.</value>
|
||||
</data>
|
||||
<data name="DELETE_MESSAGE_RBAC_BLOCKED" xml:space="preserve">
|
||||
<value>There are no alerts remaining which you have permission to dismiss.</value>
|
||||
<value>You have no permission to dismiss the selected alerts.</value>
|
||||
</data>
|
||||
<data name="DELETE_PATCH" xml:space="preserve">
|
||||
<value>Delete Patch</value>
|
||||
|
Loading…
Reference in New Issue
Block a user