diff --git a/BUILD.md b/BUILD.md
index f802ef9560c2c..aef018d32c72d 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -144,6 +144,10 @@ bin/conduit stat deployments
# view a live pipeline of requests
bin/conduit tap deploy emojivoto/voting
+
+# view grafana dashboard
+kubectl -n conduit port-forward $(kubectl --namespace=conduit get po --selector=app=grafana -o jsonpath='{.items[*].metadata.name}') 3000:3000
+open http://localhost:3000
```
## Go
diff --git a/cli/cmd/install.go b/cli/cmd/install.go
index 3759ec473dfb4..54f7f5ca57d3f 100644
--- a/cli/cmd/install.go
+++ b/cli/cmd/install.go
@@ -20,6 +20,9 @@ type installConfig struct {
ControllerImage string
WebImage string
PrometheusImage string
+ GrafanaImage string
+ VizDashboard string
+ HealthDashboard string
ControllerReplicas uint
WebReplicas uint
PrometheusReplicas uint
@@ -63,6 +66,9 @@ func validateAndBuildConfig() (*installConfig, error) {
ControllerImage: fmt.Sprintf("%s/controller:%s", dockerRegistry, conduitVersion),
WebImage: fmt.Sprintf("%s/web:%s", dockerRegistry, conduitVersion),
PrometheusImage: "prom/prometheus:v2.1.0",
+ GrafanaImage: "grafana/grafana:5.0.0-beta4",
+ VizDashboard: install.Viz,
+ HealthDashboard: install.Health,
ControllerReplicas: controllerReplicas,
WebReplicas: webReplicas,
PrometheusReplicas: prometheusReplicas,
diff --git a/cli/cmd/install_test.go b/cli/cmd/install_test.go
index 6eb978df1c0d8..4da21ca72de0b 100644
--- a/cli/cmd/install_test.go
+++ b/cli/cmd/install_test.go
@@ -25,6 +25,9 @@ func TestRender(t *testing.T) {
ControllerImage: "ControllerImage",
WebImage: "WebImage",
PrometheusImage: "PrometheusImage",
+ GrafanaImage: "GrafanaImage",
+ VizDashboard: "VizDashboard",
+ HealthDashboard: "HealthDashboard",
ControllerReplicas: 1,
WebReplicas: 2,
PrometheusReplicas: 3,
diff --git a/cli/cmd/test_helper.go b/cli/cmd/test_helper.go
index 837302c749efe..53d91dcfbef30 100644
--- a/cli/cmd/test_helper.go
+++ b/cli/cmd/test_helper.go
@@ -13,7 +13,12 @@ func diffCompare(t *testing.T, actual string, expected string) {
if actual != expected {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(expected, actual, true)
- patches := dmp.PatchMake(expected, diffs)
+
+ // colorized output for local testing
+ // t.Fatalf("Unexpected output:\n%+v", dmp.DiffPrettyText(diffs))
+
+ diffs = dmp.DiffCleanupSemantic(diffs)
+ patches := dmp.PatchMake(diffs)
patchText := dmp.PatchToText(patches)
t.Fatalf("Unexpected output:\n%+v", patchText)
}
diff --git a/cli/cmd/testdata/install_default.golden b/cli/cmd/testdata/install_default.golden
index 05f7c08a2f9ef..11e1e22b9badf 100755
--- a/cli/cmd/testdata/install_default.golden
+++ b/cli/cmd/testdata/install_default.golden
@@ -546,4 +546,273 @@ data:
- source_labels: [__meta_kubernetes_pod_container_name]
action: replace
target_label: job
+
+### Grafana ###
+---
+kind: Service
+apiVersion: v1
+metadata:
+ name: grafana
+ namespace: conduit
+ labels:
+ conduit.io/control-plane-component: grafana
+ annotations:
+ conduit.io/created-by: conduit/cli undefined
+spec:
+ type: ClusterIP
+ selector:
+ conduit.io/control-plane-component: grafana
+ ports:
+ - name: http
+ port: 3000
+ targetPort: 3000
+
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ annotations:
+ conduit.io/created-by: conduit/cli undefined
+ creationTimestamp: null
+ labels:
+ conduit.io/control-plane-component: grafana
+ name: grafana
+ namespace: conduit
+spec:
+ replicas: 1
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ conduit.io/created-by: conduit/cli undefined
+ conduit.io/proxy-version: undefined
+ creationTimestamp: null
+ labels:
+ conduit.io/control-plane-component: grafana
+ conduit.io/control-plane-ns: conduit
+ spec:
+ containers:
+ - image: grafana/grafana:5.0.0-beta4
+ imagePullPolicy: IfNotPresent
+ name: grafana
+ ports:
+ - containerPort: 3000
+ name: http
+ resources: {}
+ volumeMounts:
+ - mountPath: /etc/grafana
+ name: grafana-config
+ readOnly: true
+ - mountPath: /var/lib/grafana/dashboards
+ name: grafana-dashboards
+ - mountPath: /usr/share/grafana/public/dashboards
+ name: grafana-dashboard-home
+ readOnly: true
+ - env:
+ - name: CONDUIT_PROXY_LOG
+ value: warn,conduit_proxy=info
+ - name: CONDUIT_PROXY_CONTROL_URL
+ value: tcp://proxy-api.conduit.svc.cluster.local:8086
+ - name: CONDUIT_PROXY_CONTROL_LISTENER
+ value: tcp://0.0.0.0:4190
+ - name: CONDUIT_PROXY_PRIVATE_LISTENER
+ value: tcp://127.0.0.1:4140
+ - name: CONDUIT_PROXY_PUBLIC_LISTENER
+ value: tcp://0.0.0.0:4143
+ - name: CONDUIT_PROXY_NODE_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: spec.nodeName
+ - name: CONDUIT_PROXY_POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ - name: CONDUIT_PROXY_POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ - name: CONDUIT_PROXY_DESTINATIONS_AUTOCOMPLETE_FQDN
+ value: Kubernetes
+ image: gcr.io/runconduit/proxy:undefined
+ imagePullPolicy: IfNotPresent
+ name: conduit-proxy
+ ports:
+ - containerPort: 4143
+ name: conduit-proxy
+ resources: {}
+ securityContext:
+ runAsUser: 2102
+ initContainers:
+ - args:
+ - --incoming-proxy-port
+ - "4143"
+ - --outgoing-proxy-port
+ - "4140"
+ - --proxy-uid
+ - "2102"
+ - --inbound-ports-to-ignore
+ - "4190"
+ image: gcr.io/runconduit/proxy-init:undefined
+ imagePullPolicy: IfNotPresent
+ name: conduit-init
+ resources: {}
+ securityContext:
+ capabilities:
+ add:
+ - NET_ADMIN
+ privileged: false
+ volumes:
+ - configMap:
+ items:
+ - key: grafana.ini
+ path: grafana.ini
+ - key: datasources.yaml
+ path: provisioning/datasources/datasources.yaml
+ - key: dashboards.yaml
+ path: provisioning/dashboards/dashboards.yaml
+ name: grafana-config
+ name: grafana-config
+ - configMap:
+ name: grafana-dashboards
+ name: grafana-dashboards
+ - configMap:
+ items:
+ - key: conduit-viz.json
+ path: home.json
+ name: grafana-dashboards
+ name: grafana-dashboard-home
+status: {}
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: grafana-config
+ namespace: conduit
+ labels:
+ conduit.io/control-plane-component: grafana
+ annotations:
+ conduit.io/created-by: conduit/cli undefined
+data:
+ grafana.ini: |-
+ instance_name = conduit-grafana
+
+ [auth]
+ disable_login_form = true
+
+ [auth.anonymous]
+ enabled = true
+ org_role = Editor
+
+ [auth.basic]
+ enabled = false
+
+ datasources.yaml: |-
+ apiVersion: 1
+ datasources:
+ - name: prometheus
+ type: prometheus
+ access: proxy
+ orgId: 1
+ url: http://prometheus.conduit.svc.cluster.local:9090
+ isDefault: true
+ jsonData:
+ timeInterval: "5s"
+ version: 1
+ editable: true
+
+ dashboards.yaml: |-
+ apiVersion: 1
+ providers:
+ - name: 'default'
+ orgId: 1
+ folder: ''
+ type: file
+ disableDeletion: true
+ editable: true
+ options:
+ path: /var/lib/grafana/dashboards
+ homeDashboardId: conduit-viz
+
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: grafana-dashboards
+ namespace: conduit
+ labels:
+ conduit.io/control-plane-component: grafana
+ annotations:
+ conduit.io/created-by: conduit/cli undefined
+data:
+ conduit-viz.json: |-
+ {
+ "rows": [
+ {
+ "collapse": false,
+ "height": "50px",
+ "panels": [
+ {
+ "content": "
\n
\n

\n
\n
\n
Conduit is a next-generation ultralight service mesh for Kubernetes.\n
\n Need help? Visit
conduit.io.\n
\n
",
+ "height": "1px",
+ "id": 14,
+ "links": [],
+ "mode": "html",
+ "span": 12,
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ }
+ ],
+ "showTitle": false
+ },
+ {
+ "collapse": false,
+ "height": 250,
+ "panels": [
+ {
+ "legend": {
+ },
+ "lines": true,
+ "targets": [
+ {
+ "expr": "sum(irate(responses_total[20s])) by (target_deployment)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{target_deployment}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Request Volume",
+ "type": "graph",
+ "xaxis": {
+ "show": true
+ },
+ "yaxes": [
+ {
+ "format": "rps",
+ "show": true
+ },
+ {
+ "show": true
+ }
+ ]
+ }
+ ],
+ "showTitle": false
+ }
+ ],
+ "refresh": "5s",
+ "time": {
+ "from": "now-5m",
+ "to": "now"
+ },
+ "title": "conduit-viz"
+ }
+
+
+ conduit-health.json: |-
+ {
+ "title": "conduit-health"
+ }
+
---
diff --git a/cli/cmd/testdata/install_output.golden b/cli/cmd/testdata/install_output.golden
index a532c7253c3ef..6524732f48382 100644
--- a/cli/cmd/testdata/install_output.golden
+++ b/cli/cmd/testdata/install_output.golden
@@ -549,4 +549,208 @@ data:
- source_labels: [__meta_kubernetes_pod_container_name]
action: replace
target_label: job
+
+### Grafana ###
+---
+kind: Service
+apiVersion: v1
+metadata:
+ name: grafana
+ namespace: Namespace
+ labels:
+ ControllerComponentLabel: grafana
+ annotations:
+ CreatedByAnnotation: CliVersion
+spec:
+ type: ClusterIP
+ selector:
+ ControllerComponentLabel: grafana
+ ports:
+ - name: http
+ port: 3000
+ targetPort: 3000
+
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ annotations:
+ CreatedByAnnotation: CliVersion
+ creationTimestamp: null
+ labels:
+ ControllerComponentLabel: grafana
+ name: grafana
+ namespace: Namespace
+spec:
+ replicas: 1
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ CreatedByAnnotation: CliVersion
+ conduit.io/created-by: conduit/cli undefined
+ conduit.io/proxy-version: undefined
+ creationTimestamp: null
+ labels:
+ ControllerComponentLabel: grafana
+ conduit.io/control-plane-ns: Namespace
+ spec:
+ containers:
+ - image: GrafanaImage
+ imagePullPolicy: ImagePullPolicy
+ name: grafana
+ ports:
+ - containerPort: 3000
+ name: http
+ resources: {}
+ volumeMounts:
+ - mountPath: /etc/grafana
+ name: grafana-config
+ readOnly: true
+ - mountPath: /var/lib/grafana/dashboards
+ name: grafana-dashboards
+ - mountPath: /usr/share/grafana/public/dashboards
+ name: grafana-dashboard-home
+ readOnly: true
+ - env:
+ - name: CONDUIT_PROXY_LOG
+ value: warn,conduit_proxy=info
+ - name: CONDUIT_PROXY_CONTROL_URL
+ value: tcp://proxy-api.Namespace.svc.cluster.local:8086
+ - name: CONDUIT_PROXY_CONTROL_LISTENER
+ value: tcp://0.0.0.0:4190
+ - name: CONDUIT_PROXY_PRIVATE_LISTENER
+ value: tcp://127.0.0.1:4140
+ - name: CONDUIT_PROXY_PUBLIC_LISTENER
+ value: tcp://0.0.0.0:4143
+ - name: CONDUIT_PROXY_NODE_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: spec.nodeName
+ - name: CONDUIT_PROXY_POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ - name: CONDUIT_PROXY_POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ - name: CONDUIT_PROXY_DESTINATIONS_AUTOCOMPLETE_FQDN
+ value: Kubernetes
+ image: gcr.io/runconduit/proxy:undefined
+ imagePullPolicy: IfNotPresent
+ name: conduit-proxy
+ ports:
+ - containerPort: 4143
+ name: conduit-proxy
+ resources: {}
+ securityContext:
+ runAsUser: 2102
+ initContainers:
+ - args:
+ - --incoming-proxy-port
+ - "4143"
+ - --outgoing-proxy-port
+ - "4140"
+ - --proxy-uid
+ - "2102"
+ - --inbound-ports-to-ignore
+ - "4190"
+ image: gcr.io/runconduit/proxy-init:undefined
+ imagePullPolicy: IfNotPresent
+ name: conduit-init
+ resources: {}
+ securityContext:
+ capabilities:
+ add:
+ - NET_ADMIN
+ privileged: false
+ volumes:
+ - configMap:
+ items:
+ - key: grafana.ini
+ path: grafana.ini
+ - key: datasources.yaml
+ path: provisioning/datasources/datasources.yaml
+ - key: dashboards.yaml
+ path: provisioning/dashboards/dashboards.yaml
+ name: grafana-config
+ name: grafana-config
+ - configMap:
+ name: grafana-dashboards
+ name: grafana-dashboards
+ - configMap:
+ items:
+ - key: conduit-viz.json
+ path: home.json
+ name: grafana-dashboards
+ name: grafana-dashboard-home
+status: {}
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: grafana-config
+ namespace: Namespace
+ labels:
+ ControllerComponentLabel: grafana
+ annotations:
+ CreatedByAnnotation: CliVersion
+data:
+ grafana.ini: |-
+ instance_name = conduit-grafana
+
+ [auth]
+ disable_login_form = true
+
+ [auth.anonymous]
+ enabled = true
+ org_role = Editor
+
+ [auth.basic]
+ enabled = false
+
+ datasources.yaml: |-
+ apiVersion: 1
+ datasources:
+ - name: prometheus
+ type: prometheus
+ access: proxy
+ orgId: 1
+ url: http://prometheus.Namespace.svc.cluster.local:9090
+ isDefault: true
+ jsonData:
+ timeInterval: "5s"
+ version: 1
+ editable: true
+
+ dashboards.yaml: |-
+ apiVersion: 1
+ providers:
+ - name: 'default'
+ orgId: 1
+ folder: ''
+ type: file
+ disableDeletion: true
+ editable: true
+ options:
+ path: /var/lib/grafana/dashboards
+ homeDashboardId: conduit-viz
+
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: grafana-dashboards
+ namespace: Namespace
+ labels:
+ ControllerComponentLabel: grafana
+ annotations:
+ CreatedByAnnotation: CliVersion
+data:
+ conduit-viz.json: |-
+ VizDashboard
+
+ conduit-health.json: |-
+ HealthDashboard
---
diff --git a/cli/install/health.go b/cli/install/health.go
new file mode 100644
index 0000000000000..2804495004ff9
--- /dev/null
+++ b/cli/install/health.go
@@ -0,0 +1,7 @@
+package install
+
+// Health defines the Conduit Health Grafana dashboard, installed via the `conduit install` command.
+const Health = `{
+ "title": "conduit-health"
+ }
+`
diff --git a/cli/install/template.go b/cli/install/template.go
index 47eb8ff66ef30..539e4c9d521f1 100644
--- a/cli/install/template.go
+++ b/cli/install/template.go
@@ -368,4 +368,149 @@ data:
- source_labels: [__meta_kubernetes_pod_container_name]
action: replace
target_label: job
+
+### Grafana ###
+---
+kind: Service
+apiVersion: v1
+metadata:
+ name: grafana
+ namespace: {{.Namespace}}
+ labels:
+ {{.ControllerComponentLabel}}: grafana
+ annotations:
+ {{.CreatedByAnnotation}}: {{.CliVersion}}
+spec:
+ type: ClusterIP
+ selector:
+ {{.ControllerComponentLabel}}: grafana
+ ports:
+ - name: http
+ port: 3000
+ targetPort: 3000
+
+---
+kind: Deployment
+apiVersion: extensions/v1beta1
+metadata:
+ name: grafana
+ namespace: {{.Namespace}}
+ labels:
+ {{.ControllerComponentLabel}}: grafana
+ annotations:
+ {{.CreatedByAnnotation}}: {{.CliVersion}}
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ {{.ControllerComponentLabel}}: grafana
+ annotations:
+ {{.CreatedByAnnotation}}: {{.CliVersion}}
+ spec:
+ volumes:
+ - name: grafana-config
+ configMap:
+ name: grafana-config
+ items:
+ - key: grafana.ini
+ path: grafana.ini
+ - key: datasources.yaml
+ path: provisioning/datasources/datasources.yaml
+ - key: dashboards.yaml
+ path: provisioning/dashboards/dashboards.yaml
+ - name: grafana-dashboards
+ configMap:
+ name: grafana-dashboards
+ - name: grafana-dashboard-home
+ configMap:
+ name: grafana-dashboards
+ items:
+ - key: conduit-viz.json
+ path: home.json
+ containers:
+ - name: grafana
+ ports:
+ - name: http
+ containerPort: 3000
+ volumeMounts:
+ - name: grafana-config
+ mountPath: /etc/grafana
+ readOnly: true
+ - name: grafana-dashboards
+ mountPath: /var/lib/grafana/dashboards
+ readOnly: false
+ - name: grafana-dashboard-home
+ mountPath: /usr/share/grafana/public/dashboards
+ readOnly: true
+ image: {{.GrafanaImage}}
+ imagePullPolicy: {{.ImagePullPolicy}}
+
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: grafana-config
+ namespace: {{.Namespace}}
+ labels:
+ {{.ControllerComponentLabel}}: grafana
+ annotations:
+ {{.CreatedByAnnotation}}: {{.CliVersion}}
+data:
+ grafana.ini: |-
+ instance_name = conduit-grafana
+
+ [auth]
+ disable_login_form = true
+
+ [auth.anonymous]
+ enabled = true
+ org_role = Editor
+
+ [auth.basic]
+ enabled = false
+
+ datasources.yaml: |-
+ apiVersion: 1
+ datasources:
+ - name: prometheus
+ type: prometheus
+ access: proxy
+ orgId: 1
+ url: http://prometheus.{{.Namespace}}.svc.cluster.local:9090
+ isDefault: true
+ jsonData:
+ timeInterval: "5s"
+ version: 1
+ editable: true
+
+ dashboards.yaml: |-
+ apiVersion: 1
+ providers:
+ - name: 'default'
+ orgId: 1
+ folder: ''
+ type: file
+ disableDeletion: true
+ editable: true
+ options:
+ path: /var/lib/grafana/dashboards
+ homeDashboardId: conduit-viz
+
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: grafana-dashboards
+ namespace: {{.Namespace}}
+ labels:
+ {{.ControllerComponentLabel}}: grafana
+ annotations:
+ {{.CreatedByAnnotation}}: {{.CliVersion}}
+data:
+ conduit-viz.json: |-
+ {{.VizDashboard}}
+
+ conduit-health.json: |-
+ {{.HealthDashboard}}
`
diff --git a/cli/install/viz.go b/cli/install/viz.go
new file mode 100644
index 0000000000000..705358b49d66b
--- /dev/null
+++ b/cli/install/viz.go
@@ -0,0 +1,67 @@
+package install
+
+// Viz defines the primary Conduit Grafana dashboard, installed via the `conduit install` command.
+const Viz = `{
+ "rows": [
+ {
+ "collapse": false,
+ "height": "50px",
+ "panels": [
+ {
+ "content": "\n
\n

\n
\n
\n
Conduit is a next-generation ultralight service mesh for Kubernetes.\n
\n Need help? Visit
conduit.io.\n
\n
",
+ "height": "1px",
+ "id": 14,
+ "links": [],
+ "mode": "html",
+ "span": 12,
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ }
+ ],
+ "showTitle": false
+ },
+ {
+ "collapse": false,
+ "height": 250,
+ "panels": [
+ {
+ "legend": {
+ },
+ "lines": true,
+ "targets": [
+ {
+ "expr": "sum(irate(responses_total[20s])) by (target_deployment)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{target_deployment}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Request Volume",
+ "type": "graph",
+ "xaxis": {
+ "show": true
+ },
+ "yaxes": [
+ {
+ "format": "rps",
+ "show": true
+ },
+ {
+ "show": true
+ }
+ ]
+ }
+ ],
+ "showTitle": false
+ }
+ ],
+ "refresh": "5s",
+ "time": {
+ "from": "now-5m",
+ "to": "now"
+ },
+ "title": "conduit-viz"
+ }
+`