├── .DS_Store ├── .dockerignore ├── .gitignore ├── Dockerfile ├── Dockerfile-kube ├── README.md ├── __tests__ └── backendTests.js ├── armada-depl.yaml ├── assets └── Logo.png ├── build_docker.sh ├── build_notes.txt ├── client ├── .DS_Store ├── App.js ├── actions │ ├── actions.js │ └── constants │ │ ├── actionTypes.js │ │ └── chartConstants.js ├── alertspage │ ├── Alerts.js │ └── ExpandableRow.js ├── components │ ├── CriticalNodes │ │ └── ProblematicNodes.js │ └── Statuses │ │ └── NodesStatus.js ├── custompage │ ├── components │ │ ├── SearchBar.js │ │ ├── StepBar.js │ │ └── TimeRangeBar.js │ └── containers │ │ └── CustomMetricsContainer.js ├── demoData │ ├── alerts.json │ ├── clusterFreeMemory.json │ ├── logs.json │ ├── networkTransmitBytes.json │ ├── networkTransmitFormatted.json │ ├── nodeList.json │ ├── podList.json │ ├── rawLogs.json │ └── serviceList.json ├── homepage │ ├── components │ │ ├── Charts │ │ │ ├── BarChartTemplate.js │ │ │ ├── GaugeChartTemplate.js │ │ │ ├── LineChartTemplate.js │ │ │ └── MaterialColors.js │ │ ├── Counts │ │ │ ├── DeploymentsCount.js │ │ │ ├── NodesCount.js │ │ │ ├── PodsCount.js │ │ │ └── ServicesCount.js │ │ ├── CriticalNodes │ │ │ ├── BytesReceivedPerNode.js │ │ │ ├── BytesTransmittedPerNode.js │ │ │ ├── CPUIntensiveNodes.js │ │ │ ├── MemoryIntensiveNodes.js │ │ │ └── ProblematicItem.js │ │ ├── CriticalPods │ │ │ ├── CPUIntensivePods.js │ │ │ └── MemoryIntensivePods.js │ │ ├── Problematic │ │ │ ├── ProblematicNodes.js │ │ │ └── ProblematicPods.js │ │ ├── Refresh.js │ │ ├── Statuses │ │ │ ├── NodesStatus.js │ │ │ └── PodsStatus.js │ │ └── Utilizations │ │ │ ├── CpuTotal.js │ │ │ ├── CpuUtilization.js │ │ │ ├── MemoryTotal.js │ │ │ └── MemoryUtilization.js │ └── containers │ │ ├── CountsContainer.js │ │ ├── CriticalNodesContainer.js │ │ ├── CriticalPodsContainer.js │ │ ├── MainContainer.js │ │ ├── NavBar.js │ │ ├── ProblematicContainer.js │ │ ├── StatusContainer.js │ │ └── UtilizationContainer.js ├── index.js ├── logspage │ ├── components │ │ └── LogsTable.js │ └── containers │ │ └── LogsContainer.js ├── metricspage │ ├── components │ │ ├── BytesReceivedByNode.js │ │ ├── CPUUsageByNode.js │ │ ├── FreeMemoryByNode.js │ │ ├── NamespaceMetrics │ │ │ ├── BytesReceivedByNamespace.js │ │ │ ├── BytesTransmittedByNamespace.js │ │ │ ├── CPUUsageByNamespace.js │ │ │ └── MemoryUsageByNamespace.js │ │ ├── NodeMetrics │ │ │ ├── BytesReceivedByNode.js │ │ │ ├── BytesTransmittedByNode.js │ │ │ ├── CPUUsageByNode.js │ │ │ └── MemoryUsageByNode.js │ │ └── PodMetrics │ │ │ ├── BytesReceivedByPod.js │ │ │ ├── BytesTransmittedbyPod.js │ │ │ ├── CPUUsageByPod.js │ │ │ ├── FreeMemoryByPod.js │ │ │ └── MemoryUsageByPod.js │ └── containers │ │ └── MetricsContainer.js ├── namespaceSelection │ └── SelectNamespace.js ├── reducers │ ├── deployments.js │ ├── index.js │ ├── namespace.js │ ├── nodes.js │ ├── pods.js │ ├── promMetrics.js │ └── services.js ├── store.js ├── styles.css └── utils │ ├── ComponentWrapper.js │ ├── MetricsComponentWrapper.js │ ├── constants │ └── index.js │ ├── parseStatus.js │ ├── renderAlert.js │ └── table │ └── helpers.js ├── coverage ├── clover.xml ├── coverage-final.json ├── lcov-report │ ├── base.css │ ├── block-navigation.js │ ├── favicon.png │ ├── index.html │ ├── prettify.css │ ├── prettify.js │ ├── server │ │ ├── controllers │ │ │ ├── alertsController.js.html │ │ │ ├── getLists.js.html │ │ │ ├── index.html │ │ │ ├── logsController.js.html │ │ │ ├── metricsDataController.js.html │ │ │ └── prometheusController.js.html │ │ ├── index.html │ │ ├── routers │ │ │ ├── index.html │ │ │ └── prometheusRouter.js.html │ │ ├── server.js.html │ │ └── utils │ │ │ ├── constants.js.html │ │ │ ├── formatChartData.js.html │ │ │ ├── formatLogs.js.html │ │ │ ├── formatTimeToAvg.js.html │ │ │ ├── formatVectorData.js.html │ │ │ ├── index.html │ │ │ └── metricsFetch.js.html │ ├── sort-arrow-sprite.png │ └── sorter.js └── lcov.info ├── docker-compose.yml ├── fabric8-rbac.yaml ├── index.html ├── infra ├── alertmanager │ └── alertmanager.yml ├── docker-compose.yml ├── grafana │ └── provisioning │ │ └── datasources │ │ └── prometheus_ds.yml └── prometheus │ ├── alert.yml │ └── prometheus.yml ├── jest.config.js ├── manifests ├── alertmanager-alertmanager.yaml ├── alertmanager-podDisruptionBudget.yaml ├── alertmanager-prometheusRule.yaml ├── alertmanager-secret.yaml ├── alertmanager-service.yaml ├── alertmanager-serviceAccount.yaml ├── alertmanager-serviceMonitor.yaml ├── blackboxExporter-clusterRole.yaml ├── blackboxExporter-clusterRoleBinding.yaml ├── blackboxExporter-configuration.yaml ├── blackboxExporter-deployment.yaml ├── blackboxExporter-service.yaml ├── blackboxExporter-serviceAccount.yaml ├── blackboxExporter-serviceMonitor.yaml ├── grafana-config.yaml ├── grafana-dashboardDatasources.yaml ├── grafana-dashboardDefinitions.yaml ├── grafana-dashboardSources.yaml ├── grafana-deployment.yaml ├── grafana-service.yaml ├── grafana-serviceAccount.yaml ├── grafana-serviceMonitor.yaml ├── kubePrometheus-prometheusRule.yaml ├── kubeStateMetrics-clusterRole.yaml ├── kubeStateMetrics-clusterRoleBinding.yaml ├── kubeStateMetrics-deployment.yaml ├── kubeStateMetrics-prometheusRule.yaml ├── kubeStateMetrics-service.yaml ├── kubeStateMetrics-serviceAccount.yaml ├── kubeStateMetrics-serviceMonitor.yaml ├── kubernetesControlPlane-prometheusRule.yaml ├── kubernetesControlPlane-serviceMonitorApiserver.yaml ├── kubernetesControlPlane-serviceMonitorCoreDNS.yaml ├── kubernetesControlPlane-serviceMonitorKubeControllerManager.yaml ├── kubernetesControlPlane-serviceMonitorKubeScheduler.yaml ├── kubernetesControlPlane-serviceMonitorKubelet.yaml ├── nodeExporter-clusterRole.yaml ├── nodeExporter-clusterRoleBinding.yaml ├── nodeExporter-daemonset.yaml ├── nodeExporter-prometheusRule.yaml ├── nodeExporter-service.yaml ├── nodeExporter-serviceAccount.yaml ├── nodeExporter-serviceMonitor.yaml ├── prometheus-clusterRole.yaml ├── prometheus-clusterRoleBinding.yaml ├── prometheus-podDisruptionBudget.yaml ├── prometheus-prometheus.yaml ├── prometheus-prometheusRule.yaml ├── prometheus-roleBindingConfig.yaml ├── prometheus-roleBindingSpecificNamespaces.yaml ├── prometheus-roleConfig.yaml ├── prometheus-roleSpecificNamespaces.yaml ├── prometheus-service.yaml ├── prometheus-serviceAccount.yaml ├── prometheus-serviceMonitor.yaml ├── prometheusAdapter-apiService.yaml ├── prometheusAdapter-clusterRole.yaml ├── prometheusAdapter-clusterRoleAggregatedMetricsReader.yaml ├── prometheusAdapter-clusterRoleBinding.yaml ├── prometheusAdapter-clusterRoleBindingDelegator.yaml ├── prometheusAdapter-clusterRoleServerResources.yaml ├── prometheusAdapter-configMap.yaml ├── prometheusAdapter-deployment.yaml ├── prometheusAdapter-podDisruptionBudget.yaml ├── prometheusAdapter-roleBindingAuthReader.yaml ├── prometheusAdapter-service.yaml ├── prometheusAdapter-serviceAccount.yaml ├── prometheusAdapter-serviceMonitor.yaml ├── prometheusOperator-clusterRole.yaml ├── prometheusOperator-clusterRoleBinding.yaml ├── prometheusOperator-deployment.yaml ├── prometheusOperator-prometheusRule.yaml ├── prometheusOperator-service.yaml ├── prometheusOperator-serviceAccount.yaml ├── prometheusOperator-serviceMonitor.yaml └── setup │ ├── 0alertmanagerConfigCustomResourceDefinition.yaml │ ├── 0alertmanagerCustomResourceDefinition.yaml │ ├── 0podmonitorCustomResourceDefinition.yaml │ ├── 0probeCustomResourceDefinition.yaml │ ├── 0prometheusCustomResourceDefinition.yaml │ ├── 0prometheusruleCustomResourceDefinition.yaml │ ├── 0servicemonitorCustomResourceDefinition.yaml │ ├── 0thanosrulerCustomResourceDefinition.yaml │ └── namespace.yaml ├── package-lock.json ├── package.json ├── server ├── .DS_Store ├── PrometheusData │ └── dataSources.js ├── controllers │ ├── alertsController.js │ ├── getLists.js │ ├── logsController.js │ ├── metricsDataController.js │ └── prometheusController.js ├── routers │ └── prometheusRouter.js ├── server.js └── utils │ ├── constants.js │ ├── formatChartData.js │ ├── formatLogs.js │ ├── formatTimeToAvg.js │ ├── formatVectorData.js │ └── metricsFetch.js └── webpack.config.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/.DS_Store -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | infra 3 | out 4 | main.js 5 | preload.js -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | out 4 | infra -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 as kubebuild 2 | RUN apt-get update && apt-get install -y apt-transport-https ca-certificates curl 3 | RUN curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg 4 | RUN echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | tee /etc/apt/sources.list.d/kubernetes.list 5 | RUN apt-get update && apt-get install -y kubectl 6 | 7 | 8 | 9 | #ADD https://storage.googleapis.com/kubernetes-release/release/v1.6.4/bin/linux/amd64/kubectl /usr/local/bin/kubectl 10 | #ENV HOME=/config \ 11 | # KUBECONFIG=/etc/kubernetes/admin.conf 12 | #RUN set -x && \ 13 | # apk add --no-cache curl ca-certificates && \ 14 | # chmod +x /usr/local/bin/kubectl 15 | 16 | #your app container 17 | FROM kubebuild as armada 18 | 19 | WORKDIR /usr/src/app 20 | 21 | RUN npm install -g webpack nodemon 22 | 23 | COPY . /usr/src/app/ 24 | 25 | RUN npm install 26 | 27 | RUN npm run build 28 | 29 | EXPOSE 3001 30 | 31 | # CMD [ "npm", "run", "dev" ] 32 | CMD [ "npm", "run", "start" ] 33 | -------------------------------------------------------------------------------- /Dockerfile-kube: -------------------------------------------------------------------------------- 1 | 2 | #building and adding kubectl 3 | FROM alpine:3.8 as kubectl 4 | 5 | ADD https://storage.googleapis.com/kubernetes-release/release/v1.6.4/bin/linux/amd64/kubectl /usr/local/bin/kubectl 6 | ENV HOME=/config \ 7 | KUBECONFIG=/etc/kubernetes/admin.conf 8 | RUN set -x && \ 9 | apk add --no-cache curl ca-certificates && \ 10 | chmod +x /usr/local/bin/kubectl 11 | 12 | #your app container 13 | FROM armadak8s/armada:latest 14 | 15 | COPY --from=kubectl /usr/local/bin/kubectl /usr/local/bin/kubectl -------------------------------------------------------------------------------- /__tests__/backendTests.js: -------------------------------------------------------------------------------- 1 | const request = require('supertest'); 2 | 3 | const server = 'http://localhost:8080'; 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const promURI = 'http://127.0.0.1:9090/api/v1/'; 7 | // const serverFile = require('../server/server.js'); 8 | 9 | describe('fetch metrics', () => { 10 | describe('/api/fetchMetrics', () => { 11 | describe('GET', () => { 12 | it('responds with 200 status and data as JSON content type', () => { 13 | request(server) 14 | .get('/api/fetchMetrics') 15 | .expect(200) 16 | .expect('Content-Type', /application\/json/); 17 | }); 18 | 19 | it('client metrics are in body of response', () => 20 | request(server) 21 | .get('/api/fetchMetrics') 22 | .then((response) => { 23 | expect(response.body); 24 | expect(response.body[0].values !== undefined).toBe(true); 25 | })); 26 | }); 27 | }); 28 | }); 29 | 30 | describe('fetch alerts', () => { 31 | describe('/api/alerts', () => { 32 | describe('GET', () => { 33 | it('responds with 201 status and data as JSON content type', () => { 34 | request(server) 35 | .get('/api/alerts') 36 | .expect(201) 37 | .expect('Content-Type', /application\/json/); 38 | }); 39 | 40 | it('alerts are in body of response', () => 41 | request(server) 42 | .get('/api/alerts') 43 | .then((response) => { 44 | expect(response.body); 45 | expect(response.body.status === 'success').toBe(true); 46 | })); 47 | }); 48 | }); 49 | }); 50 | 51 | let now = new Date(); 52 | let nowCopy = new Date(now.getTime()); 53 | nowCopy.setHours(nowCopy.getHours() - 24); 54 | let endDateTime = now.toISOString(); 55 | let startDateTime = nowCopy.toISOString(); 56 | 57 | let step = '30m'; 58 | /* 59 | `/api/prometheus/homepage?startDateTime=${startDateTime}&endDateTime=${endDateTime}&step=${step}` 60 | */ 61 | describe('fetch prom metrics for homepage', () => { 62 | describe(`/api/prometheus/homepage?startDateTime=${startDateTime}&endDateTime=${endDateTime}&step=${step}`, () => { 63 | describe('GET', () => { 64 | it('responds with 200 status and data as JSON content type', () => { 65 | request(server) 66 | .get( 67 | `/api/prometheus/homepage?startDateTime=${startDateTime}&endDateTime=${endDateTime}&step=${step}` 68 | ) 69 | .expect(200) 70 | .expect('Content-Type', /application\/json/); 71 | }); 72 | 73 | it('prometheus metrics are in body of response', () => 74 | request(server) 75 | .get( 76 | `/api/prometheus/homepage?startDateTime=${startDateTime}&endDateTime=${endDateTime}&step=${step}` 77 | ) 78 | .then((response) => { 79 | expect(response.body); 80 | expect(response.body.bytesReceivedPerNode !== undefined).toBe(true); 81 | expect(response.body.bytesTransmittedPerNode !== undefined).toBe( 82 | true 83 | ); 84 | })); 85 | }); 86 | }); 87 | }); 88 | 89 | describe('fetch namespace list', () => { 90 | describe('/api/namespaceList', () => { 91 | describe('GET', () => { 92 | it('responds with 201 status and data as JSON content type', () => { 93 | request(server) 94 | .get('/api/namespaceList') 95 | .expect(201) 96 | .expect('Content-Type', /application\/json/); 97 | }); 98 | 99 | it('namespaces are in body of response', () => 100 | request(server) 101 | .get('/api/namespaceList') 102 | .then((response) => { 103 | expect(response.body); 104 | expect(response.body.items[0].metadata.name !== undefined).toBe( 105 | true 106 | ); 107 | })); 108 | }); 109 | }); 110 | }); 111 | -------------------------------------------------------------------------------- /armada-depl.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: armada 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: armada 10 | template: 11 | metadata: 12 | labels: 13 | app: armada 14 | spec: 15 | containers: 16 | - name: armada 17 | image: armadak8s:latest 18 | ports: 19 | - containerPort: 80 20 | protocol: TCP 21 | imagePullPolicy: IfNotPresent 22 | --- 23 | apiVersion: v1 24 | kind: Service 25 | metadata: 26 | name: armada 27 | labels: 28 | prometheus: cluster-monitoring 29 | k8s-app: kube-state-metrics 30 | spec: 31 | selector: 32 | app: armada 33 | type: LoadBalancer 34 | ports: 35 | - name: armada 36 | protocol: TCP 37 | port: 8080 38 | targetPort: 8080 39 | # NOTE: The service account `default:default` already exists in k8s cluster. 40 | # You can create a new account following like this: 41 | #--- 42 | #apiVersion: v1 43 | #kind: ServiceAccount 44 | #metadata: 45 | # name: 46 | # namespace: 47 | 48 | --- 49 | apiVersion: rbac.authorization.k8s.io/v1 50 | kind: ClusterRoleBinding 51 | metadata: 52 | name: fabric8-rbac 53 | subjects: 54 | - kind: ServiceAccount 55 | # Reference to upper's `metadata.name` 56 | name: default 57 | # Reference to upper's `metadata.namespace` 58 | namespace: default 59 | roleRef: 60 | kind: ClusterRole 61 | name: cluster-admin 62 | apiGroup: rbac.authorization.k8s.io 63 | -------------------------------------------------------------------------------- /assets/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/assets/Logo.png -------------------------------------------------------------------------------- /build_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t armadak8s:latest . 3 | -------------------------------------------------------------------------------- /build_notes.txt: -------------------------------------------------------------------------------- 1 | Accessing the API from within a pod: https://kubernetes.io/docs/tasks/run-application/access-api-from-pod/ 2 | 3 | build by running build_docker.sh on the same machine you are running docker desktop kubernetes 4 | The kubernetes deployment should pull the image you just built from your docker build cache (i.e., what `docker images` says) instead of from dockerhub 5 | more reading on that here: https://www.docker.com/blog/how-kubernetes-works-under-the-hood-with-docker-desktop/ 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /client/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/client/.DS_Store -------------------------------------------------------------------------------- /client/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BrowserRouter, Routes, Route } from 'react-router-dom'; 3 | import { ThemeProvider, createTheme } from '@mui/material/styles'; 4 | import MainContainer from './homepage/containers/MainContainer'; 5 | import NavBar from './homepage/containers/NavBar'; 6 | import MetricsContainer from './metricspage/containers/MetricsContainer'; 7 | import Alerts from './alertspage/Alerts'; 8 | import { Container, Box } from '@mui/material'; 9 | import { blueGrey } from '@mui/material/colors'; 10 | import LogsContainer from './logspage/containers/LogsContainer'; 11 | import CustomMetricsContainer from './custompage/containers/CustomMetricsContainer'; 12 | 13 | /* Applies MUI dark theme */ 14 | 15 | const darkTheme = createTheme({ 16 | palette: { 17 | mode: 'dark', 18 | background: { 19 | default: '#121212', 20 | paper: 'rgba(255, 255, 255, 0.08)', 21 | }, 22 | text: { 23 | primary: '#fff', 24 | }, 25 | }, 26 | }); 27 | 28 | /* Leveraging React Router to create multiple views within single page application */ 29 | function App() { 30 | return ( 31 | 32 | 33 | 34 | 35 | 36 | } /> 37 | } /> 38 | } /> 39 | } /> 40 | } /> 41 | 42 | 43 | 44 | 45 | 46 | ); 47 | } 48 | 49 | export default App; 50 | -------------------------------------------------------------------------------- /client/actions/actions.js: -------------------------------------------------------------------------------- 1 | import { 2 | FETCH_NODES_LIST, 3 | FETCH_PODS_LIST, 4 | SET_NAMESPACE, 5 | FETCH_DEPLOYMENTS_LIST, 6 | FETCH_NAMESPACES_LIST, 7 | FETCH_SERVICES_LIST, 8 | FETCH_PROM_METRICS, 9 | } from './constants/actionTypes'; 10 | 11 | export const first = (payload) => ({ 12 | type: second, 13 | payload, 14 | }); 15 | 16 | export const fetchNodesList = (payload) => ({ 17 | type: FETCH_NODES_LIST, 18 | payload, 19 | }); 20 | 21 | export const fetchPodsList = (payload) => ({ 22 | type: FETCH_PODS_LIST, 23 | payload, 24 | }); 25 | 26 | export const setNamespace = (payload) => ({ 27 | type: SET_NAMESPACE, 28 | payload, 29 | }); 30 | 31 | export const fetchNamespacesList = (payload) => ({ 32 | type: FETCH_NAMESPACES_LIST, 33 | payload, 34 | }); 35 | 36 | export const fetchServicesList = (payload) => ({ 37 | type: FETCH_SERVICES_LIST, 38 | payload, 39 | }); 40 | 41 | export const fetchDeploymentsList = (payload) => ({ 42 | type: FETCH_DEPLOYMENTS_LIST, 43 | payload, 44 | }); 45 | 46 | export const fetchPromMetrics = (payload) => ({ 47 | type: FETCH_PROM_METRICS, 48 | payload, 49 | }); 50 | -------------------------------------------------------------------------------- /client/actions/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | // export const first = 'first' 2 | // export const first = 'first' 3 | // export const first = 'first' 4 | // export const first = 'first' 5 | 6 | export const FETCH_NODES_LIST = 'FETCH_NODES_LIST'; 7 | 8 | export const FETCH_PODS_LIST = 'FETCH_PODS_LIST'; 9 | 10 | export const FETCH_SERVICES_LIST = 'FETCH_SERVICES_LIST'; 11 | 12 | export const FETCH_DEPLOYMENTS_LIST = 'FETCH_DEPLOYMENTS_LIST'; 13 | 14 | export const SET_NAMESPACE = 'SET_NAMESPACE'; 15 | 16 | export const FETCH_NAMESPACES_LIST = 'FETCH_NAMESPACES_LIST'; 17 | 18 | export const FETCH_PROM_METRICS = 'FETCH_PROM_METRICS'; 19 | -------------------------------------------------------------------------------- /client/actions/constants/chartConstants.js: -------------------------------------------------------------------------------- 1 | export const MAX_SERIES = 5; 2 | -------------------------------------------------------------------------------- /client/alertspage/ExpandableRow.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Box, 4 | Typography, 5 | Chip, 6 | Table, 7 | TableHead, 8 | TableRow, 9 | TableCell, 10 | TableBody, 11 | } from '@mui/material'; 12 | 13 | function ExpandableRow({ description, summary, alerts, open }) { 14 | const alertsRow = (alert) => { 15 | return ( 16 | 17 | 18 | 19 | Active at: {alert.activeAt} 20 | 21 | 25 | 26 | 27 | 28 | 29 | Container 30 | Instance 31 | Job 32 | Namespace 33 | Statefulset 34 | Description 35 | Summary 36 | 37 | 38 | 39 | 40 | 41 | {alert.labels.container} 42 | 43 | {alert.labels.instance} 44 | {alert.labels.job} 45 | {alert.labels.namespace} 46 | {alert.labels.statefulset} 47 | {alert.annotations.description} 48 | {alert.annotations.summary} 49 | 50 | 51 |
52 |
53 | ); 54 | }; 55 | return ( 56 | 57 | 58 | {/* */} 59 | 60 | 61 | Annotations 62 | 63 | 64 | 65 | 66 | Description 67 | {/* Runbook Url */} 68 | Summary 69 | 70 | 71 | 72 | 73 | 74 | {description} 75 | 76 | {/* {annotations?.runbook_url} */} 77 | {summary} 78 | 79 | 80 |
81 |
82 | {alerts?.length > 0 && ( 83 | 84 | 85 | Alerts 86 | 87 | {alerts.map((alert) => alertsRow(alert))} 88 | 89 | )} 90 |
91 |
92 | ); 93 | } 94 | 95 | export default ExpandableRow; 96 | -------------------------------------------------------------------------------- /client/components/CriticalNodes/ProblematicNodes.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Paper, Typography, ListSubheader } from '@mui/material'; 4 | import Box from '@mui/material/Box'; 5 | import List from '@mui/material/List'; 6 | import ListItemButton from '@mui/material/ListItemButton'; 7 | import ListItemIcon from '@mui/material/ListItemIcon'; 8 | import ListItemText from '@mui/material/ListItemText'; 9 | import Collapse from '@mui/material/Collapse'; 10 | import parseStatus from '../../../utils/parseStatus'; 11 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 12 | import ProblematicItem from './ProblematicItem'; 13 | 14 | const ProblematicNodes = ({ items, lastUpdated }) => { 15 | const [openState, setOpenState] = useState({ 16 | pidPressure: false, 17 | memoryPressure: false, 18 | diskPressure: false, 19 | down: false, 20 | }); 21 | 22 | const handleClick = (key) => { 23 | setOpenState({ ...openState, [key]: !openState[key] }); 24 | }; 25 | const nodeConditions = parseStatus(items); 26 | 27 | const renderByCondition = (nodes, conditionType, condition) => { 28 | const list = Object.keys(nodes).filter( 29 | (key) => nodes[key][conditionType] === condition 30 | ); 31 | return list.map((n) => { 32 | return ; 33 | }); 34 | }; 35 | const down = () => { 36 | return renderByCondition(nodeConditions, 'Ready', 'False'); 37 | }; 38 | const memoryPressure = () => { 39 | return renderByCondition(nodeConditions, 'MemoryPressure', 'True'); 40 | }; 41 | const diskPressure = () => { 42 | return renderByCondition(nodeConditions, 'DiskPressure', 'True'); 43 | }; 44 | const pidPressure = () => { 45 | return renderByCondition(nodeConditions, 'PIDPressure', 'True'); 46 | }; 47 | 48 | const renderList = (key, conditionType, renderComponent) => { 49 | const open = openState[key]; 50 | const length = renderComponent().length; 51 | return ( 52 | <> 53 | handleClick(key)}> 54 | 55 | dangerous 56 | 57 | 58 | {open ? ( 59 | expand_less 60 | ) : ( 61 | expand_more 62 | )} 63 | 64 | 65 | {renderComponent()} 66 | 67 | 68 | ); 69 | }; 70 | 71 | const render = () => { 72 | return ( 73 | items.length && ( 74 | 75 | 78 | // Last updated {lastUpdated.toLocaleString()} 79 | // 80 | // } 81 | > 82 | {renderList('down', 'Down', down)} 83 | {renderList('pidPressure', 'PIDPressure', pidPressure)} 84 | {renderList('memoryPressure', 'MemoryPressure', memoryPressure)} 85 | {renderList('diskPressure', 'DiskPressure', diskPressure)} 86 | 87 | 88 | ) 89 | ); 90 | }; 91 | 92 | return render(); 93 | }; 94 | 95 | const mapStateToProps = ({ nodes }) => { 96 | return nodes; 97 | }; 98 | 99 | export default connect(mapStateToProps)(ProblematicNodes); 100 | 101 | // horizontal bar charts 102 | -------------------------------------------------------------------------------- /client/components/Statuses/NodesStatus.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import Box from '@mui/material/Box'; 4 | import Tooltip from '@mui/material/Tooltip'; 5 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 6 | import parseStatus from '../../../utils/parseStatus'; 7 | 8 | const mapStateToProps = ({ nodes }) => { 9 | return nodes; 10 | }; 11 | 12 | const NodesStatus = ({ items }) => { 13 | const nodesObj = parseStatus(items); 14 | 15 | console.log('nodesObj', nodesObj); 16 | 17 | const NodeBoxes = []; 18 | for (let key of Object.keys(nodesObj)) { 19 | let boxStyle = { 20 | backgroundColor: '#3dce2d', 21 | border: '1px solid #39ba2a', 22 | borderRadius: '3px', 23 | width: '20px', 24 | height: '20px', 25 | margin: '1px', 26 | }; 27 | 28 | if (nodesObj[key]['Ready'] === 'False') { 29 | boxStyle['backgroundColor'] = '#ea2315'; 30 | boxStyle['border'] = '1px solid #d82c20'; 31 | } else if (nodesObj[key]['Ready'] === 'Unknown') { 32 | boxStyle['backgroundColor'] = 'yellow'; 33 | } 34 | 35 | let tooltipText = `Name: ${key}\n`; 36 | for (let condition of Object.keys(nodesObj[key])) { 37 | tooltipText += `${condition}: ${nodesObj[key][condition]}\n`; 38 | } 39 | 40 | NodeBoxes.push( 41 |
42 | 43 | 50 | 51 |
52 | ); 53 | } 54 | 55 | return ( 56 | 57 |
58 | {/*

Node Status

*/} 59 |
60 |
{NodeBoxes}
61 |
62 |
63 | ); 64 | }; 65 | 66 | export default connect(mapStateToProps)(NodesStatus); 67 | -------------------------------------------------------------------------------- /client/custompage/components/SearchBar.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import IconButton from '@mui/material/IconButton'; 3 | import TextField from '@mui/material/TextField'; 4 | import { Autocomplete } from '@mui/material'; 5 | import { Paper } from '@mui/material'; 6 | 7 | const SearchBar = ({ searchquery, setsearchquery, options }) => { 8 | let optionsArray = []; 9 | if (options) { 10 | for (let i = 0; i < options.length; i++) { 11 | optionsArray.push({ label: options[i] }); 12 | } 13 | } 14 | /* Renders options dropdown on Custom Metrics page */ 15 | 16 | return ( 17 | ( 21 | {children} 22 | )} 23 | options={optionsArray} 24 | sx={{ width: 500 }} 25 | renderInput={(params) => } 26 | searchquery={searchquery} 27 | onInputChange={(e, newInputValue) => { 28 | e.preventDefault(); 29 | setsearchquery(newInputValue); 30 | }} 31 | /> 32 | ); 33 | }; 34 | 35 | export default SearchBar; 36 | -------------------------------------------------------------------------------- /client/custompage/components/StepBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import IconButton from '@mui/material/IconButton'; 3 | import TextField from '@mui/material/TextField'; 4 | import { Autocomplete } from '@mui/material'; 5 | import { Paper } from '@mui/material'; 6 | 7 | const optionsArray = [ 8 | { label: '30 seconds' }, 9 | { label: '1 minute' }, 10 | { label: '2 minutes' }, 11 | { label: '5 minutes' }, 12 | { label: '10 minutes' }, 13 | ]; 14 | /* Renders step range dropdown on Custom Metrics page */ 15 | 16 | const StepBar = ({ searchquerystep, setsearchquerystep }) => ( 17 | ( 21 | {children} 22 | )} 23 | options={optionsArray} 24 | sx={{ width: 200 }} 25 | renderInput={(params) => } 26 | searchquery={searchquerystep} 27 | onInputChange={(e, newInputValue) => { 28 | e.preventDefault(); 29 | setsearchquerystep(newInputValue); 30 | }} 31 | /> 32 | ); 33 | 34 | export default StepBar; 35 | -------------------------------------------------------------------------------- /client/custompage/components/TimeRangeBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import IconButton from '@mui/material/IconButton'; 3 | import TextField from '@mui/material/TextField'; 4 | import { Autocomplete } from '@mui/material'; 5 | import { Paper } from '@mui/material'; 6 | 7 | const optionsArray = [ 8 | { label: '30 minutes' }, 9 | { label: '1 hour' }, 10 | { label: '2 hours' }, 11 | { label: '5 hours' }, 12 | { label: '12 hours' }, 13 | { label: '24 hours' }, 14 | { label: '48 hours' }, 15 | ]; 16 | /* Renders time range dropdown on Custom Metrics page */ 17 | 18 | const TimeRangeBar = ({ searchquerytime, setsearchquerytime }) => ( 19 | ( 23 | {children} 24 | )} 25 | options={optionsArray} 26 | sx={{ width: 200 }} 27 | renderInput={(params) => } 28 | searchquery={searchquerytime} 29 | onInputChange={(e, newInputValue) => { 30 | e.preventDefault(); 31 | setsearchquerytime(newInputValue); 32 | }} 33 | /> 34 | ); 35 | 36 | export default TimeRangeBar; 37 | -------------------------------------------------------------------------------- /client/demoData/clusterFreeMemory.json: -------------------------------------------------------------------------------- 1 | { 2 | "clusterFreeMemory": { 3 | "status": "success", 4 | "data": { 5 | "resultType": "matrix", 6 | "result": [ 7 | { 8 | "metric": {}, 9 | "values": [ 10 | [1652291563.841, "28732518.336729288"], 11 | [1652291863.841, "24521262.881017044"], 12 | [1652292163.841, "34801220.98376262"], 13 | [1652292463.841, "36147488.107746184"], 14 | [1652292763.841, "37328267.19789913"], 15 | [1652293063.841, "35642676.622363836"], 16 | [1652293363.841, "20197415.79499869"], 17 | [1652293663.841, "25246611.159717944"], 18 | [1652293963.841, "30263291.55848983"], 19 | [1652294263.841, "32869001.324907307"], 20 | [1652294563.841, "26834946.57640039"], 21 | [1652294863.841, "34017708.59762251"], 22 | [1652295163.841, "30417933.8965487"], 23 | [1652295463.841, "38568429.235408254"], 24 | [1652295763.841, "29424999.51126674"], 25 | [1652296063.841, "35652417.73866486"], 26 | [1652296363.841, "32139538.03160796"], 27 | [1652296663.841, "25097563.78441781"], 28 | [1652296963.841, "41108270.286731064"], 29 | [1652297263.841, "38569076.034669906"], 30 | [1652297563.841, "21408239.890216246"], 31 | [1652297863.841, "42275849.78322687"], 32 | [1652298163.841, "32006736.35061108"], 33 | [1652298463.841, "27342988.566747077"], 34 | [1652298763.841, "24834742.6172766"], 35 | [1652299063.841, "35004300.30304763"], 36 | [1652299363.841, "31325654.700019717"], 37 | [1652299663.841, "27958905.614368975"], 38 | [1652299963.841, "34151699.54849255"], 39 | [1652300263.841, "29878308.689677678"], 40 | [1652300563.841, "40291809.63402227"], 41 | [1652300863.841, "37786650.26353454"], 42 | [1652301163.841, "38750383.8075348"], 43 | [1652301463.841, "46784968.02187943"], 44 | [1652301763.841, "40958563.96381239"], 45 | [1652302063.841, "42393852.00534156"], 46 | [1652302363.841, "37972578.485541746"], 47 | [1652302663.841, "29439152.207369093"], 48 | [1652302963.841, "26436434.97497619"], 49 | [1652303263.841, "55710204.26658526"], 50 | [1652303563.841, "43009685.38784952"], 51 | [1652303863.841, "53450032.54298615"], 52 | [1652304163.841, "42945617.4370615"], 53 | [1652304463.841, "46791077.49804035"], 54 | [1652304763.841, "61634645.5937919"], 55 | [1652305063.841, "46983567.086350314"], 56 | [1652305363.841, "61861330.082515344"], 57 | [1652305663.841, "35381744.04812537"], 58 | [1652305963.841, "44126085.03915976"] 59 | ] 60 | } 61 | ] 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /client/demoData/logs.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | "kube-system", 4 | "112s", 5 | "Warning", 6 | "Unhealthy", 7 | "pod/metrics-server-847dcc659d-brstf", 8 | "Readiness probe failed: HTTP probe failed with statuscode: 500" 9 | ], 10 | [ 11 | "monitoring", 12 | "116s", 13 | "Warning", 14 | "Unhealthy", 15 | "pod/alertmanager-main-1", 16 | "Readiness probe failed: Get \"http://10.244.2.10:9093/-/ready\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)" 17 | ], 18 | [ 19 | "monitoring", 20 | "6m55s", 21 | "Warning", 22 | "Unhealthy", 23 | "pod/alertmanager-main-1", 24 | "Readiness probe failed: Get \"http://10.244.2.10:9093/-/ready\": dial tcp 10.244.2.10:9093: i/o timeout (Client.Timeout exceeded while awaiting headers)" 25 | ], 26 | [ 27 | "monitoring", 28 | "3m31s", 29 | "Warning", 30 | "FailedKillPod", 31 | "pod/node-exporter-h6nww", 32 | "error killing pod: [failed to \"KillContainer\" for \"kube-rbac-proxy\" with KillContainerError: \"rpc error: code = DeadlineExceeded desc = context deadline exceeded\", failed to \"KillPodSandbox\" for \"27cde0ab-5a07-459d-b594-ea3b9bd4d78c\" with KillPodSandboxError: \"rpc error: code = DeadlineExceeded desc = context deadline exceeded\"]" 33 | ], 34 | [ 35 | "monitoring", 36 | "21m", 37 | "Warning", 38 | "FailedKillPod", 39 | "pod/node-exporter-h6nww", 40 | "error killing pod: [failed to \"KillContainer\" for \"kube-rbac-proxy\" with KillContainerError: \"rpc error: code = DeadlineExceeded desc = context deadline exceeded\", failed to \"KillPodSandbox\" for \"27cde0ab-5a07-459d-b594-ea3b9bd4d78c\" with KillPodSandboxError: \"rpc error: code = DeadlineExceeded desc = failed to stop container \"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\": an error occurs during waiting for container \"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\" to be killed: wait container \"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\": context deadline exceeded\"]" 41 | ], 42 | [ 43 | "monitoring", 44 | "12m", 45 | "Warning", 46 | "FailedKillPod", 47 | "pod/node-exporter-h6nww", 48 | "error killing pod: [failed to \"KillContainer\" for \"kube-rbac-proxy\" with KillContainerError: \"rpc error: code = DeadlineExceeded desc = an error occurs during waiting for container \"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\" to be killed: wait container \"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\": context deadline exceeded\", failed to \"KillPodSandbox\" for \"27cde0ab-5a07-459d-b594-ea3b9bd4d78c\" with KillPodSandboxError: \"rpc error: code = DeadlineExceeded desc = context deadline exceeded\"]" 49 | ] 50 | ] 51 | -------------------------------------------------------------------------------- /client/demoData/networkTransmitBytes.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "success", 3 | "data": { 4 | "resultType": "matrix", 5 | "result": [ 6 | { 7 | "metric": {}, 8 | "values": [ 9 | [1652291563.841, "108047.37818671988"], 10 | [1652291863.841, "107245.73685371155"], 11 | [1652292163.841, "115793.2121276655"], 12 | [1652292463.841, "107417.87263466745"], 13 | [1652292763.841, "106885.49746078838"], 14 | [1652293063.841, "107819.25092709798"], 15 | [1652293363.841, "107500.40455804803"], 16 | [1652293663.841, "105742.52568548956"], 17 | [1652293963.841, "106094.6490355648"], 18 | [1652294263.841, "105952.9800882636"], 19 | [1652294563.841, "106021.33717589565"], 20 | [1652294863.841, "108055.97356071987"], 21 | [1652295163.841, "107324.71147641522"], 22 | [1652295463.841, "104939.25937906258"], 23 | [1652295763.841, "106672.7025092899"], 24 | [1652296063.841, "106815.68797786515"], 25 | [1652296363.841, "105591.91965435349"], 26 | [1652296663.841, "107217.4807600847"], 27 | [1652296963.841, "106441.27638208476"], 28 | [1652297263.841, "283298.7828569581"], 29 | [1652297563.841, "105449.50820170264"], 30 | [1652297863.841, "106187.50164594207"], 31 | [1652298163.841, "105299.54218415526"], 32 | [1652298463.841, "106133.66994888916"], 33 | [1652298763.841, "105563.59034610921"], 34 | [1652299063.841, "105051.59433548707"], 35 | [1652299363.841, "105517.20021135123"], 36 | [1652299663.841, "155268.34741625754"], 37 | [1652299963.841, "111418.85300662197"], 38 | [1652300263.841, "262735.6354487903"], 39 | [1652300563.841, "106789.99485058717"], 40 | [1652300863.841, "123126.63090096643"], 41 | [1652301163.841, "115045.53009920717"], 42 | [1652301463.841, "114698.06225393618"], 43 | [1652301763.841, "108580.04575136791"], 44 | [1652302063.841, "110642.62421863398"], 45 | [1652302363.841, "106355.11955381442"], 46 | [1652302663.841, "104785.11794104397"], 47 | [1652302963.841, "110237.29251806396"], 48 | [1652303263.841, "115000.76219683315"], 49 | [1652303563.841, "112675.5176313883"], 50 | [1652303863.841, "107342.67801346486"], 51 | [1652304163.841, "107589.0264483073"], 52 | [1652304463.841, "104962.70096899717"], 53 | [1652304763.841, "108172.17537240099"], 54 | [1652305063.841, "109968.55106923045"], 55 | [1652305363.841, "107879.54411274314"], 56 | [1652305663.841, "110755.64498746092"], 57 | [1652305963.841, "108127.34814925384"] 58 | ] 59 | } 60 | ] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /client/demoData/networkTransmitFormatted.json: -------------------------------------------------------------------------------- 1 | { 2 | "networkTransmitData": { 3 | "timestamps": [ 4 | "17:52", 5 | "17:57", 6 | "18:02", 7 | "18:07", 8 | "18:12", 9 | "18:17", 10 | "18:22", 11 | "18:27", 12 | "18:32", 13 | "18:37", 14 | "18:42", 15 | "18:47", 16 | "18:52", 17 | "18:57", 18 | "19:02", 19 | "19:07", 20 | "19:12", 21 | "19:17", 22 | "19:22", 23 | "19:27", 24 | "19:32", 25 | "19:37", 26 | "19:42", 27 | "19:47", 28 | "19:52", 29 | "19:57", 30 | "20:02", 31 | "20:07", 32 | "20:12", 33 | "20:17", 34 | "20:22", 35 | "20:27", 36 | "20:32", 37 | "20:37", 38 | "20:42", 39 | "20:47", 40 | "20:52", 41 | "20:57", 42 | "21:02", 43 | "21:07", 44 | "21:12", 45 | "21:17", 46 | "21:22", 47 | "21:27", 48 | "21:32", 49 | "21:37", 50 | "21:42", 51 | "21:47", 52 | "21:52" 53 | ], 54 | "seriesLabels": ["Cluster"], 55 | "seriesValues": [ 56 | [ 57 | "108047.37818671988", 58 | "107245.73685371155", 59 | "115793.2121276655", 60 | "107417.87263466745", 61 | "106885.49746078838", 62 | "107819.25092709798", 63 | "107500.40455804803", 64 | "105742.52568548956", 65 | "106094.6490355648", 66 | "105952.9800882636", 67 | "106021.33717589565", 68 | "108055.97356071987", 69 | "107324.71147641522", 70 | "104939.25937906258", 71 | "106672.7025092899", 72 | "106815.68797786515", 73 | "105591.91965435349", 74 | "107217.4807600847", 75 | "106441.27638208476", 76 | "283298.7828569581", 77 | "105449.50820170264", 78 | "106187.50164594207", 79 | "105299.54218415526", 80 | "106133.66994888916", 81 | "105563.59034610921", 82 | "105051.59433548707", 83 | "105517.20021135123", 84 | "155268.34741625754", 85 | "111418.85300662197", 86 | "262735.6354487903", 87 | "106789.99485058717", 88 | "123126.63090096643", 89 | "115045.53009920717", 90 | "114698.06225393618", 91 | "108580.04575136791", 92 | "110642.62421863398", 93 | "106355.11955381442", 94 | "104785.11794104397", 95 | "110237.29251806396", 96 | "115000.76219683315", 97 | "112675.5176313883", 98 | "107342.67801346486", 99 | "107589.0264483073", 100 | "104962.70096899717", 101 | "108172.17537240099", 102 | "109968.55106923045", 103 | "107879.54411274314", 104 | "110755.64498746092", 105 | "108127.34814925384" 106 | ] 107 | ] 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /client/demoData/rawLogs.json: -------------------------------------------------------------------------------- 1 | [ 2 | "NAMESPACE LAST SEEN TYPE REASON OBJECT MESSAGE", 3 | "kube-system 112s Warning Unhealthy pod/metrics-server-847dcc659d-brstf Readiness probe failed: HTTP probe failed with statuscode: 500", 4 | "monitoring 116s Warning Unhealthy pod/alertmanager-main-1 Readiness probe failed: Get \"http://10.244.2.10:9093/-/ready\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)", 5 | "monitoring 6m55s Warning Unhealthy pod/alertmanager-main-1 Readiness probe failed: Get \"http://10.244.2.10:9093/-/ready\": dial tcp 10.244.2.10:9093: i/o timeout (Client.Timeout exceeded while awaiting headers)", 6 | "monitoring 3m31s Warning FailedKillPod pod/node-exporter-h6nww error killing pod: [failed to \"KillContainer\" for \"kube-rbac-proxy\" with KillContainerError: \"rpc error: code = DeadlineExceeded desc = context deadline exceeded\", failed to \"KillPodSandbox\" for \"27cde0ab-5a07-459d-b594-ea3b9bd4d78c\" with KillPodSandboxError: \"rpc error: code = DeadlineExceeded desc = context deadline exceeded\"]", 7 | "monitoring 21m Warning FailedKillPod pod/node-exporter-h6nww error killing pod: [failed to \"KillContainer\" for \"kube-rbac-proxy\" with KillContainerError: \"rpc error: code = DeadlineExceeded desc = context deadline exceeded\", failed to \"KillPodSandbox\" for \"27cde0ab-5a07-459d-b594-ea3b9bd4d78c\" with KillPodSandboxError: \"rpc error: code = DeadlineExceeded desc = failed to stop container \\\"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\\\": an error occurs during waiting for container \\\"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\\\" to be killed: wait container \\\"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\\\": context deadline exceeded\"]", 8 | "monitoring 12m Warning FailedKillPod pod/node-exporter-h6nww error killing pod: [failed to \"KillContainer\" for \"kube-rbac-proxy\" with KillContainerError: \"rpc error: code = DeadlineExceeded desc = an error occurs during waiting for container \\\"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\\\" to be killed: wait container \\\"7cad4627df92d5c09ac630040ccfab6c76e4e0ca12bc55390faed4cec1e10935\\\": context deadline exceeded\", failed to \"KillPodSandbox\" for \"27cde0ab-5a07-459d-b594-ea3b9bd4d78c\" with KillPodSandboxError: \"rpc error: code = DeadlineExceeded desc = context deadline exceeded\"]", 9 | "" 10 | ] 11 | -------------------------------------------------------------------------------- /client/homepage/components/Charts/BarChartTemplate.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | BarElement, 7 | Title, 8 | Tooltip, 9 | Legend, 10 | } from 'chart.js'; 11 | import { Bar } from 'react-chartjs-2'; 12 | 13 | ChartJS.register( 14 | CategoryScale, 15 | LinearScale, 16 | BarElement, 17 | Title, 18 | Tooltip, 19 | Legend 20 | ); 21 | 22 | const BarChart = ({ chartData, title, label }) => { 23 | const options = { 24 | indexAxis: 'y', 25 | elements: { 26 | bar: { 27 | borderWidth: 2, 28 | }, 29 | }, 30 | responsive: true, 31 | plugins: { 32 | legend: { 33 | display: false, 34 | }, 35 | title: { 36 | display: true, 37 | text: title, 38 | color: 'white', 39 | font: { weight: 'bold' }, 40 | }, 41 | datalabels: { 42 | // hide datalabels for all datasets 43 | display: false, 44 | }, 45 | }, 46 | scales: { 47 | xAxes: { 48 | display: true, 49 | ticks: { 50 | color: 'white', 51 | }, 52 | }, 53 | yAxes: { 54 | display: true, 55 | ticks: { 56 | color: 'white', 57 | }, 58 | }, 59 | }, 60 | }; 61 | const data = { 62 | labels: chartData.map((el) => el.label), 63 | datasets: [ 64 | { 65 | // label, 66 | data: chartData.map((el) => el.data), 67 | borderColor: 'transparent', 68 | backgroundColor: 'rgb(140, 92, 142)', 69 | }, 70 | ], 71 | }; 72 | 73 | return ; 74 | }; 75 | 76 | export default BarChart; 77 | 78 | // horizontal bar charts 79 | -------------------------------------------------------------------------------- /client/homepage/components/Charts/GaugeChartTemplate.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | BarElement, 7 | Title, 8 | Tooltip, 9 | Legend, 10 | ArcElement, 11 | } from 'chart.js'; 12 | import { Doughnut } from 'react-chartjs-2'; 13 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 14 | import { Card, Typography } from '@mui/material'; 15 | import ChartDataLabels from 'chartjs-plugin-datalabels'; 16 | 17 | function GaugeChartTemplate({ chartData, title, label }) { 18 | ChartJS.register( 19 | CategoryScale, 20 | LinearScale, 21 | BarElement, 22 | Title, 23 | Tooltip, 24 | Legend, 25 | ArcElement, 26 | ChartDataLabels 27 | ); 28 | 29 | const options = { 30 | plugins: { 31 | title: { 32 | display: false, 33 | responsive: true, 34 | animation: { 35 | animateScale: true, 36 | }, 37 | }, 38 | datalabels: { 39 | // This code is used to display data values 40 | anchor: 'center', 41 | align: 'center', 42 | font: { 43 | weight: 'bold', 44 | size: 20, 45 | }, 46 | formatter: (value) => value + '%', 47 | color: 'white', 48 | }, 49 | }, 50 | layout: { 51 | padding: { 52 | top: '-50', 53 | }, 54 | }, 55 | pointRadius: 0, 56 | circumference: '180', 57 | rotation: '-90', 58 | }; 59 | 60 | let utilColor; 61 | 62 | if (chartData) { 63 | if (100 - chartData <= 33.3) { 64 | utilColor = '#ea2315'; 65 | } else if (100 - chartData > 33.3 && 100 - chartData < 66.6) { 66 | utilColor = 'yellow'; 67 | } else { 68 | utilColor = '#3dce2d'; 69 | } 70 | } 71 | 72 | const data = { 73 | datasets: [ 74 | { 75 | data: [chartData, 100 - chartData], 76 | borderColor: ['transparent', 'transparent'], 77 | backgroundColor: [utilColor, '#808080'], 78 | }, 79 | ], 80 | }; 81 | 82 | const renderChartData = () => { 83 | if (chartData !== undefined) { 84 | return {chartData.toString() + '%'}; 85 | } 86 | }; 87 | 88 | return ( 89 | 90 | 91 | 92 | ); 93 | } 94 | 95 | export default GaugeChartTemplate; 96 | -------------------------------------------------------------------------------- /client/homepage/components/Charts/LineChartTemplate.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | PointElement, 7 | LineElement, 8 | Title, 9 | Tooltip, 10 | Legend, 11 | } from 'chart.js'; 12 | import { Line } from 'react-chartjs-2'; 13 | import mdColors from './MaterialColors'; 14 | import { Button } from '@mui/material'; 15 | import { CopyToClipboard } from 'react-copy-to-clipboard'; 16 | ChartJS.register( 17 | CategoryScale, 18 | LinearScale, 19 | PointElement, 20 | LineElement, 21 | Title, 22 | Tooltip, 23 | Legend 24 | ); 25 | 26 | const LineChart = ({ chartData, title, label, query }) => { 27 | // React hooks for "Copy Query to Clipboard" button and collapsing/expanding legend 28 | const [copiedText, setCopiedText] = useState(); 29 | const [buttonClicked, setButtonClicked] = useState(false); 30 | 31 | const options = { 32 | indexAxis: 'x', 33 | maintainAspectRatio: false, 34 | responsive: true, 35 | pointRadius: 0, 36 | plugins: { 37 | legend: { 38 | display: buttonClicked, 39 | labels: { 40 | usePointStyle: true, 41 | pointStyle: 'rect', 42 | boxWidth: 6, 43 | boxHeight: 6, 44 | color: 'white', 45 | }, 46 | }, 47 | title: { 48 | display: true, 49 | text: title, 50 | font: { 51 | size: 25, 52 | }, 53 | color: 'white', 54 | padding: { 55 | bottom: 15, 56 | }, 57 | }, 58 | datalabels: { 59 | // hide datalabels for all datasets 60 | display: false, 61 | }, 62 | }, 63 | scales: { 64 | xAxes: { 65 | display: true, 66 | ticks: { 67 | color: 'white', 68 | font: { 69 | size: 12, 70 | }, 71 | }, 72 | }, 73 | yAxes: { 74 | display: true, 75 | ticks: { 76 | color: 'white', 77 | }, 78 | }, 79 | }, 80 | }; 81 | 82 | // if chart data is empty render "No data available" 83 | if (!chartData) return
No data available in {title}
; 84 | 85 | // Format chart data for line chart with varying colors 86 | const objArr = []; 87 | if (!chartData.seriesLabels) console.log('title', title); 88 | const lineChartData = chartData.seriesLabels.forEach((el, index) => { 89 | const colors = mdColors; 90 | const rand = Math.floor(Math.random() * 3); 91 | objArr.push({ 92 | data: chartData.seriesValues[index], 93 | label: chartData.seriesLabels[index], 94 | fill: true, 95 | borderColor: colors[(index * 3) % mdColors.length], 96 | backgroundColor: colors[(index * 3) % mdColors.length], 97 | pointHitRadius: 20, 98 | }); 99 | }); 100 | 101 | const data = { 102 | labels: chartData.timestamps, 103 | datasets: objArr, 104 | }; 105 | let id = 1; 106 | 107 | // Collapse or expand legend 108 | const handleLegendClick = () => { 109 | setButtonClicked((prevCheck) => !prevCheck); 110 | }; 111 | 112 | return ( 113 |
114 | 115 | setCopiedText({ query })}> 116 | 123 | 124 | 132 |
133 | ); 134 | }; 135 | 136 | export default LineChart; 137 | -------------------------------------------------------------------------------- /client/homepage/components/Counts/DeploymentsCount.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Card, Typography } from '@mui/material'; 3 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 4 | 5 | // Displays count of deployments in cluster 6 | function DeploymentsCount(props) { 7 | const { deployments } = props; 8 | const deploymentsCount = deployments.length ? deployments.length : '-'; 9 | return ( 10 | 11 | {deploymentsCount} 12 | 13 | ); 14 | } 15 | 16 | export default DeploymentsCount; 17 | -------------------------------------------------------------------------------- /client/homepage/components/Counts/NodesCount.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Card, Typography } from '@mui/material'; 4 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 5 | 6 | const mapStateToProps = ({ nodes }) => { 7 | return nodes; 8 | }; 9 | 10 | // Displays count of nodes in cluster 11 | function NodesCount({ items }) { 12 | const nodesCount = items.length ? items.length : '-'; 13 | return ( 14 | 15 | {nodesCount} 16 | 17 | ); 18 | } 19 | 20 | export default connect(mapStateToProps)(NodesCount); 21 | -------------------------------------------------------------------------------- /client/homepage/components/Counts/PodsCount.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Card, Typography } from '@mui/material'; 3 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 4 | 5 | // Displays count of pods in cluster 6 | function PodsCount(props) { 7 | const { pods } = props; 8 | const podsCount = pods.length ? pods.length : '-'; 9 | return ( 10 | 11 | {podsCount} 12 | 13 | ); 14 | } 15 | 16 | export default PodsCount; 17 | -------------------------------------------------------------------------------- /client/homepage/components/Counts/ServicesCount.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import Card from '@mui/material/Card'; 3 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 4 | import { Typography } from '@mui/material'; 5 | 6 | // Displays count of services in cluster 7 | function ServicesCount(props) { 8 | const { services } = props; 9 | const servicesCount = services.length ? services.length : '-'; 10 | return ( 11 | 12 | {servicesCount} 13 | 14 | ); 15 | } 16 | 17 | export default ServicesCount; 18 | -------------------------------------------------------------------------------- /client/homepage/components/CriticalNodes/BytesReceivedPerNode.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 3 | import BarChart from '../Charts/BarChartTemplate'; 4 | 5 | // Horizontal bar chart of bytes received per node 6 | const BytesReceivedPerNode = ({ promMetrics }) => { 7 | return ( 8 | 9 | 14 | 15 | ); 16 | }; 17 | 18 | export default BytesReceivedPerNode; 19 | -------------------------------------------------------------------------------- /client/homepage/components/CriticalNodes/BytesTransmittedPerNode.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 3 | import BarChart from '../Charts/BarChartTemplate'; 4 | 5 | // Horizontal bar chart of bytes transmitted per node 6 | const BytesTransmittedPerNode = ({ promMetrics }) => { 7 | return ( 8 | 9 | 14 | 15 | ); 16 | }; 17 | 18 | export default BytesTransmittedPerNode; 19 | -------------------------------------------------------------------------------- /client/homepage/components/CriticalNodes/CPUIntensiveNodes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 3 | import BarChart from '../Charts/BarChartTemplate'; 4 | 5 | // Horizontal bar chart showing CPU usage by node 6 | const CPUIntensiveNodes = ({ nodes }) => { 7 | return ( 8 | 9 | 14 | 15 | ); 16 | }; 17 | 18 | export default CPUIntensiveNodes; 19 | -------------------------------------------------------------------------------- /client/homepage/components/CriticalNodes/MemoryIntensiveNodes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 3 | import BarChart from '../Charts/BarChartTemplate'; 4 | 5 | // Horizontal bar chart showing memory usage bby node 6 | const MemoryIntensiveNodes = ({ nodes }) => { 7 | const unitConverted = nodes.map((el) => { 8 | return { ...el, data: el.data / 1000000000 }; 9 | }); 10 | return ( 11 | 12 | 17 | 18 | ); 19 | }; 20 | 21 | export default MemoryIntensiveNodes; 22 | -------------------------------------------------------------------------------- /client/homepage/components/CriticalNodes/ProblematicItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ListItemButton, List, Typography, ListItemText } from '@mui/material'; 3 | 4 | // Component used within ProblematicNodes and ProblematicPods to render each status element 5 | function ProblematicItem({ name, conditions }) { 6 | const conditionsText = () => { 7 | return conditions 8 | .sort( 9 | (a, b) => 10 | Date.parse(a.lastTransitionTime) - Date.parse(b.lastTransitionTime) 11 | ) 12 | .map((c) => ( 13 | {`${c.type}: ${ 14 | c.status 15 | } at ${c.lastTransitionTime.toString()}`} 16 | )); 17 | }; 18 | 19 | return ( 20 | 21 | 22 | 26 | 27 | 28 | ); 29 | } 30 | 31 | export default ProblematicItem; 32 | -------------------------------------------------------------------------------- /client/homepage/components/CriticalPods/CPUIntensivePods.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import BarChart from '../Charts/BarChartTemplate'; 3 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 4 | import { MAX_SERIES } from '../../../actions/constants/chartConstants'; 5 | 6 | const CPUIntensivePods = ({ pods }) => { 7 | return ( 8 | 9 | 14 | 15 | ); 16 | }; 17 | 18 | export default CPUIntensivePods; 19 | -------------------------------------------------------------------------------- /client/homepage/components/CriticalPods/MemoryIntensivePods.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import BarChart from '../Charts/BarChartTemplate'; 3 | import { MAX_SERIES } from '../../../actions/constants/chartConstants'; 4 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 5 | 6 | const MemoryIntensivePods = ({ pods }) => { 7 | const unitConverted = pods.map((el) => { 8 | return { ...el, data: el.data / 1000000000 }; 9 | }); 10 | return ( 11 | 12 | 17 | 18 | ); 19 | }; 20 | 21 | export default MemoryIntensivePods; 22 | -------------------------------------------------------------------------------- /client/homepage/components/Problematic/ProblematicNodes.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Paper, Typography, ListSubheader } from '@mui/material'; 4 | import Box from '@mui/material/Box'; 5 | import List from '@mui/material/List'; 6 | import ListItemButton from '@mui/material/ListItemButton'; 7 | import ListItemIcon from '@mui/material/ListItemIcon'; 8 | import ListItemText from '@mui/material/ListItemText'; 9 | import Collapse from '@mui/material/Collapse'; 10 | import parseStatus from '../../../utils/parseStatus'; 11 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 12 | import ProblematicItem from '../CriticalNodes/ProblematicItem'; 13 | 14 | // Component to show problematic nodes 15 | const ProblematicNodes = ({ items, lastUpdated }) => { 16 | const [openState, setOpenState] = useState({ 17 | pidPressure: false, 18 | memoryPressure: false, 19 | diskPressure: false, 20 | down: false, 21 | }); 22 | 23 | const handleClick = (key) => { 24 | setOpenState({ [key]: !openState[key] }); 25 | }; 26 | const nodeConditions = parseStatus(items); 27 | 28 | // Generates ProblematicItem list for each condition 29 | const renderByCondition = (nodes, conditionType, condition) => { 30 | const list = Object.keys(nodes).filter( 31 | (key) => nodes[key][conditionType] === condition 32 | ); 33 | return list.map((n) => { 34 | return ; 35 | }); 36 | }; 37 | const down = () => { 38 | return renderByCondition(nodeConditions, 'Ready', 'False'); 39 | }; 40 | const memoryPressure = () => { 41 | return renderByCondition(nodeConditions, 'MemoryPressure', 'True'); 42 | }; 43 | const diskPressure = () => { 44 | return renderByCondition(nodeConditions, 'DiskPressure', 'True'); 45 | }; 46 | const pidPressure = () => { 47 | return renderByCondition(nodeConditions, 'PIDPressure', 'True'); 48 | }; 49 | 50 | const renderList = (key, conditionType, renderComponent, icon) => { 51 | const open = openState[key]; 52 | const length = renderComponent().length; 53 | return ( 54 | <> 55 | handleClick(key)}> 56 | 57 | {icon} 58 | 59 | 60 | {open ? ( 61 | expand_less 62 | ) : ( 63 | expand_more 64 | )} 65 | 66 | 67 | {renderComponent()} 68 | 69 | 70 | ); 71 | }; 72 | 73 | const render = () => { 74 | return ( 75 | items.length && ( 76 | 77 | 78 | {renderList('down', 'Down', down, 'dangerous')} 79 | {renderList('pidPressure', 'PID Pressure', pidPressure, 'speed')} 80 | {renderList( 81 | 'memoryPressure', 82 | 'Memory Pressure', 83 | memoryPressure, 84 | 'memory' 85 | )} 86 | {renderList('diskPressure', 'Disk Pressure', diskPressure, 'save')} 87 | 88 | 89 | ) 90 | ); 91 | }; 92 | 93 | return render(); 94 | }; 95 | 96 | const mapStateToProps = ({ nodes }) => { 97 | return nodes; 98 | }; 99 | 100 | export default connect(mapStateToProps)(ProblematicNodes); 101 | -------------------------------------------------------------------------------- /client/homepage/components/Problematic/ProblematicPods.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 4 | import ProblematicItem from '../CriticalNodes/ProblematicItem'; 5 | import { POD_STATUS } from '../../../utils/constants'; 6 | import { 7 | List, 8 | ListItemButton, 9 | ListItemIcon, 10 | ListItemText, 11 | Collapse, 12 | Tooltip, 13 | } from '@mui/material'; 14 | 15 | const ProblematicPods = ({ items, namespace }) => { 16 | const [filteredItems, setFilteredItems] = useState([]); 17 | const [openState, setOpenState] = useState({ 18 | pending: false, 19 | running: false, 20 | succeeded: false, 21 | failed: false, 22 | unknown: false, 23 | }); 24 | 25 | const handleClick = (key) => { 26 | setOpenState({ ...openState, [key]: !openState[key] }); 27 | }; 28 | 29 | // Filters by namespace 30 | useEffect(() => { 31 | if (namespace !== '' && namespace !== 'All') { 32 | setFilteredItems( 33 | items.filter((item) => item.metadata.namespace === namespace) 34 | ); 35 | } else { 36 | setFilteredItems(items); 37 | } 38 | }, [namespace, items]); 39 | 40 | const phases = Object.keys(POD_STATUS); 41 | 42 | // Formats pod phases 43 | const parseItems = () => { 44 | return phases.map((p) => { 45 | let pods = filteredItems.filter((i) => i.status.phase === p); 46 | return { 47 | phase: p, 48 | pods: pods.map((pod) => { 49 | return { name: pod.metadata.name, conditions: pod.status.conditions }; 50 | }), 51 | description: POD_STATUS[p], 52 | }; 53 | }); 54 | }; 55 | 56 | const icons = [ 57 | { icon: 'pending' }, 58 | { icon: 'task_alt' }, 59 | { icon: 'published_with_changes' }, 60 | { icon: 'dangerous' }, 61 | { icon: 'question_mark' }, 62 | ]; 63 | const renderList = () => { 64 | return parseItems().map((item, index) => { 65 | const phase = item.phase; 66 | const open = openState[phase.toLowerCase()]; 67 | const length = item.pods.length; 68 | return ( 69 | 70 | 71 | handleClick(phase.toLowerCase())}> 72 | 73 | {icons[index].icon} 74 | 75 | 76 | {open ? ( 77 | expand_less 78 | ) : ( 79 | expand_more 80 | )} 81 | 82 | 83 | 84 | {item.pods.map((p) => ( 85 | 90 | ))} 91 | 92 | 93 | ); 94 | }); 95 | }; 96 | 97 | return ( 98 | 99 | {renderList()} 100 | 101 | ); 102 | }; 103 | 104 | const mapStateToProps = ({ pods, namespace }) => { 105 | return { ...pods, namespace: namespace.selectedNamespace }; 106 | }; 107 | export default connect(mapStateToProps)(ProblematicPods); 108 | -------------------------------------------------------------------------------- /client/homepage/components/Refresh.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import { Box, Typography, Button } from '@mui/material'; 3 | 4 | // Refresh omponent to refetch data. Passed down handleRefresh from MainContainer 5 | const Refresh = ({ handleRefresh, lastUpdated }) => { 6 | useEffect(() => {}, [handleRefresh, lastUpdated]); 7 | return ( 8 | 11 | 16 | Last updated at {Date(lastUpdated).toString()} 17 | 18 | 30 | 31 | ); 32 | }; 33 | 34 | export default Refresh; 35 | -------------------------------------------------------------------------------- /client/homepage/components/Statuses/NodesStatus.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import Box from '@mui/material/Box'; 4 | import Card from '@mui/material/Card'; 5 | import Popper from '@mui/material/Popper'; 6 | import Paper from '@mui/material/Paper'; 7 | import Typography from '@mui/material/Typography'; 8 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 9 | import parseStatus from '../../../utils/parseStatus'; 10 | 11 | const mapStateToProps = ({ nodes }) => { 12 | return nodes; 13 | }; 14 | 15 | const NodesStatus = ({ items }) => { 16 | const nodesObj = parseStatus(items); 17 | // const [nodesObj, setNodesObj] = React.useState(parseStatus(items)); 18 | const [anchorEl, setAnchorEl] = React.useState(null); 19 | const [open, setOpen] = React.useState(false); 20 | const [placement, setPlacement] = React.useState(); 21 | const [popperText, setPopperText] = React.useState([]); 22 | 23 | // Handleclick for popper 24 | const handleClick = (event, key) => { 25 | console.log('key', key); 26 | let popperHTML = []; 27 | popperHTML.push(

Name: {key}

); 28 | for (let condition of Object.keys(nodesObj[key])) { 29 | popperHTML.push( 30 |

31 | {condition}: {nodesObj[key][condition]} 32 |

33 | ); 34 | setPopperText(popperHTML); 35 | } 36 | setAnchorEl(event.currentTarget); 37 | setOpen((previousOpen) => !previousOpen); 38 | }; 39 | 40 | // Generate node boxes 41 | const NodeBoxes = []; 42 | for (let key of Object.keys(nodesObj)) { 43 | let boxStyle = { 44 | outline: 'none', 45 | backgroundColor: '#3dce2d', 46 | border: '1px solid #39ba2a', 47 | borderRadius: '3px', 48 | width: '30px', 49 | height: '30px', 50 | margin: '1px', 51 | }; 52 | 53 | if (nodesObj[key]['Ready'] === 'False') { 54 | boxStyle['backgroundColor'] = '#ea2315'; 55 | boxStyle['border'] = '1px solid #d82c20'; 56 | } else if (nodesObj[key]['Ready'] === 'Unknown') { 57 | boxStyle['backgroundColor'] = 'yellow'; 58 | } 59 | 60 | NodeBoxes.push( 61 |
62 | 75 |
76 | ); 77 | } 78 | 79 | return ( 80 | 81 | 82 | 83 | {popperText} 84 | 85 | 86 | 87 |
88 |
{NodeBoxes}
89 |
90 |
91 | ); 92 | }; 93 | 94 | export default connect(mapStateToProps)(NodesStatus); 95 | -------------------------------------------------------------------------------- /client/homepage/components/Statuses/PodsStatus.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import Box from '@mui/material/Box'; 3 | import Tooltip from '@mui/material/Tooltip'; 4 | import Card from '@mui/material/Card'; 5 | import Popper from '@mui/material/Popper'; 6 | import Typography from '@mui/material/Typography'; 7 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 8 | 9 | const PodsStatus = (props) => { 10 | const { pods } = props; 11 | const podsObj = {}; 12 | for (let pod of pods) { 13 | podsObj[pod.metadata.name] = pod.status.phase; 14 | } 15 | 16 | const [anchorEl, setAnchorEl] = React.useState(null); 17 | const [open, setOpen] = React.useState(false); 18 | const [placement, setPlacement] = React.useState(); 19 | const [popperText, setPopperText] = React.useState([]); 20 | 21 | // Generate pod boxes 22 | const PodsBoxes = []; 23 | for (let key of Object.keys(podsObj)) { 24 | let boxStyle = { 25 | backgroundColor: '#3dce2d', 26 | border: '1px solid #39ba2a', 27 | borderRadius: '3px', 28 | width: '30px', 29 | height: '30px', 30 | margin: '1px', 31 | }; 32 | if (podsObj[key] !== 'Running') { 33 | boxStyle['background-color'] = 'red'; 34 | } 35 | PodsBoxes.push( 36 |
37 | 43 |
44 | ); 45 | } 46 | 47 | // Handleclick for popper 48 | const handleClick = (event, key) => { 49 | let popperHTML = []; 50 | popperHTML.push(

Name: {key}

); 51 | popperHTML.push(

Status: {podsObj[key]}

); 52 | setPopperText(popperHTML); 53 | setAnchorEl(event.currentTarget); 54 | setOpen((previousOpen) => !previousOpen); 55 | }; 56 | 57 | return ( 58 | 59 | 60 | 61 | {popperText} 62 | 63 | 64 | 65 |
66 |
{PodsBoxes}
67 |
68 |
69 | ); 70 | }; 71 | 72 | export default PodsStatus; 73 | -------------------------------------------------------------------------------- /client/homepage/components/Utilizations/CpuTotal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Card, Typography } from '@mui/material'; 4 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 5 | 6 | // CPU used out of total 7 | const CpuTotal = ({ cpu, cpuusage }) => { 8 | return ( 9 | <> 10 | 11 | {cpu * (cpuusage / 100)} 12 | 13 | used 14 | 15 | {cpu} 16 | 17 | total 18 | 19 | 20 | 21 | ); 22 | }; 23 | 24 | export default CpuTotal; 25 | -------------------------------------------------------------------------------- /client/homepage/components/Utilizations/CpuUtilization.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Card, Typography } from '@mui/material'; 3 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 4 | import GaugeChartTemplate from '../Charts/GaugeChartTemplate'; 5 | 6 | function CpuUtilization({ cpu }) { 7 | return ( 8 | 13 | ); 14 | } 15 | 16 | export default CpuUtilization; 17 | -------------------------------------------------------------------------------- /client/homepage/components/Utilizations/MemoryTotal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Card, Typography } from '@mui/material'; 4 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 5 | 6 | const MemoryTotal = ({ memory, memusage }) => { 7 | let memoryinGb; 8 | if (memory) { 9 | memoryinGb = Number((memory / 10 ** 9).toFixed(0)); 10 | } 11 | 12 | return ( 13 | <> 14 | 15 | {memoryinGb} 16 | 17 | used 18 | 19 | 20 | {(memoryinGb / (memusage / 100)).toFixed(0)} 21 | 22 | 23 | total 24 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default MemoryTotal; 31 | -------------------------------------------------------------------------------- /client/homepage/components/Utilizations/MemoryUtilization.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Card, Typography } from '@mui/material'; 3 | import ComponentWrapper from '../../../utils/ComponentWrapper'; 4 | import GaugeChartTemplate from '../Charts/GaugeChartTemplate'; 5 | 6 | function MemoryUtilization({ memory }) { 7 | return ( 8 | 13 | ); 14 | } 15 | 16 | export default MemoryUtilization; 17 | -------------------------------------------------------------------------------- /client/homepage/containers/CountsContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Grid } from '@mui/material'; 3 | import NodesCount from '../components/Counts/NodesCount'; 4 | import DeploymentsCount from '../components/Counts/DeploymentsCount'; 5 | import PodsCount from '../components/Counts/PodsCount'; 6 | import ServicesCount from '../components/Counts/ServicesCount'; 7 | 8 | const CountsContainer = (props) => { 9 | const { nodes, deployments, pods, services } = props; 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ); 26 | }; 27 | 28 | export default CountsContainer; 29 | -------------------------------------------------------------------------------- /client/homepage/containers/CriticalNodesContainer.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import CPUIntensiveNodes from '../components/CriticalNodes/CPUIntensiveNodes'; 3 | import MemoryIntensiveNodes from '../components/CriticalNodes/MemoryIntensiveNodes'; 4 | import BytesTransmittedPerNode from '../components/CriticalNodes/BytesTransmittedPerNode'; 5 | import BytesReceivedPerNode from '../components/CriticalNodes/BytesReceivedPerNode'; 6 | import { Grid } from '@mui/material'; 7 | 8 | const CriticalNodesContainer = ({ promMetrics }) => { 9 | const [cpu, setCpu] = useState([]); 10 | const [memory, setMemory] = useState([]); 11 | const getCpuByNode = () => { 12 | fetch('api/prometheus/cpubynode') 13 | .then((res) => { 14 | return res.json(); 15 | }) 16 | .then((data) => { 17 | setCpu(data); 18 | }) 19 | .catch((err) => console.log('error with nodebycpu', err)); 20 | }; 21 | 22 | const getMemoryByNode = () => { 23 | fetch('/api/prometheus/memorybynode') 24 | .then((res) => res.json()) 25 | .then((data) => setMemory(data)) 26 | .catch((err) => console.log(err)); 27 | }; 28 | 29 | useEffect(() => { 30 | getCpuByNode(); 31 | getMemoryByNode(); 32 | }, []); 33 | 34 | const renderCpuGraph = () => { 35 | if (cpu.length > 0) { 36 | return ; 37 | } 38 | }; 39 | const renderMemoryGraph = () => { 40 | if (memory.length > 0) { 41 | return ; 42 | } 43 | }; 44 | 45 | const renderNetworkTransmitGraph = () => { 46 | if (promMetrics.bytesTransmittedPerNode) { 47 | return ; 48 | } 49 | }; 50 | 51 | const renderNetworkReceivedGraph = () => { 52 | if (promMetrics.bytesReceivedPerNode) { 53 | return ; 54 | } 55 | }; 56 | 57 | return ( 58 | 59 | 60 | {renderCpuGraph()} 61 | 62 | 63 | {renderMemoryGraph()} 64 | 65 | 66 | 67 | {renderNetworkTransmitGraph()} 68 | 69 | 70 | {renderNetworkReceivedGraph()} 71 | 72 | 73 | ); 74 | }; 75 | 76 | export default CriticalNodesContainer; 77 | -------------------------------------------------------------------------------- /client/homepage/containers/CriticalPodsContainer.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Grid } from '@mui/material'; 3 | import CPUIntensivePods from '../components/CriticalPods/CPUIntensivePods'; 4 | import MemoryIntensivePods from '../components/CriticalPods/MemoryIntensivePods'; 5 | 6 | const CriticalPodsContainer = (props) => { 7 | const { namespace } = props; 8 | 9 | const [cpu, setCpu] = useState([]); 10 | const [memory, setMemory] = useState([]); 11 | const fetchCpuByPod = () => { 12 | fetch(`/api/prometheus/cpubypod?namespace=${namespace}`) 13 | .then((res) => res.json()) 14 | .then((data) => { 15 | // console.log('cpu data ' + data); 16 | setCpu(data); 17 | }) 18 | .catch((err) => console.log(err)); 19 | }; 20 | 21 | const fetchMemoryByPod = () => { 22 | fetch(`/api/prometheus/memorybypod?namespace=${namespace}`) 23 | .then((res) => res.json()) 24 | .then((data) => { 25 | setMemory(data); 26 | console.log(data); 27 | }) 28 | .catch((err) => console.log(err)); 29 | }; 30 | 31 | useEffect(() => { 32 | fetchCpuByPod(); 33 | fetchMemoryByPod(); 34 | }, [namespace]); 35 | 36 | const renderCpuGraph = () => { 37 | if (cpu) { 38 | return ; 39 | } 40 | }; 41 | 42 | const renderMemory = () => { 43 | if (memory) { 44 | return ; 45 | } 46 | }; 47 | 48 | return ( 49 | 50 | 51 | {renderCpuGraph()} 52 | 53 | 54 | {renderMemory()} 55 | 56 | 57 | ); 58 | }; 59 | 60 | export default CriticalPodsContainer; 61 | -------------------------------------------------------------------------------- /client/homepage/containers/ProblematicContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ProblematicNodes from '../components/Problematic/ProblematicNodes'; 3 | import ProblematicPods from '../components/Problematic/ProblematicPods'; 4 | import { Grid } from '@mui/material'; 5 | 6 | const ProblematicContainer = () => { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default ProblematicContainer; 20 | -------------------------------------------------------------------------------- /client/homepage/containers/StatusContainer.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Grid, Box } from '@mui/material'; 3 | import NodesStatus from '../components/Statuses/NodesStatus'; 4 | import PodsStatus from '../components/Statuses/PodsStatus'; 5 | 6 | const StatusContainer = (props) => { 7 | const { nodes, pods, services } = props; 8 | 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default StatusContainer; 22 | -------------------------------------------------------------------------------- /client/homepage/containers/UtilizationContainer.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Grid } from '@mui/material'; 3 | import CpuUtilization from '../components/Utilizations/CpuUtilization.js'; 4 | import MemoryUtilization from '../components/Utilizations/MemoryUtilization.js'; 5 | import CpuTotal from '../components/Utilizations/CpuTotal.js'; 6 | import MemoryTotal from '../components/Utilizations/MemoryTotal.js'; 7 | 8 | const UtilizationContainer = (props) => { 9 | const [clusterData, setClusterData] = useState([]); 10 | 11 | const getUtilization = () => { 12 | fetch('/api/prometheus/clustermetrics') 13 | .then((data) => data.json()) 14 | .then((data) => { 15 | const obj = {}; 16 | console.log(data); 17 | for (const key in data) { 18 | if (key == 'cpuUtilization' || key == 'memoryUtilization') { 19 | obj[key] = Number(data[key] * 100).toFixed(0); 20 | } else { 21 | obj[key] = data[key]; 22 | } 23 | } 24 | setClusterData(obj); 25 | }) 26 | .catch((error) => console.log(error)); 27 | }; 28 | 29 | useEffect(() => { 30 | getUtilization(); 31 | }, []); 32 | 33 | const renderCpuUtilization = () => { 34 | if (clusterData) { 35 | return ; 36 | } 37 | }; 38 | 39 | const renderMemoryUtilization = () => { 40 | if (clusterData) { 41 | return ; 42 | } 43 | }; 44 | 45 | const renderCpuTotal = () => { 46 | if (clusterData) { 47 | return ( 48 | 52 | ); 53 | } 54 | }; 55 | 56 | const renderMemoryTotal = () => { 57 | if (clusterData) { 58 | return ( 59 | 63 | ); 64 | } 65 | }; 66 | 67 | return ( 68 | 69 | 70 | {renderCpuUtilization()} 71 | 72 | 73 | {renderMemoryUtilization()} 74 | 75 | 76 | {renderCpuTotal()} 77 | 78 | 79 | {renderMemoryTotal()} 80 | 81 | 82 | ); 83 | }; 84 | 85 | export default UtilizationContainer; 86 | -------------------------------------------------------------------------------- /client/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDom from 'react-dom/client'; 3 | import { Provider } from 'react-redux'; 4 | 5 | import store from './store'; 6 | import App from './App'; 7 | import './styles.css'; 8 | 9 | const root = ReactDom.createRoot(document.getElementById('root')); 10 | 11 | root.render( 12 | 13 | 14 | 15 | ); 16 | -------------------------------------------------------------------------------- /client/logspage/components/LogsTable.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import MaUTable from '@mui/material/Table'; 4 | import { TableBody, AlertTitle, Grid, Paper } from '@mui/material'; 5 | import TableCell from '@mui/material/TableCell'; 6 | import TableHead from '@mui/material/TableHead'; 7 | import TableRow from '@mui/material/TableRow'; 8 | import { useTable, useFilters } from 'react-table'; 9 | import { 10 | SelectColumnFilter, 11 | DefaultColumnFilter, 12 | } from '../../utils/table/helpers'; 13 | import Alert from '../../utils/renderAlert'; 14 | 15 | const HEADERS = [ 16 | 'NAMESPACE', 17 | 'LAST SEEN', 18 | 'TYPE', 19 | 'REASON', 20 | 'OBJECT', 21 | 'MESSAGE', 22 | ]; 23 | 24 | function Table({ columns, data }) { 25 | const defaultColumn = React.useMemo( 26 | () => ({ 27 | // Let's set up our default Filter UI 28 | Filter: DefaultColumnFilter, 29 | }), 30 | [] 31 | ); 32 | 33 | // Use the state and functions returned from useTable to build your UI 34 | const { getTableProps, headerGroups, rows, prepareRow } = useTable( 35 | { 36 | columns, 37 | data, 38 | defaultColumn, 39 | }, 40 | useFilters 41 | ); 42 | 43 | // Render the UI for your table 44 | return ( 45 | 46 | 47 | {headerGroups.map((headerGroup) => ( 48 | 49 | {headerGroup.headers.map((column) => ( 50 | 51 | {column.render('Header')} 52 |
{column.canFilter ? column.render('Filter') : null}
53 |
54 | ))} 55 |
56 | ))} 57 |
58 | 59 | {rows.map((row, i) => { 60 | prepareRow(row); 61 | return ( 62 | 63 | {row.cells.map((cell) => { 64 | return ( 65 | 66 | {cell.render('Cell')} 67 | 68 | ); 69 | })} 70 | 71 | ); 72 | })} 73 | 74 |
75 | ); 76 | } 77 | 78 | const formatColumns = () => { 79 | const columnsWithFilters = ['TYPE', 'REASON']; 80 | return HEADERS.map((el) => { 81 | const obj = {}; 82 | if (columnsWithFilters.includes(el)) { 83 | obj.filter = 'includes'; 84 | obj.Filter = SelectColumnFilter; 85 | } else { 86 | obj.canFilter = false; 87 | obj.disableFilters = true; 88 | } 89 | obj.Header = el.charAt(0).toUpperCase() + el.slice(1); 90 | obj.accessor = el.toLowerCase().replace(' ', '_'); 91 | return obj; 92 | }); 93 | }; 94 | 95 | function LogsTable({ data, namespace }) { 96 | const columns = React.useMemo( 97 | () => formatColumns(), 98 | 99 | [] 100 | ); 101 | 102 | const message = () => { 103 | return ( 104 | <> 105 | No logs found 106 | {namespace !== '' && 107 | namespace !== 'All' && 108 | ` in the ${namespace} namespace`} 109 | 110 | ); 111 | }; 112 | 113 | return ( 114 |
115 | {Alert(data.length, message(), 'info')} 116 | 117 | 118 | 119 | 120 | ); 121 | } 122 | 123 | export default LogsTable; 124 | -------------------------------------------------------------------------------- /client/logspage/containers/LogsContainer.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import LogsTable from '../components/LogsTable'; 4 | 5 | function LogsContainer({ namespace }) { 6 | const [logs, setLogs] = useState([]); 7 | const getLogs = () => { 8 | fetch('/api/logs') 9 | .then((res) => res.json()) 10 | .then((data) => setLogs(data)) 11 | .catch((err) => console.log(err)); 12 | }; 13 | useEffect(() => { 14 | getLogs(); 15 | }, [namespace]); 16 | 17 | const filterByNamespace = () => { 18 | if (namespace !== 'All' && namespace !== '') { 19 | return logs.filter((log) => log.namespace === namespace); 20 | } 21 | return logs; 22 | }; 23 | // console.log('logs filtered', filterByNamespace()); 24 | return ; 25 | } 26 | 27 | const mapStateToProps = ({ namespace }) => { 28 | console.log('namespace', namespace); 29 | return { namespace: namespace.selectedNamespace }; 30 | }; 31 | 32 | export default connect(mapStateToProps)(LogsContainer); 33 | -------------------------------------------------------------------------------- /client/metricspage/components/BytesReceivedByNode.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/client/metricspage/components/BytesReceivedByNode.js -------------------------------------------------------------------------------- /client/metricspage/components/CPUUsageByNode.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/client/metricspage/components/CPUUsageByNode.js -------------------------------------------------------------------------------- /client/metricspage/components/FreeMemoryByNode.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/client/metricspage/components/FreeMemoryByNode.js -------------------------------------------------------------------------------- /client/metricspage/components/NamespaceMetrics/BytesReceivedByNamespace.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | import { Button } from '@mui/material'; 5 | 6 | const BytesReceivedByNamespace = ({ metrics }) => { 7 | /* 8 | Renders the Network IO (Bps) Received by Namespace line chart on the Metrics Page 9 | */ 10 | return ( 11 |
12 | 13 | 19 | 20 |
21 | ); 22 | }; 23 | 24 | export default BytesReceivedByNamespace; 25 | -------------------------------------------------------------------------------- /client/metricspage/components/NamespaceMetrics/BytesTransmittedByNamespace.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const BytesTransmittedByNamespace = ({ metrics }) => { 6 | /* 7 | Renders Network IO (Bps) Transmitted by Namespace line chart on the Metrics Page 8 | */ 9 | return ( 10 |
11 | 12 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default BytesTransmittedByNamespace; 24 | -------------------------------------------------------------------------------- /client/metricspage/components/NamespaceMetrics/CPUUsageByNamespace.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const CPUUsageByNamespace = ({ metrics }) => { 6 | /* 7 | Renders CPU Usage % by Namespace line chart on the Metrics Page 8 | */ 9 | return ( 10 |
11 | 12 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default CPUUsageByNamespace; 24 | -------------------------------------------------------------------------------- /client/metricspage/components/NamespaceMetrics/MemoryUsageByNamespace.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const MemoryUsageByNamespace = ({ metrics }) => { 6 | /* 7 | Converts Memory Usage from Bytes to GB 8 | */ 9 | if (metrics.data) { 10 | for (let i = 0; i < metrics.data.seriesValues.length; i++) { 11 | metrics.data.seriesValues[i] = metrics.data.seriesValues[i].map((el) => { 12 | return el / 1000000000; 13 | }); 14 | } 15 | } 16 | /* 17 | Renders Memory Usage (Gb) by Namespace line chart on the Metrics Page 18 | */ 19 | return ( 20 |
21 | 22 | 28 | 29 |
30 | ); 31 | }; 32 | 33 | export default MemoryUsageByNamespace; 34 | -------------------------------------------------------------------------------- /client/metricspage/components/NodeMetrics/BytesReceivedByNode.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const BytesReceivedByNode = ({ metrics }) => { 6 | /* 7 | Renders the Network IO (Bps) Received by Node line chart on the Metrics Page 8 | */ 9 | return ( 10 |
11 | 12 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default BytesReceivedByNode; 24 | -------------------------------------------------------------------------------- /client/metricspage/components/NodeMetrics/BytesTransmittedByNode.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const BytesTransmittedByNode = ({ metrics }) => { 6 | /* 7 | Renders the Network IO (Bps) Transmitted by Node line chart on the Metrics Page 8 | */ 9 | return ( 10 |
11 | 12 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default BytesTransmittedByNode; 24 | -------------------------------------------------------------------------------- /client/metricspage/components/NodeMetrics/CPUUsageByNode.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const CPUUsageByNode = ({ metrics }) => { 6 | /* 7 | Renders the CPU Usage % Per Node line chart on the Metrics Page 8 | */ 9 | return ( 10 |
11 | 12 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default CPUUsageByNode; 24 | -------------------------------------------------------------------------------- /client/metricspage/components/NodeMetrics/MemoryUsageByNode.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const MemoryUsageByNode = ({ metrics }) => { 6 | /* 7 | Converts Memory Usage from Bytes to GB 8 | */ 9 | if (metrics.data) { 10 | for (let i = 0; i < metrics.data.seriesValues.length; i++) { 11 | metrics.data.seriesValues[i] = metrics.data.seriesValues[i].map((el) => { 12 | return el / 1000000000; 13 | }); 14 | } 15 | } 16 | 17 | /* 18 | Renders the Memory Usage (Gb) By Node line chart on the Metrics Page 19 | */ 20 | 21 | return ( 22 |
23 | 24 | 30 | 31 |
32 | ); 33 | }; 34 | 35 | export default MemoryUsageByNode; 36 | -------------------------------------------------------------------------------- /client/metricspage/components/PodMetrics/BytesReceivedByPod.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const BytesReceivedByPod = ({ metrics }) => { 6 | /* 7 | Renders the Network IO (Bps) Received by Pod line chart on the Metrics Page 8 | */ 9 | return ( 10 |
11 | 12 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default BytesReceivedByPod; 24 | -------------------------------------------------------------------------------- /client/metricspage/components/PodMetrics/BytesTransmittedbyPod.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const BytesTransmittedbyPod = ({ metrics }) => { 6 | /* 7 | Renders Network IO (Bps) Transmitted by Pod line chart on the Metrics Page 8 | */ 9 | return ( 10 |
11 | 12 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default BytesTransmittedbyPod; 24 | -------------------------------------------------------------------------------- /client/metricspage/components/PodMetrics/CPUUsageByPod.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const CPUUsageByPod = ({ metrics }) => { 6 | /* 7 | Renders CPU Usage % by Pod line chart on the Metrics Page 8 | */ 9 | return ( 10 |
11 | 12 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default CPUUsageByPod; 24 | -------------------------------------------------------------------------------- /client/metricspage/components/PodMetrics/FreeMemoryByPod.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | 4 | const FreeMemoryByPod = ({ metrics }) => { 5 | /* 6 | Renders Free Memory Per Node line chart on the Metrics Page 7 | */ 8 | return ( 9 |
10 | 11 | 17 | 18 |
19 | ); 20 | }; 21 | 22 | export default FreeMemoryByPod; 23 | -------------------------------------------------------------------------------- /client/metricspage/components/PodMetrics/MemoryUsageByPod.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineChart from '../../../homepage/components/Charts/LineChartTemplate'; 3 | import MetricsComponentWrapper from '../../../utils/MetricsComponentWrapper'; 4 | 5 | const MemoryUsageByPod = ({ metrics }) => { 6 | /* 7 | Converts Memory Usage from Bytes to GB 8 | */ 9 | if (metrics.data) { 10 | for (let i = 0; i < metrics.data.seriesValues.length; i++) { 11 | metrics.data.seriesValues[i] = metrics.data.seriesValues[i].map((el) => { 12 | return el / 1000000000; 13 | }); 14 | } 15 | } 16 | /* 17 | Renders Memory Usage (Gb) by Pod line chart on the Metrics Page 18 | */ 19 | return ( 20 |
21 | 22 | 28 | 29 |
30 | ); 31 | }; 32 | 33 | export default MemoryUsageByPod; 34 | -------------------------------------------------------------------------------- /client/namespaceSelection/SelectNamespace.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import Select from 'react-select'; 4 | import { setNamespace, fetchNamespacesList } from '../actions/actions'; 5 | 6 | function SelectNamespace({ 7 | selectedNamespace, 8 | setNamespace, 9 | fetchNamespacesList, 10 | }) { 11 | const [namespaceOptions, setNamespaceOptions] = useState([]); 12 | /* Fetch list of Namespaces from backend API endpoint that connects to prometheus*/ 13 | const getNamespaceList = () => { 14 | fetch('/api/namespaceList') 15 | .then((res) => res.json()) 16 | .then((data) => { 17 | let names = ['All']; 18 | data.items.forEach((item) => { 19 | names.push(item.metadata.name); 20 | }); 21 | fetchNamespacesList(names); 22 | return names; 23 | }) 24 | .then((list) => { 25 | const options = list.map((el) => { 26 | return { value: el, label: el }; 27 | }); 28 | setNamespaceOptions(options); 29 | }) 30 | .catch((error) => console.log(error)); 31 | }; 32 | useEffect(() => { 33 | getNamespaceList(); 34 | }, []); 35 | 36 | function handleNamespaceChange(namespace) { 37 | setNamespace(namespace.value); 38 | } 39 | 40 | return ( 41 | { 13 | setFilter(e.target.value || undefined); 14 | }} 15 | placeholder={''} 16 | /> 17 | ); 18 | } 19 | 20 | //filter for selecting option from list 21 | export function SelectColumnFilter({ 22 | column: { filterValue, setFilter, preFilteredRows, id }, 23 | }) { 24 | const options = React.useMemo(() => { 25 | const options = new Set(); 26 | preFilteredRows.forEach((row) => { 27 | options.add(row.values[id]); 28 | }); 29 | return [...options.values()]; 30 | }, [id, preFilteredRows]); 31 | 32 | // render a multi-select box 33 | return ( 34 | 47 | ); 48 | } 49 | 50 | //fuzzy text filter 51 | export function fuzzyTextFilterFn(rows, id, filterValue) { 52 | return matchSorter(rows, filterValue, { keys: [(row) => row.values[id]] }); 53 | } 54 | 55 | fuzzyTextFilterFn.autoRemove = (val) => !val; 56 | -------------------------------------------------------------------------------- /coverage/clover.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /coverage/coverage-final.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/block-navigation.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var jumpToCode = (function init() { 3 | // Classes of code we would like to highlight in the file view 4 | var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; 5 | 6 | // Elements to highlight in the file listing view 7 | var fileListingElements = ['td.pct.low']; 8 | 9 | // We don't want to select elements that are direct descendants of another match 10 | var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` 11 | 12 | // Selecter that finds elements on the page to which we can jump 13 | var selector = 14 | fileListingElements.join(', ') + 15 | ', ' + 16 | notSelector + 17 | missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` 18 | 19 | // The NodeList of matching elements 20 | var missingCoverageElements = document.querySelectorAll(selector); 21 | 22 | var currentIndex; 23 | 24 | function toggleClass(index) { 25 | missingCoverageElements 26 | .item(currentIndex) 27 | .classList.remove('highlighted'); 28 | missingCoverageElements.item(index).classList.add('highlighted'); 29 | } 30 | 31 | function makeCurrent(index) { 32 | toggleClass(index); 33 | currentIndex = index; 34 | missingCoverageElements.item(index).scrollIntoView({ 35 | behavior: 'smooth', 36 | block: 'center', 37 | inline: 'center' 38 | }); 39 | } 40 | 41 | function goToPrevious() { 42 | var nextIndex = 0; 43 | if (typeof currentIndex !== 'number' || currentIndex === 0) { 44 | nextIndex = missingCoverageElements.length - 1; 45 | } else if (missingCoverageElements.length > 1) { 46 | nextIndex = currentIndex - 1; 47 | } 48 | 49 | makeCurrent(nextIndex); 50 | } 51 | 52 | function goToNext() { 53 | var nextIndex = 0; 54 | 55 | if ( 56 | typeof currentIndex === 'number' && 57 | currentIndex < missingCoverageElements.length - 1 58 | ) { 59 | nextIndex = currentIndex + 1; 60 | } 61 | 62 | makeCurrent(nextIndex); 63 | } 64 | 65 | return function jump(event) { 66 | if ( 67 | document.getElementById('fileSearch') === document.activeElement && 68 | document.activeElement != null 69 | ) { 70 | // if we're currently focused on the search input, we don't want to navigate 71 | return; 72 | } 73 | 74 | switch (event.which) { 75 | case 78: // n 76 | case 74: // j 77 | goToNext(); 78 | break; 79 | case 66: // b 80 | case 75: // k 81 | case 80: // p 82 | goToPrevious(); 83 | break; 84 | } 85 | }; 86 | })(); 87 | window.addEventListener('keydown', jumpToCode); 88 | -------------------------------------------------------------------------------- /coverage/lcov-report/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/coverage/lcov-report/favicon.png -------------------------------------------------------------------------------- /coverage/lcov-report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for All files 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files

23 |
24 | 25 |
26 | Unknown% 27 | Statements 28 | 0/0 29 |
30 | 31 | 32 |
33 | Unknown% 34 | Branches 35 | 0/0 36 |
37 | 38 | 39 |
40 | Unknown% 41 | Functions 42 | 0/0 43 |
44 | 45 | 46 |
47 | Unknown% 48 | Lines 49 | 0/0 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 | 63 |
64 |
65 |
66 |
67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
FileStatementsBranchesFunctionsLines
83 |
84 |
85 | 86 | 91 | 92 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /coverage/lcov.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/coverage/lcov.info -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | armada: 4 | image: 'armadak8s/armada' 5 | container_name: armada 6 | ports: 7 | - '3001:3001' 8 | volumes: 9 | - .:/usr/src/app 10 | - node_modules:/usr/src/app/node_modules 11 | volumes: 12 | node_modules: 13 | -------------------------------------------------------------------------------- /fabric8-rbac.yaml: -------------------------------------------------------------------------------- 1 | # NOTE: The service account `default:default` already exists in k8s cluster. 2 | # You can create a new account following like this: 3 | #--- 4 | #apiVersion: v1 5 | #kind: ServiceAccount 6 | #metadata: 7 | # name: 8 | # namespace: 9 | 10 | --- 11 | apiVersion: rbac.authorization.k8s.io/v1 12 | kind: ClusterRoleBinding 13 | metadata: 14 | name: fabric8-rbac 15 | subjects: 16 | - kind: ServiceAccount 17 | # Reference to upper's `metadata.name` 18 | name: default 19 | # Reference to upper's `metadata.namespace` 20 | namespace: default 21 | roleRef: 22 | kind: ClusterRole 23 | name: cluster-admin 24 | apiGroup: rbac.authorization.k8s.io 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Armada 7 | 11 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /infra/alertmanager/alertmanager.yml: -------------------------------------------------------------------------------- 1 | route: 2 | group_by: [alertname] 3 | receiver: 'mail' # default receiver 4 | repeat_interval: 24h 5 | routes: 6 | - receiver: 'teams' 7 | repeat_interval: 12h 8 | matchers: 9 | - severity="medium" 10 | 11 | - receiver: 'teams' 12 | repeat_interval: 4h 13 | matchers: 14 | - severity="high" 15 | 16 | receivers: 17 | - name: 'mail' 18 | email_configs: 19 | - smarthost: 'yourmailhost.com:465' 20 | auth_username: 'yourmail@yourmailhost.com' 21 | auth_password: 'your mail password' 22 | from: 'yourmail@yourmailhost.com' 23 | to: 'someonesmail@yourmailhost.com' 24 | require_tls: false 25 | 26 | - name: 'teams' 27 | webhook_configs: 28 | - url: 'http://prom2teams:8089' 29 | send_resolved: true 30 | -------------------------------------------------------------------------------- /infra/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | prometheus: 5 | image: prom/prometheus:v2.30.3 6 | ports: 7 | - 9090:9090 8 | volumes: 9 | - ./prometheus:/etc/prometheus 10 | - prometheus-data:/prometheus 11 | command: --web.enable-lifecycle --config.file=/etc/prometheus/prometheus.yml 12 | 13 | grafana: 14 | image: grafana/grafana:8.2.2 15 | ports: 16 | - 3000:3000 17 | restart: unless-stopped 18 | volumes: 19 | - ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources 20 | - grafana-data:/var/lib/grafana 21 | 22 | alertmanager: 23 | image: prom/alertmanager:v0.23.0 24 | restart: unless-stopped 25 | ports: 26 | - '9093:9093' 27 | volumes: 28 | - './alertmanager:/config' 29 | - alertmanager-data:/data 30 | command: --config.file=/config/alertmanager.yml --log.level=debug 31 | 32 | node-exporter: 33 | image: prom/node-exporter:latest 34 | container_name: monitoring_node_exporter 35 | restart: unless-stopped 36 | expose: 37 | - 9100 38 | 39 | volumes: 40 | prometheus-data: 41 | 42 | grafana-data: 43 | 44 | alertmanager-data: 45 | -------------------------------------------------------------------------------- /infra/grafana/provisioning/datasources/prometheus_ds.yml: -------------------------------------------------------------------------------- 1 | datasources: 2 | - name: Prometheus 3 | access: proxy 4 | type: prometheus 5 | url: http://prometheus:9090 6 | isDefault: true 7 | -------------------------------------------------------------------------------- /infra/prometheus/alert.yml: -------------------------------------------------------------------------------- 1 | groups: 2 | - name: DemoAlerts 3 | rules: 4 | - alert: InstanceDown 5 | expr: up{job="services"} < 1 6 | for: 5m 7 | -------------------------------------------------------------------------------- /infra/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 30s 3 | scrape_timeout: 10s 4 | 5 | rule_files: 6 | - alert.yml 7 | 8 | scrape_configs: 9 | - job_name: services 10 | metrics_path: /metrics 11 | static_configs: 12 | - targets: 13 | - 'prometheus:9090' 14 | - 'node-exporter:9100' 15 | - 'host.docker.internal' 16 | 17 | alerting: 18 | alertmanagers: 19 | - scheme: http 20 | static_configs: 21 | - targets: ['alertmanager:9093'] 22 | -------------------------------------------------------------------------------- /manifests/alertmanager-alertmanager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: Alertmanager 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: alert-router 6 | app.kubernetes.io/instance: main 7 | app.kubernetes.io/name: alertmanager 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 0.23.0 10 | name: main 11 | namespace: monitoring 12 | spec: 13 | image: quay.io/prometheus/alertmanager:v0.23.0 14 | nodeSelector: 15 | kubernetes.io/os: linux 16 | podMetadata: 17 | labels: 18 | app.kubernetes.io/component: alert-router 19 | app.kubernetes.io/instance: main 20 | app.kubernetes.io/name: alertmanager 21 | app.kubernetes.io/part-of: kube-prometheus 22 | app.kubernetes.io/version: 0.23.0 23 | replicas: 3 24 | resources: 25 | limits: 26 | cpu: 100m 27 | memory: 100Mi 28 | requests: 29 | cpu: 4m 30 | memory: 100Mi 31 | securityContext: 32 | fsGroup: 2000 33 | runAsNonRoot: true 34 | runAsUser: 1000 35 | serviceAccountName: alertmanager-main 36 | version: 0.23.0 37 | -------------------------------------------------------------------------------- /manifests/alertmanager-podDisruptionBudget.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: policy/v1 2 | kind: PodDisruptionBudget 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: alert-router 6 | app.kubernetes.io/instance: main 7 | app.kubernetes.io/name: alertmanager 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 0.23.0 10 | name: alertmanager-main 11 | namespace: monitoring 12 | spec: 13 | maxUnavailable: 1 14 | selector: 15 | matchLabels: 16 | app.kubernetes.io/component: alert-router 17 | app.kubernetes.io/instance: main 18 | app.kubernetes.io/name: alertmanager 19 | app.kubernetes.io/part-of: kube-prometheus 20 | -------------------------------------------------------------------------------- /manifests/alertmanager-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: alert-router 6 | app.kubernetes.io/instance: main 7 | app.kubernetes.io/name: alertmanager 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 0.23.0 10 | name: alertmanager-main 11 | namespace: monitoring 12 | stringData: 13 | alertmanager.yaml: |- 14 | "global": 15 | "resolve_timeout": "5m" 16 | "inhibit_rules": 17 | - "equal": 18 | - "namespace" 19 | - "alertname" 20 | "source_matchers": 21 | - "severity = critical" 22 | "target_matchers": 23 | - "severity =~ warning|info" 24 | - "equal": 25 | - "namespace" 26 | - "alertname" 27 | "source_matchers": 28 | - "severity = warning" 29 | "target_matchers": 30 | - "severity = info" 31 | "receivers": 32 | - "name": "Default" 33 | - "name": "Watchdog" 34 | - "name": "Critical" 35 | "route": 36 | "group_by": 37 | - "namespace" 38 | "group_interval": "5m" 39 | "group_wait": "30s" 40 | "receiver": "Default" 41 | "repeat_interval": "12h" 42 | "routes": 43 | - "matchers": 44 | - "alertname = Watchdog" 45 | "receiver": "Watchdog" 46 | - "matchers": 47 | - "severity = critical" 48 | "receiver": "Critical" 49 | type: Opaque 50 | -------------------------------------------------------------------------------- /manifests/alertmanager-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: alert-router 6 | app.kubernetes.io/instance: main 7 | app.kubernetes.io/name: alertmanager 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 0.23.0 10 | name: alertmanager-main 11 | namespace: monitoring 12 | spec: 13 | ports: 14 | - name: web 15 | port: 9093 16 | targetPort: web 17 | - name: reloader-web 18 | port: 8080 19 | targetPort: reloader-web 20 | selector: 21 | app.kubernetes.io/component: alert-router 22 | app.kubernetes.io/instance: main 23 | app.kubernetes.io/name: alertmanager 24 | app.kubernetes.io/part-of: kube-prometheus 25 | sessionAffinity: ClientIP 26 | -------------------------------------------------------------------------------- /manifests/alertmanager-serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: alert-router 6 | app.kubernetes.io/instance: main 7 | app.kubernetes.io/name: alertmanager 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 0.23.0 10 | name: alertmanager-main 11 | namespace: monitoring 12 | -------------------------------------------------------------------------------- /manifests/alertmanager-serviceMonitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: alert-router 6 | app.kubernetes.io/instance: main 7 | app.kubernetes.io/name: alertmanager 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 0.23.0 10 | name: alertmanager-main 11 | namespace: monitoring 12 | spec: 13 | endpoints: 14 | - interval: 30s 15 | port: web 16 | - interval: 30s 17 | port: reloader-web 18 | selector: 19 | matchLabels: 20 | app.kubernetes.io/component: alert-router 21 | app.kubernetes.io/instance: main 22 | app.kubernetes.io/name: alertmanager 23 | app.kubernetes.io/part-of: kube-prometheus 24 | -------------------------------------------------------------------------------- /manifests/blackboxExporter-clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: blackbox-exporter 5 | rules: 6 | - apiGroups: 7 | - authentication.k8s.io 8 | resources: 9 | - tokenreviews 10 | verbs: 11 | - create 12 | - apiGroups: 13 | - authorization.k8s.io 14 | resources: 15 | - subjectaccessreviews 16 | verbs: 17 | - create 18 | -------------------------------------------------------------------------------- /manifests/blackboxExporter-clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: blackbox-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.19.0 9 | name: blackbox-exporter 10 | namespace: monitoring 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: blackbox-exporter 15 | subjects: 16 | - kind: ServiceAccount 17 | name: blackbox-exporter 18 | namespace: monitoring 19 | -------------------------------------------------------------------------------- /manifests/blackboxExporter-configuration.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | data: 3 | config.yml: |- 4 | "modules": 5 | "http_2xx": 6 | "http": 7 | "preferred_ip_protocol": "ip4" 8 | "prober": "http" 9 | "http_post_2xx": 10 | "http": 11 | "method": "POST" 12 | "preferred_ip_protocol": "ip4" 13 | "prober": "http" 14 | "irc_banner": 15 | "prober": "tcp" 16 | "tcp": 17 | "preferred_ip_protocol": "ip4" 18 | "query_response": 19 | - "send": "NICK prober" 20 | - "send": "USER prober prober prober :prober" 21 | - "expect": "PING :([^ ]+)" 22 | "send": "PONG ${1}" 23 | - "expect": "^:[^ ]+ 001" 24 | "pop3s_banner": 25 | "prober": "tcp" 26 | "tcp": 27 | "preferred_ip_protocol": "ip4" 28 | "query_response": 29 | - "expect": "^+OK" 30 | "tls": true 31 | "tls_config": 32 | "insecure_skip_verify": false 33 | "ssh_banner": 34 | "prober": "tcp" 35 | "tcp": 36 | "preferred_ip_protocol": "ip4" 37 | "query_response": 38 | - "expect": "^SSH-2.0-" 39 | "tcp_connect": 40 | "prober": "tcp" 41 | "tcp": 42 | "preferred_ip_protocol": "ip4" 43 | kind: ConfigMap 44 | metadata: 45 | labels: 46 | app.kubernetes.io/component: exporter 47 | app.kubernetes.io/name: blackbox-exporter 48 | app.kubernetes.io/part-of: kube-prometheus 49 | app.kubernetes.io/version: 0.19.0 50 | name: blackbox-exporter-configuration 51 | namespace: monitoring 52 | -------------------------------------------------------------------------------- /manifests/blackboxExporter-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: blackbox-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.19.0 9 | name: blackbox-exporter 10 | namespace: monitoring 11 | spec: 12 | replicas: 1 13 | selector: 14 | matchLabels: 15 | app.kubernetes.io/component: exporter 16 | app.kubernetes.io/name: blackbox-exporter 17 | app.kubernetes.io/part-of: kube-prometheus 18 | template: 19 | metadata: 20 | annotations: 21 | kubectl.kubernetes.io/default-container: blackbox-exporter 22 | labels: 23 | app.kubernetes.io/component: exporter 24 | app.kubernetes.io/name: blackbox-exporter 25 | app.kubernetes.io/part-of: kube-prometheus 26 | app.kubernetes.io/version: 0.19.0 27 | spec: 28 | containers: 29 | - args: 30 | - --config.file=/etc/blackbox_exporter/config.yml 31 | - --web.listen-address=:19115 32 | image: quay.io/prometheus/blackbox-exporter:v0.19.0 33 | name: blackbox-exporter 34 | ports: 35 | - containerPort: 19115 36 | name: http 37 | resources: 38 | limits: 39 | cpu: 20m 40 | memory: 40Mi 41 | requests: 42 | cpu: 10m 43 | memory: 20Mi 44 | securityContext: 45 | runAsNonRoot: true 46 | runAsUser: 65534 47 | volumeMounts: 48 | - mountPath: /etc/blackbox_exporter/ 49 | name: config 50 | readOnly: true 51 | - args: 52 | - --webhook-url=http://localhost:19115/-/reload 53 | - --volume-dir=/etc/blackbox_exporter/ 54 | image: jimmidyson/configmap-reload:v0.5.0 55 | name: module-configmap-reloader 56 | resources: 57 | limits: 58 | cpu: 20m 59 | memory: 40Mi 60 | requests: 61 | cpu: 10m 62 | memory: 20Mi 63 | securityContext: 64 | runAsNonRoot: true 65 | runAsUser: 65534 66 | terminationMessagePath: /dev/termination-log 67 | terminationMessagePolicy: FallbackToLogsOnError 68 | volumeMounts: 69 | - mountPath: /etc/blackbox_exporter/ 70 | name: config 71 | readOnly: true 72 | - args: 73 | - --logtostderr 74 | - --secure-listen-address=:9115 75 | - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 76 | - --upstream=http://127.0.0.1:19115/ 77 | image: quay.io/brancz/kube-rbac-proxy:v0.11.0 78 | name: kube-rbac-proxy 79 | ports: 80 | - containerPort: 9115 81 | name: https 82 | resources: 83 | limits: 84 | cpu: 20m 85 | memory: 40Mi 86 | requests: 87 | cpu: 10m 88 | memory: 20Mi 89 | securityContext: 90 | runAsGroup: 65532 91 | runAsNonRoot: true 92 | runAsUser: 65532 93 | nodeSelector: 94 | kubernetes.io/os: linux 95 | serviceAccountName: blackbox-exporter 96 | volumes: 97 | - configMap: 98 | name: blackbox-exporter-configuration 99 | name: config 100 | -------------------------------------------------------------------------------- /manifests/blackboxExporter-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: blackbox-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.19.0 9 | name: blackbox-exporter 10 | namespace: monitoring 11 | spec: 12 | ports: 13 | - name: https 14 | port: 9115 15 | targetPort: https 16 | - name: probe 17 | port: 19115 18 | targetPort: http 19 | selector: 20 | app.kubernetes.io/component: exporter 21 | app.kubernetes.io/name: blackbox-exporter 22 | app.kubernetes.io/part-of: kube-prometheus 23 | -------------------------------------------------------------------------------- /manifests/blackboxExporter-serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: blackbox-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.19.0 9 | name: blackbox-exporter 10 | namespace: monitoring 11 | -------------------------------------------------------------------------------- /manifests/blackboxExporter-serviceMonitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: blackbox-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.19.0 9 | name: blackbox-exporter 10 | namespace: monitoring 11 | spec: 12 | endpoints: 13 | - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 14 | interval: 30s 15 | path: /metrics 16 | port: https 17 | scheme: https 18 | tlsConfig: 19 | insecureSkipVerify: true 20 | selector: 21 | matchLabels: 22 | app.kubernetes.io/component: exporter 23 | app.kubernetes.io/name: blackbox-exporter 24 | app.kubernetes.io/part-of: kube-prometheus 25 | -------------------------------------------------------------------------------- /manifests/grafana-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: grafana 6 | app.kubernetes.io/name: grafana 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 8.3.3 9 | name: grafana-config 10 | namespace: monitoring 11 | stringData: 12 | grafana.ini: | 13 | [date_formats] 14 | default_timezone = UTC 15 | type: Opaque 16 | -------------------------------------------------------------------------------- /manifests/grafana-dashboardDatasources.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: grafana 6 | app.kubernetes.io/name: grafana 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 8.3.3 9 | name: grafana-datasources 10 | namespace: monitoring 11 | stringData: 12 | datasources.yaml: |- 13 | { 14 | "apiVersion": 1, 15 | "datasources": [ 16 | { 17 | "access": "proxy", 18 | "editable": false, 19 | "name": "prometheus", 20 | "orgId": 1, 21 | "type": "prometheus", 22 | "url": "http://prometheus-k8s.monitoring.svc:9090", 23 | "version": 1 24 | } 25 | ] 26 | } 27 | type: Opaque 28 | -------------------------------------------------------------------------------- /manifests/grafana-dashboardSources.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | data: 3 | dashboards.yaml: |- 4 | { 5 | "apiVersion": 1, 6 | "providers": [ 7 | { 8 | "folder": "Default", 9 | "folderUid": "", 10 | "name": "0", 11 | "options": { 12 | "path": "/grafana-dashboard-definitions/0" 13 | }, 14 | "orgId": 1, 15 | "type": "file" 16 | } 17 | ] 18 | } 19 | kind: ConfigMap 20 | metadata: 21 | labels: 22 | app.kubernetes.io/component: grafana 23 | app.kubernetes.io/name: grafana 24 | app.kubernetes.io/part-of: kube-prometheus 25 | app.kubernetes.io/version: 8.3.3 26 | name: grafana-dashboards 27 | namespace: monitoring 28 | -------------------------------------------------------------------------------- /manifests/grafana-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: grafana 6 | app.kubernetes.io/name: grafana 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 8.3.3 9 | name: grafana 10 | namespace: monitoring 11 | spec: 12 | ports: 13 | - name: http 14 | port: 3000 15 | targetPort: http 16 | selector: 17 | app.kubernetes.io/component: grafana 18 | app.kubernetes.io/name: grafana 19 | app.kubernetes.io/part-of: kube-prometheus 20 | -------------------------------------------------------------------------------- /manifests/grafana-serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: grafana 6 | app.kubernetes.io/name: grafana 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 8.3.3 9 | name: grafana 10 | namespace: monitoring 11 | -------------------------------------------------------------------------------- /manifests/grafana-serviceMonitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: grafana 6 | app.kubernetes.io/name: grafana 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 8.3.3 9 | name: grafana 10 | namespace: monitoring 11 | spec: 12 | endpoints: 13 | - interval: 15s 14 | port: http 15 | selector: 16 | matchLabels: 17 | app.kubernetes.io/name: grafana 18 | -------------------------------------------------------------------------------- /manifests/kubePrometheus-prometheusRule.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: PrometheusRule 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: kube-prometheus 7 | app.kubernetes.io/part-of: kube-prometheus 8 | prometheus: k8s 9 | role: alert-rules 10 | name: kube-prometheus-rules 11 | namespace: monitoring 12 | spec: 13 | groups: 14 | - name: general.rules 15 | rules: 16 | - alert: TargetDown 17 | annotations: 18 | description: '{{ printf "%.4g" $value }}% of the {{ $labels.job }}/{{ $labels.service 19 | }} targets in {{ $labels.namespace }} namespace are down.' 20 | runbook_url: https://runbooks.prometheus-operator.dev/runbooks/general/targetdown 21 | summary: One or more targets are unreachable. 22 | expr: 100 * (count(up == 0) BY (job, namespace, service) / count(up) BY (job, 23 | namespace, service)) > 10 24 | for: 10m 25 | labels: 26 | severity: warning 27 | - alert: Watchdog 28 | annotations: 29 | description: | 30 | This is an alert meant to ensure that the entire alerting pipeline is functional. 31 | This alert is always firing, therefore it should always be firing in Alertmanager 32 | and always fire against a receiver. There are integrations with various notification 33 | mechanisms that send a notification when this alert is not firing. For example the 34 | "DeadMansSnitch" integration in PagerDuty. 35 | runbook_url: https://runbooks.prometheus-operator.dev/runbooks/general/watchdog 36 | summary: An alert that should always be firing to certify that Alertmanager 37 | is working properly. 38 | expr: vector(1) 39 | labels: 40 | severity: none 41 | - name: node-network 42 | rules: 43 | - alert: NodeNetworkInterfaceFlapping 44 | annotations: 45 | description: Network interface "{{ $labels.device }}" changing its up status 46 | often on node-exporter {{ $labels.namespace }}/{{ $labels.pod }} 47 | runbook_url: https://runbooks.prometheus-operator.dev/runbooks/general/nodenetworkinterfaceflapping 48 | summary: Network interface is often changing its status 49 | expr: | 50 | changes(node_network_up{job="node-exporter",device!~"veth.+"}[2m]) > 2 51 | for: 2m 52 | labels: 53 | severity: warning 54 | - name: kube-prometheus-node-recording.rules 55 | rules: 56 | - expr: sum(rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal"}[3m])) 57 | BY (instance) 58 | record: instance:node_cpu:rate:sum 59 | - expr: sum(rate(node_network_receive_bytes_total[3m])) BY (instance) 60 | record: instance:node_network_receive_bytes:rate:sum 61 | - expr: sum(rate(node_network_transmit_bytes_total[3m])) BY (instance) 62 | record: instance:node_network_transmit_bytes:rate:sum 63 | - expr: sum(rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal"}[5m])) 64 | WITHOUT (cpu, mode) / ON(instance) GROUP_LEFT() count(sum(node_cpu_seconds_total) 65 | BY (instance, cpu)) BY (instance) 66 | record: instance:node_cpu:ratio 67 | - expr: sum(rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal"}[5m])) 68 | record: cluster:node_cpu:sum_rate5m 69 | - expr: cluster:node_cpu_seconds_total:rate5m / count(sum(node_cpu_seconds_total) 70 | BY (instance, cpu)) 71 | record: cluster:node_cpu:ratio 72 | - name: kube-prometheus-general.rules 73 | rules: 74 | - expr: count without(instance, pod, node) (up == 1) 75 | record: count:up1 76 | - expr: count without(instance, pod, node) (up == 0) 77 | record: count:up0 78 | -------------------------------------------------------------------------------- /manifests/kubeStateMetrics-clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: kube-state-metrics 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 2.3.0 9 | name: kube-state-metrics 10 | rules: 11 | - apiGroups: 12 | - "" 13 | resources: 14 | - configmaps 15 | - secrets 16 | - nodes 17 | - pods 18 | - services 19 | - resourcequotas 20 | - replicationcontrollers 21 | - limitranges 22 | - persistentvolumeclaims 23 | - persistentvolumes 24 | - namespaces 25 | - endpoints 26 | verbs: 27 | - list 28 | - watch 29 | - apiGroups: 30 | - apps 31 | resources: 32 | - statefulsets 33 | - daemonsets 34 | - deployments 35 | - replicasets 36 | verbs: 37 | - list 38 | - watch 39 | - apiGroups: 40 | - batch 41 | resources: 42 | - cronjobs 43 | - jobs 44 | verbs: 45 | - list 46 | - watch 47 | - apiGroups: 48 | - autoscaling 49 | resources: 50 | - horizontalpodautoscalers 51 | verbs: 52 | - list 53 | - watch 54 | - apiGroups: 55 | - authentication.k8s.io 56 | resources: 57 | - tokenreviews 58 | verbs: 59 | - create 60 | - apiGroups: 61 | - authorization.k8s.io 62 | resources: 63 | - subjectaccessreviews 64 | verbs: 65 | - create 66 | - apiGroups: 67 | - policy 68 | resources: 69 | - poddisruptionbudgets 70 | verbs: 71 | - list 72 | - watch 73 | - apiGroups: 74 | - certificates.k8s.io 75 | resources: 76 | - certificatesigningrequests 77 | verbs: 78 | - list 79 | - watch 80 | - apiGroups: 81 | - storage.k8s.io 82 | resources: 83 | - storageclasses 84 | - volumeattachments 85 | verbs: 86 | - list 87 | - watch 88 | - apiGroups: 89 | - admissionregistration.k8s.io 90 | resources: 91 | - mutatingwebhookconfigurations 92 | - validatingwebhookconfigurations 93 | verbs: 94 | - list 95 | - watch 96 | - apiGroups: 97 | - networking.k8s.io 98 | resources: 99 | - networkpolicies 100 | - ingresses 101 | verbs: 102 | - list 103 | - watch 104 | - apiGroups: 105 | - coordination.k8s.io 106 | resources: 107 | - leases 108 | verbs: 109 | - list 110 | - watch 111 | -------------------------------------------------------------------------------- /manifests/kubeStateMetrics-clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: kube-state-metrics 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 2.3.0 9 | name: kube-state-metrics 10 | roleRef: 11 | apiGroup: rbac.authorization.k8s.io 12 | kind: ClusterRole 13 | name: kube-state-metrics 14 | subjects: 15 | - kind: ServiceAccount 16 | name: kube-state-metrics 17 | namespace: monitoring 18 | -------------------------------------------------------------------------------- /manifests/kubeStateMetrics-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: kube-state-metrics 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 2.3.0 9 | name: kube-state-metrics 10 | namespace: monitoring 11 | spec: 12 | replicas: 1 13 | selector: 14 | matchLabels: 15 | app.kubernetes.io/component: exporter 16 | app.kubernetes.io/name: kube-state-metrics 17 | app.kubernetes.io/part-of: kube-prometheus 18 | template: 19 | metadata: 20 | annotations: 21 | kubectl.kubernetes.io/default-container: kube-state-metrics 22 | labels: 23 | app.kubernetes.io/component: exporter 24 | app.kubernetes.io/name: kube-state-metrics 25 | app.kubernetes.io/part-of: kube-prometheus 26 | app.kubernetes.io/version: 2.3.0 27 | spec: 28 | containers: 29 | - args: 30 | - --host=127.0.0.1 31 | - --port=8081 32 | - --telemetry-host=127.0.0.1 33 | - --telemetry-port=8082 34 | image: k8s.gcr.io/kube-state-metrics/kube-state-metrics:v2.3.0 35 | name: kube-state-metrics 36 | resources: 37 | limits: 38 | cpu: 100m 39 | memory: 250Mi 40 | requests: 41 | cpu: 10m 42 | memory: 190Mi 43 | securityContext: 44 | runAsUser: 65534 45 | - args: 46 | - --logtostderr 47 | - --secure-listen-address=:8443 48 | - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 49 | - --upstream=http://127.0.0.1:8081/ 50 | image: quay.io/brancz/kube-rbac-proxy:v0.11.0 51 | name: kube-rbac-proxy-main 52 | ports: 53 | - containerPort: 8443 54 | name: https-main 55 | resources: 56 | limits: 57 | cpu: 40m 58 | memory: 40Mi 59 | requests: 60 | cpu: 20m 61 | memory: 20Mi 62 | securityContext: 63 | runAsGroup: 65532 64 | runAsNonRoot: true 65 | runAsUser: 65532 66 | - args: 67 | - --logtostderr 68 | - --secure-listen-address=:9443 69 | - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 70 | - --upstream=http://127.0.0.1:8082/ 71 | image: quay.io/brancz/kube-rbac-proxy:v0.11.0 72 | name: kube-rbac-proxy-self 73 | ports: 74 | - containerPort: 9443 75 | name: https-self 76 | resources: 77 | limits: 78 | cpu: 20m 79 | memory: 40Mi 80 | requests: 81 | cpu: 10m 82 | memory: 20Mi 83 | securityContext: 84 | runAsGroup: 65532 85 | runAsNonRoot: true 86 | runAsUser: 65532 87 | nodeSelector: 88 | kubernetes.io/os: linux 89 | serviceAccountName: kube-state-metrics 90 | -------------------------------------------------------------------------------- /manifests/kubeStateMetrics-prometheusRule.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: PrometheusRule 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: kube-state-metrics 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 2.3.0 9 | prometheus: k8s 10 | role: alert-rules 11 | name: kube-state-metrics-rules 12 | namespace: monitoring 13 | spec: 14 | groups: 15 | - name: kube-state-metrics 16 | rules: 17 | - alert: KubeStateMetricsListErrors 18 | annotations: 19 | description: kube-state-metrics is experiencing errors at an elevated rate 20 | in list operations. This is likely causing it to not be able to expose metrics 21 | about Kubernetes objects correctly or at all. 22 | runbook_url: https://runbooks.prometheus-operator.dev/runbooks/kube-state-metrics/kubestatemetricslisterrors 23 | summary: kube-state-metrics is experiencing errors in list operations. 24 | expr: | 25 | (sum(rate(kube_state_metrics_list_total{job="kube-state-metrics",result="error"}[5m])) 26 | / 27 | sum(rate(kube_state_metrics_list_total{job="kube-state-metrics"}[5m]))) 28 | > 0.01 29 | for: 15m 30 | labels: 31 | severity: critical 32 | - alert: KubeStateMetricsWatchErrors 33 | annotations: 34 | description: kube-state-metrics is experiencing errors at an elevated rate 35 | in watch operations. This is likely causing it to not be able to expose 36 | metrics about Kubernetes objects correctly or at all. 37 | runbook_url: https://runbooks.prometheus-operator.dev/runbooks/kube-state-metrics/kubestatemetricswatcherrors 38 | summary: kube-state-metrics is experiencing errors in watch operations. 39 | expr: | 40 | (sum(rate(kube_state_metrics_watch_total{job="kube-state-metrics",result="error"}[5m])) 41 | / 42 | sum(rate(kube_state_metrics_watch_total{job="kube-state-metrics"}[5m]))) 43 | > 0.01 44 | for: 15m 45 | labels: 46 | severity: critical 47 | - alert: KubeStateMetricsShardingMismatch 48 | annotations: 49 | description: kube-state-metrics pods are running with different --total-shards 50 | configuration, some Kubernetes objects may be exposed multiple times or 51 | not exposed at all. 52 | runbook_url: https://runbooks.prometheus-operator.dev/runbooks/kube-state-metrics/kubestatemetricsshardingmismatch 53 | summary: kube-state-metrics sharding is misconfigured. 54 | expr: | 55 | stdvar (kube_state_metrics_total_shards{job="kube-state-metrics"}) != 0 56 | for: 15m 57 | labels: 58 | severity: critical 59 | - alert: KubeStateMetricsShardsMissing 60 | annotations: 61 | description: kube-state-metrics shards are missing, some Kubernetes objects 62 | are not being exposed. 63 | runbook_url: https://runbooks.prometheus-operator.dev/runbooks/kube-state-metrics/kubestatemetricsshardsmissing 64 | summary: kube-state-metrics shards are missing. 65 | expr: | 66 | 2^max(kube_state_metrics_total_shards{job="kube-state-metrics"}) - 1 67 | - 68 | sum( 2 ^ max by (shard_ordinal) (kube_state_metrics_shard_ordinal{job="kube-state-metrics"}) ) 69 | != 0 70 | for: 15m 71 | labels: 72 | severity: critical 73 | -------------------------------------------------------------------------------- /manifests/kubeStateMetrics-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: kube-state-metrics 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 2.3.0 9 | name: kube-state-metrics 10 | namespace: monitoring 11 | spec: 12 | clusterIP: None 13 | ports: 14 | - name: https-main 15 | port: 8443 16 | targetPort: https-main 17 | - name: https-self 18 | port: 9443 19 | targetPort: https-self 20 | selector: 21 | app.kubernetes.io/component: exporter 22 | app.kubernetes.io/name: kube-state-metrics 23 | app.kubernetes.io/part-of: kube-prometheus 24 | -------------------------------------------------------------------------------- /manifests/kubeStateMetrics-serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: kube-state-metrics 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 2.3.0 9 | name: kube-state-metrics 10 | namespace: monitoring 11 | -------------------------------------------------------------------------------- /manifests/kubeStateMetrics-serviceMonitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: kube-state-metrics 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 2.3.0 9 | name: kube-state-metrics 10 | namespace: monitoring 11 | spec: 12 | endpoints: 13 | - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 14 | honorLabels: true 15 | interval: 30s 16 | port: https-main 17 | relabelings: 18 | - action: labeldrop 19 | regex: (pod|service|endpoint|namespace) 20 | scheme: https 21 | scrapeTimeout: 30s 22 | tlsConfig: 23 | insecureSkipVerify: true 24 | - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 25 | interval: 30s 26 | port: https-self 27 | scheme: https 28 | tlsConfig: 29 | insecureSkipVerify: true 30 | jobLabel: app.kubernetes.io/name 31 | selector: 32 | matchLabels: 33 | app.kubernetes.io/component: exporter 34 | app.kubernetes.io/name: kube-state-metrics 35 | app.kubernetes.io/part-of: kube-prometheus 36 | -------------------------------------------------------------------------------- /manifests/kubernetesControlPlane-serviceMonitorCoreDNS.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: coredns 6 | app.kubernetes.io/part-of: kube-prometheus 7 | name: coredns 8 | namespace: monitoring 9 | spec: 10 | endpoints: 11 | - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 12 | interval: 15s 13 | metricRelabelings: 14 | - action: drop 15 | regex: coredns_cache_misses_total 16 | sourceLabels: 17 | - __name__ 18 | port: metrics 19 | jobLabel: app.kubernetes.io/name 20 | namespaceSelector: 21 | matchNames: 22 | - kube-system 23 | selector: 24 | matchLabels: 25 | k8s-app: kube-dns 26 | -------------------------------------------------------------------------------- /manifests/kubernetesControlPlane-serviceMonitorKubeScheduler.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: kube-scheduler 6 | app.kubernetes.io/part-of: kube-prometheus 7 | name: kube-scheduler 8 | namespace: monitoring 9 | spec: 10 | endpoints: 11 | - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 12 | interval: 30s 13 | port: https-metrics 14 | scheme: https 15 | tlsConfig: 16 | insecureSkipVerify: true 17 | jobLabel: app.kubernetes.io/name 18 | namespaceSelector: 19 | matchNames: 20 | - kube-system 21 | selector: 22 | matchLabels: 23 | app.kubernetes.io/name: kube-scheduler 24 | -------------------------------------------------------------------------------- /manifests/nodeExporter-clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: node-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 1.3.1 9 | name: node-exporter 10 | namespace: monitoring 11 | rules: 12 | - apiGroups: 13 | - authentication.k8s.io 14 | resources: 15 | - tokenreviews 16 | verbs: 17 | - create 18 | - apiGroups: 19 | - authorization.k8s.io 20 | resources: 21 | - subjectaccessreviews 22 | verbs: 23 | - create 24 | -------------------------------------------------------------------------------- /manifests/nodeExporter-clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: node-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 1.3.1 9 | name: node-exporter 10 | namespace: monitoring 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: node-exporter 15 | subjects: 16 | - kind: ServiceAccount 17 | name: node-exporter 18 | namespace: monitoring 19 | -------------------------------------------------------------------------------- /manifests/nodeExporter-daemonset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: node-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 1.3.1 9 | name: node-exporter 10 | namespace: monitoring 11 | spec: 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/component: exporter 15 | app.kubernetes.io/name: node-exporter 16 | app.kubernetes.io/part-of: kube-prometheus 17 | template: 18 | metadata: 19 | annotations: 20 | kubectl.kubernetes.io/default-container: node-exporter 21 | labels: 22 | app.kubernetes.io/component: exporter 23 | app.kubernetes.io/name: node-exporter 24 | app.kubernetes.io/part-of: kube-prometheus 25 | app.kubernetes.io/version: 1.3.1 26 | spec: 27 | containers: 28 | - args: 29 | - --web.listen-address=127.0.0.1:9100 30 | - --path.sysfs=/host/sys 31 | - --path.rootfs=/host/root 32 | - --no-collector.wifi 33 | - --no-collector.hwmon 34 | - --collector.filesystem.mount-points-exclude=^/(dev|proc|sys|run/k3s/containerd/.+|var/lib/docker/.+|var/lib/kubelet/pods/.+)($|/) 35 | - --collector.netclass.ignored-devices=^(veth.*|[a-f0-9]{15})$ 36 | - --collector.netdev.device-exclude=^(veth.*|[a-f0-9]{15})$ 37 | image: quay.io/prometheus/node-exporter:v1.3.1 38 | name: node-exporter 39 | resources: 40 | limits: 41 | cpu: 250m 42 | memory: 180Mi 43 | requests: 44 | cpu: 102m 45 | memory: 180Mi 46 | volumeMounts: 47 | - mountPath: /host/sys 48 | mountPropagation: HostToContainer 49 | name: sys 50 | readOnly: true 51 | - mountPath: /host/root 52 | mountPropagation: HostToContainer 53 | name: root 54 | readOnly: true 55 | - args: 56 | - --logtostderr 57 | - --secure-listen-address=[$(IP)]:9100 58 | - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 59 | - --upstream=http://127.0.0.1:9100/ 60 | env: 61 | - name: IP 62 | valueFrom: 63 | fieldRef: 64 | fieldPath: status.podIP 65 | image: quay.io/brancz/kube-rbac-proxy:v0.11.0 66 | name: kube-rbac-proxy 67 | ports: 68 | - containerPort: 9100 69 | hostPort: 9100 70 | name: https 71 | resources: 72 | limits: 73 | cpu: 20m 74 | memory: 40Mi 75 | requests: 76 | cpu: 10m 77 | memory: 20Mi 78 | securityContext: 79 | runAsGroup: 65532 80 | runAsNonRoot: true 81 | runAsUser: 65532 82 | hostNetwork: true 83 | hostPID: true 84 | nodeSelector: 85 | kubernetes.io/os: linux 86 | securityContext: 87 | runAsNonRoot: true 88 | runAsUser: 65534 89 | serviceAccountName: node-exporter 90 | tolerations: 91 | - operator: Exists 92 | volumes: 93 | - hostPath: 94 | path: /sys 95 | name: sys 96 | - hostPath: 97 | path: / 98 | name: root 99 | updateStrategy: 100 | rollingUpdate: 101 | maxUnavailable: 10% 102 | type: RollingUpdate 103 | -------------------------------------------------------------------------------- /manifests/nodeExporter-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: node-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 1.3.1 9 | name: node-exporter 10 | namespace: monitoring 11 | spec: 12 | clusterIP: None 13 | ports: 14 | - name: https 15 | port: 9100 16 | targetPort: https 17 | selector: 18 | app.kubernetes.io/component: exporter 19 | app.kubernetes.io/name: node-exporter 20 | app.kubernetes.io/part-of: kube-prometheus 21 | -------------------------------------------------------------------------------- /manifests/nodeExporter-serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: node-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 1.3.1 9 | name: node-exporter 10 | namespace: monitoring 11 | -------------------------------------------------------------------------------- /manifests/nodeExporter-serviceMonitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: exporter 6 | app.kubernetes.io/name: node-exporter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 1.3.1 9 | name: node-exporter 10 | namespace: monitoring 11 | spec: 12 | endpoints: 13 | - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 14 | interval: 15s 15 | port: https 16 | relabelings: 17 | - action: replace 18 | regex: (.*) 19 | replacement: $1 20 | sourceLabels: 21 | - __meta_kubernetes_pod_node_name 22 | targetLabel: instance 23 | scheme: https 24 | tlsConfig: 25 | insecureSkipVerify: true 26 | jobLabel: app.kubernetes.io/name 27 | selector: 28 | matchLabels: 29 | app.kubernetes.io/component: exporter 30 | app.kubernetes.io/name: node-exporter 31 | app.kubernetes.io/part-of: kube-prometheus 32 | -------------------------------------------------------------------------------- /manifests/prometheus-clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: prometheus 6 | app.kubernetes.io/instance: k8s 7 | app.kubernetes.io/name: prometheus 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 2.32.1 10 | name: prometheus-k8s 11 | namespace: monitoring 12 | rules: 13 | - apiGroups: 14 | - "" 15 | resources: 16 | - nodes/metrics 17 | verbs: 18 | - get 19 | - nonResourceURLs: 20 | - /metrics 21 | verbs: 22 | - get 23 | -------------------------------------------------------------------------------- /manifests/prometheus-clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: prometheus 6 | app.kubernetes.io/instance: k8s 7 | app.kubernetes.io/name: prometheus 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 2.32.1 10 | name: prometheus-k8s 11 | namespace: monitoring 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: ClusterRole 15 | name: prometheus-k8s 16 | subjects: 17 | - kind: ServiceAccount 18 | name: prometheus-k8s 19 | namespace: monitoring 20 | -------------------------------------------------------------------------------- /manifests/prometheus-podDisruptionBudget.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: policy/v1 2 | kind: PodDisruptionBudget 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: prometheus 6 | app.kubernetes.io/instance: k8s 7 | app.kubernetes.io/name: prometheus 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 2.32.1 10 | name: prometheus-k8s 11 | namespace: monitoring 12 | spec: 13 | minAvailable: 1 14 | selector: 15 | matchLabels: 16 | app.kubernetes.io/component: prometheus 17 | app.kubernetes.io/instance: k8s 18 | app.kubernetes.io/name: prometheus 19 | app.kubernetes.io/part-of: kube-prometheus 20 | -------------------------------------------------------------------------------- /manifests/prometheus-prometheus.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: Prometheus 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: prometheus 6 | app.kubernetes.io/instance: k8s 7 | app.kubernetes.io/name: prometheus 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 2.32.1 10 | name: k8s 11 | namespace: monitoring 12 | spec: 13 | alerting: 14 | alertmanagers: 15 | - apiVersion: v2 16 | name: alertmanager-main 17 | namespace: monitoring 18 | port: web 19 | enableFeatures: [] 20 | externalLabels: {} 21 | image: quay.io/prometheus/prometheus:v2.32.1 22 | nodeSelector: 23 | kubernetes.io/os: linux 24 | podMetadata: 25 | labels: 26 | app.kubernetes.io/component: prometheus 27 | app.kubernetes.io/instance: k8s 28 | app.kubernetes.io/name: prometheus 29 | app.kubernetes.io/part-of: kube-prometheus 30 | app.kubernetes.io/version: 2.32.1 31 | podMonitorNamespaceSelector: {} 32 | podMonitorSelector: {} 33 | probeNamespaceSelector: {} 34 | probeSelector: {} 35 | replicas: 2 36 | resources: 37 | requests: 38 | memory: 400Mi 39 | ruleNamespaceSelector: {} 40 | ruleSelector: {} 41 | securityContext: 42 | fsGroup: 2000 43 | runAsNonRoot: true 44 | runAsUser: 1000 45 | serviceAccountName: prometheus-k8s 46 | serviceMonitorNamespaceSelector: {} 47 | serviceMonitorSelector: {} 48 | version: 2.32.1 49 | -------------------------------------------------------------------------------- /manifests/prometheus-roleBindingConfig.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: prometheus 6 | app.kubernetes.io/instance: k8s 7 | app.kubernetes.io/name: prometheus 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 2.32.1 10 | name: prometheus-k8s-config 11 | namespace: monitoring 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: Role 15 | name: prometheus-k8s-config 16 | subjects: 17 | - kind: ServiceAccount 18 | name: prometheus-k8s 19 | namespace: monitoring 20 | -------------------------------------------------------------------------------- /manifests/prometheus-roleBindingSpecificNamespaces.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | items: 3 | - apiVersion: rbac.authorization.k8s.io/v1 4 | kind: RoleBinding 5 | metadata: 6 | labels: 7 | app.kubernetes.io/component: prometheus 8 | app.kubernetes.io/instance: k8s 9 | app.kubernetes.io/name: prometheus 10 | app.kubernetes.io/part-of: kube-prometheus 11 | app.kubernetes.io/version: 2.32.1 12 | name: prometheus-k8s 13 | namespace: default 14 | roleRef: 15 | apiGroup: rbac.authorization.k8s.io 16 | kind: Role 17 | name: prometheus-k8s 18 | subjects: 19 | - kind: ServiceAccount 20 | name: prometheus-k8s 21 | namespace: monitoring 22 | - apiVersion: rbac.authorization.k8s.io/v1 23 | kind: RoleBinding 24 | metadata: 25 | labels: 26 | app.kubernetes.io/component: prometheus 27 | app.kubernetes.io/instance: k8s 28 | app.kubernetes.io/name: prometheus 29 | app.kubernetes.io/part-of: kube-prometheus 30 | app.kubernetes.io/version: 2.32.1 31 | name: prometheus-k8s 32 | namespace: kube-system 33 | roleRef: 34 | apiGroup: rbac.authorization.k8s.io 35 | kind: Role 36 | name: prometheus-k8s 37 | subjects: 38 | - kind: ServiceAccount 39 | name: prometheus-k8s 40 | namespace: monitoring 41 | - apiVersion: rbac.authorization.k8s.io/v1 42 | kind: RoleBinding 43 | metadata: 44 | labels: 45 | app.kubernetes.io/component: prometheus 46 | app.kubernetes.io/instance: k8s 47 | app.kubernetes.io/name: prometheus 48 | app.kubernetes.io/part-of: kube-prometheus 49 | app.kubernetes.io/version: 2.32.1 50 | name: prometheus-k8s 51 | namespace: monitoring 52 | roleRef: 53 | apiGroup: rbac.authorization.k8s.io 54 | kind: Role 55 | name: prometheus-k8s 56 | subjects: 57 | - kind: ServiceAccount 58 | name: prometheus-k8s 59 | namespace: monitoring 60 | kind: RoleBindingList 61 | -------------------------------------------------------------------------------- /manifests/prometheus-roleConfig.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: prometheus 6 | app.kubernetes.io/instance: k8s 7 | app.kubernetes.io/name: prometheus 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 2.32.1 10 | name: prometheus-k8s-config 11 | namespace: monitoring 12 | rules: 13 | - apiGroups: 14 | - "" 15 | resources: 16 | - configmaps 17 | verbs: 18 | - get 19 | -------------------------------------------------------------------------------- /manifests/prometheus-roleSpecificNamespaces.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | items: 3 | - apiVersion: rbac.authorization.k8s.io/v1 4 | kind: Role 5 | metadata: 6 | labels: 7 | app.kubernetes.io/component: prometheus 8 | app.kubernetes.io/instance: k8s 9 | app.kubernetes.io/name: prometheus 10 | app.kubernetes.io/part-of: kube-prometheus 11 | app.kubernetes.io/version: 2.32.1 12 | name: prometheus-k8s 13 | namespace: default 14 | rules: 15 | - apiGroups: 16 | - "" 17 | resources: 18 | - services 19 | - endpoints 20 | - pods 21 | verbs: 22 | - get 23 | - list 24 | - watch 25 | - apiGroups: 26 | - extensions 27 | resources: 28 | - ingresses 29 | verbs: 30 | - get 31 | - list 32 | - watch 33 | - apiGroups: 34 | - networking.k8s.io 35 | resources: 36 | - ingresses 37 | verbs: 38 | - get 39 | - list 40 | - watch 41 | - apiVersion: rbac.authorization.k8s.io/v1 42 | kind: Role 43 | metadata: 44 | labels: 45 | app.kubernetes.io/component: prometheus 46 | app.kubernetes.io/instance: k8s 47 | app.kubernetes.io/name: prometheus 48 | app.kubernetes.io/part-of: kube-prometheus 49 | app.kubernetes.io/version: 2.32.1 50 | name: prometheus-k8s 51 | namespace: kube-system 52 | rules: 53 | - apiGroups: 54 | - "" 55 | resources: 56 | - services 57 | - endpoints 58 | - pods 59 | verbs: 60 | - get 61 | - list 62 | - watch 63 | - apiGroups: 64 | - extensions 65 | resources: 66 | - ingresses 67 | verbs: 68 | - get 69 | - list 70 | - watch 71 | - apiGroups: 72 | - networking.k8s.io 73 | resources: 74 | - ingresses 75 | verbs: 76 | - get 77 | - list 78 | - watch 79 | - apiVersion: rbac.authorization.k8s.io/v1 80 | kind: Role 81 | metadata: 82 | labels: 83 | app.kubernetes.io/component: prometheus 84 | app.kubernetes.io/instance: k8s 85 | app.kubernetes.io/name: prometheus 86 | app.kubernetes.io/part-of: kube-prometheus 87 | app.kubernetes.io/version: 2.32.1 88 | name: prometheus-k8s 89 | namespace: monitoring 90 | rules: 91 | - apiGroups: 92 | - "" 93 | resources: 94 | - services 95 | - endpoints 96 | - pods 97 | verbs: 98 | - get 99 | - list 100 | - watch 101 | - apiGroups: 102 | - extensions 103 | resources: 104 | - ingresses 105 | verbs: 106 | - get 107 | - list 108 | - watch 109 | - apiGroups: 110 | - networking.k8s.io 111 | resources: 112 | - ingresses 113 | verbs: 114 | - get 115 | - list 116 | - watch 117 | kind: RoleList 118 | -------------------------------------------------------------------------------- /manifests/prometheus-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: prometheus 6 | app.kubernetes.io/instance: k8s 7 | app.kubernetes.io/name: prometheus 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 2.32.1 10 | name: prometheus-k8s 11 | namespace: monitoring 12 | spec: 13 | ports: 14 | - name: web 15 | port: 9090 16 | targetPort: web 17 | - name: reloader-web 18 | port: 8080 19 | targetPort: reloader-web 20 | selector: 21 | app.kubernetes.io/component: prometheus 22 | app.kubernetes.io/instance: k8s 23 | app.kubernetes.io/name: prometheus 24 | app.kubernetes.io/part-of: kube-prometheus 25 | sessionAffinity: ClientIP 26 | -------------------------------------------------------------------------------- /manifests/prometheus-serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: prometheus 6 | app.kubernetes.io/instance: k8s 7 | app.kubernetes.io/name: prometheus 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 2.32.1 10 | name: prometheus-k8s 11 | namespace: monitoring 12 | -------------------------------------------------------------------------------- /manifests/prometheus-serviceMonitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: prometheus 6 | app.kubernetes.io/instance: k8s 7 | app.kubernetes.io/name: prometheus 8 | app.kubernetes.io/part-of: kube-prometheus 9 | app.kubernetes.io/version: 2.32.1 10 | name: prometheus-k8s 11 | namespace: monitoring 12 | spec: 13 | endpoints: 14 | - interval: 30s 15 | port: web 16 | - interval: 30s 17 | port: reloader-web 18 | selector: 19 | matchLabels: 20 | app.kubernetes.io/component: prometheus 21 | app.kubernetes.io/instance: k8s 22 | app.kubernetes.io/name: prometheus 23 | app.kubernetes.io/part-of: kube-prometheus 24 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-apiService.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiregistration.k8s.io/v1 2 | kind: APIService 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: v1beta1.metrics.k8s.io 10 | spec: 11 | group: metrics.k8s.io 12 | groupPriorityMinimum: 100 13 | insecureSkipTLSVerify: true 14 | service: 15 | name: prometheus-adapter 16 | namespace: monitoring 17 | version: v1beta1 18 | versionPriority: 100 19 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: prometheus-adapter 10 | namespace: monitoring 11 | rules: 12 | - apiGroups: 13 | - "" 14 | resources: 15 | - nodes 16 | - namespaces 17 | - pods 18 | - services 19 | verbs: 20 | - get 21 | - list 22 | - watch 23 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-clusterRoleAggregatedMetricsReader.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 10 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 11 | rbac.authorization.k8s.io/aggregate-to-view: "true" 12 | name: system:aggregated-metrics-reader 13 | namespace: monitoring 14 | rules: 15 | - apiGroups: 16 | - metrics.k8s.io 17 | resources: 18 | - pods 19 | - nodes 20 | verbs: 21 | - get 22 | - list 23 | - watch 24 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: prometheus-adapter 10 | namespace: monitoring 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: prometheus-adapter 15 | subjects: 16 | - kind: ServiceAccount 17 | name: prometheus-adapter 18 | namespace: monitoring 19 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-clusterRoleBindingDelegator.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: resource-metrics:system:auth-delegator 10 | namespace: monitoring 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: system:auth-delegator 15 | subjects: 16 | - kind: ServiceAccount 17 | name: prometheus-adapter 18 | namespace: monitoring 19 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-clusterRoleServerResources.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: resource-metrics-server-resources 10 | namespace: monitoring 11 | rules: 12 | - apiGroups: 13 | - metrics.k8s.io 14 | resources: 15 | - '*' 16 | verbs: 17 | - '*' 18 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-configMap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | data: 3 | config.yaml: |- 4 | "resourceRules": 5 | "cpu": 6 | "containerLabel": "container" 7 | "containerQuery": | 8 | sum by (<<.GroupBy>>) ( 9 | irate ( 10 | container_cpu_usage_seconds_total{<<.LabelMatchers>>,container!="",pod!=""}[120s] 11 | ) 12 | ) 13 | "nodeQuery": | 14 | sum by (<<.GroupBy>>) ( 15 | 1 - irate( 16 | node_cpu_seconds_total{mode="idle"}[60s] 17 | ) 18 | * on(namespace, pod) group_left(node) ( 19 | node_namespace_pod:kube_pod_info:{<<.LabelMatchers>>} 20 | ) 21 | ) 22 | or sum by (<<.GroupBy>>) ( 23 | 1 - irate( 24 | windows_cpu_time_total{mode="idle", job="windows-exporter",<<.LabelMatchers>>}[4m] 25 | ) 26 | ) 27 | "resources": 28 | "overrides": 29 | "namespace": 30 | "resource": "namespace" 31 | "node": 32 | "resource": "node" 33 | "pod": 34 | "resource": "pod" 35 | "memory": 36 | "containerLabel": "container" 37 | "containerQuery": | 38 | sum by (<<.GroupBy>>) ( 39 | container_memory_working_set_bytes{<<.LabelMatchers>>,container!="",pod!=""} 40 | ) 41 | "nodeQuery": | 42 | sum by (<<.GroupBy>>) ( 43 | node_memory_MemTotal_bytes{job="node-exporter",<<.LabelMatchers>>} 44 | - 45 | node_memory_MemAvailable_bytes{job="node-exporter",<<.LabelMatchers>>} 46 | ) 47 | or sum by (<<.GroupBy>>) ( 48 | windows_cs_physical_memory_bytes{job="windows-exporter",<<.LabelMatchers>>} 49 | - 50 | windows_memory_available_bytes{job="windows-exporter",<<.LabelMatchers>>} 51 | ) 52 | "resources": 53 | "overrides": 54 | "instance": 55 | "resource": "node" 56 | "namespace": 57 | "resource": "namespace" 58 | "pod": 59 | "resource": "pod" 60 | "window": "5m" 61 | kind: ConfigMap 62 | metadata: 63 | labels: 64 | app.kubernetes.io/component: metrics-adapter 65 | app.kubernetes.io/name: prometheus-adapter 66 | app.kubernetes.io/part-of: kube-prometheus 67 | app.kubernetes.io/version: 0.9.1 68 | name: adapter-config 69 | namespace: monitoring 70 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: prometheus-adapter 10 | namespace: monitoring 11 | spec: 12 | replicas: 2 13 | selector: 14 | matchLabels: 15 | app.kubernetes.io/component: metrics-adapter 16 | app.kubernetes.io/name: prometheus-adapter 17 | app.kubernetes.io/part-of: kube-prometheus 18 | strategy: 19 | rollingUpdate: 20 | maxSurge: 1 21 | maxUnavailable: 1 22 | template: 23 | metadata: 24 | labels: 25 | app.kubernetes.io/component: metrics-adapter 26 | app.kubernetes.io/name: prometheus-adapter 27 | app.kubernetes.io/part-of: kube-prometheus 28 | app.kubernetes.io/version: 0.9.1 29 | spec: 30 | containers: 31 | - args: 32 | - --cert-dir=/var/run/serving-cert 33 | - --config=/etc/adapter/config.yaml 34 | - --logtostderr=true 35 | - --metrics-relist-interval=1m 36 | - --prometheus-url=http://prometheus-k8s.monitoring.svc:9090/ 37 | - --secure-port=6443 38 | - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA 39 | image: k8s.gcr.io/prometheus-adapter/prometheus-adapter:v0.9.1 40 | name: prometheus-adapter 41 | ports: 42 | - containerPort: 6443 43 | resources: 44 | limits: 45 | cpu: 250m 46 | memory: 180Mi 47 | requests: 48 | cpu: 102m 49 | memory: 180Mi 50 | volumeMounts: 51 | - mountPath: /tmp 52 | name: tmpfs 53 | readOnly: false 54 | - mountPath: /var/run/serving-cert 55 | name: volume-serving-cert 56 | readOnly: false 57 | - mountPath: /etc/adapter 58 | name: config 59 | readOnly: false 60 | nodeSelector: 61 | kubernetes.io/os: linux 62 | serviceAccountName: prometheus-adapter 63 | volumes: 64 | - emptyDir: {} 65 | name: tmpfs 66 | - emptyDir: {} 67 | name: volume-serving-cert 68 | - configMap: 69 | name: adapter-config 70 | name: config 71 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-podDisruptionBudget.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: policy/v1 2 | kind: PodDisruptionBudget 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: prometheus-adapter 10 | namespace: monitoring 11 | spec: 12 | minAvailable: 1 13 | selector: 14 | matchLabels: 15 | app.kubernetes.io/component: metrics-adapter 16 | app.kubernetes.io/name: prometheus-adapter 17 | app.kubernetes.io/part-of: kube-prometheus 18 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-roleBindingAuthReader.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: resource-metrics-auth-reader 10 | namespace: kube-system 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: Role 14 | name: extension-apiserver-authentication-reader 15 | subjects: 16 | - kind: ServiceAccount 17 | name: prometheus-adapter 18 | namespace: monitoring 19 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: prometheus-adapter 10 | namespace: monitoring 11 | spec: 12 | ports: 13 | - name: https 14 | port: 443 15 | targetPort: 6443 16 | selector: 17 | app.kubernetes.io/component: metrics-adapter 18 | app.kubernetes.io/name: prometheus-adapter 19 | app.kubernetes.io/part-of: kube-prometheus 20 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: prometheus-adapter 10 | namespace: monitoring 11 | -------------------------------------------------------------------------------- /manifests/prometheusAdapter-serviceMonitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: metrics-adapter 6 | app.kubernetes.io/name: prometheus-adapter 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.9.1 9 | name: prometheus-adapter 10 | namespace: monitoring 11 | spec: 12 | endpoints: 13 | - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 14 | interval: 30s 15 | metricRelabelings: 16 | - action: drop 17 | regex: (apiserver_client_certificate_.*|apiserver_envelope_.*|apiserver_flowcontrol_.*|apiserver_storage_.*|apiserver_webhooks_.*|workqueue_.*) 18 | sourceLabels: 19 | - __name__ 20 | port: https 21 | scheme: https 22 | tlsConfig: 23 | insecureSkipVerify: true 24 | selector: 25 | matchLabels: 26 | app.kubernetes.io/component: metrics-adapter 27 | app.kubernetes.io/name: prometheus-adapter 28 | app.kubernetes.io/part-of: kube-prometheus 29 | -------------------------------------------------------------------------------- /manifests/prometheusOperator-clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: controller 6 | app.kubernetes.io/name: prometheus-operator 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.53.1 9 | name: prometheus-operator 10 | rules: 11 | - apiGroups: 12 | - monitoring.coreos.com 13 | resources: 14 | - alertmanagers 15 | - alertmanagers/finalizers 16 | - alertmanagerconfigs 17 | - prometheuses 18 | - prometheuses/finalizers 19 | - thanosrulers 20 | - thanosrulers/finalizers 21 | - servicemonitors 22 | - podmonitors 23 | - probes 24 | - prometheusrules 25 | verbs: 26 | - '*' 27 | - apiGroups: 28 | - apps 29 | resources: 30 | - statefulsets 31 | verbs: 32 | - '*' 33 | - apiGroups: 34 | - "" 35 | resources: 36 | - configmaps 37 | - secrets 38 | verbs: 39 | - '*' 40 | - apiGroups: 41 | - "" 42 | resources: 43 | - pods 44 | verbs: 45 | - list 46 | - delete 47 | - apiGroups: 48 | - "" 49 | resources: 50 | - services 51 | - services/finalizers 52 | - endpoints 53 | verbs: 54 | - get 55 | - create 56 | - update 57 | - delete 58 | - apiGroups: 59 | - "" 60 | resources: 61 | - nodes 62 | verbs: 63 | - list 64 | - watch 65 | - apiGroups: 66 | - "" 67 | resources: 68 | - namespaces 69 | verbs: 70 | - get 71 | - list 72 | - watch 73 | - apiGroups: 74 | - networking.k8s.io 75 | resources: 76 | - ingresses 77 | verbs: 78 | - get 79 | - list 80 | - watch 81 | - apiGroups: 82 | - authentication.k8s.io 83 | resources: 84 | - tokenreviews 85 | verbs: 86 | - create 87 | - apiGroups: 88 | - authorization.k8s.io 89 | resources: 90 | - subjectaccessreviews 91 | verbs: 92 | - create 93 | -------------------------------------------------------------------------------- /manifests/prometheusOperator-clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: controller 6 | app.kubernetes.io/name: prometheus-operator 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.53.1 9 | name: prometheus-operator 10 | roleRef: 11 | apiGroup: rbac.authorization.k8s.io 12 | kind: ClusterRole 13 | name: prometheus-operator 14 | subjects: 15 | - kind: ServiceAccount 16 | name: prometheus-operator 17 | namespace: monitoring 18 | -------------------------------------------------------------------------------- /manifests/prometheusOperator-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: controller 6 | app.kubernetes.io/name: prometheus-operator 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.53.1 9 | name: prometheus-operator 10 | namespace: monitoring 11 | spec: 12 | replicas: 1 13 | selector: 14 | matchLabels: 15 | app.kubernetes.io/component: controller 16 | app.kubernetes.io/name: prometheus-operator 17 | app.kubernetes.io/part-of: kube-prometheus 18 | template: 19 | metadata: 20 | annotations: 21 | kubectl.kubernetes.io/default-container: prometheus-operator 22 | labels: 23 | app.kubernetes.io/component: controller 24 | app.kubernetes.io/name: prometheus-operator 25 | app.kubernetes.io/part-of: kube-prometheus 26 | app.kubernetes.io/version: 0.53.1 27 | spec: 28 | containers: 29 | - args: 30 | - --kubelet-service=kube-system/kubelet 31 | - --prometheus-config-reloader=quay.io/prometheus-operator/prometheus-config-reloader:v0.53.1 32 | image: quay.io/prometheus-operator/prometheus-operator:v0.53.1 33 | name: prometheus-operator 34 | ports: 35 | - containerPort: 8080 36 | name: http 37 | resources: 38 | limits: 39 | cpu: 200m 40 | memory: 200Mi 41 | requests: 42 | cpu: 100m 43 | memory: 100Mi 44 | securityContext: 45 | allowPrivilegeEscalation: false 46 | - args: 47 | - --logtostderr 48 | - --secure-listen-address=:8443 49 | - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 50 | - --upstream=http://127.0.0.1:8080/ 51 | image: quay.io/brancz/kube-rbac-proxy:v0.11.0 52 | name: kube-rbac-proxy 53 | ports: 54 | - containerPort: 8443 55 | name: https 56 | resources: 57 | limits: 58 | cpu: 20m 59 | memory: 40Mi 60 | requests: 61 | cpu: 10m 62 | memory: 20Mi 63 | securityContext: 64 | runAsGroup: 65532 65 | runAsNonRoot: true 66 | runAsUser: 65532 67 | nodeSelector: 68 | kubernetes.io/os: linux 69 | securityContext: 70 | runAsNonRoot: true 71 | runAsUser: 65534 72 | serviceAccountName: prometheus-operator 73 | -------------------------------------------------------------------------------- /manifests/prometheusOperator-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: controller 6 | app.kubernetes.io/name: prometheus-operator 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.53.1 9 | name: prometheus-operator 10 | namespace: monitoring 11 | spec: 12 | clusterIP: None 13 | ports: 14 | - name: https 15 | port: 8443 16 | targetPort: https 17 | selector: 18 | app.kubernetes.io/component: controller 19 | app.kubernetes.io/name: prometheus-operator 20 | app.kubernetes.io/part-of: kube-prometheus 21 | -------------------------------------------------------------------------------- /manifests/prometheusOperator-serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: controller 6 | app.kubernetes.io/name: prometheus-operator 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.53.1 9 | name: prometheus-operator 10 | namespace: monitoring 11 | -------------------------------------------------------------------------------- /manifests/prometheusOperator-serviceMonitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | labels: 5 | app.kubernetes.io/component: controller 6 | app.kubernetes.io/name: prometheus-operator 7 | app.kubernetes.io/part-of: kube-prometheus 8 | app.kubernetes.io/version: 0.53.1 9 | name: prometheus-operator 10 | namespace: monitoring 11 | spec: 12 | endpoints: 13 | - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 14 | honorLabels: true 15 | port: https 16 | scheme: https 17 | tlsConfig: 18 | insecureSkipVerify: true 19 | selector: 20 | matchLabels: 21 | app.kubernetes.io/component: controller 22 | app.kubernetes.io/name: prometheus-operator 23 | app.kubernetes.io/part-of: kube-prometheus 24 | app.kubernetes.io/version: 0.53.1 25 | -------------------------------------------------------------------------------- /manifests/setup/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: monitoring 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "armada", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "./client/index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=production nodemon server/server.js", 8 | "build": "NODE_ENV=production webpack", 9 | "dev": "NODE_ENV=development nodemon server/server.js & NODE_ENV=development webpack serve", 10 | "test": "jest" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/oslabs-beta/Armada" 15 | }, 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/oslabs-beta/Armada" 20 | }, 21 | "homepage": "https://github.com/oslabs-beta/Armada", 22 | "dependencies": { 23 | "@emotion/react": "^11.9.0", 24 | "@emotion/styled": "^11.8.1", 25 | "@kubernetes/client-node": "^0.16.3", 26 | "@mui/material": "^5.7.0", 27 | "@mui/x-data-grid": "^5.11.0", 28 | "@reduxjs/toolkit": "^1.8.1", 29 | "chart.js": "^3.7.1", 30 | "chartjs-plugin-datalabels": "^2.0.0", 31 | "express": "^4.18.1", 32 | "express-ws": "^5.0.2", 33 | "fs": "0.0.1-security", 34 | "match-sorter": "^6.3.1", 35 | "node-cmd": "^5.0.0", 36 | "node-fetch": "^3.2.4", 37 | "prom-client": "^14.0.1", 38 | "react": "^18.1.0", 39 | "react-chartjs-2": "^4.1.0", 40 | "react-copy-to-clipboard": "^5.1.0", 41 | "react-dom": "^18.1.0", 42 | "react-redux": "^8.0.1", 43 | "react-router-dom": "^6.3.0", 44 | "react-scroll": "^1.8.7", 45 | "react-table": "^7.8.0", 46 | "redux": "^4.2.0", 47 | "socket.io": "^4.5.1", 48 | "socket.io-client": "^4.5.1", 49 | "webpack": "^5.72.1", 50 | "webpack-dev-server": "^4.9.0" 51 | }, 52 | "devDependencies": { 53 | "@babel/core": "^7.17.10", 54 | "@babel/preset-env": "^7.17.10", 55 | "@babel/preset-react": "^7.16.7", 56 | "babel-loader": "^8.2.5", 57 | "css-loader": "^6.7.1", 58 | "html-webpack-plugin": "^5.5.0", 59 | "jest": "^28.1.0", 60 | "mini-css-extract-plugin": "^2.6.0", 61 | "react-select": "^5.3.2", 62 | "sass-loader": "^12.6.0", 63 | "style-loader": "^3.3.1", 64 | "supertest": "^6.2.3", 65 | "webpack-cli": "^4.9.2" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /server/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Armada/b3033f291809b25805a897bc53234428a17132a1/server/.DS_Store -------------------------------------------------------------------------------- /server/PrometheusData/dataSources.js: -------------------------------------------------------------------------------- 1 | const PrometheusAPI = require('../controllers/promethusController') 2 | 3 | const memory = { 4 | isPrometheusUp: { check: false }, 5 | }; 6 | 7 | module.exports = () => { 8 | return { 9 | prometheusAPI: new PrometheusAPI(memory), 10 | }; 11 | }; -------------------------------------------------------------------------------- /server/controllers/alertsController.js: -------------------------------------------------------------------------------- 1 | const fetch = (...args) => 2 | import('node-fetch').then(({ default: fetch }) => fetch(...args)); 3 | 4 | const { prometheusURL } = require('../utils/constants'); 5 | 6 | // const prometheusURL = 'http://127.0.0.1:9090/api/v1/'; 7 | 8 | const alertsController = {}; 9 | 10 | // fetch alerts from Prometheus for Alerts page 11 | alertsController.fetchAlerts = async (req, res, next) => { 12 | try { 13 | const data = await fetch(`${prometheusURL}/rules`); 14 | res.locals.alerts = await data.json(); 15 | return next(); 16 | } catch (err) { 17 | return next({ 18 | log: 'Error in alertsController.fetchAlerts', 19 | message: { err: err.message }, 20 | }); 21 | } 22 | }; 23 | 24 | module.exports = alertsController; 25 | -------------------------------------------------------------------------------- /server/controllers/getLists.js: -------------------------------------------------------------------------------- 1 | const k8s = require('@kubernetes/client-node'); 2 | // K8s API 3 | const kc = new k8s.KubeConfig(); 4 | kc.loadFromDefault(); 5 | const k8sApiCore = kc.makeApiClient(k8s.CoreV1Api); 6 | const k8sApiApps = kc.makeApiClient(k8s.AppsV1Api); 7 | 8 | // using k8s API client, get list of components in cluster for homepage 9 | const getLists = { 10 | // get list of all nodes in cluster 11 | getNodesList: (getNodesList = (req, res, next) => { 12 | k8sApiCore 13 | .listNode('default') 14 | .then((data) => { 15 | res.locals.nodeList = data; 16 | k8sApiCore 17 | .listComponentStatus() 18 | .then((data) => { 19 | res.locals.nodeList.nodeProcesses = data; 20 | return next(); 21 | }) 22 | .catch((err) => { 23 | res 24 | .status(500) 25 | .send( 26 | `error found in get request to /nodeList at listComponentStatus(), ${err}` 27 | ); 28 | }); 29 | }) 30 | .catch((err) => { 31 | res 32 | .status(500) 33 | .send(`error found in get request to /nodeList at listNode, ${err}`); 34 | }); 35 | }), 36 | 37 | // get list of all namespaces in cluster 38 | getNamespaceList: (getNamespaceList = (req, res, next) => { 39 | k8sApiCore.listNamespace().then((data) => { 40 | // console.log(data); 41 | res.locals.namespaces = data.body; 42 | return next(); 43 | }); 44 | }), 45 | 46 | // get list of all deployments in cluster 47 | getDeploymentsList: (getDeploymentsList = (req, res, next) => { 48 | k8sApiApps 49 | .listDeploymentForAllNamespaces() 50 | .then((data) => { 51 | res.locals.deploymentsList = data.body; 52 | return next(); 53 | }) 54 | .catch((err) => 55 | next({ 56 | log: 'error in get request to /deploymentsList', 57 | message: { err: 'An error occured in getLists.getDeploymentsList' }, 58 | }) 59 | ); 60 | }), 61 | 62 | // get list of all services in cluster 63 | getServicesList: (getServicesList = (req, res, next) => { 64 | k8sApiCore 65 | .listServiceForAllNamespaces() 66 | .then((data) => { 67 | res.locals.servicesList = data.body; 68 | return next(); 69 | }) 70 | .catch((err) => { 71 | next({ 72 | log: 'error in get request to /serviceList', 73 | message: { err: err.message }, 74 | }); 75 | }); 76 | }), 77 | 78 | // get list of all pods in cluster 79 | getPodsList: (getPodsList = (req, res, next) => { 80 | k8sApiCore 81 | .listPodForAllNamespaces() 82 | .then((data) => { 83 | res.locals.podsList = data.body; 84 | return next(); 85 | }) 86 | .catch((err) => { 87 | next({ 88 | log: 'error in get request to /podList', 89 | message: { err: err.message }, 90 | }); 91 | }); 92 | }), 93 | }; 94 | 95 | module.exports = getLists; 96 | -------------------------------------------------------------------------------- /server/controllers/logsController.js: -------------------------------------------------------------------------------- 1 | const cmd = require('node-cmd'); 2 | const logsController = {}; 3 | const formatLogs = require('../utils/formatLogs'); 4 | 5 | const HEADERS = [ 6 | 'NAMESPACE', 7 | 'LAST SEEN', 8 | 'TYPE', 9 | 'REASON', 10 | 'OBJECT', 11 | 'MESSAGE', 12 | ]; 13 | 14 | // get logs for logs page through kubectl 15 | logsController.getLogs = (req, res, next) => { 16 | try { 17 | const rawLogs = cmd 18 | .runSync('kubectl get events --all-namespaces') 19 | .data.split('\n'); 20 | const formattedLogs = formatLogs(rawLogs); 21 | res.locals.logs = formattedLogs; 22 | return next(); 23 | } catch (err) { 24 | next({ logs: 'Error with getting logs', message: { err: err.message } }); 25 | } 26 | }; 27 | 28 | module.exports = logsController; 29 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const client = require('prom-client'); 3 | 4 | const path = require('path'); 5 | 6 | const getLists = require('./controllers/getLists'); 7 | const prometheusRouter = require('./routers/prometheusRouter'); 8 | const alertsController = require('./controllers/alertsController'); 9 | const logsController = require('./controllers/logsController'); 10 | 11 | const PORT = process.env.PORT || 3001; 12 | const app = express(); 13 | 14 | // Collect default metrics using Prom API 15 | client.collectDefaultMetrics(); 16 | 17 | app.use(express.json()); 18 | app.use(express.urlencoded({ extended: true })); 19 | app.use(express.static(path.resolve(__dirname, '../build'))); 20 | 21 | app.get('/api/fetchMetrics', async (req, res) => { 22 | const metrics = await client.register.getMetricsAsJSON(); 23 | res.status(200).json(metrics); 24 | }); 25 | 26 | app.get('/api/nodesList', getLists.getNodesList, (req, res) => { 27 | res.status(201).send(res.locals.nodeList.response.body.items); 28 | }); 29 | 30 | app.get('/api/deploymentsList', getLists.getDeploymentsList, (req, res) => { 31 | res.status(201).send(res.locals.deploymentsList.items); 32 | }); 33 | 34 | app.get('/api/podsList', getLists.getPodsList, (req, res) => { 35 | res.status(201).send(res.locals.podsList.items); 36 | }); 37 | 38 | app.get('/api/servicesList', getLists.getServicesList, (req, res) => { 39 | res.status(201).send(res.locals.servicesList.items); 40 | }); 41 | 42 | app.get('/api/namespaceList', getLists.getNamespaceList, (req, res) => { 43 | res.status(201).send(res.locals.namespaces); 44 | }); 45 | 46 | app.use('/api/prometheus', prometheusRouter); 47 | 48 | app.get('/api/alerts', alertsController.fetchAlerts, (req, res) => { 49 | res.status(201).json(res.locals.alerts); 50 | }); 51 | 52 | app.get('/api/logs', logsController.getLogs, (req, res) => { 53 | res.status(200).json(res.locals.logs); 54 | }); 55 | 56 | //For all routes access the index.html file 57 | app.get('*', (req, res) => { 58 | res 59 | .status(200) 60 | .sendFile('index.html', { root: path.join(__dirname, '../build') }); 61 | }); 62 | 63 | // Global route handler 64 | app.use('*', (req, res) => { 65 | console.log('Page not found.'); 66 | return res.status(404).send('Page not found.'); 67 | }); 68 | 69 | // Global error handler 70 | app.use(defaultErrorHandler); 71 | function defaultErrorHandler(err, req, res, next) { 72 | const defaultErr = { 73 | log: 'Error! at the Disco', 74 | status: 400, 75 | message: { 76 | err: "An error occurred somewhere where it isn't being handled", 77 | }, 78 | }; 79 | const errorObj = Object.assign(defaultErr, err); 80 | console.log(errorObj.log); 81 | return res.status(errorObj.status).send(JSON.stringify(errorObj.message)); 82 | } 83 | 84 | module.exports = app.listen(PORT, () => 85 | console.log(`App is listening on port ${PORT}`) 86 | ); 87 | -------------------------------------------------------------------------------- /server/utils/constants.js: -------------------------------------------------------------------------------- 1 | const constants = {}; 2 | 3 | constants.TIMESTEP = '10m'; 4 | constants.prometheusURL = 'http://127.0.0.1:9090/api/v1/'; 5 | // constants.prometheusURL = 'host.docker.internal:9090/api/v1/'; 6 | 7 | module.exports = constants; 8 | -------------------------------------------------------------------------------- /server/utils/formatChartData.js: -------------------------------------------------------------------------------- 1 | function formatChartData(data) { 2 | try { 3 | const res = { 4 | timestamps: [], 5 | seriesLabels: [], 6 | seriesValues: [], 7 | }; 8 | 9 | // Helper function to convert the Prometheus MS timestamp to HH:MM 10 | const timeFilter = /[0-9][0-9]:[0-9][0-9]/; 11 | const msToTimestamp = (ms) => 12 | new Date(1000 * ms).toISOString().match(timeFilter)[0]; 13 | 14 | // Pop the last series off the query response to extract timestamp and groupBy label 15 | const initialSet = data.pop(); 16 | const groupByLabel = Object.keys(initialSet.metric)[0]; 17 | 18 | // Add this last series to the response object arrays 19 | res.timestamps = initialSet.values.map((vals) => msToTimestamp(vals[0])); 20 | res.seriesLabels.push(initialSet.metric[groupByLabel] || 'Cluster'); 21 | res.seriesValues.push(initialSet.values.map((vals) => vals[1])); 22 | 23 | // For each remaining dataset, push the series label and array of datapoints onto the res object 24 | data.forEach((dataset) => { 25 | res.seriesLabels.push(dataset.metric[groupByLabel]); // add a new dataseries label to our res 26 | res.seriesValues.push(dataset.values.map((vals) => vals[1])); // add the dataseries to our res 27 | }); 28 | 29 | // Return the constructed response 30 | return res; 31 | } catch (err) { 32 | console.log(err); 33 | } 34 | } 35 | 36 | module.exports = formatChartData; 37 | -------------------------------------------------------------------------------- /server/utils/formatLogs.js: -------------------------------------------------------------------------------- 1 | // Format log data for presentation 2 | const formatLogs = (arr) => { 3 | arr.pop(); 4 | const trimmed = arr.map((el) => el.split(/[ ]{2,}/)); 5 | const headers = trimmed[0].map((el) => el.toLowerCase().replace(' ', '_')); 6 | trimmed.shift(); 7 | return trimmed.map((row) => { 8 | let obj = {}; 9 | row.forEach((r, i) => { 10 | obj[headers[i]] = row[i]; 11 | }); 12 | 13 | return obj; 14 | }); 15 | }; 16 | 17 | module.exports = formatLogs; 18 | -------------------------------------------------------------------------------- /server/utils/formatTimeToAvg.js: -------------------------------------------------------------------------------- 1 | const formatChartData = require('./formatChartData'); 2 | 3 | // Format time series data from Prometheus as averages over period of time 4 | function formatTimeToAvg(resp) { 5 | const formatted = formatChartData(resp.data.result); 6 | const seriesValues = formatted.seriesValues; 7 | const newValues = []; 8 | 9 | // Take an average of time series data over the length of the array 10 | seriesValues.forEach((value) => { 11 | const converted = value.map((el) => parseFloat(el)); 12 | newValues.push(converted.reduce((a, b) => a + b) / converted.length); 13 | }); 14 | formatted.seriesValues = newValues; 15 | const resultArr = []; 16 | 17 | // Reformat averaged result with label and data keys for bar graphs on client side 18 | for (let i = 0; i < formatted.seriesLabels.length; i++) { 19 | resultArr.push({ 20 | label: formatted.seriesLabels[i], 21 | data: formatted.seriesValues[i], 22 | }); 23 | } 24 | return resultArr; 25 | } 26 | 27 | module.exports = formatTimeToAvg; 28 | -------------------------------------------------------------------------------- /server/utils/formatVectorData.js: -------------------------------------------------------------------------------- 1 | // Format vector data for bar charts 2 | const formatVectorData = (arr, metricName) => { 3 | return arr 4 | .sort((a, b) => parseFloat(b.value[1]) - parseFloat(a.value[1])) 5 | .map((node) => { 6 | return { 7 | label: node.metric[metricName] ? node.metric[metricName] : 'unnamed', 8 | data: parseFloat(node.value[1]), 9 | }; 10 | }); 11 | }; 12 | 13 | module.exports = formatVectorData; 14 | -------------------------------------------------------------------------------- /server/utils/metricsFetch.js: -------------------------------------------------------------------------------- 1 | const formatChartData = require('./formatChartData'); 2 | const fetch = (...args) => 3 | import('node-fetch').then(({ default: fetch }) => fetch(...args)); 4 | 5 | // Abstracted middleware function that executes metrics queries, formats response to chart data, and stores result in res.locals 6 | const metricsFetch = (query, title, req, res, next) => { 7 | try { 8 | fetch(query) 9 | .then((resp) => resp.json()) 10 | // Return formatted data and query string on res.locals 11 | .then((resp) => { 12 | res.locals[title] = {}; 13 | if (resp.data.result.length !== 0) { 14 | const formatted = formatChartData(resp.data.result); 15 | res.locals[title].data = formatted; 16 | } else res.locals[title].data = null; 17 | res.locals[title].queryString = query; 18 | }) 19 | .then(() => next()); 20 | } catch (err) { 21 | next({ 22 | log: `Error with ${title}`, 23 | message: { err: err.message }, 24 | }); 25 | } 26 | }; 27 | 28 | module.exports = metricsFetch; 29 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 5 | 6 | const config = { 7 | mode: process.env.NODE_ENV, 8 | entry: path.join(__dirname, './client/index.js'), 9 | output: { 10 | path: path.resolve(__dirname, 'build'), 11 | filename: 'bundle.js', 12 | publicPath: '/', 13 | clean: true, 14 | }, 15 | plugins: [ 16 | new HtmlWebpackPlugin({ 17 | template: path.join(__dirname, 'index.html'), 18 | }), 19 | new MiniCssExtractPlugin(), 20 | ], 21 | resolve: { 22 | extensions: ['.jsx', '.js', '.tsx', '.ts'], 23 | }, 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.(js|jsx)$/, 28 | use: { 29 | loader: 'babel-loader', 30 | options: { 31 | presets: ['@babel/preset-env', '@babel/preset-react'], 32 | plugins: [], 33 | }, 34 | }, 35 | exclude: /node_modules/, 36 | }, 37 | { 38 | test: /\.css$/, 39 | use: [MiniCssExtractPlugin.loader, 'css-loader'], 40 | }, 41 | { 42 | test: /\.s[ac]ss$/i, 43 | exclude: /node_modules/, 44 | use: [ 45 | MiniCssExtractPlugin.loader, 46 | 'style-loader', 47 | 'css-loader', 48 | 'sass-loader', 49 | ], 50 | }, 51 | { 52 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 53 | type: 'asset/resource', 54 | }, 55 | ], 56 | }, 57 | 58 | devServer: { 59 | static: { 60 | directory: path.resolve(__dirname, 'build'), 61 | publicPath: '/', 62 | }, 63 | compress: true, 64 | port: 8080, 65 | hot: true, 66 | historyApiFallback: true, 67 | proxy: { 68 | '/api': { 69 | target: 'http://localhost:3001', 70 | secure: false, 71 | changeOrigin: true, 72 | }, 73 | '/socket.io': { 74 | target: 'http://localhost:4000', 75 | ws: true, 76 | headers: { Connection: 'keep-alive' }, 77 | }, 78 | }, 79 | }, 80 | }; 81 | 82 | module.exports = config; 83 | --------------------------------------------------------------------------------