2015-07-02 07:11:54 +02:00
|
|
|
|
/* 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.Threading;
|
|
|
|
|
using XenAdmin.Core;
|
2015-08-21 16:18:18 +02:00
|
|
|
|
using XenAdmin.Model;
|
2015-07-02 07:11:54 +02:00
|
|
|
|
using XenAdmin.Network;
|
|
|
|
|
using XenAPI;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace XenServerHealthCheck
|
|
|
|
|
{
|
|
|
|
|
public class XenServerHealthCheckBundleUpload
|
|
|
|
|
{
|
|
|
|
|
public XenServerHealthCheckBundleUpload(IXenConnection _connection)
|
|
|
|
|
{
|
|
|
|
|
connection = _connection;
|
2015-07-02 08:47:57 +02:00
|
|
|
|
server.HostName = connection.Hostname;
|
|
|
|
|
server.UserName = connection.Username;
|
|
|
|
|
server.Password = connection.Password;
|
2015-07-02 07:11:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IXenConnection connection;
|
|
|
|
|
|
|
|
|
|
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
|
public const int TIMEOUT = 24 * 60 * 60 * 1000;
|
2015-07-02 08:47:57 +02:00
|
|
|
|
public const int INTERVAL = 10 * 1000;
|
2015-07-02 07:11:54 +02:00
|
|
|
|
public const int VERBOSITY_LEVEL = 2;
|
2015-07-02 08:47:57 +02:00
|
|
|
|
private ServerInfo server = new ServerInfo();
|
2015-07-02 07:11:54 +02:00
|
|
|
|
|
2015-07-02 08:47:57 +02:00
|
|
|
|
public void runUpload(System.Threading.CancellationToken serviceStop)
|
2015-07-02 07:11:54 +02:00
|
|
|
|
{
|
|
|
|
|
DateTime startTime = DateTime.UtcNow;
|
|
|
|
|
string uploadToken = "";
|
|
|
|
|
Session session = new Session(connection.Hostname, 80);
|
|
|
|
|
session.APIVersion = API_Version.LATEST;
|
2015-07-02 08:47:57 +02:00
|
|
|
|
|
2015-07-02 07:11:54 +02:00
|
|
|
|
try
|
|
|
|
|
{
|
2015-12-14 14:11:35 +01:00
|
|
|
|
session.login_with_password(connection.Username, connection.Password, Helper.APIVersionString(API_Version.LATEST), Session.UserAgent);
|
2015-07-02 07:11:54 +02:00
|
|
|
|
connection.LoadCache(session);
|
|
|
|
|
var pool = Helpers.GetPoolOfOne(connection);
|
|
|
|
|
if (pool != null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2015-07-29 09:44:41 +02:00
|
|
|
|
string opaqueref = Secret.get_by_uuid(session, pool.HealthCheckSettings.UploadTokenSecretUuid);
|
2015-07-02 07:11:54 +02:00
|
|
|
|
uploadToken = Secret.get_value(session, opaqueref);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
log.Error("Exception getting the upload token from the xapi secret", e);
|
|
|
|
|
uploadToken = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(uploadToken))
|
|
|
|
|
{
|
|
|
|
|
if (session != null)
|
|
|
|
|
session.logout();
|
|
|
|
|
session = null;
|
|
|
|
|
log.ErrorFormat("The upload token is not retrieved for {0}", connection.Hostname);
|
2015-07-29 09:44:41 +02:00
|
|
|
|
updateHealthCheckSettings(false, startTime);
|
2015-07-02 08:47:57 +02:00
|
|
|
|
server.task = null;
|
|
|
|
|
ServerListHelper.instance.UpdateServerInfo(server);
|
2015-07-02 07:11:54 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
if (session != null)
|
|
|
|
|
session.logout();
|
|
|
|
|
session = null;
|
|
|
|
|
log.Error(e, e);
|
2015-07-29 09:44:41 +02:00
|
|
|
|
updateHealthCheckSettings(false, startTime);
|
2015-07-02 08:47:57 +02:00
|
|
|
|
server.task = null;
|
|
|
|
|
ServerListHelper.instance.UpdateServerInfo(server);
|
2015-07-02 07:11:54 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
CancellationTokenSource cts = new CancellationTokenSource();
|
|
|
|
|
Func<string> upload = delegate()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return bundleUpload(connection, session, uploadToken, cts.Token);
|
|
|
|
|
}
|
|
|
|
|
catch (OperationCanceledException)
|
|
|
|
|
{
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
System.Threading.Tasks.Task<string> task = new System.Threading.Tasks.Task<string>(upload);
|
|
|
|
|
task.Start();
|
|
|
|
|
|
2015-07-02 08:47:57 +02:00
|
|
|
|
// Check if the task runs to completion before timeout.
|
|
|
|
|
for (int i = 0; i < TIMEOUT; i += INTERVAL)
|
2015-07-02 07:11:54 +02:00
|
|
|
|
{
|
2015-07-29 09:44:41 +02:00
|
|
|
|
// If the task finishes, set HealthCheckSettings accordingly.
|
2015-07-02 08:47:57 +02:00
|
|
|
|
if (task.IsCompleted || task.IsCanceled || task.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
if (task.Status == System.Threading.Tasks.TaskStatus.RanToCompletion)
|
|
|
|
|
{
|
|
|
|
|
string upload_uuid = task.Result;
|
|
|
|
|
if (!string.IsNullOrEmpty(upload_uuid))
|
2015-07-29 09:44:41 +02:00
|
|
|
|
updateHealthCheckSettings(true, startTime, upload_uuid);
|
2015-07-02 08:47:57 +02:00
|
|
|
|
else
|
2015-07-29 09:44:41 +02:00
|
|
|
|
updateHealthCheckSettings(false, startTime);
|
2015-07-02 08:47:57 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
2015-07-29 09:44:41 +02:00
|
|
|
|
updateHealthCheckSettings(false, startTime);
|
2015-07-02 08:47:57 +02:00
|
|
|
|
|
|
|
|
|
server.task = null;
|
|
|
|
|
ServerListHelper.instance.UpdateServerInfo(server);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the main thread (XenServerHealthCheckService) stops,
|
|
|
|
|
// set the cancel token to notify the working task to return.
|
|
|
|
|
if (serviceStop.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
cts.Cancel();
|
2015-07-29 09:44:41 +02:00
|
|
|
|
updateHealthCheckSettings(false, startTime);
|
2015-07-02 08:47:57 +02:00
|
|
|
|
task.Wait();
|
|
|
|
|
server.task = null;
|
|
|
|
|
ServerListHelper.instance.UpdateServerInfo(server);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
System.Threading.Thread.Sleep(INTERVAL);
|
2015-07-02 07:11:54 +02:00
|
|
|
|
}
|
2015-07-02 08:47:57 +02:00
|
|
|
|
|
|
|
|
|
// The task has run for 24h, cancel the task and mark it as a failure upload.
|
|
|
|
|
cts.Cancel();
|
2015-07-29 09:44:41 +02:00
|
|
|
|
updateHealthCheckSettings(false, startTime);
|
2015-07-02 08:47:57 +02:00
|
|
|
|
task.Wait();
|
|
|
|
|
server.task = null;
|
|
|
|
|
ServerListHelper.instance.UpdateServerInfo(server);
|
|
|
|
|
return;
|
2015-07-02 07:11:54 +02:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
if (session != null)
|
|
|
|
|
session.logout();
|
|
|
|
|
session = null;
|
|
|
|
|
log.Error(e, e);
|
2015-07-02 08:47:57 +02:00
|
|
|
|
server.task = null;
|
|
|
|
|
ServerListHelper.instance.UpdateServerInfo(server);
|
2015-07-02 07:11:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-29 09:44:41 +02:00
|
|
|
|
public void updateHealthCheckSettings(bool success, DateTime time, string uploadUuid = "")
|
2015-07-02 07:11:54 +02:00
|
|
|
|
{
|
|
|
|
|
Session session = new Session(connection.Hostname, 80);
|
2015-12-14 14:11:35 +01:00
|
|
|
|
session.login_with_password(connection.Username, connection.Password, Helper.APIVersionString(API_Version.LATEST), Session.UserAgent);
|
2015-07-02 07:11:54 +02:00
|
|
|
|
connection.LoadCache(session);
|
|
|
|
|
|
|
|
|
|
// Round-trip format time
|
|
|
|
|
DateTime rtime = DateTime.SpecifyKind(time, DateTimeKind.Utc);
|
2015-07-29 09:44:41 +02:00
|
|
|
|
string stime = HealthCheckSettings.DateTimeToString(rtime);
|
2015-07-02 07:11:54 +02:00
|
|
|
|
|
|
|
|
|
// record upload_uuid,
|
|
|
|
|
// release the lock,
|
|
|
|
|
// set the time of LAST_SUCCESSFUL_UPLOAD or LAST_FAILED_UPLOAD
|
|
|
|
|
Dictionary<string, string> config = Pool.get_health_check_config(session, connection.Cache.Pools[0].opaque_ref);
|
2015-07-29 09:44:41 +02:00
|
|
|
|
config[HealthCheckSettings.UPLOAD_LOCK] = "";
|
2015-07-02 07:11:54 +02:00
|
|
|
|
if (success)
|
|
|
|
|
{
|
2015-07-29 09:44:41 +02:00
|
|
|
|
config[HealthCheckSettings.LAST_SUCCESSFUL_UPLOAD] = stime;
|
|
|
|
|
config[HealthCheckSettings.UPLOAD_UUID] = uploadUuid;
|
2015-07-06 18:10:00 +02:00
|
|
|
|
// reset the NEW_UPLOAD_REQUEST field, if the current successful upload was started after the request
|
2015-07-07 16:32:14 +02:00
|
|
|
|
DateTime newUploadRequestTime;
|
2015-07-29 09:44:41 +02:00
|
|
|
|
if (HealthCheckSettings.TryParseStringToDateTime(config[HealthCheckSettings.NEW_UPLOAD_REQUEST], out newUploadRequestTime))
|
2015-07-06 18:10:00 +02:00
|
|
|
|
{
|
|
|
|
|
if (rtime > newUploadRequestTime)
|
2015-07-29 09:44:41 +02:00
|
|
|
|
config[HealthCheckSettings.NEW_UPLOAD_REQUEST] = "";
|
2015-07-06 18:10:00 +02:00
|
|
|
|
}
|
2015-07-02 07:11:54 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
2015-07-29 09:44:41 +02:00
|
|
|
|
config[HealthCheckSettings.LAST_FAILED_UPLOAD] = stime;
|
2015-07-02 07:11:54 +02:00
|
|
|
|
Pool.set_health_check_config(session, connection.Cache.Pools[0].opaque_ref, config);
|
|
|
|
|
|
|
|
|
|
if (session != null)
|
|
|
|
|
session.logout();
|
|
|
|
|
session = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string bundleUpload(IXenConnection connection, Session session, string uploadToken, System.Threading.CancellationToken cancel)
|
|
|
|
|
{
|
|
|
|
|
// Collect the server status report and generate zip file to upload.
|
|
|
|
|
XenServerHealthCheckBugTool bugTool = new XenServerHealthCheckBugTool();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
bugTool.RunBugtool(connection, session);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
if (session != null)
|
|
|
|
|
session.logout();
|
|
|
|
|
session = null;
|
|
|
|
|
log.Error(e, e);
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string bundleToUpload = bugTool.outputFile;
|
|
|
|
|
if(string.IsNullOrEmpty(bundleToUpload) || !File.Exists(bundleToUpload))
|
|
|
|
|
{
|
|
|
|
|
log.ErrorFormat("Server Status Report is NOT collected");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Upload the zip file to CIS uploading server.
|
2015-08-07 06:01:02 +02:00
|
|
|
|
string upload_url = Registry.HealthCheckUploadDomainName;
|
|
|
|
|
log.InfoFormat("Upload report to {0}", upload_url);
|
2015-08-17 05:57:55 +02:00
|
|
|
|
XenServerHealthCheckUpload upload = new XenServerHealthCheckUpload(uploadToken, VERBOSITY_LEVEL, upload_url, connection);
|
2015-07-28 10:39:15 +02:00
|
|
|
|
|
|
|
|
|
string upload_uuid = "";
|
|
|
|
|
try
|
|
|
|
|
{
|
2015-11-03 16:45:59 +01:00
|
|
|
|
upload_uuid = upload.UploadZip(bundleToUpload, null, cancel);
|
2015-07-28 10:39:15 +02:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
if (session != null)
|
|
|
|
|
session.logout();
|
|
|
|
|
session = null;
|
|
|
|
|
log.Error(e, e);
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 07:11:54 +02:00
|
|
|
|
if (File.Exists(bundleToUpload))
|
|
|
|
|
File.Delete(bundleToUpload);
|
|
|
|
|
|
|
|
|
|
// Return the uuid of upload.
|
|
|
|
|
if(string.IsNullOrEmpty(upload_uuid))
|
|
|
|
|
{
|
|
|
|
|
// Fail to upload the zip to CIS server.
|
|
|
|
|
log.ErrorFormat("Fail to upload the Server Status Report {0} to CIS server", bundleToUpload);
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return upload_uuid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|