xenadmin/XenServerHealthCheck/RequestUploadTask.cs
Konstantina Chremmou 99572da0fb Corrections to the logging of Win32 exceptions. Minor refactoring.
Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
2019-11-13 12:31:44 +00:00

238 lines
11 KiB
C#
Executable File

/* 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.Network;
using XenAPI;
using XenAdmin.Model;
namespace XenServerHealthCheck
{
public class RequestUploadTask
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static T Get<T>(Dictionary<string, T> d, string k) where T : class
{
return d != null && d.ContainsKey(k) ? d[k] : null;
}
private static int IntKey(Dictionary<string, string> d, string k, int def)
{
int result;
string s = Get(d, k);
return s != null && int.TryParse(s, out result) ? result : def;
}
private static bool BoolKey(Dictionary<string, string> d, string k)
{
string v = Get(d, k);
return v == null ? false : v == "true";
}
private static double DueAfterHour = 24;
private static bool CanLock(string UploadLock, bool onDemand)
{
if (string.IsNullOrEmpty(UploadLock))
return true;
List<string> currentLock = new List<string>(UploadLock.Split('|'));
DateTime currentTime = DateTime.UtcNow;
DateTime lockTime = DateTime.Parse(currentLock[1]);
if (currentLock[0] == Properties.Settings.Default.UUID && onDemand)
return true;
if (currentLock[0] == Properties.Settings.Default.UUID)
{
if ((DateTime.Compare(lockTime.AddHours(DueAfterHour), currentTime) <= 0))
return true;
}
else if ((DateTime.Compare(lockTime.AddHours(DueAfterHour), currentTime) <= 0))
return true;
return false;
}
private static int SleepForLockConfirm = 10 * 1000; // 10 seconds
private static bool getLock(IXenConnection connection, Session session)
{
Dictionary<string, string> config = Pool.get_health_check_config(session, connection.Cache.Pools[0].opaque_ref);
string newUploadLock = Properties.Settings.Default.UUID;
newUploadLock += "|" + HealthCheckSettings.DateTimeToString(DateTime.UtcNow);
config[HealthCheckSettings.UPLOAD_LOCK] = newUploadLock;
Pool.set_health_check_config(session, connection.Cache.Pools[0].opaque_ref, config);
System.Threading.Thread.Sleep(SleepForLockConfirm);
config = Pool.get_health_check_config(session, connection.Cache.Pools[0].opaque_ref);
return config[HealthCheckSettings.UPLOAD_LOCK] == newUploadLock;
}
public static bool Request(IXenConnection connection, Session session)
{
bool needRetry = false;
Dictionary<string, string> config = Pool.get_health_check_config(session, connection.Cache.Pools[0].opaque_ref);
if (BoolKey(config, HealthCheckSettings.STATUS) == false)
{
ServerListHelper.instance.removeServerCredential(connection.Hostname);
log.InfoFormat("Will not report for XenServer {0} that was not Enroll", connection.Hostname);
return false;
}
//Check if there already some service doing the uploading already
if (CanLock(Get(config, HealthCheckSettings.UPLOAD_LOCK), false) == false)
{
log.InfoFormat("Will not report for XenServer {0} that already locked", connection.Hostname);
return false;
}
//No Lock has been set before, Check upload is due
int intervalInDays = IntKey(config, HealthCheckSettings.INTERVAL_IN_DAYS, HealthCheckSettings.DEFAULT_INTERVAL_IN_DAYS);
DateTime lastSuccessfulUpload = DateTime.UtcNow;
bool haveSuccessfulUpload = false;
if (config.ContainsKey(HealthCheckSettings.LAST_SUCCESSFUL_UPLOAD))
{
try
{
lastSuccessfulUpload = HealthCheckSettings.StringToDateTime(Get(config, HealthCheckSettings.LAST_SUCCESSFUL_UPLOAD));
haveSuccessfulUpload = true;
}
catch (Exception exn)
{
log.Error("Catch exception when Parse LAST_SUCCESSFUL_UPLOAD", exn);
}
}
if (haveSuccessfulUpload)
{//If last successful update not due. return
if (DateTime.Compare(DateTime.UtcNow, lastSuccessfulUpload.AddDays(intervalInDays)) < 0)
{
log.InfoFormat("Will not report for XenServer {0} that was not due {1} days", connection.Hostname, intervalInDays);
return false;
}
}
if (config.ContainsKey(HealthCheckSettings.LAST_FAILED_UPLOAD))
{
try
{
DateTime LastFailedUpload = HealthCheckSettings.StringToDateTime(Get(config, HealthCheckSettings.LAST_FAILED_UPLOAD));
int retryInterval = IntKey(config, HealthCheckSettings.RETRY_INTERVAL, HealthCheckSettings.DEFAULT_RETRY_INTERVAL);
if (DateTime.Compare(LastFailedUpload.AddDays(retryInterval), DateTime.UtcNow) <= 0)
{
if ((!haveSuccessfulUpload) ||
(DateTime.Compare(lastSuccessfulUpload, LastFailedUpload) < 0))
{
log.InfoFormat("Retry since retryInterval{0} - {1} > {2} met", LastFailedUpload, DateTime.UtcNow, retryInterval);
needRetry = true;
}
}
}
catch (Exception exn)
{
log.Error("Catch exception when check if retry was needed", exn);
}
}
DateTime currentTime = DateTime.Now;
if (!needRetry)
{//Check if uploading schedule meet only for new upload
DayOfWeek dayOfWeek;
if (!Enum.TryParse(Get(config, HealthCheckSettings.DAY_OF_WEEK), out dayOfWeek))
{
log.Error("DAY_OF_WEEK not existed");
return false;
}
if (!config.ContainsKey(HealthCheckSettings.TIME_OF_DAY))
{
log.Error("TIME_OF_DAY not existed");
return false;
}
int TimeOfDay = IntKey(config, HealthCheckSettings.TIME_OF_DAY, HealthCheckSettings.GetDefaultTime());
if (currentTime.DayOfWeek != dayOfWeek || currentTime.Hour != TimeOfDay)
{
log.InfoFormat("Will not report for XenServer {0} for incorrect schedule", connection.Hostname);
return false;
}
log.InfoFormat("Upload schedule for {0} is {1}:{2}, meet current time {3}", connection.Hostname, dayOfWeek, TimeOfDay, currentTime.ToString());
}
return getLock(connection, session);
}
public static bool OnDemandRequest(IXenConnection connection, Session session)
{
Dictionary<string, string> config = Pool.get_health_check_config(session, connection.Cache.Pools[0].opaque_ref);
if (BoolKey(config, HealthCheckSettings.STATUS) == false)
{
log.InfoFormat("Will not report on demand for XenServer {0} that was not Enroll", connection.Hostname);
return false;
}
//Check if there already some service doing the uploading already
if (CanLock(Get(config, HealthCheckSettings.UPLOAD_LOCK), true) == false)
{
log.InfoFormat("Will not report for XenServer {0} that already locked", connection.Hostname);
return false;
}
var newUploadRequest = Get(config, HealthCheckSettings.NEW_UPLOAD_REQUEST);
if (!string.IsNullOrEmpty(newUploadRequest))
{
DateTime newUploadRequestTime;
try
{
newUploadRequestTime = HealthCheckSettings.StringToDateTime(newUploadRequest);
}
catch (Exception exn)
{
log.Error("Exception while parsing NEW_UPLOAD_REQUEST", exn);
return false;
}
DateTime newUploadRequestDueTime = newUploadRequestTime.AddMinutes(HealthCheckSettings.UPLOAD_REQUEST_VALIDITY_INTERVAL);
if (DateTime.Compare(newUploadRequestDueTime, DateTime.UtcNow) >= 1)
{
log.InfoFormat("Will report on demand for XenServer {0} since the demand was requested on {1} (UTC time)", connection.Hostname, newUploadRequestTime);
return getLock(connection, session);
}
else
{
log.InfoFormat("Will not report on demand for XenServer {0} since the demand requested on {1} (UTC time) expired after {2} minutes",
connection.Hostname, newUploadRequestTime, HealthCheckSettings.UPLOAD_REQUEST_VALIDITY_INTERVAL);
return false;
}
}
else
return false;
}
}
}