Added Prometheus monitoring CPU and memory selector. (#1387)

* Added Prometheus monitoring CPU and memory selector.

* Minor text fixes

* Fixed memory units, improvements to get return

* Updated logic to add storageClassName to get response

* Minor fixes, removed warnings

* Removed blank entry for empty storageclassname

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
jinapurapu
2022-01-14 11:15:09 -08:00
committed by GitHub
parent 257f02c554
commit e374772fc6
8 changed files with 275 additions and 136 deletions

View File

@@ -51,6 +51,12 @@ type TenantMonitoringInfo struct {
// labels
Labels []*Label `json:"labels"`
// monitoring CPU request
MonitoringCPURequest string `json:"monitoringCPURequest,omitempty"`
// monitoring mem request
MonitoringMemRequest string `json:"monitoringMemRequest,omitempty"`
// node selector
NodeSelector []*NodeSelector `json:"nodeSelector"`

View File

@@ -3360,6 +3360,12 @@ func init() {
"$ref": "#/definitions/label"
}
},
"monitoringCPURequest": {
"type": "string"
},
"monitoringMemRequest": {
"type": "string"
},
"nodeSelector": {
"type": "array",
"items": {
@@ -7562,6 +7568,12 @@ func init() {
"$ref": "#/definitions/label"
}
},
"monitoringCPURequest": {
"type": "string"
},
"monitoringMemRequest": {
"type": "string"
},
"nodeSelector": {
"type": "array",
"items": {

View File

@@ -2143,49 +2143,75 @@ func getTenantMonitoringResponse(session *models.Principal, params operator_api.
return nil, prepareError(err)
}
var storageClassName string
monitoringInfo := &models.TenantMonitoringInfo{}
if minInst.Spec.Prometheus == nil {
monitoringInfo := &models.TenantMonitoringInfo{
PrometheusEnabled: (false),
}
if minInst.Spec.Prometheus != nil {
monitoringInfo.PrometheusEnabled = true
} else {
monitoringInfo.PrometheusEnabled = false
return monitoringInfo, nil
}
var storageClassName string
if minInst.Spec.Prometheus.StorageClassName != nil {
storageClassName = *minInst.Spec.Prometheus.StorageClassName
monitoringInfo.StorageClassName = storageClassName
}
mLabels := []*models.Label{}
for k, v := range minInst.Spec.Prometheus.Labels {
mLabels = append(mLabels, &models.Label{Key: k, Value: v})
}
mAnnotations := []*models.Annotation{}
for k, v := range minInst.Spec.Prometheus.Annotations {
mAnnotations = append(mAnnotations, &models.Annotation{Key: k, Value: v})
}
mNodeSelector := []*models.NodeSelector{}
for k, v := range minInst.Spec.Prometheus.NodeSelector {
mNodeSelector = append(mNodeSelector, &models.NodeSelector{Key: k, Value: v})
var requestedCPU string
var requestedMem string
if minInst.Spec.Prometheus.Resources.Requests != nil {
requestedCPUQ := minInst.Spec.Prometheus.Resources.Requests["cpu"]
requestedCPU = strconv.FormatInt(requestedCPUQ.Value(), 10)
requestedMemQ := minInst.Spec.Prometheus.Resources.Requests["memory"]
requestedMem = strconv.FormatInt(requestedMemQ.Value(), 10)
monitoringInfo.MonitoringCPURequest = requestedCPU
monitoringInfo.MonitoringMemRequest = requestedMem
}
if minInst.Spec.Prometheus != nil {
monitoringInfo = &models.TenantMonitoringInfo{
PrometheusEnabled: (true),
Annotations: mAnnotations,
DiskCapacityGB: strconv.Itoa(*minInst.Spec.Prometheus.DiskCapacityDB),
Image: minInst.Spec.Prometheus.Image,
InitImage: minInst.Spec.Prometheus.InitImage,
Labels: mLabels,
NodeSelector: mNodeSelector,
ServiceAccountName: minInst.Spec.Prometheus.ServiceAccountName,
SidecarImage: minInst.Spec.Prometheus.SideCarImage,
StorageClassName: storageClassName,
if len(minInst.Spec.Prometheus.Labels) != 0 && minInst.Spec.Prometheus.Labels != nil {
mLabels := []*models.Label{}
for k, v := range minInst.Spec.Prometheus.Labels {
mLabels = append(mLabels, &models.Label{Key: k, Value: v})
}
return monitoringInfo, nil
monitoringInfo.Labels = mLabels
}
if len(minInst.Spec.Prometheus.Annotations) != 0 && minInst.Spec.Prometheus.Annotations != nil {
mAnnotations := []*models.Annotation{}
for k, v := range minInst.Spec.Prometheus.Annotations {
mAnnotations = append(mAnnotations, &models.Annotation{Key: k, Value: v})
}
monitoringInfo.Annotations = mAnnotations
}
if len(minInst.Spec.Prometheus.NodeSelector) != 0 && minInst.Spec.Prometheus.NodeSelector != nil {
mNodeSelector := []*models.NodeSelector{}
for k, v := range minInst.Spec.Prometheus.NodeSelector {
mNodeSelector = append(mNodeSelector, &models.NodeSelector{Key: k, Value: v})
}
monitoringInfo.NodeSelector = mNodeSelector
}
if *minInst.Spec.Prometheus.DiskCapacityDB != 0 {
monitoringInfo.DiskCapacityGB = strconv.Itoa(*minInst.Spec.Prometheus.DiskCapacityDB)
}
if len(minInst.Spec.Prometheus.Image) != 0 {
monitoringInfo.Image = minInst.Spec.Prometheus.Image
}
if len(minInst.Spec.Prometheus.InitImage) != 0 {
monitoringInfo.InitImage = minInst.Spec.Prometheus.InitImage
}
if len(minInst.Spec.Prometheus.ServiceAccountName) != 0 {
monitoringInfo.ServiceAccountName = minInst.Spec.Prometheus.ServiceAccountName
}
if len(minInst.Spec.Prometheus.SideCarImage) != 0 {
monitoringInfo.SidecarImage = minInst.Spec.Prometheus.SideCarImage
}
return monitoringInfo, nil
}
//sets tenant Prometheus monitoring cofiguration fields to values provided
@@ -2245,18 +2271,34 @@ func setTenantMonitoringResponse(session *models.Principal, params operator_api.
}
}
var storageClassName string
if &params.Data.StorageClassName != nil {
storageClassName = params.Data.StorageClassName
monitoringResourceRequest := make(corev1.ResourceList)
if &params.Data.MonitoringCPURequest != nil {
cpuQuantity, err := resource.ParseQuantity(params.Data.MonitoringCPURequest)
if err != nil {
return false, prepareError(err)
}
memQuantity, err := resource.ParseQuantity(params.Data.MonitoringMemRequest)
if err != nil {
return false, prepareError(err)
}
monitoringResourceRequest["cpu"] = cpuQuantity
monitoringResourceRequest["memory"] = memQuantity
}
minTenant.Spec.Prometheus.Resources.Requests = monitoringResourceRequest
minTenant.Spec.Prometheus.Labels = labels
minTenant.Spec.Prometheus.Annotations = annotations
minTenant.Spec.Prometheus.NodeSelector = nodeSelector
minTenant.Spec.Prometheus.Image = params.Data.Image
minTenant.Spec.Prometheus.SideCarImage = params.Data.SidecarImage
minTenant.Spec.Prometheus.InitImage = params.Data.InitImage
minTenant.Spec.Prometheus.StorageClassName = &storageClassName
if params.Data.StorageClassName == "" {
minTenant.Spec.Prometheus.StorageClassName = nil
} else {
minTenant.Spec.Prometheus.StorageClassName = &params.Data.StorageClassName
}
diskCapacityGB, err := strconv.Atoi(params.Data.DiskCapacityGB)
if err == nil {
*minTenant.Spec.Prometheus.DiskCapacityDB = diskCapacityGB

View File

@@ -1,102 +1,102 @@
{
"name": "portal-ui",
"version": "0.1.0",
"homepage": ".",
"private": true,
"dependencies": {
"@codemirror/lang-json": "^0.19.1",
"@codemirror/legacy-modes": "^0.19.0",
"@codemirror/stream-parser": "^0.19.3",
"@date-io/moment": "1.x",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@hot-loader/react-dom": "17.0.1",
"@mui/icons-material": "^5.0.4",
"@mui/lab": "^5.0.0-alpha.30",
"@mui/material": "^5.0.4",
"@mui/styled-engine-sc": "^5.0.3",
"@mui/styles": "^5.0.1",
"@types/history": "^4.7.3",
"@types/jest": "24.0.23",
"@types/lodash": "^4.14.149",
"@types/node": "12.12.8",
"@types/react": "17.0.0",
"@types/react-copy-to-clipboard": "^4.3.0",
"@types/react-dom": "16.9.4",
"@types/react-grid-layout": "^1.1.1",
"@types/react-redux": "^7.1.5",
"@types/react-router": "^5.1.3",
"@types/react-router-dom": "^5.1.2",
"@types/react-virtualized": "^9.21.10",
"@types/superagent": "^4.1.12",
"@types/webpack-env": "^1.14.1",
"@types/websocket": "^1.0.0",
"@uiw/react-codemirror": "^4.3.2",
"ansi-to-react": "^6.0.5",
"chart.js": "^2.9.3",
"codemirror": "^5.52.2",
"history": "^4.10.1",
"local-storage-fallback": "^4.1.1",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"react": "^17.0.2",
"react-async-hook": "^3.6.1",
"react-chartjs-2": "^2.9.0",
"react-copy-to-clipboard": "^5.0.2",
"react-dom": "17.0.1",
"react-dropzone": "^11.4.2",
"react-grid-layout": "^1.2.0",
"react-hot-loader": "^4.13.0",
"react-moment": "^1.1.1",
"react-redux": "^7.1.3",
"react-router-dom": "^5.1.2",
"react-virtualized": "^9.22.2",
"react-window": "^1.8.6",
"react-window-infinite-loader": "^1.0.7",
"recharts": "^2.1.1",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"styled-components": "^5.3.1",
"superagent": "^6.1.0",
"typeface-roboto": "^0.0.75",
"use-debounce": "^5.0.1",
"websocket": "^1.0.31"
},
"scripts": {
"start": "PORT=5005 react-app-rewired start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:9090/",
"devDependencies": {
"@types/react-window": "^1.8.5",
"@types/react-window-infinite-loader": "^1.0.5",
"@types/recharts": "^1.8.22",
"prettier": "2.3.2",
"react-app-rewire-hot-loader": "^2.0.1",
"react-app-rewired": "^2.1.6",
"react-scripts": "5.0.0",
"typescript": "^4.4.3"
},
"resolutions": {
"ansi-regex": "^5.0.1",
"nth-check": "^2.0.1",
"postcss": "^8.2.13"
}
"name": "portal-ui",
"version": "0.1.0",
"homepage": ".",
"private": true,
"dependencies": {
"@codemirror/lang-json": "^0.19.1",
"@codemirror/legacy-modes": "^0.19.0",
"@codemirror/stream-parser": "^0.19.3",
"@date-io/moment": "1.x",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@hot-loader/react-dom": "17.0.1",
"@mui/icons-material": "^5.0.4",
"@mui/lab": "^5.0.0-alpha.30",
"@mui/material": "^5.0.4",
"@mui/styled-engine-sc": "^5.0.3",
"@mui/styles": "^5.0.1",
"@types/history": "^4.7.3",
"@types/jest": "24.0.23",
"@types/lodash": "^4.14.149",
"@types/node": "12.12.8",
"@types/react": "17.0.0",
"@types/react-copy-to-clipboard": "^4.3.0",
"@types/react-dom": "16.9.4",
"@types/react-grid-layout": "^1.1.1",
"@types/react-redux": "^7.1.5",
"@types/react-router": "^5.1.3",
"@types/react-router-dom": "^5.1.2",
"@types/react-virtualized": "^9.21.10",
"@types/superagent": "^4.1.12",
"@types/webpack-env": "^1.14.1",
"@types/websocket": "^1.0.0",
"@uiw/react-codemirror": "^4.3.2",
"ansi-to-react": "^6.0.5",
"chart.js": "^2.9.3",
"codemirror": "^5.52.2",
"history": "^4.10.1",
"local-storage-fallback": "^4.1.1",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"react": "^17.0.2",
"react-async-hook": "^3.6.1",
"react-chartjs-2": "^2.9.0",
"react-copy-to-clipboard": "^5.0.2",
"react-dom": "17.0.1",
"react-dropzone": "^11.4.2",
"react-grid-layout": "^1.2.0",
"react-hot-loader": "^4.13.0",
"react-moment": "^1.1.1",
"react-redux": "^7.1.3",
"react-router-dom": "^5.1.2",
"react-virtualized": "^9.22.2",
"react-window": "^1.8.6",
"react-window-infinite-loader": "^1.0.7",
"recharts": "^2.1.1",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"styled-components": "^5.3.1",
"superagent": "^6.1.0",
"typeface-roboto": "^0.0.75",
"use-debounce": "^5.0.1",
"websocket": "^1.0.31"
},
"scripts": {
"start": "PORT=5005 react-app-rewired start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:9090/",
"devDependencies": {
"@types/react-window": "^1.8.5",
"@types/react-window-infinite-loader": "^1.0.5",
"@types/recharts": "^1.8.22",
"prettier": "2.3.2",
"react-app-rewire-hot-loader": "^2.0.1",
"react-app-rewired": "^2.1.6",
"react-scripts": "5.0.0",
"typescript": "^4.4.3"
},
"resolutions": {
"ansi-regex": "^5.0.1",
"nth-check": "^2.0.1",
"postcss": "^8.2.13"
}
}

View File

@@ -16,6 +16,7 @@
import { LicenseInfo } from "../../License/types";
import { IAffinityModel } from "../../../../common/types";
import { NodeMaxAllocatableResources } from "../types";
export interface IEvent {
namespace: string;
@@ -141,6 +142,8 @@ export interface ITenantMonitoringStruct {
diskCapacityGB: string;
serviceAccountName: string;
prometheusEnabled: boolean;
monitoringCPURequest: string;
monitoringMemRequest: string;
}
export interface IKeyValue {

View File

@@ -33,6 +33,8 @@ interface IEditTenantMonitoringProps {
tenantName: string;
tenantNamespace: string;
storageClassName: string;
cpuRequest: string;
memRequest: string;
}
const styles = (theme: Theme) =>
@@ -59,6 +61,8 @@ const EditTenantMonitoringModal = ({
storageClassName,
tenantName,
tenantNamespace,
cpuRequest,
memRequest,
}: IEditTenantMonitoringProps) => {
const [validationErrors, setValidationErrors] = useState<any>({});
const [newLabels, setNewLabels] = useState<IKeyValue[]>(
@@ -76,6 +80,10 @@ const EditTenantMonitoringModal = ({
const [newDiskCapacityGB, setNewDiskCapacityGB] = useState<string>(
diskCapacityGB.toString()
);
const [newCPURequest, setNewCPURequest] = useState<string>(cpuRequest);
const [newMemRequest, setNewMemRequest] = useState<string>(
Math.floor(parseInt(memRequest, 10) / 1000000000).toString()
);
const [newServiceAccountName, setNewServiceAccountName] =
useState<string>(serviceAccountName);
const [newStorageClassName, setNewStorageClassName] =
@@ -129,6 +137,20 @@ const EditTenantMonitoringModal = ({
pattern: /^[0-9]?(10)?$/,
customPatternMessage: "Must be an integer between 0 and 10",
});
tenantMonitoringValidation.push({
fieldKey: `newCPURequest`,
required: false,
value: newCPURequest as any as string,
pattern: /^[0-9]?(10)?$/,
customPatternMessage: "Must be an integer between 0 and 10",
});
tenantMonitoringValidation.push({
fieldKey: `newMemRequest`,
required: false,
value: newMemRequest as any as string,
pattern: /^[0-9]?(10)?$/,
customPatternMessage: "Must be an integer between 0 and 10",
});
tenantMonitoringValidation.push({
fieldKey: `serviceAccountName`,
required: false,
@@ -153,6 +175,8 @@ const EditTenantMonitoringModal = ({
newDiskCapacityGB,
newServiceAccountName,
newStorageClassName,
newCPURequest,
newMemRequest,
setValidationErrors,
]);
@@ -191,6 +215,8 @@ const EditTenantMonitoringModal = ({
diskCapacityGB: newDiskCapacityGB,
serviceAccountName: newServiceAccountName,
storageClassName: newStorageClassName,
monitoringCPURequest: newCPURequest,
monitoringMemRequest: newMemRequest + "Gi",
}
)
.then(() => {
@@ -253,14 +279,40 @@ const EditTenantMonitoringModal = ({
label={""}
placeholder={"Disk Capacity (GB)"}
name={`diskCapacityGB`}
value={newDiskCapacityGB.toString()}
value={newDiskCapacityGB}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setNewDiskCapacityGB(event.target.value);
}}
key={`diskCapacityGB`}
error={validationErrors[`diskCapacityGB`] || ""}
/>
<h4>Service Account</h4>
<h4>Prometheus CPU Request</h4>
<InputBoxWrapper
id={`cpuRequest`}
label={""}
placeholder={"CPU Request"}
name={`cpuRequest`}
value={newCPURequest}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setNewCPURequest(event.target.value);
}}
key={`cpuRequest`}
error={validationErrors[`cpuRequest`] || ""}
/>
<h4>Prometheus Memory Request (Gi)</h4>
<InputBoxWrapper
id={`memRequest`}
label={""}
placeholder={"Memory request"}
name={`memRequest`}
value={newMemRequest}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setNewMemRequest(event.target.value);
}}
key={`memRequest`}
error={validationErrors[`memRequest`] || ""}
/>
<h4>Service Account Name</h4>
<InputBoxWrapper
id={`serviceAccountName`}
label={""}

View File

@@ -38,6 +38,7 @@ import { EditIcon } from "../../../../icons";
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import { ITenantMonitoringStruct } from "../ListTenants/types";
import KeyPairView from "./KeyPairView";
import { niceBytes } from "../../../../common/utils";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
import RBIconButton from "../../Buckets/BucketDetails/SummaryItems/RBIconButton";
@@ -160,6 +161,8 @@ const TenantMonitoring = ({
tenantName={tenantName}
tenantNamespace={tenantNamespace}
storageClassName={monitoringInfo?.storageClassName || ""}
cpuRequest={monitoringInfo?.monitoringCPURequest || ""}
memRequest={monitoringInfo?.monitoringMemRequest || ""}
/>
)}
{confirmOpen && (
@@ -303,10 +306,27 @@ const TenantMonitoring = ({
</tr>
</>
)}
{monitoringInfo.monitoringCPURequest != null && (
<tr>
<td className={classes.titleCol}>CPU Request:</td>
<td>{monitoringInfo?.monitoringCPURequest}</td>
</tr>
)}
{monitoringInfo.monitoringMemRequest != null && (
<tr>
<td className={classes.titleCol}>Memory Request:</td>
<td>
{niceBytes(
monitoringInfo?.monitoringMemRequest,
true
)}
</td>
</tr>
)}
{monitoringInfo.nodeSelector != null &&
monitoringInfo.nodeSelector.length > 0 && (
<tr>
<h4>Node Seletor</h4>
<h4>Node Selector:</h4>
<td className={classes.titleCol}>
<KeyPairView
records={monitoringInfo.nodeSelector}

View File

@@ -2589,6 +2589,10 @@ definitions:
type: string
storageClassName:
type: string
monitoringCPURequest:
type: string
monitoringMemRequest:
type: string
label:
type: object