diff --git a/XenAdmin/Core/HealthCheck.cs b/XenAdmin/Core/HealthCheck.cs index be002412c..1ad733b69 100644 --- a/XenAdmin/Core/HealthCheck.cs +++ b/XenAdmin/Core/HealthCheck.cs @@ -44,21 +44,17 @@ namespace XenAdmin.Core public static event Action CheckForAnalysisResultsCompleted; /// - /// Checks the analysis results for all connections + /// Checks the analysis results for all connections. + /// Will only perform the check for the connection that have sufficient rights; will not show the action progress. /// public static void CheckForAnalysisResults() { List actions = new List(); foreach (IXenConnection xenConnection in ConnectionsManager.XenConnectionsCopy) { - Pool pool = Helpers.GetPoolOfOne(xenConnection); - if (pool == null || Helpers.FeatureForbidden(xenConnection, Host.RestrictHealthCheck)) - continue; - - var healthCheckSettings = pool.HealthCheckSettings; - - if (healthCheckSettings.Status == HealthCheckStatus.Enabled && !healthCheckSettings.HasAnalysisResult) - actions.Add(new GetHealthCheckAnalysisResultAction(pool, Registry.HealthCheckDiagnosticDomainName, true)); + var action = GetAction(xenConnection, true); + if (action != null) + actions.Add(action); } if (actions.Count == 1) @@ -75,22 +71,49 @@ namespace XenAdmin.Core } /// - /// Checks the analysis results for the specified connections + /// Checks the analysis results for the specified connections. + /// Will only perform the check if the connection has sufficient rights; will not show the action progress. /// public static void CheckForAnalysisResults(object connection) { - Pool pool = Helpers.GetPoolOfOne((IXenConnection)connection); - if (pool == null || Helpers.FeatureForbidden((IXenConnection)connection, Host.RestrictHealthCheck)) - return; + CheckForAnalysisResults(connection, true); + } + + /// + /// Checks the analysis results for the specified connections. + /// Will only perform the check if the connection has sufficient rights; If suppressHistory is false, it will show the action progress. + /// + public static void CheckForAnalysisResults(object connection, bool suppressHistory) + { + var action = GetAction((IXenConnection)connection, suppressHistory); + if (action != null) + { + action.Completed += actionCompleted; + action.RunAsync(); + } + } + + private static AsyncAction GetAction(IXenConnection connection, bool suppressHistory) + { + Pool pool = Helpers.GetPoolOfOne(connection); + if (pool == null || Helpers.FeatureForbidden(connection, Host.RestrictHealthCheck)) + return null; var healthCheckSettings = pool.HealthCheckSettings; if (healthCheckSettings.Status == HealthCheckStatus.Enabled && !healthCheckSettings.HasAnalysisResult) { - var action = new GetHealthCheckAnalysisResultAction(pool, Registry.HealthCheckDiagnosticDomainName, true); - action.Completed += actionCompleted; - action.RunAsync(); + var action = new GetHealthCheckAnalysisResultAction(pool, Registry.HealthCheckDiagnosticDomainName, suppressHistory); + + if (PassedRbacChecks(pool.Connection)) + return action; } + return null; + } + + public static bool PassedRbacChecks(IXenConnection connection) + { + return Role.CanPerform(new RbacMethodList("pool.set_health_check_config"), connection); } private static void actionCompleted(ActionBase sender) diff --git a/XenAdmin/Dialogs/HealthCheck/HealthCheckOverviewDialog.cs b/XenAdmin/Dialogs/HealthCheck/HealthCheckOverviewDialog.cs index 15b961c43..ce3956058 100644 --- a/XenAdmin/Dialogs/HealthCheck/HealthCheckOverviewDialog.cs +++ b/XenAdmin/Dialogs/HealthCheck/HealthCheckOverviewDialog.cs @@ -207,6 +207,8 @@ namespace XenAdmin.Dialogs.HealthCheck scheduleLabel.Text = GetScheduleDescription(poolRow.Pool.HealthCheckSettings); lastUploadLabel.Visible = lastUploadDateLabel.Visible = !string.IsNullOrEmpty(poolRow.Pool.HealthCheckSettings.LastSuccessfulUpload); lastUploadDateLabel.Text = GetLastUploadDescription(poolRow.Pool.HealthCheckSettings); + + UpdateButtonsVisibility(poolRow.Pool); healthCheckStatusPanel.Visible = poolRow.Pool.HealthCheckSettings.Status == HealthCheckStatus.Enabled; notEnrolledPanel.Visible = poolRow.Pool.HealthCheckSettings.Status != HealthCheckStatus.Enabled; @@ -299,6 +301,16 @@ namespace XenAdmin.Dialogs.HealthCheck } } + public void UpdateButtonsVisibility(Pool pool) + { + refreshLinkLabel.Visible = + editLinkLabel.Visible = + disableLinkLabel.Visible = + uploadRequestLinkLabel.Visible = + enrollNowLinkLabel.Visible = Core.HealthCheck.PassedRbacChecks(pool.Connection); + + } + private void HealthCheckOverviewDialog_Load(object sender, EventArgs e) { LoadPools(); @@ -450,7 +462,7 @@ namespace XenAdmin.Dialogs.HealthCheck if (poolRow.Pool == null) return; - Core.HealthCheck.CheckForAnalysisResults(poolRow.Pool.Connection); + Core.HealthCheck.CheckForAnalysisResults(poolRow.Pool.Connection, false); } private void HealthCheck_CheckForUpdatesCompleted(bool succeeded) diff --git a/XenAdmin/Dialogs/HealthCheck/HealthCheckSettingsDialog.cs b/XenAdmin/Dialogs/HealthCheck/HealthCheckSettingsDialog.cs index 91cbdd078..785f915df 100644 --- a/XenAdmin/Dialogs/HealthCheck/HealthCheckSettingsDialog.cs +++ b/XenAdmin/Dialogs/HealthCheck/HealthCheckSettingsDialog.cs @@ -266,9 +266,9 @@ namespace XenAdmin.Dialogs.HealthCheck if (!CheckCredentialsEntered()) return false; - var action = new HealthCheckAuthenticationAction(pool, textBoxMyCitrixUsername.Text.Trim(), textBoxMyCitrixPassword.Text.Trim(), + var action = new HealthCheckAuthenticationAction(textBoxMyCitrixUsername.Text.Trim(), textBoxMyCitrixPassword.Text.Trim(), Registry.HealthCheckIdentityTokenDomainName, Registry.HealthCheckUploadGrantTokenDomainName, Registry.HealthCheckUploadTokenDomainName, - Registry.HealthCheckDiagnosticDomainName, Registry.HealthCheckProductKey, true, 0, false); + Registry.HealthCheckDiagnosticDomainName, Registry.HealthCheckProductKey, 0, false); try { @@ -283,7 +283,8 @@ namespace XenAdmin.Dialogs.HealthCheck } authenticationToken = action.UploadToken; // curent upload token - authenticated = pool.HealthCheckSettings.TryGetExistingTokens(pool.Connection, out authenticationToken, out diagnosticToken); + diagnosticToken = action.DiagnosticToken; // curent diagnostic token + authenticated = !String.IsNullOrEmpty(authenticationToken) && !String.IsNullOrEmpty(diagnosticToken); return authenticated; } diff --git a/XenAdmin/Wizards/BugToolWizardFiles/BugToolPageDestination.cs b/XenAdmin/Wizards/BugToolWizardFiles/BugToolPageDestination.cs index 894753435..73f263114 100644 --- a/XenAdmin/Wizards/BugToolWizardFiles/BugToolPageDestination.cs +++ b/XenAdmin/Wizards/BugToolWizardFiles/BugToolPageDestination.cs @@ -183,10 +183,10 @@ namespace XenAdmin.Wizards.BugToolWizardFiles if (string.IsNullOrEmpty(usernameTextBox.Text) || string.IsNullOrEmpty(passwordTextBox.Text)) return false; - var action = new HealthCheckAuthenticationAction(null, usernameTextBox.Text.Trim(), passwordTextBox.Text.Trim(), + var action = new HealthCheckAuthenticationAction(usernameTextBox.Text.Trim(), passwordTextBox.Text.Trim(), Registry.HealthCheckIdentityTokenDomainName, Registry.HealthCheckUploadGrantTokenDomainName, Registry.HealthCheckUploadTokenDomainName, Registry.HealthCheckDiagnosticDomainName, Registry.HealthCheckProductKey, - false, TokenExpiration, false); + TokenExpiration, false); new ActionProgressDialog(action, ProgressBarStyle.Blocks).ShowDialog(Parent); diff --git a/XenModel/Actions/HealthCheck/GetHealthCheckAnalysisResultAction.cs b/XenModel/Actions/HealthCheck/GetHealthCheckAnalysisResultAction.cs index 685b6f165..8ab7a7dcf 100644 --- a/XenModel/Actions/HealthCheck/GetHealthCheckAnalysisResultAction.cs +++ b/XenModel/Actions/HealthCheck/GetHealthCheckAnalysisResultAction.cs @@ -49,7 +49,11 @@ namespace XenAdmin.Actions public GetHealthCheckAnalysisResultAction(Pool pool, bool suppressHistory) : base(pool.Connection, Messages.ACTION_GET_HEALTH_CHECK_RESULT, Messages.ACTION_GET_HEALTH_CHECK_RESULT_PROGRESS, suppressHistory) { - + #region RBAC Dependencies + ApiMethodsToRoleCheck.Add("secret.get_by_uuid"); + ApiMethodsToRoleCheck.Add("secret.get_value"); + ApiMethodsToRoleCheck.Add("pool.set_health_check_config"); + #endregion } public GetHealthCheckAnalysisResultAction(Pool pool, string diagnosticDomainName, bool suppressHistory) @@ -63,7 +67,7 @@ namespace XenAdmin.Actions { try { - var diagnosticToken = Pool.HealthCheckSettings.GetSecretyInfo(Pool.Connection, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET); + var diagnosticToken = Pool.HealthCheckSettings.GetSecretyInfo(Session, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET); if (string.IsNullOrEmpty(diagnosticToken)) { log.InfoFormat("Cannot get the diagnostic result for {0}, because couldn't retrieve the diagnostic token", Pool.Name); diff --git a/XenModel/Actions/HealthCheck/HealthCheckAuthenticationAction.cs b/XenModel/Actions/HealthCheck/HealthCheckAuthenticationAction.cs index acafff79e..7d578e45e 100644 --- a/XenModel/Actions/HealthCheck/HealthCheckAuthenticationAction.cs +++ b/XenModel/Actions/HealthCheck/HealthCheckAuthenticationAction.cs @@ -30,14 +30,11 @@ */ using System; -using System.Collections.Generic; using System.IO; using System.Net; using System.Runtime.Serialization; -using XenAdmin.Network; using XenAPI; using System.Web.Script.Serialization; -using XenAdmin.Model; namespace XenAdmin.Actions { @@ -45,14 +42,13 @@ namespace XenAdmin.Actions { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - private readonly Pool pool; private readonly string username; private readonly string password; - private readonly bool saveTokenAsSecret; private readonly long tokenExpiration; private string uploadToken; + private string diagnosticToken; private const string identityTokenUrl = "/auth/api/create_identity/"; private const string uploadGrantTokenUrl = "/feeds/api/create_grant/"; @@ -66,25 +62,19 @@ namespace XenAdmin.Actions private readonly string productKey = "1a2d94a4263cd016dd7a7d510bde87f058a0b75d"; - public HealthCheckAuthenticationAction(Pool pool, string username, string password, bool saveTokenAsSecret, long tokenExpiration, bool suppressHistory) - : base(pool != null ? pool.Connection : null, Messages.ACTION_HEALTHCHECK_AUTHENTICATION, Messages.ACTION_HEALTHCHECK_AUTHENTICATION_PROGRESS, suppressHistory) + public HealthCheckAuthenticationAction(string username, string password, long tokenExpiration, bool suppressHistory) + : base(null, Messages.ACTION_HEALTHCHECK_AUTHENTICATION, Messages.ACTION_HEALTHCHECK_AUTHENTICATION_PROGRESS, suppressHistory) { - this.pool = pool; this.username = username; this.password = password; - this.saveTokenAsSecret = saveTokenAsSecret; this.tokenExpiration = tokenExpiration; - #region RBAC Dependencies - if (saveTokenAsSecret) - ApiMethodsToRoleCheck.Add("pool.set_health_check_config"); - #endregion } - public HealthCheckAuthenticationAction(Pool pool, string username, string password, + public HealthCheckAuthenticationAction(string username, string password, string identityTokenDomainName, string uploadGrantTokenDomainName, string uploadTokenDomainName, string diagnosticTokenDomainName, - string productKey, bool saveTokenAsSecret, long tokenExpiration, bool suppressHistory) - : this(pool, username, password, saveTokenAsSecret, tokenExpiration, suppressHistory) + string productKey, long tokenExpiration, bool suppressHistory) + : this(username, password, tokenExpiration, suppressHistory) { if (!string.IsNullOrEmpty(identityTokenDomainName)) this.identityTokenDomainName = identityTokenDomainName; @@ -100,22 +90,12 @@ namespace XenAdmin.Actions protected override void Run() { - System.Diagnostics.Trace.Assert(pool != null || !saveTokenAsSecret, "Pool is null! Cannot save token as secret"); try { string identityToken = GetIdentityToken(); string uploadGrantToken = GetUploadGrantToken(identityToken); uploadToken = GetUploadToken(uploadGrantToken); - string diagnosticToken = GetDiagnosticToken(identityToken); - - if (saveTokenAsSecret && pool != null) - { - log.Info("Saving upload token as xapi secret"); - Dictionary newConfig = pool.health_check_config; - SetSecretInfo(Connection, newConfig, HealthCheckSettings.UPLOAD_TOKEN_SECRET, uploadToken); log.Info("Saving upload token as xapi secret"); - SetSecretInfo(Connection, newConfig, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET, diagnosticToken); - Pool.set_health_check_config(Connection.Session, pool.opaque_ref, newConfig); - } + diagnosticToken = GetDiagnosticToken(identityToken); } catch (HealthCheckAuthenticationException) { @@ -132,53 +112,9 @@ namespace XenAdmin.Actions get { return uploadToken; } } - public static void SetSecretInfo(IXenConnection connection, Dictionary config, string infoKey, string infoValue) + public string DiagnosticToken { - if (string.IsNullOrEmpty(infoKey)) - return; - - if (infoValue == null) - { - if (config.ContainsKey(infoKey)) - { - TryToDestroySecret(connection, config[infoKey]); - config.Remove(infoKey); - } - } - else if (config.ContainsKey(infoKey)) - { - try - { - string secretRef = Secret.get_by_uuid(connection.Session, config[infoKey]); - Secret.set_value(connection.Session, secretRef, infoValue); - } - catch (Failure) - { - config[infoKey] = Secret.CreateSecret(connection.Session, infoValue); - } - catch (WebException) - { - config[infoKey] = Secret.CreateSecret(connection.Session, infoValue); - } - } - else - { - config[infoKey] = Secret.CreateSecret(connection.Session, infoValue); - } - } - - private static void TryToDestroySecret(IXenConnection connection, string secret_uuid) - { - try - { - var secret = Secret.get_by_uuid(connection.Session, secret_uuid); - Secret.destroy(connection.Session, secret.opaque_ref); - log.DebugFormat("Successfully destroyed secret {0}", secret_uuid); - } - catch (Exception exn) - { - log.Error(string.Format("Failed to destroy secret {0}", secret_uuid), exn); - } + get { return diagnosticToken; } } private string GetIdentityToken() diff --git a/XenModel/Actions/HealthCheck/SaveHealthCheckSettingsAction.cs b/XenModel/Actions/HealthCheck/SaveHealthCheckSettingsAction.cs index cc44888fc..60ab43c5c 100644 --- a/XenModel/Actions/HealthCheck/SaveHealthCheckSettingsAction.cs +++ b/XenModel/Actions/HealthCheck/SaveHealthCheckSettingsAction.cs @@ -29,7 +29,9 @@ * SUCH DAMAGE. */ +using System; using System.Collections.Generic; +using System.Net; using XenAdmin.Model; using XenAPI; @@ -37,6 +39,8 @@ namespace XenAdmin.Actions { public class SaveHealthCheckSettingsAction : PureAsyncAction { + private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private readonly Pool pool; HealthCheckSettings healthCheckSettings; private string authenticationToken; @@ -59,12 +63,67 @@ namespace XenAdmin.Actions { Dictionary newConfig = healthCheckSettings.ToDictionary(pool.health_check_config); if (!string.IsNullOrEmpty(authenticationToken)) - HealthCheckAuthenticationAction.SetSecretInfo(Connection, newConfig, HealthCheckSettings.UPLOAD_TOKEN_SECRET, authenticationToken); + { + log.Info("Saving upload token as xapi secret"); + SetSecretInfo(Session, newConfig, HealthCheckSettings.UPLOAD_TOKEN_SECRET, authenticationToken); + } if (!string.IsNullOrEmpty(diagnosticToken)) - HealthCheckAuthenticationAction.SetSecretInfo(Connection, newConfig, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET, diagnosticToken); - HealthCheckAuthenticationAction.SetSecretInfo(Connection, newConfig, HealthCheckSettings.UPLOAD_CREDENTIAL_USER_SECRET, username); - HealthCheckAuthenticationAction.SetSecretInfo(Connection, newConfig, HealthCheckSettings.UPLOAD_CREDENTIAL_PASSWORD_SECRET, password); - Pool.set_health_check_config(Connection.Session, pool.opaque_ref, newConfig); + { + log.Info("Saving diagnostic token as xapi secret"); + SetSecretInfo(Session, newConfig, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET, diagnosticToken); + } + SetSecretInfo(Session, newConfig, HealthCheckSettings.UPLOAD_CREDENTIAL_USER_SECRET, username); + SetSecretInfo(Session, newConfig, HealthCheckSettings.UPLOAD_CREDENTIAL_PASSWORD_SECRET, password); + Pool.set_health_check_config(Session, pool.opaque_ref, newConfig); + } + + public static void SetSecretInfo(Session session, Dictionary config, string infoKey, string infoValue) + { + if (string.IsNullOrEmpty(infoKey)) + return; + + if (infoValue == null) + { + if (config.ContainsKey(infoKey)) + { + TryToDestroySecret(session, config[infoKey]); + config.Remove(infoKey); + } + } + else if (config.ContainsKey(infoKey)) + { + try + { + string secretRef = Secret.get_by_uuid(session, config[infoKey]); + Secret.set_value(session, secretRef, infoValue); + } + catch (Failure) + { + config[infoKey] = Secret.CreateSecret(session, infoValue); + } + catch (WebException) + { + config[infoKey] = Secret.CreateSecret(session, infoValue); + } + } + else + { + config[infoKey] = Secret.CreateSecret(session, infoValue); + } + } + + private static void TryToDestroySecret(Session session, string secret_uuid) + { + try + { + var secret = Secret.get_by_uuid(session, secret_uuid); + Secret.destroy(session, secret.opaque_ref); + log.DebugFormat("Successfully destroyed secret {0}", secret_uuid); + } + catch (Exception exn) + { + log.Error(string.Format("Failed to destroy secret {0}", secret_uuid), exn); + } } } } diff --git a/XenModel/HealthCheckSettings.cs b/XenModel/HealthCheckSettings.cs index 37e02e248..2b93ce49b 100644 --- a/XenModel/HealthCheckSettings.cs +++ b/XenModel/HealthCheckSettings.cs @@ -272,7 +272,7 @@ namespace XenAdmin.Model #endregion - public string GetSecretyInfo(IXenConnection connection, string secretType) + public string GetSecretyInfo(Session session, string secretType) { string UUID = string.Empty; switch (secretType) @@ -294,12 +294,12 @@ namespace XenAdmin.Model break; } - if (connection == null || string.IsNullOrEmpty(UUID)) + if (session == null || string.IsNullOrEmpty(UUID)) return null; try { - string opaqueref = Secret.get_by_uuid(connection.Session, UUID); - return Secret.get_value(connection.Session, opaqueref); + string opaqueref = Secret.get_by_uuid(session, UUID); + return Secret.get_value(session, opaqueref); } catch (Exception e) { @@ -308,6 +308,13 @@ namespace XenAdmin.Model } } + public string GetSecretyInfo(IXenConnection connection, string secretType) + { + if (connection == null) + return null; + return GetSecretyInfo(connection.Session, secretType); + } + public bool TryGetExistingTokens(IXenConnection connection, out string uploadToken, out string diagnosticToken) { uploadToken = null;