grafana/pkg/services/publicdashboards/commands/generate_datasources/generate.go
owensmallwood 7de093738d
PublicDashboards: Adds command to generate map of supported datasources (#57841)
generates map of supported datasources for pubdash
2022-11-02 13:35:57 -06:00

107 lines
2.4 KiB
Go

package generate_datasources
import (
"encoding/json"
"fmt"
"net/http"
"sort"
"sync"
)
type listPluginResponse struct {
Items []struct {
Slug string `json:"slug"`
} `json:"items"`
}
type datasourceDetails struct {
Slug string `json:"slug"`
Backend bool `json:"backend"`
Alerting bool `json:"alerting"`
}
type datasource struct {
Json datasourceDetails `json:"json"`
}
// Get the slugs of all datasource plugins that are compatible with public dashboards
func GetCompatibleDatasources(baseUrl string) ([]string, error) {
slugs, err := getDatasourcePluginSlugs(baseUrl)
if err != nil {
return nil, err
}
datasources := getDatasourceDetails(slugs, baseUrl)
// we only consider a datasource to be supported when alerting and backend are both true
var supported []string
for _, datasource := range datasources {
if datasource.Alerting && datasource.Backend {
supported = append(supported, datasource.Slug)
}
}
sort.Strings(supported)
return supported, nil
}
// Get a list of all the datasource plugin slugs
func getDatasourcePluginSlugs(baseUrl string) ([]string, error) {
resp, err := http.Get(baseUrl + allPluginsEndpoint())
if err != nil {
return nil, err
}
res := &listPluginResponse{}
err = json.NewDecoder(resp.Body).Decode(res)
if err != nil {
return nil, err
}
var slugs []string
for _, meta := range res.Items {
slugs = append(slugs, meta.Slug)
}
_ = resp.Body.Close()
return slugs, nil
}
// Get the details for each datasource plugin by its slug
func getDatasourceDetails(slugs []string, baseUrl string) []datasourceDetails {
datasources := make([]datasourceDetails, len(slugs))
var wg sync.WaitGroup
for i, slug := range slugs {
wg.Add(1)
// create new goroutine for each outgoing request
go func(i int, slug string) {
defer wg.Done()
url := baseUrl + pluginEndpoint(slug)
// url can not be constant since it gets generated based on slug
//nolint:gosec
r, err := http.Get(url)
if err != nil {
panic(err)
}
datasource := &datasource{}
err = json.NewDecoder(r.Body).Decode(datasource)
if err != nil {
panic(err)
}
datasource.Json.Slug = slug
datasources[i] = datasource.Json
_ = r.Body.Close()
}(i, slug)
}
wg.Wait()
return datasources
}
func pluginEndpoint(slug string) string {
return fmt.Sprintf("/api/plugins/%s?version=latest", slug)
}
func allPluginsEndpoint() string {
return "/api/plugins?orderBy=weight&direction=asc&typeCodeIn[]=datasource"
}