CP-12156: Obtain and display the result of the CIS analysis of the last uploaded report

Signed-off-by: Mihaela Stoica <mihaela.stoica@citrix.com>
This commit is contained in:
Mihaela Stoica 2015-08-27 00:30:02 +01:00
parent 4b073c0bc3
commit 44e18df03d
16 changed files with 882 additions and 201 deletions

View File

@ -0,0 +1,108 @@
/* Copyright (c) Citrix Systems Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using XenAdmin.Actions;
using XenAPI;
using XenAdmin.Network;
using XenAdmin.Model;
namespace XenAdmin.Core
{
public class HealthCheck
{
public static event Action<bool> CheckForAnalysisResultsCompleted;
/// <summary>
/// Checks the analysis results for all connections
/// </summary>
public static void CheckForAnalysisResults()
{
List<AsyncAction> actions = new List<AsyncAction>();
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));
}
if (actions.Count == 1)
{
actions[0].Completed += actionCompleted;
actions[0].RunAsync();
}
else if (actions.Count > 1)
{
var parallelAction = new ParallelAction(null, "", "", "", actions);
parallelAction.Completed += actionCompleted;
parallelAction.RunAsync();
}
}
/// <summary>
/// Checks the analysis results for the specified connections
/// </summary>
public static void CheckForAnalysisResults(object connection)
{
Pool pool = Helpers.GetPoolOfOne((IXenConnection)connection);
if (pool == null || Helpers.FeatureForbidden((IXenConnection)connection, Host.RestrictHealthCheck))
return;
var healthCheckSettings = pool.HealthCheckSettings;
if (healthCheckSettings.Status == HealthCheckStatus.Enabled && !healthCheckSettings.HasAnalysisResult)
{
var action = new GetHealthCheckAnalysisResultAction(pool, Registry.HealthCheckDiagnosticDomainName, true);
action.Completed += actionCompleted;
action.RunAsync();
}
}
private static void actionCompleted(ActionBase sender)
{
Program.AssertOffEventThread();
GetHealthCheckAnalysisResultAction action = sender as GetHealthCheckAnalysisResultAction;
if (action == null)
return;
if (CheckForAnalysisResultsCompleted != null)
CheckForAnalysisResultsCompleted(action.Succeeded);
}
}
}

View File

@ -319,6 +319,11 @@ namespace XenAdmin.Core
get { return ReadKey(HEALTH_CHECK_UPLOAD_DOMAIN_NAME); }
}
public static string HealthCheckDiagnosticDomainName
{
get { return ReadKey(HEALTH_CHECK_DIAGNOSTIC_DOMAIN_NAME); }
}
public static string HealthCheckProductKey
{
get { return ReadKey(HEALTH_CHECK_PRODUCT_KEY); }
@ -343,6 +348,7 @@ namespace XenAdmin.Core
private const string HEALTH_CHECK_UPLOAD_TOKEN_DOMAIN_NAME = "HealthCheckUploadTokenDomainName";
private const string HEALTH_CHECK_UPLOAD_GRANT_TOKEN_DOMAIN_NAME = "HealthCheckUploadGrantTokenDomainName";
private const string HEALTH_CHECK_UPLOAD_DOMAIN_NAME = "HealthCheckUploadDomainName";
private const string HEALTH_CHECK_DIAGNOSTIC_DOMAIN_NAME = "HealthCheckDiagnosticDomainName";
private const string HEALTH_CHECK_PRODUCT_KEY = "HealthCheckProductKey";
}

View File

@ -39,12 +39,14 @@ namespace XenAdmin.Dialogs.HealthCheck
this.poolNameLabel = new System.Windows.Forms.Label();
this.poolDetailsPanel = new System.Windows.Forms.TableLayoutPanel();
this.healthCheckStatusPanel = new System.Windows.Forms.TableLayoutPanel();
this.lastUploadDateLabel = new System.Windows.Forms.Label();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.issuesLabel = new System.Windows.Forms.Label();
this.refreshLinkLabel = new System.Windows.Forms.LinkLabel();
this.disableLinkLabel = new System.Windows.Forms.LinkLabel();
this.uploadRequestLinkLabel = new System.Windows.Forms.LinkLabel();
this.scheduleLabel = new System.Windows.Forms.Label();
this.editLinkLabel = new System.Windows.Forms.LinkLabel();
this.issuesLabel = new System.Windows.Forms.Label();
this.lastUploadDateLabel = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.lastUploadLabel = new System.Windows.Forms.Label();
@ -71,6 +73,7 @@ namespace XenAdmin.Dialogs.HealthCheck
this.tableLayoutPanel2.SuspendLayout();
this.poolDetailsPanel.SuspendLayout();
this.healthCheckStatusPanel.SuspendLayout();
this.flowLayoutPanel1.SuspendLayout();
this.previousUploadPanel.SuspendLayout();
this.notEnrolledPanel.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
@ -146,19 +149,44 @@ namespace XenAdmin.Dialogs.HealthCheck
// healthCheckStatusPanel
//
resources.ApplyResources(this.healthCheckStatusPanel, "healthCheckStatusPanel");
this.healthCheckStatusPanel.Controls.Add(this.disableLinkLabel, 0, 9);
this.healthCheckStatusPanel.Controls.Add(this.uploadRequestLinkLabel, 0, 8);
this.healthCheckStatusPanel.Controls.Add(this.scheduleLabel, 0, 6);
this.healthCheckStatusPanel.Controls.Add(this.editLinkLabel, 0, 7);
this.healthCheckStatusPanel.Controls.Add(this.issuesLabel, 0, 2);
this.healthCheckStatusPanel.Controls.Add(this.lastUploadDateLabel, 1, 1);
this.healthCheckStatusPanel.Controls.Add(this.label4, 0, 5);
this.healthCheckStatusPanel.Controls.Add(this.flowLayoutPanel1, 0, 3);
this.healthCheckStatusPanel.Controls.Add(this.disableLinkLabel, 0, 9);
this.healthCheckStatusPanel.Controls.Add(this.uploadRequestLinkLabel, 0, 10);
this.healthCheckStatusPanel.Controls.Add(this.scheduleLabel, 0, 7);
this.healthCheckStatusPanel.Controls.Add(this.editLinkLabel, 0, 8);
this.healthCheckStatusPanel.Controls.Add(this.label4, 0, 6);
this.healthCheckStatusPanel.Controls.Add(this.label1, 0, 0);
this.healthCheckStatusPanel.Controls.Add(this.lastUploadLabel, 0, 1);
this.healthCheckStatusPanel.Controls.Add(this.ReportAnalysisLinkLabel, 0, 3);
this.healthCheckStatusPanel.Controls.Add(this.previousUploadPanel, 0, 4);
this.healthCheckStatusPanel.Controls.Add(this.ReportAnalysisLinkLabel, 0, 4);
this.healthCheckStatusPanel.Controls.Add(this.previousUploadPanel, 0, 5);
this.healthCheckStatusPanel.Name = "healthCheckStatusPanel";
//
// lastUploadDateLabel
//
resources.ApplyResources(this.lastUploadDateLabel, "lastUploadDateLabel");
this.lastUploadDateLabel.Name = "lastUploadDateLabel";
//
// flowLayoutPanel1
//
resources.ApplyResources(this.flowLayoutPanel1, "flowLayoutPanel1");
this.healthCheckStatusPanel.SetColumnSpan(this.flowLayoutPanel1, 2);
this.flowLayoutPanel1.Controls.Add(this.issuesLabel);
this.flowLayoutPanel1.Controls.Add(this.refreshLinkLabel);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
//
// issuesLabel
//
resources.ApplyResources(this.issuesLabel, "issuesLabel");
this.issuesLabel.Name = "issuesLabel";
//
// refreshLinkLabel
//
resources.ApplyResources(this.refreshLinkLabel, "refreshLinkLabel");
this.refreshLinkLabel.Name = "refreshLinkLabel";
this.refreshLinkLabel.TabStop = true;
this.refreshLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.refreshLinkLabel_LinkClicked);
//
// disableLinkLabel
//
resources.ApplyResources(this.disableLinkLabel, "disableLinkLabel");
@ -189,17 +217,6 @@ namespace XenAdmin.Dialogs.HealthCheck
this.editLinkLabel.TabStop = true;
this.editLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.editlinkLabel_LinkClicked);
//
// issuesLabel
//
resources.ApplyResources(this.issuesLabel, "issuesLabel");
this.healthCheckStatusPanel.SetColumnSpan(this.issuesLabel, 2);
this.issuesLabel.Name = "issuesLabel";
//
// lastUploadDateLabel
//
resources.ApplyResources(this.lastUploadDateLabel, "lastUploadDateLabel");
this.lastUploadDateLabel.Name = "lastUploadDateLabel";
//
// label4
//
resources.ApplyResources(this.label4, "label4");
@ -223,6 +240,7 @@ namespace XenAdmin.Dialogs.HealthCheck
this.healthCheckStatusPanel.SetColumnSpan(this.ReportAnalysisLinkLabel, 2);
this.ReportAnalysisLinkLabel.Name = "ReportAnalysisLinkLabel";
this.ReportAnalysisLinkLabel.TabStop = true;
this.ReportAnalysisLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.ReportAnalysisLinkLabel_LinkClicked);
//
// previousUploadPanel
//
@ -239,6 +257,7 @@ namespace XenAdmin.Dialogs.HealthCheck
this.previousUploadPanel.SetColumnSpan(this.viewReportLinkLabel, 2);
this.viewReportLinkLabel.Name = "viewReportLinkLabel";
this.viewReportLinkLabel.TabStop = true;
this.viewReportLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.viewReportLinkLabel_LinkClicked);
//
// previousUploadDateLabel
//
@ -339,6 +358,8 @@ namespace XenAdmin.Dialogs.HealthCheck
this.poolDetailsPanel.PerformLayout();
this.healthCheckStatusPanel.ResumeLayout(false);
this.healthCheckStatusPanel.PerformLayout();
this.flowLayoutPanel1.ResumeLayout(false);
this.flowLayoutPanel1.PerformLayout();
this.previousUploadPanel.ResumeLayout(false);
this.previousUploadPanel.PerformLayout();
this.notEnrolledPanel.ResumeLayout(false);
@ -364,13 +385,11 @@ namespace XenAdmin.Dialogs.HealthCheck
private System.Windows.Forms.DataGridViewTextBoxColumn StatusColumn;
private System.Windows.Forms.TableLayoutPanel healthCheckStatusPanel;
private System.Windows.Forms.Label issuesLabel;
private System.Windows.Forms.Label lastUploadDateLabel;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label lastUploadLabel;
private System.Windows.Forms.LinkLabel ReportAnalysisLinkLabel;
private System.Windows.Forms.TableLayoutPanel previousUploadPanel;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.LinkLabel viewReportLinkLabel;
private System.Windows.Forms.Label previousUploadDateLabel;
private System.Windows.Forms.LinkLabel editLinkLabel;
private System.Windows.Forms.Label label4;
@ -386,6 +405,10 @@ namespace XenAdmin.Dialogs.HealthCheck
private System.Windows.Forms.LinkLabel uploadRequestLinkLabel;
private System.Windows.Forms.CheckBox showAgainCheckBox;
private System.Windows.Forms.LinkLabel disableLinkLabel;
private System.Windows.Forms.LinkLabel viewReportLinkLabel;
private System.Windows.Forms.LinkLabel refreshLinkLabel;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.Label lastUploadDateLabel;
}
}

View File

@ -32,6 +32,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using XenAdmin.Actions;
@ -52,6 +53,7 @@ namespace XenAdmin.Dialogs.HealthCheck
public HealthCheckOverviewDialog()
{
InitializeComponent();
Core.HealthCheck.CheckForAnalysisResultsCompleted += HealthCheck_CheckForUpdatesCompleted;
}
private Pool currentSelected = null;
@ -154,9 +156,24 @@ namespace XenAdmin.Dialogs.HealthCheck
_nameCell.Value = Pool.Name;
_nameCell.Image = null;
_statusCell.Value = Pool.HealthCheckSettings.StatusDescription;
_statusCell.Image = Pool.HealthCheckSettings.Status != HealthCheckStatus.Enabled
? Properties.Resources._000_error_h32bit_16
: Properties.Resources._000_Alert2_h32bit_16;
_statusCell.Image = Pool.HealthCheckSettings.Status != HealthCheckStatus.Enabled || !Pool.HealthCheckSettings.HasAnalysisResult
? null
: GetSeverityImage(Pool.HealthCheckSettings);
}
private Image GetSeverityImage(HealthCheckSettings healthCheckSettings)
{
if (healthCheckSettings.ReportAnalysisIssuesDetected == 0)
return Properties.Resources._000_Tick_h32bit_16;
switch (healthCheckSettings.ReportAnalysisSeverity)
{
case DiagnosticAlertSeverity.Error:
return Properties.Resources._000_error_h32bit_16;
case DiagnosticAlertSeverity.Warning:
return Properties.Resources._000_Alert2_h32bit_16;
default:
return Properties.Resources._000_Info3_h32bit_16;
}
}
}
#endregion
@ -194,6 +211,8 @@ namespace XenAdmin.Dialogs.HealthCheck
healthCheckStatusPanel.Visible = poolRow.Pool.HealthCheckSettings.Status == HealthCheckStatus.Enabled;
notEnrolledPanel.Visible = poolRow.Pool.HealthCheckSettings.Status != HealthCheckStatus.Enabled;
UpdateUploadRequestDescription(poolRow.Pool.HealthCheckSettings);
UpdateAnalysisResult(poolRow.Pool.HealthCheckSettings);
}
public string GetScheduleDescription(HealthCheckSettings healthCheckSettings)
@ -236,6 +255,50 @@ namespace XenAdmin.Dialogs.HealthCheck
return string.Empty;
}
public void UpdateAnalysisResult(HealthCheckSettings healthCheckSettings)
{
issuesLabel.Text = healthCheckSettings.StatusDescription;
ReportAnalysisLinkLabel.Visible = healthCheckSettings.HasAnalysisResult;
if (healthCheckSettings.HasAnalysisResult)
switch (healthCheckSettings.ReportAnalysisSeverity)
{
case DiagnosticAlertSeverity.Error:
issuesLabel.ForeColor = Color.Red;
break;
case DiagnosticAlertSeverity.Warning:
issuesLabel.ForeColor = Color.OrangeRed;
break;
default:
issuesLabel.ForeColor =
healthCheckSettings.ReportAnalysisIssuesDetected > 0 ? SystemColors.ControlText : Color.Green;
break;
}
else
{
issuesLabel.ForeColor = SystemColors.ControlText;
}
refreshLinkLabel.Visible = healthCheckSettings.HasUpload && !healthCheckSettings.HasAnalysisResult;
if (healthCheckSettings.HasOldAnalysisResult)
{
previousUploadPanel.Visible = healthCheckSettings.HasOldAnalysisResult;
DateTime previousUpload;
if (HealthCheckSettings.TryParseStringToDateTime(healthCheckSettings.ReportAnalysisUploadTime,
out previousUpload))
{
previousUploadDateLabel.Text = HelpersGUI.DateTimeToString(previousUpload.ToLocalTime(),
Messages.DATEFORMAT_DMY_HM, true);
}
}
else
{
previousUploadPanel.Visible = false;
}
}
private void HealthCheckOverviewDialog_Load(object sender, EventArgs e)
{
LoadPools();
@ -313,9 +376,10 @@ namespace XenAdmin.Dialogs.HealthCheck
{
healthCheckSettings.NewUploadRequest = HealthCheckSettings.DateTimeToString(DateTime.UtcNow);
var token = healthCheckSettings.GetSecretyInfo(poolRow.Pool.Connection, HealthCheckSettings.UPLOAD_TOKEN_SECRET);
var diagnosticToken = healthCheckSettings.GetSecretyInfo(poolRow.Pool.Connection, HealthCheckSettings.UPLOAD_TOKEN_SECRET);
var user = healthCheckSettings.GetSecretyInfo(poolRow.Pool.Connection, HealthCheckSettings.UPLOAD_CREDENTIAL_USER_SECRET);
var password = healthCheckSettings.GetSecretyInfo(poolRow.Pool.Connection, HealthCheckSettings.UPLOAD_CREDENTIAL_PASSWORD_SECRET);
new SaveHealthCheckSettingsAction(poolRow.Pool, healthCheckSettings, token, user, password, false).RunAsync();
new SaveHealthCheckSettingsAction(poolRow.Pool, healthCheckSettings, token, diagnosticToken, user, password, false).RunAsync();
}
}
@ -349,9 +413,49 @@ namespace XenAdmin.Dialogs.HealthCheck
return;
}
healthCheckSettings.Status = HealthCheckStatus.Disabled;
new SaveHealthCheckSettingsAction(poolRow.Pool, healthCheckSettings, null, null, null, false).RunAsync();
new SaveHealthCheckSettingsAction(poolRow.Pool, healthCheckSettings, null, null, null, null, false).RunAsync();
}
}
private void ReportAnalysisLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
if (poolsDataGridView.SelectedRows.Count != 1 || !(poolsDataGridView.SelectedRows[0] is PoolRow))
return;
var poolRow = (PoolRow)poolsDataGridView.SelectedRows[0];
if (poolRow.Pool == null)
return;
var url = poolRow.Pool.HealthCheckSettings.GetReportAnalysisLink(Registry.HealthCheckDiagnosticDomainName);
if (!string.IsNullOrEmpty(url))
Program.OpenURL(url);
}
private void viewReportLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
if (poolsDataGridView.SelectedRows.Count != 1 || !(poolsDataGridView.SelectedRows[0] is PoolRow))
return;
var poolRow = (PoolRow)poolsDataGridView.SelectedRows[0];
if (poolRow.Pool == null)
return;
var url = poolRow.Pool.HealthCheckSettings.GetReportAnalysisLink(Registry.HealthCheckDiagnosticDomainName);
if (!string.IsNullOrEmpty(url))
Program.OpenURL(url);
}
private void refreshLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var poolRow = (PoolRow)poolsDataGridView.SelectedRows[0];
if (poolRow.Pool == null)
return;
Core.HealthCheck.CheckForAnalysisResults(poolRow.Pool.Connection);
}
private void HealthCheck_CheckForUpdatesCompleted(bool succeeded)
{
Program.Invoke(Program.MainWindow, LoadPools);
}
}
}

View File

@ -154,7 +154,7 @@
<value>0, 0</value>
</data>
<data name="poolsDataGridView.Size" type="System.Drawing.Size, System.Drawing">
<value>489, 327</value>
<value>500, 352</value>
</data>
<data name="poolsDataGridView.TabIndex" type="System.Int32, mscorlib">
<value>11</value>
@ -211,7 +211,7 @@
<value>0, 2, 0, 4</value>
</data>
<data name="poolNameLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>262, 21</value>
<value>282, 21</value>
</data>
<data name="poolNameLabel.TabIndex" type="System.Int32, mscorlib">
<value>15</value>
@ -249,6 +249,153 @@
<data name="healthCheckStatusPanel.ColumnCount" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="lastUploadDateLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="lastUploadDateLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt</value>
</data>
<data name="lastUploadDateLabel.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="lastUploadDateLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>134, 24</value>
</data>
<data name="lastUploadDateLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
</data>
<data name="lastUploadDateLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>0, 15</value>
</data>
<data name="lastUploadDateLabel.TabIndex" type="System.Int32, mscorlib">
<value>23</value>
</data>
<data name="&gt;&gt;lastUploadDateLabel.Name" xml:space="preserve">
<value>lastUploadDateLabel</value>
</data>
<data name="&gt;&gt;lastUploadDateLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;lastUploadDateLabel.Parent" xml:space="preserve">
<value>healthCheckStatusPanel</value>
</data>
<data name="&gt;&gt;lastUploadDateLabel.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="flowLayoutPanel1.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="flowLayoutPanel1.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
<value>GrowAndShrink</value>
</data>
<data name="issuesLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="issuesLabel.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="issuesLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt</value>
</data>
<data name="issuesLabel.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="issuesLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 3</value>
</data>
<data name="issuesLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
</data>
<data name="issuesLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>175, 15</value>
</data>
<data name="issuesLabel.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
</data>
<data name="issuesLabel.Text" xml:space="preserve">
<value>Report analysis not yet available</value>
</data>
<data name="&gt;&gt;issuesLabel.Name" xml:space="preserve">
<value>issuesLabel</value>
</data>
<data name="&gt;&gt;issuesLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;issuesLabel.Parent" xml:space="preserve">
<value>flowLayoutPanel1</value>
</data>
<data name="&gt;&gt;issuesLabel.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="refreshLinkLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="refreshLinkLabel.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="refreshLinkLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt</value>
</data>
<data name="refreshLinkLabel.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="refreshLinkLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>184, 3</value>
</data>
<data name="refreshLinkLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
</data>
<data name="refreshLinkLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>46, 15</value>
</data>
<data name="refreshLinkLabel.TabIndex" type="System.Int32, mscorlib">
<value>21</value>
</data>
<data name="refreshLinkLabel.Text" xml:space="preserve">
<value>Refresh</value>
</data>
<data name="refreshLinkLabel.Visible" type="System.Boolean, mscorlib">
<value>False</value>
</data>
<data name="&gt;&gt;refreshLinkLabel.Name" xml:space="preserve">
<value>refreshLinkLabel</value>
</data>
<data name="&gt;&gt;refreshLinkLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.LinkLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;refreshLinkLabel.Parent" xml:space="preserve">
<value>flowLayoutPanel1</value>
</data>
<data name="&gt;&gt;refreshLinkLabel.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="flowLayoutPanel1.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt</value>
</data>
<data name="flowLayoutPanel1.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 42</value>
</data>
<data name="flowLayoutPanel1.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>0, 0, 0, 0</value>
</data>
<data name="flowLayoutPanel1.Size" type="System.Drawing.Size, System.Drawing">
<value>233, 21</value>
</data>
<data name="flowLayoutPanel1.TabIndex" type="System.Int32, mscorlib">
<value>22</value>
</data>
<data name="&gt;&gt;flowLayoutPanel1.Name" xml:space="preserve">
<value>flowLayoutPanel1</value>
</data>
<data name="&gt;&gt;flowLayoutPanel1.Type" xml:space="preserve">
<value>System.Windows.Forms.FlowLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;flowLayoutPanel1.Parent" xml:space="preserve">
<value>healthCheckStatusPanel</value>
</data>
<data name="&gt;&gt;flowLayoutPanel1.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="disableLinkLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
@ -259,7 +406,7 @@
<value>NoControl</value>
</data>
<data name="disableLinkLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 219</value>
<value>3, 212</value>
</data>
<data name="disableLinkLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
@ -283,7 +430,7 @@
<value>healthCheckStatusPanel</value>
</data>
<data name="&gt;&gt;disableLinkLabel.ZOrder" xml:space="preserve">
<value>0</value>
<value>2</value>
</data>
<data name="uploadRequestLinkLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
@ -295,10 +442,10 @@
<value>NoControl</value>
</data>
<data name="uploadRequestLinkLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 198</value>
<value>3, 240</value>
</data>
<data name="uploadRequestLinkLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
<value>3, 10, 3, 3</value>
</data>
<data name="uploadRequestLinkLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>131, 15</value>
@ -319,14 +466,14 @@
<value>healthCheckStatusPanel</value>
</data>
<data name="&gt;&gt;uploadRequestLinkLabel.ZOrder" xml:space="preserve">
<value>1</value>
<value>3</value>
</data>
<data name="scheduleLabel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<data name="scheduleLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="scheduleLabel.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="scheduleLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt</value>
</data>
@ -334,19 +481,19 @@
<value>NoControl</value>
</data>
<data name="scheduleLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 156</value>
<value>3, 170</value>
</data>
<data name="scheduleLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
</data>
<data name="scheduleLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>250, 15</value>
<value>270, 15</value>
</data>
<data name="scheduleLabel.TabIndex" type="System.Int32, mscorlib">
<value>18</value>
</data>
<data name="scheduleLabel.Text" xml:space="preserve">
<value>Upload a Health Check report </value>
<value>Upload a Health Check report </value>
</data>
<data name="&gt;&gt;scheduleLabel.Name" xml:space="preserve">
<value>scheduleLabel</value>
@ -358,7 +505,7 @@
<value>healthCheckStatusPanel</value>
</data>
<data name="&gt;&gt;scheduleLabel.ZOrder" xml:space="preserve">
<value>2</value>
<value>4</value>
</data>
<data name="editLinkLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
@ -370,7 +517,7 @@
<value>NoControl</value>
</data>
<data name="editLinkLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 177</value>
<value>3, 191</value>
</data>
<data name="editLinkLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
@ -394,81 +541,6 @@
<value>healthCheckStatusPanel</value>
</data>
<data name="&gt;&gt;editLinkLabel.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="issuesLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="issuesLabel.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="issuesLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt</value>
</data>
<data name="issuesLabel.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="issuesLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 45</value>
</data>
<data name="issuesLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
</data>
<data name="issuesLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>250, 15</value>
</data>
<data name="issuesLabel.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
</data>
<data name="issuesLabel.Text" xml:space="preserve">
<value>Report analysis not yet available</value>
</data>
<data name="&gt;&gt;issuesLabel.Name" xml:space="preserve">
<value>issuesLabel</value>
</data>
<data name="&gt;&gt;issuesLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;issuesLabel.Parent" xml:space="preserve">
<value>healthCheckStatusPanel</value>
</data>
<data name="&gt;&gt;issuesLabel.ZOrder" xml:space="preserve">
<value>4</value>
</data>
<data name="lastUploadDateLabel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="lastUploadDateLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt</value>
</data>
<data name="lastUploadDateLabel.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="lastUploadDateLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>140, 24</value>
</data>
<data name="lastUploadDateLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
</data>
<data name="lastUploadDateLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>0, 15</value>
</data>
<data name="lastUploadDateLabel.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="lastUploadDateLabel.Visible" type="System.Boolean, mscorlib">
<value>False</value>
</data>
<data name="&gt;&gt;lastUploadDateLabel.Name" xml:space="preserve">
<value>lastUploadDateLabel</value>
</data>
<data name="&gt;&gt;lastUploadDateLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;lastUploadDateLabel.Parent" xml:space="preserve">
<value>healthCheckStatusPanel</value>
</data>
<data name="&gt;&gt;lastUploadDateLabel.ZOrder" xml:space="preserve">
<value>5</value>
</data>
<data name="label4.AutoSize" type="System.Boolean, mscorlib">
@ -481,10 +553,10 @@
<value>NoControl</value>
</data>
<data name="label4.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 135</value>
<value>3, 149</value>
</data>
<data name="label4.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
<value>3, 10, 3, 3</value>
</data>
<data name="label4.Size" type="System.Drawing.Size, System.Drawing">
<value>61, 15</value>
@ -550,16 +622,16 @@
<value>3, 24</value>
</data>
<data name="lastUploadLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
<value>3, 3, 0, 3</value>
</data>
<data name="lastUploadLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>131, 15</value>
<value>128, 15</value>
</data>
<data name="lastUploadLabel.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="lastUploadLabel.Text" xml:space="preserve">
<value>Last successful upload: </value>
<value>Last successful upload:</value>
</data>
<data name="lastUploadLabel.Visible" type="System.Boolean, mscorlib">
<value>False</value>
@ -667,7 +739,7 @@
<value>NoControl</value>
</data>
<data name="previousUploadDateLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>107, 3</value>
<value>104, 3</value>
</data>
<data name="previousUploadDateLabel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
@ -703,7 +775,7 @@
<value>3, 3</value>
</data>
<data name="label3.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 3, 3, 3</value>
<value>3, 3, 0, 3</value>
</data>
<data name="label3.Size" type="System.Drawing.Size, System.Drawing">
<value>98, 15</value>
@ -733,13 +805,16 @@
<value>Segoe UI, 9pt</value>
</data>
<data name="previousUploadPanel.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 87</value>
<value>0, 94</value>
</data>
<data name="previousUploadPanel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>0, 10, 0, 3</value>
</data>
<data name="previousUploadPanel.RowCount" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="previousUploadPanel.Size" type="System.Drawing.Size, System.Drawing">
<value>250, 42</value>
<value>276, 42</value>
</data>
<data name="previousUploadPanel.TabIndex" type="System.Int32, mscorlib">
<value>17</value>
@ -760,7 +835,7 @@
<value>10</value>
</data>
<data name="previousUploadPanel.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="viewReportLinkLabel" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="previousUploadDateLabel" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="label3" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,52,Percent,48" /&gt;&lt;Rows Styles="AutoSize,50,AutoSize,50,Absolute,20" /&gt;&lt;/TableLayoutSettings&gt;</value>
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="viewReportLinkLabel" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="previousUploadDateLabel" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="label3" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,52,Percent,48" /&gt;&lt;Rows Styles="AutoSize,0,AutoSize,0,Absolute,20" /&gt;&lt;/TableLayoutSettings&gt;</value>
</data>
<data name="healthCheckStatusPanel.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
@ -772,10 +847,10 @@
<value>3, 3</value>
</data>
<data name="healthCheckStatusPanel.RowCount" type="System.Int32, mscorlib">
<value>10</value>
<value>11</value>
</data>
<data name="healthCheckStatusPanel.Size" type="System.Drawing.Size, System.Drawing">
<value>256, 237</value>
<value>276, 279</value>
</data>
<data name="healthCheckStatusPanel.TabIndex" type="System.Int32, mscorlib">
<value>16</value>
@ -793,7 +868,7 @@
<value>0</value>
</data>
<data name="healthCheckStatusPanel.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="disableLinkLabel" Row="9" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="uploadRequestLinkLabel" Row="8" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="scheduleLabel" Row="6" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="editLinkLabel" Row="7" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="issuesLabel" Row="2" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="lastUploadDateLabel" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="label4" Row="5" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="label1" Row="0" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="lastUploadLabel" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="ReportAnalysisLinkLabel" Row="3" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="previousUploadPanel" Row="4" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100" /&gt;&lt;Rows Styles="AutoSize,50,AutoSize,50,AutoSize,20,AutoSize,20,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,20,AutoSize,20" /&gt;&lt;/TableLayoutSettings&gt;</value>
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="lastUploadDateLabel" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="flowLayoutPanel1" Row="3" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="disableLinkLabel" Row="9" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="uploadRequestLinkLabel" Row="10" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="scheduleLabel" Row="7" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="editLinkLabel" Row="8" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="label4" Row="6" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="label1" Row="0" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="lastUploadLabel" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="ReportAnalysisLinkLabel" Row="4" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="previousUploadPanel" Row="5" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100" /&gt;&lt;Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0" /&gt;&lt;/TableLayoutSettings&gt;</value>
</data>
<data name="notEnrolledPanel.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
@ -859,7 +934,7 @@
<value>3, 3, 3, 3</value>
</data>
<data name="label6.Size" type="System.Drawing.Size, System.Drawing">
<value>250, 15</value>
<value>270, 15</value>
</data>
<data name="label6.TabIndex" type="System.Int32, mscorlib">
<value>5</value>
@ -886,13 +961,13 @@
<value>Segoe UI, 9pt</value>
</data>
<data name="notEnrolledPanel.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 246</value>
<value>3, 288</value>
</data>
<data name="notEnrolledPanel.RowCount" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="notEnrolledPanel.Size" type="System.Drawing.Size, System.Drawing">
<value>256, 48</value>
<value>276, 42</value>
</data>
<data name="notEnrolledPanel.TabIndex" type="System.Int32, mscorlib">
<value>19</value>
@ -925,7 +1000,7 @@
<value>2</value>
</data>
<data name="poolDetailsPanel.Size" type="System.Drawing.Size, System.Drawing">
<value>262, 297</value>
<value>282, 322</value>
</data>
<data name="poolDetailsPanel.TabIndex" type="System.Int32, mscorlib">
<value>20</value>
@ -958,7 +1033,7 @@
<value>2</value>
</data>
<data name="tableLayoutPanel2.Size" type="System.Drawing.Size, System.Drawing">
<value>270, 327</value>
<value>290, 352</value>
</data>
<data name="tableLayoutPanel2.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
@ -997,10 +1072,10 @@
<value>220</value>
</data>
<data name="splitContainer1.Size" type="System.Drawing.Size, System.Drawing">
<value>763, 327</value>
<value>794, 352</value>
</data>
<data name="splitContainer1.SplitterDistance" type="System.Int32, mscorlib">
<value>489</value>
<value>500</value>
</data>
<data name="splitContainer1.TabIndex" type="System.Int32, mscorlib">
<value>17</value>
@ -1027,7 +1102,7 @@
<value>NoControl</value>
</data>
<data name="buttonCancel.Location" type="System.Drawing.Point, System.Drawing">
<value>703, 407</value>
<value>734, 432</value>
</data>
<data name="buttonCancel.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
@ -1111,13 +1186,13 @@
<value>185, 0</value>
</data>
<data name="PolicyStatementLinkLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>95, 15</value>
<value>96, 15</value>
</data>
<data name="PolicyStatementLinkLabel.TabIndex" type="System.Int32, mscorlib">
<value>14</value>
</data>
<data name="PolicyStatementLinkLabel.Text" xml:space="preserve">
<value>Policy statement</value>
<value>Policy Statement</value>
</data>
<data name="&gt;&gt;PolicyStatementLinkLabel.Name" xml:space="preserve">
<value>PolicyStatementLinkLabel</value>
@ -1144,7 +1219,7 @@
<value>0, 0, 0, 4</value>
</data>
<data name="flowLayoutPanel2.Size" type="System.Drawing.Size, System.Drawing">
<value>769, 18</value>
<value>800, 18</value>
</data>
<data name="flowLayoutPanel2.TabIndex" type="System.Int32, mscorlib">
<value>13</value>
@ -1183,7 +1258,7 @@
<value>0, 0, 0, 4</value>
</data>
<data name="rubricLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>766, 34</value>
<value>797, 34</value>
</data>
<data name="rubricLabel.TabIndex" type="System.Int32, mscorlib">
<value>12</value>
@ -1216,7 +1291,7 @@
<value>3</value>
</data>
<data name="tableLayoutPanel1.Size" type="System.Drawing.Size, System.Drawing">
<value>769, 389</value>
<value>800, 414</value>
</data>
<data name="tableLayoutPanel1.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
@ -1246,7 +1321,7 @@
<value>Segoe UI, 9pt</value>
</data>
<data name="showAgainCheckBox.Location" type="System.Drawing.Point, System.Drawing">
<value>9, 410</value>
<value>9, 435</value>
</data>
<data name="showAgainCheckBox.Size" type="System.Drawing.Size, System.Drawing">
<value>469, 19</value>
@ -1276,7 +1351,7 @@
<value>96, 96</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>795, 442</value>
<value>826, 467</value>
</data>
<data name="$this.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt</value>

View File

@ -47,6 +47,7 @@ namespace XenAdmin.Dialogs.HealthCheck
private bool authenticationRequired;
private bool authenticated;
private string authenticationToken;
private string diagnosticToken;
private string xsUserName;
private string xsPassword;
@ -56,7 +57,8 @@ namespace XenAdmin.Dialogs.HealthCheck
healthCheckSettings = pool.HealthCheckSettings;
if (enrollNow)
healthCheckSettings.Status = HealthCheckStatus.Enabled;
authenticationToken = healthCheckSettings.GetExistingSecretyInfo(pool.Connection, HealthCheckSettings.UPLOAD_TOKEN_SECRET);
authenticated = healthCheckSettings.TryGetExistingTokens(pool.Connection, out authenticationToken, out diagnosticToken);
authenticationRequired = !authenticated;
xsUserName = healthCheckSettings.GetSecretyInfo(pool.Connection, HealthCheckSettings.UPLOAD_CREDENTIAL_USER_SECRET);
xsPassword = healthCheckSettings.GetSecretyInfo(pool.Connection, HealthCheckSettings.UPLOAD_CREDENTIAL_PASSWORD_SECRET);
InitializeComponent();
@ -103,9 +105,6 @@ namespace XenAdmin.Dialogs.HealthCheck
private void InitializeControls()
{
authenticationRequired = string.IsNullOrEmpty(authenticationToken);
authenticated = !authenticationRequired;
Text = String.Format(Messages.HEALTHCHECK_ENROLLMENT_TITLE, pool.Name);
authenticationRubricLabel.Text = authenticationRequired
@ -165,13 +164,15 @@ namespace XenAdmin.Dialogs.HealthCheck
if (ChangesMade())
{
var newHealthCheckSettings = new HealthCheckSettings(
enrollmentCheckBox.Checked ? HealthCheckStatus.Enabled : HealthCheckStatus.Disabled,
(int)(frequencyNumericBox.Value * 7),
(DayOfWeek)dayOfWeekComboBox.SelectedValue,
(int)timeOfDayComboBox.SelectedValue);
var newHealthCheckSettings = new HealthCheckSettings(pool.health_check_config);
new SaveHealthCheckSettingsAction(pool, newHealthCheckSettings, authenticationToken, textboxXSUserName.Text, textboxXSPassword.Text, false).RunAsync();
newHealthCheckSettings.Status = enrollmentCheckBox.Checked ? HealthCheckStatus.Enabled : HealthCheckStatus.Disabled;
newHealthCheckSettings.IntervalInDays = (int)(frequencyNumericBox.Value * 7);
newHealthCheckSettings.DayOfWeek = (DayOfWeek)dayOfWeekComboBox.SelectedValue;
newHealthCheckSettings.TimeOfDay = (int)timeOfDayComboBox.SelectedValue;
newHealthCheckSettings. RetryInterval = HealthCheckSettings.DEFAULT_RETRY_INTERVAL;
new SaveHealthCheckSettingsAction(pool, newHealthCheckSettings, authenticationToken, diagnosticToken, textboxXSUserName.Text, textboxXSPassword.Text, false).RunAsync();
new TransferHealthCheckSettingsAction(pool, newHealthCheckSettings, textboxXSUserName.Text, textboxXSPassword.Text, true).RunAsync();
}
okButton.Enabled = true;
@ -267,7 +268,7 @@ namespace XenAdmin.Dialogs.HealthCheck
var action = new HealthCheckAuthenticationAction(pool, textBoxMyCitrixUsername.Text.Trim(), textBoxMyCitrixPassword.Text.Trim(),
Registry.HealthCheckIdentityTokenDomainName, Registry.HealthCheckUploadGrantTokenDomainName, Registry.HealthCheckUploadTokenDomainName,
Registry.HealthCheckProductKey, true, 0, false);
Registry.HealthCheckDiagnosticDomainName, Registry.HealthCheckProductKey, true, 0, false);
try
{
@ -282,8 +283,7 @@ namespace XenAdmin.Dialogs.HealthCheck
}
authenticationToken = action.UploadToken; // curent upload token
authenticated = !string.IsNullOrEmpty(authenticationToken);
authenticationToken = pool.HealthCheckSettings.GetExistingSecretyInfo(pool.Connection, HealthCheckSettings.UPLOAD_TOKEN_SECRET);
authenticated = pool.HealthCheckSettings.TryGetExistingTokens(pool.Connection, out authenticationToken, out diagnosticToken);
return authenticated;
}

View File

@ -126,6 +126,7 @@ namespace XenAdmin
private readonly LicenseTimer licenseTimer;
public readonly HealthCheckOverviewLauncher HealthCheckOverviewLauncher;
private readonly System.Windows.Forms.Timer healthCheckResultTimer = new System.Windows.Forms.Timer();
private Dictionary<ToolStripMenuItem, int> pluginMenuItemStartIndexes = new Dictionary<ToolStripMenuItem, int>();
@ -549,6 +550,15 @@ namespace XenAdmin
CheckForUpdatesTimer.Start();
Updates.CheckForUpdates(false);
}
if (!Program.RunInAutomatedTestMode)
{
// start healthCheckResult thread
healthCheckResultTimer.Interval = 1000 * 60 * 60; // 1 hour
healthCheckResultTimer.Tick += HealthCheckResultTimer_Tick;
healthCheckResultTimer.Start();
}
ProcessCommand(CommandLineArgType, CommandLineParam);
}
@ -557,6 +567,11 @@ namespace XenAdmin
Updates.CheckForUpdates(false);
}
private void HealthCheckResultTimer_Tick(object sender, EventArgs e)
{
HealthCheck.CheckForAnalysisResults();
}
private void LoadTasksAsMeddlingActions(IXenConnection connection)
{
if (!connection.IsConnected || connection.Session == null)
@ -855,8 +870,9 @@ namespace XenAdmin
if (Properties.Settings.Default.ShowHealthCheckEnrollmentReminder)
ThreadPool.QueueUserWorkItem(CheckHealthCheckEnrollment, connection);
ThreadPool.QueueUserWorkItem(HealthCheck.CheckForAnalysisResults, connection);
ThreadPool.QueueUserWorkItem(InformHealthCheckEnrollment, connection);
Updates.CheckServerPatches();
Updates.CheckServerVersion();
RequestRefreshTreeView();

View File

@ -184,8 +184,8 @@ namespace XenAdmin.Wizards.BugToolWizardFiles
return false;
var action = new HealthCheckAuthenticationAction(null, usernameTextBox.Text.Trim(), passwordTextBox.Text.Trim(),
Registry.HealthCheckIdentityTokenDomainName, Registry.HealthCheckUploadGrantTokenDomainName,
Registry.HealthCheckUploadTokenDomainName, Registry.HealthCheckProductKey,
Registry.HealthCheckIdentityTokenDomainName, Registry.HealthCheckUploadGrantTokenDomainName,
Registry.HealthCheckUploadTokenDomainName, Registry.HealthCheckDiagnosticDomainName, Registry.HealthCheckProductKey,
false, TokenExpiration, false);
new ActionProgressDialog(action, ProgressBarStyle.Blocks).ShowDialog(Parent);

View File

@ -197,6 +197,7 @@
<Compile Include="Controls\UpsellPage.designer.cs">
<DependentUpon>UpsellPage.cs</DependentUpon>
</Compile>
<Compile Include="Core\HealthCheck.cs" />
<Compile Include="Diagnostics\Checks\AssertCanEvacuateCheck.cs" />
<Compile Include="Diagnostics\Checks\AssertCanEvacuateUpgradeCheck.cs" />
<Compile Include="Diagnostics\Checks\SafeToUpgradeCheck.cs" />

View File

@ -0,0 +1,157 @@
/* Copyright (c) Citrix Systems Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading;
using System.Web.Script.Serialization;
using XenAdmin.Model;
using XenAPI;
namespace XenAdmin.Actions
{
public class GetHealthCheckAnalysisResultAction: AsyncAction
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private const string DIAG_RESULT_URL = "/diag_sdk/diag_results/";
private readonly string diagnosticDomainName = "https://cis.citrix.com";
private CancellationTokenSource cts;
public GetHealthCheckAnalysisResultAction(Pool pool, bool suppressHistory)
: base(pool.Connection, Messages.ACTION_GET_HEALTH_CHECK_RESULT, Messages.ACTION_GET_HEALTH_CHECK_RESULT_PROGRESS, suppressHistory)
{
}
public GetHealthCheckAnalysisResultAction(Pool pool, string diagnosticDomainName, bool suppressHistory)
: this(pool, suppressHistory)
{
if (!string.IsNullOrEmpty(diagnosticDomainName))
this.diagnosticDomainName = diagnosticDomainName;
}
protected override void Run()
{
try
{
var diagnosticToken = Pool.HealthCheckSettings.GetSecretyInfo(Pool.Connection, 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);
Description = Messages.ACTION_GET_HEALTH_CHECK_RESULT_FAILED;
return;
}
if (!Pool.HealthCheckSettings.HasUpload)
{
log.InfoFormat("Cannot get the diagnostic result for {0}, because the there is no upload completed yet", Pool.Name);
Description = Messages.ACTION_GET_HEALTH_CHECK_RESULT_FAILED;
return;
}
var analysisResult = GetAnalysisResult(diagnosticToken, Pool.HealthCheckSettings.UploadUuid);
log.Info("Saving analysis result");
Dictionary<string, string> newConfig = Pool.health_check_config;
newConfig[HealthCheckSettings.REPORT_ANALYSIS_SEVERITY] = HealthCheckSettings.DiagnosticAlertSeverityToString(GetMaxSeverity(analysisResult));
newConfig[HealthCheckSettings.REPORT_ANALYSIS_ISSUES_DETECTED] = analysisResult.Count.ToString();
newConfig[HealthCheckSettings.REPORT_ANALYSIS_UPLOAD_UUID] = Pool.HealthCheckSettings.UploadUuid;
newConfig[HealthCheckSettings.REPORT_ANALYSIS_UPLOAD_TIME] = Pool.HealthCheckSettings.LastSuccessfulUpload;
Pool.set_health_check_config(Session, Pool.opaque_ref, newConfig);
}
catch (Exception e)
{
log.InfoFormat("Exception while getting diagnostic result from {0}. Exception Message: {1} ", diagnosticDomainName, e.Message);
Description = Messages.ACTION_GET_HEALTH_CHECK_RESULT_FAILED;
throw;
}
Description = Messages.COMPLETED;
}
private DiagnosticAlertSeverity GetMaxSeverity(List<AnalysisResult> diagnosticAlerts)
{
var maxSeverity = DiagnosticAlertSeverity.Info;
foreach (var diagnosticAlert in diagnosticAlerts)
{
var severity = HealthCheckSettings.StringToDiagnosticAlertSeverity(diagnosticAlert.severity);
if (severity > maxSeverity)
maxSeverity = severity;
}
return maxSeverity;
}
private List<AnalysisResult> GetAnalysisResult(string diagnosticToken, string uploadUuid)
{
var urlString = string.Format("{0}{1}?upload_uuid={2}", diagnosticDomainName, DIAG_RESULT_URL, uploadUuid);
var authorizationHeader = "BT " + diagnosticToken;
var httpWebRequest = (HttpWebRequest)WebRequest.Create(urlString);
httpWebRequest.Headers.Add("Authorization", authorizationHeader);
httpWebRequest.Method = "GET";
string result;
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
TemplateResponse response = new JavaScriptSerializer().Deserialize<TemplateResponse>(result);
return response.results;
}
private class TemplateResponse
{
public List<AnalysisResult> results { get; set; }
}
private class AnalysisResult
{
public string severity { get; set; }
/*public string extra_information { get; set; }
public string owner { get; set; }
public string crm_id { get; set; }
public string id { get; set; }
public List<string> category { get; set; }
public string analysis_id { get; set; }
public string priority { get; set; }
public string product { get; set; }
public string description { get; set; }
public DateTime analysis_completion_time { get; set; }
public string component { get; set; }
public string name { get; set; }
public string upload_description { get; set; }
public string upload_id { get; set; }
public string recommendations { get; set; }
public string env_identifier { get; set; }*/
}
}
}

View File

@ -57,10 +57,12 @@ namespace XenAdmin.Actions
private const string identityTokenUrl = "/auth/api/create_identity/";
private const string uploadGrantTokenUrl = "/feeds/api/create_grant/";
private const string uploadTokenUrl = "/feeds/api/create_upload/";
private const string diagnosticTokenUrl = "/diag_sdk/token_grant/";
private readonly string identityTokenDomainName = "https://cis.citrix.com";
private readonly string uploadGrantTokenDomainName = "https://rttf.citrix.com";
private readonly string uploadTokenDomainName = "https://rttf.citrix.com";
private readonly string diagnosticTokenDomainName = " https://cis.citrix.com";
private readonly string productKey = "1a2d94a4263cd016dd7a7d510bde87f058a0b75d";
@ -80,15 +82,18 @@ namespace XenAdmin.Actions
}
public HealthCheckAuthenticationAction(Pool pool, string username, string password,
string identityTokenDomainName, string uploadGrantTokenDomainName, string uploadTokenDomainName, string productKey, bool saveTokenAsSecret, long tokenExpiration, bool suppressHistory)
string identityTokenDomainName, string uploadGrantTokenDomainName, string uploadTokenDomainName, string diagnosticTokenDomainName,
string productKey, bool saveTokenAsSecret, long tokenExpiration, bool suppressHistory)
: this(pool, username, password, saveTokenAsSecret, tokenExpiration, suppressHistory)
{
if (!string.IsNullOrEmpty(identityTokenDomainName))
this.identityTokenDomainName = identityTokenDomainName;
if (!string.IsNullOrEmpty(identityTokenDomainName))
if (!string.IsNullOrEmpty(uploadGrantTokenDomainName))
this.uploadGrantTokenDomainName = uploadGrantTokenDomainName;
if (!string.IsNullOrEmpty(identityTokenDomainName))
if (!string.IsNullOrEmpty(uploadTokenDomainName))
this.uploadTokenDomainName = uploadTokenDomainName;
if (!string.IsNullOrEmpty(diagnosticTokenDomainName))
this.diagnosticTokenDomainName = diagnosticTokenDomainName;
if (!string.IsNullOrEmpty(productKey))
this.productKey = productKey;
}
@ -101,12 +106,14 @@ namespace XenAdmin.Actions
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<string, string> newConfig = pool.health_check_config;
SetSecretInfo(Connection, newConfig, HealthCheckSettings.UPLOAD_TOKEN_SECRET, uploadToken);
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);
}
}
@ -184,18 +191,18 @@ namespace XenAdmin.Actions
var urlString = string.Format("{0}{1}", identityTokenDomainName, identityTokenUrl);
try
{
return GetToken(urlString, json);
return GetToken(urlString, json, null);
}
catch (WebException e)
{
log.InfoFormat("WebException while getting identity token. Exception Message: " + e.Message);
log.InfoFormat("WebException while getting identity token from {0}. Exception Message: {1} ", identityTokenDomainName, e.Message);
if (e.Status == WebExceptionStatus.ProtocolError && ((HttpWebResponse) e.Response).StatusCode == HttpStatusCode.Forbidden)
throw new HealthCheckAuthenticationException(Messages.HEALTH_CHECK_AUTHENTICATION_INVALID_CREDENTIALS, e);
throw;
}
catch (Exception e)
{
log.InfoFormat("Exception while getting identity token. Exception Message: " + e.Message);
log.InfoFormat("Exception while getting identity token from {0}. Exception Message: {1} ", identityTokenDomainName, e.Message);
throw;
}
}
@ -218,11 +225,11 @@ namespace XenAdmin.Actions
try
{
return GetToken(urlString, json);
return GetToken(urlString, json, null);
}
catch (Exception e)
{
log.InfoFormat("Exception while getting upload grant token. Exception Message: " + e.Message);
log.InfoFormat("Exception while getting upload grant token from {0}. Exception Message: {1} ", uploadGrantTokenDomainName, e.Message);
throw;
}
}
@ -238,18 +245,42 @@ namespace XenAdmin.Actions
var urlString = string.Format("{0}{1}", uploadTokenDomainName, uploadTokenUrl);
try
{
return GetToken(urlString, json);
return GetToken(urlString, json, null);
}
catch (Exception e)
{
log.InfoFormat("Exception while getting upload token. Exception Message: " + e.Message);
log.InfoFormat("Exception while getting upload token from {0}. Exception Message: {1} ", uploadTokenDomainName, e.Message);
throw;
}
}
private string GetToken(string urlString, string jsonParameters)
private string GetDiagnosticToken(string identityToken)
{
var json = new JavaScriptSerializer().Serialize(new
{
agent = "XenServer",
max_age = 10000000
});
var urlString = string.Format("{0}{1}", diagnosticTokenDomainName, diagnosticTokenUrl);
try
{
return GetToken(urlString, json, "BT " + identityToken);
}
catch (Exception e)
{
log.InfoFormat("Exception while getting diagnostic token from {0}. Exception Message: {1} ", diagnosticTokenDomainName, e.Message);
throw;
}
}
private string GetToken(string urlString, string jsonParameters, string authorizationHeader)
{
var httpWebRequest = (HttpWebRequest) WebRequest.Create(urlString);
if (authorizationHeader != null)
{
httpWebRequest.Headers.Add("Authorization", authorizationHeader);
}
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";

View File

@ -40,15 +40,17 @@ namespace XenAdmin.Actions
private readonly Pool pool;
HealthCheckSettings healthCheckSettings;
private string authenticationToken;
private string diagnosticToken;
private string username;
private string password;
public SaveHealthCheckSettingsAction(Pool pool, HealthCheckSettings healthCheckSettings, string authenticationToken, string userName, string passWord, bool suppressHistory)
public SaveHealthCheckSettingsAction(Pool pool, HealthCheckSettings healthCheckSettings, string authenticationToken, string diagnosticToken, string userName, string passWord, bool suppressHistory)
: base(pool.Connection, Messages.ACTION_SAVE_HEALTHCHECK_SETTINGS, string.Format(Messages.ACTION_SAVING_HEALTHCHECK_SETTINGS, pool.Name), suppressHistory)
{
this.pool = pool;
this.healthCheckSettings = healthCheckSettings;
this.authenticationToken = authenticationToken;
this.diagnosticToken = diagnosticToken;
this.username = healthCheckSettings.Status == HealthCheckStatus.Enabled ? userName : null;
this.password = healthCheckSettings.Status == HealthCheckStatus.Enabled ? passWord : null;
}
@ -58,6 +60,8 @@ namespace XenAdmin.Actions
Dictionary<string, string> newConfig = healthCheckSettings.ToDictionary(pool.health_check_config);
if (!string.IsNullOrEmpty(authenticationToken))
HealthCheckAuthenticationAction.SetSecretInfo(Connection, 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);

View File

@ -43,6 +43,11 @@ namespace XenAdmin.Model
Disabled, Enabled, Undefined
}
public enum DiagnosticAlertSeverity
{
Info, Warning, Error
}
public class HealthCheckSettings
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
@ -55,6 +60,12 @@ namespace XenAdmin.Model
public string UserNameSecretUuid;
public string PasswordSecretUuid;
public string LastSuccessfulUpload;
public string DiagnosticTokenSecretUuid;
public string UploadUuid;
public DiagnosticAlertSeverity ReportAnalysisSeverity;
public int ReportAnalysisIssuesDetected;
public string ReportAnalysisUploadUuid;
public string ReportAnalysisUploadTime;
public const int DEFAULT_INTERVAL_IN_DAYS = 14;
public const int DEFAULT_RETRY_INTERVAL = 7; // in days
@ -75,15 +86,13 @@ namespace XenAdmin.Model
public const string HEALTH_CHECK_PIPE = "HealthCheckServicePipe";
public const string HEALTH_CHECK_PIPE_END_MESSAGE = "HealthCheckServicePipe";
public const string UPLOAD_UUID = "UploadUuid";
public const string DIAGNOSTIC_TOKEN_SECRET = "DiagnosticToken.Secret";
public const string REPORT_ANALYSIS_SEVERITY = "ReportAnalysis.Severity";
public const string REPORT_ANALYSIS_ISSUES_DETECTED = "ReportAnalysis.IssuesDetected";
public const string REPORT_ANALYSIS_UPLOAD_UUID = "ReportAnalysis.UploadUuid";
public const string REPORT_ANALYSIS_UPLOAD_TIME = "ReportAnalysis.UploadTime";
public HealthCheckSettings(HealthCheckStatus status, int intervalInDays, DayOfWeek dayOfWeek, int timeOfDay)
{
Status = status;
IntervalInDays = intervalInDays;
DayOfWeek = dayOfWeek;
TimeOfDay = timeOfDay;
RetryInterval = DEFAULT_RETRY_INTERVAL;
}
private const string REPORT_LINK_PATH = "AutoSupport/analysis/upload_overview";
public HealthCheckSettings(Dictionary<string, string> config)
{
@ -96,10 +105,16 @@ namespace XenAdmin.Model
TimeOfDay = IntKey(config, TIME_OF_DAY, GetDefaultTime());
RetryInterval = IntKey(config, RETRY_INTERVAL, DEFAULT_RETRY_INTERVAL);
UploadTokenSecretUuid = Get(config, UPLOAD_TOKEN_SECRET);
DiagnosticTokenSecretUuid = Get(config, DIAGNOSTIC_TOKEN_SECRET);
NewUploadRequest = Get(config, NEW_UPLOAD_REQUEST);
UserNameSecretUuid = Get(config, UPLOAD_CREDENTIAL_USER_SECRET);
PasswordSecretUuid = Get(config, UPLOAD_CREDENTIAL_PASSWORD_SECRET);
LastSuccessfulUpload = Get(config, LAST_SUCCESSFUL_UPLOAD);
UploadUuid = Get(config, UPLOAD_UUID);
ReportAnalysisSeverity = StringToDiagnosticAlertSeverity(Get(config, REPORT_ANALYSIS_SEVERITY));
ReportAnalysisIssuesDetected = IntKey(config, REPORT_ANALYSIS_ISSUES_DETECTED, 0);
ReportAnalysisUploadUuid = Get(config, REPORT_ANALYSIS_UPLOAD_UUID);
ReportAnalysisUploadTime = Get(config, REPORT_ANALYSIS_UPLOAD_TIME);
}
public Dictionary<string, string> ToDictionary(Dictionary<string, string> baseDictionary)
@ -112,6 +127,7 @@ namespace XenAdmin.Model
newConfig[TIME_OF_DAY] = TimeOfDay.ToString();
newConfig[RETRY_INTERVAL] = RetryInterval.ToString();
newConfig[UPLOAD_TOKEN_SECRET] = UploadTokenSecretUuid;
newConfig[DIAGNOSTIC_TOKEN_SECRET] = DiagnosticTokenSecretUuid;
newConfig[NEW_UPLOAD_REQUEST] = NewUploadRequest;
return newConfig;
}
@ -123,7 +139,7 @@ namespace XenAdmin.Model
get
{
return Status == HealthCheckStatus.Enabled
? Messages.HEALTHCHECK_STATUS_NOT_AVAILABLE_YET
? ReportAnalysisStatus
: Messages.HEALTHCHECK_STATUS_NOT_ENROLLED;
}
}
@ -158,6 +174,50 @@ namespace XenAdmin.Model
}
}
public string ReportAnalysisStatus
{
get
{
if (HasAnalysisResult)
{
switch (ReportAnalysisIssuesDetected)
{
case 0:
return Messages.HEALTHCHECK_STATUS_NO_ISSUES_FOUND;
case 1:
return Messages.HEALTHCHECK_STATUS_ONE_ISSUE_FOUND;
default:
return String.Format(Messages.HEALTHCHECK_STATUS_ISSUES_FOUND, ReportAnalysisIssuesDetected);
}
}
return HasUpload ? Messages.HEALTHCHECK_STATUS_NOT_AVAILABLE_YET : Messages.HEALTHCHECK_STATUS_NO_UPLOAD_YET;
}
}
public string GetReportAnalysisLink(string domainName)
{
return String.Format("{0}/{1}/{2}", domainName, REPORT_LINK_PATH, ReportAnalysisUploadUuid);
}
public bool HasUpload
{
get { return !string.IsNullOrEmpty(UploadUuid); }
}
public bool HasAnalysisResult
{
get { return HasUpload && ReportAnalysisUploadUuid == UploadUuid; }
}
public bool HasOldAnalysisResult
{
get
{
return !HasAnalysisResult && !string.IsNullOrEmpty(ReportAnalysisUploadUuid) &&
!string.IsNullOrEmpty(ReportAnalysisUploadTime);
}
}
#region Helper functions
private static T Get<T>(Dictionary<string, T> d, string k) where T : class
{
@ -223,6 +283,9 @@ namespace XenAdmin.Model
case HealthCheckSettings.UPLOAD_TOKEN_SECRET:
UUID = UploadTokenSecretUuid;
break;
case HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET:
UUID = DiagnosticTokenSecretUuid;
break;
default:
log.ErrorFormat("Error getting the {0} from the xapi secret", secretType);
break;
@ -242,21 +305,26 @@ namespace XenAdmin.Model
}
}
public string GetExistingSecretyInfo(IXenConnection connection, string secretType)
public bool TryGetExistingTokens(IXenConnection connection, out string uploadToken, out string diagnosticToken)
{
uploadToken = null;
diagnosticToken = null;
if (connection == null)
return null;
return false;
string token = GetSecretyInfo(connection, secretType);
uploadToken = GetSecretyInfo(connection, UPLOAD_TOKEN_SECRET);
diagnosticToken = GetSecretyInfo(connection, DIAGNOSTIC_TOKEN_SECRET);
if (string.IsNullOrEmpty(token))
token = GetSecretyInfoFromOtherConnections(connection, secretType);
if (!String.IsNullOrEmpty(uploadToken) && !String.IsNullOrEmpty(diagnosticToken))
return true;
return token;
return TryGetExistingTokensFromOtherConnections(connection, out uploadToken, out diagnosticToken);
}
private static string GetSecretyInfoFromOtherConnections(IXenConnection currentConnection, string secretType)
private static bool TryGetExistingTokensFromOtherConnections(IXenConnection currentConnection, out string uploadToken, out string diagnosticToken)
{
uploadToken = null;
diagnosticToken = null;
foreach (var connection in ConnectionsManager.XenConnectionsCopy)
{
if (connection == currentConnection || !connection.IsConnected)
@ -264,12 +332,39 @@ namespace XenAdmin.Model
var poolOfOne = Helpers.GetPoolOfOne(connection);
if (poolOfOne != null)
{
var token = poolOfOne.HealthCheckSettings.GetSecretyInfo(connection, secretType);
if (!string.IsNullOrEmpty(token))
return token;
uploadToken = poolOfOne.HealthCheckSettings.GetSecretyInfo(connection, UPLOAD_TOKEN_SECRET);
diagnosticToken = poolOfOne.HealthCheckSettings.GetSecretyInfo(connection, DIAGNOSTIC_TOKEN_SECRET);
if (!String.IsNullOrEmpty(uploadToken) && !String.IsNullOrEmpty(diagnosticToken))
return true;
}
}
return null;
return false;
}
internal static DiagnosticAlertSeverity StringToDiagnosticAlertSeverity(string severity)
{
switch (severity)
{
case "Eror":
return DiagnosticAlertSeverity.Error;
case "Warning":
return DiagnosticAlertSeverity.Warning;
default:
return DiagnosticAlertSeverity.Info;
}
}
internal static string DiagnosticAlertSeverityToString(DiagnosticAlertSeverity severity)
{
switch (severity)
{
case DiagnosticAlertSeverity.Error:
return "Error";
case DiagnosticAlertSeverity.Warning:
return "Warning";
default:
return "Info";
}
}
}
}

View File

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34209
// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -996,6 +996,33 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to Get Health Check analysis result from Citrix Insight Services.
/// </summary>
public static string ACTION_GET_HEALTH_CHECK_RESULT {
get {
return ResourceManager.GetString("ACTION_GET_HEALTH_CHECK_RESULT", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failed to get the analysis result.
/// </summary>
public static string ACTION_GET_HEALTH_CHECK_RESULT_FAILED {
get {
return ResourceManager.GetString("ACTION_GET_HEALTH_CHECK_RESULT_FAILED", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Getting the analysis result.
/// </summary>
public static string ACTION_GET_HEALTH_CHECK_RESULT_PROGRESS {
get {
return ResourceManager.GetString("ACTION_GET_HEALTH_CHECK_RESULT_PROGRESS", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Action completed. {0} VDIs found..
/// </summary>
@ -16353,7 +16380,7 @@ namespace XenAdmin {
}
/// <summary>
/// Looks up a localized string similar to Issues found.
/// Looks up a localized string similar to {0} issues detected.
/// </summary>
public static string HEALTHCHECK_STATUS_ISSUES_FOUND {
get {
@ -16362,7 +16389,7 @@ namespace XenAdmin {
}
/// <summary>
/// Looks up a localized string similar to No issues found.
/// Looks up a localized string similar to No issues detected.
/// </summary>
public static string HEALTHCHECK_STATUS_NO_ISSUES_FOUND {
get {
@ -16370,6 +16397,15 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to No report uploaded yet.
/// </summary>
public static string HEALTHCHECK_STATUS_NO_UPLOAD_YET {
get {
return ResourceManager.GetString("HEALTHCHECK_STATUS_NO_UPLOAD_YET", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Analysis not yet available.
/// </summary>
@ -16388,6 +16424,15 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to 1 issue detected.
/// </summary>
public static string HEALTHCHECK_STATUS_ONE_ISSUE_FOUND {
get {
return ResourceManager.GetString("HEALTHCHECK_STATUS_ONE_ISSUE_FOUND", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Heartbeating status.
/// </summary>
@ -33744,7 +33789,7 @@ namespace XenAdmin {
}
/// <summary>
/// Looks up a localized string similar to {0:0} GB.
/// Looks up a localized string similar to {0:F1} GB.
/// </summary>
public static string VAL_GB_ONE_DECIMAL {
get {

View File

@ -432,6 +432,15 @@
<data name="ACTION_GET_DISK_SPACE_REQUIREMENTS_TITLE" xml:space="preserve">
<value>Get space requirements</value>
</data>
<data name="ACTION_GET_HEALTH_CHECK_RESULT" xml:space="preserve">
<value>Get Health Check analysis result from Citrix Insight Services</value>
</data>
<data name="ACTION_GET_HEALTH_CHECK_RESULT_FAILED" xml:space="preserve">
<value>Failed to get the analysis result</value>
</data>
<data name="ACTION_GET_HEALTH_CHECK_RESULT_PROGRESS" xml:space="preserve">
<value>Getting the analysis result</value>
</data>
<data name="ACTION_GET_METADATA_VDIS_DONE" xml:space="preserve">
<value>Action completed. {0} VDIs found.</value>
</data>
@ -5720,7 +5729,7 @@ Click Configure HA to alter the settings displayed below.</value>
<value>Upload a Health Check report every {0} weeks on {1} starting at {2}</value>
</data>
<data name="HEALTHCHECK_STATUS_ISSUES_FOUND" xml:space="preserve">
<value>Issues found</value>
<value>{0} issues detected</value>
</data>
<data name="HEALTHCHECK_STATUS_NOT_AVAILABLE_YET" xml:space="preserve">
<value>Analysis not yet available</value>
@ -5729,7 +5738,13 @@ Click Configure HA to alter the settings displayed below.</value>
<value>Health Check not enabled</value>
</data>
<data name="HEALTHCHECK_STATUS_NO_ISSUES_FOUND" xml:space="preserve">
<value>No issues found</value>
<value>No issues detected</value>
</data>
<data name="HEALTHCHECK_STATUS_NO_UPLOAD_YET" xml:space="preserve">
<value>No report uploaded yet</value>
</data>
<data name="HEALTHCHECK_STATUS_ONE_ISSUE_FOUND" xml:space="preserve">
<value>1 issue detected</value>
</data>
<data name="HEALTH_CHECK_AUTHENTICATION_FAILED" xml:space="preserve">
<value>Authentication with Citrix Insight Services failed. See the application log files for more information.</value>

View File

@ -62,6 +62,7 @@
<Compile Include="Actions\HealthCheck\HealthCheckAuthenticationAction.cs" />
<Compile Include="Actions\HealthCheck\SaveHealthCheckSettingsAction.cs" />
<Compile Include="Actions\HealthCheck\TransferHealthCheckSettingAction.cs" />
<Compile Include="Actions\HealthCheck\GetHealthCheckAnalysisResultAction.cs" />
<Compile Include="Actions\HealthCheck\UploadServerStatusReportAction.cs" />
<Compile Include="Actions\HealthCheck\XenServerHealthCheckUpload.cs" />
<Compile Include="Actions\CancellingAction.cs" />