Tenant log config screen (#2142)
* Created file for auditLogsScreen, connected to link in TenantDetails Audit Log tab * Fixed input title formatting, confirmation modal logic
This commit is contained in:
@@ -1639,7 +1639,6 @@ func enableTenantLoggingResponse(session *models.Principal, params operator_api.
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
minTenant.EnsureDefaults()
|
||||
|
||||
// Default class name for Log search
|
||||
diskSpaceFromAPI := int64(5) * humanize.GiByte // Default is 5Gi
|
||||
logSearchStorageClass := "standard"
|
||||
|
||||
@@ -220,6 +220,7 @@ export interface ITenantMonitoringStruct {
|
||||
}
|
||||
|
||||
export interface ITenantLogsStruct {
|
||||
auditLoggingEnabled: boolean;
|
||||
image: string;
|
||||
labels: IKeyValue[];
|
||||
annotations: IKeyValue[];
|
||||
|
||||
@@ -1,597 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
modalStyleUtils,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import { Button, Grid } from "@mui/material";
|
||||
import api from "../../../../common/api";
|
||||
import { IKeyValue, ITenant } from "../ListTenants/types";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import KeyPairEdit from "./KeyPairEdit";
|
||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import {
|
||||
commonFormValidation,
|
||||
IValidation,
|
||||
} from "../../../../utils/validationFunctions";
|
||||
import { clearValidationError } from "../utils";
|
||||
|
||||
import InputUnitMenu from "../../Common/FormComponents/InputUnitMenu/InputUnitMenu";
|
||||
|
||||
import { setModalErrorSnackMessage } from "../../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../../store";
|
||||
|
||||
interface IEditTenantLogsProps {
|
||||
tenant: ITenant;
|
||||
classes: any;
|
||||
open: boolean;
|
||||
onClose: (shouldReload: boolean) => void;
|
||||
image: string;
|
||||
labels: IKeyValue[];
|
||||
annotations: IKeyValue[];
|
||||
nodeSelector: IKeyValue[];
|
||||
diskCapacityGB: number;
|
||||
serviceAccountName: string;
|
||||
dbImage: string;
|
||||
dbInitImage: string;
|
||||
dbLabels: IKeyValue[];
|
||||
dbAnnotations: IKeyValue[];
|
||||
dbNodeSelector: IKeyValue[];
|
||||
dbServiceAccountName: string;
|
||||
cpuRequest: string;
|
||||
memRequest: string;
|
||||
dbCPURequest: string;
|
||||
dbMemRequest: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
bottomContainer: {
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
alignItems: "center",
|
||||
"& div": {
|
||||
flexGrow: 1,
|
||||
width: "100%",
|
||||
},
|
||||
},
|
||||
...modalBasic,
|
||||
...modalStyleUtils,
|
||||
...formFieldStyles,
|
||||
});
|
||||
|
||||
const EditTenantLogsModal = ({
|
||||
tenant,
|
||||
classes,
|
||||
open,
|
||||
onClose,
|
||||
image,
|
||||
labels,
|
||||
annotations,
|
||||
nodeSelector,
|
||||
diskCapacityGB,
|
||||
serviceAccountName,
|
||||
dbLabels,
|
||||
dbAnnotations,
|
||||
dbNodeSelector,
|
||||
dbImage,
|
||||
dbInitImage,
|
||||
dbServiceAccountName,
|
||||
cpuRequest,
|
||||
memRequest,
|
||||
dbCPURequest,
|
||||
dbMemRequest,
|
||||
}: IEditTenantLogsProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
const [newLabels, setNewLabels] = useState<IKeyValue[]>(
|
||||
labels.length > 0 ? [...labels] : [{ key: "", value: "" }]
|
||||
);
|
||||
const [newAnnotations, setNewAnnotations] = useState<IKeyValue[]>(
|
||||
annotations.length > 0 ? [...annotations] : [{ key: "", value: "" }]
|
||||
);
|
||||
const [newNodeSelector, setNewNodeSelector] = useState<IKeyValue[]>(
|
||||
nodeSelector.length > 0 ? [...nodeSelector] : [{ key: "", value: "" }]
|
||||
);
|
||||
const [newImage, setNewImage] = useState<string>(image);
|
||||
const [newDiskCapacityGB, setNewDiskCapacityGB] =
|
||||
useState<number>(diskCapacityGB);
|
||||
const [newServiceAccountName, setNewServiceAccountName] = useState<string>(
|
||||
serviceAccountName != null ? serviceAccountName : ""
|
||||
);
|
||||
const [newDbLabels, setNewDbLabels] = useState<IKeyValue[]>(
|
||||
dbLabels.length > 0 ? [...dbLabels] : [{ key: "", value: "" }]
|
||||
);
|
||||
const [newDbAnnotations, setNewDbAnnotations] = useState<IKeyValue[]>(
|
||||
dbAnnotations.length > 0 ? [...dbAnnotations] : [{ key: "", value: "" }]
|
||||
);
|
||||
const [newDbNodeSelector, setNewDbNodeSelector] = useState<IKeyValue[]>(
|
||||
dbNodeSelector.length > 0 ? [...dbNodeSelector] : [{ key: "", value: "" }]
|
||||
);
|
||||
const [newDbImage, setNewDbImage] = useState<string>(dbImage);
|
||||
const [newDbInitImage, setNewDbInitImage] = useState<string>(dbInitImage);
|
||||
const [newDbServiceAccountName, setNewDbServiceAccountName] =
|
||||
useState<string>(dbServiceAccountName != null ? dbServiceAccountName : "");
|
||||
const [labelsError, setLabelsError] = useState<any>({});
|
||||
const [annotationsError, setAnnotationsError] = useState<any>({});
|
||||
const [nodeSelectorError, setNodeSelectorError] = useState<any>({});
|
||||
const [dbLabelsError, setDbLabelsError] = useState<any>({});
|
||||
const [dbAnnotationsError, setDbAnnotationsError] = useState<any>({});
|
||||
const [dbNodeSelectorError, setDbNodeSelectorError] = useState<any>({});
|
||||
const [newCPURequest, setNewCPURequest] = useState<string>(cpuRequest);
|
||||
const [newMemRequest, setNewMemRequest] = useState<string>(
|
||||
memRequest
|
||||
? Math.floor(parseInt(memRequest, 10) / 1000000000).toString()
|
||||
: "0"
|
||||
);
|
||||
const [newDBCPURequest, setNewDBCPURequest] = useState<string>(dbCPURequest);
|
||||
const [newDBMemRequest, setNewDBMemRequest] = useState<string>(
|
||||
dbMemRequest
|
||||
? Math.floor(parseInt(dbMemRequest, 10) / 1000000000).toString()
|
||||
: "0"
|
||||
);
|
||||
|
||||
const trim = (x: IKeyValue[]): IKeyValue[] => {
|
||||
let retval: IKeyValue[] = [];
|
||||
for (let i = 0; i < x.length; i++) {
|
||||
if (x[i].key !== "") {
|
||||
retval.push(x[i]);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
|
||||
const cleanValidation = (fieldName: string) => {
|
||||
setValidationErrors(clearValidationError(validationErrors, fieldName));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let tenantLogValidation: IValidation[] = [];
|
||||
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `image`,
|
||||
required: false,
|
||||
value: newImage,
|
||||
pattern:
|
||||
/^([a-zA-Z0-9])([a-zA-Z0-9-._])*([a-zA-Z0-9]?)+(\/(([a-zA-Z0-9])([a-zA-Z0-9-._])*([a-zA-Z0-9])?)+)*:([a-zA-Z0-9])[a-zA-Z0-9-.]{0,127}$/,
|
||||
customPatternMessage: "Invalid image",
|
||||
});
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `dbImage`,
|
||||
required: false,
|
||||
value: newDbImage,
|
||||
pattern:
|
||||
/^([a-zA-Z0-9])([a-zA-Z0-9-._])*([a-zA-Z0-9]?)+(\/(([a-zA-Z0-9])([a-zA-Z0-9-._])*([a-zA-Z0-9])?)+)*:([a-zA-Z0-9])[a-zA-Z0-9-.]{0,127}$/,
|
||||
customPatternMessage: "Invalid image",
|
||||
});
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `dbInitImage`,
|
||||
required: false,
|
||||
value: newDbInitImage,
|
||||
pattern:
|
||||
/^([a-zA-Z0-9])([a-zA-Z0-9-._])*([a-zA-Z0-9]?)+(\/(([a-zA-Z0-9])([a-zA-Z0-9-._])*([a-zA-Z0-9])?)+)*:([a-zA-Z0-9])[a-zA-Z0-9-.]{0,127}$/,
|
||||
customPatternMessage: "Invalid image",
|
||||
});
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `diskCapacityGB`,
|
||||
required: true,
|
||||
value: newDiskCapacityGB as any as string,
|
||||
pattern: /^[0-9]*$/,
|
||||
customPatternMessage: "Must be an integer between 0 and 10",
|
||||
});
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `serviceAccountName`,
|
||||
required: false,
|
||||
value: newServiceAccountName,
|
||||
pattern: /^[a-zA-Z0-9-.]{1,253}$/,
|
||||
customPatternMessage: "Invalid service account name",
|
||||
});
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `dbServiceAccountName`,
|
||||
required: false,
|
||||
value: newDbServiceAccountName,
|
||||
pattern: /^[a-zA-Z0-9-.]{1,253}$/,
|
||||
customPatternMessage: "Invalid service account name",
|
||||
});
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `cpuRequest`,
|
||||
required: true,
|
||||
value: newCPURequest as any as string,
|
||||
pattern: /^[0-9]*$/,
|
||||
customPatternMessage:
|
||||
"Please enter an integer value for number of CPUs requested",
|
||||
});
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `memRequest`,
|
||||
required: true,
|
||||
value: newMemRequest as any as string,
|
||||
pattern: /^[0-9]*$/,
|
||||
customPatternMessage:
|
||||
"Please enter an integer value (Gi) for memory requested",
|
||||
});
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `dbCPURequest`,
|
||||
required: true,
|
||||
value: newDBCPURequest as any as string,
|
||||
pattern: /^[0-9]*$/,
|
||||
customPatternMessage:
|
||||
"Please enter an integer value for number of DB CPUs requested",
|
||||
});
|
||||
tenantLogValidation.push({
|
||||
fieldKey: `dbMemRequest`,
|
||||
required: true,
|
||||
value: newDBMemRequest as any as string,
|
||||
pattern: /^[0-9]*$/,
|
||||
customPatternMessage:
|
||||
"Please enter an integer value (Gi) for DB memory requested",
|
||||
});
|
||||
|
||||
const commonVal = commonFormValidation(tenantLogValidation);
|
||||
setValidationErrors(commonVal);
|
||||
}, [
|
||||
newImage,
|
||||
newDbImage,
|
||||
newDbInitImage,
|
||||
newDiskCapacityGB,
|
||||
newServiceAccountName,
|
||||
newDbServiceAccountName,
|
||||
newCPURequest,
|
||||
newMemRequest,
|
||||
newDBCPURequest,
|
||||
newDBMemRequest,
|
||||
setValidationErrors,
|
||||
]);
|
||||
|
||||
const checkValid = (): boolean => {
|
||||
if (
|
||||
Object.keys(validationErrors).length !== 0 ||
|
||||
Object.keys(labelsError).length !== 0 ||
|
||||
Object.keys(annotationsError).length !== 0 ||
|
||||
Object.keys(nodeSelectorError).length !== 0 ||
|
||||
Object.keys(dbLabelsError).length !== 0 ||
|
||||
Object.keys(dbAnnotationsError).length !== 0 ||
|
||||
Object.keys(dbNodeSelectorError).length !== 0
|
||||
) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
onClose={() => onClose(true)}
|
||||
modalOpen={open}
|
||||
title="Edit Logging"
|
||||
>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
if (!checkValid()) {
|
||||
dispatch(
|
||||
setModalErrorSnackMessage({
|
||||
errorMessage: "Some fields have invalid values",
|
||||
detailedError: "",
|
||||
})
|
||||
);
|
||||
} else {
|
||||
api
|
||||
.invoke(
|
||||
"PUT",
|
||||
`/api/v1/namespaces/${tenant.namespace}/tenants/${tenant.name}/log`,
|
||||
{
|
||||
labels: trim(newLabels),
|
||||
annotations: trim(newAnnotations),
|
||||
nodeSelector: trim(newNodeSelector),
|
||||
image: newImage,
|
||||
diskCapacityGB: newDiskCapacityGB,
|
||||
serviceAccountName: newServiceAccountName,
|
||||
dbLabels: trim(newDbLabels),
|
||||
dbAnnotations: trim(newDbAnnotations),
|
||||
dbNodeSelector: trim(newDbNodeSelector),
|
||||
dbImage: newDbImage,
|
||||
dbInitImage: newDbInitImage,
|
||||
dbServiceAccountName: newDbServiceAccountName,
|
||||
logCPURequest: newCPURequest,
|
||||
logMemRequest: newMemRequest + "Gi",
|
||||
logDBCPURequest: newDBCPURequest,
|
||||
logDBMemRequest: newDBMemRequest + "Gi",
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
onClose(true);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid xs={12} className={classes.modalFormScrollable}>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<h4>Logging API </h4>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`image`}
|
||||
label={"Image"}
|
||||
placeholder={"minio/operator:v4.4.22"}
|
||||
name={`image`}
|
||||
value={newImage}
|
||||
onChange={(e) => {
|
||||
setNewImage(e.target.value);
|
||||
cleanValidation(`image`);
|
||||
}}
|
||||
key={`image`}
|
||||
error={validationErrors[`image`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`diskCapacityGB`}
|
||||
label={"Disk Capacity"}
|
||||
placeholder={"Disk Capacity"}
|
||||
name={`diskCapacityGB`}
|
||||
value={newDiskCapacityGB as any as string}
|
||||
onChange={(e) => {
|
||||
setNewDiskCapacityGB(e.target.value as any as number);
|
||||
cleanValidation(`diskCapacityGB`);
|
||||
}}
|
||||
key={`diskCapacityGB`}
|
||||
error={validationErrors[`diskCapacityGB`] || ""}
|
||||
overlayObject={
|
||||
<InputUnitMenu
|
||||
id={"size-unit"}
|
||||
onUnitChange={() => {}}
|
||||
unitSelected={"Gi"}
|
||||
unitsList={[{ label: "Gi", value: "Gi" }]}
|
||||
disabled={true}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`serviceAccountName`}
|
||||
label={"Service Account"}
|
||||
placeholder={"Service Account Name"}
|
||||
name={`serviceAccountName`}
|
||||
value={newServiceAccountName}
|
||||
onChange={(e) => {
|
||||
setNewServiceAccountName(e.target.value);
|
||||
cleanValidation(`serviceAccountName`);
|
||||
}}
|
||||
key={`serviceAccountName`}
|
||||
error={validationErrors[`serviceAccountName`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`cpuRequest`}
|
||||
label={"CPU Request"}
|
||||
placeholder={"CPU Request"}
|
||||
name={`cpuRequest`}
|
||||
value={newCPURequest as any as string}
|
||||
onChange={(e) => {
|
||||
setNewCPURequest(e.target.value as any as string);
|
||||
cleanValidation(`cpuRequest`);
|
||||
}}
|
||||
key={`cpuRequest`}
|
||||
error={validationErrors[`cpuRequest`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`memRequest`}
|
||||
label={"Memory request"}
|
||||
placeholder={"Memory request"}
|
||||
name={`memRequest`}
|
||||
value={newMemRequest}
|
||||
onChange={(e) => {
|
||||
setNewMemRequest(e.target.value as any as string);
|
||||
cleanValidation(`memRequest`);
|
||||
}}
|
||||
key={`memRequest`}
|
||||
error={validationErrors[`memRequest`] || ""}
|
||||
overlayObject={
|
||||
<InputUnitMenu
|
||||
id={"size-unit"}
|
||||
onUnitChange={() => {}}
|
||||
unitSelected={"Gi"}
|
||||
unitsList={[{ label: "Gi", value: "Gi" }]}
|
||||
disabled={true}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>Labels</span>
|
||||
<KeyPairEdit
|
||||
newValues={newLabels}
|
||||
setNewValues={setNewLabels}
|
||||
paramName={"Labels"}
|
||||
error={labelsError}
|
||||
setError={setLabelsError}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>Annotations</span>
|
||||
<KeyPairEdit
|
||||
newValues={newAnnotations}
|
||||
setNewValues={setNewAnnotations}
|
||||
paramName={"Annotations"}
|
||||
error={annotationsError}
|
||||
setError={setAnnotationsError}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>Node Selector</span>
|
||||
<KeyPairEdit
|
||||
newValues={newNodeSelector}
|
||||
setNewValues={setNewNodeSelector}
|
||||
paramName={"Node Selector"}
|
||||
error={nodeSelectorError}
|
||||
setError={setNodeSelectorError}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<h4>Database Configuration </h4>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`dbImage`}
|
||||
label={"Postgres Image"}
|
||||
placeholder={"library/postgres:13"}
|
||||
name={`dbImage`}
|
||||
value={newDbImage}
|
||||
onChange={(e) => {
|
||||
setNewDbImage(e.target.value);
|
||||
cleanValidation(`dbImage`);
|
||||
}}
|
||||
key={`dbImage`}
|
||||
error={validationErrors[`dbImage`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`dbInitImage`}
|
||||
label={"Postgres Init Image"}
|
||||
placeholder={"library/busybox:1.33.1"}
|
||||
name={`dbInitImage`}
|
||||
value={newDbInitImage}
|
||||
onChange={(e) => {
|
||||
setNewDbInitImage(e.target.value);
|
||||
cleanValidation(`dbInitImage`);
|
||||
}}
|
||||
key={`dbInitImage`}
|
||||
error={validationErrors[`dbInitImage`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`dbServiceAccountName`}
|
||||
label={"Service Account"}
|
||||
placeholder={"Db Service Account Name"}
|
||||
name={`dbServiceAccountName`}
|
||||
value={newDbServiceAccountName}
|
||||
onChange={(e) => {
|
||||
setNewDbServiceAccountName(e.target.value);
|
||||
cleanValidation(`dbServiceAccountName`);
|
||||
}}
|
||||
key={`dbServiceAccountName`}
|
||||
error={validationErrors[`dbServiceAccountName`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`dbCpuRequest`}
|
||||
label={"DB CPU Request"}
|
||||
placeholder={"DB CPU Request"}
|
||||
name={`dbCpuRequest`}
|
||||
value={newDBCPURequest as any as string}
|
||||
onChange={(e) => {
|
||||
setNewDBCPURequest(e.target.value as any as string);
|
||||
cleanValidation(`dbCpuRequest`);
|
||||
}}
|
||||
key={`dbCpuRequest`}
|
||||
error={validationErrors[`dbCpuRequest`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id={`dbMemRequest`}
|
||||
label={"DB Memory request"}
|
||||
placeholder={"DB Memory request"}
|
||||
name={`dbMemRequest`}
|
||||
value={newDBMemRequest}
|
||||
onChange={(e) => {
|
||||
setNewDBMemRequest(e.target.value as any as string);
|
||||
cleanValidation(`dbMemRequest`);
|
||||
}}
|
||||
key={`dbMemRequest`}
|
||||
error={validationErrors[`dbMemRequest`] || ""}
|
||||
overlayObject={
|
||||
<InputUnitMenu
|
||||
id={"size-unit"}
|
||||
onUnitChange={() => {}}
|
||||
unitSelected={"Gi"}
|
||||
unitsList={[{ label: "Gi", value: "Gi" }]}
|
||||
disabled={true}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>Labels</span>
|
||||
<KeyPairEdit
|
||||
newValues={newDbLabels}
|
||||
setNewValues={setNewDbLabels}
|
||||
paramName={"Db Labels"}
|
||||
error={dbLabelsError}
|
||||
setError={setDbLabelsError}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>Annotations</span>
|
||||
<KeyPairEdit
|
||||
newValues={newDbAnnotations}
|
||||
setNewValues={setNewDbAnnotations}
|
||||
paramName={"Db Annotations"}
|
||||
error={dbAnnotationsError}
|
||||
setError={setDbAnnotationsError}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>Node Selector</span>
|
||||
<KeyPairEdit
|
||||
newValues={newDbNodeSelector}
|
||||
setNewValues={setNewDbNodeSelector}
|
||||
paramName={"DbNode Selector"}
|
||||
error={dbNodeSelectorError}
|
||||
setError={setDbNodeSelectorError}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid xs={12} className={classes.buttonContainer}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={!checkValid()}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</ModalWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(EditTenantLogsModal);
|
||||
@@ -0,0 +1,655 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//import { ISecurityContext} from "../types";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import {
|
||||
containerForHeader,
|
||||
createTenantCommon,
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
spacingUtils,
|
||||
tenantDetailsStyles,
|
||||
wizardCommon,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { AppState, useAppDispatch } from "../../../../store";
|
||||
import api from "../../../../common/api";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import { useParams } from "react-router-dom";
|
||||
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import { Button, DialogContentText } from "@mui/material";
|
||||
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
|
||||
import {
|
||||
setErrorSnackMessage,
|
||||
setSnackBarMessage,
|
||||
} from "../../../../systemSlice";
|
||||
import { IKeyValue } from "../ListTenants/types";
|
||||
import KeyPairEdit from "./KeyPairEdit";
|
||||
import InputUnitMenu from "../../Common/FormComponents/InputUnitMenu/InputUnitMenu";
|
||||
import { ITenantLogsStruct } from "../ListTenants/types";
|
||||
import {
|
||||
setAuditLoggingEnabled,
|
||||
setImage,
|
||||
setDBImage,
|
||||
setDBInitImage,
|
||||
setDiskCapacityGB,
|
||||
setServiceAccountName,
|
||||
setDBServiceAccountName,
|
||||
setCPURequest,
|
||||
setMemRequest,
|
||||
setDBCPURequest,
|
||||
setDBMemRequest,
|
||||
} from "../TenantDetails/tenantAuditLogSlice";
|
||||
|
||||
import { clearValidationError } from "../utils";
|
||||
|
||||
interface ITenantAuditLogs {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...tenantDetailsStyles,
|
||||
...spacingUtils,
|
||||
bold: { fontWeight: "bold" },
|
||||
italic: { fontStyle: "italic" },
|
||||
fileItem: {
|
||||
marginRight: 10,
|
||||
display: "flex",
|
||||
"& div label": {
|
||||
minWidth: 50,
|
||||
},
|
||||
|
||||
"@media (max-width: 900px)": {
|
||||
flexFlow: "column",
|
||||
},
|
||||
},
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
...createTenantCommon,
|
||||
...formFieldStyles,
|
||||
...modalBasic,
|
||||
...wizardCommon,
|
||||
});
|
||||
|
||||
const TenantAuditLogging = ({ classes }: ITenantAuditLogs) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { tenantName, tenantNamespace } = useParams();
|
||||
const auditLoggingEnabled = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.auditLoggingEnabled
|
||||
);
|
||||
const image = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.image
|
||||
);
|
||||
const dbImage = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.dbImage
|
||||
);
|
||||
const dbInitImage = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.dbInitImage
|
||||
);
|
||||
const diskCapacityGB = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.diskCapacityGB
|
||||
);
|
||||
const cpuRequest = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.cpuRequest
|
||||
);
|
||||
const memRequest = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.memRequest
|
||||
);
|
||||
|
||||
const dbCpuRequest = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.dbCPURequest
|
||||
);
|
||||
const dbMemRequest = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.dbMemRequest
|
||||
);
|
||||
const serviceAccountName = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.serviceAccountName
|
||||
);
|
||||
const dbServiceAccountName = useSelector(
|
||||
(state: AppState) => state.editTenantLogging.dbServiceAccountName
|
||||
);
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
const [toggleConfirmOpen, setToggleConfirmOpen] = useState<boolean>(false);
|
||||
|
||||
const [labels, setLabels] = useState<IKeyValue[]>([{ key: "", value: "" }]);
|
||||
const [annotations, setAnnotations] = useState<IKeyValue[]>([
|
||||
{ key: "", value: "" },
|
||||
]);
|
||||
const [nodeSelector, setNodeSelector] = useState<IKeyValue[]>([
|
||||
{ key: "", value: "" },
|
||||
]);
|
||||
const [dbLabels, setDBLabels] = useState<IKeyValue[]>([{ key: "", value: "" }]);
|
||||
const [dbAnnotations, setDBAnnotations] = useState<IKeyValue[]>([
|
||||
{ key: "", value: "" },
|
||||
]);
|
||||
const [dbNodeSelector, setDBNodeSelector] = useState<IKeyValue[]>([
|
||||
{ key: "", value: "" },
|
||||
]);
|
||||
|
||||
const [refreshLoggingInfo, setRefreshLoggingInfo] =
|
||||
useState<boolean>(true);
|
||||
const [labelsError, setLabelsError] = useState<any>({});
|
||||
const [annotationsError, setAnnotationsError] = useState<any>({});
|
||||
const [nodeSelectorError, setNodeSelectorError] = useState<any>({});
|
||||
|
||||
const [dbLabelsError, setDBLabelsError] = useState<any>({});
|
||||
const [dbAnnotationsError, setDBAnnotationsError] = useState<any>({});
|
||||
const [dbNodeSelectorError, setDBNodeSelectorError] = useState<any>({});
|
||||
|
||||
const cleanValidation = (fieldName: string) => {
|
||||
setValidationErrors(clearValidationError(validationErrors, fieldName));
|
||||
};
|
||||
|
||||
const setLoggingInfo = (res: ITenantLogsStruct) => {
|
||||
dispatch(setAuditLoggingEnabled(!res.disabled))
|
||||
dispatch(setImage(res.image));
|
||||
dispatch(setServiceAccountName(res.serviceAccountName));
|
||||
dispatch(setDBServiceAccountName(res.dbServiceAccountName));
|
||||
dispatch(setDBImage(res.dbImage));
|
||||
dispatch(setDBInitImage(res.dbInitImage));
|
||||
dispatch(setCPURequest(res.logCPURequest));
|
||||
dispatch(setDBCPURequest(res.logDBCPURequest));
|
||||
if (res.logMemRequest) {
|
||||
dispatch(
|
||||
setMemRequest(
|
||||
Math.floor(
|
||||
parseInt(res.logMemRequest, 10) / 1000000000
|
||||
).toString()
|
||||
)
|
||||
);
|
||||
} else {
|
||||
dispatch(setMemRequest("0"));
|
||||
}
|
||||
if (res.logDBMemRequest) {
|
||||
dispatch(
|
||||
setDBMemRequest(
|
||||
Math.floor(
|
||||
parseInt(res.logDBMemRequest, 10) / 1000000000
|
||||
).toString()
|
||||
)
|
||||
);
|
||||
} else {
|
||||
dispatch(setDBMemRequest("0"));
|
||||
}
|
||||
dispatch(setDiskCapacityGB(res.diskCapacityGB));
|
||||
res.labels.length > 0 ? setLabels(res.labels) : setLabels([{ key: "test", value: "test" }]);
|
||||
res.annotations.length > 0 ? setAnnotations(res.annotations) : setAnnotations([{ key: "", value: "" }]);
|
||||
res.nodeSelector.length > 0 ? setNodeSelector(res.nodeSelector) : setNodeSelector([{ key: "", value: "" }]);
|
||||
res.dbLabels.length > 0 ? setDBLabels(res.dbLabels) : setDBLabels([{ key: "", value: "" }]);
|
||||
res.dbAnnotations.length > 0 ? setDBAnnotations(res.dbAnnotations) : setDBAnnotations([{ key: "", value: "" }]);
|
||||
res.dbNodeSelector.length > 0 ? setDBNodeSelector(res.dbNodeSelector) : setDBNodeSelector([{ key: "", value: "" }]);
|
||||
};
|
||||
|
||||
const trim = (x: IKeyValue[]): IKeyValue[] => {
|
||||
let retval: IKeyValue[] = [];
|
||||
for (let i = 0; i < x.length; i++) {
|
||||
if (x[i].key !== "") {
|
||||
retval.push(x[i]);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
|
||||
const checkValid = (): boolean => {
|
||||
if (
|
||||
Object.keys(validationErrors).length !== 0 ||
|
||||
Object.keys(labelsError).length !== 0 ||
|
||||
Object.keys(annotationsError).length !== 0 ||
|
||||
Object.keys(nodeSelectorError).length !== 0 ||
|
||||
Object.keys(dbNodeSelectorError).length !== 0 ||
|
||||
Object.keys(dbAnnotationsError).length !== 0 ||
|
||||
Object.keys(dbLabelsError).length !== 0
|
||||
) {
|
||||
let err: ErrorResponseHandler = {
|
||||
errorMessage: "Invalid entry",
|
||||
detailedError: "",
|
||||
};
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (refreshLoggingInfo) {
|
||||
api
|
||||
.invoke(
|
||||
"GET",
|
||||
`/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}/log`
|
||||
)
|
||||
.then((res: ITenantLogsStruct) => {
|
||||
dispatch(setAuditLoggingEnabled(res.auditLoggingEnabled));
|
||||
setLoggingInfo(res);
|
||||
setRefreshLoggingInfo(false);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
setRefreshLoggingInfo(false);
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [refreshLoggingInfo]);
|
||||
|
||||
const submitLoggingInfo = () => {
|
||||
if (checkValid()) {
|
||||
api
|
||||
.invoke(
|
||||
"PUT",
|
||||
`/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}/log`,
|
||||
{
|
||||
labels: trim(labels),
|
||||
annotations: trim(annotations),
|
||||
nodeSelector: trim(nodeSelector),
|
||||
image: image,
|
||||
diskCapacityGB: diskCapacityGB.toString(),
|
||||
serviceAccountName: serviceAccountName,
|
||||
dbLabels: trim(dbLabels),
|
||||
dbAnnotations: trim(dbAnnotations),
|
||||
dbNodeSelector: trim(dbNodeSelector),
|
||||
dbImage: dbImage,
|
||||
dbInitImage: dbInitImage,
|
||||
dbServiceAccountName: dbServiceAccountName,
|
||||
logCPURequest: cpuRequest,
|
||||
logMemRequest: memRequest + "Gi",
|
||||
logDBCPURequest: dbCpuRequest,
|
||||
logDBMemRequest: dbMemRequest + "Gi",
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
setRefreshLoggingInfo(true);
|
||||
dispatch(setSnackBarMessage(`Audit Log configuration updated.`));
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setErrorSnackMessage(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const toggleLogging = () => {
|
||||
if(!auditLoggingEnabled) {
|
||||
api
|
||||
.invoke(
|
||||
"POST",
|
||||
`/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}/enable-logging`
|
||||
)
|
||||
.then(() => {
|
||||
setRefreshLoggingInfo(true);
|
||||
setToggleConfirmOpen(false);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(
|
||||
setErrorSnackMessage({
|
||||
errorMessage: "Error enabling logging",
|
||||
detailedError: err.detailedError,
|
||||
})
|
||||
);
|
||||
});
|
||||
} else {
|
||||
api
|
||||
.invoke(
|
||||
"POST",
|
||||
`/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}/disable-logging`
|
||||
)
|
||||
.then(() => {
|
||||
setRefreshLoggingInfo(true);
|
||||
setToggleConfirmOpen(false);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(
|
||||
setErrorSnackMessage({
|
||||
errorMessage: "Error disabling logging",
|
||||
detailedError: err.detailedError,
|
||||
})
|
||||
);
|
||||
});
|
||||
};
|
||||
};
|
||||
return (
|
||||
<Fragment>
|
||||
{toggleConfirmOpen && (
|
||||
<ConfirmDialog
|
||||
isOpen={toggleConfirmOpen}
|
||||
title={
|
||||
!auditLoggingEnabled
|
||||
? "Enable Audit Logging for this tenant?"
|
||||
: "Disable Audit Logging for this tenant?"
|
||||
}
|
||||
confirmText={!auditLoggingEnabled ? "Enable" : "Disable"}
|
||||
cancelText="Cancel"
|
||||
onClose={() => setToggleConfirmOpen(false)}
|
||||
onConfirm={toggleLogging}
|
||||
confirmationContent={
|
||||
<DialogContentText>
|
||||
{!auditLoggingEnabled
|
||||
? "A small Postgres server will be started per the configuration provided, which will collect the audit logs for your tenant."
|
||||
: " Current configuration will be lost, and defaults reset if reenabled."}
|
||||
</DialogContentText>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs>
|
||||
<h1 className={classes.sectionTitle}>Audit Logs</h1>
|
||||
</Grid>
|
||||
<Grid item xs={7} justifyContent={"end"} textAlign={"right"}>
|
||||
<FormSwitchWrapper
|
||||
label={""}
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
checked={auditLoggingEnabled}
|
||||
value={"tenant_logging"}
|
||||
id="tenant_logging"
|
||||
name="tenant_logging"
|
||||
onChange={() => {
|
||||
setToggleConfirmOpen(true);
|
||||
}}
|
||||
description=""
|
||||
/>
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<hr className={classes.hrClass} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{auditLoggingEnabled && (
|
||||
<Fragment>
|
||||
<Grid item xs={12} paddingBottom={2}>
|
||||
<InputBoxWrapper
|
||||
id={`image`}
|
||||
label={"Image"}
|
||||
placeholder={"minio/operator:v4.4.22"}
|
||||
name={`image`}
|
||||
value={image}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.validity.valid) {
|
||||
dispatch(setImage(event.target.value));
|
||||
}
|
||||
cleanValidation(`image`);
|
||||
}}
|
||||
key={`image`}
|
||||
pattern={"^[a-zA-Z0-9-./:]{1,253}$"}
|
||||
error={validationErrors[`image`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} paddingBottom={2}>
|
||||
<InputBoxWrapper
|
||||
id={`dbImage`}
|
||||
label={"DB Postgres Image"}
|
||||
placeholder={"library/postgres:13"}
|
||||
name={`dbImage`}
|
||||
value={dbImage}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.validity.valid) {
|
||||
dispatch(setDBImage(event.target.value));
|
||||
}
|
||||
cleanValidation(`dbImage`);
|
||||
}}
|
||||
key={`dbImage`}
|
||||
pattern={"^[a-zA-Z0-9-./:]{1,253}$"}
|
||||
error={validationErrors[`dbImage`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} paddingBottom={2}>
|
||||
<InputBoxWrapper
|
||||
id={`dbInitImage`}
|
||||
label={"DB Init Image"}
|
||||
placeholder={"library/busybox:1.33.1"}
|
||||
name={`dbInitImage`}
|
||||
value={dbInitImage}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.validity.valid) {
|
||||
dispatch(setDBInitImage(event.target.value));
|
||||
}
|
||||
cleanValidation(`dbInitImage`);
|
||||
}}
|
||||
key={`dbInitImage`}
|
||||
pattern={"^[a-zA-Z0-9-./:]{1,253}$"}
|
||||
error={validationErrors[`dbInitImage`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} paddingBottom={2}>
|
||||
<InputBoxWrapper
|
||||
id={`diskCapacityGB`}
|
||||
label={"Disk Capacity"}
|
||||
placeholder={"Disk Capacity"}
|
||||
name={`diskCapacityGB`}
|
||||
value={!isNaN(diskCapacityGB) ? diskCapacityGB.toString() : "0"}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.validity.valid) {
|
||||
dispatch(setDiskCapacityGB(parseInt(event.target.value)));
|
||||
}
|
||||
cleanValidation(`diskCapacityGB`);
|
||||
}}
|
||||
key={`diskCapacityGB`}
|
||||
pattern={"[0-9]*"}
|
||||
error={validationErrors[`diskCapacityGB`] || ""}
|
||||
overlayObject={
|
||||
<InputUnitMenu
|
||||
id={"size-unit"}
|
||||
onUnitChange={() => {}}
|
||||
unitSelected={"Gi"}
|
||||
unitsList={[{ label: "Gi", value: "Gi" }]}
|
||||
disabled={true}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} paddingBottom={2}>
|
||||
<InputBoxWrapper
|
||||
id={`cpuRequest`}
|
||||
label={"CPU Request"}
|
||||
placeholder={"CPU Request"}
|
||||
name={`cpuRequest`}
|
||||
value={cpuRequest}
|
||||
pattern={"[0-9]*"}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.validity.valid) {
|
||||
dispatch(setCPURequest(event.target.value));
|
||||
}
|
||||
cleanValidation(`cpuRequest`);
|
||||
}}
|
||||
key={`cpuRequest`}
|
||||
error={validationErrors[`cpuRequest`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} paddingBottom={2}>
|
||||
<InputBoxWrapper
|
||||
id={`dbCPURequest`}
|
||||
label={"DB CPU Request"}
|
||||
placeholder={"DB CPU Request"}
|
||||
name={`dbCPURequest`}
|
||||
value={dbCpuRequest}
|
||||
pattern={"[0-9]*"}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.validity.valid) {
|
||||
dispatch(setDBCPURequest(event.target.value));
|
||||
}
|
||||
cleanValidation(`dbCPURequest`);
|
||||
}}
|
||||
key={`dbCPURequest`}
|
||||
error={validationErrors[`dbCPURequest`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} paddingBottom={2}>
|
||||
<InputBoxWrapper
|
||||
id={`memRequest`}
|
||||
label={"Memory Request"}
|
||||
placeholder={"Memory request"}
|
||||
name={`memRequest`}
|
||||
value={memRequest}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.validity.valid) {
|
||||
dispatch(setMemRequest(event.target.value));
|
||||
}
|
||||
cleanValidation(`memRequest`);
|
||||
}}
|
||||
pattern={"[0-9]*"}
|
||||
key={`memRequest`}
|
||||
error={validationErrors[`memRequest`] || ""}
|
||||
overlayObject={
|
||||
<InputUnitMenu
|
||||
id={"size-unit"}
|
||||
onUnitChange={() => {}}
|
||||
unitSelected={"Gi"}
|
||||
unitsList={[{ label: "Gi", value: "Gi" }]}
|
||||
disabled={true}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} paddingBottom={2}>
|
||||
<InputBoxWrapper
|
||||
id={`dbMemRequest`}
|
||||
label={"DB Memory Request"}
|
||||
placeholder={"DB Memory request"}
|
||||
name={`dbMemRequest`}
|
||||
value={dbMemRequest}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.validity.valid) {
|
||||
dispatch(setDBMemRequest(event.target.value));
|
||||
}
|
||||
cleanValidation(`dbMemRequest`);
|
||||
}}
|
||||
pattern={"[0-9]*"}
|
||||
key={`dbMemRequest`}
|
||||
error={validationErrors[`dbMemRequest`] || ""}
|
||||
overlayObject={
|
||||
<InputUnitMenu
|
||||
id={"size-unit"}
|
||||
onUnitChange={() => {}}
|
||||
unitSelected={"Gi"}
|
||||
unitsList={[{ label: "Gi", value: "Gi" }]}
|
||||
disabled={true}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} paddingBottom={2}>
|
||||
<InputBoxWrapper
|
||||
id={`serviceAccountName`}
|
||||
label={"Service Account"}
|
||||
placeholder={"Service Account Name"}
|
||||
name={`serviceAccountName`}
|
||||
value={serviceAccountName}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.validity.valid) {
|
||||
dispatch(setServiceAccountName(event.target.value));
|
||||
}
|
||||
cleanValidation(`serviceAccountName`);
|
||||
}}
|
||||
key={`serviceAccountName`}
|
||||
pattern={"^[a-zA-Z0-9-.]{1,253}$"}
|
||||
error={validationErrors[`serviceAccountName`] || ""}
|
||||
/>
|
||||
</Grid>
|
||||
{labels !== null && (
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>Labels</span>
|
||||
<KeyPairEdit
|
||||
newValues={labels}
|
||||
setNewValues={setLabels}
|
||||
paramName={"Labels"}
|
||||
error={labelsError}
|
||||
setError={setLabelsError}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{annotations !== null && (
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>Annotations</span>
|
||||
<KeyPairEdit
|
||||
newValues={annotations}
|
||||
setNewValues={setAnnotations}
|
||||
paramName={"Annotations"}
|
||||
error={annotationsError}
|
||||
setError={setAnnotationsError}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{nodeSelector !== null && (
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>Node Selector</span>
|
||||
<KeyPairEdit
|
||||
newValues={nodeSelector}
|
||||
setNewValues={setNodeSelector}
|
||||
paramName={"Node Selector"}
|
||||
error={nodeSelectorError}
|
||||
setError={setNodeSelectorError}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{dbLabels !== null && (
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>DB Labels</span>
|
||||
<KeyPairEdit
|
||||
newValues={dbLabels}
|
||||
setNewValues={setDBLabels}
|
||||
paramName={"dbLabels"}
|
||||
error={dbLabelsError}
|
||||
setError={setDBLabelsError}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{dbAnnotations !== null && (
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>DB Annotations</span>
|
||||
<KeyPairEdit
|
||||
newValues={dbAnnotations}
|
||||
setNewValues={setDBAnnotations}
|
||||
paramName={"dbAnnotations"}
|
||||
error={dbAnnotationsError}
|
||||
setError={setDBAnnotationsError}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{dbNodeSelector !== null && (
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<span className={classes.inputLabel}>DB Node Selector</span>
|
||||
<KeyPairEdit
|
||||
newValues={dbNodeSelector}
|
||||
setNewValues={setDBNodeSelector}
|
||||
paramName={"DB Node Selector"}
|
||||
error={dbNodeSelectorError}
|
||||
setError={setDBNodeSelectorError}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12} textAlign={"right"}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={!checkValid()}
|
||||
onClick={() => submitLoggingInfo()}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(TenantAuditLogging);
|
||||
@@ -59,7 +59,7 @@ const TenantSummary = withSuspense(React.lazy(() => import("./TenantSummary")));
|
||||
const TenantLicense = withSuspense(React.lazy(() => import("./TenantLicense")));
|
||||
const PoolsSummary = withSuspense(React.lazy(() => import("./PoolsSummary")));
|
||||
const PodsSummary = withSuspense(React.lazy(() => import("./PodsSummary")));
|
||||
const TenantLogging = withSuspense(React.lazy(() => import("./TenantLogging")));
|
||||
const TenantLogging = withSuspense(React.lazy(() => import("./TenantAuditLogsScreen")));
|
||||
const TenantEvents = withSuspense(React.lazy(() => import("./TenantEvents")));
|
||||
const TenantCSR = withSuspense(React.lazy(() => import("./TenantCSR")));
|
||||
const VolumesSummary = withSuspense(
|
||||
|
||||
@@ -1,500 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { connect, useSelector } from "react-redux";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
searchField,
|
||||
tenantDetailsStyles,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { DialogContentText } from "@mui/material";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import api from "../../../../common/api";
|
||||
import { ITenantLogsStruct } from "../ListTenants/types";
|
||||
import { AppState, useAppDispatch } from "../../../../store";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import { EditIcon } from "../../../../icons";
|
||||
import EditTenantLogsModal from "./EditTenantLogsModal";
|
||||
import KeyPairView from "./KeyPairView";
|
||||
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
|
||||
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import RBIconButton from "../../Buckets/BucketDetails/SummaryItems/RBIconButton";
|
||||
import { niceBytes } from "../../../../common/utils";
|
||||
import Loader from "../../Common/Loader/Loader";
|
||||
import { setErrorSnackMessage } from "../../../../systemSlice";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
interface ITenantLogs {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...tenantDetailsStyles,
|
||||
paperContainer: {
|
||||
padding: "15px 15px 15px 50px",
|
||||
},
|
||||
...actionsTray,
|
||||
...searchField,
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const TenantLogging = ({ classes }: ITenantLogs) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const params = useParams();
|
||||
|
||||
const loadingTenant = useSelector(
|
||||
(state: AppState) => state.tenants.loadingTenant
|
||||
);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
|
||||
const [loadingTenantLogs, setLoadingTenantLogs] = useState<boolean>(true);
|
||||
const [logInfo, setLogInfo] = useState<ITenantLogsStruct>();
|
||||
const [edit, setEdit] = useState<boolean>(false);
|
||||
const [disabled, setDisabled] = useState<boolean>(false);
|
||||
const [preDisabled, setPreDisabled] = useState<boolean>(false);
|
||||
const [disableDialogOpen, setDisableDialogOpen] = useState<boolean>(false);
|
||||
const [enableDialogOpen, setEnableDialogOpen] = useState<boolean>(false);
|
||||
|
||||
const tenantName = params.tenantName;
|
||||
const tenantNamespace = params.tenantNamespace;
|
||||
|
||||
useEffect(() => {
|
||||
if (loadingTenantLogs) {
|
||||
api
|
||||
.invoke(
|
||||
"GET",
|
||||
`/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}/log`
|
||||
)
|
||||
.then((result: ITenantLogsStruct) => {
|
||||
setLogInfo(result);
|
||||
setPreDisabled(result.disabled);
|
||||
setDisabled(result.disabled);
|
||||
setLoadingTenantLogs(false);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(
|
||||
setErrorSnackMessage({
|
||||
errorMessage: "Error getting tenant logs",
|
||||
detailedError: err.detailedError,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
}, [
|
||||
tenantName,
|
||||
tenantNamespace,
|
||||
loadingTenantLogs,
|
||||
setDisabled,
|
||||
disabled,
|
||||
dispatch,
|
||||
]);
|
||||
|
||||
const onCloseEditAndRefresh = () => {
|
||||
setDisableDialogOpen(false);
|
||||
setEdit(false);
|
||||
setLoadingTenantLogs(true);
|
||||
};
|
||||
|
||||
const onCloseEnableAndRefresh = () => {
|
||||
setEnableDialogOpen(false);
|
||||
setDisabled(false);
|
||||
setLoadingTenantLogs(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<ConfirmDialog
|
||||
title="Disable Logging?"
|
||||
confirmText="Disable"
|
||||
isOpen={disableDialogOpen}
|
||||
onConfirm={() => {
|
||||
api
|
||||
.invoke(
|
||||
"POST",
|
||||
`/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}/disable-logging`
|
||||
)
|
||||
.then(() => {
|
||||
setPreDisabled(true);
|
||||
setDisabled(true);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(
|
||||
setErrorSnackMessage({
|
||||
errorMessage: "Error disabling logging",
|
||||
detailedError: err.detailedError,
|
||||
})
|
||||
);
|
||||
});
|
||||
onCloseEditAndRefresh();
|
||||
}}
|
||||
onClose={() => setDisableDialogOpen(false)}
|
||||
confirmationContent={
|
||||
<DialogContentText>
|
||||
Disabling logging will erase any custom values you have used to
|
||||
configure logging
|
||||
</DialogContentText>
|
||||
}
|
||||
/>
|
||||
<ConfirmDialog
|
||||
title="Enable Logging?"
|
||||
confirmText="Enable"
|
||||
isOpen={enableDialogOpen}
|
||||
onConfirm={() => {
|
||||
api
|
||||
.invoke(
|
||||
"POST",
|
||||
`/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}/enable-logging`
|
||||
)
|
||||
.then(() => {
|
||||
setPreDisabled(false);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(
|
||||
setErrorSnackMessage({
|
||||
errorMessage: "Error enabling logging",
|
||||
detailedError: err.detailedError,
|
||||
})
|
||||
);
|
||||
});
|
||||
onCloseEnableAndRefresh();
|
||||
}}
|
||||
onClose={() => setEnableDialogOpen(false)}
|
||||
confirmationContent={
|
||||
<DialogContentText>
|
||||
Logging will be enabled with default values
|
||||
</DialogContentText>
|
||||
}
|
||||
/>
|
||||
{edit && tenant !== null && logInfo != null && !disabled && (
|
||||
<EditTenantLogsModal
|
||||
open={edit}
|
||||
onClose={onCloseEditAndRefresh}
|
||||
tenant={tenant}
|
||||
image={logInfo.image}
|
||||
labels={logInfo.labels}
|
||||
annotations={logInfo.annotations}
|
||||
nodeSelector={logInfo.nodeSelector}
|
||||
diskCapacityGB={logInfo.diskCapacityGB}
|
||||
serviceAccountName={logInfo.serviceAccountName}
|
||||
dbImage={logInfo.dbImage}
|
||||
dbInitImage={logInfo.dbInitImage}
|
||||
dbLabels={logInfo.dbLabels}
|
||||
dbAnnotations={logInfo.dbAnnotations}
|
||||
dbNodeSelector={logInfo.dbNodeSelector}
|
||||
dbServiceAccountName={logInfo.dbServiceAccountName}
|
||||
cpuRequest={logInfo.logCPURequest}
|
||||
memRequest={logInfo.logMemRequest}
|
||||
dbCPURequest={logInfo.logDBCPURequest}
|
||||
dbMemRequest={logInfo.logDBMemRequest}
|
||||
/>
|
||||
)}
|
||||
<Grid container alignItems={"center"}>
|
||||
<Grid item xs>
|
||||
<h1 className={classes.sectionTitle}>Audit Log</h1>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<FormSwitchWrapper
|
||||
value="enableLogging"
|
||||
id="enableLogging"
|
||||
name="enableLogging"
|
||||
checked={!preDisabled}
|
||||
onChange={(e) => {
|
||||
const targetD = e.target;
|
||||
const checked = targetD.checked;
|
||||
if (checked) {
|
||||
setEnableDialogOpen(true);
|
||||
} else {
|
||||
setDisableDialogOpen(true);
|
||||
}
|
||||
}}
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
{!disabled && !loadingTenantLogs && (
|
||||
<Paper className={classes.paperContainer}>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Grid container alignItems={"center"}>
|
||||
<Grid xs={8}>
|
||||
<h3>Configuration</h3>
|
||||
</Grid>
|
||||
<Grid xs={4} justifyContent={"end"} textAlign={"right"}>
|
||||
<RBIconButton
|
||||
tooltip={"Edit Logging configuration"}
|
||||
text={"Edit"}
|
||||
onClick={() => {
|
||||
setEdit(true);
|
||||
}}
|
||||
icon={<EditIcon />}
|
||||
color="primary"
|
||||
variant={"contained"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<hr className={classes.hrClass} />
|
||||
<table width={"100%"}>
|
||||
<tbody>
|
||||
{loadingTenant ? (
|
||||
<tr>
|
||||
<td className={classes.centerAlign} colSpan={4}>
|
||||
<Loader />
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<Fragment>
|
||||
{logInfo?.logCPURequest != null && (
|
||||
<tr>
|
||||
<td className={classes.titleCol}>CPU Request:</td>
|
||||
<td>{logInfo?.logCPURequest}</td>
|
||||
</tr>
|
||||
)}
|
||||
{logInfo?.logMemRequest != null && (
|
||||
<tr>
|
||||
<td className={classes.titleCol}>Memory Request:</td>
|
||||
<td>{niceBytes(logInfo?.logMemRequest, true)}</td>
|
||||
</tr>
|
||||
)}
|
||||
{logInfo?.image != null && (
|
||||
<tr>
|
||||
<td className={classes.titleCol}>Image:</td>
|
||||
<td>{logInfo?.image}</td>
|
||||
</tr>
|
||||
)}
|
||||
{logInfo?.diskCapacityGB != null && (
|
||||
<tr>
|
||||
<td className={classes.titleCol}>
|
||||
Disk Capacity (GB):
|
||||
</td>
|
||||
<td>{logInfo?.diskCapacityGB}</td>
|
||||
</tr>
|
||||
)}
|
||||
{logInfo?.serviceAccountName != null && (
|
||||
<tr>
|
||||
<td className={classes.titleCol}>Service Account:</td>
|
||||
<td>{logInfo?.serviceAccountName}</td>
|
||||
</tr>
|
||||
)}
|
||||
{logInfo?.labels != null && logInfo.labels.length > 0 && (
|
||||
<Fragment>
|
||||
<tr>
|
||||
<td>
|
||||
<h4>Labels</h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<KeyPairView
|
||||
records={
|
||||
logInfo != null && logInfo.labels.length > 0
|
||||
? logInfo.labels
|
||||
: []
|
||||
}
|
||||
recordName="Labels"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
)}
|
||||
{logInfo?.annotations != null &&
|
||||
logInfo.annotations.length > 0 && (
|
||||
<Fragment>
|
||||
<tr>
|
||||
<td>
|
||||
<h4>Annotations</h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<KeyPairView
|
||||
records={
|
||||
logInfo != null &&
|
||||
logInfo.annotations.length > 0
|
||||
? logInfo.annotations
|
||||
: []
|
||||
}
|
||||
recordName="Annotations"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
)}
|
||||
{logInfo?.nodeSelector != null &&
|
||||
logInfo.nodeSelector.length > 0 && (
|
||||
<Fragment>
|
||||
<tr>
|
||||
<td>
|
||||
<h4>Node Selector</h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<KeyPairView
|
||||
records={
|
||||
logInfo != null &&
|
||||
logInfo.nodeSelector.length > 0
|
||||
? logInfo.nodeSelector
|
||||
: []
|
||||
}
|
||||
recordName="Node Selector"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Database Details</h2>
|
||||
<hr className={classes.hrClass} />
|
||||
<table width={"100%"}>
|
||||
<tbody>
|
||||
{loadingTenant ? (
|
||||
<tr>
|
||||
<td className={classes.centerAlign} colSpan={4}>
|
||||
<Loader />
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<Fragment>
|
||||
{logInfo?.logDBCPURequest != null && (
|
||||
<tr>
|
||||
<td className={classes.titleCol}>DB CPU Request:</td>
|
||||
<td>{logInfo?.logDBCPURequest}</td>
|
||||
</tr>
|
||||
)}
|
||||
{logInfo?.logDBMemRequest != null && (
|
||||
<tr>
|
||||
<td className={classes.titleCol}>
|
||||
DB Memory Request:
|
||||
</td>
|
||||
<td>{niceBytes(logInfo?.logDBMemRequest, true)}</td>
|
||||
</tr>
|
||||
)}
|
||||
{logInfo?.dbImage != null && (
|
||||
<tr>
|
||||
<td className={classes.titleCol}>Postgres Image:</td>
|
||||
<td>{logInfo?.dbImage}</td>
|
||||
</tr>
|
||||
)}
|
||||
{logInfo?.dbServiceAccountName != null && (
|
||||
<tr>
|
||||
<td className={classes.titleCol}>Service Account:</td>
|
||||
<td>{logInfo?.dbServiceAccountName}</td>
|
||||
</tr>
|
||||
)}
|
||||
{logInfo?.dbLabels != null &&
|
||||
logInfo.dbLabels.length > 0 && (
|
||||
<Fragment>
|
||||
<tr>
|
||||
<td>
|
||||
<h4>Labels</h4>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<KeyPairView
|
||||
records={
|
||||
logInfo != null &&
|
||||
logInfo.dbLabels?.length > 0
|
||||
? logInfo.dbLabels
|
||||
: []
|
||||
}
|
||||
recordName="labels"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
)}
|
||||
{logInfo?.annotations != null &&
|
||||
logInfo.dbAnnotations.length > 0 && (
|
||||
<Fragment>
|
||||
<tr>
|
||||
<td>
|
||||
<h4>Annotations</h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<KeyPairView
|
||||
records={
|
||||
logInfo != null &&
|
||||
logInfo.dbAnnotations?.length > 0
|
||||
? logInfo.dbAnnotations
|
||||
: []
|
||||
}
|
||||
recordName="annotations"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
)}
|
||||
{logInfo?.nodeSelector != null &&
|
||||
logInfo.dbNodeSelector.length > 0 && (
|
||||
<Fragment>
|
||||
<tr>
|
||||
<td>
|
||||
<h4>Node Selector </h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<KeyPairView
|
||||
records={
|
||||
logInfo != null &&
|
||||
logInfo.dbNodeSelector?.length > 0
|
||||
? logInfo.dbNodeSelector
|
||||
: []
|
||||
}
|
||||
recordName="node selectors"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Paper>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
loadingTenant: state.tenants.loadingTenant,
|
||||
selectedTenant: state.tenants.currentTenant,
|
||||
tenant: state.tenants.tenantInfo,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, null);
|
||||
|
||||
export default withStyles(styles)(connector(TenantLogging));
|
||||
@@ -0,0 +1,137 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { IKeyValue } from "../ListTenants/types";
|
||||
|
||||
export interface IEditTenantAuditLogging {
|
||||
auditLoggingEnabled: boolean;
|
||||
image: string;
|
||||
labels: IKeyValue[];
|
||||
annotations: IKeyValue[];
|
||||
nodeSelector: IKeyValue[];
|
||||
diskCapacityGB: number;
|
||||
serviceAccountName: string;
|
||||
dbImage: string;
|
||||
dbInitImage: string;
|
||||
dbLabels: IKeyValue[];
|
||||
dbAnnotations: IKeyValue[];
|
||||
dbNodeSelector: IKeyValue[];
|
||||
dbServiceAccountName: string;
|
||||
cpuRequest: string;
|
||||
memRequest: string;
|
||||
dbCPURequest: string;
|
||||
dbMemRequest: string;
|
||||
}
|
||||
|
||||
const initialState: IEditTenantAuditLogging = {
|
||||
auditLoggingEnabled: false,
|
||||
image: "",
|
||||
labels: [{ key: " ", value: " " }],
|
||||
annotations: [{ key: " ", value: " " }],
|
||||
nodeSelector: [{ key: " ", value: " " }],
|
||||
diskCapacityGB: 0,
|
||||
serviceAccountName: "",
|
||||
dbCPURequest: "",
|
||||
dbMemRequest: "",
|
||||
dbImage: "",
|
||||
dbInitImage: "",
|
||||
dbLabels: [{ key: " ", value: " " }],
|
||||
dbAnnotations: [{ key: " ", value: " " }],
|
||||
dbNodeSelector: [{ key: " ", value: " " }],
|
||||
dbServiceAccountName: "",
|
||||
cpuRequest: "",
|
||||
memRequest: "",
|
||||
};
|
||||
|
||||
export const editTenantAuditLoggingSlice = createSlice({
|
||||
name: "editTenantAuditLogging",
|
||||
initialState,
|
||||
reducers: {
|
||||
setAuditLoggingEnabled: (state, action: PayloadAction<boolean>) => {
|
||||
state.auditLoggingEnabled = action.payload;
|
||||
},
|
||||
setImage: (state, action: PayloadAction<string>) => {
|
||||
state.image = action.payload;
|
||||
},
|
||||
setDBImage: (state, action: PayloadAction<string>) => {
|
||||
state.dbImage = action.payload;
|
||||
},
|
||||
setDBInitImage: (state, action: PayloadAction<string>) => {
|
||||
state.dbInitImage = action.payload;
|
||||
},
|
||||
setLabels: (state, action: PayloadAction<IKeyValue[]>) => {
|
||||
state.labels = action.payload;
|
||||
},
|
||||
setAnnotations: (state, action: PayloadAction<IKeyValue[]>) => {
|
||||
state.annotations = action.payload;
|
||||
},
|
||||
setNodeSelector: (state, action: PayloadAction<IKeyValue[]>) => {
|
||||
state.nodeSelector = action.payload;
|
||||
},
|
||||
setDBLabels: (state, action: PayloadAction<IKeyValue[]>) => {
|
||||
state.dbLabels = action.payload;
|
||||
},
|
||||
setDBAnnotations: (state, action: PayloadAction<IKeyValue[]>) => {
|
||||
state.dbAnnotations = action.payload;
|
||||
},
|
||||
setDBNodeSelector: (state, action: PayloadAction<IKeyValue[]>) => {
|
||||
state.dbNodeSelector = action.payload;
|
||||
},
|
||||
setDiskCapacityGB: (state, action: PayloadAction<number>) => {
|
||||
state.diskCapacityGB = action.payload;
|
||||
},
|
||||
setServiceAccountName: (state, action: PayloadAction<string>) => {
|
||||
state.serviceAccountName = action.payload;
|
||||
},
|
||||
setDBServiceAccountName: (state, action: PayloadAction<string>) => {
|
||||
state.dbServiceAccountName = action.payload;
|
||||
},
|
||||
setCPURequest: (state, action: PayloadAction<string>) => {
|
||||
state.cpuRequest = action.payload;
|
||||
},
|
||||
setMemRequest: (state, action: PayloadAction<string>) => {
|
||||
state.memRequest = action.payload;
|
||||
},
|
||||
setDBCPURequest: (state, action: PayloadAction<string>) => {
|
||||
state.dbCPURequest = action.payload;
|
||||
},
|
||||
setDBMemRequest: (state, action: PayloadAction<string>) => {
|
||||
state.dbMemRequest = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
setAuditLoggingEnabled,
|
||||
setImage,
|
||||
setDBImage,
|
||||
setDBInitImage,
|
||||
setLabels,
|
||||
setAnnotations,
|
||||
setNodeSelector,
|
||||
setDBLabels,
|
||||
setDBAnnotations,
|
||||
setDBNodeSelector,
|
||||
setDiskCapacityGB,
|
||||
setServiceAccountName,
|
||||
setDBServiceAccountName,
|
||||
setCPURequest,
|
||||
setMemRequest,
|
||||
setDBCPURequest,
|
||||
setDBMemRequest,
|
||||
} = editTenantAuditLoggingSlice.actions;
|
||||
|
||||
export default editTenantAuditLoggingSlice.reducer;
|
||||
@@ -32,6 +32,7 @@ import createUserReducer from "./screens/Console/Users/AddUsersSlice";
|
||||
import addPoolReducer from "./screens/Console/Tenants/TenantDetails/Pools/AddPool/addPoolSlice";
|
||||
import editPoolReducer from "./screens/Console/Tenants/TenantDetails/Pools/EditPool/editPoolSlice";
|
||||
import editTenantMonitoringReducer from "./screens/Console/Tenants/TenantDetails/tenantMonitoringSlice";
|
||||
import editTenantAuditLoggingReducer from "./screens/Console/Tenants/TenantDetails/tenantAuditLogSlice";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
system: systemReducer,
|
||||
@@ -51,6 +52,7 @@ const rootReducer = combineReducers({
|
||||
addPool: addPoolReducer,
|
||||
editPool: editPoolReducer,
|
||||
editTenantMonitoring: editTenantMonitoringReducer,
|
||||
editTenantLogging: editTenantAuditLoggingReducer,
|
||||
});
|
||||
|
||||
export const store = configureStore({
|
||||
|
||||
Reference in New Issue
Block a user