grafana_gen/grafana.go
2026-02-24 12:45:35 +03:00

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))
}
}