Create security context component and add to edit Prometheus Monitoring (#2115)

This commit is contained in:
jinapurapu
2022-07-07 12:52:30 -07:00
committed by GitHub
parent cf0e326b82
commit cce054bbe8
9 changed files with 200 additions and 7 deletions

View File

@@ -63,6 +63,9 @@ type TenantMonitoringInfo struct {
// prometheus enabled // prometheus enabled
PrometheusEnabled bool `json:"prometheusEnabled,omitempty"` PrometheusEnabled bool `json:"prometheusEnabled,omitempty"`
// security context
SecurityContext *SecurityContext `json:"securityContext,omitempty"`
// service account name // service account name
ServiceAccountName string `json:"serviceAccountName,omitempty"` ServiceAccountName string `json:"serviceAccountName,omitempty"`
@@ -92,6 +95,10 @@ func (m *TenantMonitoringInfo) Validate(formats strfmt.Registry) error {
res = append(res, err) res = append(res, err)
} }
if err := m.validateSecurityContext(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 { if len(res) > 0 {
return errors.CompositeValidationError(res...) return errors.CompositeValidationError(res...)
} }
@@ -176,6 +183,25 @@ func (m *TenantMonitoringInfo) validateNodeSelector(formats strfmt.Registry) err
return nil return nil
} }
func (m *TenantMonitoringInfo) validateSecurityContext(formats strfmt.Registry) error {
if swag.IsZero(m.SecurityContext) { // not required
return nil
}
if m.SecurityContext != nil {
if err := m.SecurityContext.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("securityContext")
}
return err
}
}
return nil
}
// ContextValidate validate this tenant monitoring info based on the context it is used // ContextValidate validate this tenant monitoring info based on the context it is used
func (m *TenantMonitoringInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error { func (m *TenantMonitoringInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error var res []error
@@ -192,6 +218,10 @@ func (m *TenantMonitoringInfo) ContextValidate(ctx context.Context, formats strf
res = append(res, err) res = append(res, err)
} }
if err := m.contextValidateSecurityContext(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 { if len(res) > 0 {
return errors.CompositeValidationError(res...) return errors.CompositeValidationError(res...)
} }
@@ -258,6 +288,22 @@ func (m *TenantMonitoringInfo) contextValidateNodeSelector(ctx context.Context,
return nil return nil
} }
func (m *TenantMonitoringInfo) contextValidateSecurityContext(ctx context.Context, formats strfmt.Registry) error {
if m.SecurityContext != nil {
if err := m.SecurityContext.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("securityContext")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation // MarshalBinary interface implementation
func (m *TenantMonitoringInfo) MarshalBinary() ([]byte, error) { func (m *TenantMonitoringInfo) MarshalBinary() ([]byte, error) {
if m == nil { if m == nil {

View File

@@ -4301,6 +4301,10 @@ func init() {
"prometheusEnabled": { "prometheusEnabled": {
"type": "boolean" "type": "boolean"
}, },
"securityContext": {
"type": "object",
"$ref": "#/definitions/securityContext"
},
"serviceAccountName": { "serviceAccountName": {
"type": "string" "type": "string"
}, },
@@ -9678,6 +9682,10 @@ func init() {
"prometheusEnabled": { "prometheusEnabled": {
"type": "boolean" "type": "boolean"
}, },
"securityContext": {
"type": "object",
"$ref": "#/definitions/securityContext"
},
"serviceAccountName": { "serviceAccountName": {
"type": "string" "type": "string"
}, },

View File

@@ -2137,11 +2137,10 @@ func getTenantMonitoringResponse(session *models.Principal, params operator_api.
client: opClientClientSet, client: opClientClientSet,
} }
minInst, err := opClient.TenantGet(ctx, params.Namespace, params.Tenant, metav1.GetOptions{}) minInst, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
if err != nil { if err != nil {
return nil, restapi.ErrorWithContext(ctx, err) return nil, restapi.ErrorWithContext(ctx, err)
} }
monitoringInfo := &models.TenantMonitoringInfo{} monitoringInfo := &models.TenantMonitoringInfo{}
if minInst.Spec.Prometheus != nil { if minInst.Spec.Prometheus != nil {
@@ -2212,7 +2211,9 @@ func getTenantMonitoringResponse(session *models.Principal, params operator_api.
if len(minInst.Spec.Prometheus.SideCarImage) != 0 { if len(minInst.Spec.Prometheus.SideCarImage) != 0 {
monitoringInfo.SidecarImage = minInst.Spec.Prometheus.SideCarImage monitoringInfo.SidecarImage = minInst.Spec.Prometheus.SideCarImage
} }
if minInst.Spec.Prometheus.SecurityContext != nil {
monitoringInfo.SecurityContext = convertK8sSCToModelSC(minInst.Spec.Prometheus.SecurityContext)
}
return monitoringInfo, nil return monitoringInfo, nil
} }
@@ -2306,12 +2307,16 @@ func setTenantMonitoringResponse(session *models.Principal, params operator_api.
if err == nil { if err == nil {
*minTenant.Spec.Prometheus.DiskCapacityDB = diskCapacityGB *minTenant.Spec.Prometheus.DiskCapacityDB = diskCapacityGB
} }
minTenant.Spec.Prometheus.ServiceAccountName = params.Data.ServiceAccountName minTenant.Spec.Prometheus.ServiceAccountName = params.Data.ServiceAccountName
minTenant.Spec.Prometheus.SecurityContext, err = convertModelSCToK8sSC(params.Data.SecurityContext)
if err != nil {
return false, restapi.ErrorWithContext(ctx, err)
}
_, err = opClient.TenantUpdate(ctx, minTenant, metav1.UpdateOptions{}) _, err = opClient.TenantUpdate(ctx, minTenant, metav1.UpdateOptions{})
if err != nil { if err != nil {
return false, restapi.ErrorWithContext(ctx, err) return false, restapi.ErrorWithContext(ctx, err)
} }
return true, nil return true, nil
} }

View File

@@ -199,6 +199,7 @@ export interface ITenantMonitoringStruct {
prometheusEnabled: boolean; prometheusEnabled: boolean;
monitoringCPURequest: string; monitoringCPURequest: string;
monitoringMemRequest: string; monitoringMemRequest: string;
securityContext: ISecurityContext;
} }
export interface IKeyValue { export interface IKeyValue {

View File

@@ -14,7 +14,6 @@
// You should have received a copy of the GNU Affero General Public License // 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/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
//import { ISecurityContext} from "../types";
import { Theme } from "@mui/material/styles"; import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles"; import withStyles from "@mui/styles/withStyles";
@@ -56,9 +55,13 @@ import {
setServiceAccountName, setServiceAccountName,
setCPURequest, setCPURequest,
setMemRequest, setMemRequest,
setRunAsGroup,
setFSGroup,
setRunAsUser,
setRunAsNonRoot,
} from "../TenantDetails/tenantMonitoringSlice"; } from "../TenantDetails/tenantMonitoringSlice";
import { clearValidationError } from "../utils"; import { clearValidationError } from "../utils";
import SecurityContextSelector from "../securityContextSelector";
interface ITenantMonitoring { interface ITenantMonitoring {
classes: any; classes: any;
@@ -135,6 +138,18 @@ const TenantMonitoring = ({ classes }: ITenantMonitoring) => {
const [annotationsError, setAnnotationsError] = useState<any>({}); const [annotationsError, setAnnotationsError] = useState<any>({});
const [nodeSelectorError, setNodeSelectorError] = useState<any>({}); const [nodeSelectorError, setNodeSelectorError] = useState<any>({});
const runAsGroup = useSelector(
(state: AppState) => state.editTenantMonitoring.runAsGroup
);
const runAsUser = useSelector(
(state: AppState) => state.editTenantMonitoring.runAsUser
);
const fsGroup = useSelector(
(state: AppState) => state.editTenantMonitoring.fsGroup
);
const runAsNonRoot = useSelector(
(state: AppState) => state.editTenantMonitoring.runAsNonRoot
);
const cleanValidation = (fieldName: string) => { const cleanValidation = (fieldName: string) => {
setValidationErrors(clearValidationError(validationErrors, fieldName)); setValidationErrors(clearValidationError(validationErrors, fieldName));
}; };
@@ -167,6 +182,10 @@ const TenantMonitoring = ({ classes }: ITenantMonitoring) => {
res.nodeSelector != null res.nodeSelector != null
? setNodeSelector(res.nodeSelector) ? setNodeSelector(res.nodeSelector)
: setNodeSelector([{ key: "", value: "" }]); : setNodeSelector([{ key: "", value: "" }]);
dispatch(setRunAsGroup(res.securityContext.runAsGroup));
dispatch(setRunAsUser(res.securityContext.runAsUser));
dispatch(setRunAsNonRoot(res.securityContext.runAsNonRoot));
dispatch(setFSGroup(res.securityContext.fsGroup));
}; };
const trim = (x: IKeyValue[]): IKeyValue[] => { const trim = (x: IKeyValue[]): IKeyValue[] => {
@@ -221,6 +240,12 @@ const TenantMonitoring = ({ classes }: ITenantMonitoring) => {
const submitMonitoringInfo = () => { const submitMonitoringInfo = () => {
if (checkValid()) { if (checkValid()) {
const securityContext = {
runAsGroup: runAsGroup != null ? runAsGroup : "0",
runAsUser: runAsUser != null ? runAsUser : "0",
fsGroup: fsGroup != null ? fsGroup : "0",
runAsNonRoot: runAsNonRoot != null ? runAsNonRoot : true,
};
api api
.invoke( .invoke(
"PUT", "PUT",
@@ -237,6 +262,7 @@ const TenantMonitoring = ({ classes }: ITenantMonitoring) => {
storageClassName: storageClassName, storageClassName: storageClassName,
monitoringCPURequest: cpuRequest, monitoringCPURequest: cpuRequest,
monitoringMemRequest: memRequest + "Gi", monitoringMemRequest: memRequest + "Gi",
securityContext: securityContext,
} }
) )
.then(() => { .then(() => {
@@ -312,7 +338,7 @@ const TenantMonitoring = ({ classes }: ITenantMonitoring) => {
description="" description=""
/> />
</Grid> </Grid>
<Grid xs={12}> <Grid item xs={12}>
<hr className={classes.hrClass} /> <hr className={classes.hrClass} />
</Grid> </Grid>
</Grid> </Grid>
@@ -518,6 +544,21 @@ const TenantMonitoring = ({ classes }: ITenantMonitoring) => {
/> />
</Grid> </Grid>
)} )}
<Grid item xs={12} className={classes.formFieldRow}>
<SecurityContextSelector
classes={classes}
runAsGroup={runAsGroup}
runAsUser={runAsUser}
fsGroup={fsGroup}
runAsNonRoot={runAsNonRoot}
setFSGroup={(value: string) => dispatch(setFSGroup(value))}
setRunAsUser={(value: string) => dispatch(setRunAsUser(value))}
setRunAsGroup={(value: string) => dispatch(setRunAsGroup(value))}
setRunAsNonRoot={(value: boolean) =>
dispatch(setRunAsNonRoot(value))
}
/>
</Grid>
<Grid item xs={12} textAlign={"right"}> <Grid item xs={12} textAlign={"right"}>
<Button <Button
type="submit" type="submit"

View File

@@ -29,6 +29,10 @@ export interface IEditTenantMonitoring {
serviceAccountName: string; serviceAccountName: string;
monitoringCPURequest: string; monitoringCPURequest: string;
monitoringMemRequest: string; monitoringMemRequest: string;
runAsUser: string;
runAsGroup: string;
fsGroup: string;
runAsNonRoot: boolean;
} }
const initialState: IEditTenantMonitoring = { const initialState: IEditTenantMonitoring = {
@@ -44,6 +48,10 @@ const initialState: IEditTenantMonitoring = {
serviceAccountName: "", serviceAccountName: "",
monitoringCPURequest: "", monitoringCPURequest: "",
monitoringMemRequest: "", monitoringMemRequest: "",
runAsUser: "1000",
runAsGroup: "1000",
fsGroup: "1000",
runAsNonRoot: true,
}; };
export const editTenantMonitoringSlice = createSlice({ export const editTenantMonitoringSlice = createSlice({
@@ -86,6 +94,18 @@ export const editTenantMonitoringSlice = createSlice({
setMemRequest: (state, action: PayloadAction<string>) => { setMemRequest: (state, action: PayloadAction<string>) => {
state.monitoringMemRequest = action.payload; state.monitoringMemRequest = action.payload;
}, },
setRunAsUser: (state, action: PayloadAction<string>) => {
state.runAsUser = action.payload;
},
setRunAsGroup: (state, action: PayloadAction<string>) => {
state.runAsGroup = action.payload;
},
setFSGroup: (state, action: PayloadAction<string>) => {
state.fsGroup = action.payload;
},
setRunAsNonRoot: (state, action: PayloadAction<boolean>) => {
state.runAsNonRoot = action.payload;
},
}, },
}); });
@@ -102,6 +122,10 @@ export const {
setServiceAccountName, setServiceAccountName,
setCPURequest, setCPURequest,
setMemRequest, setMemRequest,
setRunAsUser,
setRunAsGroup,
setFSGroup,
setRunAsNonRoot,
} = editTenantMonitoringSlice.actions; } = editTenantMonitoringSlice.actions;
export default editTenantMonitoringSlice.reducer; export default editTenantMonitoringSlice.reducer;

View File

@@ -0,0 +1,57 @@
// 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 { IEditMonitoringSecurityContext } from "./types";
const initialState: IEditMonitoringSecurityContext = {
securityContextEnabled: false,
runAsUser: "1000",
runAsGroup: "1000",
fsGroup: "1000",
runAsNonRoot: true,
};
export const editMonitoringSecurityContextSlice = createSlice({
name: "editMonitoringSecurityContext",
initialState,
reducers: {
setSecurityContextEnabled: (state, action: PayloadAction<boolean>) => {
state.securityContextEnabled = action.payload;
},
setRunAsUser: (state, action: PayloadAction<string>) => {
state.runAsUser = action.payload;
},
setRunAsGroup: (state, action: PayloadAction<string>) => {
state.runAsGroup = action.payload;
},
setFSGroup: (state, action: PayloadAction<string>) => {
state.fsGroup = action.payload;
},
setRunAsNonRoot: (state, action: PayloadAction<boolean>) => {
state.runAsNonRoot = action.payload;
},
},
});
export const {
setSecurityContextEnabled,
setRunAsUser,
setRunAsGroup,
setFSGroup,
setRunAsNonRoot,
} = editMonitoringSecurityContextSlice.actions;
export default editMonitoringSecurityContextSlice.reducer;

View File

@@ -338,3 +338,11 @@ export interface ITenantIdentityProviderResponse {
user_dn_search_filter: string; user_dn_search_filter: string;
}; };
} }
export interface IEditMonitoringSecurityContext {
securityContextEnabled: boolean;
runAsUser: string;
runAsGroup: string;
fsGroup: string;
runAsNonRoot: boolean;
}

View File

@@ -3272,6 +3272,9 @@ definitions:
type: string type: string
monitoringMemRequest: monitoringMemRequest:
type: string type: string
securityContext:
type: object
$ref: "#/definitions/securityContext"
label: label:
type: object type: object