public async Task ImportFromGrafana(IEnumerable <string> dashboardUids) { HashSet <string> usedNotificationIds = new HashSet <string>(); foreach (var dashboardPath in GetAllDashboardPaths()) { if (dashboardUids.Any(d => d.Contains(GetUidFromDashboardFile(dashboardPath)))) { // This is a new dashboard, don't assume it alert tags JObject data; using (var sr = new StreamReader(dashboardPath)) using (var jr = new JsonTextReader(sr)) { data = await JObject.LoadAsync(jr).ConfigureAwait(false); } IEnumerable <string> notificationIds = data.SelectTokens("..alertRuleTags.NotificationId") .Select(d => d.Value <string>()); foreach (var alertId in notificationIds) { usedNotificationIds.Add(alertId); } } } foreach (string dashboardUid in dashboardUids) { // Get a dashboard JObject dashboard = await GrafanaClient.GetDashboardAsync(dashboardUid).ConfigureAwait(false); // Cache dashboard data needed for post string targetUid = dashboard.Value <JObject>("dashboard").Value <string>("uid"); JObject slimmedDashboard = GrafanaSerialization.SanitizeDashboard(dashboard); UpdateNotificationIds(slimmedDashboard, usedNotificationIds); JArray tags = slimmedDashboard.Value <JArray>("tags"); JToken uidTag = tags.FirstOrDefault(t => t.Value <string>().StartsWith(BaseUidTagPrefix)); if (uidTag != null) { targetUid = uidTag.Value <string>().Substring(BaseUidTagPrefix.Length); } // Get the dashboard folder data and cache if not already present int folderId = GrafanaSerialization.ExtractFolderId(dashboard); JObject folder = await GrafanaClient.GetFolderAsync(folderId).ConfigureAwait(false); FolderData folderData = GrafanaSerialization.SanitizeFolder(folder); // Get datasources used in the dashboard IEnumerable <string> dataSourceNames = GrafanaSerialization.ExtractDataSourceNames(dashboard); foreach (string datasourceName in dataSourceNames) { JObject datasource = await GrafanaClient.GetDataSourceAsync(datasourceName).ConfigureAwait(false); datasource = GrafanaSerialization.SanitizeDataSource(datasource); // Create the data source for each environment foreach (string env in _environments) { string datasourcePath = GetDatasourcePath(env, datasourceName); if (File.Exists(datasourcePath)) { // If we already have that datasource, don't overwrite it's useful values with empty ones continue; } Log.LogMessage(MessageImportance.Normal, "Importing datasource {0}...", datasourceName); Directory.CreateDirectory(Path.GetDirectoryName(datasourcePath)); using (var datasourceStreamWriter = new StreamWriter(datasourcePath)) using (var datasourceJsonWriter = new JsonTextWriter(datasourceStreamWriter)) { _serializer.Serialize(datasourceJsonWriter, datasource); } } } HashSet <string> usedNotifications = new HashSet <string>(slimmedDashboard .SelectTokens("panels.[*].alert.notifications.[*].uid") .Select(t => t.Value <string>()) .Where(uid => !string.IsNullOrEmpty(uid))); foreach (string notificationUid in usedNotifications) { JObject notificationChannel = await GrafanaClient.GetNotificationChannelAsync(notificationUid); notificationChannel = GrafanaSerialization.SanitizeNotificationChannel(notificationChannel); // Create the data source for each environment foreach (string env in _environments) { string notificationPath = GetNotificationPath(env, notificationUid); if (File.Exists(notificationPath)) { // If we already have that notification, don't overwrite it's useful values with empty ones continue; } Log.LogMessage(MessageImportance.Normal, "Importing notification channel {0}...", notificationUid); Directory.CreateDirectory(Path.GetDirectoryName(notificationPath)); using (var datasourceStreamWriter = new StreamWriter(notificationPath)) using (var datasourceJsonWriter = new JsonTextWriter(datasourceStreamWriter)) { _serializer.Serialize(datasourceJsonWriter, notificationChannel); } } } Log.LogMessage(MessageImportance.Normal, "Importing dashboard {0}...", targetUid); string dashboardPath = GetDashboardFilePath(folderData.Title, targetUid); Directory.CreateDirectory(Path.GetDirectoryName(dashboardPath)); using (var dashboardStreamWriter = new StreamWriter(dashboardPath)) using (var dashboardJsonWriter = new JsonTextWriter(dashboardStreamWriter)) { _serializer.Serialize(dashboardJsonWriter, slimmedDashboard); } } }
public async Task ImportFromGrafana(IEnumerable <string> dashboardUids) { HashSet <string> usedNotificationIds = new HashSet <string>(); foreach (var dashboardPath in GetAllDashboardPaths()) { if (dashboardUids.Any(d => d.Contains(GetUidFromDashboardFile(dashboardPath)))) { // This is a new dashboard, don't assume it alert tags JObject data; using (var sr = new StreamReader(dashboardPath)) using (var jr = new JsonTextReader(sr)) { data = await JObject.LoadAsync(jr).ConfigureAwait(false); } IEnumerable <string> notificationIds = data.SelectTokens("..alertRuleTags.NotificationId") .Select(d => d.Value <string>()); foreach (var alertId in notificationIds) { usedNotificationIds.Add(alertId); } } } List <Parameter> parameters; if (File.Exists(_parametersFilePath)) { using (var sr = new StreamReader(_parametersFilePath)) using (var jr = new JsonTextReader(sr)) { parameters = _serializer.Deserialize <List <Parameter> >(jr); } } else { parameters = new List <Parameter>(); } foreach (string dashboardUid in dashboardUids) { // Get a dashboard JObject dashboard = await GrafanaClient.GetDashboardAsync(dashboardUid).ConfigureAwait(false); // Cache dashboard data needed for post string targetUid = dashboard.Value <JObject>("dashboard").Value <string>("uid"); // SanitizeDashboard makes structural changes to the JSON and ParameterizeDashboard // expects a certain structure, so order matters when calling these methods. JObject parameterizedDashboard = GrafanaSerialization.ParameterizeDashboard(dashboard, parameters, _environments, _environment); JObject slimmedDashboard = GrafanaSerialization.SanitizeDashboard(parameterizedDashboard); UpdateNotificationIds(slimmedDashboard, usedNotificationIds); JArray tags = slimmedDashboard.Value <JArray>("tags"); JToken uidTag = tags.FirstOrDefault(t => t.Value <string>().StartsWith(BaseUidTagPrefix)); if (uidTag != null) { targetUid = uidTag.Value <string>().Substring(BaseUidTagPrefix.Length); } // Get the dashboard folder data and cache if not already present int folderId = GrafanaSerialization.ExtractFolderId(dashboard); JObject folder = await GrafanaClient.GetFolderAsync(folderId).ConfigureAwait(false); FolderData folderData = GrafanaSerialization.SanitizeFolder(folder); // Get datasources used in the dashboard IEnumerable <string> dataSourceIdentifiers = GrafanaSerialization.ExtractDataSourceIdentifiers(dashboard); foreach (string dataSourceIdentifier in dataSourceIdentifiers) { JObject datasource = await GrafanaClient.GetDataSourceByUidAsync(dataSourceIdentifier).ConfigureAwait(false) ?? await GrafanaClient.GetDataSourceByNameAsync(dataSourceIdentifier).ConfigureAwait(false); string datasourceName = datasource.Value <string>("name"); datasource = GrafanaSerialization.SanitizeDataSource(datasource); // Create the data source for each environment foreach (string env in _environments) { string datasourcePath = GetDatasourcePath(env, datasourceName); if (File.Exists(datasourcePath)) { // If we already have that datasource, don't overwrite it's useful values with empty ones continue; } Log.LogMessage(MessageImportance.Normal, "Importing datasource {0}...", datasourceName); Directory.CreateDirectory(Path.GetDirectoryName(datasourcePath)); using (var datasourceStreamWriter = new StreamWriter(datasourcePath)) using (var datasourceJsonWriter = new JsonTextWriter(datasourceStreamWriter)) { _serializer.Serialize(datasourceJsonWriter, datasource); } } } HashSet <string> usedNotifications = new HashSet <string>(slimmedDashboard .SelectTokens("panels.[*].alert.notifications.[*].uid") .Select(t => t.Value <string>()) .Where(uid => !string.IsNullOrEmpty(uid))); foreach (string notificationUid in usedNotifications) { JObject notificationChannel = await GrafanaClient.GetNotificationChannelAsync(notificationUid); notificationChannel = GrafanaSerialization.SanitizeNotificationChannel(notificationChannel); // Create the data source for each environment foreach (string env in _environments) { string notificationPath = GetNotificationPath(env, notificationUid); if (File.Exists(notificationPath)) { // If we already have that notification, don't overwrite it's useful values with empty ones continue; } Log.LogMessage(MessageImportance.Normal, "Importing notification channel {0}...", notificationUid); if (notificationChannel.ContainsKey("password")) { var password = notificationChannel.GetValue("password").Value <string>(); if (!password.Contains("vault")) { Log.LogWarning($"Please replace the password token with a key vault reference inside {notificationPath}"); } } Directory.CreateDirectory(Path.GetDirectoryName(notificationPath)); using (var datasourceStreamWriter = new StreamWriter(notificationPath)) using (var datasourceJsonWriter = new JsonTextWriter(datasourceStreamWriter)) { _serializer.Serialize(datasourceJsonWriter, notificationChannel); } } } Log.LogMessage(MessageImportance.Normal, "Importing dashboard {0}...", targetUid); string dashboardPath = GetDashboardFilePath(folderData.Title, targetUid); Directory.CreateDirectory(Path.GetDirectoryName(dashboardPath)); using (var dashboardStreamWriter = new StreamWriter(dashboardPath)) using (var dashboardJsonWriter = new JsonTextWriter(dashboardStreamWriter)) { _serializer.Serialize(dashboardJsonWriter, slimmedDashboard); } } // Save parameters back to disk Log.LogMessage(MessageImportance.Normal, "Saving parameters {0}...", _parametersFilePath); using (var sr = new StreamWriter(_parametersFilePath)) using (var jr = new JsonTextWriter(sr)) { _serializer.Serialize(jr, parameters); } }
private async Task PostDashboardsAsync() { JArray folderArray = await GrafanaClient.ListFoldersAsync().ConfigureAwait(false); List <FolderData> folders = folderArray.Select(f => new FolderData(f.Value <string>("uid"), f.Value <string>("title"))) .ToList(); var knownUids = new HashSet <string>(); List <Parameter> parameters; using (StreamReader sr = new StreamReader(_parameterFile)) using (JsonReader jr = new JsonTextReader(sr)) { JsonSerializer jsonSerializer = new JsonSerializer(); parameters = jsonSerializer.Deserialize <List <Parameter> >(jr); } foreach (string dashboardPath in GetAllDashboardPaths()) { string folderName = Path.GetFileName(Path.GetDirectoryName(dashboardPath)); string dashboardFileName = Path.GetFileName(dashboardPath); string uid = GetUidFromDashboardFile(dashboardFileName); knownUids.Add(uid); FolderData folder = folders.FirstOrDefault(f => f.Title == folderName); JObject result = await GrafanaClient.CreateFolderAsync(folderName, folderName).ConfigureAwait(false); string folderUid = result["uid"].Value <string>(); int folderId = result["id"].Value <int>(); if (folder == null) { folder = new FolderData(folderUid, folderName); } folder.Id = folderId; JObject data; using (var sr = new StreamReader(dashboardPath)) using (var jr = new JsonTextReader(sr)) { data = await JObject.LoadAsync(jr).ConfigureAwait(false); } JArray tagArray = null; if (data.TryGetValue("tags", out JToken tagToken)) { tagArray = tagToken as JArray; } if (tagArray == null) { tagArray = new JArray(); } var newTags = new JArray(); foreach (JToken tag in tagArray) { if (tag.Value <string>().StartsWith(BaseUidTagPrefix) || tag.Value <string>().StartsWith(SourceTagPrefix)) { continue; } newTags.Add(tag); } tagArray.Add(GetUidTag(uid)); tagArray.Add(SourceTag); data["tags"] = newTags; data["uid"] = uid; data = GrafanaSerialization.DeparameterizeDashboard(data, parameters, _environment); Log.LogMessage(MessageImportance.Normal, "Posting dashboard {0}...", uid); await GrafanaClient.CreateDashboardAsync(data, folderId).ConfigureAwait(false); } await ClearExtraneousDashboardsAsync(knownUids); }