/* 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.Timers; using XenAdmin.Actions; using XenAdmin.Alerts; using XenAdmin.Core; using XenAdmin.Network; using XenAPI; using XenAdmin.Dialogs; namespace XenAdmin { /// /// A custom Timer that checks at regular intervals if any server licenses have expired. Also contains logic /// for testing license state on connection as to whether we should warn about a soon to expire license. /// class LicenseTimer : System.Timers.Timer { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static readonly TimeSpan EXPIRED_REMINDER_FREQUENCY = new TimeSpan(0, 0, 30, 0); // How frequently to remind user when a license has expired private static readonly TimeSpan CONNECTION_WARN_THRESHOLD = new TimeSpan(29, 0, 0, 0); // When to start warning on connection private static readonly TimeSpan RUNNING_WARN_FREQUENCY = new TimeSpan(1, 0, 0, 0); // How frequently to remind when XC is running private static DateTime lastPeriodicLicenseWarning; private readonly LicenseManagerLauncher licenseManagerLauncher; public LicenseTimer(LicenseManagerLauncher licenseManagerLauncher) { Elapsed += new ElapsedEventHandler(licenseTimerElapsed); AutoReset = true; Interval = EXPIRED_REMINDER_FREQUENCY.TotalMilliseconds; lastPeriodicLicenseWarning = DateTime.UtcNow; this.licenseManagerLauncher = licenseManagerLauncher; Start(); } /// /// Call this to check the server licenses when a connection has been made. /// If a license has expired, the user is warned. /// internal void CheckActiveServerLicense(IXenConnection connection) { DateTime now = DateTime.UtcNow - connection.ServerTimeOffset; foreach (Host host in connection.Cache.Hosts) { if (host.IsXCP) continue; DateTime expiryDate = host.LicenseExpiryUTC; TimeSpan timeToExpiry = expiryDate.Subtract(now); if (expiryDate < now) { // License has expired already Program.Invoke(Program.MainWindow, delegate { showLicenseSummaryExpired(host, expiryDate); }); return; } else if (timeToExpiry < CONNECTION_WARN_THRESHOLD) { // If the license is sufficiently close to expiry warn now Program.Invoke(Program.MainWindow, delegate { showLicenseSummaryWarning(Helpers.GetName(host), now, expiryDate); }); return; } } } /// /// Check to see if any licenses have expired as the timer periodically elapses. /// private void licenseTimerElapsed(object sender, ElapsedEventArgs e) { if (licenseManagerLauncher.LicenceDialogIsShowing) return; foreach (IXenConnection xc in ConnectionsManager.XenConnectionsCopy) { if (periodicCheck(xc)) return; } } /// /// The logic for the periodic license warning check, only shows the less than 30 day warnings once every day XC is running. /// Invokes dialog shows as is called from background timer threads. /// /// The connection to check licenses on /// private bool periodicCheck(IXenConnection xc) { DateTime now = DateTime.UtcNow - xc.ServerTimeOffset; foreach (Host host in xc.Cache.Hosts) { if (host.IsXCP) continue; DateTime expiryDate = host.LicenseExpiryUTC; TimeSpan timeToExpiry = expiryDate.Subtract(now); if (expiryDate < now) { // License has expired. Pop up the License Manager. Program.Invoke(Program.MainWindow, delegate() { showLicenseSummaryExpired(host, expiryDate); }); return true; } else if (timeToExpiry < CONNECTION_WARN_THRESHOLD && DateTime.UtcNow.Subtract(lastPeriodicLicenseWarning) > RUNNING_WARN_FREQUENCY) { // Check to see if XC has been open one day. If it has, show < 30 day expiry warnings lastPeriodicLicenseWarning = DateTime.UtcNow; Program.Invoke(Program.MainWindow, delegate() { showLicenseSummaryWarning(Helpers.GetName(host), now, expiryDate); }); return true; } } return false; } /// /// Shows the license summary dialog to the user as their license will soon expire. /// private void showLicenseSummaryWarning(String hostname, DateTime now, DateTime expiryDate) { Program.AssertOnEventThread(); log.InfoFormat("Server {0} is within 30 days of expiry ({1}). Show License Summary if needed", hostname, HelpersGUI.DateTimeToString(expiryDate, Messages.DATEFORMAT_DMY_HMS, true)); var alert = new LicenseAlert(hostname, now, expiryDate) { LicenseManagerLauncher = licenseManagerLauncher }; Alert.AddAlert(alert); if (Program.RunInAutomatedTestMode) log.DebugFormat("In automated test mode: quashing license expiry warning '{0}'", alert.Description); else { licenseManagerLauncher.Parent = Program.MainWindow; licenseManagerLauncher.LaunchIfRequired(true, ConnectionsManager.XenConnections); } } /// /// Shows the license summary dialog to the user as their license has expired. /// /// /// Should be expressed in local time. private void showLicenseSummaryExpired(Host host, DateTime expiryDate) { Program.AssertOnEventThread(); log.InfoFormat("Server {0} has expired ({1}). Show License Summary if needed", host.Name, HelpersGUI.DateTimeToString(expiryDate, Messages.DATEFORMAT_DMY_HMS, true)); if (Program.RunInAutomatedTestMode) log.DebugFormat("In automated test mode: quashing license expiry warning"); else licenseManagerLauncher.LaunchIfRequired(true, ConnectionsManager.XenConnections); } } }