mirror of https://github.com/grafana/loki
operator: Add support for reconciling loki-mixin dashboards on OpenShift Console (#9468)
Co-authored-by: Robert Jacob <xperimental@solidproject.de>pull/9692/head
parent
8ca1d1e0a4
commit
38556c1d37
@ -0,0 +1,5 @@ |
||||
module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT |
||||
|
||||
go 1.20 |
||||
|
||||
require github.com/jsonnet-bundler/jsonnet-bundler v0.5.1 // cmd/jb |
@ -0,0 +1,50 @@ |
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= |
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= |
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= |
||||
github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= |
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= |
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= |
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= |
||||
github.com/jsonnet-bundler/jsonnet-bundler v0.5.1 h1:eUd6EA1Qzz73Q4NLNLOrNkMb96+6NTTERbX9lqaxVwk= |
||||
github.com/jsonnet-bundler/jsonnet-bundler v0.5.1/go.mod h1:Qrdw/7mOFS2SKCOALKFfEH8gdvXJi8XZjw9g5ilpf4I= |
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= |
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= |
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= |
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= |
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= |
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= |
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= |
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= |
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= |
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= |
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= |
||||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= |
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= |
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= |
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= |
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= |
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= |
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= |
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= |
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
@ -0,0 +1,5 @@ |
||||
module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT |
||||
|
||||
go 1.20 |
||||
|
||||
require github.com/google/go-jsonnet v0.20.0 // cmd/jsonnet |
@ -0,0 +1,17 @@ |
||||
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= |
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= |
||||
github.com/google/go-jsonnet v0.20.0 h1:WG4TTSARuV7bSm4PMB4ohjxe33IHT5WVTrJSU33uT4g= |
||||
github.com/google/go-jsonnet v0.20.0/go.mod h1:VbgWF9JX7ztlv770x/TolZNGGFfiHEVx9G6ca2eUmeA= |
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= |
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= |
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= |
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= |
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= |
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= |
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= |
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= |
@ -0,0 +1,5 @@ |
||||
module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT |
||||
|
||||
go 1.20 |
||||
|
||||
require github.com/google/go-jsonnet v0.20.0 // cmd/jsonnetfmt |
@ -0,0 +1,17 @@ |
||||
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= |
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= |
||||
github.com/google/go-jsonnet v0.20.0 h1:WG4TTSARuV7bSm4PMB4ohjxe33IHT5WVTrJSU33uT4g= |
||||
github.com/google/go-jsonnet v0.20.0/go.mod h1:VbgWF9JX7ztlv770x/TolZNGGFfiHEVx9G6ca2eUmeA= |
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= |
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= |
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= |
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= |
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= |
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= |
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= |
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= |
@ -0,0 +1,66 @@ |
||||
package controllers |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/ViaQ/logerr/v2/kverrors" |
||||
"github.com/go-logr/logr" |
||||
lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" |
||||
"github.com/grafana/loki/operator/internal/handlers" |
||||
"k8s.io/apimachinery/pkg/labels" |
||||
"k8s.io/apimachinery/pkg/runtime" |
||||
ctrl "sigs.k8s.io/controller-runtime" |
||||
"sigs.k8s.io/controller-runtime/pkg/builder" |
||||
"sigs.k8s.io/controller-runtime/pkg/client" |
||||
"sigs.k8s.io/controller-runtime/pkg/event" |
||||
"sigs.k8s.io/controller-runtime/pkg/manager" |
||||
"sigs.k8s.io/controller-runtime/pkg/predicate" |
||||
) |
||||
|
||||
var createOrDeletesPred = builder.WithPredicates(predicate.Funcs{ |
||||
UpdateFunc: func(e event.UpdateEvent) bool { return false }, |
||||
CreateFunc: func(e event.CreateEvent) bool { return true }, |
||||
DeleteFunc: func(e event.DeleteEvent) bool { return true }, |
||||
GenericFunc: func(e event.GenericEvent) bool { return false }, |
||||
}) |
||||
|
||||
// DashboardsReconciler deploys and removes the cluster-global resources needed
|
||||
// for the metrics dashboards depending on whether any LokiStacks exist.
|
||||
type DashboardsReconciler struct { |
||||
client.Client |
||||
Scheme *runtime.Scheme |
||||
Log logr.Logger |
||||
OperatorNs string |
||||
} |
||||
|
||||
// Reconcile creates all LokiStack dashboard ConfigMap and PrometheusRule objects on OpenShift clusters when
|
||||
// the at least one LokiStack custom resource exists or removes all when none.
|
||||
func (r *DashboardsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { |
||||
var stacks lokiv1.LokiStackList |
||||
if err := r.List(ctx, &stacks, client.MatchingLabelsSelector{Selector: labels.Everything()}); err != nil { |
||||
return ctrl.Result{}, kverrors.Wrap(err, "failed to list any lokistack instances") |
||||
} |
||||
|
||||
if len(stacks.Items) == 0 { |
||||
// Removes all LokiStack dashboard resources on OpenShift clusters when
|
||||
// the last LokiStack custom resource is deleted.
|
||||
if err := handlers.DeleteDashboards(ctx, r.Client, r.OperatorNs); err != nil { |
||||
return ctrl.Result{}, kverrors.Wrap(err, "failed to delete dashboard resources") |
||||
} |
||||
return ctrl.Result{}, nil |
||||
} |
||||
|
||||
// Creates all LokiStack dashboard resources on OpenShift clusters when
|
||||
// the first LokiStack custom resource is created.
|
||||
if err := handlers.CreateDashboards(ctx, r.Log, r.OperatorNs, r.Client, r.Scheme); err != nil { |
||||
return ctrl.Result{}, kverrors.Wrap(err, "failed to create dashboard resources", "req", req) |
||||
} |
||||
return ctrl.Result{}, nil |
||||
} |
||||
|
||||
// SetupWithManager sets up the controller with the Manager to only call this controller on create/delete/generic events.
|
||||
func (r *DashboardsReconciler) SetupWithManager(mgr manager.Manager) error { |
||||
return ctrl.NewControllerManagedBy(mgr). |
||||
For(&lokiv1.LokiStack{}, createOrDeletesPred). |
||||
Complete(r) |
||||
} |
@ -0,0 +1,51 @@ |
||||
package handlers |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
|
||||
"github.com/ViaQ/logerr/v2/kverrors" |
||||
"github.com/go-logr/logr" |
||||
"github.com/grafana/loki/operator/internal/external/k8s" |
||||
"github.com/grafana/loki/operator/internal/manifests" |
||||
"github.com/grafana/loki/operator/internal/manifests/openshift" |
||||
"k8s.io/apimachinery/pkg/runtime" |
||||
ctrl "sigs.k8s.io/controller-runtime" |
||||
"sigs.k8s.io/controller-runtime/pkg/client" |
||||
ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" |
||||
) |
||||
|
||||
// CreateDashboards handles the LokiStack dashboards create events.
|
||||
func CreateDashboards(ctx context.Context, log logr.Logger, operatorNs string, k k8s.Client, s *runtime.Scheme) error { |
||||
objs, err := openshift.BuildDashboards(operatorNs) |
||||
if err != nil { |
||||
return kverrors.Wrap(err, "failed to build dashboard manifests") |
||||
} |
||||
|
||||
var errCount int32 |
||||
for _, obj := range objs { |
||||
desired := obj.DeepCopyObject().(client.Object) |
||||
mutateFn := manifests.MutateFuncFor(obj, desired, nil) |
||||
|
||||
op, err := ctrl.CreateOrUpdate(ctx, k, obj, mutateFn) |
||||
if err != nil { |
||||
log.Error(err, "failed to configure resource") |
||||
errCount++ |
||||
continue |
||||
} |
||||
|
||||
msg := fmt.Sprintf("Resource has been %s", op) |
||||
switch op { |
||||
case ctrlutil.OperationResultNone: |
||||
log.V(1).Info(msg) |
||||
default: |
||||
log.Info(msg) |
||||
} |
||||
} |
||||
|
||||
if errCount > 0 { |
||||
return kverrors.New("failed to configure lokistack dashboard resources") |
||||
} |
||||
|
||||
return nil |
||||
} |
@ -0,0 +1,61 @@ |
||||
package handlers |
||||
|
||||
import ( |
||||
"context" |
||||
"testing" |
||||
|
||||
lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" |
||||
"github.com/grafana/loki/operator/internal/external/k8s/k8sfakes" |
||||
|
||||
"github.com/stretchr/testify/assert" |
||||
"github.com/stretchr/testify/require" |
||||
apierrors "k8s.io/apimachinery/pkg/api/errors" |
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||
"k8s.io/apimachinery/pkg/runtime/schema" |
||||
"k8s.io/apimachinery/pkg/types" |
||||
ctrl "sigs.k8s.io/controller-runtime" |
||||
"sigs.k8s.io/controller-runtime/pkg/client" |
||||
) |
||||
|
||||
func TestCreateDashboards_ReturnsResourcesInManagedNamespaces(t *testing.T) { |
||||
sw := &k8sfakes.FakeStatusWriter{} |
||||
k := &k8sfakes.FakeClient{} |
||||
r := ctrl.Request{ |
||||
NamespacedName: types.NamespacedName{ |
||||
Name: "my-stack", |
||||
Namespace: "some-ns", |
||||
}, |
||||
} |
||||
|
||||
stack := lokiv1.LokiStack{ |
||||
TypeMeta: metav1.TypeMeta{ |
||||
Kind: "LokiStack", |
||||
}, |
||||
ObjectMeta: metav1.ObjectMeta{ |
||||
Name: "my-stack", |
||||
Namespace: "some-ns", |
||||
UID: "b23f9a38-9672-499f-8c29-15ede74d3ece", |
||||
}, |
||||
} |
||||
|
||||
k.GetStub = func(_ context.Context, name types.NamespacedName, out client.Object, _ ...client.GetOption) error { |
||||
if r.Name == name.Name && r.Namespace == name.Namespace { |
||||
k.SetClientObject(out, &stack) |
||||
return nil |
||||
} |
||||
return apierrors.NewNotFound(schema.GroupResource{}, "something wasn't found") |
||||
} |
||||
|
||||
k.CreateStub = func(_ context.Context, o client.Object, _ ...client.CreateOption) error { |
||||
assert.NotEqual(t, r.Namespace, o.GetNamespace()) |
||||
return nil |
||||
} |
||||
|
||||
k.StatusStub = func() client.StatusWriter { return sw } |
||||
|
||||
err := CreateDashboards(context.TODO(), logger, "test", k, scheme) |
||||
require.NoError(t, err) |
||||
|
||||
// make sure create was called
|
||||
require.NotZero(t, k.CreateCallCount()) |
||||
} |
@ -0,0 +1,30 @@ |
||||
package handlers |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/ViaQ/logerr/v2/kverrors" |
||||
"github.com/grafana/loki/operator/internal/external/k8s" |
||||
"github.com/grafana/loki/operator/internal/manifests/openshift" |
||||
apierrors "k8s.io/apimachinery/pkg/api/errors" |
||||
"sigs.k8s.io/controller-runtime/pkg/client" |
||||
) |
||||
|
||||
// DeleteDashboards removes all cluster-scoped dashboard resources.
|
||||
func DeleteDashboards(ctx context.Context, k k8s.Client, operatorNs string) error { |
||||
objs, err := openshift.BuildDashboards(operatorNs) |
||||
if err != nil { |
||||
return kverrors.Wrap(err, "failed to build dashboards manifests") |
||||
} |
||||
|
||||
for _, obj := range objs { |
||||
key := client.ObjectKeyFromObject(obj) |
||||
if err := k.Delete(ctx, obj, &client.DeleteOptions{}); err != nil { |
||||
if apierrors.IsNotFound(err) { |
||||
continue |
||||
} |
||||
return kverrors.Wrap(err, "failed to delete dashboard", "key", key) |
||||
} |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,34 @@ |
||||
package handlers |
||||
|
||||
import ( |
||||
"context" |
||||
"testing" |
||||
|
||||
"github.com/grafana/loki/operator/internal/external/k8s/k8sfakes" |
||||
"github.com/grafana/loki/operator/internal/manifests/openshift" |
||||
"github.com/stretchr/testify/require" |
||||
apierrors "k8s.io/apimachinery/pkg/api/errors" |
||||
"k8s.io/apimachinery/pkg/runtime/schema" |
||||
"sigs.k8s.io/controller-runtime/pkg/client" |
||||
) |
||||
|
||||
func TestDeleteDashboards(t *testing.T) { |
||||
objs, err := openshift.BuildDashboards("operator-ns") |
||||
require.NoError(t, err) |
||||
|
||||
k := &k8sfakes.FakeClient{} |
||||
|
||||
err = DeleteDashboards(context.TODO(), k, "operator-ns") |
||||
require.NoError(t, err) |
||||
require.Equal(t, k.DeleteCallCount(), len(objs)) |
||||
} |
||||
|
||||
func TestDeleteDashboards_ReturnsNoError_WhenNotFound(t *testing.T) { |
||||
k := &k8sfakes.FakeClient{} |
||||
k.DeleteStub = func(context.Context, client.Object, ...client.DeleteOption) error { |
||||
return apierrors.NewNotFound(schema.GroupResource{}, "something wasn't found") |
||||
} |
||||
|
||||
err := DeleteDashboards(context.TODO(), k, "operator-ns") |
||||
require.NoError(t, err) |
||||
} |
@ -0,0 +1,71 @@ |
||||
package openshift |
||||
|
||||
import ( |
||||
"strings" |
||||
|
||||
corev1 "k8s.io/api/core/v1" |
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client" |
||||
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" |
||||
|
||||
"github.com/grafana/loki/operator/internal/manifests/openshift/internal/dashboards" |
||||
) |
||||
|
||||
const ( |
||||
labelConsoleDashboard = "console.openshift.io/dashboard" |
||||
managedConfigNamespace = "openshift-config-managed" |
||||
) |
||||
|
||||
func BuildDashboards(operatorNs string) ([]client.Object, error) { |
||||
ds, rules := dashboards.Content() |
||||
|
||||
var objs []client.Object |
||||
for name, content := range ds { |
||||
objs = append(objs, newDashboardConfigMap(name, content)) |
||||
} |
||||
|
||||
promRule, err := newDashboardPrometheusRule(operatorNs, rules) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
objs = append(objs, promRule) |
||||
|
||||
return objs, nil |
||||
} |
||||
|
||||
func newDashboardConfigMap(filename string, content []byte) *corev1.ConfigMap { |
||||
cmName := strings.Split(filename, ".")[0] |
||||
|
||||
return &corev1.ConfigMap{ |
||||
TypeMeta: metav1.TypeMeta{ |
||||
Kind: "ConfigMap", |
||||
APIVersion: corev1.SchemeGroupVersion.String(), |
||||
}, |
||||
ObjectMeta: metav1.ObjectMeta{ |
||||
Name: cmName, |
||||
Namespace: managedConfigNamespace, |
||||
Labels: map[string]string{ |
||||
labelConsoleDashboard: "true", |
||||
}, |
||||
}, |
||||
Data: map[string]string{ |
||||
filename: string(content), |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func newDashboardPrometheusRule(namespace string, spec *monitoringv1.PrometheusRuleSpec) (*monitoringv1.PrometheusRule, error) { |
||||
return &monitoringv1.PrometheusRule{ |
||||
TypeMeta: metav1.TypeMeta{ |
||||
Kind: "PrometheusRule", |
||||
APIVersion: monitoringv1.SchemeGroupVersion.String(), |
||||
}, |
||||
ObjectMeta: metav1.ObjectMeta{ |
||||
Name: dashboardPrometheusRulesName, |
||||
Namespace: namespace, |
||||
}, |
||||
Spec: *spec, |
||||
}, nil |
||||
} |
@ -0,0 +1,32 @@ |
||||
package openshift |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" |
||||
"github.com/stretchr/testify/require" |
||||
corev1 "k8s.io/api/core/v1" |
||||
) |
||||
|
||||
func TestBuildDashboards_ReturnsDashboardConfigMaps(t *testing.T) { |
||||
objs, err := BuildDashboards("test") |
||||
require.NoError(t, err) |
||||
|
||||
for _, d := range objs { |
||||
switch d.(type) { |
||||
case *corev1.ConfigMap: |
||||
require.Equal(t, d.GetNamespace(), managedConfigNamespace) |
||||
require.Contains(t, d.GetLabels(), labelConsoleDashboard) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestBuildDashboards_ReturnsPrometheusRules(t *testing.T) { |
||||
objs, err := BuildDashboards("test") |
||||
require.NoError(t, err) |
||||
|
||||
rules := objs[len(objs)-1].(*monitoringv1.PrometheusRule) |
||||
require.Equal(t, rules.GetName(), dashboardPrometheusRulesName) |
||||
require.Equal(t, rules.GetNamespace(), "test") |
||||
require.NotNil(t, rules.Spec) |
||||
} |
@ -0,0 +1,60 @@ |
||||
package dashboards |
||||
|
||||
import ( |
||||
"embed" |
||||
"encoding/json" |
||||
"io/fs" |
||||
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" |
||||
) |
||||
|
||||
const ( |
||||
staticDir = "static" |
||||
lokiStackDashboardRulesFile = "grafana-dashboard-lokistack-rules.json" |
||||
) |
||||
|
||||
var ( |
||||
//go:embed static/*.json
|
||||
lokiStackDashboards embed.FS |
||||
dashboardMap map[string][]byte |
||||
dashboardRules *monitoringv1.PrometheusRuleSpec |
||||
) |
||||
|
||||
func init() { |
||||
var err error |
||||
subDir, err := fs.Sub(lokiStackDashboards, staticDir) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
jsonFiles, err := fs.Glob(subDir, "*.json") |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
dashboardMap = map[string][]byte{} |
||||
for _, file := range jsonFiles { |
||||
var content []byte |
||||
content, err = fs.ReadFile(subDir, file) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
switch file { |
||||
case lokiStackDashboardRulesFile: |
||||
err := json.Unmarshal(content, &dashboardRules) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
default: |
||||
dashboardMap[file] = content |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Content returns the byte slices one for each LokiStack dashboard
|
||||
// and a separate byte slice for the recording rules from the embedded filesystem.
|
||||
func Content() (map[string][]byte, *monitoringv1.PrometheusRuleSpec) { |
||||
return dashboardMap, dashboardRules |
||||
} |
@ -0,0 +1,27 @@ |
||||
package dashboards |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
const ( |
||||
lokiStackChunkDashboardFile = "grafana-dashboard-lokistack-chunks.json" |
||||
lokiStackReadsDashboardFile = "grafana-dashboard-lokistack-reads.json" |
||||
lokiStackWritesDashboardFile = "grafana-dashboard-lokistack-writes.json" |
||||
lokiStackRetentionDashboardFile = "grafana-dashboard-lokistack-retention.json" |
||||
) |
||||
|
||||
func TestContent(t *testing.T) { |
||||
m, r := Content() |
||||
require.Len(t, m, 4) |
||||
require.Equal(t, dashboardMap, m) |
||||
require.Equal(t, dashboardRules, r) |
||||
|
||||
require.Contains(t, m, lokiStackChunkDashboardFile) |
||||
require.Contains(t, m, lokiStackReadsDashboardFile) |
||||
require.Contains(t, m, lokiStackWritesDashboardFile) |
||||
require.Contains(t, m, lokiStackRetentionDashboardFile) |
||||
require.NotContains(t, m, lokiStackDashboardRulesFile) |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,680 @@ |
||||
{ |
||||
"annotations": { |
||||
"list": [ ] |
||||
}, |
||||
"editable": true, |
||||
"gnetId": null, |
||||
"graphTooltip": 0, |
||||
"hideControls": false, |
||||
"links": [ |
||||
{ |
||||
"asDropdown": true, |
||||
"icon": "external link", |
||||
"includeVars": true, |
||||
"keepTime": true, |
||||
"tags": [ |
||||
"loki" |
||||
], |
||||
"targetBlank": false, |
||||
"title": "Loki Dashboards", |
||||
"type": "dashboards" |
||||
} |
||||
], |
||||
"refresh": "10s", |
||||
"rows": [ |
||||
{ |
||||
"collapse": false, |
||||
"height": "250px", |
||||
"panels": [ |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 1, |
||||
"id": 1, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ |
||||
{ |
||||
"alias": "request", |
||||
"color": "#FFC000", |
||||
"fill": 0 |
||||
}, |
||||
{ |
||||
"alias": "limit", |
||||
"color": "#E02F44", |
||||
"fill": 0 |
||||
} |
||||
], |
||||
"spaceLength": 10, |
||||
"span": 4, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "sum by(pod) (rate(container_cpu_usage_seconds_total{ namespace=~\"$namespace\", container=~\".+-compactor\"}[$__rate_interval]))", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "{{pod}}", |
||||
"legendLink": null, |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "min(kube_pod_container_resource_requests{ namespace=~\"$namespace\", container=~\".+-compactor\", resource=\"cpu\"} > 0)", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "request", |
||||
"legendLink": null, |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "min(container_spec_cpu_quota{ namespace=~\"$namespace\", container=~\".+-compactor\"} / container_spec_cpu_period{ namespace=~\"$namespace\", container=~\".+-compactor\"})", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "limit", |
||||
"legendLink": null, |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "CPU", |
||||
"tooltip": { |
||||
"sort": 2 |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 1, |
||||
"id": 2, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ |
||||
{ |
||||
"alias": "request", |
||||
"color": "#FFC000", |
||||
"fill": 0 |
||||
}, |
||||
{ |
||||
"alias": "limit", |
||||
"color": "#E02F44", |
||||
"fill": 0 |
||||
} |
||||
], |
||||
"spaceLength": 10, |
||||
"span": 4, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "max by(pod) (container_memory_working_set_bytes{ namespace=~\"$namespace\", container=~\".+-compactor\"})", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "{{pod}}", |
||||
"legendLink": null, |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "min(kube_pod_container_resource_requests{ namespace=~\"$namespace\", container=~\".+-compactor\", resource=\"memory\"} > 0)", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "request", |
||||
"legendLink": null, |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "min(container_spec_memory_limit_bytes{ namespace=~\"$namespace\", container=~\".+-compactor\"} > 0)", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "limit", |
||||
"legendLink": null, |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "Memory (workingset)", |
||||
"tooltip": { |
||||
"sort": 2 |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "bytes", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 1, |
||||
"id": 3, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 4, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "sum by(pod) (go_memstats_heap_inuse_bytes{ namespace=\"$namespace\", job=~\".+-compactor-http\"})", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "{{pod}}", |
||||
"legendLink": null, |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "Memory (go heap inuse)", |
||||
"tooltip": { |
||||
"sort": 2 |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "bytes", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"repeat": null, |
||||
"repeatIteration": null, |
||||
"repeatRowId": null, |
||||
"showTitle": true, |
||||
"title": "Resource Usage", |
||||
"titleSize": "h6" |
||||
}, |
||||
{ |
||||
"collapse": false, |
||||
"height": "250px", |
||||
"panels": [ |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fieldConfig": { |
||||
"defaults": { |
||||
"color": { |
||||
"fixedColor": "blue", |
||||
"mode": "fixed" |
||||
}, |
||||
"custom": { }, |
||||
"thresholds": { |
||||
"mode": "absolute", |
||||
"steps": [ |
||||
{ |
||||
"color": "green", |
||||
"value": null |
||||
} |
||||
] |
||||
}, |
||||
"unit": "dateTimeFromNow" |
||||
} |
||||
}, |
||||
"fill": 1, |
||||
"id": 4, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"options": { |
||||
"colorMode": "value", |
||||
"graphMode": "area", |
||||
"justifyMode": "auto", |
||||
"orientation": "auto", |
||||
"reduceOptions": { |
||||
"calcs": [ |
||||
"lastNotNull" |
||||
], |
||||
"fields": "", |
||||
"values": false |
||||
}, |
||||
"text": { }, |
||||
"textMode": "auto" |
||||
}, |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 4, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "loki_boltdb_shipper_compact_tables_operation_last_successful_run_timestamp_seconds{ namespace=~\"$namespace\"} * 1e3", |
||||
"format": "time_series", |
||||
"instant": true, |
||||
"refId": "A" |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "Last Compact and Mark Operation Success", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "stat", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 1, |
||||
"id": 5, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 4, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "loki_boltdb_shipper_compact_tables_operation_duration_seconds{ namespace=~\"$namespace\"}", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "duration", |
||||
"legendLink": null, |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "Compact and Mark Operations Duration", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "s", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 1, |
||||
"id": 6, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 4, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "sum by (status)(rate(loki_boltdb_shipper_compact_tables_operation_total{ namespace=~\"$namespace\"}[$__rate_interval]))", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "{{success}}", |
||||
"legendLink": null, |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "Compact and Mark Operations Per Status", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"repeat": null, |
||||
"repeatIteration": null, |
||||
"repeatRowId": null, |
||||
"showTitle": true, |
||||
"title": "Compact and Mark", |
||||
"titleSize": "h6" |
||||
} |
||||
], |
||||
"schemaVersion": 14, |
||||
"style": "dark", |
||||
"tags": [ |
||||
"loki", |
||||
"logging", |
||||
"loki-mixin" |
||||
], |
||||
"templating": { |
||||
"list": [ |
||||
{ |
||||
"current": { |
||||
"selected": true, |
||||
"text": "default", |
||||
"value": "default" |
||||
}, |
||||
"hide": 0, |
||||
"label": "Data Source", |
||||
"name": "datasource", |
||||
"options": [ ], |
||||
"query": "prometheus", |
||||
"refresh": 1, |
||||
"regex": "", |
||||
"type": "datasource" |
||||
}, |
||||
{ |
||||
"allValue": null, |
||||
"current": { |
||||
"selected": false, |
||||
"text": "openshift-logging", |
||||
"value": "openshift-logging" |
||||
}, |
||||
"datasource": "${datasource}", |
||||
"definition": "label_values(loki_build_info, namespace)", |
||||
"hide": 0, |
||||
"includeAll": false, |
||||
"label": "namespace", |
||||
"multi": false, |
||||
"name": "namespace", |
||||
"options": [ ], |
||||
"query": "label_values(loki_build_info, namespace)", |
||||
"refresh": 1, |
||||
"regex": "", |
||||
"sort": 2, |
||||
"tagValuesQuery": "", |
||||
"tags": [ ], |
||||
"tagsQuery": "", |
||||
"type": "query", |
||||
"useTags": false |
||||
}, |
||||
{ |
||||
"hide": 0, |
||||
"label": null, |
||||
"name": "loki_datasource", |
||||
"options": [ ], |
||||
"query": "loki", |
||||
"refresh": 1, |
||||
"regex": "", |
||||
"type": "datasource" |
||||
} |
||||
] |
||||
}, |
||||
"time": { |
||||
"from": "now-1h", |
||||
"to": "now" |
||||
}, |
||||
"timepicker": { |
||||
"refresh_intervals": [ |
||||
"5s", |
||||
"10s", |
||||
"30s", |
||||
"1m", |
||||
"5m", |
||||
"15m", |
||||
"30m", |
||||
"1h", |
||||
"2h", |
||||
"1d" |
||||
], |
||||
"time_options": [ |
||||
"5m", |
||||
"15m", |
||||
"1h", |
||||
"6h", |
||||
"12h", |
||||
"24h", |
||||
"2d", |
||||
"7d", |
||||
"30d" |
||||
] |
||||
}, |
||||
"timezone": "utc", |
||||
"title": "OpenShift Logging / LokiStack / Retention", |
||||
"uid": "RetCujSHzC8gd9i5fck9a3v9n2EvTzA", |
||||
"version": 0 |
||||
} |
@ -0,0 +1,33 @@ |
||||
{ |
||||
"groups": [ |
||||
{ |
||||
"name": "loki_rules", |
||||
"rules": [ |
||||
{ |
||||
"expr": "sum(rate(loki_request_duration_seconds_bucket[1m])) by (le, job, route)", |
||||
"record": "job_route:loki_request_duration_seconds_bucket:sum_rate" |
||||
}, |
||||
{ |
||||
"expr": "sum(rate(loki_request_duration_seconds_sum[1m])) by (job, route)", |
||||
"record": "job_route:loki_request_duration_seconds_sum:sum_rate" |
||||
}, |
||||
{ |
||||
"expr": "sum(rate(loki_request_duration_seconds_count[1m])) by (job, route)", |
||||
"record": "job_route:loki_request_duration_seconds_count:sum_rate" |
||||
}, |
||||
{ |
||||
"expr": "sum(rate(loki_request_duration_seconds_bucket[1m])) by (le, namespace, job, route)", |
||||
"record": "namespace_job_route:loki_request_duration_seconds_bucket:sum_rate" |
||||
}, |
||||
{ |
||||
"expr": "sum(rate(loki_request_duration_seconds_sum[1m])) by (namespace, job, route)", |
||||
"record": "namespace_job_route:loki_request_duration_seconds_sum:sum_rate" |
||||
}, |
||||
{ |
||||
"expr": "sum(rate(loki_request_duration_seconds_count[1m])) by (namespace, job, route)", |
||||
"record": "namespace_job_route:loki_request_duration_seconds_count:sum_rate" |
||||
} |
||||
] |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,862 @@ |
||||
{ |
||||
"annotations": { |
||||
"list": [ ] |
||||
}, |
||||
"editable": true, |
||||
"gnetId": null, |
||||
"graphTooltip": 0, |
||||
"hideControls": false, |
||||
"links": [ |
||||
{ |
||||
"asDropdown": true, |
||||
"icon": "external link", |
||||
"includeVars": true, |
||||
"keepTime": true, |
||||
"tags": [ |
||||
"loki" |
||||
], |
||||
"targetBlank": false, |
||||
"title": "Loki Dashboards", |
||||
"type": "dashboards" |
||||
} |
||||
], |
||||
"refresh": "10s", |
||||
"rows": [ |
||||
{ |
||||
"collapse": false, |
||||
"height": "250px", |
||||
"panels": [ |
||||
{ |
||||
"aliasColors": { |
||||
"1xx": "#EAB839", |
||||
"2xx": "#7EB26D", |
||||
"3xx": "#6ED0E0", |
||||
"4xx": "#EF843C", |
||||
"5xx": "#E24D42", |
||||
"error": "#E24D42", |
||||
"success": "#7EB26D" |
||||
}, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 10, |
||||
"id": 1, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 0, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 6, |
||||
"stack": true, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "sum by (status) (\n label_replace(label_replace(rate(loki_request_duration_seconds_count{namespace=\"$namespace\",job=~\".+-distributor-http\",route=\"loki_api_v1_push\", route=~\"api_prom_push|loki_api_v1_push|/httpgrpc.HTTP/Handle\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-z]+)\"))\n", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "{{status}}", |
||||
"refId": "A", |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "QPS", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 1, |
||||
"id": 2, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 6, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "histogram_quantile(0.99, sum by (le) (namespace_job_route:loki_request_duration_seconds_bucket:sum_rate{namespace=\"$namespace\", job=~\".+-distributor-http\", route=\"loki_api_v1_push\"})) * 1e3", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "99th Percentile", |
||||
"refId": "A", |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "histogram_quantile(0.50, sum by (le) (namespace_job_route:loki_request_duration_seconds_bucket:sum_rate{namespace=\"$namespace\", job=~\".+-distributor-http\", route=\"loki_api_v1_push\"})) * 1e3", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "50th Percentile", |
||||
"refId": "B", |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "1e3 * sum(namespace_job_route:loki_request_duration_seconds_sum:sum_rate{namespace=\"$namespace\", job=~\".+-distributor-http\", route=\"loki_api_v1_push\"}) / sum(namespace_job_route:loki_request_duration_seconds_count:sum_rate{namespace=\"$namespace\", job=~\".+-distributor-http\", route=\"loki_api_v1_push\"})", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "Average", |
||||
"refId": "C", |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "Latency", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "ms", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"repeat": null, |
||||
"repeatIteration": null, |
||||
"repeatRowId": null, |
||||
"showTitle": true, |
||||
"title": "Distributor", |
||||
"titleSize": "h6" |
||||
}, |
||||
{ |
||||
"collapse": false, |
||||
"height": "250px", |
||||
"panels": [ |
||||
{ |
||||
"aliasColors": { |
||||
"1xx": "#EAB839", |
||||
"2xx": "#7EB26D", |
||||
"3xx": "#6ED0E0", |
||||
"4xx": "#EF843C", |
||||
"5xx": "#E24D42", |
||||
"error": "#E24D42", |
||||
"success": "#7EB26D" |
||||
}, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 10, |
||||
"id": 5, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 0, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 6, |
||||
"stack": true, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "sum by (status) (\n label_replace(label_replace(rate(loki_request_duration_seconds_count{namespace=\"$namespace\",job=~\".+-ingester-http\", route=\"/logproto.Pusher/Push\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-z]+)\"))\n", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "{{status}}", |
||||
"refId": "A", |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "QPS", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 1, |
||||
"id": 6, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 6, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "histogram_quantile(0.99, sum by (le) (namespace_job_route:loki_request_duration_seconds_bucket:sum_rate{namespace=\"$namespace\", job=~\".+-ingester-http\", route=\"/logproto.Pusher/Push\"})) * 1e3", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "99th Percentile", |
||||
"refId": "A", |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "histogram_quantile(0.50, sum by (le) (namespace_job_route:loki_request_duration_seconds_bucket:sum_rate{namespace=\"$namespace\", job=~\".+-ingester-http\", route=\"/logproto.Pusher/Push\"})) * 1e3", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "50th Percentile", |
||||
"refId": "B", |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "1e3 * sum(namespace_job_route:loki_request_duration_seconds_sum:sum_rate{namespace=\"$namespace\", job=~\".+-ingester-http\", route=\"/logproto.Pusher/Push\"}) / sum(namespace_job_route:loki_request_duration_seconds_count:sum_rate{namespace=\"$namespace\", job=~\".+-ingester-http\", route=\"/logproto.Pusher/Push\"})", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "Average", |
||||
"refId": "C", |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "Latency", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "ms", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"repeat": null, |
||||
"repeatIteration": null, |
||||
"repeatRowId": null, |
||||
"showTitle": true, |
||||
"title": "Ingester", |
||||
"titleSize": "h6" |
||||
}, |
||||
{ |
||||
"collapse": false, |
||||
"height": "250px", |
||||
"panels": [ |
||||
{ |
||||
"aliasColors": { |
||||
"1xx": "#EAB839", |
||||
"2xx": "#7EB26D", |
||||
"3xx": "#6ED0E0", |
||||
"4xx": "#EF843C", |
||||
"5xx": "#E24D42", |
||||
"error": "#E24D42", |
||||
"success": "#7EB26D" |
||||
}, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 10, |
||||
"id": 7, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 0, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 6, |
||||
"stack": true, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "sum by (status) (\n label_replace(label_replace(rate(loki_index_request_duration_seconds_count{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"index_chunk\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-z]+)\"))\n", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "{{status}}", |
||||
"refId": "A", |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "QPS", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 1, |
||||
"id": 8, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 6, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "histogram_quantile(0.99, sum(rate(loki_index_request_duration_seconds_bucket{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"index_chunk\"}[$__rate_interval])) by (le)) * 1e3", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "99th Percentile", |
||||
"refId": "A", |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "histogram_quantile(0.50, sum(rate(loki_index_request_duration_seconds_bucket{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"index_chunk\"}[$__rate_interval])) by (le)) * 1e3", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "50th Percentile", |
||||
"refId": "B", |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "sum(rate(loki_index_request_duration_seconds_sum{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"index_chunk\"}[$__rate_interval])) * 1e3 / sum(rate(loki_index_request_duration_seconds_count{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"index_chunk\"}[$__rate_interval]))", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "Average", |
||||
"refId": "C", |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "Latency", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "ms", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"repeat": null, |
||||
"repeatIteration": null, |
||||
"repeatRowId": null, |
||||
"showTitle": true, |
||||
"title": "Index", |
||||
"titleSize": "h6" |
||||
}, |
||||
{ |
||||
"collapse": false, |
||||
"height": "250px", |
||||
"panels": [ |
||||
{ |
||||
"aliasColors": { |
||||
"1xx": "#EAB839", |
||||
"2xx": "#7EB26D", |
||||
"3xx": "#6ED0E0", |
||||
"4xx": "#EF843C", |
||||
"5xx": "#E24D42", |
||||
"error": "#E24D42", |
||||
"success": "#7EB26D" |
||||
}, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 10, |
||||
"id": 9, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 0, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 6, |
||||
"stack": true, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "sum by (status) (\n label_replace(label_replace(rate(loki_boltdb_shipper_request_duration_seconds_count{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"WRITE\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-z]+)\"))\n", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "{{status}}", |
||||
"refId": "A", |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "QPS", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"aliasColors": { }, |
||||
"bars": false, |
||||
"dashLength": 10, |
||||
"dashes": false, |
||||
"datasource": "$datasource", |
||||
"fill": 1, |
||||
"id": 10, |
||||
"legend": { |
||||
"avg": false, |
||||
"current": false, |
||||
"max": false, |
||||
"min": false, |
||||
"show": true, |
||||
"total": false, |
||||
"values": false |
||||
}, |
||||
"lines": true, |
||||
"linewidth": 1, |
||||
"links": [ ], |
||||
"nullPointMode": "null as zero", |
||||
"percentage": false, |
||||
"pointradius": 5, |
||||
"points": false, |
||||
"renderer": "flot", |
||||
"seriesOverrides": [ ], |
||||
"spaceLength": 10, |
||||
"span": 6, |
||||
"stack": false, |
||||
"steppedLine": false, |
||||
"targets": [ |
||||
{ |
||||
"expr": "histogram_quantile(0.99, sum(rate(loki_boltdb_shipper_request_duration_seconds_bucket{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"WRITE\"}[$__rate_interval])) by (le)) * 1e3", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "99th Percentile", |
||||
"refId": "A", |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "histogram_quantile(0.50, sum(rate(loki_boltdb_shipper_request_duration_seconds_bucket{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"WRITE\"}[$__rate_interval])) by (le)) * 1e3", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "50th Percentile", |
||||
"refId": "B", |
||||
"step": 10 |
||||
}, |
||||
{ |
||||
"expr": "sum(rate(loki_boltdb_shipper_request_duration_seconds_sum{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"WRITE\"}[$__rate_interval])) * 1e3 / sum(rate(loki_boltdb_shipper_request_duration_seconds_count{namespace=\"$namespace\",job=~\".+-ingester-http\", operation=\"WRITE\"}[$__rate_interval]))", |
||||
"format": "time_series", |
||||
"intervalFactor": 2, |
||||
"legendFormat": "Average", |
||||
"refId": "C", |
||||
"step": 10 |
||||
} |
||||
], |
||||
"thresholds": [ ], |
||||
"timeFrom": null, |
||||
"timeShift": null, |
||||
"title": "Latency", |
||||
"tooltip": { |
||||
"shared": true, |
||||
"sort": 2, |
||||
"value_type": "individual" |
||||
}, |
||||
"type": "graph", |
||||
"xaxis": { |
||||
"buckets": null, |
||||
"mode": "time", |
||||
"name": null, |
||||
"show": true, |
||||
"values": [ ] |
||||
}, |
||||
"yaxes": [ |
||||
{ |
||||
"format": "ms", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": 0, |
||||
"show": true |
||||
}, |
||||
{ |
||||
"format": "short", |
||||
"label": null, |
||||
"logBase": 1, |
||||
"max": null, |
||||
"min": null, |
||||
"show": false |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"repeat": null, |
||||
"repeatIteration": null, |
||||
"repeatRowId": null, |
||||
"showTitle": true, |
||||
"title": "BoltDB Shipper", |
||||
"titleSize": "h6" |
||||
} |
||||
], |
||||
"schemaVersion": 14, |
||||
"style": "dark", |
||||
"tags": [ |
||||
"loki", |
||||
"logging", |
||||
"loki-mixin" |
||||
], |
||||
"templating": { |
||||
"list": [ |
||||
{ |
||||
"current": { |
||||
"selected": true, |
||||
"text": "default", |
||||
"value": "default" |
||||
}, |
||||
"hide": 0, |
||||
"label": "Data Source", |
||||
"name": "datasource", |
||||
"options": [ ], |
||||
"query": "prometheus", |
||||
"refresh": 1, |
||||
"regex": "", |
||||
"type": "datasource" |
||||
}, |
||||
{ |
||||
"allValue": null, |
||||
"current": { |
||||
"selected": false, |
||||
"text": "openshift-logging", |
||||
"value": "openshift-logging" |
||||
}, |
||||
"datasource": "${datasource}", |
||||
"definition": "label_values(loki_build_info, namespace)", |
||||
"hide": 0, |
||||
"includeAll": false, |
||||
"label": "namespace", |
||||
"multi": false, |
||||
"name": "namespace", |
||||
"options": [ ], |
||||
"query": "label_values(loki_build_info, namespace)", |
||||
"refresh": 1, |
||||
"regex": "", |
||||
"sort": 2, |
||||
"tagValuesQuery": "", |
||||
"tags": [ ], |
||||
"tagsQuery": "", |
||||
"type": "query", |
||||
"useTags": false |
||||
} |
||||
] |
||||
}, |
||||
"time": { |
||||
"from": "now-1h", |
||||
"to": "now" |
||||
}, |
||||
"timepicker": { |
||||
"refresh_intervals": [ |
||||
"5s", |
||||
"10s", |
||||
"30s", |
||||
"1m", |
||||
"5m", |
||||
"15m", |
||||
"30m", |
||||
"1h", |
||||
"2h", |
||||
"1d" |
||||
], |
||||
"time_options": [ |
||||
"5m", |
||||
"15m", |
||||
"1h", |
||||
"6h", |
||||
"12h", |
||||
"24h", |
||||
"2d", |
||||
"7d", |
||||
"30d" |
||||
] |
||||
}, |
||||
"timezone": "utc", |
||||
"title": "OpenShift Logging / LokiStack / Writes", |
||||
"uid": "F6nRYKuXmFVpVSFQmXr7cgXy5j7UNr", |
||||
"version": 0 |
||||
} |
@ -0,0 +1,16 @@ |
||||
package operator |
||||
|
||||
import "os" |
||||
|
||||
const inClusterNamespaceFile = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" |
||||
|
||||
// GetNamespace returns the namespace the operator is running in from
|
||||
// the `/var/run/secrets/kubernetes.io/serviceaccount/namespace` file.
|
||||
func GetNamespace() (string, error) { |
||||
b, err := os.ReadFile(inClusterNamespaceFile) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
return string(b), nil |
||||
} |
@ -0,0 +1,219 @@ |
||||
local utils = (import 'github.com/grafana/jsonnet-libs/mixin-utils/utils.libsonnet'); |
||||
|
||||
{ |
||||
loki: { |
||||
local withDatasource = function(ds) ds + ( |
||||
if ds.name == 'datasource' then { |
||||
query: 'prometheus', |
||||
current: { |
||||
selected: true, |
||||
text: 'default', |
||||
value: 'default', |
||||
}, |
||||
} else {} |
||||
), |
||||
|
||||
local withNamespace = function(ns) ns + ( |
||||
if ns.label == 'namespace' then { |
||||
datasource: '${datasource}', |
||||
current: { |
||||
selected: false, |
||||
text: 'openshift-logging', |
||||
value: 'openshift-logging', |
||||
}, |
||||
definition: 'label_values(loki_build_info, namespace)', |
||||
query: 'label_values(loki_build_info, namespace)', |
||||
} else {} |
||||
), |
||||
|
||||
local defaultLokiTags = function(t) |
||||
std.uniq(t + ['logging', 'loki-mixin']), |
||||
|
||||
local replaceMatchers = function(replacements) |
||||
function(p) p { |
||||
targets: [ |
||||
t { |
||||
expr: std.foldl(function(x, rp) std.strReplace(x, rp.from, rp.to), replacements, t.expr), |
||||
} |
||||
for t in p.targets |
||||
if std.objectHas(p, 'targets') |
||||
], |
||||
}, |
||||
|
||||
// dropPanels removes unnecessary panels from the loki dashboards |
||||
// that are of obsolete usage on our AWS-based deployment environment. |
||||
local dropPanels = function(panels, dropList, fn) |
||||
[ |
||||
p |
||||
for p in panels |
||||
if !std.member(dropList, p.title) && fn(p) |
||||
], |
||||
|
||||
// mapPanels applies recursively a set of functions over all panels. |
||||
// Note: A Grafana dashboard panel can include other panels. |
||||
// Example: Replace job label in expression and add axis units for all panels. |
||||
local mapPanels = function(funcs, panels) |
||||
[ |
||||
// Transform the current panel by applying all transformer funcs. |
||||
// Keep the last version after foldl ends. |
||||
std.foldl(function(agg, fn) fn(agg), funcs, p) + ( |
||||
// Recursively apply all transformer functions to any |
||||
// children panels. |
||||
if std.objectHas(p, 'panels') then { |
||||
panels: mapPanels(funcs, p.panels), |
||||
} else {} |
||||
) |
||||
for p in panels |
||||
], |
||||
|
||||
// mapTemplateParameters applies a static list of transformer functions to |
||||
// all dashboard template parameters. The static list includes: |
||||
// - cluster-prometheus as datasource based on environment. |
||||
local mapTemplateParameters = function(ls) |
||||
[ |
||||
std.foldl(function(x, fn) fn(x), [withDatasource, withNamespace], item) |
||||
for item in ls |
||||
if item.name != 'cluster' |
||||
], |
||||
|
||||
local dropRules = function(rules, dropList) |
||||
[ |
||||
r |
||||
for r in rules |
||||
if !std.member(dropList, r.record) |
||||
], |
||||
|
||||
prometheusRules+: { |
||||
local dropList = [ |
||||
'cluster_job:loki_request_duration_seconds:99quantile', |
||||
'cluster_job:loki_request_duration_seconds:50quantile', |
||||
'cluster_job:loki_request_duration_seconds:avg', |
||||
'cluster_job:loki_request_duration_seconds_bucket:sum_rate', |
||||
'cluster_job:loki_request_duration_seconds_sum:sum_rate', |
||||
'cluster_job:loki_request_duration_seconds_count:sum_rate', |
||||
'cluster_job_route:loki_request_duration_seconds:99quantile', |
||||
'cluster_job_route:loki_request_duration_seconds:50quantile', |
||||
'cluster_job_route:loki_request_duration_seconds:avg', |
||||
'cluster_namespace_job_route:loki_request_duration_seconds:99quantile', |
||||
'cluster_namespace_job_route:loki_request_duration_seconds:50quantile', |
||||
'cluster_namespace_job_route:loki_request_duration_seconds:avg', |
||||
], |
||||
groups: [ |
||||
g { |
||||
rules: [ |
||||
r { |
||||
expr: std.strReplace(r.expr, 'cluster, ', ''), |
||||
record: std.strReplace(r.record, 'cluster_', ''), |
||||
} |
||||
for r in dropRules(g.rules, dropList) |
||||
], |
||||
} |
||||
for g in super.groups |
||||
], |
||||
}, |
||||
|
||||
local dropHistograms = function(p) |
||||
local elems = std.filter(function(p) p.type == 'heatmap', p.panels); |
||||
std.length(elems) == 0, |
||||
|
||||
grafanaDashboards+: { |
||||
'loki-retention.json'+: { |
||||
local dropList = ['Logs', 'Per Table Marker', 'Sweeper', ''], |
||||
local replacements = [ |
||||
{ from: 'cluster=~"$cluster",', to: '' }, |
||||
{ from: 'container="compactor"', to: 'container=~".+-compactor"' }, |
||||
{ from: 'job=~"($namespace)/compactor"', to: 'namespace="$namespace", job=~".+-compactor-http"' }, |
||||
], |
||||
uid: 'RetCujSHzC8gd9i5fck9a3v9n2EvTzA', |
||||
title: 'OpenShift Logging / LokiStack / Retention', |
||||
tags: defaultLokiTags(super.tags), |
||||
rows: [ |
||||
r { |
||||
panels: mapPanels([replaceMatchers(replacements)], r.panels), |
||||
} |
||||
for r in dropPanels(super.rows, dropList, function(p) true) |
||||
], |
||||
templating+: { |
||||
list: mapTemplateParameters(super.list), |
||||
}, |
||||
}, |
||||
'loki-chunks.json'+: { |
||||
local dropList = ['Utilization'], |
||||
uid: 'GtCujSHzC8gd9i5fck9a3v9n2EvTzA', |
||||
title: 'OpenShift Logging / LokiStack / Chunks', |
||||
tags: defaultLokiTags(super.tags), |
||||
showMultiCluster:: false, |
||||
namespaceQuery:: 'label_values(loki_build_info, namespace)', |
||||
namespaceType:: 'query', |
||||
labelsSelector:: 'namespace="$namespace", job=~".+-ingester-http"', |
||||
rows: [ |
||||
r |
||||
for r in dropPanels(super.rows, dropList, dropHistograms) |
||||
], |
||||
templating+: { |
||||
list: mapTemplateParameters(super.list), |
||||
}, |
||||
}, |
||||
'loki-reads.json'+: { |
||||
local dropList = ['BigTable', 'Ingester - Zone Aware'], |
||||
|
||||
uid: '62q5jjYwhVSaz4Mcrm8tV3My3gcKED', |
||||
title: 'OpenShift Logging / LokiStack / Reads', |
||||
tags: defaultLokiTags(super.tags), |
||||
showMultiCluster:: false, |
||||
namespaceQuery:: 'label_values(loki_build_info, namespace)', |
||||
namespaceType:: 'query', |
||||
matchers:: { |
||||
cortexgateway:: [], |
||||
queryFrontend:: [ |
||||
utils.selector.eq('namespace', '$namespace'), |
||||
utils.selector.re('job', '.+-query-frontend-http'), |
||||
], |
||||
querier:: [ |
||||
utils.selector.eq('namespace', '$namespace'), |
||||
utils.selector.re('job', '.+-querier-http'), |
||||
], |
||||
ingester:: [ |
||||
utils.selector.eq('namespace', '$namespace'), |
||||
utils.selector.re('job', '.+-ingester-http'), |
||||
], |
||||
ingesterZoneAware:: [], |
||||
querierOrIndexGateway:: [ |
||||
utils.selector.eq('namespace', '$namespace'), |
||||
utils.selector.re('job', '.+-index-gateway-http'), |
||||
], |
||||
}, |
||||
rows: dropPanels(super.rows, dropList, function(p) true), |
||||
templating+: { |
||||
list: mapTemplateParameters(super.list), |
||||
}, |
||||
}, |
||||
'loki-writes.json'+: { |
||||
local dropList = ['Ingester - Zone Aware'], |
||||
uid: 'F6nRYKuXmFVpVSFQmXr7cgXy5j7UNr', |
||||
title: 'OpenShift Logging / LokiStack / Writes', |
||||
tags: defaultLokiTags(super.tags), |
||||
showMultiCluster:: false, |
||||
namespaceQuery:: 'label_values(loki_build_info, namespace)', |
||||
namespaceType:: 'query', |
||||
matchers:: { |
||||
cortexgateway:: [], |
||||
distributor:: [ |
||||
utils.selector.eq('namespace', '$namespace'), |
||||
utils.selector.re('job', '.+-distributor-http'), |
||||
utils.selector.eq('route', 'loki_api_v1_push'), |
||||
], |
||||
ingester:: [ |
||||
utils.selector.eq('namespace', '$namespace'), |
||||
utils.selector.re('job', '.+-ingester-http'), |
||||
], |
||||
ingester_zone:: [], |
||||
}, |
||||
rows: dropPanels(super.rows, dropList, function(p) true), |
||||
templating+: { |
||||
list: mapTemplateParameters(super.list), |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
} |
@ -0,0 +1,10 @@ |
||||
local cfg = (import 'config.libsonnet'); |
||||
local loki = (import 'github.com/grafana/loki/production/loki-mixin/mixin.libsonnet') + cfg.loki; |
||||
|
||||
{ |
||||
'grafana-dashboard-lokistack-chunks.json': loki.grafanaDashboards['loki-chunks.json'], |
||||
'grafana-dashboard-lokistack-reads.json': loki.grafanaDashboards['loki-reads.json'], |
||||
'grafana-dashboard-lokistack-writes.json': loki.grafanaDashboards['loki-writes.json'], |
||||
'grafana-dashboard-lokistack-retention.json': loki.grafanaDashboards['loki-retention.json'], |
||||
'grafana-dashboard-lokistack-rules.json': loki.prometheusRules, |
||||
} |
@ -0,0 +1,15 @@ |
||||
{ |
||||
"version": 1, |
||||
"dependencies": [ |
||||
{ |
||||
"source": { |
||||
"git": { |
||||
"remote": "https://github.com/grafana/loki.git", |
||||
"subdir": "production/loki-mixin" |
||||
} |
||||
}, |
||||
"version": "v2.8.2" |
||||
} |
||||
], |
||||
"legacyImports": true |
||||
} |
@ -0,0 +1,66 @@ |
||||
{ |
||||
"version": 1, |
||||
"dependencies": [ |
||||
{ |
||||
"source": { |
||||
"git": { |
||||
"remote": "https://github.com/grafana/grafonnet-lib.git", |
||||
"subdir": "grafonnet" |
||||
} |
||||
}, |
||||
"version": "f0b70307b8e5f12236b277883d998af129a8211f", |
||||
"sum": "342u++/7rViR/zj2jeJOjshzglkZ1SY+hFNuyCBFMdc=" |
||||
}, |
||||
{ |
||||
"source": { |
||||
"git": { |
||||
"remote": "https://github.com/grafana/jsonnet-libs.git", |
||||
"subdir": "grafana-builder" |
||||
} |
||||
}, |
||||
"version": "e8e0f6f536f3397a22a49bd9014a7e0a1dfa151d", |
||||
"sum": "tDR6yT2GVfw0wTU12iZH+m01HrbIr6g/xN+/8nzNkU0=" |
||||
}, |
||||
{ |
||||
"source": { |
||||
"git": { |
||||
"remote": "https://github.com/grafana/jsonnet-libs.git", |
||||
"subdir": "mixin-utils" |
||||
} |
||||
}, |
||||
"version": "e8e0f6f536f3397a22a49bd9014a7e0a1dfa151d", |
||||
"sum": "N1Uz6AJpnQXv4w8F6lxDqMwoT7azPVrpuhJ4N7Oqzcw=" |
||||
}, |
||||
{ |
||||
"source": { |
||||
"git": { |
||||
"remote": "https://github.com/grafana/loki.git", |
||||
"subdir": "production/loki-mixin" |
||||
} |
||||
}, |
||||
"version": "b7ce95402ac5e2712432e8bfc638b262793b8811", |
||||
"sum": "iYoW3v95aLI2zY2zoQvS0TrIe6kVzdIYyCaGUJ0oC+s=" |
||||
}, |
||||
{ |
||||
"source": { |
||||
"git": { |
||||
"remote": "https://github.com/grafana/mimir.git", |
||||
"subdir": "operations/mimir-mixin" |
||||
} |
||||
}, |
||||
"version": "154abe81c5c6b3f263e2b39084f186dd564860af", |
||||
"sum": "xnakaDny0zXG7mhuyUH90swndHinwpt5/RRVFotDqFY=" |
||||
}, |
||||
{ |
||||
"source": { |
||||
"git": { |
||||
"remote": "https://github.com/prometheus-operator/kube-prometheus.git", |
||||
"subdir": "jsonnet/kube-prometheus/lib" |
||||
} |
||||
}, |
||||
"version": "b176baa776a4d6002fe162846dacb424965df1bc", |
||||
"sum": "QKRgrgEZ3k9nLmLCrDBaeIGVqQZf+AvZTcnhdLk3TrA=" |
||||
} |
||||
], |
||||
"legacyImports": false |
||||
} |
@ -0,0 +1 @@ |
||||
(import 'dashboards.jsonnet') |
Loading…
Reference in new issue