diff --git a/chart/templates/base.yaml b/chart/templates/base.yaml
index 9cc964f1eb478..dab426a67b8c1 100644
--- a/chart/templates/base.yaml
+++ b/chart/templates/base.yaml
@@ -29,7 +29,7 @@ metadata:
{{- end}}
rules:
- apiGroups: ["extensions", "apps"]
- resources: ["daemonsets", "deployments", "replicasets"]
+ resources: ["daemonsets", "deployments", "replicasets", "statefulsets"]
verbs: ["list", "get", "watch"]
- apiGroups: [""]
resources: ["pods", "endpoints", "services", "replicationcontrollers"{{if not .Values.SingleNamespace}}, "namespaces"{{end}}]
diff --git a/cli/cmd/stat.go b/cli/cmd/stat.go
index cc5cd169433dd..091164dd4efd3 100644
--- a/cli/cmd/stat.go
+++ b/cli/cmd/stat.go
@@ -60,6 +60,7 @@ func newCmdStat() *cobra.Command {
* deploy
* deploy/my-deploy
* ds/my-daemonset
+ * statefulset/my-statefulset
* rc/my-replication-controller
* ns/my-ns
* authority
@@ -71,6 +72,7 @@ func newCmdStat() *cobra.Command {
Valid resource types include:
* daemonsets
+ * statefulsets
* deployments
* namespaces
* pods
diff --git a/cli/cmd/tap.go b/cli/cmd/tap.go
index 42d094a659d28..fec50f9e23446 100644
--- a/cli/cmd/tap.go
+++ b/cli/cmd/tap.go
@@ -59,10 +59,13 @@ func newCmdTap() *cobra.Command {
* deploy/my-deploy
* deploy my-deploy
* ds/my-daemonset
+ * statefulset
+ * statefulset/my-statefulset
* ns/my-ns
Valid resource types include:
* daemonsets
+ * statefulsets
* deployments
* namespaces
* pods
diff --git a/cli/cmd/testdata/install_default.golden b/cli/cmd/testdata/install_default.golden
index 4844a1f74ff42..6ab33d2821ee0 100644
--- a/cli/cmd/testdata/install_default.golden
+++ b/cli/cmd/testdata/install_default.golden
@@ -20,7 +20,7 @@ metadata:
name: linkerd-linkerd-controller
rules:
- apiGroups: ["extensions", "apps"]
- resources: ["daemonsets", "deployments", "replicasets"]
+ resources: ["daemonsets", "deployments", "replicasets", "statefulsets"]
verbs: ["list", "get", "watch"]
- apiGroups: [""]
resources: ["pods", "endpoints", "services", "replicationcontrollers", "namespaces"]
diff --git a/cli/cmd/testdata/install_ha_output.golden b/cli/cmd/testdata/install_ha_output.golden
index d1dc46f95dc49..5a0c6cc94d837 100644
--- a/cli/cmd/testdata/install_ha_output.golden
+++ b/cli/cmd/testdata/install_ha_output.golden
@@ -20,7 +20,7 @@ metadata:
name: linkerd-linkerd-controller
rules:
- apiGroups: ["extensions", "apps"]
- resources: ["daemonsets", "deployments", "replicasets"]
+ resources: ["daemonsets", "deployments", "replicasets", "statefulsets"]
verbs: ["list", "get", "watch"]
- apiGroups: [""]
resources: ["pods", "endpoints", "services", "replicationcontrollers", "namespaces"]
diff --git a/cli/cmd/testdata/install_ha_with_overrides_output.golden b/cli/cmd/testdata/install_ha_with_overrides_output.golden
index 802def4547f25..70b5121f0fdca 100644
--- a/cli/cmd/testdata/install_ha_with_overrides_output.golden
+++ b/cli/cmd/testdata/install_ha_with_overrides_output.golden
@@ -20,7 +20,7 @@ metadata:
name: linkerd-linkerd-controller
rules:
- apiGroups: ["extensions", "apps"]
- resources: ["daemonsets", "deployments", "replicasets"]
+ resources: ["daemonsets", "deployments", "replicasets", "statefulsets"]
verbs: ["list", "get", "watch"]
- apiGroups: [""]
resources: ["pods", "endpoints", "services", "replicationcontrollers", "namespaces"]
diff --git a/cli/cmd/testdata/install_no_init_container.golden b/cli/cmd/testdata/install_no_init_container.golden
index 87c581628726f..fbf854d8b697c 100644
--- a/cli/cmd/testdata/install_no_init_container.golden
+++ b/cli/cmd/testdata/install_no_init_container.golden
@@ -20,7 +20,7 @@ metadata:
name: linkerd-linkerd-controller
rules:
- apiGroups: ["extensions", "apps"]
- resources: ["daemonsets", "deployments", "replicasets"]
+ resources: ["daemonsets", "deployments", "replicasets", "statefulsets"]
verbs: ["list", "get", "watch"]
- apiGroups: [""]
resources: ["pods", "endpoints", "services", "replicationcontrollers", "namespaces"]
diff --git a/cli/cmd/testdata/install_no_init_container_auto_inject.golden b/cli/cmd/testdata/install_no_init_container_auto_inject.golden
index c2a22edce8673..4bc911543d681 100644
--- a/cli/cmd/testdata/install_no_init_container_auto_inject.golden
+++ b/cli/cmd/testdata/install_no_init_container_auto_inject.golden
@@ -22,7 +22,7 @@ metadata:
name: linkerd-linkerd-controller
rules:
- apiGroups: ["extensions", "apps"]
- resources: ["daemonsets", "deployments", "replicasets"]
+ resources: ["daemonsets", "deployments", "replicasets", "statefulsets"]
verbs: ["list", "get", "watch"]
- apiGroups: [""]
resources: ["pods", "endpoints", "services", "replicationcontrollers", "namespaces"]
diff --git a/cli/cmd/testdata/install_output.golden b/cli/cmd/testdata/install_output.golden
index e5fa24875ce4e..c82774625fe22 100644
--- a/cli/cmd/testdata/install_output.golden
+++ b/cli/cmd/testdata/install_output.golden
@@ -22,7 +22,7 @@ metadata:
name: linkerd-Namespace-controller
rules:
- apiGroups: ["extensions", "apps"]
- resources: ["daemonsets", "deployments", "replicasets"]
+ resources: ["daemonsets", "deployments", "replicasets", "statefulsets"]
verbs: ["list", "get", "watch"]
- apiGroups: [""]
resources: ["pods", "endpoints", "services", "replicationcontrollers", "namespaces"]
diff --git a/cli/cmd/testdata/install_single_namespace_output.golden b/cli/cmd/testdata/install_single_namespace_output.golden
index 3dc39ae75eac8..27aa2333a5f95 100644
--- a/cli/cmd/testdata/install_single_namespace_output.golden
+++ b/cli/cmd/testdata/install_single_namespace_output.golden
@@ -15,7 +15,7 @@ metadata:
namespace: Namespace
rules:
- apiGroups: ["extensions", "apps"]
- resources: ["daemonsets", "deployments", "replicasets"]
+ resources: ["daemonsets", "deployments", "replicasets", "statefulsets"]
verbs: ["list", "get", "watch"]
- apiGroups: [""]
resources: ["pods", "endpoints", "services", "replicationcontrollers"]
diff --git a/cli/cmd/top.go b/cli/cmd/top.go
index 98e102ae15949..7eee88f5f9be5 100644
--- a/cli/cmd/top.go
+++ b/cli/cmd/top.go
@@ -285,10 +285,13 @@ func newCmdTop() *cobra.Command {
* deploy/my-deploy
* deploy my-deploy
* ds/my-daemonset
+ * statefulset
+ * statefulset/my-statefulset
* ns/my-ns
Valid resource types include:
* daemonsets
+ * statefulsets
* deployments
* namespaces
* pods
diff --git a/controller/api/public/stat_summary_test.go b/controller/api/public/stat_summary_test.go
index 2b3d4abb1a1e3..50a94a7d37ee8 100644
--- a/controller/api/public/stat_summary_test.go
+++ b/controller/api/public/stat_summary_test.go
@@ -108,7 +108,6 @@ func testStatSummary(t *testing.T, expectations []statSumExpected) {
if !proto.Equal(exp.expectedResponse.GetOk(), statOkRsp) {
t.Fatalf("Expected: %+v\n Got: %+v", &exp.expectedResponse, rsp)
}
-
}
}
@@ -286,6 +285,101 @@ status:
testStatSummary(t, expectations)
})
+ t.Run("Successfully performs a query based on resource type StatefulSet", func(t *testing.T) {
+ expectations := []statSumExpected{
+ statSumExpected{
+ expectedStatRPC: expectedStatRPC{
+ err: nil,
+ k8sConfigs: []string{`
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: redis
+ namespace: emojivoto
+ labels:
+ app: redis
+ linkerd.io/control-plane-ns: linkerd
+spec:
+ replicas: 3
+ serviceName: redis
+ selector:
+ matchLabels:
+ app: redis
+ template:
+ metadata:
+ labels:
+ app: redis
+ spec:
+ containers:
+ - image: redis
+ volumeMounts:
+ - name: data
+ mountPath: /var/lib/redis
+ volumeClaimTemplates:
+ - metadata:
+ name: data
+ spec:
+ accessModes: ["ReadWriteOnce"]
+ resources:
+ requests:
+ storage: 10Gi
+`, `
+apiVersion: v1
+kind: Pod
+metadata:
+ name: redis-0
+ namespace: emojivoto
+ labels:
+ app: redis
+ linkerd.io/control-plane-ns: linkerd
+status:
+ phase: Running
+`, `
+apiVersion: v1
+kind: Pod
+metadata:
+ name: redis-1
+ namespace: emojivoto
+ labels:
+ app: redis
+ linkerd.io/control-plane-ns: linkerd
+status:
+ phase: Running
+`, `
+apiVersion: v1
+kind: Pod
+metadata:
+ name: redis-2
+ namespace: emojivoto
+ labels:
+ app: redis
+ linkerd.io/control-plane-ns: linkerd
+status:
+ phase: Running
+`,
+ },
+ mockPromResponse: prometheusMetric("redis", "statefulset", "emojivoto", "success", false),
+ },
+ req: pb.StatSummaryRequest{
+ Selector: &pb.ResourceSelection{
+ Resource: &pb.Resource{
+ Namespace: "emojivoto",
+ Type: pkgK8s.StatefulSet,
+ },
+ },
+ TimeWindow: "1m",
+ },
+ expectedResponse: GenStatSummaryResponse("redis", pkgK8s.StatefulSet, []string{"emojivoto"}, &PodCounts{
+ MeshedPods: 3,
+ RunningPods: 3,
+ FailedPods: 0,
+ }, true),
+ },
+ }
+
+ testStatSummary(t, expectations)
+ })
+
t.Run("Queries prometheus for a specific resource if name is specified", func(t *testing.T) {
expectations := []statSumExpected{
statSumExpected{
@@ -713,6 +807,13 @@ status:
},
},
},
+ &pb.StatTable{
+ Table: &pb.StatTable_PodGroup_{
+ PodGroup: &pb.StatTable_PodGroup{
+ Rows: []*pb.StatTable_PodGroup_Row{},
+ },
+ },
+ },
&pb.StatTable{
Table: &pb.StatTable_PodGroup_{
PodGroup: &pb.StatTable_PodGroup{
diff --git a/controller/api/public/top_routes_test.go b/controller/api/public/top_routes_test.go
index 8aa5795fd1996..4bb833f56dae9 100644
--- a/controller/api/public/top_routes_test.go
+++ b/controller/api/public/top_routes_test.go
@@ -51,6 +51,36 @@ spec:
containers:
- image: buoyantio/booksapp:v0.0.2`
+var booksStatefulsetConfig = `kind: StatefulSet
+apiVersion: apps/v1
+metadata:
+ name: books
+ namespace: default
+spec:
+ selector:
+ matchLabels:
+ app: books
+ template:
+ serviceName: books
+ metadata:
+ labels:
+ app: books
+ spec:
+ containers:
+ - image: buoyantio/booksapp:v0.0.2
+ volumes:
+ - name: data
+ mountPath: /usr/src/app
+ volumeClaimTemplates:
+ - metadata:
+ name: data
+ spec:
+ accessModes: ["ReadWriteOnce"]
+ resources:
+ requests:
+ storage: 10Gi
+`
+
var booksServiceConfig = []string{
// service/books
`apiVersion: v1
@@ -93,6 +123,7 @@ spec:
var booksConfig = append(booksServiceConfig, booksDeployConfig)
var booksDSConfig = append(booksServiceConfig, booksDaemonsetConfig)
+var booksSSConfig = append(booksServiceConfig, booksStatefulsetConfig)
type topRoutesExpected struct {
expectedStatRPC
@@ -292,6 +323,39 @@ func TestTopRoutes(t *testing.T) {
testTopRoutes(t, expectations)
})
+ t.Run("Successfully performs a routes query for a statefulset", func(t *testing.T) {
+ routes := []string{"/a"}
+ counts := []uint64{123}
+ expectations := []topRoutesExpected{
+ topRoutesExpected{
+ expectedStatRPC: expectedStatRPC{
+ err: nil,
+ mockPromResponse: routesMetric([]string{"/a"}),
+ expectedPrometheusQueries: []string{
+ `histogram_quantile(0.5, sum(irate(route_response_latency_ms_bucket{direction="inbound", dst=~"(books.default.svc.cluster.local)(:\\d+)?", namespace="default", statefulset="books"}[1m])) by (le, dst, rt_route))`,
+ `histogram_quantile(0.95, sum(irate(route_response_latency_ms_bucket{direction="inbound", dst=~"(books.default.svc.cluster.local)(:\\d+)?", namespace="default", statefulset="books"}[1m])) by (le, dst, rt_route))`,
+ `histogram_quantile(0.99, sum(irate(route_response_latency_ms_bucket{direction="inbound", dst=~"(books.default.svc.cluster.local)(:\\d+)?", namespace="default", statefulset="books"}[1m])) by (le, dst, rt_route))`,
+ `sum(increase(route_response_total{direction="inbound", dst=~"(books.default.svc.cluster.local)(:\\d+)?", namespace="default", statefulset="books"}[1m])) by (rt_route, dst, classification)`,
+ },
+ k8sConfigs: booksSSConfig,
+ },
+ req: pb.TopRoutesRequest{
+ Selector: &pb.ResourceSelection{
+ Resource: &pb.Resource{
+ Namespace: "default",
+ Type: pkgK8s.StatefulSet,
+ Name: "books",
+ },
+ },
+ TimeWindow: "1m",
+ },
+ expectedResponse: GenTopRoutesResponse(routes, counts, false, "books"),
+ },
+ }
+
+ testTopRoutes(t, expectations)
+ })
+
t.Run("Successfully performs an outbound routes query", func(t *testing.T) {
routes := []string{"/a"}
counts := []uint64{123}
diff --git a/controller/api/util/api_utils.go b/controller/api/util/api_utils.go
index 99039f3b6e59f..def1db07f828a 100644
--- a/controller/api/util/api_utils.go
+++ b/controller/api/util/api_utils.go
@@ -29,6 +29,7 @@ var (
ValidTargets = []string{
k8s.Authority,
k8s.DaemonSet,
+ k8s.StatefulSet,
k8s.Deployment,
k8s.Namespace,
k8s.Pod,
@@ -39,6 +40,7 @@ var (
// destination resource on an outbound 'to' query
ValidTapDestinations = []string{
k8s.DaemonSet,
+ k8s.StatefulSet,
k8s.Deployment,
k8s.Job,
k8s.Namespace,
diff --git a/controller/cmd/public-api/main.go b/controller/cmd/public-api/main.go
index ea1611897c3d4..b99195104d505 100644
--- a/controller/cmd/public-api/main.go
+++ b/controller/cmd/public-api/main.go
@@ -55,7 +55,7 @@ func main() {
var spClient *spclient.Clientset
restrictToNamespace := ""
- resources := []k8s.APIResource{k8s.DS, k8s.Deploy, k8s.Pod, k8s.RC, k8s.RS, k8s.Svc}
+ resources := []k8s.APIResource{k8s.DS, k8s.Deploy, k8s.Pod, k8s.RC, k8s.RS, k8s.Svc, k8s.SS}
if *singleNamespace {
restrictToNamespace = *controllerNamespace
diff --git a/controller/cmd/tap/main.go b/controller/cmd/tap/main.go
index 4f0187682820f..31db0b6d52f47 100644
--- a/controller/cmd/tap/main.go
+++ b/controller/cmd/tap/main.go
@@ -38,6 +38,7 @@ func main() {
nil,
restrictToNamespace,
k8s.DS,
+ k8s.SS,
k8s.Deploy,
k8s.Pod,
k8s.RC,
diff --git a/controller/k8s/api.go b/controller/k8s/api.go
index 2b1f2608da7f5..2a12601583d02 100644
--- a/controller/k8s/api.go
+++ b/controller/k8s/api.go
@@ -46,6 +46,7 @@ const (
RS
SP
Svc
+ SS
)
// API provides shared informers for all Kubernetes objects
@@ -55,6 +56,7 @@ type API struct {
cm coreinformers.ConfigMapInformer
deploy appv1beta2informers.DeploymentInformer
ds appv1informers.DaemonSetInformer
+ ss appv1informers.StatefulSetInformer
endpoint coreinformers.EndpointsInformer
mwc arinformers.MutatingWebhookConfigurationInformer
pod coreinformers.PodInformer
@@ -110,6 +112,9 @@ func NewAPI(k8sClient kubernetes.Interface, spClient spclient.Interface, namespa
case DS:
api.ds = sharedInformers.Apps().V1().DaemonSets()
api.syncChecks = append(api.syncChecks, api.ds.Informer().HasSynced)
+ case SS:
+ api.ss = sharedInformers.Apps().V1().StatefulSets()
+ api.syncChecks = append(api.syncChecks, api.ss.Informer().HasSynced)
case Endpoint:
api.endpoint = sharedInformers.Core().V1().Endpoints()
api.syncChecks = append(api.syncChecks, api.endpoint.Informer().HasSynced)
@@ -168,6 +173,14 @@ func (api *API) DS() appv1informers.DaemonSetInformer {
return api.ds
}
+// SS provides access to a shared informer and lister for Statefulsets.
+func (api *API) SS() appv1informers.StatefulSetInformer {
+ if api.ss == nil {
+ panic("SS informer not configured")
+ }
+ return api.ss
+}
+
// RS provides access to a shared informer and lister for ReplicaSets.
func (api *API) RS() appv1beta2informers.ReplicaSetInformer {
if api.rs == nil {
@@ -242,6 +255,8 @@ func (api *API) GetObjects(namespace, restype, name string) ([]runtime.Object, e
return api.getNamespaces(name)
case k8s.DaemonSet:
return api.getDaemonsets(namespace, name)
+ case k8s.StatefulSet:
+ return api.getStatefulsets(namespace, name)
case k8s.Deployment:
return api.getDeployments(namespace, name)
case k8s.Pod:
@@ -294,6 +309,10 @@ func (api *API) GetPodsFor(obj runtime.Object, includeFailed bool) ([]*apiv1.Pod
namespace = typed.Namespace
selector = labels.Set(typed.Spec.Selector.MatchLabels).AsSelector()
+ case *appsv1.StatefulSet:
+ namespace = typed.Namespace
+ selector = labels.Set(typed.Spec.Selector.MatchLabels).AsSelector()
+
case *appsv1beta2.Deployment:
namespace = typed.Namespace
selector = labels.Set(typed.Spec.Selector.MatchLabels).AsSelector()
@@ -355,6 +374,9 @@ func GetNameAndNamespaceOf(obj runtime.Object) (string, string, error) {
case *appsv1.DaemonSet:
return typed.Name, typed.Namespace, nil
+ case *appsv1.StatefulSet:
+ return typed.Name, typed.Namespace, nil
+
case *appsv1beta2.Deployment:
return typed.Name, typed.Namespace, nil
@@ -536,6 +558,32 @@ func (api *API) getDaemonsets(namespace, name string) ([]runtime.Object, error)
return objects, nil
}
+func (api *API) getStatefulsets(namespace, name string) ([]runtime.Object, error) {
+ var err error
+ var statefulsets []*appsv1.StatefulSet
+
+ if namespace == "" {
+ statefulsets, err = api.SS().Lister().List(labels.Everything())
+ } else if name == "" {
+ statefulsets, err = api.SS().Lister().StatefulSets(namespace).List(labels.Everything())
+ } else {
+ var ss *appsv1.StatefulSet
+ ss, err = api.SS().Lister().StatefulSets(namespace).Get(name)
+ statefulsets = []*appsv1.StatefulSet{ss}
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ objects := []runtime.Object{}
+ for _, ss := range statefulsets {
+ objects = append(objects, ss)
+ }
+
+ return objects, nil
+}
+
func (api *API) getServices(namespace, name string) ([]runtime.Object, error) {
services, err := api.GetServices(namespace, name)
diff --git a/controller/k8s/api_test.go b/controller/k8s/api_test.go
index 34ea96af04efa..05ec2bb588ee8 100644
--- a/controller/k8s/api_test.go
+++ b/controller/k8s/api_test.go
@@ -163,6 +163,39 @@ apiVersion: apps/v1
kind: DaemonSet
metadata:
name: my-ds
+ namespace: not-my-ns`,
+ },
+ },
+ getObjectsExpected{
+ err: nil,
+ namespace: "",
+ resType: k8s.StatefulSet,
+ name: "",
+ k8sResResults: []string{`
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: my-deploy
+ namespace: my-ns`,
+ },
+ },
+ getObjectsExpected{
+ err: nil,
+ namespace: "my-ns",
+ resType: k8s.StatefulSet,
+ name: "my-ss",
+ k8sResResults: []string{`
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: my-ss
+ namespace: my-ns`,
+ },
+ k8sResMisc: []string{`
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: my-ss
namespace: not-my-ns`,
},
},
diff --git a/controller/k8s/test_helper.go b/controller/k8s/test_helper.go
index 68345693b0770..0cf0188c476b0 100644
--- a/controller/k8s/test_helper.go
+++ b/controller/k8s/test_helper.go
@@ -43,6 +43,7 @@ func NewFakeAPI(namespace string, configs ...string) (*API, error) {
CM,
Deploy,
DS,
+ SS,
Endpoint,
Pod,
RC,
diff --git a/grafana/dashboards/statefulset.json b/grafana/dashboards/statefulset.json
new file mode 100644
index 0000000000000..77be8507984e8
--- /dev/null
+++ b/grafana/dashboards/statefulset.json
@@ -0,0 +1,2241 @@
+{
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 1,
+ "id": null,
+ "iteration": 1531763681685,
+ "links": [],
+ "panels": [
+ {
+ "content": "
\n

\n
statefulset/$statefulset\n
",
+ "gridPos": {
+ "h": 2.4,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 20,
+ "links": [],
+ "mode": "html",
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#d44a3a",
+ "rgba(237, 129, 40, 0.89)",
+ "#299c46"
+ ],
+ "datasource": "prometheus",
+ "decimals": null,
+ "format": "percentunit",
+ "gauge": {
+ "maxValue": 1,
+ "minValue": 0,
+ "show": true,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 8,
+ "x": 0,
+ "y": 2.4
+ },
+ "id": 5,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": true,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s]))",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 1,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "0.9,.99",
+ "title": "SUCCESS RATE",
+ "transparent": true,
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "prometheus",
+ "decimals": null,
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 8,
+ "x": 8,
+ "y": 2.4
+ },
+ "id": 4,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": " RPS",
+ "postfixFontSize": "100%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": true,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s]))",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 1,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "REQUEST RATE",
+ "transparent": true,
+ "type": "singlestat",
+ "valueFontSize": "100%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "prometheus",
+ "decimals": null,
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 4,
+ "x": 16,
+ "y": 2.4
+ },
+ "id": 11,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "100%",
+ "prefix": "",
+ "prefixFontSize": "100%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "count(count(request_total{dst_namespace=\"$namespace\", statefulset!=\"\", dst_statefulset!=\"\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}) by (namespace, statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "INBOUND STATEFULSETS",
+ "transparent": true,
+ "type": "singlestat",
+ "valueFontSize": "100%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "prometheus",
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 4,
+ "x": 20,
+ "y": 2.4
+ },
+ "id": 15,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "100%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "count(count(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}) by (namespace, dst_statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "OUTBOUND STATEFULSETS",
+ "transparent": true,
+ "type": "singlestat",
+ "valueFontSize": "100%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "content": "\n INBOUND TRAFFIC\n
",
+ "gridPos": {
+ "h": 2.2,
+ "w": 24,
+ "x": 0,
+ "y": 6.4
+ },
+ "id": 17,
+ "links": [],
+ "mode": "html",
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 8.600000000000001
+ },
+ "id": 67,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (statefulset) / sum(irate(response_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (statefulset)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "statefulset/{{statefulset}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "SUCCESS RATE",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "decimals": null,
+ "format": "percentunit",
+ "label": "",
+ "logBase": 1,
+ "max": "1",
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 8.600000000000001
+ },
+ "id": 2,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\", tls=\"true\"}[30s])) by (statefulset)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "🔒statefulset/{{statefulset}}",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\", tls!=\"true\"}[30s])) by (statefulset)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "statefulset/{{statefulset}}",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "REQUEST RATE",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "decimals": null,
+ "format": "rps",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 8.600000000000001
+ },
+ "id": 68,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (le, statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "p50 statefulset/{{statefulset}}",
+ "refId": "A"
+ },
+ {
+ "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (le, statefulset))",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "p95 statefulset/{{statefulset}}",
+ "refId": "B"
+ },
+ {
+ "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (le, statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "p99 statefulset/{{statefulset}}",
+ "refId": "C"
+ }
+ ],
+ "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": [
+ {
+ "decimals": null,
+ "format": "ms",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 15.600000000000001
+ },
+ "id": 148,
+ "panels": [
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 16.6
+ },
+ "id": 167,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "tcp_close_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\",errno!=\"\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{peer}} {{errno}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "TCP CONNECTION FAILURES",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "decimals": null,
+ "format": "none",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 16.6
+ },
+ "id": 168,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "tcp_open_connections{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{peer}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "TCP CONNECTIONS OPEN",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "cards": {
+ "cardPadding": null,
+ "cardRound": null
+ },
+ "color": {
+ "cardColor": "#b4ff00",
+ "colorScale": "sqrt",
+ "colorScheme": "interpolateOranges",
+ "exponent": 0.5,
+ "mode": "spectrum"
+ },
+ "dataFormat": "timeseries",
+ "datasource": "prometheus",
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 16.6
+ },
+ "heatmap": {},
+ "highlightCards": true,
+ "id": 169,
+ "legend": {
+ "show": false
+ },
+ "links": [],
+ "targets": [
+ {
+ "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "refId": "A"
+ }
+ ],
+ "title": "TCP CONNECTION DURATION",
+ "tooltip": {
+ "show": true,
+ "showHistogram": true
+ },
+ "type": "heatmap",
+ "xAxis": {
+ "show": true
+ },
+ "xBucketNumber": null,
+ "xBucketSize": null,
+ "yAxis": {
+ "decimals": null,
+ "format": "dtdurationms",
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true,
+ "splitFactor": null
+ },
+ "yBucketBound": "auto",
+ "yBucketNumber": null,
+ "yBucketSize": null
+ }
+ ],
+ "title": "Inbound TCP Metrics",
+ "type": "row"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 16.6
+ },
+ "id": 152,
+ "panels": [],
+ "title": "",
+ "type": "row"
+ },
+ {
+ "content": "\n INBOUND STATEFULSETS\n
",
+ "gridPos": {
+ "h": 2.2,
+ "w": 24,
+ "x": 0,
+ "y": 17.6
+ },
+ "id": 76,
+ "links": [],
+ "mode": "html",
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 19.8
+ },
+ "id": 59,
+ "panels": [
+ {
+ "content": "\n

\n
statefulset/$inbound\n
",
+ "gridPos": {
+ "h": 2,
+ "w": 24,
+ "x": 0,
+ "y": 20.8
+ },
+ "id": 39,
+ "links": [],
+ "mode": "html",
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 22.8
+ },
+ "id": 36,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(response_total{classification=\"success\", statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (statefulset, pod) / sum(irate(response_total{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (statefulset, pod)",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 1,
+ "legendFormat": "po/{{pod}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "SUCCESS RATE",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "decimals": null,
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": "1",
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 22.8
+ },
+ "id": 22,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(request_total{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\", tls=\"true\"}[30s])) by (statefulset, pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "🔒po/{{pod}}",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(irate(request_total{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\", tls!=\"true\"}[30s])) by (statefulset, pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "po/{{pod}}",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "REQUEST RATE",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "decimals": null,
+ "format": "rps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 22.8
+ },
+ "id": 29,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (le, statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "P50 statefulset/{{statefulset}}",
+ "refId": "A"
+ },
+ {
+ "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (le, statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "P95 statefulset/{{statefulset}}",
+ "refId": "B"
+ },
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (le, statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "P99 statefulset/{{statefulset}}",
+ "refId": "C"
+ }
+ ],
+ "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": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ }
+ ],
+ "repeat": "inbound",
+ "title": "statefulset/$inbound",
+ "type": "row"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 20.8
+ },
+ "id": 34,
+ "panels": [],
+ "repeat": null,
+ "title": "",
+ "type": "row"
+ },
+ {
+ "content": "\n OUTBOUND TRAFFIC\n
",
+ "gridPos": {
+ "h": 2.2,
+ "w": 24,
+ "x": 0,
+ "y": 21.8
+ },
+ "id": 32,
+ "links": [],
+ "mode": "html",
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 24
+ },
+ "id": 77,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (dst_statefulset) / sum(irate(response_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (dst_statefulset)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "statefulset/{{dst_statefulset}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "SUCCESS RATE",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "decimals": null,
+ "format": "percentunit",
+ "label": "",
+ "logBase": 1,
+ "max": "1",
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 24
+ },
+ "id": 78,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_statefulset)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "🔒statefulset/{{dst_statefulset}}",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_statefulset)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "statefulset/{{dst_statefulset}}",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "REQUEST RATE",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "rps",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 24
+ },
+ "id": 79,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (le, dst_statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "P95 statefulset/{{dst_statefulset}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "P95 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": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 31
+ },
+ "id": 154,
+ "panels": [
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 41
+ },
+ "id": 157,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "tcp_close_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\",errno!=\"\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{peer}} {{errno}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "TCP CONNECTION FAILURES",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "decimals": null,
+ "format": "none",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 41
+ },
+ "id": 166,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "tcp_open_connections{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{peer}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "TCP CONNECTIONS OPEN",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "cards": {
+ "cardPadding": null,
+ "cardRound": null
+ },
+ "color": {
+ "cardColor": "#b4ff00",
+ "colorScale": "sqrt",
+ "colorScheme": "interpolateOranges",
+ "exponent": 0.5,
+ "mode": "spectrum"
+ },
+ "dataFormat": "timeseries",
+ "datasource": "prometheus",
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 41
+ },
+ "heatmap": {},
+ "highlightCards": true,
+ "id": 160,
+ "legend": {
+ "show": false
+ },
+ "links": [],
+ "targets": [
+ {
+ "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "refId": "A"
+ }
+ ],
+ "title": "TCP CONNECTION DURATION",
+ "tooltip": {
+ "show": true,
+ "showHistogram": true
+ },
+ "type": "heatmap",
+ "xAxis": {
+ "show": true
+ },
+ "xBucketNumber": null,
+ "xBucketSize": null,
+ "yAxis": {
+ "decimals": null,
+ "format": "dtdurationms",
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true,
+ "splitFactor": null
+ },
+ "yBucketBound": "auto",
+ "yBucketNumber": null,
+ "yBucketSize": null
+ }
+ ],
+ "title": "Outbound TCP Metrics",
+ "type": "row"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 32
+ },
+ "id": 156,
+ "panels": [],
+ "title": "",
+ "type": "row"
+ },
+ {
+ "content": "\n OUTBOUND STATEFULSETS\n
",
+ "gridPos": {
+ "h": 2.2,
+ "w": 24,
+ "x": 0,
+ "y": 33
+ },
+ "id": 80,
+ "links": [],
+ "mode": "html",
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 35.2
+ },
+ "id": 27,
+ "panels": [
+ {
+ "content": "\n

\n
statefulset/$outbound\n
",
+ "gridPos": {
+ "h": 2,
+ "w": 24,
+ "x": 0,
+ "y": 36.2
+ },
+ "id": 40,
+ "links": [],
+ "mode": "html",
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 38.2
+ },
+ "id": 28,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_statefulset) / sum(irate(response_total{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_statefulset)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "statefulset/{{dst_statefulset}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "SUCCESS RATE",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "decimals": null,
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": "1",
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 38.2
+ },
+ "id": 35,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_statefulset)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "🔒statefulset/{{dst_statefulset}}",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_statefulset)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "statefulset/{{dst_statefulset}}",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "REQUEST RATE",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "rps",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "prometheus",
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 38.2
+ },
+ "id": 41,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "P50 statefulset/{{dst_statefulset}}",
+ "refId": "A"
+ },
+ {
+ "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "P95 statefulset/{{dst_statefulset}}",
+ "refId": "B"
+ },
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_statefulset))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "P99 statefulset/{{dst_statefulset}}",
+ "refId": "C"
+ }
+ ],
+ "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": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ }
+ ],
+ "repeat": "outbound",
+ "title": "statefulset/$outbound",
+ "type": "row"
+ },
+ {
+ "content": "\n
\n

\n
\n
\n
\n
\n",
+ "gridPos": {
+ "h": 3,
+ "w": 24,
+ "x": 0,
+ "y": 36.2
+ },
+ "height": "1px",
+ "id": 171,
+ "links": [],
+ "mode": "html",
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ }
+ ],
+ "refresh": "5s",
+ "schemaVersion": 16,
+ "style": "dark",
+ "tags": [
+ "linkerd"
+ ],
+ "templating": {
+ "list": [
+ {
+ "allValue": null,
+ "current": {},
+ "datasource": "prometheus",
+ "hide": 0,
+ "includeAll": false,
+ "label": "Namespace",
+ "multi": false,
+ "name": "namespace",
+ "options": [],
+ "query": "label_values(request_total{statefulset!=\"\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {},
+ "datasource": "prometheus",
+ "hide": 0,
+ "includeAll": false,
+ "label": "StatefulSet",
+ "multi": false,
+ "name": "statefulset",
+ "options": [],
+ "query": "label_values(request_total{namespace=\"$namespace\"}, statefulset)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {},
+ "datasource": "prometheus",
+ "hide": 2,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "inbound",
+ "options": [],
+ "query": "label_values(request_total{dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\"}, statefulset)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {},
+ "datasource": "prometheus",
+ "hide": 2,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "outbound",
+ "options": [],
+ "query": "label_values(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\"}, dst_statefulset)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-5m",
+ "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": "",
+ "title": "Linkerd StatefulSet",
+ "uid": "6svnwykmk",
+ "version": 1
+}
diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go
index 8b919257df041..238f8e724562f 100644
--- a/pkg/k8s/k8s.go
+++ b/pkg/k8s/k8s.go
@@ -46,6 +46,7 @@ var AllResources = []string{
var StatAllResourceTypes = []string{
// TODO: add Namespace here to decrease queries from the web process
DaemonSet,
+ StatefulSet,
Deployment,
ReplicationController,
Pod,
diff --git a/web/app/js/components/Namespace.jsx b/web/app/js/components/Namespace.jsx
index a2a311349efcd..8bc2b7fefeb70 100644
--- a/web/app/js/components/Namespace.jsx
+++ b/web/app/js/components/Namespace.jsx
@@ -143,6 +143,7 @@ class Namespaces extends React.Component {
}
{this.renderResourceSection("deployment", metrics.deployment)}
{this.renderResourceSection("daemonset", metrics.daemonset)}
+ {this.renderResourceSection("statefulset", metrics.statefulset)}
{this.renderResourceSection("replicationcontroller", metrics.replicationcontroller)}
{this.renderResourceSection("pod", metrics.pod)}
{this.renderResourceSection("authority", metrics.authority)}
diff --git a/web/app/js/components/NamespaceLanding.jsx b/web/app/js/components/NamespaceLanding.jsx
index 255b79f6f1e00..bf7bbe6f78e91 100644
--- a/web/app/js/components/NamespaceLanding.jsx
+++ b/web/app/js/components/NamespaceLanding.jsx
@@ -156,6 +156,7 @@ class NamespaceLanding extends React.Component {
{this.renderResourceSection("deployment", metrics.deployment)}
{this.renderResourceSection("daemonset", metrics.daemonset)}
+ {this.renderResourceSection("statefulset", metrics.statefulset)}
{this.renderResourceSection("replicationcontroller", metrics.replicationcontroller)}
{this.renderResourceSection("pod", metrics.pod)}
{this.renderResourceSection("authority", metrics.authority)}
diff --git a/web/app/js/components/NavigationResources.jsx b/web/app/js/components/NavigationResources.jsx
index c8631c32dc800..231ccf93a2971 100644
--- a/web/app/js/components/NavigationResources.jsx
+++ b/web/app/js/components/NavigationResources.jsx
@@ -70,6 +70,7 @@ class NavigationResourcesBase extends React.Component {
+
diff --git a/web/app/js/components/util/Utils.js b/web/app/js/components/util/Utils.js
index 53a28123f10b7..a42dd4b46555a 100644
--- a/web/app/js/components/util/Utils.js
+++ b/web/app/js/components/util/Utils.js
@@ -129,7 +129,10 @@ export const friendlyTitle = singularOrPluralResource => {
titleCase = _startCase("replication controller");
} else if (resource === "daemonset") {
titleCase = _startCase("daemon set");
+ } else if (resource === "statefulset") {
+ titleCase = _startCase("stateful set");
}
+
let titles = { singular: titleCase };
if (resource === "authority") {
titles.plural = "Authorities";
diff --git a/web/app/js/index.js b/web/app/js/index.js
index 4fd2f70fdf511..116b86db96f74 100644
--- a/web/app/js/index.js
+++ b/web/app/js/index.js
@@ -65,6 +65,9 @@ let applicationHtml = (
} />
+ } />
} />
@@ -89,6 +92,9 @@ let applicationHtml = (
} />
+ } />
} />
diff --git a/web/srv/server.go b/web/srv/server.go
index c7edf8e09b69e..4a3547ba4d00b 100644
--- a/web/srv/server.go
+++ b/web/srv/server.go
@@ -95,12 +95,14 @@ func NewServer(
server.router.GET("/namespaces", handler.handleIndex)
server.router.GET("/namespaces/:namespace", handler.handleIndex)
server.router.GET("/daemonsets", handler.handleIndex)
+ server.router.GET("/statefulsets", handler.handleIndex)
server.router.GET("/deployments", handler.handleIndex)
server.router.GET("/replicationcontrollers", handler.handleIndex)
server.router.GET("/pods", handler.handleIndex)
server.router.GET("/authorities", handler.handleIndex)
server.router.GET("/namespaces/:namespace/pods/:pod", handler.handleIndex)
server.router.GET("/namespaces/:namespace/daemonsets/:daemonset", handler.handleIndex)
+ server.router.GET("/namespaces/:namespace/statefulsets/:statefulset", handler.handleIndex)
server.router.GET("/namespaces/:namespace/deployments/:deployment", handler.handleIndex)
server.router.GET("/namespaces/:namespace/replicationcontrollers/:replicationcontroller", handler.handleIndex)
server.router.GET("/tap", handler.handleIndex)