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.Globalization ;
2015-02-25 14:01:03 +01:00
using System.Linq ;
2013-06-24 13:41:48 +02:00
using System.Threading ;
using Citrix.XenCenter ;
using XenAdmin ;
using XenAdmin.Core ;
using XenAdmin.Network ;
2017-04-11 18:31:17 +02:00
using System.Diagnostics ;
2013-06-24 13:41:48 +02:00
namespace XenAPI
{
public partial class Host : IComparable < Host > , IEquatable < Host >
{
2013-12-12 12:59:00 +01:00
private static readonly log4net . ILog log = log4net . LogManager . GetLogger ( System . Reflection . MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2013-06-24 13:41:48 +02:00
public enum Edition
{
Free ,
2013-07-01 15:03:35 +02:00
PerSocket , //Added in Clearwater (PR-1589)
2014-12-08 15:29:54 +01:00
XenDesktop , //Added in Clearwater (PR-1589) and is new form of "EnterpriseXD"
2014-10-28 17:42:27 +01:00
EnterprisePerSocket , // Added in Creedence (enterprise-per-socket)
EnterprisePerUser , // Added in Creedence (enterprise-per-user)
StandardPerSocket , // Added in Creedence (standard-per-socket)
2014-12-08 15:29:54 +01:00
Desktop , // Added in Creedence (desktop)
2016-01-21 13:31:33 +01:00
DesktopPlus , // Added in Creedence (desktop-plus)
2016-06-14 14:27:43 +02:00
Standard , // Added in Dundee/Violet (standard)
2016-01-21 13:31:33 +01:00
Premium // Added in Indigo (premium)
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public const string LicenseServerWebConsolePort = "8082" ;
2014-10-31 16:06:35 +01:00
2017-09-03 04:33:29 +02:00
public override string Name ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return name_label ;
2013-06-24 13:41:48 +02:00
}
public static Edition GetEdition ( string editionText )
{
switch ( editionText )
{
case "xendesktop" :
return Edition . XenDesktop ;
case "per-socket" :
return Edition . PerSocket ;
2014-10-28 17:42:27 +01:00
case "enterprise-per-socket" :
return Edition . EnterprisePerSocket ;
case "enterprise-per-user" :
return Edition . EnterprisePerUser ;
case "standard-per-socket" :
return Edition . StandardPerSocket ;
2014-12-08 15:29:54 +01:00
case "desktop" :
return Edition . Desktop ;
case "desktop-plus" :
return Edition . DesktopPlus ;
2016-01-25 13:07:58 +01:00
case "basic" :
return Edition . Free ;
2016-01-21 13:31:33 +01:00
case "premium" :
return Edition . Premium ;
2016-03-09 17:14:05 +01:00
case "standard" :
return Edition . Standard ;
2013-06-24 13:41:48 +02:00
default :
return Edition . Free ;
}
}
public bool CanSeeNetwork ( XenAPI . Network network )
{
System . Diagnostics . Trace . Assert ( network ! = null ) ;
// Special case for local networks.
if ( network . PIFs . Count = = 0 )
return true ;
2016-10-11 10:45:37 +02:00
foreach ( var pifRef in network . PIFs )
2013-06-24 13:41:48 +02:00
{
2016-10-11 10:45:37 +02:00
PIF pif = network . Connection . Resolve ( pifRef ) ;
if ( pif ! = null & & pif . host ! = null & & pif . host . opaque_ref = = opaque_ref )
2013-06-24 13:41:48 +02:00
return true ;
}
return false ;
}
public static string GetEditionText ( Edition edition )
{
switch ( edition )
{
2017-05-05 18:03:45 +02:00
2013-06-24 13:41:48 +02:00
case Edition . XenDesktop :
return "xendesktop" ;
case Edition . PerSocket :
return "per-socket" ;
2014-10-28 17:42:27 +01:00
case Edition . EnterprisePerSocket :
return "enterprise-per-socket" ;
case Edition . EnterprisePerUser :
return "enterprise-per-user" ;
case Edition . StandardPerSocket :
return "standard-per-socket" ;
2014-12-08 15:29:54 +01:00
case Edition . Desktop :
return "desktop" ;
case Edition . DesktopPlus :
return "desktop-plus" ;
2016-01-21 13:31:33 +01:00
case Edition . Premium :
return "premium" ;
2016-03-09 17:14:05 +01:00
case Edition . Standard :
return "standard" ;
2013-06-24 13:41:48 +02:00
default :
return "free" ;
}
}
2017-09-05 03:15:38 +02:00
public string GetIscsiIqn ( )
2013-06-24 13:41:48 +02:00
{
2017-09-05 03:15:38 +02:00
return Get ( other_config , "iscsi_iqn" ) ? ? "" ;
}
public void SetIscsiIqn ( string value )
{
SetDictionaryKey ( other_config , "iscsi_iqn" , value ) ;
2013-06-24 13:41:48 +02:00
}
public override string ToString ( )
{
return this . name_label ;
}
2017-09-03 04:33:29 +02:00
public override string Description ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( name_description = = "Default install of XenServer" | | name_description = = "Default install" ) // i18n: CA-30372, CA-207273
return Messages . DEFAULT_INSTALL_OF_XENSERVER ;
else if ( name_description = = null )
return "" ;
else
return name_description ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// The expiry date of this host's license in UTC.
/// </summary>
2017-09-03 04:33:29 +02:00
public virtual DateTime LicenseExpiryUTC ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( license_params ! = null & & license_params . ContainsKey ( "expiry" ) )
return TimeUtil . ParseISO8601DateTime ( license_params [ "expiry" ] ) ;
return new DateTime ( 2030 , 1 , 1 ) ;
2013-06-24 13:41:48 +02:00
}
public static bool RestrictRBAC ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_rbac" ) ;
2013-06-24 13:41:48 +02:00
}
public static bool RestrictDMC ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_dmc" ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Added for Clearwater
/// </summary>
/// <param name="h"></param>
/// <returns></returns>
public static bool RestrictHotfixApply ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_hotfix_apply" ) ;
2016-05-04 11:27:10 +02:00
}
2016-12-10 15:44:15 +01:00
/// <summary>
/// Restrict Automated Updates
/// </summary>
/// <param name="h">host</param>
/// <returns></returns>
2016-05-04 11:27:10 +02:00
public static bool RestrictBatchHotfixApply ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_batch_hotfix_apply" ) ;
2016-05-04 11:27:10 +02:00
}
2013-06-24 13:41:48 +02:00
public static bool RestrictCheckpoint ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_checkpoint" ) ;
2013-06-24 13:41:48 +02:00
}
2015-03-03 16:51:56 +01:00
public static bool RestrictCifs ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_cifs" ) ;
2015-03-03 16:51:56 +01:00
}
2015-12-17 16:31:41 +01:00
public static bool RestrictVendorDevice ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_pci_device_for_auto_update" ) ;
2015-12-17 16:31:41 +01:00
}
2013-06-24 13:41:48 +02:00
public static bool RestrictWLB ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_wlb" ) ;
2013-06-24 13:41:48 +02:00
}
public static bool RestrictVSwitchController ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_vswitch_controller" ) ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public static bool RestrictPooling ( Host h )
2016-01-15 15:42:36 +01:00
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_pooling" ) ;
2016-01-15 15:42:36 +01:00
}
2016-02-05 08:14:39 +01:00
public static bool RestrictVMSnapshotSchedule ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_vmss" ) ;
2016-02-05 08:14:39 +01:00
}
2013-06-24 13:41:48 +02:00
public static bool RestrictVMAppliances ( Host h )
{
2017-09-03 04:33:29 +02:00
return false ;
2013-06-24 13:41:48 +02:00
}
public static bool RestrictDR ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_dr" ) ;
2013-06-24 13:41:48 +02:00
}
public static bool RestrictCrossPoolMigrate ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_storage_xen_motion" ) ;
2013-06-24 13:41:48 +02:00
}
public virtual bool IsFreeLicense ( )
{
2015-10-26 17:01:55 +01:00
return edition = = "free" ;
2013-06-24 13:41:48 +02:00
}
2015-10-26 17:01:55 +01:00
public static bool RestrictHA ( Host h )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return ! BoolKey ( h . license_params , "enable_xha" ) ;
2013-06-24 13:41:48 +02:00
}
public static bool RestrictAlerts ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_email_alerting" ) ;
2013-06-24 13:41:48 +02:00
}
public static bool RestrictStorageChoices ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_netapp" ) ;
2013-06-24 13:41:48 +02:00
}
public static bool RestrictPerformanceGraphs ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_historical_performance" ) ;
2013-06-24 13:41:48 +02:00
}
public static bool RestrictCpuMasking ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_cpu_masking" ) ;
2013-06-24 13:41:48 +02:00
}
2013-09-18 14:06:47 +02:00
2013-06-24 13:41:48 +02:00
public static bool RestrictGpu ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_gpu" ) ;
2013-06-24 13:41:48 +02:00
}
2013-09-18 14:06:47 +02:00
public static bool RestrictVgpu ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_vgpu" ) ;
2017-01-24 03:22:35 +01:00
}
public static bool RestrictManagementOnVLAN ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_management_on_vlan" ) ;
2015-02-25 14:01:03 +01:00
}
public static bool RestrictIntegratedGpuPassthrough ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_integrated_gpu_passthrough" ) ;
2015-02-25 14:01:03 +01:00
}
2017-09-03 04:33:29 +02:00
public static bool RestrictExportResourceData ( Host h )
2014-10-27 16:58:18 +01:00
{
2017-09-03 04:33:29 +02:00
if ( Helpers . CreedenceOrGreater ( h . Connection ) )
2014-10-27 16:58:18 +01:00
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_export_resource_data" ) ;
2014-10-27 16:58:18 +01:00
}
2017-09-03 04:33:29 +02:00
// Pre-Creedence hosts:
// allowed on Per-Socket edition for Clearwater hosts
var hostEdition = GetEdition ( h . edition ) ;
if ( hostEdition = = Edition . PerSocket )
{
return h . LicenseExpiryUTC ( ) < DateTime . UtcNow - h . Connection . ServerTimeOffset ; // restrict if the license has expired
}
return true ;
2015-11-24 09:29:45 +01:00
}
2016-01-20 14:48:36 +01:00
public static bool RestrictIntraPoolMigrate ( Host h )
2015-11-24 09:29:45 +01:00
{
2017-09-03 04:33:29 +02:00
return BoolKey ( h . license_params , "restrict_xen_motion" ) ;
2015-11-24 09:29:45 +01:00
}
2016-05-20 14:01:51 +02:00
/// <summary>
/// Active directory is restricted only if the "restrict_ad" key exists and it is true
/// </summary>
public static bool RestrictAD ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKey ( h . license_params , "restrict_ad" ) ;
2015-02-19 15:09:08 +01:00
}
public static bool RestrictReadCaching ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_read_caching" ) ;
2015-06-26 11:56:58 +02:00
}
public static bool RestrictHealthCheck ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_health_check" ) ;
2015-06-26 11:56:58 +02:00
}
2015-08-17 18:32:22 +02:00
/// <summary>
/// Vss feature is restricted only if the "restrict_vss" key exists and it is true
/// </summary>
2017-09-03 04:33:29 +02:00
public static bool RestrictVss ( Host h )
2015-08-17 18:32:22 +02:00
{
2017-09-03 04:33:29 +02:00
return BoolKey ( h . license_params , "restrict_vss" ) ;
2015-08-17 18:32:22 +02:00
}
2017-09-22 17:57:09 +02:00
public static bool RestrictPoolSize ( Host h )
{
return BoolKey ( h . license_params , "restrict_pool_size" ) ;
}
2017-09-03 04:33:29 +02:00
public static bool RestrictPvsCache ( Host h )
2015-08-17 18:32:22 +02:00
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_pvs_proxy" ) ;
2015-08-17 18:32:22 +02:00
}
2016-06-24 14:16:40 +02:00
/// <summary>
/// For Dundee and greater hosts: the feature is restricted only if the "restrict_ssl_legacy_switch" key exists and it is true
/// For pre-Dundee hosts: the feature is restricted if the "restrict_ssl_legacy_switch" key is absent or it is true
/// </summary>
public static bool RestrictSslLegacySwitch ( Host h )
{
2017-09-03 04:33:29 +02:00
return Helpers . DundeeOrGreater ( h )
? BoolKey ( h . license_params , "restrict_ssl_legacy_switch" )
: BoolKeyPreferTrue ( h . license_params , "restrict_ssl_legacy_switch" ) ;
2016-09-01 15:59:37 +02:00
}
public static bool RestrictLivePatching ( Host h )
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_live_patching" ) ;
2016-09-01 15:59:37 +02:00
}
2017-07-20 13:42:43 +02:00
public static bool RestrictIGMPSnooping ( Host h )
{
2017-09-18 07:56:20 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_igmp_snooping" ) ;
2017-07-20 13:42:43 +02:00
}
2016-09-29 13:11:37 +02:00
public static bool RestrictVcpuHotplug ( Host h )
{
2017-09-03 04:33:29 +02:00
if ( Helpers . ElyOrGreater ( h . Connection ) )
2016-09-29 13:11:37 +02:00
{
2017-09-03 04:33:29 +02:00
return BoolKeyPreferTrue ( h . license_params , "restrict_set_vcpus_number_live" ) ;
2016-09-29 13:11:37 +02:00
}
2017-09-03 04:33:29 +02:00
// Pre-Ely hosts:
// allowed on Premium edition only
var hostEdition = GetEdition ( h . edition ) ;
if ( hostEdition = = Edition . Premium )
{
return h . LicenseExpiryUTC ( ) < DateTime . UtcNow - h . Connection . ServerTimeOffset ; // restrict if the license has expired
2016-09-29 13:11:37 +02:00
}
2017-09-03 04:33:29 +02:00
return true ;
2016-09-29 13:11:37 +02:00
}
2017-09-25 14:27:06 +02:00
/// <summary>
/// The feature is restricted if the "restrict_rpu" key exists and it is true
/// or if the key is absent and the host is unlicensed
/// </summary>
public static bool RestrictRpu ( Host h )
{
return h . license_params . ContainsKey ( "restrict_rpu" )
? BoolKey ( h . license_params , "restrict_rpu" )
: GetEdition ( h . edition ) = = Edition . Free | | h . LicenseExpiryUTC ( ) < DateTime . UtcNow - h . Connection . ServerTimeOffset ; // restrict on Free edition or if the license has expired
}
2013-06-24 13:41:48 +02:00
public bool HasPBDTo ( SR sr )
{
foreach ( XenRef < PBD > pbd in PBDs )
{
PBD thePBD = sr . Connection . Resolve < PBD > ( pbd ) ;
if ( thePBD ! = null & & thePBD . SR . opaque_ref = = sr . opaque_ref )
{
return true ;
}
}
return false ;
}
public PBD GetPBDTo ( SR sr )
{
foreach ( XenRef < PBD > pbd in PBDs )
{
PBD thePBD = sr . Connection . Resolve < PBD > ( pbd ) ;
if ( thePBD ! = null & & thePBD . SR . opaque_ref = = sr . opaque_ref )
{
return thePBD ;
}
}
return null ;
}
// Constants for other-config from CP-329
public const String MULTIPATH = "multipathing" ;
public const String MULTIPATH_HANDLE = "multipathhandle" ;
public const String DMP = "dmp" ;
2017-09-03 04:33:29 +02:00
public bool MultipathEnabled ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return BoolKey ( other_config , MULTIPATH ) ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public String MultipathHandle ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return Get ( other_config , MULTIPATH_HANDLE ) ;
2013-06-24 13:41:48 +02:00
}
public override int CompareTo ( Host other )
{
// CA-20865 Sort in the following order:
// * Masters first
// * Then connected slaves
// * Then disconnected servers
// Within each group, in NaturalCompare order
bool thisConnected = ( Connection . IsConnected & & Helpers . GetMaster ( Connection ) ! = null ) ;
bool otherConnected = ( other . Connection . IsConnected & & Helpers . GetMaster ( other . Connection ) ! = null ) ;
if ( thisConnected & & ! otherConnected )
return - 1 ;
else if ( ! thisConnected & & otherConnected )
return 1 ;
else if ( thisConnected )
{
bool thisIsMaster = IsMaster ( ) ;
bool otherIsMaster = other . IsMaster ( ) ;
if ( thisIsMaster & & ! otherIsMaster )
return - 1 ;
else if ( ! thisIsMaster & & otherIsMaster )
return 1 ;
}
return base . CompareTo ( other ) ;
}
public virtual bool IsMaster ( )
{
Pool pool = Helpers . GetPoolOfOne ( Connection ) ;
if ( pool = = null )
return false ;
Host master = Connection . Resolve < Host > ( pool . master ) ;
2017-09-03 04:33:29 +02:00
return master ! = null & & master . uuid = = this . uuid ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Return this host's product version triplet (e.g. 5.6.100), or null if it can't be found.
/// </summary>
2017-09-03 04:33:29 +02:00
public virtual string ProductVersion ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return Get ( software_version , "product_version" ) ;
2013-06-24 13:41:48 +02:00
}
private string MarketingVersion ( string field )
{
string s = Get ( software_version , field ) ;
2017-09-03 04:33:29 +02:00
return string . IsNullOrEmpty ( s ) ? ProductVersion ( ) : s ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Return this host's marketing version number (e.g. 5.6 Feature Pack 1),
/// or ProductVersion (which can still be null) if it can't be found, including pre-Cowley hosts.
/// </summary>
2017-09-03 04:33:29 +02:00
public string ProductVersionText ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return MarketingVersion ( "product_version_text" ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Return this host's marketing version number in short form (e.g. 5.6 FP1),
/// or ProductVersion (which can still be null) if it can't be found, including pre-Cowley hosts.
/// </summary>
2017-09-03 04:33:29 +02:00
public string ProductVersionTextShort ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return MarketingVersion ( "product_version_text_short" ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Return this host's XCP version triplet (e.g. 1.0.50), or null if it can't be found,
/// including all pre-Tampa hosts.
/// </summary>
2017-09-03 04:33:29 +02:00
public virtual string PlatformVersion ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return Get ( software_version , "platform_version" ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
2017-04-11 17:29:57 +02:00
/// For legacy build numbers only (used to be integers + one char at the end)
/// From Falcon, this property is not used.
/// </summary>
/// <remarks>
2013-06-24 13:41:48 +02:00
/// Return the build number of this host, or -1 if none can be found. This will often be
/// 0 or -1 for developer builds, so comparisons should generally treat those numbers as if
/// they were brand new.
2017-04-11 17:29:57 +02:00
/// </remarks>
2017-09-03 04:33:29 +02:00
internal int BuildNumber ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
Debug . Assert ( ! Helpers . ElyOrGreater ( this ) ) ;
2017-04-11 18:31:17 +02:00
2017-09-03 04:33:29 +02:00
string bn = BuildNumberRaw ( ) ;
if ( bn = = null )
return - 1 ;
while ( bn . Length > 0 & & ! char . IsDigit ( bn [ bn . Length - 1 ] ) )
{
bn = bn . Substring ( 0 , bn . Length - 1 ) ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
int result ;
if ( int . TryParse ( bn , out result ) )
return result ;
else
return - 1 ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
2017-04-11 17:29:57 +02:00
/// Return the exact build_number of this host
2013-06-24 13:41:48 +02:00
/// </summary>
2017-04-11 17:29:57 +02:00
/// <remarks>
/// null if not found
/// </remarks>
2017-09-03 04:33:29 +02:00
public virtual string BuildNumberRaw ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return Get ( software_version , "build_number" ) ;
2013-06-24 13:41:48 +02:00
}
2013-06-28 16:50:14 +02:00
/// <summary>
/// Return this host's product version and build number (e.g. 5.6.100.72258), or null if product version can't be found.
/// </summary>
2017-09-03 04:33:29 +02:00
public virtual string LongProductVersion ( )
2013-06-28 16:50:14 +02:00
{
2017-09-03 04:33:29 +02:00
string productVersion = ProductVersion ( ) ;
return productVersion ! = null ? string . Format ( "{0}.{1}" , productVersion , Helpers . ElyOrGreater ( this ) ? BuildNumberRaw ( ) : BuildNumber ( ) . ToString ( ) ) : null ;
2013-06-28 16:50:14 +02:00
}
2013-06-24 13:41:48 +02:00
/// <summary>
/// Return the product_brand of this host, or null if none can be found.
/// </summary>
2017-09-03 04:33:29 +02:00
public string ProductBrand ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return Get ( software_version , "product_brand" ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
2017-09-05 03:15:38 +02:00
/// The remote syslog target. May return null if not set on the server.
2013-06-24 13:41:48 +02:00
/// </summary>
2017-09-05 03:15:38 +02:00
public string GetSysLogDestination ( )
2013-06-24 13:41:48 +02:00
{
2017-09-05 03:15:38 +02:00
return logging ! = null & & logging . ContainsKey ( "syslog_destination" ) ? logging [ "syslog_destination" ] : null ;
}
2013-06-24 13:41:48 +02:00
2017-09-05 03:15:38 +02:00
/// <summary>
/// Set to null to unset
2013-06-24 13:41:48 +02:00
/// </summary>
2017-09-05 03:15:38 +02:00
public void SetSysLogDestination ( string value )
2013-06-24 13:41:48 +02:00
{
2017-09-05 03:15:38 +02:00
SetDictionaryKey ( logging , "syslog_destination" , value ) ;
2013-06-24 13:41:48 +02:00
}
public static bool IsFullyPatched ( Host host , IEnumerable < IXenConnection > connections )
{
List < Pool_patch > patches = Pool_patch . GetAllThatApply ( host , connections ) ;
List < Pool_patch > appliedPatches
= host . AppliedPatches ( ) ;
if ( appliedPatches . Count = = patches . Count )
return true ;
foreach ( Pool_patch patch in patches )
{
Pool_patch patch1 = patch ;
2016-02-08 11:14:05 +01:00
if ( ! appliedPatches . Exists ( otherPatch = > string . Equals ( patch1 . uuid , otherPatch . uuid , StringComparison . OrdinalIgnoreCase ) ) )
2013-06-24 13:41:48 +02:00
return false ;
}
return true ;
}
public virtual List < Pool_patch > AppliedPatches ( )
{
List < Pool_patch > patches = new List < Pool_patch > ( ) ;
foreach ( Host_patch hostPatch in Connection . ResolveAll ( this . patches ) )
{
Pool_patch patch = Connection . Resolve ( hostPatch . pool_patch ) ;
if ( patch ! = null )
patches . Add ( patch ) ;
}
return patches ;
}
2016-10-04 15:58:54 +02:00
public virtual List < Pool_update > AppliedUpdates ( )
{
var updates = new List < Pool_update > ( ) ;
foreach ( var hostUpdate in Connection . ResolveAll ( this . updates ) )
{
if ( hostUpdate ! = null )
updates . Add ( hostUpdate ) ;
}
return updates ;
}
2017-09-03 04:33:29 +02:00
public string XAPI_version ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return Get ( software_version , "xapi" ) ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public bool LinuxPackPresent ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return software_version . ContainsKey ( "xs:linux" ) ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public bool HasCrashDumps ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return crashdumps ! = null & & crashdumps . Count > 0 ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public bool IsLive ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( Connection = = null )
return false ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
Host_metrics hm = Connection . Resolve ( metrics ) ;
return hm ! = null & & hm . live ;
2013-06-24 13:41:48 +02:00
}
public const string MAINTENANCE_MODE = "MAINTENANCE_MODE" ;
2017-09-03 04:33:29 +02:00
public bool MaintenanceMode ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return BoolKey ( other_config , MAINTENANCE_MODE ) ;
2013-06-24 13:41:48 +02:00
}
public const string BOOT_TIME = "boot_time" ;
2017-09-03 04:33:29 +02:00
public double BootTime ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( other_config = = null )
return 0.0 ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
if ( ! other_config . ContainsKey ( BOOT_TIME ) )
return 0.0 ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
double bootTime ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
if ( ! double . TryParse ( other_config [ BOOT_TIME ] , NumberStyles . Number ,
CultureInfo . InvariantCulture , out bootTime ) )
return 0.0 ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
return bootTime ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public PrettyTimeSpan Uptime ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
double bootTime = BootTime ( ) ;
if ( bootTime = = 0.0 )
return null ;
return new PrettyTimeSpan ( DateTime . UtcNow - Util . FromUnixTime ( bootTime ) - Connection . ServerTimeOffset ) ;
2013-06-24 13:41:48 +02:00
}
public const string AGENT_START_TIME = "agent_start_time" ;
2017-09-03 04:33:29 +02:00
public double AgentStartTime ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( other_config = = null )
return 0.0 ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
if ( ! other_config . ContainsKey ( AGENT_START_TIME ) )
return 0.0 ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
double agentStartTime ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
if ( ! double . TryParse ( other_config [ AGENT_START_TIME ] , System . Globalization . NumberStyles . Any , CultureInfo . InvariantCulture , out agentStartTime ) )
return 0.0 ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
return agentStartTime ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public PrettyTimeSpan AgentUptime ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
double startTime = AgentStartTime ( ) ;
if ( startTime = = 0.0 )
return null ;
return new PrettyTimeSpan ( DateTime . UtcNow - Util . FromUnixTime ( startTime ) - Connection . ServerTimeOffset ) ;
2013-06-24 13:41:48 +02:00
}
// Get the path counts from the Multipath Boot From SAN feature (see PR-1034 and CP-1696).
// Returns true if the Host.other_config contains the multipathed and mpath-boot keys,
// and the mpath-boot key is parseable. In this case, current and max will contain the result;
// otherwise they will contain zero.
public bool GetBootPathCounts ( out int current , out int max )
{
current = max = 0 ;
return ( BoolKey ( other_config , "multipathed" ) & &
other_config . ContainsKey ( "mpath-boot" ) & &
PBD . ParsePathCounts ( other_config [ "mpath-boot" ] , out current , out max ) ) ;
}
2017-09-03 04:33:29 +02:00
public bool HasRunningVMs ( )
2016-06-23 16:26:32 +02:00
{
2017-09-03 04:33:29 +02:00
// 2 not 1, because the Control Domain doesn't count
return resident_VMs ! = null & & resident_VMs . Count > = 2 ;
2016-06-23 16:26:32 +02:00
}
2013-06-24 13:41:48 +02:00
#region Save Evacuated VMs for later
public const String MAINTENANCE_MODE_EVACUATED_VMS_MIGRATED = "MAINTENANCE_MODE_EVACUATED_VMS_MIGRATED" ;
public const String MAINTENANCE_MODE_EVACUATED_VMS_SUSPENDED = "MAINTENANCE_MODE_EVACUATED_VMS_SUSPENDED" ;
public const String MAINTENANCE_MODE_EVACUATED_VMS_HALTED = "MAINTENANCE_MODE_EVACUATED_VMS_HALTED" ;
/// <summary>
/// Save the list of VMs on this host, so we can try and put them back when finished.
/// This may get run multiple times, after which some vms will have been suspended / shutdown.
/// </summary>
2017-06-20 15:29:22 +02:00
/// <param name="session">Pass in the session you want to use for the other config writing</param>
2013-06-24 13:41:48 +02:00
public void SaveEvacuatedVMs ( Session session )
{
//Program.AssertOffEventThread();
XenRef < Host > opaque_ref = get_by_uuid ( session , uuid ) ;
List < VM > migratedVMs = GetVMs ( MAINTENANCE_MODE_EVACUATED_VMS_MIGRATED ) ;
List < VM > suspendedVMs = GetVMs ( MAINTENANCE_MODE_EVACUATED_VMS_SUSPENDED ) ;
List < VM > haltedVMs = GetVMs ( MAINTENANCE_MODE_EVACUATED_VMS_HALTED ) ;
List < VM > allVMs = new List < VM > ( ) ;
allVMs . AddRange ( migratedVMs ) ;
allVMs . AddRange ( suspendedVMs ) ;
allVMs . AddRange ( haltedVMs ) ;
// First time round there will be no saved VMs,
// (or less saved VMs than currently resident)
// so just save them all as migrated
// don't forget the control domain
if ( allVMs . Count < resident_VMs . Count - 1 )
{
SaveVMList ( session , opaque_ref , MAINTENANCE_MODE_EVACUATED_VMS_MIGRATED ,
Connection . ResolveAll ( resident_VMs ) ) ;
return ;
}
// We've been round once, so just make sure all the vms are in the correct list
// and then save the lists again
migratedVMs . Clear ( ) ;
suspendedVMs . Clear ( ) ;
haltedVMs . Clear ( ) ;
foreach ( VM vm in allVMs )
{
switch ( vm . power_state )
{
case vm_power_state . Halted :
haltedVMs . Add ( vm ) ;
break ;
case vm_power_state . Running :
migratedVMs . Add ( vm ) ;
break ;
case vm_power_state . Suspended :
suspendedVMs . Add ( vm ) ;
break ;
}
}
SaveVMList ( session , opaque_ref , MAINTENANCE_MODE_EVACUATED_VMS_MIGRATED , migratedVMs ) ;
SaveVMList ( session , opaque_ref , MAINTENANCE_MODE_EVACUATED_VMS_HALTED , haltedVMs ) ;
SaveVMList ( session , opaque_ref , MAINTENANCE_MODE_EVACUATED_VMS_SUSPENDED , suspendedVMs ) ;
}
private static void SaveVMList ( Session session , String serverOpaqueRef , String key , List < VM > vms )
{
//Program.AssertOffEventThread();
List < String > vmUUIDs = new List < String > ( ) ;
foreach ( VM vm in vms )
{
if ( vm . is_control_domain )
continue ;
vmUUIDs . Add ( vm . uuid ) ;
}
Host . remove_from_other_config ( session , serverOpaqueRef , key ) ;
Host . add_to_other_config ( session , serverOpaqueRef , key , String . Join ( "," , vmUUIDs . ToArray ( ) ) ) ;
}
private List < VM > GetVMs ( String key )
{
List < VM > vms = new List < VM > ( ) ;
if ( other_config = = null | | ! other_config . ContainsKey ( key ) )
return vms ;
String vmUUIDs = other_config [ key ] ;
if ( String . IsNullOrEmpty ( vmUUIDs ) )
return vms ;
foreach ( String vmUUID in vmUUIDs . Split ( new char [ ] { ',' } ) )
foreach ( VM vm in Connection . Cache . VMs )
if ( vm . uuid = = vmUUID )
{
if ( ! vms . Contains ( vm ) )
vms . Add ( vm ) ;
break ;
}
return vms ;
}
public void ClearEvacuatedVMs ( Session session )
{
XenRef < Host > serverOpaqueRef1 = get_by_uuid ( session , uuid ) ;
remove_from_other_config ( session , serverOpaqueRef1 , MAINTENANCE_MODE_EVACUATED_VMS_MIGRATED ) ;
remove_from_other_config ( session , serverOpaqueRef1 , MAINTENANCE_MODE_EVACUATED_VMS_HALTED ) ;
remove_from_other_config ( session , serverOpaqueRef1 , MAINTENANCE_MODE_EVACUATED_VMS_SUSPENDED ) ;
}
public List < VM > GetMigratedEvacuatedVMs ( )
{
return GetEvacuatedVMs ( MAINTENANCE_MODE_EVACUATED_VMS_MIGRATED , vm_power_state . Running ) ;
}
public List < VM > GetSuspendedEvacuatedVMs ( )
{
return GetEvacuatedVMs ( MAINTENANCE_MODE_EVACUATED_VMS_SUSPENDED , vm_power_state . Suspended ) ;
}
public List < VM > GetHaltedEvacuatedVMs ( )
{
return GetEvacuatedVMs ( MAINTENANCE_MODE_EVACUATED_VMS_HALTED , vm_power_state . Halted ) ;
}
private List < VM > GetEvacuatedVMs ( String key , vm_power_state expectedPowerState )
{
List < VM > vms = GetVMs ( key ) ;
foreach ( VM vm in vms . ToArray ( ) )
if ( vm . power_state ! = expectedPowerState )
vms . Remove ( vm ) ;
return vms ;
}
#endregion
/// <summary>
/// Will return null if cannot find connection or any control domain in list of vms
/// </summary>
2017-09-03 04:33:29 +02:00
public VM ControlDomainZero ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( Connection = = null )
return null ;
2016-07-04 14:21:52 +02:00
2017-09-03 04:33:29 +02:00
if ( ! Helper . IsNullOrEmptyOpaqueRef ( control_domain ) )
return Connection . Resolve ( control_domain ) ;
2016-07-04 14:21:52 +02:00
2017-09-03 04:33:29 +02:00
var vms = Connection . ResolveAll ( resident_VMs ) ;
return vms . FirstOrDefault ( vm = > vm . is_control_domain & & vm . domid = = 0 ) ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public bool HasManyControlDomains ( )
2016-07-05 09:14:13 +02:00
{
2017-09-03 04:33:29 +02:00
if ( Connection = = null )
return false ;
2016-07-05 09:14:13 +02:00
2017-09-03 04:33:29 +02:00
var vms = Connection . ResolveAll ( resident_VMs ) ;
return vms . FindAll ( v = > v . is_control_domain ) . Count > 1 ;
2016-07-05 09:14:13 +02:00
}
2017-09-03 04:33:29 +02:00
public IEnumerable < VM > OtherControlDomains ( )
2016-07-05 09:14:13 +02:00
{
2017-09-03 04:33:29 +02:00
if ( Connection = = null )
return null ;
2016-07-05 09:14:13 +02:00
2017-09-03 04:33:29 +02:00
var vms = Connection . ResolveAll ( resident_VMs ) ;
2016-07-05 09:14:13 +02:00
2017-09-03 04:33:29 +02:00
if ( ! Helper . IsNullOrEmptyOpaqueRef ( control_domain ) )
return vms . Where ( v = > v . is_control_domain & & v . opaque_ref ! = control_domain ) ;
2016-07-05 09:14:13 +02:00
2017-09-03 04:33:29 +02:00
return vms . Where ( v = > v . is_control_domain & & v . domid ! = 0 ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Interpret a value from the software_version dictionary as a int, or 0 if we couldn't parse it.
/// </summary>
private int GetSVAsInt ( string key )
{
string s = Get ( software_version , key ) ;
if ( s = = null )
return 0 ;
return ( int ) Helper . GetAPIVersion ( s ) ;
}
/// <summary>
/// The xencenter_min as a int, or 0. if we couldn't parse it.
/// </summary>
2017-09-03 04:33:29 +02:00
public int XenCenterMin ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return GetSVAsInt ( "xencenter_min" ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// The xencenter_max as a int, or 0 if we couldn't parse it.
/// </summary>
2017-09-03 04:33:29 +02:00
public int XenCenterMax ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return GetSVAsInt ( "xencenter_max" ) ;
2013-06-24 13:41:48 +02:00
}
2017-04-10 10:25:51 +02:00
public string GetDatabaseSchema ( )
{
return Get ( software_version , "db_schema" ) ;
}
2013-06-24 13:41:48 +02:00
/// <summary>
2015-10-26 17:01:55 +01:00
/// The amount of memory free on the host. For George and earlier hosts, we use to use
/// the obvious Host_metrics.memory_free. Since Midnight Ride, however, we use
2013-06-24 13:41:48 +02:00
/// the same calculation as xapi, adding the used memory and the virtualisation overheads
/// on each of the VMs. This is a more conservative estimate (i.e., it reports less memory
/// free), but it's the one we need to make the memory go down to zero when ballooning
/// takes place.
/// </summary>
2017-09-03 04:33:29 +02:00
public long memory_free_calc ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
Host_metrics host_metrics = Connection . Resolve ( this . metrics ) ;
if ( host_metrics = = null )
return 0 ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
long used = memory_overhead ;
foreach ( VM vm in Connection . ResolveAll ( resident_VMs ) )
{
used + = vm . memory_overhead ;
VM_metrics vm_metrics = vm . Connection . Resolve ( vm . metrics ) ;
if ( vm_metrics ! = null )
used + = vm_metrics . memory_actual ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
// This hack is needed because of bug CA-32509. xapi uses a deliberately generous
// estimate of VM.memory_overhead: but the low-level squeezer code doesn't (and can't)
// know about the same calculation, and so uses some of this memory_overhead for the
// VM's memory_actual. This causes up to 1MB of double-counting per VM.
return ( ( host_metrics . memory_total > used ) ? ( host_metrics . memory_total - used ) : 0 ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// The total of all the dynamic_minimum memories of all resident VMs other than the control domain.
/// For non-ballonable VMs, we use the static_maximum instead, because the dynamic_minimum has no effect.
/// </summary>
2017-09-03 04:33:29 +02:00
public long tot_dyn_min ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
long ans = 0 ;
foreach ( VM vm in Connection . ResolveAll ( resident_VMs ) )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( ! vm . is_control_domain )
ans + = vm . has_ballooning ( ) ? vm . memory_dynamic_min : vm . memory_static_max ;
}
return ans ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// The total of all the dynamic_maximum memories of all resident VMs other than the control domain.
/// For non-ballonable VMs, we use the static_maximum instead, because the dynamic_maximum has no effect.
/// </summary>
2017-09-03 04:33:29 +02:00
public long tot_dyn_max ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
long ans = 0 ;
foreach ( VM vm in Connection . ResolveAll ( resident_VMs ) )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( ! vm . is_control_domain )
ans + = vm . has_ballooning ( ) ? vm . memory_dynamic_max : vm . memory_static_max ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
return ans ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// The amount of available memory on the host. This is not the same as the amount of free memory, because
/// it includes the memory that could be freed by reducing balloonable VMs to their dynamic_minimum memory.
/// </summary>
2017-09-03 04:33:29 +02:00
public long memory_available_calc ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
Host_metrics host_metrics = Connection . Resolve ( this . metrics ) ;
if ( host_metrics = = null )
return 0 ;
long avail = host_metrics . memory_total - tot_dyn_min ( ) - xen_memory_calc ( ) ;
if ( avail < 0 )
avail = 0 ; // I don't think this can happen, but I'm nervous about CA-32509: play it safe
return avail ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// The amount of memory used by Xen, including the control domain plus host and VM overheads.
/// Used to calculate this as total - free - tot_vm_mem, but that caused xen_mem to jump around
/// during VM startup/shutdown because some changes happen before others.
/// </summary>
2017-09-03 04:33:29 +02:00
public long xen_memory_calc ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
long xen_mem = memory_overhead ;
foreach ( VM vm in Connection . ResolveAll ( resident_VMs ) )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
xen_mem + = vm . memory_overhead ;
if ( vm . is_control_domain )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
VM_metrics vmMetrics = vm . Connection . Resolve ( vm . metrics ) ;
if ( vmMetrics ! = null )
xen_mem + = vmMetrics . memory_actual ;
2013-06-24 13:41:48 +02:00
}
}
2017-09-03 04:33:29 +02:00
return xen_mem ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
public long dom0_memory ( )
2016-08-01 10:25:10 +02:00
{
2017-09-03 04:33:29 +02:00
long dom0_mem = 0 ;
VM vm = ControlDomainZero ( ) ;
if ( vm ! = null )
2016-08-01 10:25:10 +02:00
{
2017-09-03 04:33:29 +02:00
VM_metrics vmMetrics = vm . Connection . Resolve ( vm . metrics ) ;
dom0_mem = vmMetrics ! = null ? vmMetrics . memory_actual : vm . memory_dynamic_min ;
2016-08-01 10:25:10 +02:00
}
2017-09-03 04:33:29 +02:00
return dom0_mem ;
2016-08-01 10:25:10 +02:00
}
2017-09-03 04:33:29 +02:00
public long dom0_memory_extra ( )
2016-10-01 01:23:28 +02:00
{
2017-09-03 04:33:29 +02:00
VM vm = ControlDomainZero ( ) ;
return vm ! = null ? vm . memory_static_max - vm . memory_static_min : 0 ;
2016-10-01 01:23:28 +02:00
}
2016-08-01 10:25:10 +02:00
2013-06-24 13:41:48 +02:00
/// <summary>
/// Friendly string showing memory usage on the host
/// </summary>
2017-09-03 04:33:29 +02:00
public string HostMemoryString ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
Host_metrics m = Connection . Resolve ( metrics ) ;
if ( m = = null )
return Messages . GENERAL_UNKNOWN ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
long ServerMBAvail = memory_available_calc ( ) ;
long ServerMBTotal = m . memory_total ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
return string . Format ( Messages . GENERAL_MEMORY_SERVER_FREE ,
Util . MemorySizeStringSuitableUnits ( ServerMBAvail , true ) ,
Util . MemorySizeStringSuitableUnits ( ServerMBTotal , true ) ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// A friendly string for the XenMemory on this host
/// </summary>
2017-09-03 04:33:29 +02:00
public string XenMemoryString ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( Connection . Resolve ( metrics ) = = null )
return Messages . GENERAL_UNKNOWN ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
return Util . MemorySizeStringSuitableUnits ( xen_memory_calc ( ) , true ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// A friendly string of the resident VM's memory usage, with each entry separated by a line break
/// </summary>
2017-09-03 04:33:29 +02:00
public string ResidentVMMemoryUsageString ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
Host_metrics m = Connection . Resolve ( metrics ) ;
if ( m = = null )
return Messages . GENERAL_UNKNOWN ;
else
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
List < string > lines = new List < string > ( ) ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
foreach ( VM vm in Connection . ResolveAll ( resident_VMs ) )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( vm . is_control_domain )
continue ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
VM_metrics VMMetrics = Connection . Resolve ( vm . metrics ) ;
if ( VMMetrics = = null )
continue ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
string message = string . Format ( Messages . GENERAL_MEMORY_VM_USED , vm . Name ( ) ,
Util . MemorySizeStringSuitableUnits ( VMMetrics . memory_actual , true ) ) ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
lines . Add ( message ) ;
2013-06-24 13:41:48 +02:00
}
2017-09-03 04:33:29 +02:00
return string . Join ( "\n" , lines . ToArray ( ) ) ;
2013-06-24 13:41:48 +02:00
}
}
/// <summary>
/// Wait about two minutes for all the PBDs on this host to become plugged:
/// if they do not, try and plug them. (Refs: CA-41219, CA-41305, CA-66496).
/// </summary>
public void CheckAndPlugPBDs ( )
{
bool allPBDsReady = false ;
int timeout = 120 ;
2017-09-03 04:33:29 +02:00
log . DebugFormat ( "Waiting for PBDs on host {0} to become plugged" , Name ( ) ) ;
2013-12-12 12:59:00 +01:00
2013-06-24 13:41:48 +02:00
do
{
if ( this . enabled ) // if the Host is not yet enabled, pbd.currently_attached may not be accurate: see CA-66496.
{
allPBDsReady = true ;
foreach ( PBD pbd in Connection . ResolveAll ( PBDs ) )
{
if ( ! pbd . currently_attached )
{
allPBDsReady = false ;
break ;
}
}
}
2013-12-12 12:59:00 +01:00
2013-06-24 13:41:48 +02:00
if ( ! allPBDsReady )
{
Thread . Sleep ( 1000 ) ;
timeout - - ;
}
} while ( ! allPBDsReady & & timeout > 0 ) ;
2013-12-12 12:59:00 +01:00
if ( allPBDsReady )
return ;
foreach ( var pbd in Connection . ResolveAll ( PBDs ) )
2013-06-24 13:41:48 +02:00
{
2013-12-12 12:59:00 +01:00
if ( pbd . currently_attached )
continue ;
Session session = Connection . DuplicateSession ( ) ;
// If we still havent plugged, then try and plug it - this will probably
// fail, but at least we'll get a better error message.
try
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
log . DebugFormat ( "Plugging PBD {0} on host {1}" , pbd . Name ( ) , Name ( ) ) ;
2013-12-12 12:59:00 +01:00
PBD . plug ( session , pbd . opaque_ref ) ;
}
catch ( Exception e )
{
2017-09-03 04:33:29 +02:00
log . Debug ( string . Format ( "Error plugging PBD {0} on host {1}" , pbd . Name ( ) , Name ( ) ) , e ) ;
2013-06-24 13:41:48 +02:00
}
}
}
2017-09-03 04:33:29 +02:00
2013-06-24 13:41:48 +02:00
/// <summary>
/// Whether the host is running the vSwitch network stack
/// </summary>
2017-09-03 04:33:29 +02:00
public bool vSwitchNetworkBackend ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return software_version . ContainsKey ( "network_backend" ) & &
software_version [ "network_backend" ] = = "openvswitch" ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// The number of CPU sockets the host has
/// Return 0 if a problem is found
/// </summary>
2017-09-03 04:33:29 +02:00
public virtual int CpuSockets ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
const string key = "socket_count" ;
const int defaultSockets = 0 ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
if ( cpu_info = = null | | ! cpu_info . ContainsKey ( key ) )
return defaultSockets ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
int sockets ;
bool parsed = int . TryParse ( cpu_info [ key ] , out sockets ) ;
if ( ! parsed )
return defaultSockets ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
return sockets ;
2013-06-24 13:41:48 +02:00
}
2014-06-05 14:00:14 +02:00
/// <summary>
/// The number of cpus the host has
/// Return 0 if a problem is found
/// </summary>
2017-09-03 04:33:29 +02:00
public int CpuCount ( )
2014-06-05 14:00:14 +02:00
{
2017-09-03 04:33:29 +02:00
const string key = "cpu_count" ;
const int defaultCpuCount = 0 ;
2014-06-05 14:00:14 +02:00
2017-09-03 04:33:29 +02:00
if ( cpu_info = = null | | ! cpu_info . ContainsKey ( key ) )
return defaultCpuCount ;
2014-06-05 14:00:14 +02:00
2017-09-03 04:33:29 +02:00
int cpuCount ;
bool parsed = int . TryParse ( cpu_info [ key ] , out cpuCount ) ;
if ( ! parsed )
return defaultCpuCount ;
2014-06-05 14:00:14 +02:00
2017-09-03 04:33:29 +02:00
return cpuCount ;
2014-06-05 14:00:14 +02:00
}
/// <summary>
/// The number of cores per socket the host has
/// Return 0 if a problem is found
/// </summary>
2017-09-03 04:33:29 +02:00
public int CoresPerSocket ( )
2014-06-05 14:00:14 +02:00
{
2017-09-03 04:33:29 +02:00
var sockets = CpuSockets ( ) ;
var cpuCount = CpuCount ( ) ;
if ( sockets > 0 & & cpuCount > 0 )
return ( cpuCount / sockets ) ;
2014-06-05 14:00:14 +02:00
2017-09-03 04:33:29 +02:00
return 0 ;
2014-06-05 14:00:14 +02:00
}
2013-06-24 13:41:48 +02:00
/// <summary>
/// Is the host allowed to install hotfixes or are they restricted?
/// </summary>
2017-09-03 04:33:29 +02:00
public virtual bool CanApplyHotfixes ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return ! Helpers . FeatureForbidden ( Connection , RestrictHotfixApply ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Grace is either upgrade or regular
/// </summary>
2017-09-03 04:33:29 +02:00
public virtual bool InGrace ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
return license_params . ContainsKey ( "grace" ) ;
2013-06-24 13:41:48 +02:00
}
2015-01-20 15:22:29 +01:00
2017-09-03 04:33:29 +02:00
internal override string LocationString ( )
2015-01-14 17:20:36 +01:00
{
2017-09-03 04:33:29 +02:00
//for standalone hosts we do not show redundant location info
return Helpers . GetPool ( Connection ) = = null ? string . Empty : base . LocationString ( ) ;
2015-01-20 15:22:29 +01:00
}
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
public bool EnterpriseFeaturesEnabled ( )
2014-10-28 18:02:55 +01:00
{
2017-09-03 04:33:29 +02:00
var hostEdition = GetEdition ( edition ) ;
return EligibleForSupport ( ) & & ( hostEdition = = Edition . EnterprisePerSocket | | hostEdition = = Edition . EnterprisePerUser
| | hostEdition = = Edition . PerSocket ) ;
2014-11-14 18:29:01 +01:00
}
2017-09-03 04:33:29 +02:00
public bool DesktopPlusFeaturesEnabled ( )
2014-12-08 15:29:54 +01:00
{
2017-09-03 04:33:29 +02:00
return GetEdition ( edition ) = = Edition . DesktopPlus ;
2014-12-08 15:29:54 +01:00
}
2017-09-03 04:33:29 +02:00
public bool DesktopFeaturesEnabled ( )
2014-11-14 18:29:01 +01:00
{
2017-09-03 04:33:29 +02:00
return GetEdition ( edition ) = = Edition . Desktop ;
2014-10-28 18:02:55 +01:00
}
2017-09-03 04:33:29 +02:00
public bool PremiumFeaturesEnabled ( )
2016-02-08 11:10:01 +01:00
{
2017-09-03 04:33:29 +02:00
return GetEdition ( edition ) = = Edition . Premium ;
2016-02-08 11:10:01 +01:00
}
2017-09-03 04:33:29 +02:00
public bool StandardFeaturesEnabled ( )
2016-03-09 17:14:05 +01:00
{
2017-09-03 04:33:29 +02:00
return GetEdition ( edition ) = = Edition . Standard ;
2016-03-09 17:14:05 +01:00
}
2017-09-03 04:33:29 +02:00
public bool EligibleForSupport ( )
2014-10-28 18:02:55 +01:00
{
2017-09-03 04:33:29 +02:00
return ( Helpers . CreedenceOrGreater ( this ) & & GetEdition ( edition ) ! = Edition . Free ) ;
2015-01-14 17:20:36 +01:00
}
2013-06-24 13:41:48 +02:00
#region Supplemental Packs
// From http://scale.uk.xensource.com/confluence/display/engp/Supplemental+Pack+product+design+notes#SupplementalPackproductdesignnotes-XenAPI:
// The supplemental packs that are installed on a host are listed in the host's Host.software_version field in the data model.
// The keys of the entries have the form "<originator>:<name>", the value is "<description>, version <version>", appended by
// ", build <build>" if the build number is present in the XML file, and further appended by ", homogeneous" if the
// enforce-homogeneity attribute is present and set to true.
//
// Examples:
// xs:main: Base Pack, version 5.5.900, build 19689c
// xs:linux: Linux Pack, version 5.5.900, build 19689c, homogeneous
public class SuppPack
{
private string originator , name , description , version , build ;
private bool homogeneous ;
public string Originator { get { return originator ; } }
public string Name { get { return name ; } }
public string Description { get { return description ; } }
public string Version { get { return version ; } }
public string Build { get { return build ; } }
public bool Homogeneous { get { return homogeneous ; } }
public string OriginatorAndName { get { return originator + ":" + name ; } }
private bool parsed = false ;
public bool IsValid { get { return parsed ; } }
2017-03-23 13:28:32 +01:00
public string LongDescription { get { return string . Format ( Messages . SUPP_PACK_DESCRIPTION , description , version ) ; } }
2015-01-28 14:17:58 +01:00
2013-06-24 13:41:48 +02:00
/// <summary>
/// Try to parse the supp pack information from one key of software_version
/// </summary>
public SuppPack ( string key , string value )
{
// Parse the key
string [ ] splitKey = key . Split ( ':' ) ;
if ( splitKey . Length ! = 2 )
return ;
originator = splitKey [ 0 ] ;
name = splitKey [ 1 ] ;
// Parse the value. The description may contain arbitrary text, so we have to be a bit subtle:
// we first search from the end to find where the description ends.
int x = value . LastIndexOf ( ", version " ) ;
if ( x < = 0 )
return ;
description = value . Substring ( 0 , x ) ;
string val = value . Substring ( x + 10 ) ;
string [ ] delims = new string [ ] { ", " } ;
string [ ] splitValue = val . Split ( delims , StringSplitOptions . None ) ;
if ( splitValue . Length = = 0 | | splitValue . Length > 3 )
return ;
version = splitValue [ 0 ] ;
if ( splitValue . Length > = 2 )
{
if ( ! splitValue [ 1 ] . StartsWith ( "build " ) )
return ;
build = splitValue [ 1 ] . Substring ( 6 ) ;
}
if ( splitValue . Length > = 3 )
{
if ( splitValue [ 2 ] ! = "homogeneous" )
return ;
homogeneous = true ;
}
else
homogeneous = false ;
parsed = true ;
}
}
/// <summary>
/// Return a list of the supplemental packs
/// </summary>
2017-09-03 04:33:29 +02:00
public List < SuppPack > SuppPacks ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
List < SuppPack > packs = new List < SuppPack > ( ) ;
if ( software_version = = null )
2013-06-24 13:41:48 +02:00
return packs ;
2017-09-03 04:33:29 +02:00
foreach ( string key in software_version . Keys )
2015-01-20 15:22:29 +01:00
{
2017-09-03 04:33:29 +02:00
SuppPack pack = new SuppPack ( key , software_version [ key ] ) ;
if ( pack . IsValid )
packs . Add ( pack ) ;
2015-01-20 15:22:29 +01:00
}
2017-09-03 04:33:29 +02:00
return packs ;
2015-01-20 15:22:29 +01:00
}
2017-09-03 04:33:29 +02:00
2013-06-24 13:41:48 +02:00
#endregion
2015-02-25 14:01:03 +01:00
/// <summary>
/// The PGPU that is the system display device or null
/// </summary>
2017-09-03 04:33:29 +02:00
public PGPU SystemDisplayDevice ( )
2015-02-25 14:01:03 +01:00
{
2017-09-03 04:33:29 +02:00
var pGpus = Connection . ResolveAll ( PGPUs ) ;
return pGpus . FirstOrDefault ( pGpu = > pGpu . is_system_display_device ) ;
2015-02-25 14:01:03 +01:00
}
/// <summary>
/// Is the host allowed to enable/disable integrated GPU passthrough or is the feature unavailable/restricted?
/// </summary>
2017-09-03 04:33:29 +02:00
public bool CanEnableDisableIntegratedGpu ( )
2015-02-25 14:01:03 +01:00
{
2017-09-03 04:33:29 +02:00
return Helpers . CreamOrGreater ( Connection )
& & Helpers . GpuCapability ( Connection )
& & ! Helpers . FeatureForbidden ( Connection , RestrictIntegratedGpuPassthrough ) ;
2015-02-25 14:01:03 +01:00
}
2013-06-24 13:41:48 +02:00
#region IEquatable < Host > Members
/// <summary>
/// Indicates whether the current object is equal to the specified object. This calls the implementation from XenObject.
/// This implementation is required for ToStringWrapper.
/// </summary>
public bool Equals ( Host other )
{
return base . Equals ( other ) ;
}
#endregion
}
}