diff --git a/CHANGELOG.md b/CHANGELOG.md index c958b2867..bfcaf7d97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan - [#269](https://github.com/kobsio/kobs/pull/269): [applications] :warning: _Breaking change:_ :warning: Improve topology graph, by allowing custom styles for applications. - [#275](https://github.com/kobsio/kobs/pull/275): [azure] Improve cost management integration by adjusting the chart style and allowing the usage in dashboard panels. - [#276](https://github.com/kobsio/kobs/pull/276): [resources] :warning: _Breaking change:_ :warning: Add new `verbs` property for resource permissions, to allow administrators more control about what users can do. +- [#279](https://github.com/kobsio/kobs/pull/279): [dashboards] :warning: _Breaking change:_ :warning: Refactor defaults, placeholders and variables handling. ## [v0.7.0](https://github.com/kobsio/kobs/releases/tag/v0.7.0) (2021-11-19) diff --git a/deploy/demo/bookinfo/details-application.yaml b/deploy/demo/bookinfo/details-application.yaml index 793b9c71b..12b6a261c 100644 --- a/deploy/demo/bookinfo/details-application.yaml +++ b/deploy/demo/bookinfo/details-application.yaml @@ -28,8 +28,6 @@ spec: - name: resources namespace: kobs title: Resources in the bookinfo namespace - placeholders: - namespace: bookinfo - name: resource-usage namespace: kobs title: Resource Usage diff --git a/deploy/demo/kobs/base/dashboards/istio-http.yaml b/deploy/demo/kobs/base/dashboards/istio-http.yaml index ab2cddd59..cada105e9 100644 --- a/deploy/demo/kobs/base/dashboards/istio-http.yaml +++ b/deploy/demo/kobs/base/dashboards/istio-http.yaml @@ -28,7 +28,7 @@ spec: options: type: labelValues label: destination_workload - query: istio_requests_total{reporter="{% .var_reporter %}", app=~"{{ .app }}", destination_workload_namespace=~"{{ .namespace }}"} + query: istio_requests_total{reporter="{% .var_reporter %}", app=~"{% .app %}", destination_workload_namespace=~"{% .namespace %}"} - name: var_source_workload_namespace label: Source Workload Namespace plugin: @@ -36,7 +36,7 @@ spec: options: type: labelValues label: source_workload_namespace - query: istio_requests_total{reporter="{% .var_reporter %}", destination_workload="{% .var_workload %}", destination_workload_namespace=~"{{ .namespace }}"} + query: istio_requests_total{reporter="{% .var_reporter %}", destination_workload="{% .var_workload %}", destination_workload_namespace=~"{% .namespace %}"} allowAll: true - name: var_source_workload label: Source Workload @@ -45,7 +45,7 @@ spec: options: type: labelValues label: source_workload - query: istio_requests_total{reporter="{% .var_reporter %}", destination_workload="{% .var_workload %}", destination_workload_namespace=~"{{ .namespace }}", source_workload_namespace=~"{% .var_source_workload_namespace %}"} + query: istio_requests_total{reporter="{% .var_reporter %}", destination_workload="{% .var_workload %}", destination_workload_namespace=~"{% .namespace %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"} allowAll: true rows: - size: 1 @@ -58,7 +58,7 @@ spec: unit: req/s type: sparkline queries: - - query: round(sum(irate(istio_requests_total{reporter="{% .var_reporter %}",destination_workload_namespace=~"{{ .namespace }}",destination_workload=~"{% .var_workload %}"}[5m])), 0.001) + - query: round(sum(irate(istio_requests_total{reporter="{% .var_reporter %}",destination_workload_namespace=~"{% .namespace %}",destination_workload=~"{% .var_workload %}"}[5m])), 0.001) - title: Incoming Success Rate colSpan: 6 plugin: @@ -67,7 +67,7 @@ spec: unit: "%" type: sparkline queries: - - query: sum(irate(istio_requests_total{reporter="{% .var_reporter %}",destination_workload_namespace=~"{{ .namespace }}",destination_workload=~"{% .var_workload %}",response_code!~"5.*"}[5m])) / sum(irate(istio_requests_total{reporter="{% .var_reporter %}",destination_workload_namespace=~"{{ .namespace }}",destination_workload=~"{% .var_workload %}"}[5m])) * 100 + - query: sum(irate(istio_requests_total{reporter="{% .var_reporter %}",destination_workload_namespace=~"{% .namespace %}",destination_workload=~"{% .var_workload %}",response_code!~"5.*"}[5m])) / sum(irate(istio_requests_total{reporter="{% .var_reporter %}",destination_workload_namespace=~"{% .namespace %}",destination_workload=~"{% .var_workload %}"}[5m])) * 100 - size: 2 panels: - title: Request Duration @@ -79,11 +79,11 @@ spec: type: line queries: - label: P50 - query: histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter="{% .var_reporter %}",destination_workload_namespace=~"{{ .namespace }}",destination_workload=~"{% .var_workload %}"}[1m])) by (le)) + query: histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter="{% .var_reporter %}",destination_workload_namespace=~"{% .namespace %}",destination_workload=~"{% .var_workload %}"}[1m])) by (le)) - label: P90 - query: histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter="{% .var_reporter %}",destination_workload_namespace=~"{{ .namespace }}",destination_workload=~"{% .var_workload %}"}[1m])) by (le)) + query: histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter="{% .var_reporter %}",destination_workload_namespace=~"{% .namespace %}",destination_workload=~"{% .var_workload %}"}[1m])) by (le)) - label: P99 - query: histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter="{% .var_reporter %}",destination_workload_namespace=~"{{ .namespace }}",destination_workload=~"{% .var_workload %}"}[1m])) by (le)) + query: histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter="{% .var_reporter %}",destination_workload_namespace=~"{% .namespace %}",destination_workload=~"{% .var_workload %}"}[1m])) by (le)) - title: Inbound Workloads size: 3 panels: @@ -97,9 +97,9 @@ spec: legend: table queries: - label: "{% .source_workload %}.{% .source_workload_namespace %} : {% .response_code %} (πŸ” mTLS)" - query: round(sum(irate(istio_requests_total{connection_security_policy="mutual_tls", destination_workload_namespace=~"{{ .namespace }}", destination_workload=~"{% .var_workload %}", reporter="{% .var_reporter %}", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001) + query: round(sum(irate(istio_requests_total{connection_security_policy="mutual_tls", destination_workload_namespace=~"{% .namespace %}", destination_workload=~"{% .var_workload %}", reporter="{% .var_reporter %}", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001) - label: "{% .source_workload %}.{% .source_workload_namespace %} : {% .response_code %}" - query: round(sum(irate(istio_requests_total{connection_security_policy!="mutual_tls", destination_workload_namespace=~"{{ .namespace }}", destination_workload=~"{% .var_workload %}", reporter="{% .var_reporter %}", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001) + query: round(sum(irate(istio_requests_total{connection_security_policy!="mutual_tls", destination_workload_namespace=~"{% .namespace %}", destination_workload=~"{% .var_workload %}", reporter="{% .var_reporter %}", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001) - title: Incoming Success Rate (non-5xx responses) By Source colSpan: 6 plugin: @@ -110,6 +110,6 @@ spec: legend: table queries: - label: "{% .source_workload %}.{% .source_workload_namespace %} (πŸ” mTLS)" - query: sum(irate(istio_requests_total{reporter="{% .var_reporter %}", connection_security_policy="mutual_tls", destination_workload_namespace=~"{{ .namespace }}", destination_workload=~"{% .var_workload %}",response_code!~"5.*", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter="{% .var_reporter %}", connection_security_policy="mutual_tls", destination_workload_namespace=~"{{ .namespace }}", destination_workload=~"{% .var_workload %}", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace) * 100 + query: sum(irate(istio_requests_total{reporter="{% .var_reporter %}", connection_security_policy="mutual_tls", destination_workload_namespace=~"{% .namespace %}", destination_workload=~"{% .var_workload %}",response_code!~"5.*", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter="{% .var_reporter %}", connection_security_policy="mutual_tls", destination_workload_namespace=~"{% .namespace %}", destination_workload=~"{% .var_workload %}", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace) * 100 - label: "{% .source_workload %}.{% .source_workload_namespace %}" - query: sum(irate(istio_requests_total{reporter="{% .var_reporter %}", connection_security_policy!="mutual_tls", destination_workload_namespace=~"{{ .namespace }}", destination_workload=~"{% .var_workload %}",response_code!~"5.*", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter="{% .var_reporter %}", connection_security_policy!="mutual_tls", destination_workload_namespace=~"{{ .namespace }}", destination_workload=~"{% .var_workload %}", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace) * 100 + query: sum(irate(istio_requests_total{reporter="{% .var_reporter %}", connection_security_policy!="mutual_tls", destination_workload_namespace=~"{% .namespace %}", destination_workload=~"{% .var_workload %}",response_code!~"5.*", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter="{% .var_reporter %}", connection_security_policy!="mutual_tls", destination_workload_namespace=~"{% .namespace %}", destination_workload=~"{% .var_workload %}", source_workload=~"{% .var_source_workload %}", source_workload_namespace=~"{% .var_source_workload_namespace %}"}[5m])) by (source_workload, source_workload_namespace) * 100 diff --git a/deploy/demo/kobs/base/dashboards/istio-logs.yaml b/deploy/demo/kobs/base/dashboards/istio-logs.yaml index c2dc17675..b4b23357d 100644 --- a/deploy/demo/kobs/base/dashboards/istio-logs.yaml +++ b/deploy/demo/kobs/base/dashboards/istio-logs.yaml @@ -22,7 +22,7 @@ spec: showChart: true queries: - name: Istio Logs - query: "kubernetes.namespace: {{ .namespace }} AND kubernetes.labels.app: {{ .app }} AND kubernetes.container.name: istio-proxy AND _exists_: content.method" + query: "kubernetes.namespace: {% .namespace %} AND kubernetes.labels.app: {% .app %} AND kubernetes.container.name: istio-proxy AND _exists_: content.method" fields: - "kubernetes.pod.name" - "content.authority" diff --git a/deploy/demo/kobs/base/dashboards/pod-logs.yaml b/deploy/demo/kobs/base/dashboards/pod-logs.yaml index 698acc91f..16feef3b3 100644 --- a/deploy/demo/kobs/base/dashboards/pod-logs.yaml +++ b/deploy/demo/kobs/base/dashboards/pod-logs.yaml @@ -22,7 +22,7 @@ spec: showChart: true queries: - name: Pod Logs - query: "kubernetes.namespace: {{ .namespace }} AND kubernetes.pod.name: {{ .name }}" + query: "kubernetes.namespace: {% .namespace %} AND kubernetes.pod.name: {% .name %}" fields: - "kubernetes.container.name" - "message" diff --git a/deploy/demo/kobs/base/dashboards/resource-usage.yaml b/deploy/demo/kobs/base/dashboards/resource-usage.yaml index 2b39fa60c..24338078d 100644 --- a/deploy/demo/kobs/base/dashboards/resource-usage.yaml +++ b/deploy/demo/kobs/base/dashboards/resource-usage.yaml @@ -19,7 +19,7 @@ spec: options: type: labelValues label: pod - query: container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{{ .pod }}", container!="POD", container!=""} + query: container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .pod %}", container!="POD", container!=""} allowAll: false rows: - size: 1 @@ -32,7 +32,7 @@ spec: type: sparkline unit: Cores queries: - - query: sum(rate(container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) + - query: sum(rate(container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) - title: Memory Usage colSpan: 4 plugin: @@ -41,7 +41,7 @@ spec: type: sparkline unit: MiB queries: - - query: sum(container_memory_working_set_bytes{namespace="{{ .namespace }}", pod=~"{% .var_pod %}", container!="POD", container!=""}) / 1024 / 1024 + - query: sum(container_memory_working_set_bytes{namespace="{% .namespace %}", pod=~"{% .var_pod %}", container!="POD", container!=""}) / 1024 / 1024 - title: Restarts colSpan: 4 plugin: @@ -49,7 +49,7 @@ spec: options: type: sparkline queries: - - query: kube_pod_container_status_restarts_total{namespace="{{ .namespace }}", pod=~"{% .var_pod %}"} + - query: kube_pod_container_status_restarts_total{namespace="{% .namespace %}", pod=~"{% .var_pod %}"} - size: 3 panels: - title: CPU Usage @@ -62,11 +62,11 @@ spec: legend: table queries: - label: "Usage: {% .container %}" - query: sum(rate(container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) by (container) + query: sum(rate(container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) by (container) - label: "Request: {% .container %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) - label: "Limits: {% .container %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) - title: Memory Usage colSpan: 6 plugin: @@ -77,11 +77,11 @@ spec: legend: table queries: - label: "Usage: {% .container %}" - query: sum(container_memory_working_set_bytes{namespace="{{ .namespace }}", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 + query: sum(container_memory_working_set_bytes{namespace="{% .namespace %}", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 - label: "Request: {% .container %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 - label: "Limits: {% .container %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 - title: Network size: 3 panels: @@ -94,9 +94,9 @@ spec: unit: bytes/s queries: - label: Received - query: sum(irate(container_network_receive_bytes_total{namespace="{{ .namespace }}", pod="{% .var_pod %}"}[2m])) by (pod) + query: sum(irate(container_network_receive_bytes_total{namespace="{% .namespace %}", pod="{% .var_pod %}"}[2m])) by (pod) - label: Transmitted - query: -sum(irate(container_network_transmit_bytes_total{namespace="{{ .namespace }}", pod="{% .var_pod %}"}[2m])) by (pod) + query: -sum(irate(container_network_transmit_bytes_total{namespace="{% .namespace %}", pod="{% .var_pod %}"}[2m])) by (pod) - title: Rate of Packets colSpan: 6 plugin: @@ -106,9 +106,9 @@ spec: unit: bytes/s queries: - label: Received - query: sum(irate(container_network_receive_packets_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: sum(irate(container_network_receive_packets_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - label: Transmitted - query: -sum(irate(container_network_transmit_packets_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: -sum(irate(container_network_transmit_packets_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - title: Rate of Packets Dropped colSpan: 6 plugin: @@ -118,9 +118,9 @@ spec: unit: bytes/s queries: - label: Received - query: sum(irate(container_network_receive_packets_dropped_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: sum(irate(container_network_receive_packets_dropped_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - label: Transmitted - query: -sum(irate(container_network_transmit_packets_dropped_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: -sum(irate(container_network_transmit_packets_dropped_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - title: "Resource Usage for all Pods" panels: - title: Table @@ -130,17 +130,17 @@ spec: type: table queries: - label: "{% .pod %}" - query: sum(rate(container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{{ .pod }}", container!="POD", container!=""}[2m])) by (pod) + query: sum(rate(container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .pod %}", container!="POD", container!=""}[2m])) by (pod) - label: "{% .pod %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="cpu", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="cpu", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) - label: "{% .pod %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="cpu", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="cpu", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) - label: "{% .pod %}" - query: sum(container_memory_working_set_bytes{namespace="{{ .namespace }}", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) / 1024 / 1024 + query: sum(container_memory_working_set_bytes{namespace="{% .namespace %}", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) / 1024 / 1024 - label: "{% .pod %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="memory", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) / 1024 / 1024 + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="memory", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) / 1024 / 1024 - label: "{% .pod %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="memory", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) / 1024 / 1024 + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="memory", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) / 1024 / 1024 columns: - name: pod title: Pod diff --git a/deploy/demo/kobs/base/dashboards/resources.yaml b/deploy/demo/kobs/base/dashboards/resources.yaml index 7876dca96..cebbe5ccf 100644 --- a/deploy/demo/kobs/base/dashboards/resources.yaml +++ b/deploy/demo/kobs/base/dashboards/resources.yaml @@ -6,26 +6,16 @@ metadata: namespace: kobs spec: description: Resources for an Application - placeholders: - - name: namespace - description: Namespace for the Application - variables: - - name: cluster - label: Cluster - plugin: - name: core - options: - type: clusters rows: - panels: - - title: Resources in the {{ .namespace }} ({% .cluster %}) + - title: Resources in the {% .__namespace %} ({% .__cluster %}) plugin: name: resources options: - clusters: - - "{% .cluster %}" + - "{% .__cluster %}" namespaces: - - "{{ .namespace }}" + - "{% .__namespace %}" resources: - pods - deployments @@ -40,9 +30,9 @@ spec: options: view: gallery clusters: - - "{% .cluster %}" + - "{% .__cluster %}" namespaces: - - "{{ .namespace }}" + - "{% .__namespace %}" - title: Applications Topology colSpan: 6 plugin: @@ -50,6 +40,6 @@ spec: options: view: topology clusters: - - "{% .cluster %}" + - "{% .__cluster %}" namespaces: - - "{{ .namespace }}" + - "{% .__namespace %}" diff --git a/deploy/demo/kobs/base/dashboards/traces.yaml b/deploy/demo/kobs/base/dashboards/traces.yaml index c4e6fc1cb..418b4703a 100644 --- a/deploy/demo/kobs/base/dashboards/traces.yaml +++ b/deploy/demo/kobs/base/dashboards/traces.yaml @@ -19,5 +19,5 @@ spec: options: showChart: true queries: - - name: "{{ .service }}" - service: "{{ .service }}" + - name: "{% .service %}" + service: "{% .service %}" diff --git a/docs/plugins/applications.md b/docs/plugins/applications.md index df976dde1..caecaa609 100644 --- a/docs/plugins/applications.md +++ b/docs/plugins/applications.md @@ -45,9 +45,9 @@ plugins: | Field | Type | Description | Required | | ----- | ---- | ----------- | -------- | -| view | string | The view, which should be used to show the applications. This must be `gallery` or `topology`. The default will be `gallery`. | No | -| clusters | []string | A list of clusters. If this value isn't provided, it will be the cluster from the team or application where the dashboard is used. | No | -| namespaces | []string | A list of namespaces. If this value isn't provided, it will be the namespace from the team or application where the dashboard is used. | No | +| view | string | The view, which should be used to show the applications. This must be `gallery` or `topology`. | Yes | +| clusters | []string | A list of clusters. | Yes | +| namespaces | []string | A list of namespaces. | Yes | | tags | []string | An optional list of tags. | No | | team | [Team](#team) | Get the applications for a team instead of clusters and namespaces. | No | @@ -57,13 +57,13 @@ It is also possible to show all applications for a team. If a team is provided t | Field | Type | Description | Required | | ----- | ---- | ----------- | -------- | -| cluster | string | The cluster of the team. | No | -| namespace | string | The namespace of the team. | No | +| cluster | string | The cluster of the team. | Yes | +| namespace | string | The namespace of the team. | Yes | | name | string | The name of the team. | Yes | ## Examples -The following dashboard contains two panels for application, one shows the applications in the gallery view and the other one in the topology view. +The following dashboard contains two panels for an application, one shows the applications in the gallery view and the other one in the topology view. ```yaml --- @@ -93,7 +93,7 @@ spec: clusters: - "{% .cluster %}" namespaces: - - "{{ .namespace }}" + - "{% .namespace %}" - title: Applications Topology colSpan: 6 plugin: @@ -103,7 +103,7 @@ spec: clusters: - "{% .cluster %}" namespaces: - - "{{ .namespace }}" + - "{% .namespace %}" ``` The following example shows all applications for `team-diablo`. @@ -121,6 +121,7 @@ spec: options: view: gallery team: + cluster: "{% .__cluster %}" namespace: kobs name: team-diablo ``` diff --git a/docs/plugins/dashboards.md b/docs/plugins/dashboards.md index 653c3480c..4476dc7ae 100644 --- a/docs/plugins/dashboards.md +++ b/docs/plugins/dashboards.md @@ -8,8 +8,8 @@ The options for the dashboards plugin is a list of objects with the following pr | Field | Type | Description | Required | | ----- | ---- | ----------- | -------- | -| cluster | string | Cluster of the dashboard. If this field is omitted kobs will look in the same cluster as the application was created in. | No | -| namespace | string | Namespace of the dashboard. If this field is omitted kobs will look in the same namespace as the application was created in. | No | +| cluster | string | Cluster of the dashboard | Yes | +| namespace | string | Namespace of the dashboard. | Yes | | name | string | Name of the dashboard. | Yes | | title | string | Title for the dashboard | Yes | | description | string | The description can be used to explain the content of the dashboard. | No | @@ -28,15 +28,19 @@ spec: plugin: name: dashboards options: - - name: resources - namespace: kobs - title: Resources in the bookinfo namespace - placeholders: - namespace: bookinfo - - name: resource-usage - namespace: kobs - title: Resource Usage - placeholders: - namespace: bookinfo - pod: ".*" + - cluster: "{% .__cluster %}" + namespace: "{% .__namespace %}" + name: resources + namespace: kobs + title: Resources in the bookinfo namespace + placeholders: + namespace: bookinfo + - cluster: "{% .__cluster %}" + namespace: "{% .__namespace %}" + name: resource-usage + namespace: kobs + title: Resource Usage + placeholders: + namespace: bookinfo + pod: ".*" ``` diff --git a/docs/plugins/elasticsearch.md b/docs/plugins/elasticsearch.md index 0d7b84a64..63fb3cb6e 100644 --- a/docs/plugins/elasticsearch.md +++ b/docs/plugins/elasticsearch.md @@ -70,7 +70,7 @@ spec: showChart: true queries: - name: Istio Logs - query: "kubernetes.namespace: {{ .namespace }} AND kubernetes.labels.app: {{ .app }} AND kubernetes.container.name: istio-proxy AND _exists_: content.method" + query: "kubernetes.namespace: {% .namespace %} AND kubernetes.labels.app: {% .app %} AND kubernetes.container.name: istio-proxy AND _exists_: content.method" fields: - "kubernetes.pod.name" - "content.authority" diff --git a/docs/plugins/flux.md b/docs/plugins/flux.md index 5c8defe1a..160c88171 100644 --- a/docs/plugins/flux.md +++ b/docs/plugins/flux.md @@ -11,11 +11,11 @@ The following options can be used for a panel with the Flux plugin: | Field | Type | Description | Required | | ----- | ---- | ----------- | -------- | | type | string | The Flux resource which should be displayed. This must be `gitrepositories.source.toolkit.fluxcd.io/v1beta1`, `helmrepositories.source.toolkit.fluxcd.io/v1beta1`, `buckets.source.toolkit.fluxcd.io/v1beta1`, `kustomizations.kustomize.toolkit.fluxcd.io/v1beta1` or `helmreleases.helm.toolkit.fluxcd.io/v2beta1`. | Yes | -| cluster | string | The cluster for which the resources should be displayed. If this is empty the cluster from the Application or Team, where the dashboard is used will be used. | No | -| namespace | string | The namespace for which the resources should be displayed. If this is empty the resources will from all namespaces will be displayed. | No | +| cluster | string | The cluster for which the resources should be displayed. | Yes | +| namespace | string | The namespace for which the resources should be displayed. | Yes | | selector | string | An optional selector for the selection of Flux resources. | No | -For example the following dashboard shows all Kustomizations, Helm Releases, Git Repositories and Helm Repositories: +For example the following dashboard shows all Kustomizations, Helm Releases, Git Repositories and Helm Repositories from the cluster and namespace, where the dashboard is used as reference: ```yaml --- @@ -30,6 +30,8 @@ spec: name: flux options: type: kustomizations.kustomize.toolkit.fluxcd.io/v1beta1 + cluster: "{% .__cluster %}" + namespace: "{% .__namespace %}" - size: -1 panels: - title: Helm Releases @@ -37,6 +39,8 @@ spec: name: flux options: type: helmreleases.helm.toolkit.fluxcd.io/v2beta1 + cluster: "{% .__cluster %}" + namespace: "{% .__namespace %}" - size: -1 panels: - title: Git Repositories @@ -44,6 +48,8 @@ spec: name: flux options: type: gitrepositories.source.toolkit.fluxcd.io/v1beta1 + cluster: "{% .__cluster %}" + namespace: "{% .__namespace %}" - size: -1 panels: - title: Helm Repositories @@ -51,4 +57,6 @@ spec: name: flux options: type: helmrepositories.source.toolkit.fluxcd.io/v1beta1 + cluster: "{% .__cluster %}" + namespace: "{% .__namespace %}" ``` diff --git a/docs/plugins/helm.md b/docs/plugins/helm.md index bf6ce328c..535665df2 100644 --- a/docs/plugins/helm.md +++ b/docs/plugins/helm.md @@ -21,8 +21,8 @@ The following options can be used for a panel with the Helm plugin: | Field | Type | Description | Required | | ----- | ---- | ----------- | -------- | | type | string | The panel type. This could be `releases` or `releasehistory`. | Yes | -| clusters | []string | A list of cluster for which the Helm releases should be shown. If this is empty the cluster from the team / application is used. | No | -| namespaces |[]string | A list of namespaces for which the Helm releases should be shown. If this is empty the namespace from the team / application is used. | No | +| clusters | []string | A list of cluster for which the Helm releases should be shown. | Yes | +| namespaces |[]string | A list of namespaces for which the Helm releases should be shown. | Yes | | name | string | The name of the Helm release for whih the history should be shown, when the type is `releasehistory`. | No | ## Example @@ -41,6 +41,8 @@ spec: name: helm options: type: releases + clusters: + - "{% .__cluster %}" namespaces: - kobs - cert-manager @@ -53,6 +55,8 @@ spec: name: helm options: type: releasehistory + clusters: + - "{% .__cluster %}" namespaces: - kobs name: kobs @@ -62,6 +66,8 @@ spec: name: helm options: type: releasehistory + clusters: + - "{% .__cluster %}" namespaces: - cert-manager name: cert-manager @@ -71,6 +77,8 @@ spec: name: helm options: type: releasehistory + clusters: + - "{% .__cluster %}" namespaces: - monitoring name: prometheus-operator diff --git a/docs/plugins/jaeger.md b/docs/plugins/jaeger.md index 43af60de0..ca3414733 100644 --- a/docs/plugins/jaeger.md +++ b/docs/plugins/jaeger.md @@ -73,9 +73,9 @@ spec: options: showChart: true queries: - - name: "{{ .service }} requests" - service: "{{ .service }}" - - name: "{{ .service }} slow requests" - service: "{{ .service }}" + - name: "{% .service %} requests" + service: "{% .service %}" + - name: "{% .service %} slow requests" + service: "{% .service %}" minDuration: 1000ms ``` diff --git a/docs/plugins/markdown.md b/docs/plugins/markdown.md index db1b5fd3d..4ab32b062 100644 --- a/docs/plugins/markdown.md +++ b/docs/plugins/markdown.md @@ -48,7 +48,7 @@ spec: ![Bookinfo Application without Istio](https://istio.io/latest/docs/examples/bookinfo/noistio.svg) This application is polyglot, i.e., the microservices are written in different languages. - It’s worth noting that these services have no dependencies on Istio, but make an interesting + It's worth noting that these services have no dependencies on Istio, but make an interesting service mesh example, particularly because of the multitude of services, languages and versions for the `reviews` service. ``` diff --git a/docs/plugins/prometheus.md b/docs/plugins/prometheus.md index 1e00c551f..6aeaaa90f 100644 --- a/docs/plugins/prometheus.md +++ b/docs/plugins/prometheus.md @@ -107,7 +107,7 @@ spec: options: type: labelValues label: pod - query: container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{{ .pod }}", container!="POD", container!=""} + query: container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .pod %}", container!="POD", container!=""} allowAll: false rows: - size: 1 @@ -120,7 +120,7 @@ spec: type: sparkline unit: Cores queries: - - query: sum(rate(container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) + - query: sum(rate(container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) - title: Memory Usage colSpan: 4 plugin: @@ -129,7 +129,7 @@ spec: type: sparkline unit: MiB queries: - - query: sum(container_memory_working_set_bytes{namespace="{{ .namespace }}", pod=~"{% .var_pod %}", container!="POD", container!=""}) / 1024 / 1024 + - query: sum(container_memory_working_set_bytes{namespace="{% .namespace %}", pod=~"{% .var_pod %}", container!="POD", container!=""}) / 1024 / 1024 - title: Restarts colSpan: 4 plugin: @@ -137,7 +137,7 @@ spec: options: type: sparkline queries: - - query: kube_pod_container_status_restarts_total{namespace="{{ .namespace }}", pod=~"{% .var_pod %}"} + - query: kube_pod_container_status_restarts_total{namespace="{% .namespace %}", pod=~"{% .var_pod %}"} - size: 3 panels: - title: CPU Usage @@ -150,11 +150,11 @@ spec: legend: table queries: - label: "Usage: {% .container %}" - query: sum(rate(container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) by (container) + query: sum(rate(container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) by (container) - label: "Request: {% .container %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) - label: "Limits: {% .container %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) - title: Memory Usage colSpan: 6 plugin: @@ -165,11 +165,11 @@ spec: legend: table queries: - label: "Usage: {% .container %}" - query: sum(container_memory_working_set_bytes{namespace="{{ .namespace }}", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 + query: sum(container_memory_working_set_bytes{namespace="{% .namespace %}", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 - label: "Request: {% .container %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 - label: "Limits: {% .container %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 - title: Network size: 3 panels: @@ -182,9 +182,9 @@ spec: unit: bytes/s queries: - label: Received - query: sum(irate(container_network_receive_bytes_total{namespace="{{ .namespace }}", pod="{% .var_pod %}"}[2m])) by (pod) + query: sum(irate(container_network_receive_bytes_total{namespace="{% .namespace %}", pod="{% .var_pod %}"}[2m])) by (pod) - label: Transmitted - query: -sum(irate(container_network_transmit_bytes_total{namespace="{{ .namespace }}", pod="{% .var_pod %}"}[2m])) by (pod) + query: -sum(irate(container_network_transmit_bytes_total{namespace="{% .namespace %}", pod="{% .var_pod %}"}[2m])) by (pod) - title: Rate of Packets colSpan: 6 plugin: @@ -194,9 +194,9 @@ spec: unit: bytes/s queries: - label: Received - query: sum(irate(container_network_receive_packets_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: sum(irate(container_network_receive_packets_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - label: Transmitted - query: -sum(irate(container_network_transmit_packets_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: -sum(irate(container_network_transmit_packets_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - title: Rate of Packets Dropped colSpan: 6 plugin: @@ -206,9 +206,9 @@ spec: unit: bytes/s queries: - label: Received - query: sum(irate(container_network_receive_packets_dropped_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: sum(irate(container_network_receive_packets_dropped_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - label: Transmitted - query: -sum(irate(container_network_transmit_packets_dropped_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: -sum(irate(container_network_transmit_packets_dropped_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - title: "Resource Usage for all Pods" panels: - title: Table @@ -218,17 +218,17 @@ spec: type: table queries: - label: "{% .pod %}" - query: sum(rate(container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{{ .pod }}", container!="POD", container!=""}[2m])) by (pod) + query: sum(rate(container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .pod %}", container!="POD", container!=""}[2m])) by (pod) - label: "{% .pod %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="cpu", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="cpu", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) - label: "{% .pod %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="cpu", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="cpu", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) - label: "{% .pod %}" - query: sum(container_memory_working_set_bytes{namespace="{{ .namespace }}", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) / 1024 / 1024 + query: sum(container_memory_working_set_bytes{namespace="{% .namespace %}", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) / 1024 / 1024 - label: "{% .pod %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="memory", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) / 1024 / 1024 + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="memory", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) / 1024 / 1024 - label: "{% .pod %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="memory", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) / 1024 / 1024 + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="memory", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) / 1024 / 1024 columns: - name: pod title: Pod diff --git a/docs/plugins/resources.md b/docs/plugins/resources.md index 52a6b4a0f..cf890af3b 100644 --- a/docs/plugins/resources.md +++ b/docs/plugins/resources.md @@ -27,8 +27,8 @@ plugins: | Field | Type | Description | Required | | ----- | ---- | ----------- | -------- | -| clusters | []string | A list of clusters. If this value isn't provided, it will be the cluster from the team or application where the dashboard is used. | No | -| namespaces | []string | A list of namespaces. If this value isn't provided, it will be the namespace from the team or application where the dashboard is used. | No | +| clusters | []string | A list of clusters. | Yes | +| namespaces | []string | A list of namespaces. | Yes | | resources | []string | A list of resources. | Yes | | selector | string | An optional selector for the selection of resources | No | @@ -52,7 +52,9 @@ spec: plugin: name: resources options: - - namespaces: + - clusters: + - "{% .__cluster %}" + namespaces: - bookinfo resources: - pods diff --git a/docs/plugins/users.md b/docs/plugins/users.md index ab8de74b0..989ace50c 100644 --- a/docs/plugins/users.md +++ b/docs/plugins/users.md @@ -6,8 +6,8 @@ The users plugin can be used to show a list of users which are members of the sp | Field | Type | Description | Required | | ----- | ---- | ----------- | -------- | -| clusters | string | The cluster name of the team. | No | -| namespaces | string | The namespace of the team | No | +| cluster | string | The cluster name of the team. | Yes | +| namespace | string | The namespace of the team | Yes | | name | string | The name of the team. | Yes | ## Example @@ -30,5 +30,7 @@ spec: plugin: name: users options: + cluster: "{% .__cluster %}" + namespace: kobs name: team-diablo ``` diff --git a/docs/resources/dashboards.md b/docs/resources/dashboards.md index bd82e3e8d..54dedeb19 100644 --- a/docs/resources/dashboards.md +++ b/docs/resources/dashboards.md @@ -25,13 +25,13 @@ In the following you can found the specification for the Dashboard CRD. On the b ### Placeholder -Placeholders are providing a way to use custom values in the dashboard. The value for a placeholder must be set by the user in the dashboards reference of a [Team](./teams#dashboard) or an [Applications](./applications#dashboard). +Placeholders are similar to variables with the difference that they must be set when the dashboard is referenced in a [Team](./teams#dashboard) or an [Applications](./applications#dashboard). -The value of a placeholder can be used via the following templating string: `{{ . }}`. This string is then replaced with the provided value when the dashboard is loaded. +The value of a placeholder can be used via the following templating string: `{% . %}`. This string is then replaced with the provided value when the dashboard is loaded. | Field | Type | Description | Required | | ----- | ---- | ----------- | -------- | -| name | string | The name for the placeholder, which can be used in the dashboard via `{{ . }}`. | Yes | +| name | string | The name for the placeholder, which can be used in the dashboard via `{% . %}`. | Yes | | description | string | An optional description, to provide more information how the placeholder is used. | No | ### Variable @@ -48,16 +48,16 @@ Variables can be used to select between different values in the dashboard. To us !!! note Dashboards are also supporting some special variables, which always can be used and must not be defined by a users. These variables are: - - `__timeStart`: The start time of the selected time range in seconds. - - `__timeEnd`: The end time of the selected time range in seconds. - - These variables can then be used via `{{ .__timeStart }}` and `{{ .__timeEnd }}` in the dashboard. + - `__cluster`: The cluster from the Application / Team were the dashboard is used. This variable can be used via `{% .__cluster %}` in a dashboard. + - `__namespace`: The cluster from the Application / Team were the dashboard is used. This variable can be used via `{% .__namespace %}` in a dashboard. + - `__timeStart`: The start time of the selected time range in seconds. This variable can be used via `{% .__timeStart %}` in a dashboard. + - `__timeEnd`: The end time of the selected time range in seconds. This variable can be used via `{% .__timeEnd %}` in a dashboard. ### Variable Plugin | Field | Type | Description | Required | | ----- | ---- | ----------- | -------- | -| name | string | The name of the plugin, this must be `core` or the name of an configured Prometheus instance. | Yes | +| name | string | The name of the plugin, this must be `core` or the name of an configured Plugin which supports variables (e.g. Prometheus). | Yes | | options | [Variable Plugin Options](#variable-plugin-options) | Plugin specific options to retrieve the values for the variable. | Yes | ### Variable Plugin Options @@ -156,7 +156,7 @@ spec: options: type: labelValues label: pod - query: container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{{ .pod }}", container!="POD", container!=""} + query: container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .pod %}", container!="POD", container!=""} allowAll: false rows: - size: 1 @@ -169,7 +169,7 @@ spec: type: sparkline unit: Cores queries: - - query: sum(rate(container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) + - query: sum(rate(container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) - title: Memory Usage colSpan: 4 plugin: @@ -178,7 +178,7 @@ spec: type: sparkline unit: MiB queries: - - query: sum(container_memory_working_set_bytes{namespace="{{ .namespace }}", pod=~"{% .var_pod %}", container!="POD", container!=""}) / 1024 / 1024 + - query: sum(container_memory_working_set_bytes{namespace="{% .namespace %}", pod=~"{% .var_pod %}", container!="POD", container!=""}) / 1024 / 1024 - title: Restarts colSpan: 4 plugin: @@ -186,7 +186,7 @@ spec: options: type: sparkline queries: - - query: kube_pod_container_status_restarts_total{namespace="{{ .namespace }}", pod=~"{% .var_pod %}"} + - query: kube_pod_container_status_restarts_total{namespace="{% .namespace %}", pod=~"{% .var_pod %}"} - size: 3 panels: - title: CPU Usage @@ -199,11 +199,11 @@ spec: legend: table queries: - label: "Usage: {% .container %}" - query: sum(rate(container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) by (container) + query: sum(rate(container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .var_pod %}", container!="POD", container!=""}[2m])) by (container) - label: "Request: {% .container %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) - label: "Limits: {% .container %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="cpu", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) - title: Memory Usage colSpan: 6 plugin: @@ -214,11 +214,11 @@ spec: legend: table queries: - label: "Usage: {% .container %}" - query: sum(container_memory_working_set_bytes{namespace="{{ .namespace }}", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 + query: sum(container_memory_working_set_bytes{namespace="{% .namespace %}", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 - label: "Request: {% .container %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 - label: "Limits: {% .container %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="memory", pod=~"{% .var_pod %}", container!="POD", container!=""}) by (container) / 1024 / 1024 - title: Network size: 3 panels: @@ -231,9 +231,9 @@ spec: unit: bytes/s queries: - label: Received - query: sum(irate(container_network_receive_bytes_total{namespace="{{ .namespace }}", pod="{% .var_pod %}"}[2m])) by (pod) + query: sum(irate(container_network_receive_bytes_total{namespace="{% .namespace %}", pod="{% .var_pod %}"}[2m])) by (pod) - label: Transmitted - query: -sum(irate(container_network_transmit_bytes_total{namespace="{{ .namespace }}", pod="{% .var_pod %}"}[2m])) by (pod) + query: -sum(irate(container_network_transmit_bytes_total{namespace="{% .namespace %}", pod="{% .var_pod %}"}[2m])) by (pod) - title: Rate of Packets colSpan: 6 plugin: @@ -243,9 +243,9 @@ spec: unit: bytes/s queries: - label: Received - query: sum(irate(container_network_receive_packets_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: sum(irate(container_network_receive_packets_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - label: Transmitted - query: -sum(irate(container_network_transmit_packets_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: -sum(irate(container_network_transmit_packets_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - title: Rate of Packets Dropped colSpan: 6 plugin: @@ -255,9 +255,9 @@ spec: unit: bytes/s queries: - label: Received - query: sum(irate(container_network_receive_packets_dropped_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: sum(irate(container_network_receive_packets_dropped_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - label: Transmitted - query: -sum(irate(container_network_transmit_packets_dropped_total{namespace=~"{{ .namespace }}", pod=~"{% .var_pod %}"}[2m])) by (pod) + query: -sum(irate(container_network_transmit_packets_dropped_total{namespace=~"{% .namespace %}", pod=~"{% .var_pod %}"}[2m])) by (pod) - title: "Resource Usage for all Pods" panels: - title: Table @@ -267,17 +267,17 @@ spec: type: table queries: - label: "{% .pod %}" - query: sum(rate(container_cpu_usage_seconds_total{namespace="{{ .namespace }}", image!="", pod=~"{{ .pod }}", container!="POD", container!=""}[2m])) by (pod) + query: sum(rate(container_cpu_usage_seconds_total{namespace="{% .namespace %}", image!="", pod=~"{% .pod %}", container!="POD", container!=""}[2m])) by (pod) - label: "{% .pod %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="cpu", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="cpu", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) - label: "{% .pod %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="cpu", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="cpu", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) - label: "{% .pod %}" - query: sum(container_memory_working_set_bytes{namespace="{{ .namespace }}", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) / 1024 / 1024 + query: sum(container_memory_working_set_bytes{namespace="{% .namespace %}", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) / 1024 / 1024 - label: "{% .pod %}" - query: sum(kube_pod_container_resource_requests{namespace="{{ .namespace }}", resource="memory", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) / 1024 / 1024 + query: sum(kube_pod_container_resource_requests{namespace="{% .namespace %}", resource="memory", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) / 1024 / 1024 - label: "{% .pod %}" - query: sum(kube_pod_container_resource_limits{namespace="{{ .namespace }}", resource="memory", pod=~"{{ .pod }}", container!="POD", container!=""}) by (pod) / 1024 / 1024 + query: sum(kube_pod_container_resource_limits{namespace="{% .namespace %}", resource="memory", pod=~"{% .pod %}", container!="POD", container!=""}) by (pod) / 1024 / 1024 columns: - name: pod title: Pod diff --git a/pkg/api/clusters/cluster/cluster.go b/pkg/api/clusters/cluster/cluster.go index cd2286288..3dfd7b59c 100644 --- a/pkg/api/clusters/cluster/cluster.go +++ b/pkg/api/clusters/cluster/cluster.go @@ -403,15 +403,7 @@ func (c *client) GetApplications(ctx context.Context, namespace string) ([]appli var applications []application.ApplicationSpec for _, applicationItem := range applicationsList.Items { - application := applicationItem.Spec - application.Cluster = c.name - application.Namespace = applicationItem.Namespace - application.Name = applicationItem.Name - - if application.Topology.Type == "" { - application.Topology.Type = "application" - } - + application := setApplicationDefaults(applicationItem.Spec, c.name, applicationItem.Namespace, applicationItem.Name) applications = append(applications, application) } @@ -422,20 +414,12 @@ func (c *client) GetApplications(ctx context.Context, namespace string) ([]appli // the cluster, namespace and name in the spec of the Application CR. This is needed, so that the user doesn't have to, // provide these fields. func (c *client) GetApplication(ctx context.Context, namespace, name string) (*application.ApplicationSpec, error) { - applicationCR, err := c.applicationClientset.KobsV1beta1().Applications(namespace).Get(ctx, name, metav1.GetOptions{}) + teamItem, err := c.applicationClientset.KobsV1beta1().Applications(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return nil, err } - application := applicationCR.Spec - application.Cluster = c.name - application.Namespace = namespace - application.Name = name - - if application.Topology.Type == "" { - application.Topology.Type = "application" - } - + application := setApplicationDefaults(teamItem.Spec, c.name, namespace, name) return &application, nil } @@ -450,11 +434,7 @@ func (c *client) GetTeams(ctx context.Context, namespace string) ([]team.TeamSpe var teams []team.TeamSpec for _, teamItem := range teamsList.Items { - team := teamItem.Spec - team.Cluster = c.name - team.Namespace = teamItem.Namespace - team.Name = teamItem.Name - + team := setTeamDefaults(teamItem.Spec, c.name, teamItem.Namespace, teamItem.Name) teams = append(teams, team) } @@ -465,16 +445,12 @@ func (c *client) GetTeams(ctx context.Context, namespace string) ([]team.TeamSpe // namespace and name in the spec of the Team CR. This is needed, so that the user doesn't have to, provide these // fields. func (c *client) GetTeam(ctx context.Context, namespace, name string) (*team.TeamSpec, error) { - teamCR, err := c.teamClientset.KobsV1beta1().Teams(namespace).Get(ctx, name, metav1.GetOptions{}) + teamItem, err := c.teamClientset.KobsV1beta1().Teams(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return nil, err } - team := teamCR.Spec - team.Cluster = c.name - team.Namespace = namespace - team.Name = name - + team := setTeamDefaults(teamItem.Spec, c.name, namespace, name) return &team, nil } @@ -489,12 +465,7 @@ func (c *client) GetDashboards(ctx context.Context, namespace string) ([]dashboa var dashboards []dashboard.DashboardSpec for _, dashboardItem := range dashboardsList.Items { - dashboard := dashboardItem.Spec - dashboard.Cluster = c.name - dashboard.Namespace = dashboardItem.Namespace - dashboard.Name = dashboardItem.Name - dashboard.Title = dashboardItem.Name - + dashboard := setDashboardDefaults(dashboardItem.Spec, c.name, dashboardItem.Namespace, dashboardItem.Name) dashboards = append(dashboards, dashboard) } @@ -505,17 +476,12 @@ func (c *client) GetDashboards(ctx context.Context, namespace string) ([]dashboa // the cluster, namespace and name in the spec of the Dashboard CR. This is needed, so that the user doesn't have to, // provide these fields. func (c *client) GetDashboard(ctx context.Context, namespace, name string) (*dashboard.DashboardSpec, error) { - dashboardCR, err := c.dashboardClientset.KobsV1beta1().Dashboards(namespace).Get(ctx, name, metav1.GetOptions{}) + dashboardItem, err := c.dashboardClientset.KobsV1beta1().Dashboards(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return nil, err } - dashboard := dashboardCR.Spec - dashboard.Cluster = c.name - dashboard.Namespace = namespace - dashboard.Name = name - dashboard.Title = name - + dashboard := setDashboardDefaults(dashboardItem.Spec, c.name, namespace, name) return &dashboard, nil } @@ -530,11 +496,7 @@ func (c *client) GetUsers(ctx context.Context, namespace string) ([]user.UserSpe var users []user.UserSpec for _, userItem := range usersList.Items { - user := userItem.Spec - user.Cluster = c.name - user.Namespace = userItem.Namespace - user.Name = userItem.Name - + user := setUserDefaults(userItem.Spec, c.name, userItem.Namespace, userItem.Name) users = append(users, user) } @@ -545,16 +507,12 @@ func (c *client) GetUsers(ctx context.Context, namespace string) ([]user.UserSpe // namespace and name in the spec of the User CR. This is needed, so that the user doesn't have to, provide these // fields. func (c *client) GetUser(ctx context.Context, namespace, name string) (*user.UserSpec, error) { - userCR, err := c.userClientset.KobsV1beta1().Users(namespace).Get(ctx, name, metav1.GetOptions{}) + userItem, err := c.userClientset.KobsV1beta1().Users(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return nil, err } - user := userCR.Spec - user.Cluster = c.name - user.Namespace = namespace - user.Name = name - + user := setUserDefaults(userItem.Spec, c.name, namespace, name) return &user, nil } diff --git a/pkg/api/clusters/cluster/defaults.go b/pkg/api/clusters/cluster/defaults.go new file mode 100644 index 000000000..60bd9ccb1 --- /dev/null +++ b/pkg/api/clusters/cluster/defaults.go @@ -0,0 +1,99 @@ +package cluster + +import ( + application "github.com/kobsio/kobs/pkg/api/apis/application/v1beta1" + dashboard "github.com/kobsio/kobs/pkg/api/apis/dashboard/v1beta1" + team "github.com/kobsio/kobs/pkg/api/apis/team/v1beta1" + user "github.com/kobsio/kobs/pkg/api/apis/user/v1beta1" +) + +func setApplicationDefaults(application application.ApplicationSpec, cluster, namespace, name string) application.ApplicationSpec { + application.Cluster = cluster + application.Namespace = namespace + application.Name = name + + if application.Topology.Type == "" { + application.Topology.Type = "application" + } + + for i := 0; i < len(application.Teams); i++ { + if application.Teams[i].Cluster == "" { + application.Teams[i].Cluster = application.Cluster + } + if application.Teams[i].Namespace == "" { + application.Teams[i].Namespace = application.Namespace + } + } + + for i := 0; i < len(application.Topology.Dependencies); i++ { + if application.Topology.Dependencies[i].Cluster == "" { + application.Topology.Dependencies[i].Cluster = application.Cluster + } + if application.Topology.Dependencies[i].Namespace == "" { + application.Topology.Dependencies[i].Namespace = application.Namespace + } + + for j := 0; j < len(application.Topology.Dependencies[i].Dashboards); j++ { + if application.Topology.Dependencies[i].Dashboards[j].Cluster == "" { + application.Topology.Dependencies[i].Dashboards[j].Cluster = application.Cluster + } + if application.Topology.Dependencies[i].Dashboards[j].Namespace == "" { + application.Topology.Dependencies[i].Dashboards[j].Namespace = application.Namespace + } + } + } + + for i := 0; i < len(application.Dashboards); i++ { + if application.Dashboards[i].Cluster == "" { + application.Dashboards[i].Cluster = application.Cluster + } + if application.Dashboards[i].Namespace == "" { + application.Dashboards[i].Namespace = application.Namespace + } + } + + return application +} + +func setTeamDefaults(team team.TeamSpec, cluster, namespace, name string) team.TeamSpec { + team.Cluster = cluster + team.Namespace = namespace + team.Name = name + + for i := 0; i < len(team.Dashboards); i++ { + if team.Dashboards[i].Cluster == "" { + team.Dashboards[i].Cluster = team.Cluster + } + if team.Dashboards[i].Namespace == "" { + team.Dashboards[i].Namespace = team.Namespace + } + } + + return team +} + +func setDashboardDefaults(dashboard dashboard.DashboardSpec, cluster, namespace, name string) dashboard.DashboardSpec { + dashboard.Cluster = cluster + dashboard.Namespace = namespace + dashboard.Name = name + dashboard.Title = name + + return dashboard +} + +func setUserDefaults(user user.UserSpec, cluster, namespace, name string) user.UserSpec { + user.Cluster = cluster + user.Namespace = namespace + user.Name = name + + for i := 0; i < len(user.Teams); i++ { + if user.Teams[i].Cluster == "" { + user.Teams[i].Cluster = user.Cluster + } + if user.Teams[i].Namespace == "" { + user.Teams[i].Namespace = user.Namespace + } + } + + return user +} diff --git a/pkg/api/clusters/cluster/defaults_test.go b/pkg/api/clusters/cluster/defaults_test.go new file mode 100644 index 000000000..562928478 --- /dev/null +++ b/pkg/api/clusters/cluster/defaults_test.go @@ -0,0 +1,160 @@ +package cluster + +import ( + "testing" + + application "github.com/kobsio/kobs/pkg/api/apis/application/v1beta1" + dashboard "github.com/kobsio/kobs/pkg/api/apis/dashboard/v1beta1" + team "github.com/kobsio/kobs/pkg/api/apis/team/v1beta1" + user "github.com/kobsio/kobs/pkg/api/apis/user/v1beta1" + + "github.com/stretchr/testify/require" +) + +func TestSetApplicationDefaults(t *testing.T) { + require.Equal( + t, + application.ApplicationSpec{ + Cluster: "cluster1", + Namespace: "namespace1", + Name: "application1", + Teams: []application.TeamReference{ + {Cluster: "cluster1", Namespace: "namespace1", Name: "team1"}, + {Cluster: "cluster2", Namespace: "namespace1", Name: "team2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "team3"}, + }, + Topology: application.Topology{ + Type: "application", + Dependencies: []application.Dependency{ + {Cluster: "cluster1", Namespace: "namespace1", Name: "application2"}, + {Cluster: "cluster2", Namespace: "namespace1", Name: "application3"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "application4", Dashboards: []dashboard.Reference{ + {Cluster: "cluster1", Namespace: "namespace1", Name: "dashboard1"}, + {Cluster: "cluster2", Namespace: "namespace1", Name: "dashboard2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "dashboard3"}, + }}, + }, + }, + Dashboards: []dashboard.Reference{ + {Cluster: "cluster1", Namespace: "namespace1", Name: "dashboard1"}, + {Cluster: "cluster2", Namespace: "namespace1", Name: "dashboard2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "dashboard3"}, + }, + }, + setApplicationDefaults( + application.ApplicationSpec{ + Cluster: "", + Namespace: "", + Name: "", + Teams: []application.TeamReference{ + {Cluster: "", Namespace: "", Name: "team1"}, + {Cluster: "cluster2", Namespace: "", Name: "team2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "team3"}, + }, + Topology: application.Topology{ + Dependencies: []application.Dependency{ + {Cluster: "", Namespace: "", Name: "application2"}, + {Cluster: "cluster2", Namespace: "", Name: "application3"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "application4", Dashboards: []dashboard.Reference{ + {Cluster: "", Namespace: "", Name: "dashboard1"}, + {Cluster: "cluster2", Namespace: "", Name: "dashboard2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "dashboard3"}, + }}, + }, + }, + Dashboards: []dashboard.Reference{ + {Cluster: "", Namespace: "", Name: "dashboard1"}, + {Cluster: "cluster2", Namespace: "", Name: "dashboard2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "dashboard3"}, + }, + }, + "cluster1", + "namespace1", + "application1", + ), + ) +} + +func TestSetTeamDefaults(t *testing.T) { + require.Equal( + t, + team.TeamSpec{ + Cluster: "cluster1", + Namespace: "namespace1", + Name: "team1", + Dashboards: []dashboard.Reference{ + {Cluster: "cluster1", Namespace: "namespace1", Name: "dashboard1"}, + {Cluster: "cluster2", Namespace: "namespace1", Name: "dashboard2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "dashboard3"}, + }, + }, + setTeamDefaults( + team.TeamSpec{ + Cluster: "", + Namespace: "", + Name: "", + Dashboards: []dashboard.Reference{ + {Cluster: "", Namespace: "", Name: "dashboard1"}, + {Cluster: "cluster2", Namespace: "", Name: "dashboard2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "dashboard3"}, + }, + }, + "cluster1", + "namespace1", + "team1", + ), + ) +} + +func TestSetDashboardDefaults(t *testing.T) { + require.Equal( + t, + dashboard.DashboardSpec{ + Cluster: "cluster1", + Namespace: "namespace1", + Name: "dashboard1", + Title: "dashboard1", + }, + setDashboardDefaults( + dashboard.DashboardSpec{ + Cluster: "", + Namespace: "", + Name: "", + }, + "cluster1", + "namespace1", + "dashboard1", + ), + ) +} + +func TestSetUserDefaults(t *testing.T) { + require.Equal( + t, + user.UserSpec{ + Cluster: "cluster1", + Namespace: "namespace1", + Name: "user1", + Teams: []user.TeamReference{ + {Cluster: "cluster1", Namespace: "namespace1", Name: "team1"}, + {Cluster: "cluster2", Namespace: "namespace1", Name: "team2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "team3"}, + }, + }, + setUserDefaults( + user.UserSpec{ + Cluster: "", + Namespace: "", + Name: "", + Teams: []user.TeamReference{ + {Cluster: "", Namespace: "", Name: "team1"}, + {Cluster: "cluster2", Namespace: "", Name: "team2"}, + {Cluster: "cluster2", Namespace: "namespace2", Name: "team3"}, + }, + }, + "cluster1", + "namespace1", + "user1", + ), + ) +} diff --git a/plugins/applications/applications_test.go b/plugins/applications/applications_test.go index 38acda766..920b7b3bf 100644 --- a/plugins/applications/applications_test.go +++ b/plugins/applications/applications_test.go @@ -144,7 +144,7 @@ func TestGetApplications(t *testing.T) { topologyCache: topology.Cache{Topology: &topology.Topology{Edges: nil, Nodes: nil}}, url: "/applications?view=topology&cluster=cluster1&namespace=namespace2", expectedStatusCode: http.StatusOK, - expectedBody: "{\"edges\":[{\"data\":{\"id\":\"cluster1-namespace1-application2-cluster1-namespace2-application3\",\"source\":\"cluster1-namespace1-application2\",\"target\":\"cluster1-namespace2-application3\",\"description\":\"\",\"dashboards\":null}},{\"data\":{\"id\":\"cluster1-namespace2-application3-cluster2-namespace3-application4\",\"source\":\"cluster1-namespace2-application3\",\"target\":\"cluster2-namespace3-application4\",\"description\":\"\",\"dashboards\":null}},{\"data\":{\"id\":\"cluster1-namespace2-application3-cluster2-namespace3-application5\",\"source\":\"cluster1-namespace2-application3\",\"target\":\"cluster2-namespace3-application5\",\"description\":\"\",\"dashboards\":null}}],\"nodes\":[{\"data\":{\"id\":\"cluster1-namespace1-application2\",\"type\":\"-not-selected\",\"label\":\"application2\",\"parent\":\"cluster1-namespace1\",\"cluster\":\"cluster1\",\"namespace\":\"namespace1\",\"name\":\"application2\",\"topology\":{\"dependencies\":[{\"namespace\":\"namespace2\",\"name\":\"application3\"}]}}},{\"data\":{\"id\":\"cluster1-namespace2-application3\",\"type\":\"\",\"label\":\"application3\",\"parent\":\"cluster1-namespace2\",\"cluster\":\"cluster1\",\"namespace\":\"namespace2\",\"name\":\"application3\",\"topology\":{\"dependencies\":[{\"cluster\":\"cluster2\",\"namespace\":\"namespace3\",\"name\":\"application4\"},{\"cluster\":\"cluster2\",\"namespace\":\"namespace3\",\"name\":\"application5\"}]}}},{\"data\":{\"id\":\"cluster2-namespace3-application4\",\"type\":\"-not-selected\",\"label\":\"application4\",\"parent\":\"cluster2-namespace3\",\"cluster\":\"cluster2\",\"namespace\":\"namespace3\",\"name\":\"application4\",\"topology\":{}}},{\"data\":{\"id\":\"cluster2-namespace3-application5\",\"type\":\"-not-selected\",\"label\":\"application5\",\"parent\":\"cluster2-namespace3\",\"cluster\":\"cluster2\",\"namespace\":\"namespace3\",\"name\":\"application5\",\"topology\":{}}},{\"data\":{\"id\":\"cluster1\",\"type\":\"cluster\",\"label\":\"cluster1\",\"parent\":\"\",\"topology\":{}}},{\"data\":{\"id\":\"cluster2\",\"type\":\"cluster\",\"label\":\"cluster2\",\"parent\":\"\",\"topology\":{}}},{\"data\":{\"id\":\"cluster1-namespace1\",\"type\":\"namespace\",\"label\":\"namespace1\",\"parent\":\"cluster1\",\"topology\":{}}},{\"data\":{\"id\":\"cluster1-namespace2\",\"type\":\"namespace\",\"label\":\"namespace2\",\"parent\":\"cluster1\",\"topology\":{}}},{\"data\":{\"id\":\"cluster1-namespace2\",\"type\":\"namespace\",\"label\":\"namespace2\",\"parent\":\"cluster1\",\"topology\":{}}},{\"data\":{\"id\":\"cluster2-namespace3\",\"type\":\"namespace\",\"label\":\"namespace3\",\"parent\":\"cluster2\",\"topology\":{}}},{\"data\":{\"id\":\"cluster1-namespace2\",\"type\":\"namespace\",\"label\":\"namespace2\",\"parent\":\"cluster1\",\"topology\":{}}},{\"data\":{\"id\":\"cluster2-namespace3\",\"type\":\"namespace\",\"label\":\"namespace3\",\"parent\":\"cluster2\",\"topology\":{}}}]}\n", + expectedBody: "{\"edges\":[{\"data\":{\"id\":\"cluster1-namespace2-application3-cluster2-namespace3-application4\",\"source\":\"cluster1-namespace2-application3\",\"target\":\"cluster2-namespace3-application4\",\"description\":\"\",\"dashboards\":null}},{\"data\":{\"id\":\"cluster1-namespace2-application3-cluster2-namespace3-application5\",\"source\":\"cluster1-namespace2-application3\",\"target\":\"cluster2-namespace3-application5\",\"description\":\"\",\"dashboards\":null}}],\"nodes\":[{\"data\":{\"id\":\"cluster1-namespace2-application3\",\"type\":\"\",\"label\":\"application3\",\"parent\":\"cluster1-namespace2\",\"cluster\":\"cluster1\",\"namespace\":\"namespace2\",\"name\":\"application3\",\"topology\":{\"dependencies\":[{\"cluster\":\"cluster2\",\"namespace\":\"namespace3\",\"name\":\"application4\"},{\"cluster\":\"cluster2\",\"namespace\":\"namespace3\",\"name\":\"application5\"}]}}},{\"data\":{\"id\":\"cluster2-namespace3-application4\",\"type\":\"-not-selected\",\"label\":\"application4\",\"parent\":\"cluster2-namespace3\",\"cluster\":\"cluster2\",\"namespace\":\"namespace3\",\"name\":\"application4\",\"topology\":{}}},{\"data\":{\"id\":\"cluster2-namespace3-application5\",\"type\":\"-not-selected\",\"label\":\"application5\",\"parent\":\"cluster2-namespace3\",\"cluster\":\"cluster2\",\"namespace\":\"namespace3\",\"name\":\"application5\",\"topology\":{}}},{\"data\":{\"id\":\"cluster1\",\"type\":\"cluster\",\"label\":\"cluster1\",\"parent\":\"\",\"topology\":{}}},{\"data\":{\"id\":\"cluster2\",\"type\":\"cluster\",\"label\":\"cluster2\",\"parent\":\"\",\"topology\":{}}},{\"data\":{\"id\":\"cluster1-namespace2\",\"type\":\"namespace\",\"label\":\"namespace2\",\"parent\":\"cluster1\",\"topology\":{}}},{\"data\":{\"id\":\"cluster2-namespace3\",\"type\":\"namespace\",\"label\":\"namespace3\",\"parent\":\"cluster2\",\"topology\":{}}},{\"data\":{\"id\":\"cluster1-namespace2\",\"type\":\"namespace\",\"label\":\"namespace2\",\"parent\":\"cluster1\",\"topology\":{}}},{\"data\":{\"id\":\"cluster2-namespace3\",\"type\":\"namespace\",\"label\":\"namespace3\",\"parent\":\"cluster2\",\"topology\":{}}}]}\n", prepare: func(mockClusterClient *cluster.MockClient) { mockClusterClient.On("GetApplications", mock.Anything, "").Return([]application.ApplicationSpec{ {Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Topology: application.Topology{Dependencies: []application.Dependency{{Cluster: "", Namespace: "", Name: "application2"}}}}, diff --git a/plugins/applications/pkg/teams/teams.go b/plugins/applications/pkg/teams/teams.go index f4e04fd44..b2bf50df5 100644 --- a/plugins/applications/pkg/teams/teams.go +++ b/plugins/applications/pkg/teams/teams.go @@ -85,14 +85,6 @@ func GetApplications(teams []Team, cluster, namespace, name string) []applicatio // application and the cluster, namespace and name of the team as arguments. func doesApplicationContainsTeam(application application.ApplicationSpec, cluster, namespace, name string) bool { for _, t := range application.Teams { - if t.Cluster == "" { - t.Cluster = application.Cluster - } - - if t.Namespace == "" { - t.Namespace = application.Namespace - } - if t.Cluster == cluster && t.Namespace == namespace && t.Name == name { return true } diff --git a/plugins/applications/pkg/teams/teams_test.go b/plugins/applications/pkg/teams/teams_test.go index eaac5ddb7..d187a82bf 100644 --- a/plugins/applications/pkg/teams/teams_test.go +++ b/plugins/applications/pkg/teams/teams_test.go @@ -61,7 +61,5 @@ func TestGetApplications(t *testing.T) { func TestDoesApplicationContainsTeam(t *testing.T) { require.Equal(t, true, doesApplicationContainsTeam(application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Teams: []application.TeamReference{{Cluster: "cluster1", Namespace: "namespace1", Name: "team1"}}}, "cluster1", "namespace1", "team1")) - require.Equal(t, true, doesApplicationContainsTeam(application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Teams: []application.TeamReference{{Cluster: "", Namespace: "namespace1", Name: "team1"}}}, "cluster1", "namespace1", "team1")) - require.Equal(t, true, doesApplicationContainsTeam(application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Teams: []application.TeamReference{{Cluster: "", Namespace: "", Name: "team1"}}}, "cluster1", "namespace1", "team1")) - require.Equal(t, false, doesApplicationContainsTeam(application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Teams: []application.TeamReference{{Cluster: "", Namespace: "", Name: "team1"}}}, "cluster1", "namespace1", "team2")) + require.Equal(t, false, doesApplicationContainsTeam(application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Teams: []application.TeamReference{{Cluster: "cluster1", Namespace: "namespace1", Name: "team1"}}}, "cluster1", "namespace1", "team2")) } diff --git a/plugins/applications/pkg/topology/topology.go b/plugins/applications/pkg/topology/topology.go index 7c992fef2..dc6c65423 100644 --- a/plugins/applications/pkg/topology/topology.go +++ b/plugins/applications/pkg/topology/topology.go @@ -103,29 +103,17 @@ func Get(ctx context.Context, clustersClient clusters.Client) *Topology { // cluster and namespace to the cluster and namespace of the current application, when it isn't defined in // the dependency reference. for _, dependency := range application.Topology.Dependencies { - dependencyCluster := dependency.Cluster - if dependencyCluster == "" { - dependencyCluster = application.Cluster - } - - dependencyNamespace := dependency.Namespace - if dependencyNamespace == "" { - dependencyNamespace = application.Namespace - } - - dependencyName := dependency.Name - edges = append(edges, Edge{ Data: EdgeData{ - ID: application.Cluster + "-" + application.Namespace + "-" + application.Name + "-" + dependencyCluster + "-" + dependencyNamespace + "-" + dependencyName, + ID: application.Cluster + "-" + application.Namespace + "-" + application.Name + "-" + dependency.Cluster + "-" + dependency.Namespace + "-" + dependency.Name, Source: application.Cluster + "-" + application.Namespace + "-" + application.Name, SourceCluster: application.Cluster, SourceNamespace: application.Namespace, SourceName: application.Name, - Target: dependencyCluster + "-" + dependencyNamespace + "-" + dependencyName, - TargetCluster: dependencyCluster, - TargetNamespace: dependencyNamespace, - TargetName: dependencyName, + Target: dependency.Cluster + "-" + dependency.Namespace + "-" + dependency.Name, + TargetCluster: dependency.Cluster, + TargetNamespace: dependency.Namespace, + TargetName: dependency.Name, Description: dependency.Description, Dashboards: dependency.Dashboards, }, diff --git a/plugins/applications/pkg/topology/topology_test.go b/plugins/applications/pkg/topology/topology_test.go index a3433ecf5..b87654798 100644 --- a/plugins/applications/pkg/topology/topology_test.go +++ b/plugins/applications/pkg/topology/topology_test.go @@ -21,8 +21,8 @@ var expectedGetTopology = Topology{ {Data: EdgeData{ID: "cluster1-namespace2-application3-cluster2-namespace3-application5", Source: "cluster1-namespace2-application3", SourceCluster: "cluster1", SourceNamespace: "namespace2", SourceName: "application3", Target: "cluster2-namespace3-application5", TargetCluster: "cluster2", TargetNamespace: "namespace3", TargetName: "application5"}}, }, Nodes: []Node{ - {Data: NodeData{ID: "cluster1-namespace1-application1", Type: "application", Label: "application1", Parent: "cluster1-namespace1", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "", Namespace: "", Name: "application2"}}}}}}, - {Data: NodeData{ID: "cluster1-namespace1-application2", Type: "application", Label: "application2", Parent: "cluster1-namespace1", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application2", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "", Namespace: "namespace2", Name: "application3"}}}}}}, + {Data: NodeData{ID: "cluster1-namespace1-application1", Type: "application", Label: "application1", Parent: "cluster1-namespace1", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "cluster1", Namespace: "namespace1", Name: "application2"}}}}}}, + {Data: NodeData{ID: "cluster1-namespace1-application2", Type: "application", Label: "application2", Parent: "cluster1-namespace1", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application2", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "cluster1", Namespace: "namespace2", Name: "application3"}}}}}}, {Data: NodeData{ID: "cluster1-namespace2-application3", Type: "application", Label: "application3", Parent: "cluster1-namespace2", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace2", Name: "application3", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "cluster2", Namespace: "namespace3", Name: "application4"}, {Cluster: "cluster2", Namespace: "namespace3", Name: "application5"}}}}}}, {Data: NodeData{ID: "cluster2-namespace3-application4", Type: "application", Label: "application4", Parent: "cluster2-namespace3", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster2", Namespace: "namespace3", Name: "application4", Topology: application.Topology{Type: "application"}}}}, {Data: NodeData{ID: "cluster2-namespace3-application5", Type: "application", Label: "application5", Parent: "", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster2", Namespace: "namespace3", Name: "application5", Topology: application.Topology{Type: "application", External: true}}}}, @@ -37,8 +37,8 @@ var expectedGenerateTopology = Topology{ {Data: EdgeData{ID: "cluster1-namespace2-application3-cluster2-namespace3-application5", Source: "cluster1-namespace2-application3", SourceCluster: "cluster1", SourceNamespace: "namespace2", SourceName: "application3", Target: "cluster2-namespace3-application5", TargetCluster: "cluster2", TargetNamespace: "namespace3", TargetName: "application5"}}, }, Nodes: []Node{ - {Data: NodeData{ID: "cluster1-namespace1-application1", Type: "application", Label: "application1", Parent: "cluster1-namespace1", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "", Namespace: "", Name: "application2"}}}}}}, - {Data: NodeData{ID: "cluster1-namespace1-application2", Type: "application", Label: "application2", Parent: "cluster1-namespace1", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application2", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "", Namespace: "namespace2", Name: "application3"}}}}}}, + {Data: NodeData{ID: "cluster1-namespace1-application1", Type: "application", Label: "application1", Parent: "cluster1-namespace1", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "cluster1", Namespace: "namespace1", Name: "application2"}}}}}}, + {Data: NodeData{ID: "cluster1-namespace1-application2", Type: "application", Label: "application2", Parent: "cluster1-namespace1", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace1", Name: "application2", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "cluster1", Namespace: "namespace2", Name: "application3"}}}}}}, {Data: NodeData{ID: "cluster1-namespace2-application3", Type: "application", Label: "application3", Parent: "cluster1-namespace2", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster1", Namespace: "namespace2", Name: "application3", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "cluster2", Namespace: "namespace3", Name: "application4"}, {Cluster: "cluster2", Namespace: "namespace3", Name: "application5"}}}}}}, {Data: NodeData{ID: "cluster2-namespace3-application4", Type: "application", Label: "application4", Parent: "cluster2-namespace3", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster2", Namespace: "namespace3", Name: "application4", Topology: application.Topology{Type: "application"}}}}, {Data: NodeData{ID: "cluster2-namespace3-application5", Type: "application", Label: "application5", Parent: "", ApplicationSpec: application.ApplicationSpec{Cluster: "cluster2", Namespace: "namespace3", Name: "application5", Topology: application.Topology{Type: "application", External: true}}}}, @@ -65,15 +65,15 @@ func TestGet(t *testing.T) { mockClustersClient.On("GetClusters").Return([]cluster.Client{mockClusterClient}) t.Run("get applications error", func(t *testing.T) { - mockClusterClient.On("GetApplications", mock.Anything, "").Return(nil, fmt.Errorf("could not get teams")).Once() + mockClusterClient.On("GetApplications", mock.Anything, "").Return(nil, fmt.Errorf("could not get applications")).Once() teams := Get(context.Background(), mockClustersClient) require.Empty(t, teams) }) t.Run("get topology", func(t *testing.T) { mockClusterClient.On("GetApplications", mock.Anything, "").Return([]application.ApplicationSpec{ - {Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "", Namespace: "", Name: "application2"}}}}, - {Cluster: "cluster1", Namespace: "namespace1", Name: "application2", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "", Namespace: "namespace2", Name: "application3"}}}}, + {Cluster: "cluster1", Namespace: "namespace1", Name: "application1", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "cluster1", Namespace: "namespace1", Name: "application2"}}}}, + {Cluster: "cluster1", Namespace: "namespace1", Name: "application2", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "cluster1", Namespace: "namespace2", Name: "application3"}}}}, {Cluster: "cluster1", Namespace: "namespace2", Name: "application3", Topology: application.Topology{Type: "application", Dependencies: []application.Dependency{{Cluster: "cluster2", Namespace: "namespace3", Name: "application4"}, {Cluster: "cluster2", Namespace: "namespace3", Name: "application5"}}}}, {Cluster: "cluster2", Namespace: "namespace3", Name: "application4", Topology: application.Topology{Type: "application"}}, {Cluster: "cluster2", Namespace: "namespace3", Name: "application5", Topology: application.Topology{Type: "application", External: true}}, diff --git a/plugins/applications/src/components/page/Application.tsx b/plugins/applications/src/components/page/Application.tsx index f094002fa..322300d6c 100644 --- a/plugins/applications/src/components/page/Application.tsx +++ b/plugins/applications/src/components/page/Application.tsx @@ -120,12 +120,7 @@ const Application: React.FunctionComponent = () => { {data.teams && data.teams.map((team, index) => ( - + @@ -148,7 +143,12 @@ const Application: React.FunctionComponent = () => { {data.dashboards ? ( - + ) : ( )} diff --git a/plugins/applications/src/components/page/Applications.tsx b/plugins/applications/src/components/page/Applications.tsx index 9cee412f2..2c5197c54 100644 --- a/plugins/applications/src/components/page/Applications.tsx +++ b/plugins/applications/src/components/page/Applications.tsx @@ -84,7 +84,6 @@ const Applications: React.FunctionComponent = ({ ) : ( = ({ - defaults, title, description, options, @@ -23,24 +22,11 @@ export const Panel: React.FunctionComponent = ({ pluginOptions, setDetails, }: IPanelProps) => { - // We have to validate that the required options object was provided in the Application CR by a user. This is - // important so that the React UI doesn't crash, when the user didn't use the plugin correctly. - if (!options || !times) { - return ( - - ); - } - // We have to check if the user selected the topology view and mount the corresponding component, because the data // handling is different for the gallery and topology view. // When a title is set we are sure that the component is used in a dashboard so we will wrap the topology component in // the PluginCard component. - if (options.view === 'topology') { + if (options && options.view === 'topology' && options.clusters && options.namespaces !== undefined && times) { const customStyleSheet: cytoscape.Stylesheet[] = []; if (pluginOptions && pluginOptions.topology && Array.isArray(pluginOptions.topology)) { @@ -65,8 +51,8 @@ export const Panel: React.FunctionComponent = ({ const topology = ( = ({ actions={ } @@ -97,41 +83,108 @@ export const Panel: React.FunctionComponent = ({ return topology; } - // If the user doesn't selected a view, we assume he wants to have the gallery view. As for the topology we also have - // to check if the component is used in a dashboard or in the applications page. - const gallery = ( - - ); + // When the user selected the gallery view, we check if he provided a team. If this is the case we can pass an empty + // array for clusters and namespaces to the gallery component and add the team proverty. + if (options && options.view === 'gallery' && options.team && times) { + const gallery = ( + + ); - if (title) { - return ( - + {gallery} + + ); + } + + return gallery; + } + + // If the user doesn't provied the team option we have to check if he specify a list of clusters and namespaces. If + // this is the case we show the galler component with the applications from the selected clusters and namespaces. + if (options && options.view === 'gallery' && options.clusters && options.namespaces && times) { + const gallery = ( + + ); + + if (title) { + return ( + - ) - } - > - {gallery} - + } + > + {gallery} + + ); + } + + return gallery; + } + + // If the user doesn't selected a view, we assume he wants to have the gallery view. As for the topology we also have + // to check if the component is used in a dashboard or in the applications page. + if (options && options.view === 'gallery' && options.clusters && options.namespaces !== undefined && times) { + const gallery = ( + ); + + if (title) { + return ( + + ) + } + > + {gallery} + + ); + } + + return gallery; } - return gallery; + // We have to validate that the required options object was provided in the Application CR by a user. This is + // important so that the React UI doesn't crash, when the user didn't use the plugin correctly. + return ( + + ); }; export default memo(Panel, (prevProps, nextProps) => { diff --git a/plugins/applications/src/components/panel/details/DependencyDetails.tsx b/plugins/applications/src/components/panel/details/DependencyDetails.tsx index c60cd1f48..dbd9c4524 100644 --- a/plugins/applications/src/components/panel/details/DependencyDetails.tsx +++ b/plugins/applications/src/components/panel/details/DependencyDetails.tsx @@ -55,16 +55,7 @@ const DependencyDetails: React.FunctionComponent = ({

 

- {dashboards ? ( - - ) : null} + {dashboards ? : null}

 

diff --git a/plugins/applications/src/components/panel/details/Details.tsx b/plugins/applications/src/components/panel/details/Details.tsx index 193d8dff2..aed2c33ca 100644 --- a/plugins/applications/src/components/panel/details/Details.tsx +++ b/plugins/applications/src/components/panel/details/Details.tsx @@ -61,12 +61,7 @@ const Details: React.FunctionComponent = ({ application, close }: {application.teams && application.teams.length > 0 ? application.teams.map((team, index) => ( - + @@ -80,9 +75,7 @@ const Details: React.FunctionComponent = ({ application, close }: