private static LicenseState GetLicenseState(Database db, License license, DateTime? buildDate, DateTime now, Dictionary<int, LicenseState> cache, Dictionary<int, string> errors) { LicenseState licenseState; if (cache.TryGetValue(license.LicenseId, out licenseState)) return licenseState; ParsedLicense parsedLicense = ParsedLicenseManager.GetParsedLicense(license.LicenseKey); if (parsedLicense == null) { errors[license.LicenseId] = string.Format("The license key #{0} is invalid.", license.LicenseId); return null; } if (!parsedLicense.IsLicenseServerElligible()) { errors[license.LicenseId] = string.Format("The license #{0}, of type {1}, cannot be used in the license server.", license.LicenseId, parsedLicense.LicenseType); return null; } if ( !(buildDate == null || parsedLicense.SubscriptionEndDate == null || buildDate <= parsedLicense.SubscriptionEndDate ) ) { errors[license.LicenseId] = string.Format("The maintenance subscription of license #{0} ends on {1:d} but the requested version has been built on {2:d}.", license.LicenseId, parsedLicense.SubscriptionEndDate, buildDate); return null; } licenseState = new LicenseState(now, db, license, parsedLicense); cache.Add(license.LicenseId, licenseState); return licenseState; }
protected override void OnLoad( EventArgs e ) { Database db = new Database(); License[] licenses = (from l in db.Licenses orderby l.Priority, l.LicenseId descending select l).ToArray(); List<LicenseInfo> licenseInfos = new List<LicenseInfo>(); for ( int i = 0; i < licenses.Length; i++ ) { License license = licenses[i]; LicenseInfo licenseInfo = new LicenseInfo {LicenseId = license.LicenseId}; ParsedLicense parsedLicense = ParsedLicenseManager.GetParsedLicense( license.LicenseKey ); if ( parsedLicense == null ) { licenseInfo.LicenseType = "INVALID"; } else { licenseInfo.LicenseType = parsedLicense.LicenseType.ToString(); licenseInfo.MaxUsers = parsedLicense.UserNumber; licenseInfo.CurrentUsers = db.GetActiveLeads( license.LicenseId, VirtualDateTime.UtcNow ); licenseInfo.ProductCode = parsedLicense.Product.ToString(); licenseInfo.GraceStartTime = license.GraceStartTime; licenseInfo.Status = license.Priority >= 0 ? "Active" : "Disabled"; licenseInfo.MaintenanceEndDate = parsedLicense.SubscriptionEndDate; } licenseInfos.Add( licenseInfo ); } this.noLicensePanel.Visible = licenseInfos.Count == 0; this.GridView1.DataSource = licenseInfos; this.GridView1.DataBind(); }
internal static void CheckAssertions(Database db, License license, DateTime now) { #if FALSE db.SubmitChanges(); Dictionary<int, LicenseState> cache = new Dictionary<int, LicenseState>(); List<string> errors = new List<string>(); LicenseState licenseState = GetLicenseState( db, license, now, cache, errors ); if ( licenseState == null ) throw new Exception( string.Join( ". ", errors.ToArray() ) ); if ( licenseState.Maximum.HasValue ) { double max = Math.Ceiling(licenseState.Maximum.Value * (100.0 + Settings.Default.GracePeriodPercent) / 100.0); if (licenseState.Usage > max) throw new Exception( "Maximum exceeded." ); } #endif }
public void ProcessRequest(HttpContext context) { this.context = context; using (Database db = new Database()) { // Parse requested product code. string productCode = context.Request.QueryString["product"]; if (string.IsNullOrEmpty(productCode)) { this.SetError(400, "Missing query string argument: product."); return; } // Parse build date. string buildDateString = context.Request.QueryString["buildDate"]; DateTime? buildDate = null; if (!string.IsNullOrEmpty(buildDateString)) { DateTime buildDateNotNull; if ( !DateTime.TryParse(buildDateString, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out buildDateNotNull)) { this.SetError(400, "Cannot parse the argument: buildDate."); return; } buildDate = buildDateNotNull; } // Parse machine name. string machine = context.Request.QueryString["machine"]; if (string.IsNullOrEmpty(machine)) { this.SetError(400, "Missing query string argument: machine."); return; } machine = machine.ToLowerInvariant(); // Parse user name. string userName = context.Request.QueryString["user"]; if (string.IsNullOrEmpty(userName)) { this.SetError(400, "Missing query string argument: user."); return; } userName = userName.ToLowerInvariant(); bool releaseMutex = false; try { while (true) { try { if (!mutex.WaitOne(TimeSpan.FromSeconds(Settings.Default.MutexTimeout))) { this.SetError(503, "Service overloaded."); return; } else { releaseMutex = true; break; } } catch (AbandonedMutexException) { try { mutex.ReleaseMutex(); } catch { } try { mutex.Close(); } catch { } mutex = CreateMutex(); } } Stopwatch stopwatch = Stopwatch.StartNew(); LicenseLease licenseLease = new LeaseService(true).GetLicenseLease(db, productCode, buildDate, machine, userName, context.User.Identity.Name, VirtualDateTime.UtcNow, errors); if (licenseLease != null) { db.SubmitChanges(); string serializedLease = licenseLease.Serialize(); context.Response.Write(serializedLease); } else { this.SetError(403, "No license with free capacity. " + string.Join(" ", this.errors.Values)); } if (stopwatch.ElapsedMilliseconds > 1000) { context.Trace.Warn(string.Format("Request served in {0}", stopwatch.Elapsed)); } } finally { if (releaseMutex) { try { mutex.ReleaseMutex(); } catch { } } } } }
protected override void OnLoad(EventArgs e) { Database db = new Database(); LicenseId = int.Parse(this.Request.QueryString["id"]); Days = int.Parse( this.Request.QueryString["days"] ?? "30" ); DateTime endDate = VirtualDateTime.UtcNow.Date.AddDays(1); DateTime startDate = endDate.AddDays( -Days ); // Retrieve license information. License license = (from l in db.Licenses where l.LicenseId == LicenseId select l).Single(); ParsedLicense parsedLicense = ParsedLicense.Deserialize(license.LicenseKey); if (parsedLicense != null) { if (parsedLicense.UserNumber.HasValue) { this.Maximum = parsedLicense.UserNumber; this.GraceMaximum = this.Maximum.GetValueOrDefault()*(100 + parsedLicense.GetGracePercentOrDefault())/100; this.AxisMaximum = GraceMaximum.GetValueOrDefault(); } } var q = from l in db.GetLeaseCountingPoints(LicenseId, startDate, endDate) group l by l.Time.Date into d select new { Date = d.Key, Count = d.Max(point => point.LeaseCount), LastCount = d.OrderByDescending(point => point.Time).First().LeaseCount }; // Fill the array with data. this.Keys = new string[Days]; this.Values = new string[Days]; var lastValues = new int?[Days]; foreach ( var point in q ) { int day = (int) Math.Floor( point.Date.Subtract( startDate ).TotalDays ); if ( point.Count > this.AxisMaximum ) { this.AxisMaximum = point.Count; } if ( day < 0 ) { this.Values[0] = point.Count.ToString(); lastValues[0] = point.LastCount; } else if ( day < Days ) { this.Values[day] = point.Count.ToString(); lastValues[day] = point.LastCount; } } // Do extrapolation of missing values. string lastValue = "0"; for ( int i = 0; i < Days; i++ ) { DateTime date = startDate.AddDays( i ); if (date.DayOfWeek == DayOfWeek.Monday) { this.Keys[i] = date.ToString( "MM/dd/yyyy", CultureInfo.InvariantCulture ); } if ( this.Values[i] == null ) { if (i > 0) { this.Values[i] = lastValue; } else { this.Values[0] = lastValue; } } if ( lastValues[i] != null ) { lastValue = lastValues[i].ToString(); } } this.AxisMaximum = (int) Math.Ceiling( Math.Ceiling( this.AxisMaximum*1.2 )/10)*10; }
public LicenseState( DateTime time, Database db, License license, ParsedLicense parsedLicense ) { this.time = time; this.db = db; this.license = license; this.ParsedLicense = parsedLicense; }
public Lease GetLease(Database db, string productCode, DateTime? buildDate, string machine, string userName, string authenticatedUserName, DateTime now, Dictionary<int, string> errors, License[] licenses) { Dictionary<int, LicenseState> licenseStates = new Dictionary<int, LicenseState>(); Settings settings = Settings.Default; // Check if we have a lease that we can use. foreach (License license in licenses) { LicenseState licenseState = GetLicenseState( db, license, buildDate, now, licenseStates, errors ); if ( licenseState == null ) continue; int licenseId = license.LicenseId; Lease[] currentLeases = (from l in db.OpenLeases where l.LicenseId == licenseId && l.StartTime <= now && l.EndTime > now && l.UserName == userName orderby l.StartTime select l).ToArray(); Dictionary<string, string> machines = new Dictionary<string, string>( StringComparer.OrdinalIgnoreCase ); foreach (Lease candidateLease in currentLeases) { machines[candidateLease.Machine] = candidateLease.Machine; if (candidateLease.Machine != machine) continue; if (candidateLease.EndTime > now.AddDays(settings.MinLeaseDays)) { // We have already a good lease. return candidateLease; } else { // Invariant: we can always prolong a lease because licenses are always acquired from // the present moment, therefore taking the current lease into account. // UNLESS it's the end of the license period or the grace period. Lease lease = db.ProlongLease( candidateLease, authenticatedUserName, now ); if ( lease == null ) { continue; } return lease; } } // We did not find a lease for the requested machines. // See if we can do a new lease that would not increment the number of concurrent users. if (machines.Count % Settings.Default.MachinesPerUser != 0) { CheckAssertions( db, license, now ); Lease lease = db.CreateLease(license, userName, machine, authenticatedUserName, now, licenseState.InExcess); if (lease != null) return lease; } } // We don't have a current lease. Create a new one. foreach (License license in licenses) { LicenseState licenseState = GetLicenseState( db, license, buildDate, now, licenseStates, errors ); if (licenseState == null) continue; if (licenseState.Maximum.HasValue && licenseState.Maximum.Value <= licenseState.Usage && ( !licenseState.ParsedLicense.ValidTo.HasValue || now < licenseState.ParsedLicense.ValidTo )) { // Not enough users for this license. continue; } Lease lease = db.CreateLease( license, userName, machine, authenticatedUserName, now, false ); if (lease != null) return lease; } // We did not find a suitable license. See if we can use the grace period. foreach (License license in licenses) { LicenseState licenseState = GetLicenseState(db, license, buildDate, now, licenseStates, errors); if ( licenseState == null ) continue; if (license.GraceStartTime == null) { license.GraceStartTime = now; } int graceLimit = (int)Math.Ceiling(licenseState.Maximum.Value * (100.0 + licenseState.ParsedLicense.GetGracePercentOrDefault()) / 100.0); DateTime graceEnd = license.GraceStartTime.Value.AddDays(licenseState.ParsedLicense.GetGraceDaysOrDefault()); if (license.GraceStartTime <= now && graceEnd > now && licenseState.Usage < graceLimit) { // We will use the grace period. // See if we should send a warning message. if (license.GraceLastWarningTime.GetValueOrDefault(DateTime.MinValue).AddDays(settings.GracePeriodWarningDays) < now) { try { string body = string.Format( "The license #{0} has a capacity of {1} concurrent user(s), but {2} users are currently using the product {3}. " + "The grace period has started on {4} and will end on {5}. After this date, additional leases will be denied." + "Please contact PostSharp Technologies to acquire additional licenses.", license.LicenseId, licenseState.Maximum, licenseState.Usage + 1, licenseState.ParsedLicense.Product, license.GraceStartTime, graceEnd); const string subject = "WARNING: licensing capacity exceeded"; SendEmail(settings.GracePeriodWarningEmailTo, settings.GracePeriodWarningEmailCC, subject, body); license.GraceLastWarningTime = now; } catch (Exception e) { Trace.TraceError(e.ToString()); } } Lease lease = db.CreateLease(license, userName, machine, authenticatedUserName, now, true); if (lease != null) return lease; } } SendEmail(settings.DeniedRequestEmailTo, null, "ERROR: license request denied", string.Format("No license with free capacity was found to satisfy the lease request for the product {0} from " + "the user '{1}' (authentication: '{2}'), machine '{3}'. " + string.Join(". ", errors.ToArray()), productCode, userName, authenticatedUserName, machine)); return null; }
public Lease GetLease( Database db, string productCode, DateTime? buildDate, string machine, string userName, string authenticatedUserName, DateTime now, Dictionary<int,string> errors ) { License[] licenses = (from license in db.Licenses where license.ProductCode == productCode orderby license.Priority, license.LicenseId descending select license).ToArray(); return GetLease( db, productCode, buildDate, machine, userName, authenticatedUserName, now, errors, licenses ); }
public LicenseLease GetLicenseLease(Database db, string productCode, DateTime? buildDate, string machine, string userName, string authenticatedUserName, DateTime now, Dictionary<int, string> errors) { Settings settings = Settings.Default; // Get suitable active licenses. License[] licenses = (from license in db.Licenses where license.ProductCode == productCode && license.Priority >= 0 orderby license.Priority select license).ToArray(); // Check if the machine belongs to build server user. if ( IsBuildServer( machine ) ) { License buildServerLicense = GetBuildServerLicense( licenses ); if ( buildServerLicense != null ) { DateTime endTime = now.AddDays( Settings.Default.NewLeaseDays ); LicenseLease buildServerLicenseLease = new LicenseLease( buildServerLicense.LicenseKey, now, endTime, endTime.AddDays( -settings.MinLeaseDays ) ); // Lease for build server should not be stored - build server users shouldn't steal developer licenses. return buildServerLicenseLease; } // try to acquire lease in normal way } Lease lease = GetLease( db, productCode, buildDate, machine, userName, authenticatedUserName, now, errors, licenses ); if ( lease == null ) return null; LicenseLease licenseLease = new LicenseLease(lease.License.LicenseKey, lease.StartTime, lease.EndTime, lease.EndTime.AddDays(-settings.MinLeaseDays)); return licenseLease; }