2013-06-24 13:41:48 +02:00
/ * 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 ;
2013-12-05 13:46:39 +01:00
using System.ComponentModel ;
2013-06-24 13:41:48 +02:00
using System.Linq ;
using XenAdmin.Actions ;
using XenAPI ;
using XenAdmin.Alerts ;
using XenAdmin.Network ;
2016-02-02 20:12:38 +01:00
using System.Diagnostics ;
2013-06-24 13:41:48 +02:00
namespace XenAdmin.Core
{
public class Updates
{
private static readonly log4net . ILog log = log4net . LogManager . GetLogger ( System . Reflection . MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2013-11-21 15:27:34 +01:00
public static event Action < bool , string > CheckForUpdatesCompleted ;
2013-12-05 13:46:39 +01:00
public static event Action CheckForUpdatesStarted ;
2013-11-21 15:27:34 +01:00
2014-01-08 14:17:02 +01:00
private static readonly object downloadedUpdatesLock = new object ( ) ;
2015-08-04 18:28:29 +02:00
private static List < XenServerVersion > XenServerVersionsForAutoCheck = new List < XenServerVersion > ( ) ;
2013-12-05 13:46:39 +01:00
private static List < XenServerPatch > XenServerPatches = new List < XenServerPatch > ( ) ;
2014-01-08 14:17:02 +01:00
private static List < XenCenterVersion > XenCenterVersions = new List < XenCenterVersion > ( ) ;
2015-08-04 18:28:29 +02:00
private static List < XenServerVersion > XenServerVersions = new List < XenServerVersion > ( ) ;
2013-12-05 13:46:39 +01:00
private static readonly object updateAlertsLock = new object ( ) ;
private static readonly ChangeableList < Alert > updateAlerts = new ChangeableList < Alert > ( ) ;
public static IEnumerable < Alert > UpdateAlerts
2013-11-21 15:27:34 +01:00
{
get { return updateAlerts ; }
}
2013-12-05 13:46:39 +01:00
public static int UpdateAlertsCount
{
get { return updateAlerts . Count ; }
}
private static void AddUpate ( Alert update )
{
try
{
lock ( updateAlertsLock )
2015-07-29 14:43:47 +02:00
{
2015-08-03 16:12:42 +02:00
if ( ! updateAlerts . Contains ( update ) )
{
updateAlerts . Add ( update ) ;
}
2015-07-29 14:43:47 +02:00
}
2013-12-05 13:46:39 +01:00
}
catch ( Exception e )
{
log . Error ( "Failed to add update" , e ) ;
}
}
2015-07-23 12:48:14 +02:00
public static void RemoveUpdate ( Alert update )
2013-12-05 13:46:39 +01:00
{
try
{
lock ( updateAlertsLock )
2015-08-04 17:27:12 +02:00
{
if ( updateAlerts . Contains ( update ) )
{
updateAlerts . Remove ( update ) ;
}
}
2013-12-05 13:46:39 +01:00
}
catch ( Exception e )
{
log . Error ( "Failed to remove update" , e ) ;
}
}
2015-07-29 14:43:47 +02:00
/// <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>
/// <param name="toBeDismissed"></param>
public static void DismissUpdates ( List < Alert > toBeDismissed )
{
2015-11-05 16:49:38 +01:00
if ( toBeDismissed . Count = = 0 )
return ;
2015-07-29 14:43:47 +02:00
foreach ( IXenConnection connection in ConnectionsManager . XenConnectionsCopy )
{
2015-11-05 16:49:38 +01:00
if ( ! Alert . AllowedToDismiss ( connection ) )
continue ;
2015-07-29 14:43:47 +02:00
XenAPI . 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 )
{
if ( other_config . ContainsKey ( IgnorePatchAction . IgnorePatchKey ) )
{
List < string > current = new List < string > ( other_config [ IgnorePatchAction . IgnorePatchKey ] . Split ( ',' ) ) ;
2016-02-08 11:14:05 +01:00
if ( current . Contains ( ( ( XenServerPatchAlert ) alert ) . Patch . Uuid , StringComparer . OrdinalIgnoreCase ) )
2015-07-29 14:43:47 +02:00
continue ;
current . Add ( ( ( XenServerPatchAlert ) alert ) . Patch . Uuid ) ;
other_config [ IgnorePatchAction . IgnorePatchKey ] = string . Join ( "," , current . ToArray ( ) ) ;
}
else
{
other_config . Add ( IgnorePatchAction . IgnorePatchKey , ( ( XenServerPatchAlert ) alert ) . Patch . Uuid ) ;
}
}
if ( alert is XenServerVersionAlert )
{
if ( other_config . ContainsKey ( IgnoreServerAction . LAST_SEEN_SERVER_VERSION_KEY ) )
{
List < string > current = new List < string > ( other_config [ IgnoreServerAction . LAST_SEEN_SERVER_VERSION_KEY ] . Split ( ',' ) ) ;
if ( current . Contains ( ( ( XenServerVersionAlert ) alert ) . Version . VersionAndOEM ) )
continue ;
current . Add ( ( ( XenServerVersionAlert ) alert ) . Version . VersionAndOEM ) ;
other_config [ IgnoreServerAction . LAST_SEEN_SERVER_VERSION_KEY ] = string . Join ( "," , current . ToArray ( ) ) ;
}
else
{
other_config . Add ( IgnoreServerAction . LAST_SEEN_SERVER_VERSION_KEY , ( ( XenServerVersionAlert ) alert ) . Version . VersionAndOEM ) ;
}
}
Updates . RemoveUpdate ( alert ) ;
}
XenAPI . Pool . set_other_config ( connection . Session , pool . opaque_ref , other_config ) ;
}
}
2013-12-05 13:46:39 +01:00
private static Alert FindUpdate ( Alert alert )
{
lock ( updateAlertsLock )
return FindUpdate ( a = > a . Equals ( alert ) ) ;
}
private static Alert FindUpdate ( Predicate < Alert > predicate )
{
lock ( updateAlertsLock )
return updateAlerts . Find ( predicate ) ;
}
2013-11-21 15:27:34 +01:00
2014-01-08 14:17:02 +01:00
/// <summary>
/// If AutomaticCheck is enabled it checks for updates regardless the
/// value of the parameter force. If AutomaticCheck is disabled it only
/// checks if force is true.
/// </summary>
public static void CheckForUpdates ( bool force )
{
if ( Helpers . CommonCriteriaCertificationRelease )
return ;
if ( Properties . Settings . Default . AllowXenCenterUpdates | |
Properties . Settings . Default . AllowXenServerUpdates | |
Properties . Settings . Default . AllowPatchesUpdates | | force )
{
DownloadUpdatesXmlAction action = new DownloadUpdatesXmlAction (
Properties . Settings . Default . AllowXenCenterUpdates | | force ,
Properties . Settings . Default . AllowXenServerUpdates | | force ,
2016-02-04 11:39:14 +01:00
Properties . Settings . Default . AllowPatchesUpdates | | force ,
2016-06-07 17:02:43 +02:00
Updates . CheckForUpdatesUrl ) ;
2014-01-08 14:17:02 +01:00
{
action . Completed + = actionCompleted ;
}
if ( CheckForUpdatesStarted ! = null )
CheckForUpdatesStarted ( ) ;
action . RunAsync ( ) ;
}
}
2016-06-07 17:02:43 +02:00
public static string CheckForUpdatesUrl
{
get
{
return Registry . CustomUpdatesXmlLocation ? ? Branding . CheckForUpdatesUrl ;
}
}
2013-11-21 15:27:34 +01:00
private static void actionCompleted ( ActionBase sender )
{
Program . AssertOffEventThread ( ) ;
2013-12-05 13:46:39 +01:00
2013-11-21 15:27:34 +01:00
DownloadUpdatesXmlAction action = sender as DownloadUpdatesXmlAction ;
2013-12-05 13:46:39 +01:00
if ( action = = null )
return ;
2013-11-21 15:27:34 +01:00
2013-12-05 13:46:39 +01:00
bool succeeded = action . Succeeded ;
2013-11-21 15:27:34 +01:00
string errorMessage = string . Empty ;
2013-12-05 13:46:39 +01:00
lock ( updateAlertsLock )
2013-11-21 15:27:34 +01:00
updateAlerts . Clear ( ) ;
2013-12-05 13:46:39 +01:00
if ( succeeded )
{
2014-01-08 14:17:02 +01:00
lock ( downloadedUpdatesLock )
{
var xcvs = action . XenCenterVersions . Where ( v = > ! XenCenterVersions . Contains ( v ) ) ;
XenCenterVersions . AddRange ( xcvs ) ;
2015-08-04 18:28:29 +02:00
var versForAutoCheck = action . XenServerVersionsForAutoCheck . Where ( v = > ! XenServerVersionsForAutoCheck . Contains ( v ) ) ;
XenServerVersionsForAutoCheck . AddRange ( versForAutoCheck ) ;
2014-01-08 14:17:02 +01:00
var vers = action . XenServerVersions . Where ( v = > ! XenServerVersions . Contains ( v ) ) ;
XenServerVersions . AddRange ( vers ) ;
2013-11-21 15:27:34 +01:00
2014-01-08 14:17:02 +01:00
var patches = action . XenServerPatches . Where ( p = > ! XenServerPatches . Contains ( p ) ) ;
XenServerPatches . AddRange ( patches ) ;
}
var xenCenterAlert = NewXenCenterUpdateAlert ( XenCenterVersions , Program . Version ) ;
2015-07-23 12:48:14 +02:00
if ( xenCenterAlert ! = null & & ! xenCenterAlert . IsDismissed ( ) )
2013-12-05 13:46:39 +01:00
updateAlerts . Add ( xenCenterAlert ) ;
2013-11-21 15:27:34 +01:00
2015-08-04 18:28:29 +02:00
var xenServerUpdateAlert = NewXenServerVersionAlert ( XenServerVersionsForAutoCheck ) ;
2014-01-08 14:17:02 +01:00
if ( xenServerUpdateAlert ! = null & & ! xenServerUpdateAlert . CanIgnore )
2013-12-05 13:46:39 +01:00
updateAlerts . Add ( xenServerUpdateAlert ) ;
2014-01-08 14:17:02 +01:00
var xenServerPatchAlerts = NewXenServerPatchAlerts ( XenServerVersions , XenServerPatches ) ;
2013-12-05 13:46:39 +01:00
if ( xenServerPatchAlerts ! = null )
2014-01-08 14:17:02 +01:00
updateAlerts . AddRange ( xenServerPatchAlerts . Where ( alert = > ! alert . CanIgnore ) ) ;
2013-12-05 13:46:39 +01:00
}
else
{
if ( action . Exception ! = null )
2013-11-21 15:27:34 +01:00
{
2013-12-05 13:46:39 +01:00
if ( action . Exception is System . Net . Sockets . SocketException )
2013-11-21 15:27:34 +01:00
{
2013-12-05 13:46:39 +01:00
errorMessage = Messages . AVAILABLE_UPDATES_NETWORK_ERROR ;
2013-11-21 15:27:34 +01:00
}
2013-12-05 13:46:39 +01:00
else
2013-11-21 15:27:34 +01:00
{
2013-12-05 13:46:39 +01:00
// Clean up and remove excess newlines, carriage returns, trailing nonsense
string errorText = action . Exception . Message . Trim ( ) ;
errorText = System . Text . RegularExpressions . Regex . Replace ( errorText , @"\r\n+" , "" ) ;
errorMessage = string . Format ( Messages . AVAILABLE_UPDATES_ERROR , errorText ) ;
2013-11-21 15:27:34 +01:00
}
}
2013-12-05 13:46:39 +01:00
if ( string . IsNullOrEmpty ( errorMessage ) )
errorMessage = Messages . AVAILABLE_UPDATES_INTERNAL_ERROR ;
2013-11-21 15:27:34 +01:00
}
if ( CheckForUpdatesCompleted ! = null )
CheckForUpdatesCompleted ( succeeded , errorMessage ) ;
}
2014-01-08 14:17:02 +01:00
2013-12-05 13:46:39 +01:00
public static void RegisterCollectionChanged ( CollectionChangeEventHandler handler )
{
updateAlerts . CollectionChanged + = handler ;
}
public static void DeregisterCollectionChanged ( CollectionChangeEventHandler handler )
{
updateAlerts . CollectionChanged - = handler ;
}
2013-06-24 13:41:48 +02:00
2013-12-05 13:59:38 +01:00
public static XenCenterUpdateAlert NewXenCenterUpdateAlert ( List < XenCenterVersion > xenCenterVersions , Version currentProgramVersion )
2013-06-24 13:41:48 +02:00
{
if ( Helpers . CommonCriteriaCertificationRelease )
return null ;
2014-01-08 14:17:02 +01:00
XenCenterVersion toUse = null ;
if ( xenCenterVersions . Count ! = 0 & & currentProgramVersion ! = new Version ( 0 , 0 , 0 , 0 ) )
{
var latest = from v in xenCenterVersions where v . IsLatest select v ;
toUse = latest . FirstOrDefault ( xcv = > xcv . Lang = = Program . CurrentLanguage ) ? ?
latest . FirstOrDefault ( xcv = > string . IsNullOrEmpty ( xcv . Lang ) ) ;
}
2013-06-24 13:41:48 +02:00
if ( toUse = = null )
return null ;
if ( toUse . Version > currentProgramVersion | |
( toUse . Version = = currentProgramVersion & & toUse . Lang = = Program . CurrentLanguage & &
! PropertyManager . IsCultureLoaded ( Program . CurrentCulture ) ) )
{
return new XenCenterUpdateAlert ( toUse ) ;
}
log . Info ( string . Format ( "Not alerting XenCenter update - lastest = {0}, detected = {1}" ,
toUse . VersionAndLang , Program . VersionAndLanguage ) ) ;
return null ;
}
2013-12-05 13:59:38 +01:00
public static List < XenServerPatchAlert > NewXenServerPatchAlerts ( List < XenServerVersion > xenServerVersions ,
2013-12-05 12:34:16 +01:00
List < XenServerPatch > xenServerPatches )
2013-06-24 13:41:48 +02:00
{
if ( Helpers . CommonCriteriaCertificationRelease )
return null ;
2014-01-08 14:17:02 +01:00
var alerts = new List < XenServerPatchAlert > ( ) ;
2013-06-24 13:41:48 +02:00
foreach ( IXenConnection xenConnection in ConnectionsManager . XenConnectionsCopy )
{
Host master = Helpers . GetMaster ( xenConnection ) ;
Pool pool = Helpers . GetPoolOfOne ( xenConnection ) ;
List < Host > hosts = xenConnection . Cache . Hosts . ToList ( ) ;
if ( master = = null | | pool = = null )
continue ;
2014-01-08 14:17:02 +01:00
var serverVersions = xenServerVersions . FindAll ( version = >
2013-06-24 13:41:48 +02:00
{
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 ( ) ) ;
} ) ;
if ( serverVersions . Count = = 0 )
continue ;
foreach ( XenServerVersion xenServerVersion in serverVersions )
{
XenServerVersion version = xenServerVersion ;
List < XenServerPatch > patches = xenServerPatches . FindAll ( patch = > version . Patches . Contains ( patch ) ) ;
if ( patches . Count = = 0 )
continue ;
foreach ( XenServerPatch xenServerPatch in patches )
{
2014-01-08 14:17:02 +01:00
var alert = new XenServerPatchAlert ( xenServerPatch ) ;
var existingAlert = alerts . Find ( al = > al . Equals ( alert ) ) ;
if ( existingAlert ! = null )
alert = existingAlert ;
else
alerts . Add ( alert ) ;
if ( ! xenConnection . IsConnected )
continue ;
2013-06-24 13:41:48 +02:00
XenServerPatch serverPatch = xenServerPatch ;
2014-02-17 10:31:57 +01:00
// 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 = >
{
var appliedPatches = host . AppliedPatches ( ) ;
// 1. patch is not already installed
2016-02-08 11:14:05 +01:00
if ( appliedPatches . Any ( patch = > string . Equals ( patch . uuid , serverPatch . Uuid , StringComparison . OrdinalIgnoreCase ) ) )
2014-02-17 10:31:57 +01:00
return false ;
// 2. the host has all the required patches installed
if ( serverPatch . RequiredPatches ! = null & & serverPatch . RequiredPatches . Count > 0 & &
2016-02-08 11:14:05 +01:00
! serverPatch . RequiredPatches . All ( requiredPatchUuid = > appliedPatches . Any ( patch = > string . Equals ( patch . uuid , requiredPatchUuid , StringComparison . OrdinalIgnoreCase ) ) ) )
2014-02-17 10:31:57 +01:00
return false ;
// 3. the host doesn't have any of the conflicting patches installed
if ( serverPatch . ConflictingPatches ! = null & & serverPatch . ConflictingPatches . Count > 0 & &
2016-02-08 11:14:05 +01:00
serverPatch . ConflictingPatches . Any ( conflictingPatchUuid = > appliedPatches . Any ( patch = > string . Equals ( patch . uuid , conflictingPatchUuid , StringComparison . OrdinalIgnoreCase ) ) ) )
2014-02-17 10:31:57 +01:00
return false ;
return true ;
} ) ;
2013-06-24 13:41:48 +02:00
2013-12-05 13:03:34 +01:00
if ( noPatchHosts . Count ( ) = = hosts . Count )
2013-06-24 13:41:48 +02:00
alert . IncludeConnection ( xenConnection ) ;
else
alert . IncludeHosts ( noPatchHosts ) ;
}
}
}
return alerts ;
}
2016-02-02 20:12:38 +01:00
2016-06-08 14:34:59 +02:00
/// <summary>
/// This method returns the minimal set of patches for a host if this class already has information about them. Otherwise it returns empty list.
/// Calling this function will not initiate a download or update.
/// </summary>
/// <param name="host"></param>
/// <returns></returns>
public static List < XenServerPatch > RecommendedPatchesForHost ( Host host )
{
var recommendedPatches = new List < XenServerPatch > ( ) ;
if ( XenServerVersions = = null )
return recommendedPatches ;
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 ( ) ) ;
} ) ;
if ( serverVersions . Count ! = 0 )
{
var minimumPatches = new List < XenServerPatch > ( ) ;
minimumPatches = serverVersions [ 0 ] . MinimalPatches ;
var appliedPatches = host . AppliedPatches ( ) ;
recommendedPatches = minimumPatches . FindAll ( p = > ! appliedPatches . Any ( ap = > string . Equals ( ap . uuid , p . Uuid , StringComparison . OrdinalIgnoreCase ) ) ) ;
}
return recommendedPatches ;
}
2016-03-24 19:24:12 +01:00
public static UpgradeSequence GetUpgradeSequence ( IXenConnection conn )
2016-02-02 20:12:38 +01:00
{
2016-03-24 19:24:12 +01:00
var uSeq = new UpgradeSequence ( ) ;
2016-02-02 20:12:38 +01:00
Host master = Helpers . GetMaster ( conn ) ;
if ( master = = null )
return null ;
2016-06-08 14:34:59 +02:00
List < Host > hosts = conn . Cache . Hosts . ToList ( ) ;
2016-02-02 20:12:38 +01:00
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 ( ) ) ;
} ) ;
List < XenServerPatch > allPatches = new List < XenServerPatch > ( ) ;
if ( serverVersions . Count > 0 )
{
2016-03-14 17:10:16 +01:00
// Take all the hotfixes for this version
2016-02-02 20:12:38 +01:00
allPatches . AddRange ( serverVersions [ 0 ] . Patches ) ;
2016-03-14 17:10:16 +01:00
var minimumPatches = serverVersions [ 0 ] . MinimalPatches ;
2016-02-02 20:12:38 +01:00
foreach ( Host h in hosts )
{
2016-03-14 17:10:16 +01:00
uSeq [ h ] = GetUpgradeSequenceForHost ( h , allPatches , minimumPatches ) ;
2016-02-02 20:27:08 +01:00
}
}
2016-02-02 20:12:38 +01:00
2016-02-02 20:27:08 +01:00
return uSeq ;
}
2016-02-02 20:12:38 +01:00
2016-02-02 20:27:08 +01:00
private static List < XenServerPatch > GetUpgradeSequenceForHost ( Host h , List < XenServerPatch > allPatches , List < XenServerPatch > latestPatches )
{
var sequence = new List < XenServerPatch > ( ) ;
var appliedPatches = h . AppliedPatches ( ) ;
var neededPatches = new List < XenServerPatch > ( latestPatches ) ;
2016-02-03 13:00:41 +01:00
//Iterate through latestPatches once; in each iteration, move the first item from L0 that has its dependencies met to the end of the Update Schedule (US)
2016-02-02 20:27:08 +01:00
for ( int ii = 0 ; ii < neededPatches . Count ; ii + + )
{
var p = neededPatches [ ii ] ;
//checking requirements
2016-03-31 16:40:23 +02:00
if ( //not applied yet
! appliedPatches . Any ( ap = > string . Equals ( ap . uuid , p . Uuid , StringComparison . OrdinalIgnoreCase ) )
// and either no requirements or they are meet
& & ( p . RequiredPatches = = null
2016-02-02 20:27:08 +01:00
| | p . RequiredPatches . Count = = 0
// all requirements met?
| | p . RequiredPatches . All (
rp = >
//sequence already has the required-patch
2016-03-16 14:46:58 +01:00
( sequence . Count ! = 0 & & sequence . Any ( useqp = > string . Equals ( useqp . Uuid , rp , StringComparison . OrdinalIgnoreCase ) ) )
2016-02-02 20:27:08 +01:00
//the required-patch has already been applied
2016-03-16 14:46:58 +01:00
| | ( appliedPatches . Count ! = 0 & & appliedPatches . Any ( ap = > string . Equals ( ap . uuid , rp , StringComparison . OrdinalIgnoreCase ) ) )
2016-02-02 20:27:08 +01:00
)
2016-03-31 16:40:23 +02:00
) )
2016-02-02 20:27:08 +01:00
{
// this patch can be added to the upgrade sequence now
2016-03-16 14:41:10 +01:00
sequence . Add ( p ) ;
2016-02-02 20:27:08 +01:00
// by now the patch has either been added to the upgrade sequence or something already contains it among the installed patches
neededPatches . RemoveAt ( ii ) ;
//resetting position - the loop will start on 0. item
ii = - 1 ;
2016-02-02 20:12:38 +01:00
}
}
2016-02-02 20:27:08 +01:00
return sequence ;
2016-02-02 20:12:38 +01:00
}
2016-03-24 19:24:12 +01:00
public class UpgradeSequence : Dictionary < Host , List < XenServerPatch > >
2016-02-02 20:12:38 +01:00
{
2016-03-24 19:24:12 +01:00
private IEnumerable < XenServerPatch > AllPatches
{
get
{
foreach ( var patches in this . Values )
foreach ( var patch in patches )
yield return patch ;
}
}
public List < XenServerPatch > UniquePatches
{
get
{
return AllPatches . Distinct ( ) . ToList ( ) ;
}
}
2016-02-02 20:12:38 +01:00
}
2013-06-24 13:41:48 +02:00
2014-01-03 09:37:45 +01:00
public static XenServerVersionAlert NewXenServerVersionAlert ( List < XenServerVersion > xenServerVersions )
2013-06-24 13:41:48 +02:00
{
if ( Helpers . CommonCriteriaCertificationRelease )
return null ;
2013-12-05 13:03:34 +01:00
var latestVersion = xenServerVersions . FindAll ( item = > item . Latest ) . OrderByDescending ( v = > v . Version ) . FirstOrDefault ( ) ;
if ( latestVersion = = null )
2013-06-24 13:41:48 +02:00
return null ;
2014-01-03 09:37:45 +01:00
var alert = new XenServerVersionAlert ( latestVersion ) ;
2013-06-24 13:41:48 +02:00
foreach ( IXenConnection xc in ConnectionsManager . XenConnectionsCopy )
{
2014-01-08 14:17:02 +01:00
if ( ! xc . IsConnected )
continue ;
2013-06-24 13:41:48 +02:00
Host master = Helpers . GetMaster ( xc ) ;
Pool pool = Helpers . GetPoolOfOne ( xc ) ;
List < Host > hosts = xc . Cache . Hosts . ToList ( ) ;
if ( master = = null | | pool = = null )
continue ;
2013-12-05 13:03:34 +01:00
var outOfDateHosts = hosts . Where ( host = > new Version ( Helpers . HostProductVersion ( host ) ) < latestVersion . Version ) ;
2013-06-24 13:41:48 +02:00
2013-12-05 13:03:34 +01:00
if ( outOfDateHosts . Count ( ) = = hosts . Count )
2013-06-24 13:41:48 +02:00
alert . IncludeConnection ( xc ) ;
else
alert . IncludeHosts ( outOfDateHosts ) ;
}
return alert ;
}
2013-12-05 13:46:39 +01:00
2014-01-08 14:17:02 +01:00
2013-12-05 13:46:39 +01:00
public static void CheckServerVersion ( )
{
2015-08-04 18:28:29 +02:00
var alert = NewXenServerVersionAlert ( XenServerVersionsForAutoCheck ) ;
2013-12-05 13:46:39 +01:00
if ( alert = = null )
return ;
2014-01-08 14:17:02 +01:00
CheckUpdate ( alert ) ;
2013-12-05 13:46:39 +01:00
}
public static void CheckServerPatches ( )
{
2014-01-08 14:17:02 +01:00
var alerts = NewXenServerPatchAlerts ( XenServerVersions , XenServerPatches ) ;
if ( alerts = = null )
2013-12-05 13:46:39 +01:00
return ;
foreach ( var alert in alerts )
2014-01-08 14:17:02 +01:00
CheckUpdate ( alert ) ;
}
private static void CheckUpdate ( XenServerUpdateAlert alert )
{
var existingAlert = FindUpdate ( alert ) ;
if ( existingAlert ! = null & & alert . CanIgnore )
RemoveUpdate ( existingAlert ) ;
else if ( existingAlert ! = null )
( ( XenServerUpdateAlert ) existingAlert ) . CopyConnectionsAndHosts ( alert ) ;
else if ( ! alert . CanIgnore )
AddUpate ( alert ) ;
2013-12-05 13:46:39 +01:00
}
2015-07-23 14:37:14 +02:00
public static void RestoreDismissedUpdates ( )
{
foreach ( IXenConnection _connection in ConnectionsManager . XenConnectionsCopy )
{
2015-11-05 16:49:38 +01:00
if ( ! AllowedToRestoreDismissedUpdates ( _connection ) )
continue ;
2015-07-23 14:37:14 +02:00
XenAPI . Pool pool = Helpers . GetPoolOfOne ( _connection ) ;
if ( pool = = null )
continue ;
Dictionary < string , string > other_config = pool . other_config ;
if ( other_config . ContainsKey ( IgnorePatchAction . IgnorePatchKey ) )
{
other_config . Remove ( IgnorePatchAction . IgnorePatchKey ) ;
}
if ( other_config . ContainsKey ( IgnoreServerAction . LAST_SEEN_SERVER_VERSION_KEY ) )
{
2015-07-30 15:58:23 +02:00
other_config . Remove ( IgnoreServerAction . LAST_SEEN_SERVER_VERSION_KEY ) ;
2015-07-23 14:37:14 +02:00
}
2015-07-30 15:58:23 +02:00
XenAPI . Pool . set_other_config ( _connection . Session , pool . opaque_ref , other_config ) ;
2015-07-23 14:37:14 +02:00
}
Properties . Settings . Default . LatestXenCenterSeen = "" ;
Settings . TrySaveSettings ( ) ;
Updates . CheckForUpdates ( true ) ;
}
2015-11-05 16:49:38 +01:00
/// <summary>
/// Checks the user has sufficient RBAC privileges to restore dismissed alerts on a given connection
/// </summary>
public static bool AllowedToRestoreDismissedUpdates ( IXenConnection c )
{
if ( c = = null | | c . Session = = null )
return false ;
if ( c . Session . IsLocalSuperuser )
return true ;
List < Role > rolesAbleToCompleteAction = Role . ValidRoleList ( "Pool.set_other_config" , c ) ;
foreach ( Role possibleRole in rolesAbleToCompleteAction )
{
if ( c . Session . Roles . Contains ( possibleRole ) )
return true ;
}
return false ;
}
2013-06-24 13:41:48 +02:00
}
}