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 ;
using System.ComponentModel ;
using System.Drawing ;
2015-01-26 16:43:36 +01:00
using System.IO ;
2016-08-19 13:11:50 +02:00
using System.Linq ;
2013-06-24 13:41:48 +02:00
using System.Reflection ;
using System.Threading ;
using log4net ;
using XenAdmin.Controls ;
using XenAdmin.Diagnostics.Problems ;
2015-02-27 18:00:03 +01:00
using XenAdmin.Dialogs ;
2013-06-24 13:41:48 +02:00
using XenAdmin.Wizards.PatchingWizard.PlanActions ;
using XenAPI ;
using XenAdmin.Actions ;
2016-08-19 13:11:50 +02:00
using XenAdmin.Core ;
2013-06-24 13:41:48 +02:00
namespace XenAdmin.Wizards.PatchingWizard
{
public partial class PatchingWizard_PatchingPage : XenTabPage
{
protected static readonly ILog log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2016-10-20 18:19:42 +02:00
public Dictionary < string , livepatch_status > LivePatchCodesByHost
2016-08-23 19:16:33 +02:00
{
get ;
set ;
}
2013-06-24 13:41:48 +02:00
private bool _thisPageHasBeenCompleted = false ;
private BackgroundWorker actionsWorker = null ;
public PatchingWizard_PatchingPage ( )
{
InitializeComponent ( ) ;
}
#region Accessors
public List < Host > SelectedMasters { private get ; set ; }
public List < Host > SelectedServers { private get ; set ; }
public List < Pool > SelectedPools { private get ; set ; }
public UpdateType SelectedUpdateType { private get ; set ; }
public Pool_patch Patch { private get ; set ; }
2016-10-04 15:58:54 +02:00
public Pool_update PoolUpdate { private get ; set ; }
2013-06-24 13:41:48 +02:00
public string ManualTextInstructions { private get ; set ; }
public bool IsAutomaticMode { private get ; set ; }
2015-07-08 18:35:50 +02:00
public bool RemoveUpdateFile { private get ; set ; }
2013-06-24 13:41:48 +02:00
public string SelectedNewPatch { private get ; set ; }
public List < Problem > ProblemsResolvedPreCheck { private get ; set ; }
2015-01-26 16:43:36 +01:00
public Dictionary < Host , VDI > SuppPackVdis { private get ; set ; }
2013-06-24 13:41:48 +02:00
#endregion
public override string Text
{
get
{
return Messages . PATCHINGWIZARD_PATCHINGPAGE_TEXT ;
}
}
public override string PageTitle
{
get
{
return Messages . PATCHINGWIZARD_PATCHINGPAGE_TITLE ;
}
}
public override string HelpID
{
get { return "InstallUpdate" ; }
}
public override bool EnablePrevious ( )
{
return false ;
}
private bool _nextEnabled ;
public override bool EnableNext ( )
{
return _nextEnabled ;
}
private bool _cancelEnabled ;
public override bool EnableCancel ( )
{
return _cancelEnabled ;
}
2018-03-09 01:31:46 +01:00
protected override void PageLoadedCore ( PageLoadedDirection direction )
2013-06-24 13:41:48 +02:00
{
if ( _thisPageHasBeenCompleted )
{
actionsWorker = null ;
return ;
}
2016-10-04 15:58:54 +02:00
2013-06-24 13:41:48 +02:00
if ( ! IsAutomaticMode )
{
2016-03-03 12:34:00 +01:00
textBoxLog . Text = ManualTextInstructions ;
List < AsyncAction > actions = new List < AsyncAction > ( ) ;
2016-10-04 15:58:54 +02:00
if ( SelectedUpdateType = = UpdateType . ISO & & PoolUpdate ! = null )
{
//Ely or greater: iso update format
2017-02-03 18:41:23 +01:00
foreach ( var server in SelectedServers )
actions . Add ( new ApplyUpdateAction ( PoolUpdate , server ) ) ;
2016-10-04 15:58:54 +02:00
}
2015-01-26 16:43:36 +01:00
else
2016-10-04 15:58:54 +02:00
{
//legacy mode
if ( SelectedUpdateType ! = UpdateType . ISO )
2017-02-03 18:41:23 +01:00
{
foreach ( var server in SelectedServers )
actions . Add ( new ApplyPatchAction ( Patch , server ) ) ;
}
2016-10-04 15:58:54 +02:00
else
2017-02-03 18:41:23 +01:00
actions . Add ( new InstallSupplementalPackAction ( SuppPackVdis , false ) ) ;
2016-10-04 15:58:54 +02:00
}
2016-03-03 12:34:00 +01:00
2016-08-31 11:42:09 +02:00
if ( RemoveUpdateFile & & SelectedUpdateType ! = UpdateType . ISO )
2016-03-03 12:34:00 +01:00
{
foreach ( Pool pool in SelectedPools )
{
actions . Add ( new PoolPatchCleanAction ( pool , Patch , false ) ) ;
}
}
using ( var multipleAction = new MultipleAction ( Connection , "" , "" , "" , actions , true , true , true ) )
{
multipleAction . Changed + = action_Changed ;
multipleAction . Completed + = action_Completed ;
multipleAction . RunAsync ( ) ;
}
2013-06-24 13:41:48 +02:00
return ;
}
_nextEnabled = false ;
OnPageUpdated ( ) ;
List < PlanAction > planActions = new List < PlanAction > ( ) ;
foreach ( Pool pool in SelectedPools )
{
2016-10-04 15:58:54 +02:00
var poolHosts = new List < Host > ( pool . Connection . Cache . Hosts ) ;
Host master = SelectedServers . Find ( host = > host . IsMaster ( ) & & poolHosts . Contains ( host ) ) ;
//For Ely or greater: ISO updates only
2017-01-16 20:59:50 +01:00
if ( SelectedUpdateType = = UpdateType . ISO & & Helpers . ElyOrGreater ( pool . Connection ) ) //updates for Ely (or higher) are always ISO
2015-01-26 16:43:36 +01:00
{
2016-10-04 15:58:54 +02:00
var poolUpdates = new List < Pool_update > ( pool . Connection . Cache . Pool_updates ) ;
var poolUpdate = poolUpdates . FirstOrDefault ( u = > u ! = null & & string . Equals ( u . uuid , PoolUpdate . uuid , StringComparison . OrdinalIgnoreCase ) ) ;
//master first
if ( master ! = null & & ! poolUpdate . AppliedOn ( master ) )
{
planActions . AddRange ( CompilePoolUpdateActionList ( master , poolUpdate ) ) ;
}
2013-06-24 13:41:48 +02:00
2016-10-04 15:58:54 +02:00
//other hosts
foreach ( var host in SelectedServers . Where ( s = > poolHosts . Contains ( s ) & & ! s . IsMaster ( ) & & ! poolUpdate . AppliedOn ( s ) ) . ToList ( ) )
{
planActions . AddRange ( CompilePoolUpdateActionList ( host , poolUpdate ) ) ;
}
}
// Legacy (pre-Ely) case: either ISO for supplemental packs (Pool_patch == null) or patch (Pool_patch != null)
else
2016-09-09 13:02:59 +02:00
{
2016-10-04 15:58:54 +02:00
Pool_patch poolPatch = null ;
if ( SelectedUpdateType ! = UpdateType . ISO )
2016-09-09 13:02:59 +02:00
{
2016-10-04 15:58:54 +02:00
List < Pool_patch > poolPatches = new List < Pool_patch > ( pool . Connection . Cache . Pool_patches ) ;
poolPatch = poolPatches . Find ( delegate ( Pool_patch otherPatch )
{
if ( Patch ! = null )
return string . Equals ( otherPatch . uuid , Patch . uuid , StringComparison . OrdinalIgnoreCase ) ;
return false ;
} ) ;
}
2016-09-09 13:02:59 +02:00
2016-10-04 15:58:54 +02:00
//master first
if ( master ! = null & & ( poolPatch = = null | | poolPatch . AppliedOn ( master ) = = DateTime . MaxValue ) )
planActions . AddRange ( CompileActionList ( master , poolPatch ) ) ;
2016-09-09 13:02:59 +02:00
2016-10-04 15:58:54 +02:00
foreach ( Host server in SelectedServers )
{
if ( poolHosts . Contains ( server ) )
2016-09-09 13:02:59 +02:00
{
2016-10-04 15:58:54 +02:00
if ( ! server . IsMaster ( ) )
{
// check patch isn't already applied here
if ( poolPatch = = null | | poolPatch . AppliedOn ( server ) = = DateTime . MaxValue )
planActions . AddRange ( CompileActionList ( server , poolPatch ) ) ;
}
2016-09-09 13:02:59 +02:00
}
}
2016-10-04 15:58:54 +02:00
if ( RemoveUpdateFile )
2013-06-24 13:41:48 +02:00
{
2016-10-04 15:58:54 +02:00
planActions . Add ( new RemoveUpdateFile ( pool , poolPatch ) ) ;
2013-06-24 13:41:48 +02:00
}
}
2016-10-04 15:58:54 +02:00
} //end pool in foreach
2014-02-03 12:13:45 +01:00
planActions . Add ( new UnwindProblemsAction ( ProblemsResolvedPreCheck ) ) ;
2013-06-24 13:41:48 +02:00
actionsWorker = new BackgroundWorker ( ) ;
actionsWorker . DoWork + = new DoWorkEventHandler ( PatchingWizardAutomaticPatchWork ) ;
actionsWorker . WorkerReportsProgress = true ;
actionsWorker . ProgressChanged + = new ProgressChangedEventHandler ( actionsWorker_ProgressChanged ) ;
actionsWorker . RunWorkerCompleted + = new RunWorkerCompletedEventHandler ( actionsWorker_RunWorkerCompleted ) ;
actionsWorker . WorkerSupportsCancellation = true ;
actionsWorker . RunWorkerAsync ( planActions ) ;
}
#region manual_mode
2013-08-05 15:28:21 +02:00
private void action_Completed ( ActionBase sender )
2013-06-24 13:41:48 +02:00
{
_nextEnabled = true ;
_cancelEnabled = false ;
2013-08-05 15:28:21 +02:00
2013-06-24 13:41:48 +02:00
try
{
2015-01-26 16:43:36 +01:00
if ( sender . Exception ! = null )
{
2017-02-03 18:41:23 +01:00
var multipleAction = sender as MultipleAction ;
var actionTitle = multipleAction ! = null ? multipleAction . SubActionTitle : sender . Title ;
Program . Invoke ( Program . MainWindow , ( ) = > FinishedWithErrors ( actionTitle , new Exception ( actionTitle , sender . Exception ) ) ) ;
2015-01-26 16:43:36 +01:00
}
else
Program . Invoke ( Program . MainWindow , FinishedSuccessfully ) ;
2013-06-24 13:41:48 +02:00
}
catch ( Exception except )
{
2017-02-03 18:41:23 +01:00
Program . Invoke ( Program . MainWindow , ( ) = > FinishedWithErrors ( string . Empty , except ) ) ;
2013-06-24 13:41:48 +02:00
}
2013-08-05 15:28:21 +02:00
Program . Invoke ( Program . MainWindow , OnPageUpdated ) ;
2013-06-24 13:41:48 +02:00
_thisPageHasBeenCompleted = true ;
}
2013-08-05 15:28:21 +02:00
private void action_Changed ( ActionBase sender )
2013-06-24 13:41:48 +02:00
{
AsyncAction action = ( AsyncAction ) sender ;
Program . Invoke ( Program . MainWindow , delegate { progressBar . Value = action . PercentComplete ; } ) ;
}
#endregion
#region automatic_mode
private void actionsWorker_ProgressChanged ( object sender , ProgressChangedEventArgs e )
{
if ( ! actionsWorker . CancellationPending )
{
PlanAction action = ( PlanAction ) e . UserState ;
if ( e . ProgressPercentage = = 0 )
textBoxLog . Text + = action ;
else
{
textBoxLog . Text + = string . Format ( "{0}\r\n" , Messages . DONE ) ;
progressBar . Value + = e . ProgressPercentage ;
}
}
}
private void PatchingWizardAutomaticPatchWork ( object obj , DoWorkEventArgs doWorkEventArgs )
{
List < PlanAction > actionList = ( List < PlanAction > ) doWorkEventArgs . Argument ;
foreach ( PlanAction action in actionList )
{
try
{
if ( actionsWorker . CancellationPending )
{
doWorkEventArgs . Cancel = true ;
return ;
}
this . actionsWorker . ReportProgress ( 0 , action ) ;
action . Run ( ) ;
Thread . Sleep ( 1000 ) ;
this . actionsWorker . ReportProgress ( ( int ) ( ( 1.0 / ( double ) actionList . Count ) * 100 ) , action ) ;
}
catch ( Exception e )
{
log . Error ( "Failed to carry out plan." , e ) ;
log . Debug ( actionList ) ;
2015-02-27 18:00:03 +01:00
doWorkEventArgs . Result = new Exception ( action . Title , e ) ;
2013-06-24 13:41:48 +02:00
break ;
}
}
}
private void actionsWorker_RunWorkerCompleted ( object sender , RunWorkerCompletedEventArgs e )
{
if ( ! e . Cancelled )
{
Exception exception = e . Result as Exception ;
if ( exception ! = null )
{
2017-02-03 18:41:23 +01:00
FinishedWithErrors ( exception . Message , exception ) ; // here exception.Message is the Title of the action that failed (see how doWorkEventArgs.Result is assigned above)
2013-06-24 13:41:48 +02:00
}
else
{
FinishedSuccessfully ( ) ;
}
progressBar . Value = 100 ;
_cancelEnabled = false ;
_nextEnabled = true ;
}
OnPageUpdated ( ) ;
_thisPageHasBeenCompleted = true ;
}
private List < PlanAction > CompileActionList ( Host host , Pool_patch patch )
{
2016-08-31 11:42:09 +02:00
if ( SelectedUpdateType = = UpdateType . ISO )
2015-01-26 16:43:36 +01:00
return CompileSuppPackActionList ( host ) ;
2013-06-24 13:41:48 +02:00
List < PlanAction > actions = new List < PlanAction > ( ) ;
2015-01-26 16:43:36 +01:00
if ( patch = = null )
return actions ;
2015-11-08 17:31:48 +01:00
actions . Add ( new ApplyPatchPlanAction ( host , patch ) ) ;
2013-06-24 13:41:48 +02:00
2018-03-05 11:15:39 +01:00
if ( patch . after_apply_guidance . Contains ( after_apply_guidance . restartHost )
& & ! ( LivePatchCodesByHost ! = null & & LivePatchCodesByHost . ContainsKey ( host . uuid ) & & LivePatchCodesByHost [ host . uuid ] = = livepatch_status . ok_livepatch_complete ) )
2013-06-24 13:41:48 +02:00
{
2018-03-06 16:12:04 +01:00
actions . Add ( new RestartHostPlanAction ( host , host . GetRunningVMs ( ) ) ) ;
2013-06-24 13:41:48 +02:00
}
if ( patch . after_apply_guidance . Contains ( after_apply_guidance . restartXAPI ) )
{
actions . Add ( new RestartAgentPlanAction ( host ) ) ;
}
if ( patch . after_apply_guidance . Contains ( after_apply_guidance . restartHVM ) )
{
2018-03-01 13:42:33 +01:00
actions . Add ( new RebootVMsPlanAction ( host , host . GetRunningHvmVMs ( ) ) ) ;
2013-06-24 13:41:48 +02:00
}
if ( patch . after_apply_guidance . Contains ( after_apply_guidance . restartPV ) )
{
2018-03-01 13:42:33 +01:00
actions . Add ( new RebootVMsPlanAction ( host , host . GetRunningPvVMs ( ) ) ) ;
2013-06-24 13:41:48 +02:00
}
return actions ;
}
2015-01-26 16:43:36 +01:00
private List < PlanAction > CompileSuppPackActionList ( Host host )
{
List < PlanAction > actions = new List < PlanAction > ( ) ;
2016-08-31 11:42:09 +02:00
if ( SelectedUpdateType ! = UpdateType . ISO | | SuppPackVdis = = null | | ! SuppPackVdis . ContainsKey ( host ) )
2015-01-26 16:43:36 +01:00
return actions ;
actions . Add ( new InstallSupplementalPackPlanAction ( host , SuppPackVdis [ host ] ) ) ;
// after_apply_guidance is restartHost
2018-03-06 16:12:04 +01:00
actions . Add ( new RestartHostPlanAction ( host , host . GetRunningVMs ( ) ) ) ;
2015-01-26 16:43:36 +01:00
return actions ;
}
2016-10-04 15:58:54 +02:00
private List < PlanAction > CompilePoolUpdateActionList ( Host host , Pool_update poolUpdate )
{
List < PlanAction > actions = new List < PlanAction > ( ) ;
if ( SelectedUpdateType ! = UpdateType . ISO | | poolUpdate = = null )
return actions ;
actions . Add ( new ApplyPoolUpdatePlanAction ( host , poolUpdate ) ) ;
if ( poolUpdate . after_apply_guidance . Contains ( update_after_apply_guidance . restartHost )
2016-10-20 18:19:42 +02:00
& & ! ( LivePatchCodesByHost ! = null & & LivePatchCodesByHost . ContainsKey ( host . uuid ) & & LivePatchCodesByHost [ host . uuid ] = = livepatch_status . ok_livepatch_complete ) )
2016-10-04 15:58:54 +02:00
{
2018-03-06 16:12:04 +01:00
actions . Add ( new RestartHostPlanAction ( host , host . GetRunningVMs ( ) ) ) ;
2016-10-04 15:58:54 +02:00
}
if ( poolUpdate . after_apply_guidance . Contains ( update_after_apply_guidance . restartXAPI ) )
{
actions . Add ( new RestartAgentPlanAction ( host ) ) ;
}
if ( poolUpdate . after_apply_guidance . Contains ( update_after_apply_guidance . restartHVM ) )
{
2018-03-01 13:42:33 +01:00
actions . Add ( new RebootVMsPlanAction ( host , host . GetRunningHvmVMs ( ) ) ) ;
2016-10-04 15:58:54 +02:00
}
if ( poolUpdate . after_apply_guidance . Contains ( update_after_apply_guidance . restartPV ) )
{
2018-03-01 13:42:33 +01:00
actions . Add ( new RebootVMsPlanAction ( host , host . GetRunningPvVMs ( ) ) ) ;
2016-10-04 15:58:54 +02:00
}
return actions ;
}
2013-06-24 13:41:48 +02:00
#endregion
2017-02-03 18:41:23 +01:00
private void FinishedWithErrors ( string actionTitle , Exception exception )
2013-06-24 13:41:48 +02:00
{
2015-01-26 16:43:36 +01:00
labelTitle . Text = string . Format ( Messages . UPDATE_WAS_NOT_COMPLETED , GetUpdateName ( ) ) ;
2016-03-01 17:06:42 +01:00
string errorMessage = null ;
if ( exception ! = null & & exception . InnerException ! = null & & exception . InnerException is Failure )
{
var innerEx = exception . InnerException as Failure ;
2017-02-03 18:41:23 +01:00
errorMessage = string . Format ( Messages . STRING_SPACE_STRING , actionTitle , innerEx . Message ) ;
2016-03-01 17:51:01 +01:00
if ( innerEx . ErrorDescription ! = null & & innerEx . ErrorDescription . Count > 0 )
log . Error ( string . Concat ( innerEx . ErrorDescription . ToArray ( ) ) ) ;
2016-03-01 17:06:42 +01:00
}
labelError . Text = errorMessage ? ? string . Format ( Messages . PATCHING_WIZARD_ERROR , exception . Message ) ;
2016-03-01 17:10:24 +01:00
log . ErrorFormat ( "Error message displayed: {0}" , labelError . Text ) ;
2013-06-24 13:41:48 +02:00
pictureBox1 . Image = SystemIcons . Error . ToBitmap ( ) ;
2015-02-27 18:00:03 +01:00
if ( exception . InnerException is SupplementalPackInstallFailedException )
{
errorLinkLabel . Visible = true ;
errorLinkLabel . Tag = exception . InnerException ;
}
2013-06-24 13:41:48 +02:00
panel1 . Visible = true ;
}
2016-08-19 13:11:50 +02:00
/// <summary>
/// Live patching is attempted for a host if the LivePatchCodesByHost contains the LIVEPATCH_COMPLETE value for that host
/// </summary>
/// <param name="host"></param>
/// <returns></returns>
private bool LivePatchingAttemptedForHost ( Host host )
{
return LivePatchCodesByHost ! = null & & LivePatchCodesByHost . ContainsKey ( host . uuid ) & &
2016-10-20 18:19:42 +02:00
LivePatchCodesByHost [ host . uuid ] = = livepatch_status . ok_livepatch_complete ;
2016-08-19 13:11:50 +02:00
}
/// <summary>
2016-10-12 15:48:17 +02:00
/// Returns true if <paramref name="host"/> has to be rebooted for this update
2016-08-19 13:11:50 +02:00
/// </summary>
2016-10-12 15:48:17 +02:00
private bool HostRequiresReboot ( Host host )
2016-08-19 13:11:50 +02:00
{
2016-10-12 15:48:17 +02:00
return
host . updates_requiring_reboot ! = null & & PoolUpdate ! = null
& & host . updates_requiring_reboot . Select ( uRef = > host . Connection . Resolve ( uRef ) ) . Any ( u = > u ! = null & & u . uuid . Equals ( PoolUpdate . uuid ) ) ;
2016-08-19 13:11:50 +02:00
}
2013-06-24 13:41:48 +02:00
private void FinishedSuccessfully ( )
{
2015-01-26 16:43:36 +01:00
labelTitle . Text = string . Format ( Messages . UPDATE_WAS_SUCCESSFULLY_INSTALLED , GetUpdateName ( ) ) ;
2013-06-24 13:41:48 +02:00
pictureBox1 . Image = null ;
labelError . Text = Messages . CLOSE_WIZARD_CLICK_FINISH ;
2016-08-19 13:11:50 +02:00
// Live patching failed is per-host
var livePatchingFailedHosts = new List < Host > ( ) ;
foreach ( var host in SelectedMasters )
{
2016-10-12 15:48:17 +02:00
if ( LivePatchingAttemptedForHost ( host ) & & HostRequiresReboot ( host ) )
2016-08-19 13:11:50 +02:00
{
livePatchingFailedHosts . Add ( host ) ;
}
}
if ( livePatchingFailedHosts . Count = = 0 )
{
return ;
}
LivePatchingFailed ( livePatchingFailedHosts ) ;
}
private void LivePatchingFailed ( IList < Host > hosts )
{
string dialogMessage ;
if ( hosts . Count = = 1 )
{
dialogMessage = string . Format ( Messages . LIVE_PATCHING_FAILED_ONE_HOST , hosts [ 0 ] ) ;
}
else
{
dialogMessage = string . Format ( Messages . LIVE_PATCHING_FAILED_MULTI_HOST ,
string . Join ( Messages . LIST_SEPARATOR , hosts . Select ( s = > s . ToString ( ) . SurroundWith ( '\'' ) ) ) ) ;
}
using ( var dlg = new ThreeButtonDialog (
new ThreeButtonDialog . Details ( SystemIcons . Warning ,
dialogMessage , Messages . XENCENTER ) ,
ThreeButtonDialog . ButtonOK ) )
{
dlg . ShowDialog ( Program . MainWindow ) ;
}
2013-06-24 13:41:48 +02:00
}
2015-01-26 16:43:36 +01:00
private string GetUpdateName ( )
{
2015-01-28 10:51:25 +01:00
if ( Patch ! = null )
2017-09-03 04:33:29 +02:00
return Patch . Name ( ) ;
2015-01-28 10:51:25 +01:00
try
{
return new FileInfo ( SelectedNewPatch ) . Name ;
}
catch ( Exception )
{
return SelectedNewPatch ;
}
2015-01-26 16:43:36 +01:00
}
2015-02-27 18:00:03 +01:00
private void errorLinkLabel_LinkClicked ( object sender , System . Windows . Forms . LinkLabelLinkClickedEventArgs e )
{
if ( errorLinkLabel . Tag is Exception )
ShowMoreInfo ( errorLinkLabel . Tag as Exception ) ;
}
private void ShowMoreInfo ( Exception exception )
{
if ( ! ( exception is SupplementalPackInstallFailedException ) )
return ;
var msg = string . Format ( Messages . SUPP_PACK_INSTALL_FAILED_MORE_INFO , exception . Message ) ;
2016-06-20 11:49:12 +02:00
using ( var dlg = new ThreeButtonDialog ( new ThreeButtonDialog . Details ( SystemIcons . Error , msg ) ) )
{
dlg . ShowDialog ( this ) ;
}
2015-02-27 18:00:03 +01:00
}
2013-06-24 13:41:48 +02:00
}
}