2017-01-16 20:59:50 +01:00
/ * Copyright ( c ) Citrix Systems , Inc .
2013-06-24 13:41:48 +02:00
* 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 ;
2016-11-16 13:26:26 +01:00
using System.Windows.Forms ;
using XenAdmin.Dialogs ;
2017-04-26 13:45:49 +02:00
using System.Text ;
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 ;
2016-08-08 15:37:47 +02:00
public static event Action RestoreDismissedUpdatesStarted ;
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 > ( ) ;
2016-06-29 13:49:53 +02:00
public 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
2017-02-24 13:03:03 +01:00
/// value of the parameter force. If AutomaticCheck is disabled it
/// checks for all update types if force is true; forceRefresh causes
/// the check for update action to run and refresh the Updates page
2014-01-08 14:17:02 +01:00
/// </summary>
2017-02-24 13:03:03 +01:00
public static void CheckForUpdates ( bool force , bool forceRefresh = false )
2014-01-08 14:17:02 +01:00
{
if ( Helpers . CommonCriteriaCertificationRelease )
return ;
if ( Properties . Settings . Default . AllowXenCenterUpdates | |
Properties . Settings . Default . AllowXenServerUpdates | |
2017-02-24 13:03:03 +01:00
Properties . Settings . Default . AllowPatchesUpdates | | force | | forceRefresh )
2014-01-08 14:17:02 +01:00
{
2017-04-26 13:45:49 +02:00
var action = CreateDownloadUpdatesXmlAction (
2014-01-08 14:17:02 +01:00
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 ) ;
2016-08-08 15:37:47 +02:00
action . Completed + = actionCompleted ;
2014-01-08 14:17:02 +01:00
if ( CheckForUpdatesStarted ! = null )
CheckForUpdatesStarted ( ) ;
action . RunAsync ( ) ;
}
}
2016-06-07 17:02:43 +02:00
2017-04-26 13:45:49 +02:00
private static DownloadUpdatesXmlAction CreateDownloadUpdatesXmlAction ( bool checkForXenCenter , bool checkForServerVersion , bool checkForPatches , string checkForUpdatesUrl = null )
{
2017-07-03 18:54:57 +02:00
string userAgent = string . Format ( "{0}/{1}.{2} ({3}-bit)" , Branding . BRAND_CONSOLE , Branding . XENCENTER_VERSION , Program . Version . Revision . ToString ( ) , IntPtr . Size * 8 ) ;
2017-04-26 13:45:49 +02:00
string userAgentId = GetUniqueIdHash ( ) ;
return new DownloadUpdatesXmlAction ( checkForXenCenter , checkForServerVersion , checkForPatches , userAgent , userAgentId , checkForUpdatesUrl ) ;
}
2017-06-26 23:06:45 +02:00
internal static string GetUniqueIdHash ( )
2017-04-26 13:45:49 +02:00
{
string uniqueIdHash = "nil" ;
try
{
var managementObj = new System . Management . ManagementObject ( "Win32_OperatingSystem=@" ) ;
string serialNumber = ( string ) managementObj [ "SerialNumber" ] ;
if ( ! string . IsNullOrWhiteSpace ( serialNumber ) )
{
var serialBytes = Encoding . ASCII . GetBytes ( serialNumber ) ;
using ( var md = new System . Security . Cryptography . MD5CryptoServiceProvider ( ) ) // MD5 to keep it short enough as this hash is not used for security in any way
{
var hash = md . ComputeHash ( serialBytes ) ;
uniqueIdHash = BitConverter . ToString ( hash ) . Replace ( "-" , "" ) . ToLowerInvariant ( ) ;
}
}
}
catch ( Exception ex )
{
log . Error ( ex ) ;
}
return uniqueIdHash ;
}
2016-11-16 13:26:26 +01:00
/// <summary>
/// It does exactly what CheckForUpdates(true) does, but this is sync and shows an ActionProgressDialog while running
/// </summary>
/// <returns>true if the action has succeeded</returns>
public static bool CheckForUpdatesSync ( Control parentForProgressDialog )
{
if ( Helpers . CommonCriteriaCertificationRelease )
return false ;
2017-04-26 13:45:49 +02:00
var action = CreateDownloadUpdatesXmlAction ( true , true , true , Updates . CheckForUpdatesUrl ) ;
2016-11-16 13:26:26 +01:00
action . Completed + = actionCompleted ;
if ( CheckForUpdatesStarted ! = null )
CheckForUpdatesStarted ( ) ;
using ( var dialog = new ActionProgressDialog ( action , ProgressBarStyle . Marquee ) )
dialog . ShowDialog ( parentForProgressDialog ) ;
return action . Succeeded ;
}
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 )
{
2017-01-19 18:51:25 +01:00
XenCenterVersions = action . XenCenterVersions ;
2014-01-08 14:17:02 +01:00
2017-01-19 18:51:25 +01:00
XenServerVersionsForAutoCheck = action . XenServerVersionsForAutoCheck ;
2015-08-04 18:28:29 +02:00
2017-01-19 18:51:25 +01:00
XenServerVersions = action . XenServerVersions ;
2013-11-21 15:27:34 +01:00
2017-01-19 18:51:25 +01:00
XenServerPatches = action . XenServerPatches ;
2014-01-08 14:17:02 +01:00
}
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 )
2017-09-03 04:33:29 +02:00
return ( master . BuildNumberRaw ( ) = = version . BuildNumber ) ;
2013-06-24 13:41:48 +02:00
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 = >
{
2016-10-05 13:55:34 +02:00
bool elyOrGreater = Helpers . ElyOrGreater ( host ) ;
var appliedUpdates = host . AppliedUpdates ( ) ;
2014-02-17 10:31:57 +01:00
var appliedPatches = host . AppliedPatches ( ) ;
2016-10-05 13:55:34 +02:00
// 1. patch is not already installed
if ( elyOrGreater & & appliedUpdates . Any ( update = > string . Equals ( update . uuid , serverPatch . Uuid , StringComparison . OrdinalIgnoreCase ) ) )
return false ;
2016-10-12 17:49:43 +02:00
else if ( ! elyOrGreater & & appliedPatches . Any ( patch = > string . Equals ( patch . uuid , serverPatch . Uuid , StringComparison . OrdinalIgnoreCase ) ) )
2016-10-05 13:55:34 +02:00
return false ;
2014-02-17 10:31:57 +01:00
// 2. the host has all the required patches installed
if ( serverPatch . RequiredPatches ! = null & & serverPatch . RequiredPatches . Count > 0 & &
2016-10-05 13:55:34 +02:00
! serverPatch . RequiredPatches
. All ( requiredPatchUuid = >
elyOrGreater & & appliedUpdates . Any ( update = > string . Equals ( update . uuid , requiredPatchUuid , StringComparison . OrdinalIgnoreCase ) )
2016-10-12 17:49:43 +02:00
| | ! elyOrGreater & & appliedPatches . Any ( patch = > string . Equals ( patch . uuid , requiredPatchUuid , StringComparison . OrdinalIgnoreCase ) )
2016-10-05 13:55:34 +02:00
)
)
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-10-05 13:55:34 +02:00
serverPatch . ConflictingPatches
. Any ( conflictingPatchUuid = >
elyOrGreater & & appliedUpdates . Any ( update = > string . Equals ( update . uuid , conflictingPatchUuid , StringComparison . OrdinalIgnoreCase ) )
2016-10-12 17:49:43 +02:00
| | ! elyOrGreater & & appliedPatches . Any ( patch = > string . Equals ( patch . uuid , conflictingPatchUuid , StringComparison . OrdinalIgnoreCase ) )
2016-10-05 13:55:34 +02:00
)
)
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 )
2017-09-03 04:33:29 +02:00
return ( host . BuildNumberRaw ( ) = = version . BuildNumber ) ;
2016-06-08 14:34:59 +02:00
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 )
{
2016-08-10 11:48:22 +02:00
var minimumPatches = serverVersions [ 0 ] . MinimalPatches ;
2016-06-08 14:34:59 +02:00
2016-08-08 19:30:54 +02:00
if ( minimumPatches = = null ) //unknown
return recommendedPatches ;
2016-10-05 13:55:34 +02:00
bool elyOrGreater = Helpers . ElyOrGreater ( host ) ;
2016-06-08 14:34:59 +02:00
var appliedPatches = host . AppliedPatches ( ) ;
2016-10-05 13:55:34 +02:00
var appliedUpdates = host . AppliedUpdates ( ) ;
if ( elyOrGreater )
{
recommendedPatches = minimumPatches . FindAll ( p = > ! appliedUpdates . Any ( au = > string . Equals ( au . uuid , p . Uuid , StringComparison . OrdinalIgnoreCase ) ) ) ;
}
else
{
recommendedPatches = minimumPatches . FindAll ( p = > ! appliedPatches . Any ( ap = > string . Equals ( ap . uuid , p . Uuid , StringComparison . OrdinalIgnoreCase ) ) ) ;
}
2016-06-08 14:34:59 +02:00
}
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-11-16 14:53:29 +01:00
if ( XenServerVersions = = null )
2016-08-09 17:53:02 +02:00
return null ;
2016-02-02 20:12:38 +01:00
Host master = Helpers . GetMaster ( conn ) ;
if ( master = = null )
return null ;
2016-11-16 14:53:29 +01:00
var version = GetCommonServerVersionOfHostsInAConnection ( conn , XenServerVersions ) ;
2016-08-10 13:50:45 +02:00
2016-08-10 11:48:22 +02:00
if ( version ! = null )
2016-02-02 20:12:38 +01:00
{
2016-08-10 11:48:22 +02:00
if ( version . MinimalPatches = = null )
2016-08-08 19:30:54 +02:00
return null ;
2016-08-10 13:50:45 +02:00
var uSeq = new UpgradeSequence ( ) ;
2016-08-10 11:48:22 +02:00
uSeq . MinimalPatches = version . MinimalPatches ;
2016-02-02 20:12:38 +01:00
2016-08-10 11:48:22 +02:00
List < Host > hosts = conn . Cache . Hosts . ToList ( ) ;
2016-08-10 13:50:45 +02:00
2016-02-02 20:12:38 +01:00
foreach ( Host h in hosts )
{
2016-08-10 11:48:22 +02:00
uSeq [ h ] = GetUpgradeSequenceForHost ( h , uSeq . MinimalPatches ) ;
2016-02-02 20:27:08 +01:00
}
2016-08-09 17:53:02 +02:00
return uSeq ;
2016-02-02 20:27:08 +01:00
}
2016-08-08 19:30:54 +02:00
else
{
return null ;
}
2016-02-02 20:27:08 +01:00
}
2016-02-02 20:12:38 +01:00
2016-08-10 11:48:22 +02:00
/// <summary>
2016-08-11 12:14:32 +02:00
/// Returns a XenServerVersion if all hosts of the pool have the same version
2016-08-10 11:48:22 +02:00
/// Returns null if it is unknown or they don't match
/// </summary>
/// <returns></returns>
2016-08-10 13:50:45 +02:00
private static XenServerVersion GetCommonServerVersionOfHostsInAConnection ( IXenConnection connection , List < XenServerVersion > xsVersions )
2016-08-10 11:48:22 +02:00
{
2016-08-10 13:50:45 +02:00
XenServerVersion commonXenServerVersion = null ;
2016-08-10 11:48:22 +02:00
if ( connection = = null )
return null ;
List < Host > hosts = connection . Cache . Hosts . ToList ( ) ;
foreach ( Host host in hosts )
{
2016-08-10 13:50:45 +02:00
var hostVersions = xsVersions . FindAll ( version = >
2016-08-10 11:48:22 +02:00
{
if ( version . BuildNumber ! = string . Empty )
2017-09-03 04:33:29 +02:00
return ( host . BuildNumberRaw ( ) = = version . BuildNumber ) ;
2016-08-10 11:48:22 +02:00
return Helpers . HostProductVersionWithOEM ( host ) = = version . VersionAndOEM
| | ( version . Oem ! = null & & Helpers . OEMName ( host ) . StartsWith ( version . Oem )
& & Helpers . HostProductVersion ( host ) = = version . Version . ToString ( ) ) ;
} ) ;
var foundVersion = hostVersions . FirstOrDefault ( ) ;
if ( foundVersion = = null )
{
return null ;
}
else
{
2016-08-10 13:50:45 +02:00
if ( commonXenServerVersion = = null )
2016-08-10 11:48:22 +02:00
{
2016-08-10 13:50:45 +02:00
commonXenServerVersion = foundVersion ;
2016-08-10 11:48:22 +02:00
}
else
{
2016-08-10 13:50:45 +02:00
if ( commonXenServerVersion ! = foundVersion )
2016-08-10 11:48:22 +02:00
return null ;
}
}
}
2016-08-10 13:50:45 +02:00
return commonXenServerVersion ;
2016-08-10 11:48:22 +02:00
}
private static List < XenServerPatch > GetUpgradeSequenceForHost ( Host h , List < XenServerPatch > latestPatches )
2016-02-02 20:27:08 +01:00
{
var sequence = new List < XenServerPatch > ( ) ;
2016-10-05 13:55:34 +02:00
var appliedUpdateUuids = new List < string > ( ) ;
bool elyOrGreater = Helpers . ElyOrGreater ( h ) ;
if ( elyOrGreater )
{
appliedUpdateUuids = h . AppliedUpdates ( ) . Select ( u = > u . uuid ) . ToList ( ) ;
}
else
{
appliedUpdateUuids = h . AppliedPatches ( ) . Select ( p = > p . uuid ) . ToList ( ) ;
}
2016-02-02 20:27:08 +01:00
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
2016-10-05 13:55:34 +02:00
! appliedUpdateUuids . Any ( apu = > string . Equals ( apu , p . Uuid , StringComparison . OrdinalIgnoreCase ) )
2016-03-31 16:40:23 +02:00
// 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-10-05 13:55:34 +02:00
| | ( appliedUpdateUuids . Count ! = 0 & & appliedUpdateUuids . Any ( apu = > string . Equals ( apu , 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
{
2016-08-02 17:58:24 +02:00
var uniquePatches = new List < XenServerPatch > ( ) ;
foreach ( var mp in MinimalPatches )
{
if ( AllPatches . Any ( p = > p . Uuid = = mp . Uuid ) )
{
uniquePatches . Add ( mp ) ;
}
}
return uniquePatches ;
2016-03-24 19:24:12 +01:00
}
}
2016-07-19 10:12:30 +02:00
public bool AllHostsUpToDate
{
get
{
if ( this . Count = = 0 )
return false ;
foreach ( var host in this . Keys )
{
if ( this [ host ] . Count > 0 )
return false ;
}
return true ;
}
}
2016-08-02 17:58:24 +02:00
public List < XenServerPatch > MinimalPatches
{
set ;
get ;
}
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 ( )
{
2016-08-08 15:37:47 +02:00
var actions = new List < AsyncAction > ( ) ;
foreach ( IXenConnection connection in ConnectionsManager . XenConnectionsCopy )
actions . Add ( new RestoreDismissedUpdatesAction ( connection ) ) ;
2015-07-30 15:58:23 +02:00
2016-08-08 15:37:47 +02:00
var action = new ParallelAction ( Messages . RESTORE_DISMISSED_UPDATES , Messages . RESTORING , Messages . COMPLETED , actions , true , false ) ;
action . Completed + = action_Completed ;
2015-07-23 14:37:14 +02:00
2016-08-08 15:37:47 +02:00
if ( RestoreDismissedUpdatesStarted ! = null )
RestoreDismissedUpdatesStarted ( ) ;
2015-07-23 14:37:14 +02:00
2016-08-08 15:37:47 +02:00
action . RunAsync ( ) ;
2015-07-23 14:37:14 +02:00
}
2015-11-05 16:49:38 +01:00
2016-08-08 15:37:47 +02:00
private static void action_Completed ( ActionBase action )
2015-11-05 16:49:38 +01:00
{
2016-08-08 15:37:47 +02:00
Program . Invoke ( Program . MainWindow , ( ) = >
2015-11-05 16:49:38 +01:00
{
2016-08-08 15:37:47 +02:00
Properties . Settings . Default . LatestXenCenterSeen = "" ;
Settings . TrySaveSettings ( ) ;
CheckForUpdates ( true ) ;
} ) ;
2015-11-05 16:49:38 +01:00
}
2013-06-24 13:41:48 +02:00
}
}