github.com/esnet/gdg@v0.6.1-0.20240412190737-6b6eba9c14d8/internal/service/libraryelements.go (about)

     1  package service
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"github.com/esnet/gdg/internal/config"
     8  	"github.com/esnet/gdg/internal/service/filters"
     9  	"github.com/esnet/gdg/internal/tools"
    10  	"github.com/gosimple/slug"
    11  	"github.com/grafana/grafana-openapi-client-go/client/library_elements"
    12  	"github.com/grafana/grafana-openapi-client-go/models"
    13  	"github.com/tidwall/gjson"
    14  	"golang.org/x/exp/maps"
    15  	"golang.org/x/exp/slices"
    16  	"log"
    17  	"log/slog"
    18  	"strings"
    19  )
    20  
    21  const (
    22  	listLibraryPanels int64 = 1
    23  	listLibraryVars   int64 = 2
    24  )
    25  
    26  func (s *DashNGoImpl) ListLibraryElementsConnections(filter filters.Filter, connectionID string) []*models.DashboardFullWithMeta {
    27  	payload, err := s.GetClient().LibraryElements.GetLibraryElementConnections(connectionID)
    28  	if err != nil {
    29  		log.Fatalf("unable to retrieve a valid connection for %s", connectionID)
    30  	}
    31  	var results []*models.DashboardFullWithMeta
    32  
    33  	for _, item := range payload.GetPayload().Result {
    34  		dashboard, err := s.getDashboardByUid(item.ConnectionUID)
    35  		if err != nil {
    36  			slog.Error("failed to retrieve linked Dashboard", "uid", item.ConnectionUID)
    37  		}
    38  		results = append(results, dashboard)
    39  	}
    40  
    41  	return results
    42  }
    43  
    44  func (s *DashNGoImpl) ListLibraryElements(filter filters.Filter) []*models.LibraryElementDTO {
    45  	ignoreFilters := config.Config().GetDefaultGrafanaConfig().GetFilterOverrides().IgnoreDashboardFilters
    46  	folderFilter := NewFolderFilter()
    47  	if ignoreFilters {
    48  		folderFilter = nil
    49  	}
    50  
    51  	folderNameMap := getFolderNameIDMap(s.ListFolder(folderFilter))
    52  	values := maps.Values(folderNameMap)
    53  	var buf = strings.Builder{}
    54  	//Check to see if General should be included
    55  	//If Ignore Filters OR General is in monitored list, add 0 folder
    56  	if (!ignoreFilters && slices.Contains(config.Config().GetDefaultGrafanaConfig().GetMonitoredFolders(), DefaultFolderName)) || ignoreFilters {
    57  		buf.WriteString("0,")
    58  	} else {
    59  		buf.WriteString("")
    60  	}
    61  	for _, i := range values {
    62  		buf.WriteString(fmt.Sprintf("%d,", i))
    63  	}
    64  	folderList := buf.String()[:len(buf.String())-1]
    65  
    66  	params := library_elements.NewGetLibraryElementsParams()
    67  	params.FolderFilter = &folderList
    68  	params.Kind = tools.PtrOf(listLibraryPanels)
    69  	libraryElements, err := s.GetClient().LibraryElements.GetLibraryElements(params)
    70  	if err != nil {
    71  		log.Fatalf("Unable to list Library Elements %v", err)
    72  
    73  	}
    74  	return libraryElements.GetPayload().Result.Elements
    75  }
    76  
    77  // DownloadLibraryElements downloads all the Library Elements
    78  func (s *DashNGoImpl) DownloadLibraryElements(filter filters.Filter) []string {
    79  	var (
    80  		listing   []*models.LibraryElementDTO
    81  		dsPacked  []byte
    82  		err       error
    83  		dataFiles []string
    84  	)
    85  
    86  	folderMap := reverseLookUp(getFolderNameIDMap(s.ListFolder(nil)))
    87  	listing = s.ListLibraryElements(filter)
    88  	for _, item := range listing {
    89  		if dsPacked, err = json.MarshalIndent(item, "", "	"); err != nil {
    90  			slog.Error("Unable to serialize object", "err", err, "library-element", item.Name)
    91  			continue
    92  		}
    93  		folderName := DefaultFolderName
    94  
    95  		if val, ok := folderMap[item.FolderID]; ok {
    96  			folderName = val
    97  		}
    98  
    99  		libraryPath := fmt.Sprintf("%s/%s.json", BuildResourceFolder(folderName, config.LibraryElementResource), slug.Make(item.Name))
   100  
   101  		if err = s.storage.WriteFile(libraryPath, dsPacked); err != nil {
   102  			slog.Error("Unable to write file", "err", err, "library-element", slug.Make(item.Name))
   103  		} else {
   104  			dataFiles = append(dataFiles, libraryPath)
   105  		}
   106  	}
   107  	return dataFiles
   108  }
   109  
   110  // UploadLibraryElements uploads all the Library Elements
   111  func (s *DashNGoImpl) UploadLibraryElements(filter filters.Filter) []string {
   112  	var (
   113  		exported          []string = make([]string, 0)
   114  		rawLibraryElement []byte
   115  		folderName        string
   116  		libraryUID        string
   117  	)
   118  
   119  	slog.Info("Reading files from folder", "folder", config.Config().GetDefaultGrafanaConfig().GetPath(config.LibraryElementResource))
   120  	filesInDir, err := s.storage.FindAllFiles(config.Config().GetDefaultGrafanaConfig().GetPath(config.LibraryElementResource), true)
   121  
   122  	currentLibElements := s.ListLibraryElements(filter)
   123  	libMapping := make(map[string]*models.LibraryElementDTO, 0)
   124  	//Build a mapping by UID
   125  	for ndx, item := range currentLibElements {
   126  		libMapping[item.UID] = currentLibElements[ndx]
   127  	}
   128  
   129  	if err != nil {
   130  		slog.Error("failed to list files in directory for library elements", "err", err)
   131  	}
   132  
   133  	for _, file := range filesInDir {
   134  		fileLocation := file
   135  		if strings.HasSuffix(file, ".json") {
   136  			if rawLibraryElement, err = s.storage.ReadFile(fileLocation); err != nil {
   137  				slog.Error("failed to read file", "file", fileLocation, "err", err)
   138  				continue
   139  			}
   140  
   141  			Results := gjson.GetManyBytes(rawLibraryElement, "meta.folderName", "uid")
   142  
   143  			if Results[0].Exists() {
   144  				folderName = Results[0].String()
   145  			} else {
   146  				slog.Error("Unable to determine folder name of library component, skipping.", "filename", file)
   147  				continue
   148  			}
   149  			//Get UID
   150  			if Results[1].Exists() {
   151  				libraryUID = Results[1].String()
   152  			} else {
   153  				slog.Error("Unable to determine the library panel UID, attempting to export anyways", "filename", file)
   154  			}
   155  
   156  			if _, ok := libMapping[libraryUID]; ok {
   157  				slog.Warn("Library already exists, skipping", "filename", file)
   158  				continue
   159  			}
   160  
   161  			if !slices.Contains(config.Config().GetDefaultGrafanaConfig().GetMonitoredFolders(), folderName) {
   162  				slog.Warn("Skipping since requested file is not in a folder gdg is configured to manage", "folder", folderName, "file", file)
   163  				continue
   164  			}
   165  			var newLibraryRequest models.CreateLibraryElementCommand
   166  
   167  			if err = json.Unmarshal(rawLibraryElement, &newLibraryRequest); err != nil {
   168  				slog.Error("failed to unmarshall file", "filename", fileLocation, "err", err)
   169  				continue
   170  			}
   171  
   172  			entity, err := s.GetClient().LibraryElements.CreateLibraryElement(&newLibraryRequest)
   173  			if err != nil {
   174  				slog.Error("Failed to create library element", "err", err)
   175  			} else {
   176  				exported = append(exported, entity.Payload.Result.Name)
   177  			}
   178  		}
   179  	}
   180  	return exported
   181  }
   182  
   183  // DeleteAllLibraryElements deletes all the Library Elements
   184  func (s *DashNGoImpl) DeleteAllLibraryElements(filter filters.Filter) []string {
   185  	var entries []string
   186  	libraryElements := s.ListLibraryElements(filter)
   187  	for _, element := range libraryElements {
   188  
   189  		_, err := s.GetClient().LibraryElements.DeleteLibraryElementByUID(element.UID)
   190  		if err != nil {
   191  			logEntries := make([]interface{}, 0)
   192  			var serr *library_elements.DeleteLibraryElementByUIDForbidden
   193  			if errors.As(err, &serr) {
   194  				logEntries = append(logEntries, []interface{}{"ErrorMessage", *serr.GetPayload().Message}...)
   195  			}
   196  
   197  			logEntries = append(logEntries, []interface{}{"panel", element.Name}...)
   198  			slog.Error("Failed to delete library panel", logEntries...)
   199  			continue
   200  		}
   201  		entries = append(entries, element.Name)
   202  	}
   203  
   204  	return entries
   205  }