182 lines
4.9 KiB
Go
182 lines
4.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// sendToGrafana отправляет дашборд в Grafana
|
|
// Дашборд будет создан в указанной папке (folder)
|
|
func sendToGrafana(dashboard map[string]interface{}, config Config) error {
|
|
// Получить или создать folder ID
|
|
folderID, err := ensureFolder(config)
|
|
if err != nil {
|
|
log.Printf("Warning: Failed to ensure folder exists: %v", err)
|
|
log.Printf("Dashboard will be created in General folder")
|
|
folderID = 0 // General folder
|
|
}
|
|
|
|
// Добавить folder ID в запрос
|
|
dashboard["folderId"] = folderID
|
|
if folderID > 0 {
|
|
log.Printf("Creating dashboard in folder: %s (ID: %d)", config.GrafanaFolder, folderID)
|
|
}
|
|
|
|
jsonData, err := json.Marshal(dashboard)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal dashboard: %w", err)
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/api/dashboards/db", strings.TrimRight(config.GrafanaURL, "/"))
|
|
|
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create request: %w", err)
|
|
}
|
|
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", config.GrafanaAPIKey))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send request: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
return fmt.Errorf("grafana API returned status %d: %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
// Parse response to get dashboard URL
|
|
var response map[string]interface{}
|
|
if err := json.Unmarshal(body, &response); err == nil {
|
|
if url, ok := response["url"].(string); ok {
|
|
log.Printf("Dashboard URL: %s%s", config.GrafanaURL, url)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ensureFolder создает папку если её нет и возвращает её ID
|
|
func ensureFolder(config Config) (int, error) {
|
|
if config.GrafanaFolder == "" {
|
|
return 0, nil // General folder
|
|
}
|
|
|
|
// Поиск существующей папки
|
|
folderID, err := findFolder(config)
|
|
if err == nil && folderID > 0 {
|
|
return folderID, nil
|
|
}
|
|
|
|
// Создать папку если не найдена
|
|
return createFolder(config)
|
|
}
|
|
|
|
// findFolder ищет папку по имени
|
|
func findFolder(config Config) (int, error) {
|
|
url := fmt.Sprintf("%s/api/folders", strings.TrimRight(config.GrafanaURL, "/"))
|
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", config.GrafanaAPIKey))
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return 0, fmt.Errorf("failed to list folders: status %d", resp.StatusCode)
|
|
}
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
var folders []map[string]interface{}
|
|
if err := json.Unmarshal(body, &folders); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// Поиск по title
|
|
for _, folder := range folders {
|
|
if title, ok := folder["title"].(string); ok && title == config.GrafanaFolder {
|
|
if id, ok := folder["id"].(float64); ok {
|
|
log.Printf("Found existing folder: %s (ID: %d)", config.GrafanaFolder, int(id))
|
|
return int(id), nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0, fmt.Errorf("folder not found")
|
|
}
|
|
|
|
// createFolder создает новую папку
|
|
func createFolder(config Config) (int, error) {
|
|
url := fmt.Sprintf("%s/api/folders", strings.TrimRight(config.GrafanaURL, "/"))
|
|
|
|
payload := map[string]interface{}{
|
|
"title": config.GrafanaFolder,
|
|
}
|
|
|
|
jsonData, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", config.GrafanaAPIKey))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
return 0, fmt.Errorf("failed to create folder: status %d: %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
var response map[string]interface{}
|
|
if err := json.Unmarshal(body, &response); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if id, ok := response["id"].(float64); ok {
|
|
log.Printf("Created new folder: %s (ID: %d)", config.GrafanaFolder, int(id))
|
|
return int(id), nil
|
|
}
|
|
|
|
return 0, fmt.Errorf("failed to get folder ID from response")
|
|
}
|
|
|
|
func logDryRun(clientTitle string, dashboard map[string]interface{}) {
|
|
jsonData, _ := json.MarshalIndent(dashboard, "", " ")
|
|
log.Printf("DRY RUN: Dashboard for %s (%d bytes)", clientTitle, len(jsonData))
|
|
// Optionally print first 500 chars
|
|
if len(jsonData) > 500 {
|
|
log.Printf("Preview: %s...", string(jsonData[:500]))
|
|
} else {
|
|
log.Printf("Preview: %s", string(jsonData))
|
|
}
|
|
}
|