Skip to content

Commit

Permalink
Merge branch 'master' into fix/sort-plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
hubeadmin authored Sep 2, 2024
2 parents f36d9c1 + 02929fb commit 877ca4f
Show file tree
Hide file tree
Showing 14 changed files with 645 additions and 64 deletions.
13 changes: 13 additions & 0 deletions api/v1beta1/grafanadashboard_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ type GrafanaDashboardDatasource struct {
DatasourceName string `json:"datasourceName"`
}

type GrafanaDashboardUrlBasicAuth struct {
Username *v1.SecretKeySelector `json:"username,omitempty"`
Password *v1.SecretKeySelector `json:"password,omitempty"`
}

type GrafanaDashboardUrlAuthorization struct {
BasicAuth *GrafanaDashboardUrlBasicAuth `json:"basicAuth,omitempty"`
}

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

Expand All @@ -64,6 +73,10 @@ type GrafanaDashboardSpec struct {
// +optional
Url string `json:"url,omitempty"`

// authorization options for dashboard from url
// +optional
UrlAuthorization *GrafanaDashboardUrlAuthorization `json:"urlAuthorization,omitempty"`

// Jsonnet
// +optional
Jsonnet string `json:"jsonnet,omitempty"`
Expand Down
50 changes: 50 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 59 additions & 0 deletions config/crd/bases/grafana.integreatly.org_grafanadashboards.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,65 @@ spec:
url:
description: dashboard url
type: string
urlAuthorization:
description: authorization options for dashboard from url
properties:
basicAuth:
properties:
password:
description: SecretKeySelector selects a key of a Secret.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret or its key must
be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
username:
description: SecretKeySelector selects a key of a Secret.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret or its key must
be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
type: object
required:
- instanceSelector
type: object
Expand Down
36 changes: 36 additions & 0 deletions controllers/client/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package client

import (
"context"
"errors"
"fmt"

v1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func GetValueFromSecretKey(ctx context.Context, ref *v1.SecretKeySelector, c client.Client, namespace string) ([]byte, error) {
if ref == nil {
return nil, errors.New("empty secret key selector")
}

secret := &v1.Secret{}
selector := client.ObjectKey{
Name: ref.Name,
Namespace: namespace,
}
err := c.Get(ctx, selector, secret)
if err != nil {
return nil, err
}

if secret.Data == nil {
return nil, fmt.Errorf("empty credential secret: %v/%v", namespace, ref.Name)
}

if val, ok := secret.Data[ref.Key]; ok {
return val, nil
}

return nil, fmt.Errorf("credentials not found in secret: %v/%v", namespace, ref.Name)
}
35 changes: 6 additions & 29 deletions controllers/client/grafana_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ import (
"net/url"
"time"

"github.com/grafana/grafana-operator/v5/controllers/metrics"
v1 "k8s.io/api/core/v1"

genapi "github.com/grafana/grafana-openapi-client-go/client"
"github.com/grafana/grafana-operator/v5/api/v1beta1"
"github.com/grafana/grafana-operator/v5/controllers/config"
"github.com/grafana/grafana-operator/v5/controllers/metrics"
"github.com/grafana/grafana-operator/v5/controllers/model"
"sigs.k8s.io/controller-runtime/pkg/client"
)
Expand All @@ -25,32 +23,11 @@ type grafanaAdminCredentials struct {

func getAdminCredentials(ctx context.Context, c client.Client, grafana *v1beta1.Grafana) (*grafanaAdminCredentials, error) {
credentials := &grafanaAdminCredentials{}
getValueFromSecret := func(ref *v1.SecretKeySelector) ([]byte, error) {
secret := &v1.Secret{}
selector := client.ObjectKey{
Name: ref.Name,
Namespace: grafana.Namespace,
}
err := c.Get(ctx, selector, secret)
if err != nil {
return nil, err
}

if secret.Data == nil {
return nil, fmt.Errorf("empty credential secret: %v/%v", grafana.Namespace, ref.Name)
}

if val, ok := secret.Data[ref.Key]; ok {
return val, nil
}

return nil, fmt.Errorf("admin credentials not found: %v/%v", grafana.Namespace, ref.Name)
}

if grafana.IsExternal() {
// prefer api key if present
if grafana.Spec.External.ApiKey != nil {
apikey, err := getValueFromSecret(grafana.Spec.External.ApiKey)
apikey, err := GetValueFromSecretKey(ctx, grafana.Spec.External.ApiKey, c, grafana.Namespace)
if err != nil {
return nil, err
}
Expand All @@ -59,12 +36,12 @@ func getAdminCredentials(ctx context.Context, c client.Client, grafana *v1beta1.
}

// rely on username and password otherwise
username, err := getValueFromSecret(grafana.Spec.External.AdminUser)
username, err := GetValueFromSecretKey(ctx, grafana.Spec.External.AdminUser, c, grafana.Namespace)
if err != nil {
return nil, err
}

password, err := getValueFromSecret(grafana.Spec.External.AdminPassword)
password, err := GetValueFromSecretKey(ctx, grafana.Spec.External.AdminPassword, c, grafana.Namespace)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -95,7 +72,7 @@ func getAdminCredentials(ctx context.Context, c client.Client, grafana *v1beta1.

if env.ValueFrom != nil {
if env.ValueFrom.SecretKeyRef != nil {
usernameFromSecret, err := getValueFromSecret(env.ValueFrom.SecretKeyRef)
usernameFromSecret, err := GetValueFromSecretKey(ctx, env.ValueFrom.SecretKeyRef, c, grafana.Namespace)
if err != nil {
return nil, err
}
Expand All @@ -111,7 +88,7 @@ func getAdminCredentials(ctx context.Context, c client.Client, grafana *v1beta1.

if env.ValueFrom != nil {
if env.ValueFrom.SecretKeyRef != nil {
passwordFromSecret, err := getValueFromSecret(env.ValueFrom.SecretKeyRef)
passwordFromSecret, err := GetValueFromSecretKey(ctx, env.ValueFrom.SecretKeyRef, c, grafana.Namespace)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions controllers/dashboard_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ func (r *GrafanaDashboardReconciler) fetchDashboardJson(ctx context.Context, das
case v1beta1.DashboardSourceTypeGzipJson:
return v1beta1.Gunzip([]byte(dashboard.Spec.GzipJson))
case v1beta1.DashboardSourceTypeUrl:
return fetchers.FetchDashboardFromUrl(dashboard, client2.InsecureTLSConfiguration)
return fetchers.FetchDashboardFromUrl(ctx, dashboard, r.Client, client2.InsecureTLSConfiguration)
case v1beta1.DashboardSourceTypeJsonnet:
envs, err := r.getDashboardEnvs(ctx, dashboard)
if err != nil {
Expand All @@ -495,7 +495,7 @@ func (r *GrafanaDashboardReconciler) fetchDashboardJson(ctx context.Context, das
}
return fetchers.BuildProjectAndFetchJsonnetFrom(dashboard, envs)
case v1beta1.DashboardSourceTypeGrafanaCom:
return fetchers.FetchDashboardFromGrafanaCom(dashboard)
return fetchers.FetchDashboardFromGrafanaCom(ctx, dashboard, r.Client)
case v1beta1.DashboardSourceConfigMap:
return fetchers.FetchDashboardFromConfigMap(dashboard, r.Client)
default:
Expand Down
7 changes: 5 additions & 2 deletions controllers/fetchers/grafana_com_fetcher.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package fetchers

import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"net/http"

"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/grafana/grafana-operator/v5/api/v1beta1"
client2 "github.com/grafana/grafana-operator/v5/controllers/client"
"github.com/grafana/grafana-operator/v5/controllers/metrics"
)

const grafanaComDashboardApiUrlRoot = "https://grafana.com/api/dashboards"

func FetchDashboardFromGrafanaCom(dashboard *v1beta1.GrafanaDashboard) ([]byte, error) {
func FetchDashboardFromGrafanaCom(ctx context.Context, dashboard *v1beta1.GrafanaDashboard, c client.Client) ([]byte, error) {
cache := dashboard.GetContentCache()
if len(cache) > 0 {
return cache, nil
Expand All @@ -33,7 +36,7 @@ func FetchDashboardFromGrafanaCom(dashboard *v1beta1.GrafanaDashboard) ([]byte,

dashboard.Spec.Url = fmt.Sprintf("%s/%d/revisions/%d/download", grafanaComDashboardApiUrlRoot, source.Id, *source.Revision)

return FetchDashboardFromUrl(dashboard, tlsConfig)
return FetchDashboardFromUrl(ctx, dashboard, c, tlsConfig)
}

func getLatestGrafanaComRevision(dashboard *v1beta1.GrafanaDashboard, tlsConfig *tls.Config) (int, error) {
Expand Down
3 changes: 2 additions & 1 deletion controllers/fetchers/grafana_com_fetcher_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fetchers

import (
"context"
"testing"

"github.com/grafana/grafana-operator/v5/api/v1beta1"
Expand All @@ -17,7 +18,7 @@ func TestFetchDashboardFromGrafanaCom(t *testing.T) {
Status: v1beta1.GrafanaDashboardStatus{},
}

fetchedDashboard, err := FetchDashboardFromGrafanaCom(dashboard)
fetchedDashboard, err := FetchDashboardFromGrafanaCom(context.Background(), dashboard, k8sClient)
assert.Nil(t, err)
assert.NotNil(t, fetchedDashboard, "Fetched dashboard shouldn't be empty")
assert.GreaterOrEqual(t, *dashboard.Spec.GrafanaCom.Revision, 30, "At least 30 revisions exist for dashboard 1860 as of 2023-03-29")
Expand Down
Loading

0 comments on commit 877ca4f

Please sign in to comment.