├── .gitattributes ├── .gitignore ├── .nuget ├── NuGet.Config └── NuGet.targets ├── .vs └── config │ └── applicationhost.config ├── LICENSE ├── NuGet.Services.Dashboard.Common ├── AlertThresholds.cs ├── App_Readme │ └── Elmah.txt ├── ConfigurationProcessor.cs ├── DatabaseEvent.cs ├── DatabaseIndex.cs ├── DatabaseRequest.cs ├── DatabaseSize.cs ├── ElmahError.cs ├── IISIPDetails.cs ├── IISRequestDetails.cs ├── IISResponseTimeDetails.cs ├── IISUserAgentDetails.cs ├── NuGet.Services.Dashboard.Common.csproj ├── Properties │ └── AssemblyInfo.cs ├── RefreshDB.cs ├── RefreshElmahError.cs ├── SearchResult.cs ├── SecretReaderFactory.cs ├── VsTrending.cs ├── WorkJobInstanceDetails.cs ├── WorkJobInvocation.cs ├── app.config └── packages.config ├── NuGet.Services.Dashboard.Operations.Tools ├── DebugHelper.cs ├── ExceptionUtility.cs ├── NuGet.Services.Dashboard.Operations.Tools.csproj ├── NuGet.Services.Dashboard.Operations.Tools.nuspec ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── SnazzyConsoleTarget.cs ├── app.config └── packages.config ├── NuGet.Services.Dashboard.Operations ├── App.config ├── App_Readme │ └── Elmah.txt ├── Attributes │ ├── CommandAttribute.cs │ └── OptionAttribute.cs ├── Commands │ └── HelpCommand.cs ├── Common │ ├── ArgCheck.cs │ ├── CloudStorageAccountConverter.cs │ ├── CommandHelp.Designer.cs │ ├── CommandHelp.resx │ ├── CommandLineConstants.cs │ ├── CommandLineException.cs │ ├── CommonResources.Designer.cs │ ├── CommonResources.resx │ ├── LocalizedResourceManager.cs │ ├── ReportHelpers.cs │ ├── ResourceHelper.cs │ ├── SqlConnectionStringConverter.cs │ ├── SqlHelper.cs │ ├── StreamConverter.cs │ ├── TaskResources.Designer.cs │ ├── TaskResources.resx │ └── TypeHelper.cs ├── DeploymentEnvironment.cs ├── Infrastructure │ ├── CommandLineParser.cs │ ├── CommandManager.cs │ ├── ICommand.cs │ ├── ICommandManager.cs │ └── Verbosity.cs ├── NuGet.Services.Dashboard.Operations.csproj ├── Properties │ └── AssemblyInfo.cs ├── Scripts │ └── Highcharts-4.0.1 │ │ └── js │ │ ├── adapters │ │ ├── standalone-framework.js │ │ └── standalone-framework.src.js │ │ ├── highcharts-3d.js │ │ ├── highcharts-3d.src.js │ │ ├── highcharts-all.js │ │ ├── highcharts-more.js │ │ ├── highcharts-more.src.js │ │ ├── highcharts.js │ │ ├── highcharts.src.js │ │ ├── modules │ │ ├── canvas-tools.js │ │ ├── canvas-tools.src.js │ │ ├── data.js │ │ ├── data.src.js │ │ ├── drilldown.js │ │ ├── drilldown.src.js │ │ ├── exporting.js │ │ ├── exporting.src.js │ │ ├── funnel.js │ │ ├── funnel.src.js │ │ ├── heatmap.js │ │ ├── heatmap.src.js │ │ ├── no-data-to-display.js │ │ ├── no-data-to-display.src.js │ │ ├── solid-gauge.js │ │ └── solid-gauge.src.js │ │ └── themes │ │ ├── dark-blue.js │ │ ├── dark-green.js │ │ ├── dark-unica.js │ │ ├── gray.js │ │ ├── grid-light.js │ │ ├── grid.js │ │ ├── sand-signika.js │ │ └── skies.js ├── ScriptsAndReferences │ ├── DailyStatusReport.htm │ ├── DashboardAlertMail.htm │ ├── DeployDashboardTasks.ps1 │ ├── LoadTestReport.htm │ └── WeeklyStatusReport.htm ├── Tasks │ ├── DashBoardTasks │ │ ├── AzureManagementTasks │ │ │ ├── CreateCloudServiceDetailsReportTask.cs │ │ │ └── CreateTrafficManagerStatusOverviewReportTask.cs │ │ ├── ConsolidatedSearch │ │ │ └── CreateSearchIndexingStatusReportTask.cs │ │ ├── CreateStatsMonthlyReport.cs │ │ ├── CreateSupportRequestReportTask.cs │ │ ├── CreateWADPerformanceDiagnosticsReportTask.cs │ │ ├── DatabaseTasks │ │ │ ├── CreateDatabaseDetailedReportTask.cs │ │ │ ├── CreateDatabaseMetricsReportTask.cs │ │ │ └── CreateDatabaseSizeReportTask.cs │ │ ├── IssLogCleanUptask.cs │ │ ├── PingdomTasks │ │ │ ├── CreatePingdomDetailedReportTask.cs │ │ │ ├── CreatePingdomServiceDisruptionReportTask.cs │ │ │ └── CreatePingdomWeeklyAndHourlyReportTask.cs │ │ ├── ReportMailTasks │ │ │ ├── SendAlertMailTask.cs │ │ │ ├── SendDailyStatusReportEmailTask.cs │ │ │ ├── SendLoadTestReportEmailTask.cs │ │ │ └── SendWeeklyStatusReportEmailTask.cs │ │ ├── RunBackgroundCheckForMetricsService.cs │ │ ├── SearchServiceTasks │ │ │ ├── CreateSearchCpuMemStatusReportTask.cs │ │ │ └── CreateSearchIndexingStatusReportTask.cs │ │ ├── TrendingTasks │ │ │ ├── CreateStatsHourlyReportTask.cs │ │ │ ├── CreateStatsMonthlyReportTask.cs │ │ │ └── CreateVsTrendingReportTask.cs │ │ ├── UnixTimeStampUtility.cs │ │ ├── V2GalleryFrontendTasks │ │ │ ├── CreateE2ELatencyReportTask.cs │ │ │ ├── CreateElmahErrorDetailedReportTask.cs │ │ │ ├── CreateElmahErrorOverviewReportTask.cs │ │ │ ├── CreateIPDetailsPerDayReportTask.cs │ │ │ └── CreateRequestsPerHourReportTask.cs │ │ ├── V3JobsBackGroundTasks │ │ │ ├── CreateBackupLuceneIndexTask.cs │ │ │ ├── V3CatalogMonitoringTask.cs │ │ │ ├── V3SearchAndRegistrationBlobMonitoringTask.cs │ │ │ └── V3Utility.cs │ │ ├── VerifyPostValidationCursorTask.cs │ │ └── WorkServiceTasks │ │ │ ├── CreateVMWorkJobDetailReportTask.cs │ │ │ ├── CreateWorkJobDetailReportTask.cs │ │ │ ├── CreateWorkJobWeeklyReport.cs │ │ │ ├── RunBackGroundChecksForWorkerJobs.cs │ │ │ └── RunBackgroundCheckForFailoverDC.cs │ ├── DashboardAlertMail.htm │ ├── OpsTask.cs │ └── TaskBases.cs ├── Util.cs ├── content │ ├── Promise.js │ ├── d3.v3.min.js │ ├── further.js │ └── jsonld.js └── packages.config ├── NuGet.Services.Dashboard.sln ├── Nuget.config ├── README.md └── build.ps1 /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.meta 24 | *.obj 25 | *.pch 26 | *.pdb 27 | *.pgc 28 | *.pgd 29 | *.rsp 30 | *.sbr 31 | *.tlb 32 | *.tli 33 | *.tlh 34 | *.tmp 35 | *.log 36 | *.vspscc 37 | *.vssscc 38 | .builds 39 | 40 | # Visual C++ cache files 41 | ipch/ 42 | *.aps 43 | *.ncb 44 | *.opensdf 45 | *.sdf 46 | 47 | # Visual Studio profiler 48 | *.psess 49 | *.vsp 50 | *.vspx 51 | 52 | # Guidance Automation Toolkit 53 | *.gpState 54 | 55 | # ReSharper is a .NET coding add-in 56 | _ReSharper* 57 | 58 | # NCrunch 59 | *.ncrunch* 60 | .*crunch*.local.xml 61 | 62 | # Installshield output folder 63 | [Ee]xpress 64 | 65 | # DocProject is a documentation generator add-in 66 | DocProject/buildhelp/ 67 | DocProject/Help/*.HxT 68 | DocProject/Help/*.HxC 69 | DocProject/Help/*.hhc 70 | DocProject/Help/*.hhk 71 | DocProject/Help/*.hhp 72 | DocProject/Help/Html2 73 | DocProject/Help/html 74 | 75 | # Click-Once directory 76 | publish 77 | 78 | # Publish Web Output 79 | *.Publish.xml 80 | 81 | # NuGet Packages Directory 82 | packages/ 83 | 84 | # Windows Azure Build Output 85 | csx 86 | *.build.csdef 87 | 88 | # Windows Store app package directory 89 | AppPackages/ 90 | 91 | # Others 92 | [Bb]in 93 | [Oo]bj 94 | sql 95 | TestResults 96 | [Tt]est[Rr]esult* 97 | *.Cache 98 | ClientBin 99 | [Ss]tyle[Cc]op.* 100 | ~$* 101 | *.dbmdl 102 | Generated_Code #added for RIA/Silverlight projects 103 | 104 | # Backup & report files from converting an old project file to a newer 105 | # Visual Studio version. Backup files are not needed, because we have git ;-) 106 | _UpgradeReport_Files/ 107 | Backup*/ 108 | UpgradeLog*.XML 109 | *.pubxml 110 | 111 | ########## 112 | # Custom # 113 | ########## 114 | AssemblyInfo.g.cs 115 | tools 116 | build 117 | .nuget/CredentialProviderBundle.zip 118 | .nuget/CredentialProvider.VSS.exe 119 | .nuget/EULA_Microsoft Visual Studio Team Services Credential Provider.docx 120 | .nuget/NuGet.exe 121 | .nuget/ThirdPartyNotices.txt 122 | -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/App_Readme/Elmah.txt: -------------------------------------------------------------------------------- 1 | A new HTTP handler has been configured in your application for consulting the 2 | error log and its feeds. It is reachable at elmah.axd under your application 3 | root. If, for example, your application is deployed at http://www.example.com, 4 | the URL for ELMAH would be http://www.example.com/elmah.axd. You can, of 5 | course, change this path in your application's configuration file. 6 | 7 | ELMAH is also set up to be secure such that it can only be accessed locally. 8 | You can enable remote access but then it is paramount that you secure access 9 | to authorized users or/and roles only. This can be done using standard 10 | authorization rules and configuration already built into ASP.NET. For more 11 | information, see http://code.google.com/p/elmah/wiki/SecuringErrorLogPages on 12 | the project site. 13 | 14 | Please review the commented out authorization section under 15 | and make the appropriate changes. 16 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/ConfigurationProcessor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Collections.Specialized; 7 | using NuGet.Services.KeyVault; 8 | 9 | namespace NuGet.Services.Dashboard.Common 10 | { 11 | public class ConfigurationProcessor 12 | { 13 | private ISecretReaderFactory _secretReaderFactory; 14 | 15 | public ConfigurationProcessor(ISecretReaderFactory secretReaderFactory) 16 | { 17 | _secretReaderFactory = secretReaderFactory; 18 | } 19 | 20 | public void InjectSecretsInto(NameValueCollection collection) 21 | { 22 | var secretReader = _secretReaderFactory.CreateSecretReader(); 23 | var secretInjector = _secretReaderFactory.CreateSecretInjector(secretReader); 24 | 25 | IEnumerable keys = new List(collection.AllKeys); 26 | 27 | foreach (string key in keys) 28 | { 29 | var framedString = collection[key]; 30 | var newValue = secretInjector.InjectAsync(framedString).Result; 31 | collection.Set(key, newValue); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/DatabaseEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { public class DatabaseEvent 9 | { 10 | public DateTime start_time; 11 | public DateTime end_time; 12 | public string event_type; 13 | public int event_count; 14 | public string description; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/DatabaseIndex.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class DatabaseIndex 10 | { 11 | public string ObjectName; 12 | public string IndexName; 13 | public double Fragmentation; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/DatabaseRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class DatabaseRequest 10 | { 11 | public string text; 12 | public DateTime start_time; 13 | public string Status; 14 | public string Command; 15 | public string Wait_Type; 16 | public int wait_time; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/DatabaseSize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class DatabaseSize 10 | { 11 | public string DBName; 12 | public int SizeInMb; 13 | public string Edition; 14 | public Int64 MaxSizeInMb; 15 | public DatabaseSize() 16 | { 17 | 18 | } 19 | 20 | public DatabaseSize(string dbName,int sizeInMb, Int64 maxSize, string edition) 21 | { 22 | this.DBName = dbName; 23 | this.SizeInMb = sizeInMb; 24 | this.MaxSizeInMb = maxSize; 25 | this.Edition = edition; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/ElmahError.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class ElmahError 10 | { 11 | public string Error; 12 | public int Occurecnes; 13 | public DateTime FirstReported; 14 | public DateTime LastReported; 15 | public string Link; 16 | public string Detail; 17 | public int Severity; 18 | 19 | public ElmahError(string error,int occurences,DateTime firstReported,DateTime lastReported, string link, string detail,int severity) 20 | { 21 | this.Error = error; 22 | this.Occurecnes = occurences; 23 | this.FirstReported = firstReported; 24 | this.LastReported = lastReported; 25 | this.Link = link; 26 | this.Detail = detail; 27 | this.Severity = severity; 28 | 29 | } 30 | public ElmahError() 31 | { 32 | 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/IISIPDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class IISIPDetails 10 | { 11 | public string cip; 12 | public int AvgTimeTakenInMilliSeconds; 13 | public int RequestsPerHour; 14 | 15 | public IISIPDetails() 16 | { 17 | 18 | } 19 | public IISIPDetails(string cip, int avgTime, int requestsPerHour) 20 | { 21 | this.cip = cip; 22 | this.AvgTimeTakenInMilliSeconds = avgTime; 23 | this.RequestsPerHour = requestsPerHour; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/IISRequestDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class IISRequestDetails 10 | { 11 | public string ScenarioName; 12 | public string UriStem; 13 | public int AvgTimeTakenInMilliSeconds; 14 | public int RequestsPerHour; 15 | 16 | public IISRequestDetails() 17 | { 18 | 19 | } 20 | public IISRequestDetails(string scenarioName,string uriStem, int avgTime, int requestsPerHour) 21 | { 22 | this.ScenarioName = scenarioName; 23 | this.UriStem = uriStem; 24 | this.AvgTimeTakenInMilliSeconds = avgTime; 25 | this.RequestsPerHour = requestsPerHour; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/IISResponseTimeDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class IISResponseTimeDetails 10 | { 11 | public string UriStem; 12 | public int AvgTimeTakenInMilliSeconds; 13 | 14 | public IISResponseTimeDetails() 15 | { 16 | 17 | } 18 | public IISResponseTimeDetails(string uriStem, int avgTime) 19 | { 20 | this.UriStem = uriStem; 21 | this.AvgTimeTakenInMilliSeconds = avgTime; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/IISUserAgentDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class IISUserAgentDetails 10 | { 11 | public string UserAgentName; 12 | public string UserAgent; 13 | public int AvgTimeTakenInMilliSeconds; 14 | public int RequestsPerHour; 15 | 16 | public IISUserAgentDetails() 17 | { 18 | 19 | } 20 | public IISUserAgentDetails(string userAgentName, string userAgent, int avgTime, int requestsPerHour) 21 | { 22 | this.UserAgentName = userAgentName; 23 | this.UserAgent = userAgent; 24 | this.AvgTimeTakenInMilliSeconds = avgTime; 25 | this.RequestsPerHour = requestsPerHour; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("NuGet.Services.Dashboard.Common")] 5 | [assembly: AssemblyDescription("")] 6 | 7 | // The following GUID is for the ID of the typelib if this project is exposed to COM 8 | [assembly: Guid("aeae461d-c225-4567-99f3-9e62e898d8ab")] 9 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/RefreshDB.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.WindowsAzure.Storage; 7 | using Microsoft.WindowsAzure.Storage.Blob; 8 | using System.Data.SqlClient; 9 | using AnglicanGeek.DbExecutor; 10 | 11 | 12 | namespace NuGet.Services.Dashboard.Common 13 | { 14 | public class RefreshDB 15 | { 16 | private string ConnectionString { get; set; } 17 | 18 | private int LastNHours { get; set; } 19 | 20 | public RefreshDB(string ConnectionString, int LastNHours) 21 | { 22 | this.ConnectionString = ConnectionString; 23 | this.LastNHours = LastNHours; 24 | } 25 | 26 | public List RefreshDatabaseEvent() 27 | { 28 | var masterConnectionString = new SqlConnectionStringBuilder(ConnectionString) { InitialCatalog = "master" }.ToString(); 29 | var currentDbName = new SqlConnectionStringBuilder(ConnectionString).InitialCatalog; 30 | using (var sqlConnection = new SqlConnection(masterConnectionString)) 31 | { 32 | using (var dbExecutor = new SqlExecutor(sqlConnection)) 33 | { 34 | sqlConnection.Open(); 35 | 36 | var usageSeconds = dbExecutor.Query(string.Format("select start_time, end_time,event_type,event_count,description from sys.event_log where start_time>='{0}' and start_time<='{1}' and database_name = '{2}' and severity = 2", DateTime.UtcNow.AddHours(-LastNHours).ToString("yyyy-MM-dd hh:mm:ss"), DateTime.UtcNow.ToString("yyyy-MM-dd hh:mm:ss"), currentDbName)); 37 | return usageSeconds.ToList(); 38 | } 39 | 40 | } 41 | } 42 | 43 | public List RefreshDatebaseRequest() 44 | { 45 | List> connectionCountDataPoints = new List>(); 46 | using (var sqlConnection = new SqlConnection(ConnectionString)) 47 | { 48 | using (var dbExecutor = new SqlExecutor(sqlConnection)) 49 | { 50 | sqlConnection.Open(); 51 | var requests = dbExecutor.Query("SELECT t.text, r.start_time, r.status, r.command, r.wait_type, r.wait_time FROM sys.dm_exec_requests r OUTER APPLY sys.dm_exec_sql_text(sql_handle) t​"); 52 | return requests.ToList(); 53 | } 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/RefreshElmahError.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Data; 4 | using System.Data.SqlClient; 5 | using System.IO; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Microsoft.WindowsAzure.Storage; 9 | using Microsoft.WindowsAzure.Storage.Blob; 10 | using Newtonsoft.Json.Linq; 11 | using AnglicanGeek.DbExecutor; 12 | using System; 13 | using System.Net; 14 | using System.Web.Script.Serialization; 15 | using NuGetGallery; 16 | using NuGetGallery.Infrastructure; 17 | using Elmah; 18 | using NuGet.Services.Dashboard.Common; 19 | using System.Net.Mail; 20 | using System.Configuration; 21 | using System.Net.Mime; 22 | 23 | namespace NuGet.Services.Dashboard.Common 24 | { 25 | 26 | public class RefreshElmahError 27 | { 28 | private string ElmahAccountCredentials { get; set; } 29 | private int LastNHours { get; set; } 30 | private CloudStorageAccount StorageAccount { get; set; } 31 | private string ContainerName { get; set; } 32 | private string ConnectionString { get; set; } 33 | 34 | public RefreshElmahError(string ConnectionString, string ContainerName, int LastNHours, string ElmahAccountCredentials) 35 | { 36 | this.ConnectionString = ConnectionString; 37 | this.ContainerName = ContainerName; 38 | this.LastNHours = LastNHours; 39 | this.ElmahAccountCredentials = ElmahAccountCredentials; 40 | } 41 | 42 | public RefreshElmahError(CloudStorageAccount StorageAccount, string ContainerName, int LastNHours, string ElmahAccountCredentials) 43 | { 44 | this.StorageAccount = StorageAccount; 45 | this.ContainerName = ContainerName; 46 | this.LastNHours = LastNHours; 47 | this.ElmahAccountCredentials = ElmahAccountCredentials; 48 | } 49 | 50 | 51 | 52 | 53 | public List ExecuteRefresh() 54 | { 55 | return GetElmahError(DateTime.Now.Subtract(new TimeSpan(LastNHours, 0, 0)), DateTime.Now); 56 | } 57 | 58 | public List GetElmahError(DateTime start, DateTime end) 59 | { 60 | if (StorageAccount == null) StorageAccount = CloudStorageAccount.Parse(ConnectionString); 61 | List nonCriticalErrorDictionary = new JavaScriptSerializer().Deserialize>(Load(StorageAccount, "Configuration.ElmahNonCriticalErrors.json", ContainerName)); 62 | TableErrorLog log = new TableErrorLog(string.Format(ElmahAccountCredentials)); 63 | List entities = new List(); 64 | 65 | int lasthours = DateTime.Now.Subtract(start).Hours + 1; 66 | 67 | log.GetErrors(0, 500 * lasthours, entities); //retrieve n * LastNHours errors assuming a max of 500 errors per hour. 68 | List listOfErrors = new List(); 69 | 70 | //Get the error from Last N hours. 71 | if (entities.Any(entity => entity.Error.Time.ToUniversalTime() > start.ToUniversalTime() && entity.Error.Time.ToUniversalTime() < end.ToUniversalTime())) 72 | { 73 | entities = entities.Where(entity => entity.Error.Time.ToUniversalTime() > start.ToUniversalTime() && entity.Error.Time.ToUniversalTime() < end.ToUniversalTime()).ToList(); 74 | var elmahGroups = entities.GroupBy(item => item.Error.Message); 75 | 76 | //Group the error based on exception and send alerts if critical errors exceed the thresold values. 77 | foreach (IGrouping errorGroups in elmahGroups) 78 | { 79 | Console.WriteLine(errorGroups.Key.ToString() + " " + errorGroups.Count()); 80 | int severity = 0; 81 | if (nonCriticalErrorDictionary.Any(item => errorGroups.Key.ToString().Contains(item))) 82 | { 83 | severity = 1; //sev 1 is low pri and sev 0 is high pri. 84 | } 85 | string link = "https://www.nuget.org/Admin/Errors.axd/detail?id={0}"; 86 | if (ContainerName.Contains("qa")) 87 | { 88 | link = "https://int.nugettest.org/Admin/Errors.axd/detail?id={0}"; 89 | } 90 | //for severity, assume all refresh error, severity = 0 91 | listOfErrors.Add(new ElmahError(errorGroups.Key.ToString(), errorGroups.Count(), errorGroups.Min(item => item.Error.Time.ToLocalTime()), errorGroups.Max(item => item.Error.Time.ToLocalTime()), string.Format(link, errorGroups.First().Id), errorGroups.First().Error.Detail, severity)); 92 | 93 | } 94 | } 95 | 96 | return listOfErrors; 97 | } 98 | 99 | private string Load(CloudStorageAccount storageAccount, string name, string containerName = "dashboard") 100 | { 101 | CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); 102 | CloudBlobContainer container = blobClient.GetContainerReference(containerName); 103 | CloudBlockBlob blob = container.GetBlockBlobReference(name); 104 | string content = string.Empty; 105 | if (blob != null) 106 | { 107 | using (var memoryStream = new MemoryStream()) 108 | { 109 | blob.DownloadToStream(memoryStream); 110 | content = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray()); 111 | } 112 | } 113 | 114 | return content; 115 | } 116 | 117 | 118 | 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/SearchResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace NuGet.Services.Dashboard.Common 9 | { 10 | public class SearchDocument 11 | { 12 | public string Version; 13 | public PackageRegistration PackageRegistration; 14 | public SearchDocument() 15 | { 16 | 17 | } 18 | 19 | public SearchDocument(PackageRegistration _registration, string _version) 20 | { 21 | this.PackageRegistration = _registration; 22 | this.Version = _version; 23 | } 24 | } 25 | 26 | public class PackageRegistration 27 | { 28 | public string Id; 29 | public PackageRegistration() 30 | { 31 | 32 | } 33 | 34 | public PackageRegistration(string Id) 35 | { 36 | this.Id = Id; 37 | } 38 | } 39 | 40 | public class SearchResult:IEnumerator,IEnumerable 41 | { 42 | public List data = new List(); 43 | int position = -1; 44 | public SearchResult() 45 | { 46 | 47 | } 48 | 49 | public IEnumerator GetEnumerator() 50 | { 51 | return (IEnumerator)this; 52 | } 53 | 54 | //IEnumerator 55 | public bool MoveNext() 56 | { 57 | if (position < data.Count) 58 | { 59 | position++; 60 | return true; 61 | } 62 | else 63 | { 64 | return false; 65 | } 66 | } 67 | 68 | //IEnumerable 69 | public void Reset() 70 | { position = -1; } 71 | 72 | //IEnumerable 73 | public object Current 74 | { 75 | get { return data[position]; } 76 | } 77 | 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/SecretReaderFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System; 5 | using System.Collections.Specialized; 6 | using System.Security.Cryptography.X509Certificates; 7 | using NuGet.Services.KeyVault; 8 | 9 | namespace NuGet.Services.Dashboard.Common 10 | { 11 | public class SecretReaderFactory : ISecretReaderFactory 12 | { 13 | private string _vaultName; 14 | private string _clientId; 15 | private string _certificateThumbprint; 16 | private string _storeName; 17 | private string _storeLocation; 18 | private bool _validateCertificate; 19 | 20 | public SecretReaderFactory(NameValueCollection config) 21 | { 22 | _vaultName = config["keyVault-VaultName"]; 23 | _clientId = config["keyVault-ClientId"]; 24 | _certificateThumbprint = config["keyVault-CertificateThumbprint"]; 25 | _storeName = config["keyVault-StoreName"]; 26 | _storeLocation = config["keyVault-StoreLocation"]; 27 | _validateCertificate = bool.Parse(config["keyVault-ValidateCertificate"]); 28 | } 29 | 30 | public ISecretReader CreateSecretReader() 31 | { 32 | if (string.IsNullOrEmpty(_vaultName)) 33 | { 34 | return new EmptySecretReader(); 35 | } 36 | 37 | var keyVaultConfiguration = new KeyVaultConfiguration( 38 | _vaultName, 39 | _clientId, 40 | _certificateThumbprint, 41 | !string.IsNullOrEmpty(_storeName) ? (StoreName)Enum.Parse(typeof(StoreName), _storeName) : StoreName.My, 42 | !string.IsNullOrEmpty(_storeLocation) ? (StoreLocation)Enum.Parse(typeof(StoreLocation), _storeLocation) : StoreLocation.LocalMachine, 43 | _validateCertificate); 44 | 45 | return new KeyVaultReader(keyVaultConfiguration); 46 | } 47 | 48 | public ISecretInjector CreateSecretInjector(ISecretReader secretReader) 49 | { 50 | return new SecretInjector(secretReader); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/VsTrending.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class OperationRequest 10 | { 11 | public string Operation; 12 | public int download; 13 | } 14 | 15 | public class agentRequest 16 | { 17 | public string key; 18 | public int value; 19 | 20 | public agentRequest(string Version, int download) 21 | { 22 | this.key = Version; 23 | this.value = download; 24 | } 25 | } 26 | 27 | public class VsRequest 28 | { 29 | public string key; 30 | public string value; 31 | 32 | public VsRequest(string VsVersion, string download) 33 | { 34 | this.key = VsVersion; 35 | this.value = download; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/WorkJobInstanceDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class WorkJobInstanceDetails 10 | { 11 | 12 | public string JobInstanceName; 13 | public int FrequencyInMinutes; 14 | public string url; 15 | 16 | public WorkJobInstanceDetails(string jobInstanceName,int repeatFrequency,string url) 17 | { 18 | this.JobInstanceName = jobInstanceName; 19 | this.FrequencyInMinutes = repeatFrequency; 20 | this.url = url; 21 | } 22 | public WorkJobInstanceDetails() 23 | { 24 | 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/WorkJobInvocation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGet.Services.Dashboard.Common 8 | { 9 | public class WorkJobInvocation 10 | { 11 | public Guid id; 12 | public string job; 13 | public string jobInstanceName; 14 | public string source; 15 | public string status; 16 | public string result; 17 | public string resultMessage; 18 | public string lastUpdatedBy; 19 | public string logUrl; 20 | public int dequeueCount; 21 | public bool isContinuation; 22 | public DateTime lastDequeuedAt; 23 | public DateTime completedAt; 24 | public DateTime queuedAt; 25 | public DateTime nextVisibleAt; 26 | public DateTime updatedAt; 27 | } 28 | public class WorkInstanceDetail 29 | { 30 | public string jobName; 31 | public string Frequency; 32 | public string LastTime; 33 | public string RunTime; 34 | public string InvocationNo; 35 | public string FaultedNo; 36 | public int FaultRate; 37 | public Dictionary> ErrorMessage; 38 | 39 | public WorkInstanceDetail(string jobName, string Frequency, string LastTime, string RunTime, string InvocationNo, string FaultedNo, int FaultRate,Dictionary> ErrorMessage) 40 | { 41 | this.jobName = jobName; 42 | this.Frequency = Frequency; 43 | this.LastTime = LastTime; 44 | this.RunTime = RunTime; 45 | this.InvocationNo = InvocationNo; 46 | this.FaultedNo = FaultedNo; 47 | this.FaultRate = FaultRate; 48 | this.ErrorMessage = ErrorMessage; 49 | } 50 | 51 | public WorkInstanceDetail() 52 | { 53 | 54 | } 55 | } 56 | 57 | public class WorkServiceAdmin 58 | { 59 | public string username; 60 | public string key; 61 | 62 | public WorkServiceAdmin(string username, string key) 63 | { 64 | this.username = username; 65 | this.key = key; 66 | } 67 | 68 | public WorkServiceAdmin() 69 | { 70 | 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Common/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations.Tools/DebugHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using System.Threading; 5 | 6 | namespace NuGetGallery.Operations.Tools 7 | { 8 | public static class DebugHelper 9 | { 10 | [Conditional("DEBUG")] 11 | public static void WaitForDebugger(ref string[] args) 12 | { 13 | if (args.Length >= 1 && 14 | (String.Equals("dbg", args[0], StringComparison.OrdinalIgnoreCase) || 15 | String.Equals("debug", args[0], StringComparison.OrdinalIgnoreCase))) 16 | { 17 | args = args.Skip(1).ToArray(); 18 | Console.WriteLine("Waiting for Debugger..."); 19 | SpinWait.SpinUntil(() => Debugger.IsAttached); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations.Tools/ExceptionUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace NuGet 5 | { 6 | public static class ExceptionUtility 7 | { 8 | public static Exception Unwrap(Exception exception) 9 | { 10 | if (exception == null) 11 | { 12 | throw new ArgumentNullException("exception"); 13 | } 14 | 15 | if (exception.InnerException == null) 16 | { 17 | return exception; 18 | } 19 | 20 | // Always return the inner exception from a target invocation exception 21 | if (exception is AggregateException || 22 | exception is TargetInvocationException) 23 | { 24 | return exception.GetBaseException(); 25 | } 26 | 27 | return exception; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations.Tools/NuGet.Services.Dashboard.Operations.Tools.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | galops 5 | $version$ 6 | .NET Foundation 7 | .NET Foundation 8 | galops 9 | Copyright .NET Foundation 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations.Tools/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System; 5 | using System.Linq; 6 | using System.Collections.Generic; 7 | using System.ComponentModel.Composition; 8 | using System.ComponentModel.Composition.Hosting; 9 | using System.Configuration; 10 | using NuBot.Infrastructure; 11 | using NuGet; 12 | using NuGet.Services.Dashboard.Common; 13 | using NLog.Config; 14 | using NLog; 15 | using System.Net; 16 | 17 | namespace NuGetGallery.Operations.Tools 18 | { 19 | [Export] 20 | class Program 21 | { 22 | private Logger _logger = LogManager.GetLogger("Program"); 23 | 24 | public HelpCommand HelpCommand { get; set; } 25 | 26 | [ImportMany] 27 | public IEnumerable Commands { get; set; } 28 | 29 | [Import] 30 | public ICommandManager Manager { get; set; } 31 | 32 | static int Main(string[] args) 33 | { 34 | DebugHelper.WaitForDebugger(ref args); 35 | 36 | // Configure Logging 37 | ConfigureLogs(); 38 | 39 | // Compose 40 | var catalog = new AggregateCatalog( 41 | new AssemblyCatalog(typeof(Program).Assembly), 42 | new AssemblyCatalog(typeof(HelpCommand).Assembly)); 43 | var container = new CompositionContainer(catalog); 44 | var p = container.GetExportedValue(); 45 | 46 | // Execute 47 | return p.Invoke(args); 48 | } 49 | 50 | public int Invoke(string[] args) 51 | { 52 | try 53 | { 54 | HelpCommand = new HelpCommand(Manager, "galops", "NuGet Gallery Operations", "https://github.com/NuGet/NuGetOperations/wiki/GalOps---Gallery-Operations-Commands"); 55 | 56 | // Add commands 57 | foreach (ICommand cmd in Commands) 58 | { 59 | Manager.RegisterCommand(cmd); 60 | } 61 | 62 | var secretReaderFactory = new SecretReaderFactory(ConfigurationManager.AppSettings); 63 | 64 | var configurationProcessor = new ConfigurationProcessor(secretReaderFactory); 65 | configurationProcessor.InjectSecretsInto(ConfigurationManager.AppSettings); 66 | 67 | // Parse the command 68 | var parser = new CommandLineParser(Manager, secretReaderFactory); 69 | ICommand command = parser.ParseCommandLine(args) ?? HelpCommand; 70 | 71 | // Fall back on help command if we failed to parse a valid command 72 | if (!ArgumentCountValid(command)) 73 | { 74 | string commandName = command.CommandAttribute.CommandName; 75 | Console.WriteLine("{0}: invalid arguments..", commandName); 76 | HelpCommand.ViewHelpForCommand(commandName); 77 | } 78 | else 79 | { 80 | // Ensure that SSLv3 is disabled and that Tls v1.2 is enabled. 81 | ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3; 82 | ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; 83 | 84 | command.Execute(); 85 | } 86 | } 87 | catch (AggregateException exception) 88 | { 89 | string message; 90 | Exception unwrappedEx = ExceptionUtility.Unwrap(exception); 91 | if (unwrappedEx == exception) 92 | { 93 | // If the AggregateException contains more than one InnerException, it cannot be unwrapped. In which case, simply print out individual error messages 94 | message = String.Join(Environment.NewLine, exception.InnerExceptions.Select(ex => ex.Message).Distinct(StringComparer.CurrentCulture)); 95 | } 96 | else 97 | { 98 | message = ExceptionUtility.Unwrap(exception).Message; 99 | } 100 | _logger.Error("{0}: {1}", unwrappedEx.GetType().Name, message); 101 | _logger.Error(" Stack Trace: " + unwrappedEx.StackTrace); 102 | return 1; 103 | } 104 | catch (Exception e) 105 | { 106 | var ex = ExceptionUtility.Unwrap(e); 107 | _logger.Error("{0}: {1}", ex.GetType().Name, ex.Message); 108 | _logger.Error(" Stack Trace: " + ex.StackTrace); 109 | return 1; 110 | } 111 | return 0; 112 | } 113 | 114 | private static void ConfigureLogs() 115 | { 116 | // Just a simple logging mechanism 117 | var consoleTarget = new SnazzyConsoleTarget() 118 | { 119 | Layout = "${message}" 120 | }; 121 | 122 | var config = new LoggingConfiguration(); 123 | config.AddTarget("console", consoleTarget); 124 | config.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, consoleTarget)); 125 | 126 | LogManager.Configuration = config; 127 | } 128 | 129 | public static bool ArgumentCountValid(ICommand command) 130 | { 131 | CommandAttribute attribute = command.CommandAttribute; 132 | return command.Arguments.Count >= attribute.MinArgs && 133 | command.Arguments.Count <= attribute.MaxArgs; 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations.Tools/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("galops")] 5 | [assembly: AssemblyDescription("Command-line runner for NuGet Gallery Operations commands")] 6 | 7 | // The following GUID is for the ID of the typelib if this project is exposed to COM 8 | [assembly: Guid("ce2f7d7f-caae-4399-b5f9-d32e0a0c525f")] 9 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations.Tools/SnazzyConsoleTarget.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using NLog; 5 | using NLog.Targets; 6 | using ColorPair = System.Tuple; 7 | 8 | namespace NuBot.Infrastructure 9 | { 10 | public class SnazzyConsoleTarget : TargetWithLayout 11 | { 12 | private static readonly Dictionary ColorTable = new Dictionary() 13 | { 14 | { LogLevel.Debug, new ColorPair(ConsoleColor.Magenta, null) }, 15 | { LogLevel.Error, new ColorPair(ConsoleColor.Red, null) }, 16 | { LogLevel.Fatal, new ColorPair(ConsoleColor.White, ConsoleColor.Red) }, 17 | { LogLevel.Info, new ColorPair(ConsoleColor.Green, null) }, 18 | { LogLevel.Trace, new ColorPair(ConsoleColor.DarkGray, null) }, 19 | { LogLevel.Warn, new ColorPair(ConsoleColor.Black, ConsoleColor.Yellow) } 20 | }; 21 | 22 | private static readonly Dictionary LevelNames = new Dictionary() { 23 | { LogLevel.Debug, "debug" }, 24 | { LogLevel.Error, "error" }, 25 | { LogLevel.Fatal, "fatal" }, 26 | { LogLevel.Info, "info" }, 27 | { LogLevel.Trace, "trace" }, 28 | { LogLevel.Warn, "warn" }, 29 | }; 30 | 31 | private static readonly int LevelLength = LevelNames.Values.Max(s => s.Length); 32 | 33 | protected override void Write(LogEventInfo logEvent) 34 | { 35 | var oldForeground = Console.ForegroundColor; 36 | var oldBackground = Console.BackgroundColor; 37 | 38 | // Get us to the start of a line 39 | if (Console.CursorLeft > 0) 40 | { 41 | Console.WriteLine(); 42 | } 43 | 44 | // Get Color Pair colors 45 | ColorPair pair; 46 | if (!ColorTable.TryGetValue(logEvent.Level, out pair)) 47 | { 48 | pair = new ColorPair(Console.ForegroundColor, Console.BackgroundColor); 49 | } 50 | 51 | // Get level string 52 | string levelName; 53 | if (!LevelNames.TryGetValue(logEvent.Level, out levelName)) 54 | { 55 | levelName = logEvent.Level.ToString(); 56 | } 57 | levelName = levelName.PadRight(LevelLength).Substring(0, LevelLength); 58 | 59 | // Break the message in to lines as necessary 60 | var message = Layout.Render(logEvent); 61 | var existingLines = message.Split(new string[] {Environment.NewLine}, StringSplitOptions.None); 62 | var lines = new List(); 63 | foreach (var existingLine in existingLines) 64 | { 65 | var prefix = levelName + ": "; 66 | var fullMessage = prefix + existingLine; 67 | var maxWidth = Console.BufferWidth - 2; 68 | var currentLine = existingLine; 69 | while (fullMessage.Length > maxWidth) 70 | { 71 | int end = maxWidth - prefix.Length; 72 | int spaceIndex = currentLine.LastIndexOf(' ', Math.Min(end, message.Length - 1)); 73 | if (spaceIndex < 10) 74 | { 75 | spaceIndex = end; 76 | } 77 | lines.Add(currentLine.Substring(0, spaceIndex).Trim()); 78 | currentLine = currentLine.Substring(spaceIndex).Trim(); 79 | fullMessage = prefix + currentLine; 80 | } 81 | lines.Add(currentLine); 82 | } 83 | 84 | // Write lines 85 | bool first = true; 86 | foreach (var line in lines.Where(l => !String.IsNullOrWhiteSpace(l))) 87 | { 88 | if (first) 89 | { 90 | first = false; 91 | } 92 | else 93 | { 94 | Console.WriteLine(); 95 | } 96 | 97 | // Write Level 98 | Console.ForegroundColor = pair.Item1; 99 | if (pair.Item2.HasValue) 100 | { 101 | Console.BackgroundColor = pair.Item2.Value; 102 | } 103 | Console.Write(levelName); 104 | 105 | // Write the message using the default foreground color, but the specified background color 106 | // UNLESS: The background color has been changed. In which case the foreground color applies here too 107 | var foreground = pair.Item2.HasValue 108 | ? pair.Item1 109 | : oldForeground; 110 | Console.ForegroundColor = foreground; 111 | Console.Write(": " + line); 112 | } 113 | Console.WriteLine(); 114 | 115 | Console.ForegroundColor = oldForeground; 116 | Console.BackgroundColor = oldBackground; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations.Tools/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations.Tools/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/App_Readme/Elmah.txt: -------------------------------------------------------------------------------- 1 | A new HTTP handler has been configured in your application for consulting the 2 | error log and its feeds. It is reachable at elmah.axd under your application 3 | root. If, for example, your application is deployed at http://www.example.com, 4 | the URL for ELMAH would be http://www.example.com/elmah.axd. You can, of 5 | course, change this path in your application's configuration file. 6 | 7 | ELMAH is also set up to be secure such that it can only be accessed locally. 8 | You can enable remote access but then it is paramount that you secure access 9 | to authorized users or/and roles only. This can be done using standard 10 | authorization rules and configuration already built into ASP.NET. For more 11 | information, see http://code.google.com/p/elmah/wiki/SecuringErrorLogPages on 12 | the project site. 13 | 14 | Please review the commented out authorization section under 15 | and make the appropriate changes. 16 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Attributes/CommandAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NuGetGallery.Operations 4 | { 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] 6 | public sealed class CommandAttribute : Attribute 7 | { 8 | private string _description; 9 | private string _usageSummary; 10 | private string _usageDescription; 11 | private string _example; 12 | 13 | public string CommandName { get; private set; } 14 | public Type ResourceType { get; private set; } 15 | public string DescriptionResourceName { get; private set; } 16 | 17 | 18 | public string AltName { get; set; } 19 | public int MinArgs { get; set; } 20 | public int MaxArgs { get; set; } 21 | public string UsageSummaryResourceName { get; set; } 22 | public string UsageDescriptionResourceName { get; set; } 23 | public string UsageExampleResourceName { get; set; } 24 | public bool IsSpecialPurpose { get; set; } 25 | 26 | public string Description 27 | { 28 | get 29 | { 30 | if (ResourceType != null && !String.IsNullOrEmpty(DescriptionResourceName)) 31 | { 32 | return ResourceHelper.GetLocalizedString(ResourceType, DescriptionResourceName); 33 | } 34 | return _description; 35 | } 36 | private set 37 | { 38 | _description = value; 39 | } 40 | } 41 | 42 | public string UsageSummary 43 | { 44 | get 45 | { 46 | if (ResourceType != null && !String.IsNullOrEmpty(UsageSummaryResourceName)) 47 | { 48 | return ResourceHelper.GetLocalizedString(ResourceType, UsageSummaryResourceName); 49 | } 50 | return _usageSummary; 51 | } 52 | set 53 | { 54 | _usageSummary = value; 55 | } 56 | } 57 | 58 | public string UsageDescription 59 | { 60 | get 61 | { 62 | if (ResourceType != null && !String.IsNullOrEmpty(UsageDescriptionResourceName)) 63 | { 64 | return ResourceHelper.GetLocalizedString(ResourceType, UsageDescriptionResourceName); 65 | } 66 | return _usageDescription; 67 | } 68 | set 69 | { 70 | _usageDescription = value; 71 | } 72 | } 73 | 74 | public string UsageExample 75 | { 76 | get 77 | { 78 | if (ResourceType != null && !String.IsNullOrEmpty(UsageExampleResourceName)) 79 | { 80 | return ResourceHelper.GetLocalizedString(ResourceType, UsageExampleResourceName); 81 | } 82 | return _example; 83 | } 84 | set 85 | { 86 | _example = value; 87 | } 88 | } 89 | 90 | public CommandAttribute(string commandName, string description) 91 | { 92 | CommandName = commandName; 93 | Description = description; 94 | MinArgs = 0; 95 | MaxArgs = Int32.MaxValue; 96 | } 97 | 98 | public CommandAttribute(Type resourceType, string commandName, string descriptionResourceName) 99 | { 100 | ResourceType = resourceType; 101 | CommandName = commandName; 102 | DescriptionResourceName = descriptionResourceName; 103 | MinArgs = 0; 104 | MaxArgs = Int32.MaxValue; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Attributes/OptionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NuGetGallery.Operations 4 | { 5 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] 6 | public sealed class OptionAttribute : Attribute 7 | { 8 | private string _description; 9 | 10 | public string AltName { get; set; } 11 | public string DescriptionResourceName { get; private set; } 12 | 13 | public string Description 14 | { 15 | get 16 | { 17 | if (ResourceType != null && !String.IsNullOrEmpty(DescriptionResourceName)) 18 | { 19 | return ResourceHelper.GetLocalizedString(ResourceType, DescriptionResourceName); 20 | } 21 | return _description; 22 | 23 | } 24 | private set 25 | { 26 | _description = value; 27 | } 28 | } 29 | 30 | public Type ResourceType { get; private set; } 31 | 32 | public OptionAttribute(string description) 33 | { 34 | Description = description; 35 | } 36 | 37 | public OptionAttribute(Type resourceType, string descriptionResourceName) 38 | { 39 | ResourceType = resourceType; 40 | DescriptionResourceName = descriptionResourceName; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/ArgCheck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NuGetGallery.Operations.Common 4 | { 5 | public static class ArgCheck 6 | { 7 | public static void RequiredOrConfig(object value, string name) 8 | { 9 | if (value == null) 10 | { 11 | throw CreateRequiredOrConfigEx(name); 12 | } 13 | } 14 | 15 | public static void RequiredOrConfig(string value, string name) 16 | { 17 | if (String.IsNullOrWhiteSpace(value)) 18 | { 19 | throw CreateRequiredOrConfigEx(name); 20 | } 21 | } 22 | 23 | public static void Required(object value, string name) 24 | { 25 | if (value == null) 26 | { 27 | throw CreateRequiredEx(name); 28 | } 29 | } 30 | 31 | public static void Required(string value, string name) 32 | { 33 | if (String.IsNullOrWhiteSpace(value)) 34 | { 35 | throw CreateRequiredEx(name); 36 | } 37 | } 38 | 39 | private static CommandLineException CreateRequiredEx(string name) 40 | { 41 | return new CommandLineException(String.Format(CommandHelp.Option_Required, name)); 42 | } 43 | 44 | private static CommandLineException CreateRequiredOrConfigEx(string name) 45 | { 46 | return new CommandLineException(String.Format(CommandHelp.Option_RequiredOrConfig, name)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/CloudStorageAccountConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using Microsoft.WindowsAzure.Storage; 4 | 5 | namespace NuGetGallery.Operations.Common 6 | { 7 | public class CloudStorageAccountConverter : TypeConverter 8 | { 9 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 10 | { 11 | return sourceType == typeof(string); 12 | } 13 | 14 | public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 15 | { 16 | string s = value as string; 17 | if (s != null) 18 | { 19 | CloudStorageAccount acct; 20 | if (CloudStorageAccount.TryParse(s, out acct)) 21 | { 22 | return acct; 23 | } 24 | } 25 | return null; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/CommandLineConstants.cs: -------------------------------------------------------------------------------- 1 | namespace NuGet.Common 2 | { 3 | internal static class CommandLineConstants 4 | { 5 | internal static string ReferencePage = "https://github.com/NuGet/NuGetOperations"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/CommandLineException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Runtime.Serialization; 4 | 5 | namespace NuGetGallery.Operations 6 | { 7 | [Serializable] 8 | public class CommandLineException : Exception 9 | { 10 | public CommandLineException() 11 | { 12 | } 13 | 14 | public CommandLineException(string message) 15 | : base(message) 16 | { 17 | } 18 | 19 | public CommandLineException(string format, params object[] args) 20 | : base(String.Format(CultureInfo.CurrentCulture, format, args)) 21 | { 22 | } 23 | 24 | public CommandLineException(string message, Exception exception) 25 | : base(message, exception) 26 | { 27 | } 28 | 29 | protected CommandLineException(SerializationInfo info, StreamingContext context) 30 | : base(info, context) 31 | { 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/LocalizedResourceManager.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Threading; 3 | 4 | namespace NuGetGallery.Operations 5 | { 6 | internal static class LocalizedResourceManager 7 | { 8 | private static readonly ResourceManager _resourceManager = new ResourceManager("NuGet.Resources", typeof(LocalizedResourceManager).Assembly); 9 | 10 | public static string GetString(string resourceName) 11 | { 12 | var culture = Thread.CurrentThread.CurrentUICulture.ThreeLetterISOLanguageName; 13 | return _resourceManager.GetString(resourceName + '_' + culture) ?? 14 | _resourceManager.GetString(resourceName); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/ResourceHelper.cs: -------------------------------------------------------------------------------- 1 | using NuGetGallery.Operations.Common; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | using System.IO; 6 | using System.Reflection; 7 | using System.Resources; 8 | using System.Text; 9 | 10 | namespace NuGetGallery.Operations 11 | { 12 | public static class ResourceHelper 13 | { 14 | private static Dictionary _cachedManagers; 15 | 16 | public static string GetLocalizedString(Type resourceType, string resourceNames) 17 | { 18 | if (String.IsNullOrEmpty(resourceNames)) 19 | { 20 | throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "resourceNames"); 21 | } 22 | 23 | if (resourceType == null) 24 | { 25 | throw new ArgumentNullException("resourceType"); 26 | } 27 | 28 | if (_cachedManagers == null) 29 | { 30 | _cachedManagers = new Dictionary(); 31 | } 32 | 33 | ResourceManager resourceManager; 34 | if (!_cachedManagers.TryGetValue(resourceType, out resourceManager)) 35 | { 36 | PropertyInfo property = resourceType.GetProperty("ResourceManager", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); 37 | 38 | if (property == null || property.GetGetMethod(nonPublic: true) == null) 39 | { 40 | throw new InvalidOperationException( 41 | String.Format(CultureInfo.CurrentCulture, TaskResources.ResourceTypeDoesNotHaveProperty, resourceType, "ResourceManager")); 42 | } 43 | 44 | if (property.PropertyType != typeof(ResourceManager)) 45 | { 46 | throw new InvalidOperationException( 47 | String.Format(CultureInfo.CurrentCulture, TaskResources.ResourcePropertyIncorrectType, resourceNames, resourceType)); 48 | } 49 | 50 | resourceManager = (ResourceManager)property.GetGetMethod(nonPublic: true) 51 | .Invoke(obj: null, parameters: null); 52 | } 53 | 54 | var builder = new StringBuilder(); 55 | foreach (var resource in resourceNames.Split(';')) 56 | { 57 | string value = resourceManager.GetString(resource); 58 | if (String.IsNullOrEmpty(value)) 59 | { 60 | throw new InvalidOperationException( 61 | String.Format(CultureInfo.CurrentCulture, TaskResources.ResourceTypeDoesNotHaveProperty, resourceType, resource)); 62 | } 63 | if (builder.Length > 0) 64 | { 65 | builder.AppendLine(); 66 | } 67 | builder.Append(value); 68 | } 69 | 70 | return builder.ToString(); 71 | } 72 | 73 | public static string GetBatchFromSqlFile(string filename) 74 | { 75 | using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filename)) 76 | { 77 | using (var reader = new StreamReader(stream)) 78 | { 79 | return reader.ReadToEnd(); 80 | } 81 | } 82 | } 83 | 84 | public static IEnumerable GetBatchesFromSqlFile(string filename) 85 | { 86 | List batches = new List(); 87 | 88 | using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filename)) 89 | { 90 | using (var reader = new StreamReader(stream)) 91 | { 92 | StringBuilder batch = new StringBuilder(); 93 | 94 | while (!reader.EndOfStream) 95 | { 96 | string line = reader.ReadLine(); 97 | 98 | if (line.Trim().Equals("GO", StringComparison.OrdinalIgnoreCase)) 99 | { 100 | batches.Add(batch.ToString()); 101 | batch.Clear(); 102 | } 103 | else 104 | { 105 | batch.AppendLine(line); 106 | } 107 | } 108 | } 109 | } 110 | 111 | return batches; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/SqlConnectionStringConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Data.SqlClient; 4 | using System.Globalization; 5 | 6 | namespace NuGetGallery.Operations.Common 7 | { 8 | class SqlConnectionStringConverter : TypeConverter 9 | { 10 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 11 | { 12 | return sourceType == typeof(string); 13 | } 14 | 15 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 16 | { 17 | string s = value as string; 18 | if (s != null) 19 | { 20 | return new SqlConnectionStringBuilder(s); 21 | } 22 | return null; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/SqlHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | 4 | namespace NuGetGallery.Operations.Common 5 | { 6 | static class SqlHelper 7 | { 8 | public static void ExecuteBatch(string connectionString, string sql, int timeout = 180) 9 | { 10 | try 11 | { 12 | using (SqlConnection conn = new SqlConnection(connectionString)) 13 | { 14 | conn.Open(); 15 | 16 | SqlCommand command = new SqlCommand(sql, conn); 17 | command.CommandTimeout = timeout; 18 | command.ExecuteNonQuery(); 19 | } 20 | } 21 | catch (Exception e) 22 | { 23 | throw new ApplicationException(string.Format("{0}\n{1}", e.Message, sql), e); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/StreamConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.IO; 4 | 5 | namespace NuGetGallery.Operations.Common 6 | { 7 | public class FileStreamConverter : TypeConverter 8 | { 9 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 10 | { 11 | return sourceType == typeof(string); 12 | } 13 | 14 | public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 15 | { 16 | string s = value as string; 17 | if (s != null) 18 | { 19 | return File.Open(s, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); 20 | } 21 | return null; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Common/TypeHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data.SqlClient; 5 | using System.Globalization; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Reflection; 9 | using Microsoft.WindowsAzure.Storage; 10 | using NuGetGallery.Operations.Common; 11 | 12 | namespace NuGetGallery.Operations 13 | { 14 | internal static class TypeHelper 15 | { 16 | private static Dictionary> _additionalConverters = new Dictionary>(); 17 | 18 | static TypeHelper() 19 | { 20 | RegisterConverter(typeof(Stream), () => new FileStreamConverter()); 21 | RegisterConverter(typeof(CloudStorageAccount), () => new CloudStorageAccountConverter()); 22 | RegisterConverter(typeof(SqlConnectionStringBuilder), () => new SqlConnectionStringConverter()); 23 | } 24 | 25 | public static void RegisterConverter(Type type, Func ctor) 26 | { 27 | _additionalConverters[type] = ctor; 28 | } 29 | 30 | public static Type RemoveNullableFromType(Type type) 31 | { 32 | return Nullable.GetUnderlyingType(type) ?? type; 33 | } 34 | 35 | public static object ChangeType(object value, Type type) 36 | { 37 | if (type == null) 38 | { 39 | throw new ArgumentNullException("type"); 40 | } 41 | 42 | if (value == null) 43 | { 44 | if (TypeAllowsNull(type)) 45 | { 46 | return null; 47 | } 48 | return Convert.ChangeType(value, type, CultureInfo.CurrentCulture); 49 | } 50 | 51 | type = RemoveNullableFromType(type); 52 | 53 | if (value.GetType() == type) 54 | { 55 | return value; 56 | } 57 | 58 | TypeConverter converter = TypeDescriptor.GetConverter(type); 59 | if (converter.CanConvertFrom(value.GetType())) 60 | { 61 | return converter.ConvertFrom(value); 62 | } 63 | 64 | converter = TypeDescriptor.GetConverter(value.GetType()); 65 | if (converter.CanConvertTo(type)) 66 | { 67 | return converter.ConvertTo(value, type); 68 | } 69 | 70 | Func ctor; 71 | if (_additionalConverters.TryGetValue(type, out ctor)) 72 | { 73 | converter = ctor(); 74 | if (converter.CanConvertFrom(value.GetType())) 75 | { 76 | return converter.ConvertFrom(value); 77 | } 78 | } 79 | 80 | if (_additionalConverters.TryGetValue(value.GetType(), out ctor)) 81 | { 82 | converter = ctor(); 83 | if (converter.CanConvertTo(type)) 84 | { 85 | return converter.ConvertTo(value, type); 86 | } 87 | } 88 | 89 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 90 | TaskResources.UnableToConvertTypeError, value.GetType(), type)); 91 | } 92 | 93 | public static bool TypeAllowsNull(Type type) 94 | { 95 | return Nullable.GetUnderlyingType(type) != null || !type.IsValueType; 96 | } 97 | 98 | public static Type GetGenericCollectionType(Type type) 99 | { 100 | return GetInterfaceType(type, typeof(ICollection<>)); 101 | } 102 | 103 | public static Type GetDictionaryType(Type type) 104 | { 105 | return GetInterfaceType(type, typeof(IDictionary<,>)); 106 | } 107 | 108 | private static Type GetInterfaceType(Type type, Type interfaceType) 109 | { 110 | if (type.IsGenericType && type.GetGenericTypeDefinition() == interfaceType) 111 | { 112 | return type; 113 | } 114 | return (from t in type.GetInterfaces() 115 | where t.IsGenericType && t.GetGenericTypeDefinition() == interfaceType 116 | select t).SingleOrDefault(); 117 | } 118 | 119 | public static bool IsKeyValueProperty(PropertyInfo property) 120 | { 121 | return GetDictionaryType(property.PropertyType) != null; 122 | } 123 | 124 | public static bool IsMultiValuedProperty(PropertyInfo property) 125 | { 126 | return GetGenericCollectionType(property.PropertyType) != null || IsKeyValueProperty(property); 127 | } 128 | 129 | public static bool IsEnumProperty(PropertyInfo property) 130 | { 131 | return property.PropertyType.IsEnum; 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/DeploymentEnvironment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.SqlClient; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Linq; 8 | using Microsoft.WindowsAzure.Storage; 9 | 10 | namespace NuGetGallery.Operations 11 | { 12 | public class DeploymentEnvironment 13 | { 14 | public IDictionary Settings { get; private set; } 15 | public SqlConnectionStringBuilder MainDatabase { get; private set; } 16 | public SqlConnectionStringBuilder WarehouseDatabase { get; private set; } 17 | public SqlConnectionStringBuilder BackupSourceDatabase { get; set; } 18 | 19 | public CloudStorageAccount MainStorage { get; private set; } 20 | public CloudStorageAccount ReportStorage { get; private set; } 21 | public CloudStorageAccount BackupSourceStorage { get; private set; } 22 | 23 | public DeploymentEnvironment(IDictionary deploymentSettings) 24 | { 25 | Settings = deploymentSettings; 26 | MainDatabase = GetSqlConnectionStringBuilder(deploymentSettings["Operations.Sql.Primary"]); 27 | WarehouseDatabase = GetSqlConnectionStringBuilder(deploymentSettings["Operations.Sql.Warehouse"]); 28 | BackupSourceDatabase = GetSqlConnectionStringBuilder(deploymentSettings["Operations.Sql.BackupSource"]); 29 | 30 | MainStorage = GetCloudStorageAccount(deploymentSettings["Operations.Storage.Primary"]); 31 | ReportStorage = GetCloudStorageAccount(deploymentSettings["Operations.Storage.Reports"]); 32 | BackupSourceStorage = GetCloudStorageAccount(deploymentSettings["Operations.Storage.BackupSource"]); 33 | } 34 | 35 | public static DeploymentEnvironment FromConfigFile(string configFile) 36 | { 37 | // Load the file 38 | var doc = XDocument.Load(configFile); 39 | 40 | // Build a dictionary of settings 41 | var settings = BuildSettingsDictionary(doc); 42 | 43 | // Construct the deployment environment 44 | return new DeploymentEnvironment(settings); 45 | } 46 | 47 | private CloudStorageAccount GetCloudStorageAccount(string connectionString) 48 | { 49 | return String.IsNullOrEmpty(connectionString) ? null : CloudStorageAccount.Parse(connectionString); 50 | } 51 | 52 | private SqlConnectionStringBuilder GetSqlConnectionStringBuilder(string connectionString) 53 | { 54 | return String.IsNullOrEmpty(connectionString) ? null : new SqlConnectionStringBuilder(connectionString); 55 | } 56 | 57 | private static IDictionary BuildSettingsDictionary(XDocument doc) 58 | { 59 | XNamespace ns = XNamespace.Get("http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration"); 60 | return (from s in doc.Element(ns + "ServiceConfiguration") 61 | .Element(ns + "Role") 62 | .Element(ns + "ConfigurationSettings") 63 | .Elements(ns + "Setting") 64 | select new KeyValuePair( 65 | s.Attribute("name").Value, 66 | s.Attribute("value").Value)) 67 | .ToDictionary(p => p.Key, p => p.Value); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Infrastructure/CommandManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Composition; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Reflection; 7 | using NuGetGallery.Operations.Common; 8 | 9 | namespace NuGetGallery.Operations 10 | { 11 | [Export(typeof(ICommandManager))] 12 | public class CommandManager : ICommandManager 13 | { 14 | private readonly IList _commands = new List(); 15 | 16 | public IEnumerable GetCommands() 17 | { 18 | return _commands; 19 | } 20 | 21 | public ICommand GetCommand(string commandName) 22 | { 23 | if (String.IsNullOrEmpty(commandName)) 24 | { 25 | throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, commandName); 26 | } 27 | 28 | IEnumerable results = from command in _commands 29 | where command.CommandAttribute.CommandName.StartsWith(commandName, StringComparison.OrdinalIgnoreCase) || 30 | (command.CommandAttribute.AltName ?? String.Empty).StartsWith(commandName, StringComparison.OrdinalIgnoreCase) 31 | select command; 32 | 33 | if (!results.Any()) 34 | { 35 | throw new CommandLineException(TaskResources.UnknownCommandError, commandName); 36 | } 37 | 38 | var matchedCommand = results.First(); 39 | if (results.Skip(1).Any()) 40 | { 41 | // Were there more than one results found? 42 | matchedCommand = results.FirstOrDefault(c => c.CommandAttribute.CommandName.Equals(commandName, StringComparison.OrdinalIgnoreCase) 43 | || commandName.Equals(c.CommandAttribute.AltName, StringComparison.OrdinalIgnoreCase)); 44 | 45 | if (matchedCommand == null) 46 | { 47 | // No exact match was found and the result returned multiple prefixes. 48 | throw new CommandLineException(String.Format(CultureInfo.CurrentCulture, TaskResources.AmbiguousCommand, commandName, 49 | String.Join(" ", from c in results select c.CommandAttribute.CommandName))); 50 | } 51 | } 52 | return matchedCommand; 53 | } 54 | 55 | public IDictionary GetCommandOptions(ICommand command) 56 | { 57 | var result = new Dictionary(); 58 | 59 | foreach (PropertyInfo propInfo in command.GetType().GetProperties()) 60 | { 61 | foreach (OptionAttribute attr in propInfo.GetCustomAttributes(typeof(OptionAttribute), inherit: true)) 62 | { 63 | if (!propInfo.CanWrite && !TypeHelper.IsMultiValuedProperty(propInfo)) 64 | { 65 | // If the property has neither a setter nor is of a type that can be cast to ICollection<> then there's no way to assign 66 | // values to it. In this case throw. 67 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 68 | TaskResources.OptionInvalidWithoutSetter, command.GetType().FullName + "." + propInfo.Name)); 69 | } 70 | result.Add(attr, propInfo); 71 | } 72 | } 73 | 74 | return result; 75 | } 76 | 77 | public void RegisterCommand(ICommand command) 78 | { 79 | var attrib = command.CommandAttribute; 80 | if (attrib != null) 81 | { 82 | _commands.Add(command); 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Infrastructure/ICommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.Composition; 3 | 4 | namespace NuGetGallery.Operations 5 | { 6 | [InheritedExport] 7 | public interface ICommand 8 | { 9 | CommandAttribute CommandAttribute { get; } 10 | 11 | IList Arguments { get; } 12 | 13 | void Execute(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Infrastructure/ICommandManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Reflection; 4 | 5 | namespace NuGetGallery.Operations 6 | { 7 | public interface ICommandManager 8 | { 9 | [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Method would do reflection and a property would be inappropriate.")] 10 | IEnumerable GetCommands(); 11 | ICommand GetCommand(string commandName); 12 | IDictionary GetCommandOptions(ICommand command); 13 | void RegisterCommand(ICommand command); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Infrastructure/Verbosity.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace NuGetGallery.Operations 3 | { 4 | public enum Verbosity 5 | { 6 | Normal, 7 | Quiet, 8 | Detailed 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("NuGetGallery.Operations")] 5 | [assembly: AssemblyDescription("Extensions to NuGetGallery.Monitoring for Azure Web Applications")] 6 | 7 | // The following GUID is for the ID of the typelib if this project is exposed to COM 8 | [assembly: Guid("13364c31-0176-41ce-a6d2-f0b0905e77f5")] -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/adapters/standalone-framework.js: -------------------------------------------------------------------------------- 1 | /* 2 | Highcharts JS v4.0.1 (2014-04-24) 3 | 4 | Standalone Highcharts Framework 5 | 6 | License: MIT License 7 | */ 8 | var HighchartsAdapter=function(){function o(c){function b(b,a,d){b.removeEventListener(a,d,!1)}function d(b,a,d){d=b.HCProxiedMethods[d.toString()];b.detachEvent("on"+a,d)}function a(a,c){var f=a.HCEvents,i,g,k,j;if(a.removeEventListener)i=b;else if(a.attachEvent)i=d;else return;c?(g={},g[c]=!0):g=f;for(j in g)if(f[j])for(k=f[j].length;k--;)i(a,j,f[j][k])}c.HCExtended||Highcharts.extend(c,{HCExtended:!0,HCEvents:{},bind:function(b,a){var d=this,c=this.HCEvents,g;if(d.addEventListener)d.addEventListener(b, 9 | a,!1);else if(d.attachEvent){g=function(b){b.target=b.srcElement||window;a.call(d,b)};if(!d.HCProxiedMethods)d.HCProxiedMethods={};d.HCProxiedMethods[a.toString()]=g;d.attachEvent("on"+b,g)}c[b]===r&&(c[b]=[]);c[b].push(a)},unbind:function(c,h){var f,i;c?(f=this.HCEvents[c]||[],h?(i=HighchartsAdapter.inArray(h,f),i>-1&&(f.splice(i,1),this.HCEvents[c]=f),this.removeEventListener?b(this,c,h):this.attachEvent&&d(this,c,h)):(a(this,c),this.HCEvents[c]=[])):(a(this),this.HCEvents={})},trigger:function(b, 10 | a){var d=this.HCEvents[b]||[],c=d.length,g,k,j;k=function(){a.defaultPrevented=!0};for(g=0;g=a.duration+this.startTime){this.now=this.end; 14 | this.pos=this.state=1;this.update();b=this.options.curAnim[this.prop]=!0;for(h in a.curAnim)a.curAnim[h]!==!0&&(b=!1);b&&a.complete&&a.complete.call(e);a=!1}else e=c-this.startTime,this.state=e/a.duration,this.pos=a.easing(e,0,1,a.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update(),a=!0;return a}};this.animate=function(b,d,a){var e,h="",f,i,g;b.stopAnimation=!1;if(typeof a!=="object"||a===null)e=arguments,a={duration:e[2],easing:e[3],complete:e[4]};if(typeof a.duration!=="number")a.duration= 15 | 400;a.easing=Math[a.easing]||Math.easeInOutSine;a.curAnim=Highcharts.extend({},d);for(g in d)i=new n(b,a,g),f=null,g==="d"?(i.paths=c.init(b,b.d,d.d),i.toD=d.d,e=0,f=1):b.attr?e=b.attr(g):(e=parseFloat(HighchartsAdapter._getStyle(b,g))||0,g!=="opacity"&&(h="px")),f||(f=parseFloat(d[g])),i.custom(e,f,h)}},_getStyle:function(c,b){return window.getComputedStyle(c,void 0).getPropertyValue(b)},getScript:function(c,b){var d=l.getElementsByTagName("head")[0],a=l.createElement("script");a.type="text/javascript"; 16 | a.src=c;a.onload=b;d.appendChild(a)},inArray:function(c,b){return b.indexOf?b.indexOf(c):p.indexOf.call(b,c)},adapterRun:function(c,b){return parseInt(HighchartsAdapter._getStyle(c,b),10)},grep:function(c,b){return p.filter.call(c,b)},map:function(c,b){for(var d=[],a=0,e=c.length;a=e&&c<=h&&!j&&k!==""&&(k=b.split(f),m(k,function(b,a){a>=i&&a<=g&&(d[a-i]||(d[a-i]=[]),d[a-i][o]=b)}),o+=1)}),this.dataFound())},parseTable:function(){var a=this.options,b=a.table,c=this.columns,d=a.startRow||0,e=a.endRow||Number.MAX_VALUE,h=a.startColumn||0,i=a.endColumn||Number.MAX_VALUE;b&&(typeof b==="string"&&(b=document.getElementById(b)),m(b.getElementsByTagName("tr"),function(a, 11 | b){b>=d&&b<=e&&m(a.children,function(a,e){if((a.tagName==="TD"||a.tagName==="TH")&&e>=h&&e<=i)c[e-h]||(c[e-h]=[]),c[e-h][b-d]=a.innerHTML})}),this.dataFound())},parseGoogleSpreadsheet:function(){var a=this,b=this.options,c=b.googleSpreadsheetKey,d=this.columns,e=b.startRow||0,h=b.endRow||Number.MAX_VALUE,i=b.startColumn||0,g=b.endColumn||Number.MAX_VALUE,f,k;c&&jQuery.ajax({dataType:"json",url:"https://spreadsheets.google.com/feeds/cells/"+c+"/"+(b.googleSpreadsheetWorksheet||"od6")+"/public/values?alt=json-in-script&callback=?", 12 | error:b.error,success:function(b){var b=b.feed.entry,c,j=b.length,m=0,n=0,l;for(l=0;l=i&&l<=g)d[l-i]=[],d[l-i].length=Math.min(n,h-e);for(l=0;l=i&&k<=g&&f>=e&&f<=h)d[k-i][f-e]=c.content.$t;a.dataFound()}})},findHeaderRow:function(){m(this.columns,function(){});this.headerRow=0},trim:function(a){return typeof a==="string"?a.replace(/^\s+|\s+$/g,""):a},parseTypes:function(){for(var a= 13 | this.columns,b=a.length,c,d,e,h;b--;)for(c=a[b].length;c--;)d=a[b][c],e=parseFloat(d),h=this.trim(d),h==e?(a[b][c]=e,e>31536E6?a[b].isDatetime=!0:a[b].isNumeric=!0):(d=this.parseDate(d),b===0&&typeof d==="number"&&!isNaN(d)?(a[b][c]=d,a[b].isDatetime=!0):a[b][c]=h===""?null:h)},dateFormats:{"YYYY-mm-dd":{regex:"^([0-9]{4})-([0-9]{2})-([0-9]{2})$",parser:function(a){return Date.UTC(+a[1],a[2]-1,+a[3])}}},parseDate:function(a){var b=this.options.parseDate,c,d,e;b&&(c=b(a));if(typeof a==="string")for(d in this.dateFormats)b= 14 | this.dateFormats[d],(e=a.match(b.regex))&&(c=b.parser(e));return c},rowsToColumns:function(a){var b,c,d,e,h;if(a){h=[];c=a.length;for(b=0;b1&&(b=a.shift(),this.headerRow===0&&b.shift(),b.isDatetime?c="datetime":b.isNumeric|| 15 | (c="category"));for(g=0;g1&&i[f].push(a[g+1][f]!==void 0?a[g+1][f]:null),e>2&&i[f].push(a[g+2][f]!==void 0?a[g+2][f]:null),e>3&&i[f].push(a[g+3][f]!==void 0?a[g+3][f]:null),e>4&&i[f].push(a[g+4][f]!==void 0?a[g+4][f]:null);h[k]={name:a[g].name,data:i};g+= 16 | e}d.complete({xAxis:{type:c},series:h})}}});j.Data=n;j.data=function(a,b){return new n(a,b)};j.wrap(j.Chart.prototype,"init",function(a,b,c){var d=this;b&&b.data?j.data(j.extend(b.data,{complete:function(e){b.hasOwnProperty("series")&&(typeof b.series==="object"?m(b.series,function(a,c){b.series[c]=j.merge(a,e.series[c])}):delete b.series);b=j.merge(e,b);a.call(d,b,c)}}),b):a.call(d,b,c)})})(Highcharts); 17 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/modules/funnel.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Highcharts funnel module 4 | 5 | (c) 2010-2014 Torstein Honsi 6 | 7 | License: www.highcharts.com/license 8 | */ 9 | (function(b){var d=b.getOptions(),v=d.plotOptions,q=b.seriesTypes,E=b.merge,D=function(){},A=b.each;v.funnel=E(v.pie,{animation:!1,center:["50%","50%"],width:"90%",neckWidth:"30%",height:"100%",neckHeight:"25%",reversed:!1,dataLabels:{connectorWidth:1,connectorColor:"#606060"},size:!0,states:{select:{color:"#C0C0C0",borderColor:"#000000",shadow:!1}}});q.funnel=b.extendClass(q.pie,{type:"funnel",animate:D,singularTooltips:!0,translate:function(){var a=function(j,a){return/%$/.test(j)?a*parseInt(j, 10 | 10)/100:parseInt(j,10)},B=0,f=this.chart,c=this.options,g=c.reversed,b=f.plotWidth,n=f.plotHeight,o=0,f=c.center,h=a(f[0],b),d=a(f[0],n),q=a(c.width,b),k,r,e=a(c.height,n),s=a(c.neckWidth,b),t=a(c.neckHeight,n),w=e-t,a=this.data,x,y,v=c.dataLabels.position==="left"?1:0,z,l,C,p,i,u,m;this.getWidthAt=r=function(j){return j>e-t||e===t?s:s+(q-s)*((e-t-j)/(e-t))};this.getX=function(j,a){return h+(a?-1:1)*(r(g?n-j:j)/2+c.dataLabels.distance)};this.center=[h,d,e];this.centerX=h;A(a,function(a){B+=a.y}); 11 | A(a,function(a){m=null;y=B?a.y/B:0;l=d-e/2+o*e;i=l+y*e;k=r(l);z=h-k/2;C=z+k;k=r(i);p=h-k/2;u=p+k;l>w?(z=p=h-s/2,C=u=h+s/2):i>w&&(m=i,k=r(w),p=h-k/2,u=p+k,i=w);g&&(l=e-l,i=e-i,m=m?e-m:null);x=["M",z,l,"L",C,l,u,i];m&&x.push(u,m,p,m);x.push(p,i,"Z");a.shapeType="path";a.shapeArgs={d:x};a.percentage=y*100;a.plotX=h;a.plotY=(l+(m||i))/2;a.tooltipPos=[h,a.plotY];a.slice=D;a.half=v;o+=y})},drawPoints:function(){var a=this,b=a.options,f=a.chart.renderer;A(a.data,function(c){var g=c.graphic,d=c.shapeArgs; 12 | g?g.animate(d):c.graphic=f.path(d).attr({fill:c.color,stroke:b.borderColor,"stroke-width":b.borderWidth}).add(a.group)})},sortByAngle:function(a){a.sort(function(a,b){return a.plotY-b.plotY})},drawDataLabels:function(){var a=this.data,b=this.options.dataLabels.distance,f,c,g,d=a.length,n,o;for(this.center[2]-=2*b;d--;)g=a[d],c=(f=g.half)?1:-1,o=g.plotY,n=this.getX(o,f),g.labelPos=[0,o,n+(b-5)*c,o,n+b*c,o,f?"right":"left",0];q.pie.prototype.drawDataLabels.call(this)}});d.plotOptions.pyramid=b.merge(d.plotOptions.funnel, 13 | {neckWidth:"0%",neckHeight:"0%",reversed:!0});b.seriesTypes.pyramid=b.extendClass(b.seriesTypes.funnel,{type:"pyramid"})})(Highcharts); 14 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/modules/no-data-to-display.js: -------------------------------------------------------------------------------- 1 | /* 2 | Highcharts JS v4.0.1 (2014-04-24) 3 | Plugin for displaying a message when there is no data visible in chart. 4 | 5 | (c) 2010-2014 Highsoft AS 6 | Author: Oystein Moseng 7 | 8 | License: www.highcharts.com/license 9 | */ 10 | (function(c){function f(){return!!this.points.length}function g(){this.hasData()?this.hideNoData():this.showNoData()}var d=c.seriesTypes,e=c.Chart.prototype,h=c.getOptions(),i=c.extend;i(h.lang,{noData:"No data to display"});h.noData={position:{x:0,y:0,align:"center",verticalAlign:"middle"},attr:{},style:{fontWeight:"bold",fontSize:"12px",color:"#60606a"}};if(d.pie)d.pie.prototype.hasData=f;if(d.gauge)d.gauge.prototype.hasData=f;if(d.waterfall)d.waterfall.prototype.hasData=f;c.Series.prototype.hasData= 11 | function(){return this.dataMax!==void 0&&this.dataMin!==void 0};e.showNoData=function(a){var b=this.options,a=a||b.lang.noData,b=b.noData;if(!this.noDataLabel)this.noDataLabel=this.renderer.label(a,0,0,null,null,null,null,null,"no-data").attr(b.attr).css(b.style).add(),this.noDataLabel.align(i(this.noDataLabel.getBBox(),b.position),!1,"plotBox")};e.hideNoData=function(){if(this.noDataLabel)this.noDataLabel=this.noDataLabel.destroy()};e.hasData=function(){for(var a=this.series,b=a.length;b--;)if(a[b].hasData()&& 12 | !a[b].options.isInternal)return!0;return!1};e.callbacks.push(function(a){c.addEvent(a,"load",g);c.addEvent(a,"redraw",g)})})(Highcharts); 13 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/modules/no-data-to-display.src.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Highcharts JS v4.0.1 (2014-04-24) 3 | * Plugin for displaying a message when there is no data visible in chart. 4 | * 5 | * (c) 2010-2014 Highsoft AS 6 | * Author: Oystein Moseng 7 | * 8 | * License: www.highcharts.com/license 9 | */ 10 | 11 | (function (H) { // docs 12 | 13 | var seriesTypes = H.seriesTypes, 14 | chartPrototype = H.Chart.prototype, 15 | defaultOptions = H.getOptions(), 16 | extend = H.extend; 17 | 18 | // Add language option 19 | extend(defaultOptions.lang, { 20 | noData: 'No data to display' 21 | }); 22 | 23 | // Add default display options for message 24 | defaultOptions.noData = { 25 | position: { 26 | x: 0, 27 | y: 0, 28 | align: 'center', 29 | verticalAlign: 'middle' 30 | }, 31 | attr: { 32 | }, 33 | style: { 34 | fontWeight: 'bold', 35 | fontSize: '12px', 36 | color: '#60606a' 37 | } 38 | }; 39 | 40 | /** 41 | * Define hasData functions for series. These return true if there are data points on this series within the plot area 42 | */ 43 | function hasDataPie() { 44 | return !!this.points.length; /* != 0 */ 45 | } 46 | 47 | if (seriesTypes.pie) { 48 | seriesTypes.pie.prototype.hasData = hasDataPie; 49 | } 50 | 51 | if (seriesTypes.gauge) { 52 | seriesTypes.gauge.prototype.hasData = hasDataPie; 53 | } 54 | 55 | if (seriesTypes.waterfall) { 56 | seriesTypes.waterfall.prototype.hasData = hasDataPie; 57 | } 58 | 59 | H.Series.prototype.hasData = function () { 60 | return this.dataMax !== undefined && this.dataMin !== undefined; 61 | }; 62 | 63 | /** 64 | * Display a no-data message. 65 | * 66 | * @param {String} str An optional message to show in place of the default one 67 | */ 68 | chartPrototype.showNoData = function (str) { 69 | var chart = this, 70 | options = chart.options, 71 | text = str || options.lang.noData, 72 | noDataOptions = options.noData; 73 | 74 | if (!chart.noDataLabel) { 75 | chart.noDataLabel = chart.renderer.label(text, 0, 0, null, null, null, null, null, 'no-data') 76 | .attr(noDataOptions.attr) 77 | .css(noDataOptions.style) 78 | .add(); 79 | chart.noDataLabel.align(extend(chart.noDataLabel.getBBox(), noDataOptions.position), false, 'plotBox'); 80 | } 81 | }; 82 | 83 | /** 84 | * Hide no-data message 85 | */ 86 | chartPrototype.hideNoData = function () { 87 | var chart = this; 88 | if (chart.noDataLabel) { 89 | chart.noDataLabel = chart.noDataLabel.destroy(); 90 | } 91 | }; 92 | 93 | /** 94 | * Returns true if there are data points within the plot area now 95 | */ 96 | chartPrototype.hasData = function () { 97 | var chart = this, 98 | series = chart.series, 99 | i = series.length; 100 | 101 | while (i--) { 102 | if (series[i].hasData() && !series[i].options.isInternal) { 103 | return true; 104 | } 105 | } 106 | 107 | return false; 108 | }; 109 | 110 | /** 111 | * Show no-data message if there is no data in sight. Otherwise, hide it. 112 | */ 113 | function handleNoData() { 114 | var chart = this; 115 | if (chart.hasData()) { 116 | chart.hideNoData(); 117 | } else { 118 | chart.showNoData(); 119 | } 120 | } 121 | 122 | /** 123 | * Add event listener to handle automatic display of no-data message 124 | */ 125 | chartPrototype.callbacks.push(function (chart) { 126 | H.addEvent(chart, 'load', handleNoData); 127 | H.addEvent(chart, 'redraw', handleNoData); 128 | }); 129 | 130 | }(Highcharts)); 131 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/modules/solid-gauge.js: -------------------------------------------------------------------------------- 1 | /* 2 | Highcharts JS v4.0.1 (2014-04-24) 3 | Solid angular gauge module 4 | 5 | (c) 2010-2014 Torstein Honsi 6 | 7 | License: www.highcharts.com/license 8 | */ 9 | (function(a){var l=a.getOptions().plotOptions,o=a.pInt,p=a.pick,j=a.each,m;l.solidgauge=a.merge(l.gauge,{colorByPoint:!0});m={initDataClasses:function(b){var h=this,e=this.chart,c,k=0,f=this.options;this.dataClasses=c=[];j(b.dataClasses,function(g,d){var i,g=a.merge(g);c.push(g);if(!g.color)f.dataClassColor==="category"?(i=e.options.colors,g.color=i[k++],k===i.length&&(k=0)):g.color=h.tweenColors(a.Color(f.minColor),a.Color(f.maxColor),d/(b.dataClasses.length-1))})},initStops:function(b){this.stops= 10 | b.stops||[[0,this.options.minColor],[1,this.options.maxColor]];j(this.stops,function(b){b.color=a.Color(b[1])})},toColor:function(b,h){var e,c=this.stops,a,f=this.dataClasses,g,d;if(f)for(d=f.length;d--;){if(g=f[d],a=g.from,c=g.to,(a===void 0||b>=a)&&(c===void 0||b<=c)){e=g.color;if(h)h.dataClass=d;break}}else{this.isLog&&(b=this.val2lin(b));e=1-(this.max-b)/(this.max-this.min);for(d=c.length;d--;)if(e>c[d][0])break;a=c[d]||c[d+1];c=c[d+1]||a;e=1-(c[0]-e)/(c[0]-a[0]||1);e=this.tweenColors(a.color, 11 | c.color,e)}return e},tweenColors:function(b,a,e){var c=a.rgba[3]!==1||b.rgba[3]!==1;return b.rgba.length===0||a.rgba.length===0?"none":(c?"rgba(":"rgb(")+Math.round(a.rgba[0]+(b.rgba[0]-a.rgba[0])*(1-e))+","+Math.round(a.rgba[1]+(b.rgba[1]-a.rgba[1])*(1-e))+","+Math.round(a.rgba[2]+(b.rgba[2]-a.rgba[2])*(1-e))+(c?","+(a.rgba[3]+(b.rgba[3]-a.rgba[3])*(1-e)):"")+")"}};a.seriesTypes.solidgauge=a.extendClass(a.seriesTypes.gauge,{type:"solidgauge",bindAxes:function(){var b;a.seriesTypes.gauge.prototype.bindAxes.call(this); 12 | b=this.yAxis;a.extend(b,m);b.options.dataClasses&&b.initDataClasses(b.options);b.initStops(b.options)},drawPoints:function(){var b=this,h=b.yAxis,e=h.center,c=b.options,k=b.chart.renderer;a.each(b.points,function(f){var g=f.graphic,d=h.startAngleRad+h.translate(f.y,null,null,null,!0),i=o(p(c.radius,100))*e[2]/200,l=o(p(c.innerRadius,60))*e[2]/200,n=h.toColor(f.y,f),j;if(n!=="none")j=f.color,f.color=n;c.wrap===!1&&(d=Math.max(h.startAngleRad,Math.min(h.endAngleRad,d)));d=d*180/Math.PI;d={x:e[0],y:e[1], 13 | r:i,innerR:l,start:h.startAngleRad,end:d/(180/Math.PI)};g?(i=d.d,g.attr({fill:f.color}).animate(d,{step:function(b,c){g.attr("fill",m.tweenColors(a.Color(j),a.Color(n),c.pos))}}),d.d=i):f.graphic=k.arc(d).attr({stroke:c.borderColor||"none","stroke-width":c.borderWidth||0,fill:f.color}).add(b.group)})},animate:null})})(Highcharts); 14 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/themes/dark-blue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dark blue theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#DDDF0D", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 8 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 9 | chart: { 10 | backgroundColor: { 11 | linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 }, 12 | stops: [ 13 | [0, 'rgb(48, 48, 96)'], 14 | [1, 'rgb(0, 0, 0)'] 15 | ] 16 | }, 17 | borderColor: '#000000', 18 | borderWidth: 2, 19 | className: 'dark-container', 20 | plotBackgroundColor: 'rgba(255, 255, 255, .1)', 21 | plotBorderColor: '#CCCCCC', 22 | plotBorderWidth: 1 23 | }, 24 | title: { 25 | style: { 26 | color: '#C0C0C0', 27 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 28 | } 29 | }, 30 | subtitle: { 31 | style: { 32 | color: '#666666', 33 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 34 | } 35 | }, 36 | xAxis: { 37 | gridLineColor: '#333333', 38 | gridLineWidth: 1, 39 | labels: { 40 | style: { 41 | color: '#A0A0A0' 42 | } 43 | }, 44 | lineColor: '#A0A0A0', 45 | tickColor: '#A0A0A0', 46 | title: { 47 | style: { 48 | color: '#CCC', 49 | fontWeight: 'bold', 50 | fontSize: '12px', 51 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 52 | 53 | } 54 | } 55 | }, 56 | yAxis: { 57 | gridLineColor: '#333333', 58 | labels: { 59 | style: { 60 | color: '#A0A0A0' 61 | } 62 | }, 63 | lineColor: '#A0A0A0', 64 | minorTickInterval: null, 65 | tickColor: '#A0A0A0', 66 | tickWidth: 1, 67 | title: { 68 | style: { 69 | color: '#CCC', 70 | fontWeight: 'bold', 71 | fontSize: '12px', 72 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 73 | } 74 | } 75 | }, 76 | tooltip: { 77 | backgroundColor: 'rgba(0, 0, 0, 0.75)', 78 | style: { 79 | color: '#F0F0F0' 80 | } 81 | }, 82 | toolbar: { 83 | itemStyle: { 84 | color: 'silver' 85 | } 86 | }, 87 | plotOptions: { 88 | line: { 89 | dataLabels: { 90 | color: '#CCC' 91 | }, 92 | marker: { 93 | lineColor: '#333' 94 | } 95 | }, 96 | spline: { 97 | marker: { 98 | lineColor: '#333' 99 | } 100 | }, 101 | scatter: { 102 | marker: { 103 | lineColor: '#333' 104 | } 105 | }, 106 | candlestick: { 107 | lineColor: 'white' 108 | } 109 | }, 110 | legend: { 111 | itemStyle: { 112 | font: '9pt Trebuchet MS, Verdana, sans-serif', 113 | color: '#A0A0A0' 114 | }, 115 | itemHoverStyle: { 116 | color: '#FFF' 117 | }, 118 | itemHiddenStyle: { 119 | color: '#444' 120 | } 121 | }, 122 | credits: { 123 | style: { 124 | color: '#666' 125 | } 126 | }, 127 | labels: { 128 | style: { 129 | color: '#CCC' 130 | } 131 | }, 132 | 133 | navigation: { 134 | buttonOptions: { 135 | symbolStroke: '#DDDDDD', 136 | hoverSymbolStroke: '#FFFFFF', 137 | theme: { 138 | fill: { 139 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 140 | stops: [ 141 | [0.4, '#606060'], 142 | [0.6, '#333333'] 143 | ] 144 | }, 145 | stroke: '#000000' 146 | } 147 | } 148 | }, 149 | 150 | // scroll charts 151 | rangeSelector: { 152 | buttonTheme: { 153 | fill: { 154 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 155 | stops: [ 156 | [0.4, '#888'], 157 | [0.6, '#555'] 158 | ] 159 | }, 160 | stroke: '#000000', 161 | style: { 162 | color: '#CCC', 163 | fontWeight: 'bold' 164 | }, 165 | states: { 166 | hover: { 167 | fill: { 168 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 169 | stops: [ 170 | [0.4, '#BBB'], 171 | [0.6, '#888'] 172 | ] 173 | }, 174 | stroke: '#000000', 175 | style: { 176 | color: 'white' 177 | } 178 | }, 179 | select: { 180 | fill: { 181 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 182 | stops: [ 183 | [0.1, '#000'], 184 | [0.3, '#333'] 185 | ] 186 | }, 187 | stroke: '#000000', 188 | style: { 189 | color: 'yellow' 190 | } 191 | } 192 | } 193 | }, 194 | inputStyle: { 195 | backgroundColor: '#333', 196 | color: 'silver' 197 | }, 198 | labelStyle: { 199 | color: 'silver' 200 | } 201 | }, 202 | 203 | navigator: { 204 | handles: { 205 | backgroundColor: '#666', 206 | borderColor: '#AAA' 207 | }, 208 | outlineColor: '#CCC', 209 | maskFill: 'rgba(16, 16, 16, 0.5)', 210 | series: { 211 | color: '#7798BF', 212 | lineColor: '#A6C7ED' 213 | } 214 | }, 215 | 216 | scrollbar: { 217 | barBackgroundColor: { 218 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 219 | stops: [ 220 | [0.4, '#888'], 221 | [0.6, '#555'] 222 | ] 223 | }, 224 | barBorderColor: '#CCC', 225 | buttonArrowColor: '#CCC', 226 | buttonBackgroundColor: { 227 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 228 | stops: [ 229 | [0.4, '#888'], 230 | [0.6, '#555'] 231 | ] 232 | }, 233 | buttonBorderColor: '#CCC', 234 | rifleColor: '#FFF', 235 | trackBackgroundColor: { 236 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 237 | stops: [ 238 | [0, '#000'], 239 | [1, '#333'] 240 | ] 241 | }, 242 | trackBorderColor: '#666' 243 | }, 244 | 245 | // special colors for some of the 246 | legendBackgroundColor: 'rgba(0, 0, 0, 0.5)', 247 | background2: 'rgb(35, 35, 70)', 248 | dataLabelsColor: '#444', 249 | textColor: '#C0C0C0', 250 | maskColor: 'rgba(255,255,255,0.3)' 251 | }; 252 | 253 | // Apply the theme 254 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 255 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/themes/dark-green.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dark blue theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#DDDF0D", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 8 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 9 | chart: { 10 | backgroundColor: { 11 | linearGradient: [0, 0, 250, 500], 12 | stops: [ 13 | [0, 'rgb(48, 96, 48)'], 14 | [1, 'rgb(0, 0, 0)'] 15 | ] 16 | }, 17 | borderColor: '#000000', 18 | borderWidth: 2, 19 | className: 'dark-container', 20 | plotBackgroundColor: 'rgba(255, 255, 255, .1)', 21 | plotBorderColor: '#CCCCCC', 22 | plotBorderWidth: 1 23 | }, 24 | title: { 25 | style: { 26 | color: '#C0C0C0', 27 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 28 | } 29 | }, 30 | subtitle: { 31 | style: { 32 | color: '#666666', 33 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 34 | } 35 | }, 36 | xAxis: { 37 | gridLineColor: '#333333', 38 | gridLineWidth: 1, 39 | labels: { 40 | style: { 41 | color: '#A0A0A0' 42 | } 43 | }, 44 | lineColor: '#A0A0A0', 45 | tickColor: '#A0A0A0', 46 | title: { 47 | style: { 48 | color: '#CCC', 49 | fontWeight: 'bold', 50 | fontSize: '12px', 51 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 52 | 53 | } 54 | } 55 | }, 56 | yAxis: { 57 | gridLineColor: '#333333', 58 | labels: { 59 | style: { 60 | color: '#A0A0A0' 61 | } 62 | }, 63 | lineColor: '#A0A0A0', 64 | minorTickInterval: null, 65 | tickColor: '#A0A0A0', 66 | tickWidth: 1, 67 | title: { 68 | style: { 69 | color: '#CCC', 70 | fontWeight: 'bold', 71 | fontSize: '12px', 72 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 73 | } 74 | } 75 | }, 76 | tooltip: { 77 | backgroundColor: 'rgba(0, 0, 0, 0.75)', 78 | style: { 79 | color: '#F0F0F0' 80 | } 81 | }, 82 | toolbar: { 83 | itemStyle: { 84 | color: 'silver' 85 | } 86 | }, 87 | plotOptions: { 88 | line: { 89 | dataLabels: { 90 | color: '#CCC' 91 | }, 92 | marker: { 93 | lineColor: '#333' 94 | } 95 | }, 96 | spline: { 97 | marker: { 98 | lineColor: '#333' 99 | } 100 | }, 101 | scatter: { 102 | marker: { 103 | lineColor: '#333' 104 | } 105 | }, 106 | candlestick: { 107 | lineColor: 'white' 108 | } 109 | }, 110 | legend: { 111 | itemStyle: { 112 | font: '9pt Trebuchet MS, Verdana, sans-serif', 113 | color: '#A0A0A0' 114 | }, 115 | itemHoverStyle: { 116 | color: '#FFF' 117 | }, 118 | itemHiddenStyle: { 119 | color: '#444' 120 | } 121 | }, 122 | credits: { 123 | style: { 124 | color: '#666' 125 | } 126 | }, 127 | labels: { 128 | style: { 129 | color: '#CCC' 130 | } 131 | }, 132 | 133 | 134 | navigation: { 135 | buttonOptions: { 136 | symbolStroke: '#DDDDDD', 137 | hoverSymbolStroke: '#FFFFFF', 138 | theme: { 139 | fill: { 140 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 141 | stops: [ 142 | [0.4, '#606060'], 143 | [0.6, '#333333'] 144 | ] 145 | }, 146 | stroke: '#000000' 147 | } 148 | } 149 | }, 150 | 151 | // scroll charts 152 | rangeSelector: { 153 | buttonTheme: { 154 | fill: { 155 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 156 | stops: [ 157 | [0.4, '#888'], 158 | [0.6, '#555'] 159 | ] 160 | }, 161 | stroke: '#000000', 162 | style: { 163 | color: '#CCC', 164 | fontWeight: 'bold' 165 | }, 166 | states: { 167 | hover: { 168 | fill: { 169 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 170 | stops: [ 171 | [0.4, '#BBB'], 172 | [0.6, '#888'] 173 | ] 174 | }, 175 | stroke: '#000000', 176 | style: { 177 | color: 'white' 178 | } 179 | }, 180 | select: { 181 | fill: { 182 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 183 | stops: [ 184 | [0.1, '#000'], 185 | [0.3, '#333'] 186 | ] 187 | }, 188 | stroke: '#000000', 189 | style: { 190 | color: 'yellow' 191 | } 192 | } 193 | } 194 | }, 195 | inputStyle: { 196 | backgroundColor: '#333', 197 | color: 'silver' 198 | }, 199 | labelStyle: { 200 | color: 'silver' 201 | } 202 | }, 203 | 204 | navigator: { 205 | handles: { 206 | backgroundColor: '#666', 207 | borderColor: '#AAA' 208 | }, 209 | outlineColor: '#CCC', 210 | maskFill: 'rgba(16, 16, 16, 0.5)', 211 | series: { 212 | color: '#7798BF', 213 | lineColor: '#A6C7ED' 214 | } 215 | }, 216 | 217 | scrollbar: { 218 | barBackgroundColor: { 219 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 220 | stops: [ 221 | [0.4, '#888'], 222 | [0.6, '#555'] 223 | ] 224 | }, 225 | barBorderColor: '#CCC', 226 | buttonArrowColor: '#CCC', 227 | buttonBackgroundColor: { 228 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 229 | stops: [ 230 | [0.4, '#888'], 231 | [0.6, '#555'] 232 | ] 233 | }, 234 | buttonBorderColor: '#CCC', 235 | rifleColor: '#FFF', 236 | trackBackgroundColor: { 237 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 238 | stops: [ 239 | [0, '#000'], 240 | [1, '#333'] 241 | ] 242 | }, 243 | trackBorderColor: '#666' 244 | }, 245 | 246 | // special colors for some of the 247 | legendBackgroundColor: 'rgba(0, 0, 0, 0.5)', 248 | background2: 'rgb(35, 35, 70)', 249 | dataLabelsColor: '#444', 250 | textColor: '#C0C0C0', 251 | maskColor: 'rgba(255,255,255,0.3)' 252 | }; 253 | 254 | // Apply the theme 255 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 256 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/themes/dark-unica.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dark theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | // Load the fonts 7 | Highcharts.createElement('link', { 8 | href: 'http://fonts.googleapis.com/css?family=Unica+One', 9 | rel: 'stylesheet', 10 | type: 'text/css' 11 | }, null, document.getElementsByTagName('head')[0]); 12 | 13 | Highcharts.theme = { 14 | colors: ["#2b908f", "#90ee7e", "#f45b5b", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 15 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 16 | chart: { 17 | backgroundColor: { 18 | linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 }, 19 | stops: [ 20 | [0, '#2a2a2b'], 21 | [1, '#3e3e40'] 22 | ] 23 | }, 24 | style: { 25 | fontFamily: "'Unica One', sans-serif" 26 | }, 27 | plotBorderColor: '#606063' 28 | }, 29 | title: { 30 | style: { 31 | color: '#E0E0E3', 32 | textTransform: 'uppercase', 33 | fontSize: '20px' 34 | } 35 | }, 36 | subtitle: { 37 | style: { 38 | color: '#E0E0E3', 39 | textTransform: 'uppercase' 40 | } 41 | }, 42 | xAxis: { 43 | gridLineColor: '#707073', 44 | labels: { 45 | style: { 46 | color: '#E0E0E3' 47 | } 48 | }, 49 | lineColor: '#707073', 50 | minorGridLineColor: '#505053', 51 | tickColor: '#707073', 52 | title: { 53 | style: { 54 | color: '#A0A0A3' 55 | 56 | } 57 | } 58 | }, 59 | yAxis: { 60 | gridLineColor: '#707073', 61 | labels: { 62 | style: { 63 | color: '#E0E0E3' 64 | } 65 | }, 66 | lineColor: '#707073', 67 | minorGridLineColor: '#505053', 68 | tickColor: '#707073', 69 | tickWidth: 1, 70 | title: { 71 | style: { 72 | color: '#A0A0A3' 73 | } 74 | } 75 | }, 76 | tooltip: { 77 | backgroundColor: 'rgba(0, 0, 0, 0.85)', 78 | style: { 79 | color: '#F0F0F0' 80 | } 81 | }, 82 | plotOptions: { 83 | series: { 84 | dataLabels: { 85 | color: '#B0B0B3' 86 | }, 87 | marker: { 88 | lineColor: '#333' 89 | } 90 | }, 91 | boxplot: { 92 | fillColor: '#505053' 93 | }, 94 | candlestick: { 95 | lineColor: 'white' 96 | }, 97 | errorbar: { 98 | color: 'white' 99 | } 100 | }, 101 | legend: { 102 | itemStyle: { 103 | color: '#E0E0E3' 104 | }, 105 | itemHoverStyle: { 106 | color: '#FFF' 107 | }, 108 | itemHiddenStyle: { 109 | color: '#606063' 110 | } 111 | }, 112 | credits: { 113 | style: { 114 | color: '#666' 115 | } 116 | }, 117 | labels: { 118 | style: { 119 | color: '#707073' 120 | } 121 | }, 122 | 123 | drilldown: { 124 | activeAxisLabelStyle: { 125 | color: '#F0F0F3' 126 | }, 127 | activeDataLabelStyle: { 128 | color: '#F0F0F3' 129 | } 130 | }, 131 | 132 | navigation: { 133 | buttonOptions: { 134 | symbolStroke: '#DDDDDD', 135 | theme: { 136 | fill: '#505053' 137 | } 138 | } 139 | }, 140 | 141 | // scroll charts 142 | rangeSelector: { 143 | buttonTheme: { 144 | fill: '#505053', 145 | stroke: '#000000', 146 | style: { 147 | color: '#CCC' 148 | }, 149 | states: { 150 | hover: { 151 | fill: '#707073', 152 | stroke: '#000000', 153 | style: { 154 | color: 'white' 155 | } 156 | }, 157 | select: { 158 | fill: '#000003', 159 | stroke: '#000000', 160 | style: { 161 | color: 'white' 162 | } 163 | } 164 | } 165 | }, 166 | inputBoxBorderColor: '#505053', 167 | inputStyle: { 168 | backgroundColor: '#333', 169 | color: 'silver' 170 | }, 171 | labelStyle: { 172 | color: 'silver' 173 | } 174 | }, 175 | 176 | navigator: { 177 | handles: { 178 | backgroundColor: '#666', 179 | borderColor: '#AAA' 180 | }, 181 | outlineColor: '#CCC', 182 | maskFill: 'rgba(255,255,255,0.1)', 183 | series: { 184 | color: '#7798BF', 185 | lineColor: '#A6C7ED' 186 | }, 187 | xAxis: { 188 | gridLineColor: '#505053' 189 | } 190 | }, 191 | 192 | scrollbar: { 193 | barBackgroundColor: '#808083', 194 | barBorderColor: '#808083', 195 | buttonArrowColor: '#CCC', 196 | buttonBackgroundColor: '#606063', 197 | buttonBorderColor: '#606063', 198 | rifleColor: '#FFF', 199 | trackBackgroundColor: '#404043', 200 | trackBorderColor: '#404043' 201 | }, 202 | 203 | // special colors for some of the 204 | legendBackgroundColor: 'rgba(0, 0, 0, 0.5)', 205 | background2: '#505053', 206 | dataLabelsColor: '#B0B0B3', 207 | textColor: '#C0C0C0', 208 | contrastTextColor: '#F0F0F3', 209 | maskColor: 'rgba(255,255,255,0.3)' 210 | }; 211 | 212 | // Apply the theme 213 | Highcharts.setOptions(Highcharts.theme); 214 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/themes/gray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Gray theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#DDDF0D", "#7798BF", "#55BF3B", "#DF5353", "#aaeeee", "#ff0066", "#eeaaee", 8 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 9 | chart: { 10 | backgroundColor: { 11 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 12 | stops: [ 13 | [0, 'rgb(96, 96, 96)'], 14 | [1, 'rgb(16, 16, 16)'] 15 | ] 16 | }, 17 | borderWidth: 0, 18 | borderRadius: 0, 19 | plotBackgroundColor: null, 20 | plotShadow: false, 21 | plotBorderWidth: 0 22 | }, 23 | title: { 24 | style: { 25 | color: '#FFF', 26 | font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 27 | } 28 | }, 29 | subtitle: { 30 | style: { 31 | color: '#DDD', 32 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 33 | } 34 | }, 35 | xAxis: { 36 | gridLineWidth: 0, 37 | lineColor: '#999', 38 | tickColor: '#999', 39 | labels: { 40 | style: { 41 | color: '#999', 42 | fontWeight: 'bold' 43 | } 44 | }, 45 | title: { 46 | style: { 47 | color: '#AAA', 48 | font: 'bold 12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 49 | } 50 | } 51 | }, 52 | yAxis: { 53 | alternateGridColor: null, 54 | minorTickInterval: null, 55 | gridLineColor: 'rgba(255, 255, 255, .1)', 56 | minorGridLineColor: 'rgba(255,255,255,0.07)', 57 | lineWidth: 0, 58 | tickWidth: 0, 59 | labels: { 60 | style: { 61 | color: '#999', 62 | fontWeight: 'bold' 63 | } 64 | }, 65 | title: { 66 | style: { 67 | color: '#AAA', 68 | font: 'bold 12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 69 | } 70 | } 71 | }, 72 | legend: { 73 | itemStyle: { 74 | color: '#CCC' 75 | }, 76 | itemHoverStyle: { 77 | color: '#FFF' 78 | }, 79 | itemHiddenStyle: { 80 | color: '#333' 81 | } 82 | }, 83 | labels: { 84 | style: { 85 | color: '#CCC' 86 | } 87 | }, 88 | tooltip: { 89 | backgroundColor: { 90 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 91 | stops: [ 92 | [0, 'rgba(96, 96, 96, .8)'], 93 | [1, 'rgba(16, 16, 16, .8)'] 94 | ] 95 | }, 96 | borderWidth: 0, 97 | style: { 98 | color: '#FFF' 99 | } 100 | }, 101 | 102 | 103 | plotOptions: { 104 | series: { 105 | nullColor: '#444444' 106 | }, 107 | line: { 108 | dataLabels: { 109 | color: '#CCC' 110 | }, 111 | marker: { 112 | lineColor: '#333' 113 | } 114 | }, 115 | spline: { 116 | marker: { 117 | lineColor: '#333' 118 | } 119 | }, 120 | scatter: { 121 | marker: { 122 | lineColor: '#333' 123 | } 124 | }, 125 | candlestick: { 126 | lineColor: 'white' 127 | } 128 | }, 129 | 130 | toolbar: { 131 | itemStyle: { 132 | color: '#CCC' 133 | } 134 | }, 135 | 136 | navigation: { 137 | buttonOptions: { 138 | symbolStroke: '#DDDDDD', 139 | hoverSymbolStroke: '#FFFFFF', 140 | theme: { 141 | fill: { 142 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 143 | stops: [ 144 | [0.4, '#606060'], 145 | [0.6, '#333333'] 146 | ] 147 | }, 148 | stroke: '#000000' 149 | } 150 | } 151 | }, 152 | 153 | // scroll charts 154 | rangeSelector: { 155 | buttonTheme: { 156 | fill: { 157 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 158 | stops: [ 159 | [0.4, '#888'], 160 | [0.6, '#555'] 161 | ] 162 | }, 163 | stroke: '#000000', 164 | style: { 165 | color: '#CCC', 166 | fontWeight: 'bold' 167 | }, 168 | states: { 169 | hover: { 170 | fill: { 171 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 172 | stops: [ 173 | [0.4, '#BBB'], 174 | [0.6, '#888'] 175 | ] 176 | }, 177 | stroke: '#000000', 178 | style: { 179 | color: 'white' 180 | } 181 | }, 182 | select: { 183 | fill: { 184 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 185 | stops: [ 186 | [0.1, '#000'], 187 | [0.3, '#333'] 188 | ] 189 | }, 190 | stroke: '#000000', 191 | style: { 192 | color: 'yellow' 193 | } 194 | } 195 | } 196 | }, 197 | inputStyle: { 198 | backgroundColor: '#333', 199 | color: 'silver' 200 | }, 201 | labelStyle: { 202 | color: 'silver' 203 | } 204 | }, 205 | 206 | navigator: { 207 | handles: { 208 | backgroundColor: '#666', 209 | borderColor: '#AAA' 210 | }, 211 | outlineColor: '#CCC', 212 | maskFill: 'rgba(16, 16, 16, 0.5)', 213 | series: { 214 | color: '#7798BF', 215 | lineColor: '#A6C7ED' 216 | } 217 | }, 218 | 219 | scrollbar: { 220 | barBackgroundColor: { 221 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 222 | stops: [ 223 | [0.4, '#888'], 224 | [0.6, '#555'] 225 | ] 226 | }, 227 | barBorderColor: '#CCC', 228 | buttonArrowColor: '#CCC', 229 | buttonBackgroundColor: { 230 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 231 | stops: [ 232 | [0.4, '#888'], 233 | [0.6, '#555'] 234 | ] 235 | }, 236 | buttonBorderColor: '#CCC', 237 | rifleColor: '#FFF', 238 | trackBackgroundColor: { 239 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 240 | stops: [ 241 | [0, '#000'], 242 | [1, '#333'] 243 | ] 244 | }, 245 | trackBorderColor: '#666' 246 | }, 247 | 248 | // special colors for some of the demo examples 249 | legendBackgroundColor: 'rgba(48, 48, 48, 0.8)', 250 | background2: 'rgb(70, 70, 70)', 251 | dataLabelsColor: '#444', 252 | textColor: '#E0E0E0', 253 | maskColor: 'rgba(255,255,255,0.3)' 254 | }; 255 | 256 | // Apply the theme 257 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 258 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/themes/grid-light.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid-light theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | // Load the fonts 7 | Highcharts.createElement('link', { 8 | href: 'http://fonts.googleapis.com/css?family=Dosis:400,600', 9 | rel: 'stylesheet', 10 | type: 'text/css' 11 | }, null, document.getElementsByTagName('head')[0]); 12 | 13 | Highcharts.theme = { 14 | colors: ["#7cb5ec", "#f7a35c", "#90ee7e", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 15 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 16 | chart: { 17 | backgroundColor: null, 18 | style: { 19 | fontFamily: "Dosis, sans-serif" 20 | } 21 | }, 22 | title: { 23 | style: { 24 | fontSize: '16px', 25 | fontWeight: 'bold', 26 | textTransform: 'uppercase' 27 | } 28 | }, 29 | tooltip: { 30 | borderWidth: 0, 31 | backgroundColor: 'rgba(219,219,216,0.8)', 32 | shadow: false 33 | }, 34 | legend: { 35 | itemStyle: { 36 | fontWeight: 'bold', 37 | fontSize: '13px' 38 | } 39 | }, 40 | xAxis: { 41 | gridLineWidth: 1, 42 | labels: { 43 | style: { 44 | fontSize: '12px' 45 | } 46 | } 47 | }, 48 | yAxis: { 49 | minorTickInterval: 'auto', 50 | title: { 51 | style: { 52 | textTransform: 'uppercase' 53 | } 54 | }, 55 | labels: { 56 | style: { 57 | fontSize: '12px' 58 | } 59 | } 60 | }, 61 | plotOptions: { 62 | candlestick: { 63 | lineColor: '#404048' 64 | } 65 | }, 66 | 67 | 68 | // General 69 | background2: '#F0F0EA' 70 | 71 | }; 72 | 73 | // Apply the theme 74 | Highcharts.setOptions(Highcharts.theme); 75 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/themes/grid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ['#058DC7', '#50B432', '#ED561B', '#DDDF00', '#24CBE5', '#64E572', '#FF9655', '#FFF263', '#6AF9C4'], 8 | chart: { 9 | backgroundColor: { 10 | linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 }, 11 | stops: [ 12 | [0, 'rgb(255, 255, 255)'], 13 | [1, 'rgb(240, 240, 255)'] 14 | ] 15 | }, 16 | borderWidth: 2, 17 | plotBackgroundColor: 'rgba(255, 255, 255, .9)', 18 | plotShadow: true, 19 | plotBorderWidth: 1 20 | }, 21 | title: { 22 | style: { 23 | color: '#000', 24 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 25 | } 26 | }, 27 | subtitle: { 28 | style: { 29 | color: '#666666', 30 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 31 | } 32 | }, 33 | xAxis: { 34 | gridLineWidth: 1, 35 | lineColor: '#000', 36 | tickColor: '#000', 37 | labels: { 38 | style: { 39 | color: '#000', 40 | font: '11px Trebuchet MS, Verdana, sans-serif' 41 | } 42 | }, 43 | title: { 44 | style: { 45 | color: '#333', 46 | fontWeight: 'bold', 47 | fontSize: '12px', 48 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 49 | 50 | } 51 | } 52 | }, 53 | yAxis: { 54 | minorTickInterval: 'auto', 55 | lineColor: '#000', 56 | lineWidth: 1, 57 | tickWidth: 1, 58 | tickColor: '#000', 59 | labels: { 60 | style: { 61 | color: '#000', 62 | font: '11px Trebuchet MS, Verdana, sans-serif' 63 | } 64 | }, 65 | title: { 66 | style: { 67 | color: '#333', 68 | fontWeight: 'bold', 69 | fontSize: '12px', 70 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 71 | } 72 | } 73 | }, 74 | legend: { 75 | itemStyle: { 76 | font: '9pt Trebuchet MS, Verdana, sans-serif', 77 | color: 'black' 78 | 79 | }, 80 | itemHoverStyle: { 81 | color: '#039' 82 | }, 83 | itemHiddenStyle: { 84 | color: 'gray' 85 | } 86 | }, 87 | labels: { 88 | style: { 89 | color: '#99b' 90 | } 91 | }, 92 | 93 | navigation: { 94 | buttonOptions: { 95 | theme: { 96 | stroke: '#CCCCCC' 97 | } 98 | } 99 | } 100 | }; 101 | 102 | // Apply the theme 103 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 104 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/themes/sand-signika.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sand-Signika theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | // Load the fonts 7 | Highcharts.createElement('link', { 8 | href: 'http://fonts.googleapis.com/css?family=Signika:400,700', 9 | rel: 'stylesheet', 10 | type: 'text/css' 11 | }, null, document.getElementsByTagName('head')[0]); 12 | 13 | // Add the background image to the container 14 | Highcharts.wrap(Highcharts.Chart.prototype, 'getContainer', function (proceed) { 15 | proceed.call(this); 16 | this.container.style.background = 'url(http://www.highcharts.com/samples/graphics/sand.png)'; 17 | }); 18 | 19 | 20 | Highcharts.theme = { 21 | colors: ["#f45b5b", "#8085e9", "#8d4654", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 22 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 23 | chart: { 24 | backgroundColor: null, 25 | style: { 26 | fontFamily: "Signika, serif" 27 | } 28 | }, 29 | title: { 30 | style: { 31 | color: 'black', 32 | fontSize: '16px', 33 | fontWeight: 'bold' 34 | } 35 | }, 36 | subtitle: { 37 | style: { 38 | color: 'black' 39 | } 40 | }, 41 | tooltip: { 42 | borderWidth: 0 43 | }, 44 | legend: { 45 | itemStyle: { 46 | fontWeight: 'bold', 47 | fontSize: '13px' 48 | } 49 | }, 50 | xAxis: { 51 | labels: { 52 | style: { 53 | color: '#6e6e70' 54 | } 55 | } 56 | }, 57 | yAxis: { 58 | labels: { 59 | style: { 60 | color: '#6e6e70' 61 | } 62 | } 63 | }, 64 | plotOptions: { 65 | series: { 66 | shadow: true 67 | }, 68 | candlestick: { 69 | lineColor: '#404048' 70 | } 71 | }, 72 | 73 | // Highstock specific 74 | navigator: { 75 | xAxis: { 76 | gridLineColor: '#D0D0D8' 77 | } 78 | }, 79 | rangeSelector: { 80 | buttonTheme: { 81 | fill: 'white', 82 | stroke: '#C0C0C8', 83 | 'stroke-width': 1, 84 | states: { 85 | select: { 86 | fill: '#D0D0D8' 87 | } 88 | } 89 | } 90 | }, 91 | scrollbar: { 92 | trackBorderColor: '#C0C0C8' 93 | }, 94 | 95 | // General 96 | background2: '#E0E0E8' 97 | 98 | }; 99 | 100 | // Apply the theme 101 | Highcharts.setOptions(Highcharts.theme); 102 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Scripts/Highcharts-4.0.1/js/themes/skies.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Skies theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#514F78", "#42A07B", "#9B5E4A", "#72727F", "#1F949A", "#82914E", "#86777F", "#42A07B"], 8 | chart: { 9 | className: 'skies', 10 | borderWidth: 0, 11 | plotShadow: true, 12 | plotBackgroundImage: 'http://www.highcharts.com/demo/gfx/skies.jpg', 13 | plotBackgroundColor: { 14 | linearGradient: [0, 0, 250, 500], 15 | stops: [ 16 | [0, 'rgba(255, 255, 255, 1)'], 17 | [1, 'rgba(255, 255, 255, 0)'] 18 | ] 19 | }, 20 | plotBorderWidth: 1 21 | }, 22 | title: { 23 | style: { 24 | color: '#3E576F', 25 | font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 26 | } 27 | }, 28 | subtitle: { 29 | style: { 30 | color: '#6D869F', 31 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 32 | } 33 | }, 34 | xAxis: { 35 | gridLineWidth: 0, 36 | lineColor: '#C0D0E0', 37 | tickColor: '#C0D0E0', 38 | labels: { 39 | style: { 40 | color: '#666', 41 | fontWeight: 'bold' 42 | } 43 | }, 44 | title: { 45 | style: { 46 | color: '#666', 47 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 48 | } 49 | } 50 | }, 51 | yAxis: { 52 | alternateGridColor: 'rgba(255, 255, 255, .5)', 53 | lineColor: '#C0D0E0', 54 | tickColor: '#C0D0E0', 55 | tickWidth: 1, 56 | labels: { 57 | style: { 58 | color: '#666', 59 | fontWeight: 'bold' 60 | } 61 | }, 62 | title: { 63 | style: { 64 | color: '#666', 65 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 66 | } 67 | } 68 | }, 69 | legend: { 70 | itemStyle: { 71 | font: '9pt Trebuchet MS, Verdana, sans-serif', 72 | color: '#3E576F' 73 | }, 74 | itemHoverStyle: { 75 | color: 'black' 76 | }, 77 | itemHiddenStyle: { 78 | color: 'silver' 79 | } 80 | }, 81 | labels: { 82 | style: { 83 | color: '#3E576F' 84 | } 85 | } 86 | }; 87 | 88 | // Apply the theme 89 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 90 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/ScriptsAndReferences/DeployDashboardTasks.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory=$true)] [string]$FrontEndStorageConnectionString, 3 | [Parameter(Mandatory=$true)] [string]$FrontEndLegacyDBConnectionString, 4 | [Parameter(Mandatory=$true)] [string]$SubscriptionId, 5 | [Parameter(Mandatory=$false)][string]$FrontEndCloudServiceName, 6 | [Parameter(Mandatory=$false)][string]$TrafficManagerProfileName, 7 | [Parameter(Mandatory=$false)][string]$ProdManagementCertName, 8 | [Parameter(Mandatory=$true)] [string]$PingdomUserName, 9 | [Parameter(Mandatory=$true)] [string]$PingdomPassword, 10 | [Parameter(Mandatory=$true)] [string]$PingdomAppKey, 11 | [Parameter(Mandatory=$true)] [string]$DashboardStorageConnectionString, 12 | [Parameter(Mandatory=$true)] [string]$DashboardStorageContainerName, 13 | [Parameter(Mandatory=$true)] [string]$WorkingDir, 14 | [Parameter(Mandatory=$true)] [string]$CurrentUserPassword, 15 | [Parameter(Mandatory=$false)][string]$EnvName, 16 | [Parameter(Mandatory=$false)][string]$ConsolidatedSearchServiceEndPoint 17 | ) 18 | 19 | $time = [System.DateTime]::Now 20 | $time = $time.AddMinutes(-($time.Minute)) 21 | 22 | function CreateTask() { 23 | param([string]$taskName, [string]$argument, [int]$interval) 24 | 25 | $settings = New-ScheduledTaskSettingsSet -MultipleInstances P 26 | $Action = New-ScheduledTaskAction -Execute "$WorkingDir\galops.exe" -WorkingDirectory $WorkingDir -Argument $argument 27 | $trigger = New-ScheduledTaskTrigger -Once -At $time -RepetitionDuration ([Timespan]::MaxValue) -RepetitionInterval (New-TimeSpan -Minutes $interval) 28 | Unregister-ScheduledTask -TaskName $taskName -TaskPath "\NuGetDashboard\$EnvName\" -ErrorAction SilentlyContinue -Confirm:$false 29 | Register-ScheduledTask -TaskName $taskName -TaskPath "\NuGetDashboard\$EnvName\" -User $env:USERDOMAIN\$env:USERNAME -Password $CurrentUserPassword -Action $Action -Trigger $trigger -Settings $settings 30 | } 31 | 32 | # Database related tasks 33 | CreateTask "CreateTrendingOverviewReport" "cshr -db `"$FrontEndLegacyDBConnectionString`" -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName" 60 34 | 35 | # Enable or remove based on the outcome of: 36 | # https://github.com/NuGet/Engineering/issues/291 37 | # CreateTask "CreateDataBaseOverviewReport" "cdrt -db `"$FrontEndLegacyDBConnectionString`" -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName" 30 38 | # CreateTask "CreateDataBase24HourDetailedReport" "cddrt -db `"$FrontEndLegacyDBConnectionString`" -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName -n 24" 30 39 | 40 | # ElmahError related tasks 41 | CreateTask "CreateElmaherrorOverviewReport" "ceeort -ea `"$FrontEndStorageConnectionString`" -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName" 60 42 | CreateTask "CreateElmaherror1HourDetailedReport" "ceedrt -ea `"$FrontEndStorageConnectionString`" -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName -n 1" 30 43 | CreateTask "CreateElmaherror6HourDetailedReport" "ceedrt -ea `"$FrontEndStorageConnectionString`" -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName -n 6" 30 44 | CreateTask "CreateElmaherror24HourDetailedReport" "ceedrt -ea `"$FrontEndStorageConnectionString`" -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName -n 24" 30 45 | 46 | # Pingdom tasks 47 | CreateTask "CreatePingdomHourlyReport" "cpdwr -user `"$PingdomUserName`" -password `"$PingdomPassword`" -appkey `"$PingdomAppKey`" -frequency Hourly -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName" 60 48 | CreateTask "CreatePingdomServiceDisruptionReport" "psdrt -user `"$PingdomUserName`" -password `"$PingdomPassword`" -appkey `"$PingdomAppKey`" -n 1 -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName" 60 49 | 50 | # SearchService tasks 51 | CreateTask "CreateConsolidatedSearchIndexingStatusReportTask" "ccsisrt -db `"$FrontEndLegacyDBConnectionString`" -se $ConsolidatedSearchServiceEndPoint -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName -alsev1 120 -alsev2 30 -disn -disic" 10 52 | 53 | # Misc 54 | CreateTask "CreateRequestsCountOverviewReport" "crphrt -iis `"$FrontEndStorageConnectionString`" -retry 3 -servicename $FrontEndCloudServiceName -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName" 60 55 | CreateTask "CreateTrafficManagerStatusOverviewReport" "ctmort -id $SubscriptionId -name $TrafficManagerProfileName -cername $ProdManagementCertName -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName" 5 56 | CreateTask "CreateV2GalleryInstanceCountReport" "ccsdrt -id $SubscriptionId -name $FrontEndCloudServiceName -cername $ProdManagementCertName -st `"$DashboardStorageConnectionString`" -ct $DashboardStorageContainerName" 60 57 | 58 | # Clean-up 59 | CreateTask "IISLogCleanUpTask" "clean" 1440 60 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/ScriptsAndReferences/LoadTestReport.htm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NuGet/NuGet.Services.Dashboard/000734d70fe984b351d09d08fc92debf280ae96b/NuGet.Services.Dashboard.Operations/ScriptsAndReferences/LoadTestReport.htm -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/AzureManagementTasks/CreateTrafficManagerStatusOverviewReportTask.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using Newtonsoft.Json.Linq; 4 | using NuGetGallery.Operations.Common; 5 | using System; 6 | using System.Net; 7 | using System.Security.Cryptography.X509Certificates; 8 | using System.Xml; 9 | 10 | 11 | namespace NuGetGallery.Operations 12 | { 13 | [Command("CreateTrafficManagerStatusOverviewReportTask", "Creates report for highlevel status of Traffic manager", AltName = "ctmort")] 14 | public class CreateTrafficManagerStatusOverviewReportTask : StorageTask 15 | { 16 | [Option("SubsciptionId", AltName = "id")] 17 | public string SubscriptionId { get; set; } 18 | 19 | [Option("ProfileName", AltName = "name")] 20 | public string ProfileName { get; set; } 21 | 22 | [Option("CertificateName", AltName = "cername")] 23 | public string CertificateName { get; set; } 24 | public override void ExecuteCommand() 25 | { 26 | X509Certificate cert = X509Certificate.CreateFromCertFile(CertificateName); 27 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format("https://management.core.windows.net/{0}/services/WATM/profiles/{1}/definitions", SubscriptionId, ProfileName)); 28 | request.ClientCertificates.Add(cert); 29 | request.Headers.Add("x-ms-version: 2014-02-01"); 30 | request.PreAuthenticate = true; 31 | request.Method = "GET"; 32 | var response = request.GetResponse(); 33 | //Schema of the response would be as specified in http://msdn.microsoft.com/en-us/library/azure/hh758251.aspx 34 | using (var reader = new StreamReader(response.GetResponseStream())) 35 | { 36 | var responseContent = reader.ReadToEnd(); 37 | Console.WriteLine(responseContent); 38 | 39 | var responseDoc = new XmlDocument(); 40 | responseDoc.LoadXml(responseContent); 41 | var endpointNodes = responseDoc.GetElementsByTagName("Endpoint", "http://schemas.microsoft.com/windowsazure"); 42 | //Endpoint Structure 43 | // 44 | // Name 45 | // Enabled 46 | // CloudService 47 | // North Central US 48 | // Online 49 | // 1 50 | // 51 | 52 | var endpointValues = new List>(); 53 | foreach (XmlNode endpointNode in endpointNodes) 54 | { 55 | string endpointName = endpointNode["DomainName"].InnerText; 56 | string endpointStatus = endpointNode["MonitorStatus"].InnerText; 57 | Console.WriteLine(string.Format("Endpoint name {0}, status {1}", endpointName, endpointStatus)); 58 | endpointValues.Add(Tuple.Create(endpointName, endpointStatus)); 59 | if (!endpointStatus.Equals("Online", StringComparison.OrdinalIgnoreCase)) 60 | { 61 | new SendAlertMailTask 62 | { 63 | AlertSubject = string.Format("Error: Traffic manager endpoint alert activated for {0}", endpointName), 64 | Details = string.Format("The status of the endpoint {0} monitoring by traffic manager {1} is {2}", endpointName, ProfileName, endpointStatus), 65 | AlertName = "Error: Alert for TrafficManagerEndpoint", 66 | Component = "TrafficManager", 67 | Level = "Error" 68 | }.ExecuteCommand(); 69 | } 70 | 71 | } 72 | JArray reportObject = ReportHelpers.GetJson(endpointValues); 73 | ReportHelpers.CreateBlob(StorageAccount, "TrafficManagerStatus.json", ContainerName, "application/json", ReportHelpers.ToStream(reportObject)); 74 | } 75 | } 76 | 77 | 78 | 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/CreateStatsMonthlyReport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NuGetGallery.Operations.Tasks.DashBoardTasks 8 | { 9 | class CreateStatsMonthlyReport 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/CreateWADPerformanceDiagnosticsReportTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Script.Serialization; 3 | using Microsoft.WindowsAzure.Storage; 4 | using Microsoft.WindowsAzure.Storage.Table; 5 | using NuGetGallery.Operations.Common; 6 | 7 | 8 | namespace NuGetGallery.Operations 9 | { 10 | [Command("CreatePerfUsageReportTask", "Create performance counter usage report task", AltName = "cpurt")] 11 | public class CreateWADPerformanceDiagnosticsReportTask : StorageTask 12 | { 13 | [Option("PerfCounterTableStorageAccount", AltName = "table")] 14 | public string PerfCounterTableStorageAccount { get; set; } 15 | 16 | [Option("PerfCounterName", AltName = "counter")] 17 | public string PerfCounterName { get; set; } 18 | 19 | [Option("frequencyInMin", AltName = "f")] 20 | public int frequencyInMin { get; set; } 21 | 22 | [Option("ServiceName", AltName = "name")] 23 | public string ServiceName { get; set; } 24 | 25 | public override void ExecuteCommand() 26 | { 27 | string DeployId = new JavaScriptSerializer().Deserialize(ReportHelpers.Load(StorageAccount, "DeploymentId_" + ServiceName + ".json", ContainerName)); 28 | CloudStorageAccount storageAccount = CloudStorageAccount.Parse(PerfCounterTableStorageAccount); 29 | CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); 30 | CloudTable table = tableClient.GetTableReference("WAD"+DeployId+"PT5MRTable"); 31 | int count = 0; 32 | double sum = 0; 33 | 34 | TableQuery rangeQuery = new TableQuery().Where(TableQuery.CombineFilters( 35 | TableQuery.GenerateFilterConditionForDate("Timestamp", QueryComparisons.GreaterThan, DateTime.UtcNow.AddMinutes(-frequencyInMin)), 36 | TableOperators.And, 37 | TableQuery.GenerateFilterCondition("CounterName", QueryComparisons.Equal, PerfCounterName))); 38 | 39 | foreach (dataEntity entity in table.ExecuteQuery(rangeQuery)) 40 | { 41 | count++; 42 | sum += entity.Total / entity.Count; 43 | } 44 | 45 | ReportHelpers.AppendDatatoBlob(StorageAccount, ServiceName + PerfCounterName + string.Format("{0:MMdd}", DateTime.Now) + ".json", new Tuple(String.Format("{0:HH:mm}", DateTime.Now), (sum/count).ToString("F")), 24*60 / frequencyInMin, ContainerName); 46 | 47 | } 48 | 49 | private class dataEntity : TableEntity 50 | { 51 | public int Count { get; set; } 52 | public double Total { get; set; } 53 | 54 | public string CounterName { get; set; } 55 | 56 | public string Role { get; set; } 57 | 58 | public string DepolymentId { get; set; } 59 | 60 | public dataEntity() { } 61 | 62 | public dataEntity(string PartitionKey, string RowKey) 63 | { 64 | this.PartitionKey = PartitionKey; 65 | this.RowKey = RowKey; 66 | } 67 | } 68 | 69 | 70 | 71 | } 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/DatabaseTasks/CreateDatabaseSizeReportTask.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Data.SqlClient; 4 | using NuGetGallery.Operations.Common; 5 | using AnglicanGeek.DbExecutor; 6 | using System; 7 | using System.Web.Script.Serialization; 8 | using NuGet.Services.Dashboard.Common; 9 | 10 | 11 | namespace NuGetGallery.Operations 12 | { 13 | [Command("CreateDatabaseSizeReportTask", "Creates database size report", AltName = "cdsrt")] 14 | public class CreateDatabaseSizeReportTask : StorageTask 15 | { 16 | private string SqlQueryForDbSize = @"SELECT CONVERT(int,SUM(reserved_page_count)*8.0/1024) FROM sys.dm_db_partition_stats"; 17 | private string SqlQueryForEdition = @"SELECT DATABASEPROPERTYEX (DB_NAME(), 'Edition') AS Edition"; 18 | 19 | private string SqlQueryForMaxSize = @"SELECT (CONVERT(bigint, DATABASEPROPERTYEX (DB_NAME(), 'MaxSizeInBytes')) / (1024*1024)) AS MaxSizeInMB"; 20 | 21 | 22 | //[Option("Connection string to the primary database", AltName = "pdb")] 23 | //public SqlConnectionStringBuilder PrimaryConnectionString { get; set; } 24 | 25 | [Option("Connection string to the legacy database", AltName = "ldb")] 26 | public SqlConnectionStringBuilder LegacyConnectionString { get; set; } 27 | 28 | [Option("Connection string to the warehouse database", AltName = "wdb")] 29 | public SqlConnectionStringBuilder WarehouseConnectionString { get; set; } 30 | 31 | 32 | 33 | public override void ExecuteCommand() 34 | { 35 | JavaScriptSerializer js = new JavaScriptSerializer(); 36 | AlertThresholds thresholdValues = js.Deserialize(ReportHelpers.Load(StorageAccount, "Configuration.AlertThresholds.json", ContainerName)); 37 | int error = thresholdValues.DatabaseSizePercentErrorThreshold; 38 | int warning = thresholdValues.DatabaseSizePercentWarningThreshold; 39 | 40 | List dbSizeDetails = new List(); 41 | // dbSizeDetails.Add(GetDataSize(PrimaryConnectionString.ConnectionString,threshold)); 42 | dbSizeDetails.Add(GetDataSize(LegacyConnectionString.ConnectionString, error,warning)); 43 | dbSizeDetails.Add(GetDataSize(WarehouseConnectionString.ConnectionString, error,warning)); 44 | 45 | var json = js.Serialize(dbSizeDetails); 46 | ReportHelpers.CreateBlob(StorageAccount, "DBSize.json", ContainerName, "application/json",ReportHelpers.ToStream(json)); 47 | } 48 | 49 | private DatabaseSize GetDataSize(string connectionString,int error, int warning) 50 | { 51 | 52 | using (var sqlConnection = new SqlConnection(connectionString)) 53 | { 54 | using (var dbExecutor = new SqlExecutor(sqlConnection)) 55 | { 56 | sqlConnection.Open(); 57 | int sizeInMb = dbExecutor.Query(SqlQueryForDbSize).SingleOrDefault(); 58 | Int64 maxSizeInMb = dbExecutor.Query(SqlQueryForMaxSize).SingleOrDefault(); 59 | double percentUsed = (sizeInMb/maxSizeInMb)*100; 60 | string edition = dbExecutor.Query(SqlQueryForEdition).SingleOrDefault(); 61 | string dbName = Util.GetDbName(connectionString); 62 | 63 | if (percentUsed > error) 64 | { 65 | new SendAlertMailTask 66 | { 67 | AlertSubject = string.Format("Error: SQL Azure database size alert activated for {0}",dbName), 68 | Details = string.Format("DB Size excced the Error threshold percent.Current Used % {0}, Threshold % : {1}", percentUsed, error ), 69 | AlertName = "Error: SQL Azure DB alert for database size limit", 70 | Component = string.Format("SQL Azure database-{0}",dbName), 71 | Level = "Error" 72 | }.ExecuteCommand(); 73 | } 74 | else if (percentUsed > warning) 75 | { 76 | new SendAlertMailTask 77 | { 78 | AlertSubject = string.Format("Warning: SQL Azure database size alert activated for {0}", dbName), 79 | Details = string.Format("DB Size excced the Warning threshold percent.Current Used % {0}, Threshold % : {1}", percentUsed, warning), 80 | AlertName = "Warning: SQL Azure DB alert for database size limit", 81 | Component = string.Format("SQL Azure database-{0}", dbName), 82 | Level = "Warning" 83 | }.ExecuteCommand(); 84 | } 85 | 86 | return new DatabaseSize(dbName, sizeInMb, maxSizeInMb, edition); 87 | } 88 | } 89 | } 90 | 91 | 92 | } 93 | } 94 | 95 | 96 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/IssLogCleanUptask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace NuGetGallery.Operations.Tasks.DashBoardTasks 5 | { 6 | [Command("IssCleanUpTask", "clean up old iss log in current dir", AltName = "clean")] 7 | class IssLogCleanUptask : OpsTask 8 | { 9 | public override void ExecuteCommand() 10 | { 11 | var dirs = Directory.EnumerateDirectories(Environment.CurrentDirectory, "*.log"); 12 | var files = Directory.EnumerateFiles(Environment.CurrentDirectory, "*.log"); 13 | 14 | foreach (string file in files) 15 | { 16 | try 17 | { 18 | string filename = file.Substring(Environment.CurrentDirectory.Length); 19 | string date = filename.Substring("\\u_ex".Length, "yyMMddHH".Length); 20 | DateTime logdate = new DateTime(); 21 | logdate = DateTime.ParseExact(date, "yyMMddHH", null); 22 | if (logdate < DateTime.UtcNow.AddHours(-48)) File.Delete(file); 23 | } 24 | catch (Exception e) 25 | { 26 | Console.WriteLine("clean up error: {0}", e.Message); 27 | } 28 | } 29 | foreach (string dir in dirs) 30 | { 31 | try 32 | { 33 | string date = RemoveLetter(dir.Substring(Environment.CurrentDirectory.Length)); 34 | DateTime logdate = new DateTime(); 35 | logdate = DateTime.ParseExact(date, "yyMMddHH", null); 36 | if (logdate < DateTime.UtcNow.AddHours(-48)) Directory.Delete(dir, true); 37 | } 38 | catch (Exception e) 39 | { 40 | Console.WriteLine("clean up error: {0}", e.Message); 41 | } 42 | } 43 | } 44 | private string RemoveLetter(string src) 45 | { 46 | if (src.Equals("")) return src; 47 | if (char.IsDigit(src[0])) return src[0] + RemoveLetter(src.Substring(1)); 48 | else return RemoveLetter(src.Substring(1)); 49 | } 50 | } 51 | } 52 | 53 | 54 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/PingdomTasks/CreatePingdomWeeklyAndHourlyReportTask.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Data; 4 | using System.Data.SqlClient; 5 | using System.IO; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Microsoft.WindowsAzure.Storage; 9 | using Microsoft.WindowsAzure.Storage.Blob; 10 | using Newtonsoft.Json.Linq; 11 | using NuGetGallery.Operations.Common; 12 | using AnglicanGeek.DbExecutor; 13 | using System; 14 | using System.Net; 15 | using System.Web.Script.Serialization; 16 | 17 | namespace NuGetGallery.Operations 18 | { 19 | [Command("createpingdomweeklyreport", "Creates report for average response time for all the pingdom checks for fhe last 7 days/hours.", AltName = "cpdwr")] 20 | public class CreatePingdomWeeklyAndHourlyReportTask : StorageTask 21 | { 22 | [Option("PingdomUserName", AltName = "user")] 23 | public string UserName { get; set; } 24 | 25 | [Option("PingdomUserpassword", AltName = "password")] 26 | public string Password { get; set; } 27 | 28 | [Option("PingdomAppKey", AltName = "appkey")] 29 | public string AppKey { get; set; } 30 | 31 | [Option("Frequency", AltName = "f")] 32 | public string Frequency { get; set; } 33 | 34 | 35 | public override void ExecuteCommand() 36 | { 37 | NetworkCredential nc = new NetworkCredential(UserName, Password); 38 | WebRequest request = WebRequest.Create("https://api.pingdom.com/api/2.0/checks"); 39 | request.Credentials = nc; 40 | request.Headers.Add(AppKey); 41 | request.PreAuthenticate = true; 42 | request.Method = "GET"; 43 | WebResponse respose = request.GetResponse(); 44 | using (var reader = new StreamReader(respose.GetResponseStream())) 45 | { 46 | JavaScriptSerializer js = new JavaScriptSerializer(); 47 | var objects = js.Deserialize(reader.ReadToEnd()); 48 | foreach (var o in objects["checks"]) 49 | { 50 | List> summary = GetCheckSummaryAvgForSpecifiedTimeSpan(o["id"]); 51 | JArray reportObject = ReportHelpers.GetJson(summary); 52 | string checkAlias = o["name"].ToString(); 53 | checkAlias = checkAlias.Replace(" ","."); 54 | checkAlias = checkAlias.Replace("(", "").Replace(")", ""); 55 | ReportHelpers.CreateBlob(StorageAccount, checkAlias + Frequency + "Report.json", ContainerName, "application/json", ReportHelpers.ToStream(reportObject)); 56 | } 57 | } 58 | } 59 | 60 | private List> GetCheckSummaryAvgForSpecifiedTimeSpan(int checkId) 61 | { 62 | int i = 7; 63 | List> summaryValues = new List>(); 64 | while (i >= 1) 65 | { 66 | //Get the average response time for the past 7 hours/weeks based on the frequency. 67 | long fromTime = 0; 68 | long toTime = 0; 69 | if (Frequency.Equals("Hourly", StringComparison.OrdinalIgnoreCase)) 70 | { 71 | fromTime = UnixTimeStampUtility.GetUnixTimestampSeconds(DateTime.UtcNow.Subtract(new TimeSpan(0, i, 0, 0))); 72 | toTime = UnixTimeStampUtility.GetUnixTimestampSeconds(DateTime.UtcNow.Subtract(new TimeSpan(0, i-1, 0, 0))); 73 | } 74 | else 75 | { 76 | fromTime = UnixTimeStampUtility.GetUnixTimestampSeconds(DateTime.UtcNow.Subtract(new TimeSpan(i, 0, 0, 0))); 77 | toTime = UnixTimeStampUtility.GetUnixTimestampSeconds(DateTime.UtcNow.Subtract(new TimeSpan(i - 1, 0, 0, 0))); 78 | } 79 | NetworkCredential nc = new NetworkCredential(UserName, Password); 80 | WebRequest request = WebRequest.Create(string.Format("https://api.pingdom.com/api/2.0/summary.average/{0}?from={1}&to={2}", checkId, fromTime, toTime)); 81 | request.Credentials = nc; 82 | request.Headers.Add(AppKey); 83 | request.PreAuthenticate = true; 84 | request.Method = "GET"; 85 | WebResponse respose = request.GetResponse(); 86 | using (var reader = new StreamReader(respose.GetResponseStream())) 87 | { 88 | JavaScriptSerializer js = new JavaScriptSerializer(); 89 | var summaryObject = js.Deserialize(reader.ReadToEnd()); 90 | foreach (var summary in summaryObject["summary"]) 91 | { 92 | foreach (var status in summary.Value) 93 | { 94 | //Get the average response time and store it to the JSON object. 95 | if (status.Key == "avgresponse") 96 | { 97 | if(Frequency.Equals("Hourly",StringComparison.OrdinalIgnoreCase)) 98 | summaryValues.Add(new Tuple(String.Format("{0:HH:mm}", UnixTimeStampUtility.DateTimeFromUnixTimestampSeconds(fromTime).ToLocalTime()), status.Value.ToString())); 99 | else 100 | summaryValues.Add(new Tuple(String.Format("{0:MM/dd}", UnixTimeStampUtility.DateTimeFromUnixTimestampSeconds(fromTime).ToLocalTime()), status.Value.ToString())); 101 | } 102 | } 103 | } 104 | } 105 | i--; 106 | } 107 | return summaryValues; 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/SearchServiceTasks/CreateSearchCpuMemStatusReportTask.cs: -------------------------------------------------------------------------------- 1 | using NuGet.Services.Dashboard.Common; 2 | using NuGetGallery.Operations.Common; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Web.Script.Serialization; 11 | 12 | namespace NuGetGallery.Operations.Tasks.DashBoardTasks 13 | { 14 | [Command("CreateSearchCpuMemStatusReportTask", "Creates the report for CPU and Mem usage of search service.", AltName = "cscmsrt")] 15 | class CreateSearchCpuMemStatusReportTask : StorageTask 16 | { 17 | [Option("SearchEndPoint", AltName = "se")] 18 | public string SearchEndPoint { get; set; } 19 | 20 | [Option("SearchAdminUserName", AltName = "sa")] 21 | public string SearchAdminUserName { get; set; } 22 | 23 | [Option("SearchAdminkey", AltName = "sk")] 24 | public string SearchAdminKey { get; set; } 25 | 26 | public override void ExecuteCommand() 27 | { 28 | NetworkCredential nc = new NetworkCredential(SearchAdminUserName, SearchAdminKey); 29 | WebRequest request = WebRequest.Create(SearchEndPoint); 30 | AlertThresholds thresholdValues = new JavaScriptSerializer().Deserialize(ReportHelpers.Load(StorageAccount, "Configuration.AlertThresholds.json", ContainerName)); 31 | request.Credentials = nc; 32 | request.PreAuthenticate = true; 33 | request.Method = "GET"; 34 | WebResponse respose = request.GetResponse(); 35 | using (var reader = new StreamReader(respose.GetResponseStream())) 36 | { 37 | JavaScriptSerializer js = new JavaScriptSerializer(); 38 | var objects = js.Deserialize(reader.ReadToEnd()); 39 | var process_info = objects["process"]; 40 | double cpusecond = (double)process_info["cpuSeconds"]; 41 | long memory = (long)process_info["virtualMemorySize"]; 42 | int cpuUsage = 0; 43 | int memUsage = 0; 44 | 45 | if (cpuUsage > thresholdValues.SearchCpuPercentErrorThreshold) 46 | { 47 | new SendAlertMailTask 48 | { 49 | AlertSubject = "Error: Search Service Alert activated for cpu usage", 50 | Details = string.Format("Search service process cpu usage is above Error threshold: {0}% , it's {1}% ", thresholdValues.SearchCpuPercentErrorThreshold, cpuUsage.ToString()), 51 | AlertName = "Error: Alert for Serach CPU Usage", 52 | Component = "SearchService", 53 | Level = "Error" 54 | }.ExecuteCommand(); 55 | } 56 | else if (cpuUsage > thresholdValues.SearchCpuPercentWarningThreshold) 57 | { 58 | new SendAlertMailTask 59 | { 60 | AlertSubject = "Warning: Search Service Alert activated for cpu usage", 61 | Details = string.Format("Search service process cpu usage is above Warning threshold: {0}% , it's {1}% ", thresholdValues.SearchCpuPercentWarningThreshold, cpuUsage.ToString()), 62 | AlertName = "Warning: Alert for Serach CPU Usage", 63 | Component = "SearchService", 64 | Level = "Warning" 65 | }.ExecuteCommand(); 66 | } 67 | 68 | if (memUsage > thresholdValues.SearchMemErrorThresholdInGb*(1<<30)) 69 | { 70 | new SendAlertMailTask 71 | { 72 | AlertSubject = "Error: Search Service Alert activated for memory usage", 73 | Details = string.Format("Search service process memory usage is above Error threshold: {0}% GB, it's {1}% Byte ", thresholdValues.SearchMemErrorThresholdInGb, memUsage.ToString()), 74 | AlertName = "Error: Alert for Serach Memory Usage", 75 | Component = "SearchService", 76 | Level = "Error" 77 | }.ExecuteCommand(); 78 | } 79 | else if (memUsage > thresholdValues.SearchMemWarningThresholdInGb * (1 << 30)) 80 | { 81 | new SendAlertMailTask 82 | { 83 | AlertSubject = "Warning: Search Service Alert activated for memory usage", 84 | Details = string.Format("Search service process memory usage is above Warning threshold {0}% GB, it's {1}% Byte ", thresholdValues.SearchMemWarningThresholdInGb, memUsage.ToString()), 85 | AlertName = "Warning: Alert for Serach Memory Usage", 86 | Component = "SearchService", 87 | Level = "Warning" 88 | }.ExecuteCommand(); 89 | } 90 | ReportHelpers.AppendDatatoBlob(StorageAccount, "SearchCpuUsage" + string.Format("{0:MMdd}", DateTime.Now) + "HourlyReport.json", new Tuple(string.Format("{0:HH-mm}", DateTime.Now), cpusecond.ToString()), 24, ContainerName); 91 | ReportHelpers.AppendDatatoBlob(StorageAccount, "SearchMemUsage" + string.Format("{0:MMdd}", DateTime.Now) + "HourlyReport.json", new Tuple(string.Format("{0:HH-mm}", DateTime.Now), memory.ToString()), 24, ContainerName); 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/TrendingTasks/CreateStatsHourlyReportTask.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Data; 4 | using System.Data.SqlClient; 5 | using System.IO; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Microsoft.WindowsAzure.Storage; 9 | using Microsoft.WindowsAzure.Storage.Blob; 10 | using Newtonsoft.Json.Linq; 11 | using NuGetGallery.Operations.Common; 12 | using AnglicanGeek.DbExecutor; 13 | using System; 14 | 15 | namespace NuGetGallery.Operations 16 | { 17 | [Command("createstatshourlyreport", "Creates the stats (uploads,downloads and users) hoourly report for Gallery ", AltName = "cshr")] 18 | public class CreateStatsHourlyReportTask : DatabaseAndStorageTask 19 | { 20 | private string SqlQueryForUploads = @"SELECT Count (*) FROM [dbo].[Packages] where [Created] >= '{0}' AND [Created] <= '{1}'"; 21 | private string SqlQueryForUniqueUploads = @"SELECT COUNT(*) 22 | From 23 | ( 24 | SELECT Id 25 | FROM [dbo].Packages 26 | INNER JOIN PackageRegistrations ON Packages.PackageRegistrationKey = PackageRegistrations.[Key] 27 | GROUP BY PackageRegistrations.Id 28 | HAVING MIN([Created]) >= '{0}' AND MIN([Created]) <= '{1}') data"; 29 | 30 | private string SqlQueryForUsers = @"SELECT Count (*) FROM [dbo].[Users] where [CreatedUtc] >= '{0}' AND [CreatedUtc] <= '{1}'"; 31 | private DateTime startingTime; //initialize start date to the NuGet initial release time. 32 | 33 | public override void ExecuteCommand() 34 | { 35 | CreateWeeklyStatReportFor(ConnectionString.ConnectionString, SqlQueryForUploads, "Uploads" + string.Format("{0:MMdd}", DateTime.Now)); 36 | CreateWeeklyStatReportFor(ConnectionString.ConnectionString, SqlQueryForUniqueUploads, "UniqueUploads" + string.Format("{0:MMdd}", DateTime.Now)); 37 | CreateWeeklyStatReportFor(ConnectionString.ConnectionString, SqlQueryForUsers, "Users" + string.Format("{0:MMdd}", DateTime.Now)); 38 | } 39 | 40 | private void CreateWeeklyStatReportFor(string connectionString, string sqlQuery, string reportName) 41 | { 42 | startingTime = DateTime.Now.AddHours(-1).ToUniversalTime(); //initialize to day 01 of the given month. 43 | DateTime endTime = DateTime.Now.ToUniversalTime(); 44 | List> uploadsDataPoints = new List>(); 45 | using (var sqlConnection = new SqlConnection(connectionString)) 46 | { 47 | using (var dbExecutor = new SqlExecutor(sqlConnection)) 48 | { 49 | sqlConnection.Open(); 50 | try 51 | { 52 | var count = dbExecutor.Query(string.Format(sqlQuery, startingTime.ToString("yyyy-MM-dd HH:mm:ss"), endTime.ToString("yyyy-MM-dd HH:mm:ss"))).SingleOrDefault(); 53 | ReportHelpers.AppendDatatoBlob(StorageAccount, reportName + "HourlyReport.json", new Tuple(string.Format("{0:HH:mm}", endTime.ToLocalTime()), count.ToString()), 50, ContainerName); 54 | } 55 | catch (NullReferenceException) 56 | { 57 | uploadsDataPoints.Add(new Tuple("0", "0")); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/TrendingTasks/CreateStatsMonthlyReportTask.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Data; 4 | using System.Data.SqlClient; 5 | using System.IO; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Microsoft.WindowsAzure.Storage; 9 | using Microsoft.WindowsAzure.Storage.Blob; 10 | using Newtonsoft.Json.Linq; 11 | using NuGetGallery.Operations.Common; 12 | using AnglicanGeek.DbExecutor; 13 | using System; 14 | 15 | namespace NuGetGallery.Operations 16 | { 17 | [Command("createpackagedownloadreport", "Creates the stats (uploads,downloads and users) for Gallery for a given month", AltName = "csmr")] 18 | public class CreateStatsMonthlyReport : ReportsTask 19 | { 20 | private string SqlQueryForDownloads = @" SELECT SUM(f.DownloadCount) FROM [dbo].[Fact_Download] f JOIN [dbo].[Dimension_Date] dd ON dd.[Id] = f.Dimension_Date_Id WHERE dd.[Date] >= '{0}'AND dd.[Date] <= '{1}'"; 21 | private string SqlQueryForUploads = @"SELECT Count (*) FROM [dbo].[Packages] where [Created] >= '{0}' AND [Created] <= '{1}'"; 22 | private string SqlQueryForUsers = @"SELECT Count (*) FROM [dbo].[Users] where [CreatedUtc] >= '{0}' AND [CreatedUtc] <= '{1}'"; 23 | private DateTime startingTime; //initialize start date to the NuGet initial release time. 24 | [Option("MonthName", AltName = "m")] 25 | public string Month { get; set; } 26 | 27 | [Option("Year", AltName = "y")] 28 | public int Year { get; set; } 29 | 30 | [Option("WarehouseConnectionString", AltName = "wrdb")] 31 | public string WarehouseConnectionString { get; set; } 32 | 33 | public override void ExecuteCommand() 34 | { 35 | CreateWeeklyStatReportFor(ConnectionString.ConnectionString, SqlQueryForUploads,"Uploads"); 36 | CreateWeeklyStatReportFor(ConnectionString.ConnectionString, SqlQueryForUsers, "Users"); 37 | CreateWeeklyStatReportFor(WarehouseConnectionString, SqlQueryForDownloads, "Downloads"); //uploads and users data can be data from Gallery DB whereas downloads stats will be present in warehouse. 38 | } 39 | 40 | private void CreateWeeklyStatReportFor(string connectionString,string sqlQuery,string reportName) 41 | { 42 | startingTime = new DateTime(Year, UnixTimeStampUtility.GetMonthNumber(Month), 01); //initialize to day 01 of the given month. 43 | DateTime monthEndTime = new DateTime(Year, UnixTimeStampUtility.GetMonthNumber(Month), UnixTimeStampUtility.GetDaysInMonth(Month)); 44 | List> uploadsDataPoints = new List>(); 45 | int week = 1; 46 | using (var sqlConnection = new SqlConnection(connectionString)) 47 | { 48 | using (var dbExecutor = new SqlExecutor(sqlConnection)) 49 | { 50 | sqlConnection.Open(); 51 | 52 | while (startingTime <= monthEndTime) 53 | { 54 | DateTime endTime = startingTime.AddDays(7); 55 | if (endTime > monthEndTime) endTime = monthEndTime; 56 | try 57 | { 58 | var count = dbExecutor.Query(string.Format(sqlQuery, startingTime.ToString("yyyy-MM-dd"), endTime.ToString("yyyy-MM-dd"))).SingleOrDefault(); 59 | uploadsDataPoints.Add(new Tuple("Week" + week++, count.ToString())); 60 | } 61 | catch (NullReferenceException) 62 | { 63 | uploadsDataPoints.Add(new Tuple("Week" + week++, "0")); 64 | } 65 | 66 | startingTime = startingTime.AddDays(7); 67 | } 68 | } 69 | } 70 | JArray reportObject = ReportHelpers.GetJson(uploadsDataPoints); 71 | ReportHelpers.CreateBlob(ReportStorage, reportName + Month + "MonthlyReport.json", "dashboard", "application/json", ReportHelpers.ToStream(reportObject)); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/UnixTimeStampUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Globalization; 7 | 8 | namespace NuGetGallery.Operations 9 | { 10 | /// 11 | /// Helper class to convert C# DateTime to UNIX time stamp. 12 | /// 13 | public class UnixTimeStampUtility 14 | { 15 | private static readonly DateTime UnixEpoch = 16 | new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 17 | 18 | public static long GetCurrentUnixTimestampMillis() 19 | { 20 | return (long)(DateTime.UtcNow - UnixEpoch).TotalMilliseconds; 21 | } 22 | 23 | public static DateTime DateTimeFromUnixTimestampMillis(long millis) 24 | { 25 | return UnixEpoch.AddMilliseconds(millis); 26 | } 27 | 28 | public static long GetCurrentUnixTimestampSeconds() 29 | { 30 | return (long)(DateTime.UtcNow - UnixEpoch).TotalSeconds; 31 | } 32 | 33 | public static long GetUnixTimestampSeconds(DateTime time) 34 | { 35 | return (long)(time - UnixEpoch).TotalSeconds; 36 | } 37 | 38 | public static long GetLastMonthUnixTimestampSeconds() 39 | { 40 | return (long)(DateTime.UtcNow.Subtract(new TimeSpan(30, 0, 0, 0)) - UnixEpoch).TotalSeconds; 41 | } 42 | 43 | public static long GetLastWeekUnixTimestampSeconds() 44 | { 45 | return (long)(DateTime.UtcNow.Subtract(new TimeSpan(7, 0, 0, 0)) - UnixEpoch).TotalSeconds; 46 | } 47 | 48 | public static long GetSecondsForDays(int noOfDays) 49 | { 50 | double total = new TimeSpan(noOfDays, 0, 0, 0).TotalSeconds; 51 | return (long)total; 52 | } 53 | 54 | public static DateTime DateTimeFromUnixTimestampSeconds(long seconds) 55 | { 56 | return UnixEpoch.AddSeconds(seconds); 57 | } 58 | 59 | public static int GetDaysInMonth(string month) 60 | { 61 | return DateTime.DaysInMonth(DateTime.Now.Year, GetMonthNumber(month)); 62 | } 63 | 64 | public static string GetMonthName(int Month) 65 | { 66 | DateTimeFormatInfo dfi = new DateTimeFormatInfo(); 67 | string monthName = dfi.GetAbbreviatedMonthName(Month); 68 | return monthName; 69 | } 70 | 71 | public static int GetMonthNumber(string monthName) 72 | { 73 | int iMonthNo = Convert.ToDateTime("01-" + monthName + "-2011").Month; 74 | return iMonthNo; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/V2GalleryFrontendTasks/CreateElmahErrorDetailedReportTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Web.Script.Serialization; 4 | using NuGet.Services.Dashboard.Common; 5 | using NuGetGallery.Operations.Common; 6 | 7 | 8 | namespace NuGetGallery.Operations 9 | { 10 | [Command("CreateElmahErrorDetailedReportTask", "Creates detailed error report for last N hours from Elmah logs", AltName = "ceedrt")] 11 | public class CreateElmahErrorDetailedReportTask : StorageTask 12 | { 13 | [Option("LastNHours", AltName = "n")] 14 | public int LastNHours { get; set; } 15 | 16 | [Option("ElmahAccountCredentials", AltName = "ea")] 17 | public string ElmahAccountCredentials { get; set; } 18 | 19 | public override void ExecuteCommand() 20 | { 21 | 22 | AlertThresholds thresholds = new JavaScriptSerializer().Deserialize(ReportHelpers.Load(StorageAccount, "Configuration.AlertThresholds.json", ContainerName)); 23 | 24 | List listOfErrors = new List(); 25 | RefreshElmahError RefreshExecute = new RefreshElmahError(StorageAccount, ContainerName, LastNHours, ElmahAccountCredentials); 26 | 27 | listOfErrors = RefreshExecute.ExecuteRefresh(); 28 | 29 | foreach (ElmahError error in listOfErrors) 30 | { 31 | if (error.Severity == 0) 32 | { 33 | if (error.Occurecnes > thresholds.ElmahCriticalErrorPerHourAlertErrorThreshold && LastNHours == 1) 34 | { 35 | new SendAlertMailTask 36 | { 37 | AlertSubject = string.Format("Error: Elmah Error Alert on {0} activated for {1}", ContainerName, error.Error), 38 | Details = String.Format("Number of {0} exceeded Error threshold limit during the last hour.Threshold error count per hour : {1}, Events recorded in the last hour: {2}", error.Error, thresholds.ElmahCriticalErrorPerHourAlertErrorThreshold, error.Occurecnes.ToString()), 39 | AlertName = string.Format("Error: {0} Elmah Error Alert for {1}", ContainerName, error.Error), 40 | Component = "Web Server", 41 | Level = "Error" 42 | }.ExecuteCommand(); 43 | } 44 | else if (error.Occurecnes > thresholds.ElmahCriticalErrorPerHourAlertWarningThreshold && LastNHours == 1) 45 | { 46 | new SendAlertMailTask 47 | { 48 | AlertSubject = string.Format("Warning: Elmah Error Alert on {0} activated for {1}", ContainerName, error.Error), 49 | Details = String.Format("Number of {0} exceeded Warning threshold limit during the last hour.Threshold error count per hour : {1}, Events recorded in the last hour: {2}", error.Error, thresholds.ElmahCriticalErrorPerHourAlertWarningThreshold, error.Occurecnes.ToString()), 50 | AlertName = string.Format("Warning: {0} Elmah Error Alert for {1}", ContainerName, error.Error), 51 | Component = "Web Server", 52 | Level = "Warning" 53 | }.ExecuteCommand(); 54 | } 55 | } 56 | } 57 | 58 | var json = new JavaScriptSerializer().Serialize(listOfErrors); 59 | ReportHelpers.CreateBlob(StorageAccount, "ElmahErrorsDetailed" + LastNHours.ToString() + "hours.json", ContainerName, "application/json", ReportHelpers.ToStream(json)); 60 | 61 | } 62 | 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/V2GalleryFrontendTasks/CreateElmahErrorOverviewReportTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Linq; 5 | using Elmah; 6 | using NuGetGallery.Infrastructure; 7 | using NuGetGallery.Operations.Common; 8 | 9 | 10 | namespace NuGetGallery.Operations 11 | { 12 | [Command("CreateElmahErrorOverviewReportTask", "Creates trending report for Elmah error count", AltName = "ceeort")] 13 | public class CreateElmahErrorOverviewReportTask : StorageTask 14 | { 15 | [Option("ElmahAccountCredentials", AltName = "ea")] 16 | public string ElmahAccountCredentials { get; set; } 17 | public override void ExecuteCommand() 18 | { 19 | TableErrorLog log = new TableErrorLog(string.Format(ElmahAccountCredentials)); 20 | List entities = new List(); 21 | log.GetErrors(0, 500, entities); //retrieve n * LastNHours errors assuming a max of 500 errors per hour. 22 | int count = entities.Where(entity => entity.Error.Time.ToUniversalTime() > DateTime.UtcNow.AddHours(-1) && entity.Error.Time.ToUniversalTime() < DateTime.UtcNow).ToList().Count; 23 | ReportHelpers.AppendDatatoBlob(StorageAccount, "ErrorRate" + string.Format("{0:MMdd}", DateTime.Now) + ".json", new Tuple(String.Format("{0:HH:mm}", DateTime.Now), count.ToString()), 50, ContainerName); 24 | } 25 | 26 | 27 | 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/V3JobsBackGroundTasks/V3Utility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Data.SqlClient; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using System.Web.Script.Serialization; 11 | using Microsoft.WindowsAzure.Storage; 12 | using Microsoft.WindowsAzure.Storage.Blob; 13 | using Newtonsoft.Json.Linq; 14 | using NuGet.Services.Dashboard.Common; 15 | using NuGetGallery.Operations.Common; 16 | using NuGet.Services.Metadata.Catalog; 17 | 18 | 19 | namespace NuGetGallery.Operations.Tasks.DashBoardTasks.V3JobsBackGroundTasks 20 | { 21 | public class V3Utility 22 | { 23 | public static HashSet GetCatalogPackages(string catalogRootUrl, string storageConnectionString) 24 | { 25 | return GetCatalogPackages(catalogRootUrl, storageConnectionString, DateTime.MinValue, DateTime.MaxValue); 26 | } 27 | 28 | public static HashSet GetCatalogPackages(string catalogRootUrl,string storageConnectionString,DateTime startCommitTimeStamp,DateTime endCommitTimeStamp) 29 | { 30 | CollectorHttpClient client = new CollectorHttpClient(); 31 | CloudStorageAccount csa = CloudStorageAccount.Parse(storageConnectionString); 32 | var blobClient = csa.CreateCloudBlobClient(); 33 | Uri catalogIndex = new Uri(catalogRootUrl); 34 | CatalogIndexReader reader = new CatalogIndexReader(catalogIndex, client); 35 | //TBD Update CatalogIndexReader to return packages based on commit time stamp.Right now it returns all packages. 36 | var task = reader.GetEntries(); 37 | task.Wait(); 38 | List entries = task.Result.ToList(); 39 | entries = entries.Where(e => e.CommitTimeStamp >= startCommitTimeStamp && e.CommitTimeStamp <= endCommitTimeStamp).ToList(); 40 | var catalogPackages = new HashSet(entries.Select(e => new PackageEntry(e.Id, e.Version.ToNormalizedString())), PackageEntry.Comparer); 41 | return catalogPackages; 42 | } 43 | public static DateTime GetValueFromCatalogIndex(string catalogRootUrl, string keyName) 44 | { 45 | WebRequest request = WebRequest.Create(catalogRootUrl); 46 | request.PreAuthenticate = true; 47 | request.Method = "GET"; 48 | WebResponse respose = request.GetResponse(); 49 | using (var reader = new StreamReader(respose.GetResponseStream())) 50 | { 51 | JavaScriptSerializer js = new JavaScriptSerializer(); 52 | var objects = js.Deserialize(reader.ReadToEnd()); 53 | DateTime catalogCommitTimeStamp = Convert.ToDateTime(objects[keyName]); 54 | return catalogCommitTimeStamp.ToUniversalTime(); 55 | } 56 | } 57 | } 58 | 59 | public class PackageEntry : IEquatable 60 | { 61 | public string Id { get; private set; } 62 | public string Version { get; private set; } 63 | 64 | public PackageEntry(string id, string version) 65 | { 66 | Id = id.ToLowerInvariant(); 67 | Version = version.ToLowerInvariant(); 68 | } 69 | 70 | public bool Equals(PackageEntry other) 71 | { 72 | return Compare(this, other); 73 | } 74 | 75 | public override string ToString() 76 | { 77 | return String.Format("{0} {1}", Id, Version); 78 | } 79 | 80 | public static bool Compare(PackageEntry x, PackageEntry y) 81 | { 82 | return StringComparer.OrdinalIgnoreCase.Equals(x.Id, y.Id) && StringComparer.OrdinalIgnoreCase.Equals(x.Version, y.Version); 83 | } 84 | 85 | public static IEqualityComparer Comparer 86 | { 87 | get 88 | { 89 | return new PackageEntryComparer(); 90 | } 91 | } 92 | 93 | public class PackageEntryComparer : IEqualityComparer 94 | { 95 | public bool Equals(PackageEntry x, PackageEntry y) 96 | { 97 | return PackageEntry.Compare(x, y); 98 | } 99 | 100 | public int GetHashCode(PackageEntry obj) 101 | { 102 | return obj.ToString().GetHashCode(); 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/DashBoardTasks/VerifyPostValidationCursorTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Web.Script.Serialization; 5 | 6 | namespace NuGetGallery.Operations.Tasks.DashBoardTasks 7 | { 8 | [Command("VerifyPostValidationCursorTask", "Checks the post-validation cursor lag.", AltName = "vpvc")] 9 | class VerifyPostValidationCursorTask : OpsTask 10 | { 11 | [Option("CursorUrl", AltName = "cu")] 12 | public string CursorUrl { get; set; } 13 | 14 | public override void ExecuteCommand() 15 | { 16 | WebRequest request = WebRequest.Create(CursorUrl); 17 | request.Method = "GET"; 18 | WebResponse respose = request.GetResponse(); 19 | using (var reader = new StreamReader(respose.GetResponseStream())) 20 | { 21 | JavaScriptSerializer js = new JavaScriptSerializer(); 22 | var objects = js.Deserialize(reader.ReadToEnd()); 23 | 24 | var lastCreated = DateTimeOffset.Parse(objects["lastCreated"]); 25 | 26 | if (lastCreated.UtcDateTime < DateTimeOffset.UtcNow.AddDays(-2).UtcDateTime) 27 | { 28 | new SendAlertMailTask 29 | { 30 | AlertSubject = "Error: Post validation job may not be running", 31 | Details = string.Format("Post validation job may not be running. Cursor was last updated {0} (UTC).", lastCreated.UtcDateTime.ToString("O")), 32 | AlertName = "Error: Post validation", 33 | Component = "PostValidation", 34 | Level = "Error" 35 | }.ExecuteCommand(); 36 | } 37 | else if (lastCreated.UtcDateTime < DateTimeOffset.UtcNow.AddDays(-1).UtcDateTime) 38 | { 39 | new SendAlertMailTask 40 | { 41 | AlertSubject = "Warning: Post validation job may not be running", 42 | Details = string.Format("Post validation job may not be running. Cursor was last updated {0} (UTC).", lastCreated.UtcDateTime.ToString("O")), 43 | AlertName = "Warning: Post validation", 44 | Component = "PostValidation", 45 | Level = "Warning" 46 | }.ExecuteCommand(); 47 | } 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Tasks/OpsTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Composition; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Linq; 6 | using NLog; 7 | using NuGetGallery.Operations.Common; 8 | using System.Configuration; 9 | 10 | namespace NuGetGallery.Operations 11 | { 12 | public abstract class OpsTask : ICommand 13 | { 14 | private const string CommandSuffix = "Task"; 15 | 16 | private CommandAttribute _commandAttribute; 17 | private List _arguments = new List(); 18 | private Logger _logger; 19 | protected internal Logger Log 20 | { 21 | get { return _logger ?? (_logger = LogManager.GetLogger(GetType().Name)); } 22 | internal set { _logger = value; } 23 | } 24 | 25 | public CommandAttribute CommandAttribute 26 | { 27 | get 28 | { 29 | if (_commandAttribute == null) 30 | { 31 | _commandAttribute = GetCommandAttribute(); 32 | } 33 | return _commandAttribute; 34 | } 35 | } 36 | 37 | public IList Arguments 38 | { 39 | get { return _arguments; } 40 | } 41 | 42 | [Import] 43 | public HelpCommand HelpCommand { get; set; } 44 | 45 | public DeploymentEnvironment CurrentEnvironment 46 | { 47 | get 48 | { 49 | return !String.IsNullOrEmpty(ConfigFile) ? 50 | DeploymentEnvironment.FromConfigFile(ConfigFile) : 51 | null; 52 | } 53 | } 54 | 55 | [Option("DisableNotification", AltName = "disn")] 56 | public bool DisableNotification { get; set; } 57 | 58 | [Option("DisableIncidentCreation", AltName = "disic")] 59 | public bool DisableIncidentCreation { get; set; } 60 | 61 | [Option("Path to the configuration file to use when command line arguments aren't specified")] 62 | public string ConfigFile { get; set; } 63 | 64 | [Option("Name of the environment specified by the configuration file")] 65 | public string EnvironmentName { get; set; } 66 | 67 | [Option("Gets help for this command", AltName = "?")] 68 | public bool Help { get; set; } 69 | 70 | [Option("Instead of performing any write operations, the command will just output what it WOULD do. Read operations are still performed.", AltName = "!")] 71 | public bool WhatIf { get; set; } 72 | 73 | public void Execute() 74 | { 75 | if (!String.IsNullOrEmpty(ConfigFile)) 76 | { 77 | Log.Info("Running against {0} environment", EnvironmentName); 78 | } 79 | 80 | if (WhatIf) 81 | { 82 | Log.Info("Running in WhatIf mode"); 83 | } 84 | if (Help) 85 | { 86 | HelpCommand.ViewHelpForCommand(CommandAttribute.CommandName); 87 | } 88 | else 89 | { 90 | try 91 | { 92 | ValidateArguments(); 93 | ExecuteCommand(); 94 | } 95 | catch (Exception e) 96 | { 97 | if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["SmtpUserName"]) && !string.IsNullOrEmpty(ConfigurationManager.AppSettings["SmtpPassword"])) 98 | { 99 | new SendAlertMailTask 100 | { 101 | AlertSubject = string.Format("Error executing task {0}", this.GetType().ToString()), 102 | Details = String.Format("Exception thrown while executing task {0}. Exception Message : {1}, Stack Trace : {2}", this.GetType().ToString(), e.Message, e.StackTrace), 103 | AlertName = "Exception from Dashboard OpsTask", 104 | Component = "Dashboard Ops" 105 | }.ExecuteCommand(); 106 | } 107 | throw; 108 | } 109 | } 110 | } 111 | 112 | public abstract void ExecuteCommand(); 113 | 114 | public virtual void ValidateArguments() 115 | { 116 | } 117 | 118 | [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does quite a bit of processing.")] 119 | public virtual CommandAttribute GetCommandAttribute() 120 | { 121 | var attributes = GetType().GetCustomAttributes(typeof(CommandAttribute), true); 122 | if (attributes.Any()) 123 | { 124 | return (CommandAttribute)attributes.FirstOrDefault(); 125 | } 126 | 127 | // Use the command name minus the suffix if present and default description 128 | string name = GetType().Name; 129 | int idx = name.LastIndexOf(CommandSuffix, StringComparison.OrdinalIgnoreCase); 130 | if (idx >= 0) 131 | { 132 | name = name.Substring(0, idx); 133 | } 134 | if (!String.IsNullOrEmpty(name)) 135 | { 136 | return new CommandAttribute(name, TaskResources.DefaultCommandDescription); 137 | } 138 | return null; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/Util.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.SqlClient; 4 | using System.Globalization; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Security.Cryptography; 8 | using System.Web; 9 | using AnglicanGeek.DbExecutor; 10 | using Microsoft.WindowsAzure.Storage.Blob; 11 | using System.Text.RegularExpressions; 12 | 13 | namespace NuGetGallery.Operations 14 | { 15 | public static class Util 16 | { 17 | public const byte OnlineState = 0; 18 | private static readonly Regex BackupNameFormat = new Regex(@"^(?.+)_(?\d{4}[A-Za-z]{3}\d{2}_\d{4})Z$",RegexOptions.IgnoreCase); // Backup_2013Apr12_1452Z 19 | public static string GetDbName(string connectionString) 20 | { 21 | var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString); 22 | return connectionStringBuilder.InitialCatalog; 23 | } 24 | public static string GetMasterConnectionString(string connectionString) 25 | { 26 | var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString) { InitialCatalog = "master" }; 27 | return connectionStringBuilder.ToString(); 28 | } 29 | 30 | public static DateTime GetDateTimeFromTimestamp(string timestamp) 31 | { 32 | DateTime result; 33 | if (DateTime.TryParseExact(timestamp, "yyyyMMddHHmmss", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out result)) 34 | { 35 | return result; 36 | } 37 | else if (DateTime.TryParseExact(timestamp, "yyyyMMMdd_HHmmZ", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out result)) 38 | { 39 | return result; 40 | } 41 | return DateTime.MinValue; 42 | } 43 | 44 | public static Db GetLastBackup(SqlExecutor dbExecutor, string backupNamePrefix) 45 | { 46 | var allBackups = dbExecutor.Query( 47 | "SELECT name, state FROM sys.databases WHERE name LIKE '" + backupNamePrefix + "%' AND state = @state", 48 | new { state = OnlineState }); 49 | var orderedBackups = from db in allBackups 50 | let t = ParseNewTimestamp(BackupNameFormat.Match(db.Name).Groups["timestamp"].Value) 51 | where t != null 52 | orderby t descending 53 | select db; 54 | 55 | return orderedBackups.FirstOrDefault(); 56 | } 57 | 58 | public static DateTime GetLastBackupTime(SqlExecutor dbExecutor, string backupNamePrefix) 59 | { 60 | var lastBackup = GetLastBackup(dbExecutor, backupNamePrefix); 61 | 62 | if (lastBackup == null) 63 | return DateTime.MinValue; 64 | 65 | var timestamp = lastBackup.Name.Substring(backupNamePrefix.Length); 66 | 67 | return GetDateTimeFromTimestamp(timestamp); 68 | } 69 | 70 | private static DateTimeOffset ParseNewTimestamp(string timestamp) 71 | { 72 | return new DateTimeOffset( 73 | DateTime.ParseExact(timestamp, "yyyyMMMdd_HHmm", CultureInfo.CurrentCulture), 74 | TimeSpan.Zero); 75 | } 76 | } 77 | 78 | public class Db 79 | { 80 | public string Name { get; set; } 81 | public byte State { get; set; } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/content/further.js: -------------------------------------------------------------------------------- 1 |  2 | // further flattens and already flattened JSON-LD document 3 | 4 | var further = function (flattened) { 5 | var result = []; 6 | for (var i = 0; i !== flattened.length; i += 1) { 7 | var subject = flattened[i]['@id']; 8 | for (var prop in flattened[i]) { 9 | if (prop !== '@id') { 10 | var predicate = prop; 11 | for (var j = 0; j !== flattened[i][prop].length; j += 1) { 12 | var object = {}; 13 | if (flattened[i][prop][j]['@id'] !== undefined) { 14 | object = { value: flattened[i][prop][j]['@id'], type: 'uri' }; 15 | } 16 | else { 17 | object = { value: flattened[i][prop][j]['@value'], type: 'literal' }; 18 | } 19 | result[result.length] = { subject: subject, predicate: predicate, object: object }; 20 | } 21 | } 22 | } 23 | } 24 | return result; 25 | } 26 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.Operations/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /NuGet.Services.Dashboard.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{E4F8E102-7447-4D41-A244-9AC4E352271C}" 7 | ProjectSection(SolutionItems) = preProject 8 | .nuget\NuGet.Config = .nuget\NuGet.Config 9 | .nuget\NuGet.exe = .nuget\NuGet.exe 10 | .nuget\NuGet.targets = .nuget\NuGet.targets 11 | EndProjectSection 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Services.Dashboard.Operations", "NuGet.Services.Dashboard.Operations\NuGet.Services.Dashboard.Operations.csproj", "{DBECF66B-8F2F-4B32-9143-E243BAFF12DF}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Services.Dashboard.Operations.Tools", "NuGet.Services.Dashboard.Operations.Tools\NuGet.Services.Dashboard.Operations.Tools.csproj", "{F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}" 16 | EndProject 17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Services.Dashboard.Common", "NuGet.Services.Dashboard.Common\NuGet.Services.Dashboard.Common.csproj", "{5566AE9C-8466-4316-9372-7B38B57DBB20}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Debug|Mixed Platforms = Debug|Mixed Platforms 23 | Debug|x86 = Debug|x86 24 | Release|Any CPU = Release|Any CPU 25 | Release|Mixed Platforms = Release|Mixed Platforms 26 | Release|x86 = Release|x86 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 32 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 33 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Debug|x86.ActiveCfg = Debug|Any CPU 34 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 37 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Release|Mixed Platforms.Build.0 = Release|Any CPU 38 | {DBECF66B-8F2F-4B32-9143-E243BAFF12DF}.Release|x86.ActiveCfg = Release|Any CPU 39 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Debug|Any CPU.ActiveCfg = Debug|x86 40 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 41 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Debug|Mixed Platforms.Build.0 = Debug|x86 42 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Debug|x86.ActiveCfg = Debug|x86 43 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Debug|x86.Build.0 = Debug|x86 44 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Release|Any CPU.ActiveCfg = Release|x86 45 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Release|Mixed Platforms.ActiveCfg = Release|x86 46 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Release|Mixed Platforms.Build.0 = Release|x86 47 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Release|x86.ActiveCfg = Release|x86 48 | {F240D1BC-BBFB-4F22-9DF8-3FDE36BFD665}.Release|x86.Build.0 = Release|x86 49 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 52 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 53 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Debug|x86.ActiveCfg = Debug|Any CPU 54 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 57 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Release|Mixed Platforms.Build.0 = Release|Any CPU 58 | {5566AE9C-8466-4316-9372-7B38B57DBB20}.Release|x86.ActiveCfg = Release|Any CPU 59 | EndGlobalSection 60 | GlobalSection(SolutionProperties) = preSolution 61 | HideSolutionNode = FALSE 62 | EndGlobalSection 63 | EndGlobal 64 | -------------------------------------------------------------------------------- /Nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NuGet.Services.Dashboard 2 | ======================== 3 | 4 | This repo contains the source code for NuGet Dashboard frontend website and back end operations. 5 | 6 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 7 | 8 | ###NuGet.Services.Dashboard.Operations### 9 | 10 | Contains tasks that retrieves monitoring data from various sources like Pingdom, WAD performance data, SQL Azure DMV queries and gallery database. 11 | Each task collects the required data and generates a json report which gets uploaded to the specified blob storage container. 12 | 13 | ###NuGet.Services.Dashboard.FrontEnd### 14 | 15 | Contains the Web application that displays the monitoring data. The Website reads the json report created by the backend tasks and displays them as charts and tables. 16 | 17 | ###NuGet.Services.Dashboard.Operations.Tools### 18 | 19 | Contains the commandline runner (galops.exe) that is used to invoke invidiual dashboard tasks. 20 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(DefaultParameterSetName='RegularBuild')] 2 | param ( 3 | [ValidateSet("debug", "release")] 4 | [string]$Configuration = 'debug', 5 | [int]$BuildNumber, 6 | [switch]$SkipRestore, 7 | [switch]$CleanCache, 8 | [string]$SimpleVersion = '1.0.0', 9 | [string]$SemanticVersion = '1.0.0-zlocal', 10 | [string]$Branch, 11 | [string]$CommitSHA, 12 | [string]$BuildBranch = '1c479a7381ebbc0fe1fded765de70d513b8bd68e' 13 | ) 14 | 15 | # For TeamCity - If any issue occurs, this script fail the build. - By default, TeamCity returns an exit code of 0 for all powershell scripts, even if they fail 16 | trap { 17 | Write-Host "BUILD FAILED: $_" -ForegroundColor Red 18 | Write-Host "ERROR DETAILS:" -ForegroundColor Red 19 | Write-Host $_.Exception -ForegroundColor Red 20 | Write-Host ("`r`n" * 3) 21 | exit 1 22 | } 23 | 24 | if (-not (Test-Path "$PSScriptRoot/build")) { 25 | New-Item -Path "$PSScriptRoot/build" -ItemType "directory" 26 | } 27 | wget -UseBasicParsing -Uri "https://raw.githubusercontent.com/NuGet/ServerCommon/$BuildBranch/build/init.ps1" -OutFile "$PSScriptRoot/build/init.ps1" 28 | . "$PSScriptRoot/build/init.ps1" -BuildBranch "$BuildBranch" 29 | 30 | Write-Host ("`r`n" * 3) 31 | Trace-Log ('=' * 60) 32 | 33 | $startTime = [DateTime]::UtcNow 34 | if (-not $BuildNumber) { 35 | $BuildNumber = Get-BuildNumber 36 | } 37 | Trace-Log "Build #$BuildNumber started at $startTime" 38 | 39 | $BuildErrors = @() 40 | 41 | Invoke-BuildStep 'Getting private build tools' { Install-PrivateBuildTools } ` 42 | -ev +BuildErrors 43 | 44 | Invoke-BuildStep 'Installing NuGet.exe' { Install-NuGet } ` 45 | -ev +BuildErrors 46 | 47 | Invoke-BuildStep 'Clearing package cache' { Clear-PackageCache } ` 48 | -skip:(-not $CleanCache) ` 49 | -ev +BuildErrors 50 | 51 | Invoke-BuildStep 'Clearing artifacts' { Clear-Artifacts } ` 52 | -ev +BuildErrors 53 | 54 | Invoke-BuildStep 'Restoring solution packages' { ` 55 | Install-SolutionPackages -path (Join-Path $PSScriptRoot ".nuget\packages.config") -output (Join-Path $PSScriptRoot "packages") -excludeversion } ` 56 | -skip:$SkipRestore ` 57 | -ev +BuildErrors 58 | 59 | Invoke-BuildStep 'Set version metadata in AssemblyInfo.cs' { 60 | $Paths = ` 61 | (Join-Path $PSScriptRoot "NuGet.Services.Dashboard.Common\Properties\AssemblyInfo.g.cs"), ` 62 | (Join-Path $PSScriptRoot "NuGet.Services.Dashboard.Operations\Properties\AssemblyInfo.g.cs"), ` 63 | (Join-Path $PSScriptRoot "NuGet.Services.Dashboard.Operations.Tools\Properties\AssemblyInfo.g.cs") 64 | 65 | Foreach ($Path in $Paths) { 66 | Set-VersionInfo -Path $Path -Version $SimpleVersion -Branch $Branch -Commit $CommitSHA 67 | } 68 | } ` 69 | -ev +BuildErrors 70 | 71 | Invoke-BuildStep 'Building solution' { 72 | $SolutionPath = Join-Path $PSScriptRoot "NuGet.Services.Dashboard.sln" 73 | Build-Solution $Configuration $BuildNumber -MSBuildVersion "14" $SolutionPath -SkipRestore:$SkipRestore ` 74 | } ` 75 | -ev +BuildErrors 76 | 77 | Invoke-BuildStep 'Creating artifacts' { 78 | New-Package (Join-Path $PSScriptRoot "NuGet.Services.Dashboard.Operations.Tools\NuGet.Services.Dashboard.Operations.Tools.csproj") -Configuration $Configuration -Symbols -BuildNumber $BuildNumber -Version $SemanticVersion -Branch $Branch 79 | } ` 80 | -ev +BuildErrors 81 | 82 | Trace-Log ('-' * 60) 83 | 84 | ## Calculating Build time 85 | $endTime = [DateTime]::UtcNow 86 | Trace-Log "Build #$BuildNumber ended at $endTime" 87 | Trace-Log "Time elapsed $(Format-ElapsedTime ($endTime - $startTime))" 88 | 89 | Trace-Log ('=' * 60) 90 | 91 | if ($BuildErrors) { 92 | $ErrorLines = $BuildErrors | %{ ">>> $($_.Exception.Message)" } 93 | Error-Log "Builds completed with $($BuildErrors.Count) error(s):`r`n$($ErrorLines -join "`r`n")" -Fatal 94 | } 95 | 96 | Write-Host ("`r`n" * 3) 97 | --------------------------------------------------------------------------------