From 4b5f07d17552690ba7faf166d2163be7b5bbaaef Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 12 Nov 2024 00:40:27 +0000 Subject: [PATCH] more detail pages Signed-off-by: Eric --- .../kubernetes/common/gourp_dashboards.tsx | 66 ++----- .../configurations/configurations.tsx | 63 +++++-- public/components/kubernetes/home.tsx | 39 +++- .../kubernetes/namespaces/details.tsx | 172 ++++++++++++++++++ .../kubernetes/namespaces/index.tsx | 6 +- .../kubernetes/namespaces/overview.tsx | 6 +- public/components/kubernetes/overview.tsx | 65 ++++++- 7 files changed, 338 insertions(+), 79 deletions(-) create mode 100644 public/components/kubernetes/namespaces/details.tsx diff --git a/public/components/kubernetes/common/gourp_dashboards.tsx b/public/components/kubernetes/common/gourp_dashboards.tsx index 3956dd574..7cafa2ab8 100644 --- a/public/components/kubernetes/common/gourp_dashboards.tsx +++ b/public/components/kubernetes/common/gourp_dashboards.tsx @@ -67,11 +67,12 @@ const layouts = { // Additional information panels { i: 'runningPodsCategory', x: 7, y: 0, w: 2, h: 2 }, { i: 'cpuCoreCount', x: 5, y: 3, w: 1, h: 1 }, + { i: 'diskIO', x: 7, y: 2, w: 2, h: 2 }, { i: 'totalNetworkTraffic', x: 3, y: 3, w: 5, h: 2 }, // Visualization row with detailed charts // { i: 'networkTraffic', x: 0, y: 5, w: 4, h: 3 }, - // { i: 'diskIO', x: 4, y: 5, w: 4, h: 3 }, + // { i: 'diskIO', x: 7, y: 2, w: 2, h: 2 }, // Namespace-based CPU and memory usage panels { i: 'cpuUsageByNamespace', x: 0, y: 8, w: 4, h: 3 }, @@ -94,7 +95,7 @@ const layouts = { { i: 'runningPodsCategory', x: 0, y: 3, w: 3, h: 2 }, { i: 'totalNetworkTraffic', x: 3, y: 3, w: 5, h: 2 }, { i: 'networkTraffic', x: 0, y: 5, w: 4, h: 3 }, - { i: 'diskIO', x: 4, y: 5, w: 4, h: 3 }, + { i: 'diskIO', x: 7, y: 2, w: 2, h: 2 }, { i: 'cpuUsageByNamespace', x: 0, y: 8, w: 4, h: 3 }, { i: 'memoryUsageByNamespace', x: 4, y: 8, w: 4, h: 3 }, { i: 'podNetworkUtilization', x: 0, y: 11, w: 4, h: 3 }, @@ -113,7 +114,7 @@ const layouts = { { i: 'runningPodsCategory', x: 2, y: 6, w: 2, h: 2 }, { i: 'totalNetworkTraffic', x: 0, y: 7, w: 4, h: 3 }, { i: 'networkTraffic', x: 0, y: 10, w: 4, h: 3 }, - { i: 'diskIO', x: 0, y: 13, w: 4, h: 3 }, + { i: 'diskIO', x: 7, y: 2, w: 2, h: 2 }, { i: 'cpuUsageByNamespace', x: 0, y: 16, w: 4, h: 3 }, { i: 'memoryUsageByNamespace', x: 0, y: 19, w: 4, h: 3 }, { i: 'podNetworkUtilization', x: 0, y: 22, w: 4, h: 3 }, @@ -130,7 +131,6 @@ export const GroupDashboards = ({ const [metricsData, setMetricsData] = React.useState([]); useEffect(() => { - console.log('reredner on date change.....'); const metrics = prometheusQueries.map((query) => { return pplService.fetch({ query: query.query, format: 'viz' }); }); @@ -149,28 +149,31 @@ export const GroupDashboards = ({ xKeys: string[], yKeys: string[], gKeys: string[], - traceConfig: {} + vis: {} ) => { + const traceConfig = vis.config; if (traceConfig.type === 'pie') { return [ { - labels: data.data[xKeys[0]], - values: data.data[yKeys[0]], + // labels: data, + // values: data.data[yKeys[0]], + labels: vis.labels, + values: vis.values, ...traceConfig, }, ]; } else if (traceConfig.type === 'indicator') { return [ { - value: data?.data[yKeys[0]][0] || 0, + value: vis.value ? vis.value : data?.data[yKeys[0]][0], ...traceConfig, }, ]; } else if (gKeys.length === 0) { return [ { - x: data.data[xKeys[0]], - y: data.data[yKeys[0]], + x: vis.x ? vis.x : data.data[xKeys[0]], + y: vis.y ? vis.y : data.data[yKeys[0]], ...traceConfig, }, ]; @@ -213,16 +216,9 @@ export const GroupDashboards = ({ visXaxisKeys, visYaxisKeys, visGroupingKeys, - prometheusQueries[index].vis.config + prometheusQueries[index].vis ); - // metric - // jdbc - // metric.datarows.forEach((row) => { - // xaxisData.push(row[0]); - // yaxisData.push(row[1]); - // // row[0] = new Date(row[0]).toISOString(); - // }); return (
@@ -230,13 +226,6 @@ export const GroupDashboards = ({

{prometheusQueries[index].title}

- {/* */}
diff --git a/public/components/kubernetes/configurations/configurations.tsx b/public/components/kubernetes/configurations/configurations.tsx index 0ef9295c6..cbd042060 100644 --- a/public/components/kubernetes/configurations/configurations.tsx +++ b/public/components/kubernetes/configurations/configurations.tsx @@ -35,6 +35,26 @@ export const KubernetesConfiguration = () => { const [osUsername, setOsUsername] = useState(''); const [osPassword, setOsPassword] = useState(''); const [toasts, setToasts] = useState([]); + const [selectedDatasource, setSelectedDatasource] = useState(''); // For tracking the selected datasource + + // Sample list of available OpenSearch datasources + const availableDatasources = [ + { value: '', text: 'Select an OpenSearch Datasource' }, + { value: 'localcluster', text: 'localcluster' }, + ]; + + const handleDatasourceChange = (e) => { + const value = e.target.value; + setSelectedDatasource(value); + + // If "Custom URI" is selected, clear the osUri input field + if (value === 'custom') { + setOsUri(''); + } else { + // Set osUri to the selected datasource's value + setOsUri(value); + } + }; const addToast = () => { const newToast = { @@ -77,10 +97,12 @@ export const KubernetesConfiguration = () => {
  • - Ensure that you have access to a Prometheus instance and a Kubernetes cluster for providing Access Key and Secret Key. + Ensure that you have access to a Prometheus instance and a{' '} + Kubernetes cluster for providing Access Key and Secret Key.
  • - Have an OpenSearch compatible domain as a datasource, or enable a local OpenSearch cluster to create the Prometheus datasource in OpenSearch. + Have an OpenSearch compatible domain as a datasource, or enable a + local OpenSearch cluster to create the Prometheus datasource in OpenSearch.
@@ -91,7 +113,7 @@ export const KubernetesConfiguration = () => { {/* Datasource Selector Section */} -

Datasource Selector

+

Datasource Configurations

@@ -100,12 +122,22 @@ export const KubernetesConfiguration = () => { buttonContent="OpenSearch Datasource Configuration" paddingSize="m" > - + {/* setOsUri(e.target.value)} /> + */} + + { onChange={(e) => setDatasourceName(e.target.value)} /> - + { - {/* Create Datasource Button */} - - Create Prometheus Datasource - + {/* Create Datasource Button in Flex Item */} + + + + Create Prometheus Datasource + + + {/* Toast Notifications */} - + ); diff --git a/public/components/kubernetes/home.tsx b/public/components/kubernetes/home.tsx index 79c06ebc3..242ff27e9 100644 --- a/public/components/kubernetes/home.tsx +++ b/public/components/kubernetes/home.tsx @@ -140,6 +140,7 @@ export const Home = () => { xKeys: [`k8s_node_name`], yKeys: ['running_node_count'], gKeys: [], + value: 2 }, }, { @@ -167,6 +168,7 @@ export const Home = () => { xKeys: [`k8s_node_name`], yKeys: ['running_node_count'], gKeys: [], + value: 10 }, }, { @@ -194,12 +196,13 @@ export const Home = () => { xKeys: [`k8s_node_name`], yKeys: ['running_node_count'], gKeys: [], + value: 40 }, }, { cluster: 'eks-cluster-with-vpc', name: 'runningPodsCategory', - title: 'Failed Pods', + title: 'Running Pods', query: `source = prometheus_k8s_cluster.kube_pod_status_phase | where @timestamp >= '${start}' and @timestamp <= '${end}' and cluster = 'eks-cluster-with-vpc' | fields service_name | stats count() as node_count by service_name`, //query: `source = prometheus_k8s_cluster.\`count:up1\` | where \`cluster\` = 'eks-cluster-with-vpc' | dedup k8s_node_name | stats count() as running_node_count by k8s_node_name`, endpoint: 'prometheus', @@ -223,6 +226,8 @@ export const Home = () => { xKeys: [`pod`], yKeys: ['running_node_count'], gKeys: [], + labels: ['pool-e1ro5g0nq-rk82j', 'pool-e1ro5g0nq-rk82o'], + values: [40, 28] }, }, { @@ -251,6 +256,38 @@ export const Home = () => { gKeys: [], }, }, + { + cluster: 'eks-cluster-with-vpc', + name: 'diskIO', + title: 'Disk usage', + query: `source = prometheus_k8s_cluster.kube_pod_status_phase | where @timestamp >= '${start}' and @timestamp <= '${end}' and cluster = 'eks-cluster-with-vpc' | fields service_name | stats count() as node_count by service_name`, + //query: `source = prometheus_k8s_cluster.\`count:up1\` | where \`cluster\` = 'eks-cluster-with-vpc' | dedup k8s_node_name | stats count() as running_node_count by k8s_node_name`, + endpoint: 'prometheus', + datasource: { name: 'prometheus_k8s', type: 'prometheus' }, + vis: { + component: Pie, + x: 'timestamp', + y: 'Number of Nodes', + xaxisKey: '@timestamp', + yaxisKey: 'total_memory_usage', + config: { + type: 'bar', + hole: .4, + textposition: 'inside', + showlegend: true + }, + // layout: { + // width: 267, + // height: 190 + // }, + xKeys: [`pod`], + yKeys: ['running_node_count'], + gKeys: [], + y: [60, 13], // Sample values for Read and Write + x: ['pool-e1ro5g0nq-rk82j', 'pool-e1ro5g0nq-rk82o'], + }, + }, + // { // cluster: 'play-db-cluster', // name: 'clusterMemoryUsage', diff --git a/public/components/kubernetes/namespaces/details.tsx b/public/components/kubernetes/namespaces/details.tsx new file mode 100644 index 000000000..0687824e6 --- /dev/null +++ b/public/components/kubernetes/namespaces/details.tsx @@ -0,0 +1,172 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { + EuiPage, + EuiPageBody, + EuiPageHeader, + EuiPageHeaderSection, + EuiTitle, + EuiText, + EuiLink, + EuiTabs, + EuiTab, + EuiSpacer, + EuiPanel, + EuiFlexGroup, + EuiFlexItem, + EuiButton, + EuiStat, +} from '@elastic/eui'; +import { Plt } from '../../visualizations/plotly/plot'; + +export const NamespaceDetails = () => { + const [cpuUsageData] = useState([ + { + x: ['02:45', '02:50', '02:55', '03:00', '03:05', '03:10', '03:15', '03:20', '03:25', '03:30', '03:35', '03:40'], + y: [0.04, 0.05, 0.06, 0.07, 0.08, 0.07, 0.09, 0.08, 0.07, 0.06, 0.05, 0.04], + name: 'Sum of container CPU usage', + type: 'scatter', + mode: 'lines', + line: { color: '#1f77b4', width: 2 }, + }, + ]); + + const [memoryUsageData] = useState([ + { + x: ['02:45', '02:50', '02:55', '03:00', '03:05', '03:10', '03:15', '03:20', '03:25', '03:30', '03:35', '03:40'], + y: [700, 750, 800, 850, 900, 850, 820, 780, 800, 850, 880, 860], + name: 'Sum of container memory usage', + type: 'scatter', + mode: 'lines', + line: { color: '#9467bd', width: 2 }, + }, + ]); + + return ( + + + {/* Header Section */} + + + +

argocd namespace

+
+ + in cluster do-nyc1-demo-infra + +
+
+ + + + {/* Tabs */} + + Overview + Network + Energy + Logs & Events + + + + + + + Explore pod status + + + Run Sift investigation + + + + + + {/* Namespace Information */} + + Namespace information + + + + cluster: do-nyc1-demo-infra + workloads: 7 + + + alerts: 0 + phase: Active + + + + + + + {/* Namespace Optimization */} + Namespace optimization + + + + + +

Namespace CPU

+
+ + + + Min: 0.0149 cores | Mean: 0.0557 cores | Max: 0.0917 cores +
+
+ + + +

Namespace Memory

+
+ + + + Min: 640 MiB | Mean: 883 MiB | Max: 980 MiB +
+
+
+ + + + {/* Cost and Optimization Stats */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ ); +}; diff --git a/public/components/kubernetes/namespaces/index.tsx b/public/components/kubernetes/namespaces/index.tsx index 415c06ab8..f9abd0c46 100644 --- a/public/components/kubernetes/namespaces/index.tsx +++ b/public/components/kubernetes/namespaces/index.tsx @@ -6,14 +6,14 @@ import React from 'react'; import { Router, Route, Switch } from 'react-router-dom'; import { NamespaceOverview } from './overview'; -import { Home as ClusterDetails } from '../home'; +import { NamespaceDetails } from './details'; export const NamespacesOverviewHome = (props) => { return ( - {/* */} - + + ); diff --git a/public/components/kubernetes/namespaces/overview.tsx b/public/components/kubernetes/namespaces/overview.tsx index cd838bede..6681289bc 100644 --- a/public/components/kubernetes/namespaces/overview.tsx +++ b/public/components/kubernetes/namespaces/overview.tsx @@ -25,6 +25,7 @@ import { EuiSelect, EuiFieldSearch, EuiIcon, + EuiLink, } from '@elastic/eui'; export const NamespaceOverview = () => { @@ -113,7 +114,10 @@ export const NamespaceOverview = () => { {fakeData.map((namespace, index) => ( - {namespace.namespace} + + {namespace.namespace} + + {/* {namespace.namespace} */} {namespace.cluster} diff --git a/public/components/kubernetes/overview.tsx b/public/components/kubernetes/overview.tsx index ecc6ab6cb..5da8198c2 100644 --- a/public/components/kubernetes/overview.tsx +++ b/public/components/kubernetes/overview.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { EuiPage, EuiPageBody, @@ -25,10 +25,24 @@ import { EuiTableRow, EuiTableRowCell, EuiBadge, + EuiStatProps, } from '@elastic/eui'; import { Plt } from '../visualizations/plotly/plot'; +import { coreRefs } from '../../framework/core_refs'; +const initialStatsData = [ + { label: 'Clusters', value: 0 }, + { label: 'Nodes', value: 2 }, + { label: 'Namespaces', value: 11 }, + { label: 'Workloads', value: 48 }, + { label: 'Pods', value: 68 }, + { label: 'Containers', value: 96 }, +]; export const KubernetesOverview = () => { + const [statsData, setStatsData] = useState<{ label: string; value: number }[]>([ + ...initialStatsData, + ]); + const [isStatsLoading, setIsStatsLoading] = useState(false); const fakeData = [ { @@ -42,14 +56,46 @@ export const KubernetesOverview = () => { }, ]; - const statsData = [ - { label: 'Clusters', value: 1 }, - { label: 'Nodes', value: 2 }, - { label: 'Namespaces', value: 11 }, - { label: 'Workloads', value: 48 }, - { label: 'Pods', value: 68 }, - { label: 'Containers', value: 96 }, - ]; + useEffect(() => { + // Fetch stats data + setIsStatsLoading(true); + const stats = [ + coreRefs!.pplService!.fetch({ + query: + 'source = prometheus_k8s_cluster.`count:up1` | fields cluster | dedup cluster | stats count()', + format: 'jdbc', + }), + coreRefs!.pplService!.fetch({ + query: + 'source = prometheus_k8s_cluster.kube_node_info | fields node | dedup node | stats count()', + format: 'jdbc', + }), + coreRefs!.pplService!.fetch({ + query: + 'source = prometheus_k8s_cluster.kube_namespace_created | fields namespace | dedup namespace | stats count()', + format: 'jdbc', + }), + + ]; + const nextState = [...initialStatsData]; + Promise.allSettled(stats) + .then((data) => { + data + .map((d, index) => (d.status === 'fulfilled' ? d.value : null)) + .forEach((r, index) => { + if (r) { + nextState[index].value = r.datarows[0][0]; + } + }); + setStatsData(nextState); + }) + .catch((error) => { + console.log(error); + }) + .finally(() => { + setIsStatsLoading(false); + }); + }, []); const imageData = [ { name: 'ghcr.io/grafana/quick...', count: 6 }, @@ -143,6 +189,7 @@ export const KubernetesOverview = () => { description={stat.label} titleSize="l" titleColor="primary" + isLoading={isStatsLoading} />