This is small tool to help you interact with Grafana API. It could be used to create new Organization, add new user and provision basic datasources from templates, ie. Prometheus, Loki, Tempo.

You can test it using small demo code but you need to have your grafana instance running and available in some URL. You also need to have local Grafana user/pass with admin privileges.

export DEV_GRAFANA_URL=your-url
export DEV_GRAFANA_USER=your-user
export DEV_GRAFANA_PASS='your-pass-with-special-chars'

Grafana Struct

Keeps basic data about target Grafana like url, username, password and base64 encoded user:pass needed for Basic Authentication. This will be added into Authorization Header.

package main

import (
	"encoding/base64"
	"fmt"
)

type Grafana struct {
	Url         string
	User        string
	Pass        string
	Credentials string
}

func EncodeCredentials(g Grafana) Grafana {
	g.Credentials = base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", g.User, g.Pass)))
	return g
}

Organization Struct

Keeps basic data about Organization and implements specific HTTP calls related to Organization, ie. GetOrgById or CreateOrg. It is also populated from HTTP responses by transforming (unmarshaling) JSON into struct.

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strconv"
	"strings"
)

type Org struct {
	Id   int    `json:"orgId"`
	Name string `json:"name"`
}

// Input Grafana must be initialized with credentials
func GetOrgById(g Grafana, id int) Org {

	// Cretate HTTP Request to given Grafana for given Id
	url := g.Url + "/api/orgs/" + strconv.Itoa(id)

	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Basic "+g.Credentials)

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	// Return the Org
	body, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}

	fmt.Println("Response Status:", res.StatusCode)
	if res.StatusCode != http.StatusOK {
		log.Fatal("Couldn't fetch Org: \n", string(body))
	}

	var org Org
	if err := json.Unmarshal(body, &org); err != nil {
		panic(err)
	}

	return org
}

// Input Grafana must be initialized with credentials
func GetOrgByName(g Grafana, name string) Org {

	// Cretate HTTP Request to given Grafana for given Id
	url := g.Url + "/api/orgs/name/" + name

	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Basic "+g.Credentials)

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	// Return the Org
	body, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}

	fmt.Println("Response Status:", res.StatusCode)
	if res.StatusCode != http.StatusOK {
		log.Fatal("Couldn't fetch Org: \n", string(body))
	}

	var org Org
	if err := json.Unmarshal(body, &org); err != nil {
		panic(err)
	}

	return org
}

// Create Org
func CreateOrg(g Grafana, name string) int {

	type OrgResponse struct {
		Message string `json:"message"`
		Id      int    `json:"orgId"`
	}

	// Cretate HTTP Request to given Grafana for given Id
	url := g.Url + "/api/orgs"

	post_body := strings.NewReader(fmt.Sprintf(`{"name": "%s"}`, name))

	req, _ := http.NewRequest("POST", url, post_body)

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Basic "+g.Credentials)

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	// Return the Org
	body, err := io.ReadAll(res.Body)

	if err != nil {
		panic(err)
	}

	fmt.Println("Response Status:", res.StatusCode, string(body))
	if res.StatusCode != http.StatusOK {
		log.Fatal("Couldn't fetch Org: \n", string(body))
	}

	var org_res OrgResponse
	if err := json.Unmarshal(body, &org_res); err != nil {
		panic(err)
	}

	return org_res.Id
}

Test Code

This is simple test to show capabilities

package main

import (
	"fmt"
	"os"
)

func main() {

	dev_grafana := EncodeCredentials(Grafana{
		Url:  os.Getenv("DEV_GRAFANA_URL"),
		User: os.Getenv("DEV_GRAFANA_USER"),

		// If your pass has special characters, export with single quotes
		Pass: os.Getenv("DEV_GRAFANA_PASS"),
	})

	current_org := GetOrgById(dev_grafana, 1)
	fmt.Println("Organization ID:", current_org.Id, "Name:", current_org.Name)

	current_org = GetOrgByName(dev_grafana, "Main Org.")
	fmt.Println("Organization ID:", current_org.Id, "Name:", current_org.Name)

	new_org_id := CreateOrg(dev_grafana, "test-org-1")
	fmt.Println("New Organization ID:", new_org_id)

}