This is an automated email from the ASF dual-hosted git repository.
yashmayya pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new a94380a492 Render new UI options for rebalance server operation
(#15256)
a94380a492 is described below
commit a94380a49234bb8ba0903bfbdf0dadb110d73cfb
Author: Soumya Himanish Mohapatra
<[email protected]>
AuthorDate: Wed Mar 19 10:52:52 2025 +0530
Render new UI options for rebalance server operation (#15256)
---
.../main/resources/app/components/CustomDialog.tsx | 34 +++-
.../RebalanceServerConfigurationOption.tsx | 43 +++++
.../RebalanceServerConfigurationOptionInteger.tsx | 57 ++++++
.../RebalanceServerConfigurationOptionLabel.tsx | 38 ++++
.../RebalanceServerConfigurationOptionSelect.tsx | 63 +++++++
...alanceServerConfigurationOptionToggleSwitch.tsx | 54 ++++++
.../RebalanceServerConfigurationSection.tsx | 68 +++++++
.../RebalanceServerDialogHeader.tsx | 43 +++++
.../RebalanceServer/RebalanceServerOptions.ts | 168 +++++++++++++++++
.../Homepage/Operations/RebalanceServerTableOp.tsx | 200 ++++++++++-----------
10 files changed, 650 insertions(+), 118 deletions(-)
diff --git
a/pinot-controller/src/main/resources/app/components/CustomDialog.tsx
b/pinot-controller/src/main/resources/app/components/CustomDialog.tsx
index 60815d8e03..0e5fcc6fb4 100644
--- a/pinot-controller/src/main/resources/app/components/CustomDialog.tsx
+++ b/pinot-controller/src/main/resources/app/components/CustomDialog.tsx
@@ -17,8 +17,17 @@
* under the License.
*/
-import React from 'react';
-import { Button, Dialog, DialogActions, DialogContent, DialogTitle,
makeStyles, withStyles } from '@material-ui/core';
+import React, {ReactNode} from 'react';
+import {
+ Button,
+ Dialog,
+ DialogActions,
+ DialogContent,
+ DialogTitle,
+ Divider,
+ makeStyles,
+ withStyles
+} from '@material-ui/core';
import { red } from '@material-ui/core/colors';
const useStyles = makeStyles((theme) => ({
@@ -27,7 +36,7 @@ const useStyles = makeStyles((theme) => ({
minWidth: '600px'
},
"& .MuiDialogContent-root": {
- padding: 8
+ padding: '10px 24px',
}
},
dialogTitle: {
@@ -56,8 +65,11 @@ type Props = {
showCancelBtn?: boolean,
showOkBtn?: boolean,
size?: false | "xs" | "sm" | "md" | "lg" | "xl",
- disableBackdropClick?: boolean
- disableEscapeKeyDown?: boolean
+ disableBackdropClick?: boolean,
+ disableEscapeKeyDown?: boolean,
+ showTitleDivider?: boolean,
+ showFooterDivider?: boolean,
+ moreActions?: ReactNode
};
export default function CustomDialog({
@@ -72,7 +84,10 @@ export default function CustomDialog({
showOkBtn = true,
size,
disableBackdropClick = false,
- disableEscapeKeyDown = false
+ disableEscapeKeyDown = false,
+ showTitleDivider = false,
+ showFooterDivider = false,
+ moreActions
}: Props) {
const classes = useStyles();
@@ -89,16 +104,19 @@ export default function CustomDialog({
disableEscapeKeyDown={disableEscapeKeyDown}
>
<DialogTitle className={classes.dialogTitle}>{title}</DialogTitle>
+ {showTitleDivider && <Divider style={{ marginBottom: 10 }} />}
<DialogContent>
{children}
</DialogContent>
+ {showFooterDivider && <Divider style={{ marginBottom: 10 }} />}
<DialogActions>
{showCancelBtn &&
- <CancelButton onClick={handleClose} variant="outlined">
+ <CancelButton onClick={handleClose} style={{ textTransform: 'none' }}
variant="outlined">
{btnCancelText || 'Cancel'}
</CancelButton>}
+ {moreActions}
{showOkBtn &&
- <Button onClick={handleSave} variant="outlined" color="primary">
+ <Button onClick={handleSave} variant="contained" style={{
textTransform: 'none' }} color="primary">
{btnOkText || 'Save'}
</Button>}
</DialogActions>
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOption.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOption.tsx
new file mode 100644
index 0000000000..180c230621
--- /dev/null
+++
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOption.tsx
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {RebalanceServerOption} from "./RebalanceServerOptions";
+import {
+ RebalanceServerConfigurationOptionSwitch
+} from
"./RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionToggleSwitch";
+import React from 'react';
+import {
+ RebalanceServerConfigurationOptionInteger
+} from
"./RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionInteger";
+import {
+ RebalanceServerConfigurationOptionSelect
+} from
"./RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionSelect";
+
+export const RebalanceServerConfigurationOption = (
+ { option, handleConfigChange }: { option: RebalanceServerOption,
handleConfigChange: (config: { [key: string]: string | number | boolean }) =>
void }) => {
+ switch (option.type) {
+ case "BOOL":
+ return <RebalanceServerConfigurationOptionSwitch option={option}
handleConfigChange={handleConfigChange} />;
+ case "INTEGER":
+ return <RebalanceServerConfigurationOptionInteger option={option}
handleConfigChange={handleConfigChange} />;
+ case "SELECT":
+ return <RebalanceServerConfigurationOptionSelect option={option}
handleConfigChange={handleConfigChange} />;
+ default:
+ return null;
+ }
+}
\ No newline at end of file
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionInteger.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionInteger.tsx
new file mode 100644
index 0000000000..a209bdf73e
--- /dev/null
+++
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionInteger.tsx
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {Box, FormControl, TextField, Typography} from "@material-ui/core";
+import React, {useState} from "react";
+import {RebalanceServerOption} from "../RebalanceServerOptions";
+import {
+ RebalanceServerConfigurationOptionLabel
+} from
"./RebalanceServerConfigurationOptionLabel/RebalanceServerConfigurationOptionLabel";
+
+type RebalanceServerConfigurationOptionIntegerProps = {
+ option: RebalanceServerOption;
+ handleConfigChange: (config: { [key: string]: string | number | boolean })
=> void;
+}
+export const RebalanceServerConfigurationOptionInteger = (
+ { option, handleConfigChange }:
RebalanceServerConfigurationOptionIntegerProps
+) => {
+ const [value, setValue] = useState<number>(option.defaultValue as number);
+ return (
+ <Box display='flex' flexDirection='column'>
+ <FormControl fullWidth>
+ <RebalanceServerConfigurationOptionLabel option={option} />
+ <TextField
+ variant='outlined'
+ fullWidth
+ style={{ width: '100%' }}
+ size='small'
+ id={`rebalance-server-number-input-${option.name}`}
+ type='number'
+ value={value}
+ onChange={(e) => {
+ handleConfigChange(
+ {
+ [option.name]: parseInt(e.target.value)
+ });
+ setValue(parseInt(e.target.value));
+ }}/>
+ <Typography variant='caption'>{option.description}</Typography>
+ </FormControl>
+ </Box>
+ );
+}
\ No newline at end of file
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionLabel/RebalanceServerConfigurationOptionLabel.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionLabel/RebalanceServerConfigurationOptionLabel.tsx
new file mode 100644
index 0000000000..cbef81cc62
--- /dev/null
+++
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionLabel/RebalanceServerConfigurationOptionLabel.tsx
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {Box, Tooltip, Typography} from "@material-ui/core";
+import {ReportProblemOutlined} from "@material-ui/icons";
+import React from "react";
+import {RebalanceServerOption} from "../../RebalanceServerOptions";
+
+type RebalanceServerConfigurationOptionLabelProps = {
+ option: RebalanceServerOption;
+}
+export const RebalanceServerConfigurationOptionLabel = ({option}:
RebalanceServerConfigurationOptionLabelProps) => (
+ <Box display='flex' flexDirection='row' alignItems='center'>
+ <Typography variant='body2' style={{marginRight: 10, fontWeight:
"600"}}>
+ {option.label}
+ </Typography>
+ {option.markWithWarningIcon && (
+ <Tooltip title={option.toolTip} arrow placement="right">
+ <ReportProblemOutlined color='error' fontSize='small' />
+ </Tooltip>
+ )}
+ </Box>
+);
\ No newline at end of file
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionSelect.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionSelect.tsx
new file mode 100644
index 0000000000..5ed6e83478
--- /dev/null
+++
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionSelect.tsx
@@ -0,0 +1,63 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {
+ Box, FormControl, MenuItem, TextField, Typography
+} from "@material-ui/core";
+import React, {useState} from "react";
+import {RebalanceServerOption} from "../RebalanceServerOptions";
+import {
+ RebalanceServerConfigurationOptionLabel
+} from
"./RebalanceServerConfigurationOptionLabel/RebalanceServerConfigurationOptionLabel";
+
+type RebalanceServerConfigurationOptionSelectProps = {
+ option: RebalanceServerOption;
+ handleConfigChange: (config: { [key: string]: string | number | boolean })
=> void;
+}
+export const RebalanceServerConfigurationOptionSelect = (
+ { option, handleConfigChange }:
RebalanceServerConfigurationOptionSelectProps
+) => {
+ const [value, setValue] = useState<string>(option.defaultValue as string);
+ return (
+ <Box display='flex' flexDirection='column'>
+ <FormControl fullWidth={true}>
+ <RebalanceServerConfigurationOptionLabel option={option} />
+ <TextField
+ variant='outlined'
+ fullWidth
+ style={{ width: '100%' }}
+ size='small'
+ select
+ id={`rebalance-server-select-input-${option.name}`}
+ value={value}
+ onChange={(e) => {
+ handleConfigChange(
+ {
+ [option.name]: e.target.value
+ });
+ setValue(e.target.value);
+ }}>
+ {option.allowedValues.map((allowedValue) => (
+ <MenuItem key={allowedValue}
value={allowedValue}>{allowedValue}</MenuItem>
+ ))}
+ </TextField>
+ </FormControl>
+ <Typography variant='caption'>{option.description}</Typography>
+ </Box>
+ );
+}
\ No newline at end of file
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionToggleSwitch.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionToggleSwitch.tsx
new file mode 100644
index 0000000000..e4f2f06448
--- /dev/null
+++
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationOptions/RebalanceServerConfigurationOptionToggleSwitch.tsx
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {Box, FormControlLabel, Switch, Typography} from "@material-ui/core";
+import React, {useState} from "react";
+import {RebalanceServerOption} from "../RebalanceServerOptions";
+import {
+ RebalanceServerConfigurationOptionLabel
+} from
"./RebalanceServerConfigurationOptionLabel/RebalanceServerConfigurationOptionLabel";
+
+type RebalanceServerConfigurationOptionSwitchProps = {
+ option: RebalanceServerOption;
+ handleConfigChange: (config: { [key: string]: string | number | boolean })
=> void;
+}
+export const RebalanceServerConfigurationOptionSwitch = (
+ { option, handleConfigChange }:
RebalanceServerConfigurationOptionSwitchProps) => {
+ const [isChecked, setIsChecked] = useState<boolean>(option.defaultValue as
boolean);
+ return (
+ <Box display='flex' flexDirection='column'>
+ <FormControlLabel
+ control={
+ <Switch
+ checked={isChecked}
+ onChange={() => {
+ handleConfigChange({
+ [option.name]: !isChecked
+ })
+ setIsChecked(isChecked => !isChecked)
+ }}
+ name={option.name}
+ color="primary"
+ />
+ }
+ label={<RebalanceServerConfigurationOptionLabel
option={option} />}
+ />
+ <Typography variant='caption'>{option.description}</Typography>
+ </Box>
+ );
+}
\ No newline at end of file
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationSection.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationSection.tsx
new file mode 100644
index 0000000000..40a655ced9
--- /dev/null
+++
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerConfigurationSection.tsx
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {Box, Typography} from "@material-ui/core";
+import React, {ReactNode, useEffect, useRef, useState} from "react";
+import Link from "@material-ui/core/Link";
+
+type RebalanceServerConfigurationSectionProps = {
+ sectionTitle: string;
+ children: ReactNode;
+ showSectionByDefault?: boolean;
+ canHideSection?: boolean;
+}
+
+export const RebalanceServerConfigurationSection = (
+ { sectionTitle, children, showSectionByDefault = true, canHideSection =
false }: RebalanceServerConfigurationSectionProps
+) => {
+ const [showSection, setShowSection] =
useState<boolean>(showSectionByDefault);
+ const showHideSectionRef = useRef(null);
+
+ const handleScrollToSection = () => {
+ if (showHideSectionRef.current) {
+ showHideSectionRef.current.scrollIntoView(
+ {
+ behavior: 'smooth',
+ block: 'start',
+ });
+ }
+ };
+
+ useEffect(() => {
+ if (showSection && !showSectionByDefault) {
+ handleScrollToSection();
+ }
+ }, [showSection, showHideSectionRef]);
+
+ return (
+ <Box marginBottom={2}>
+ <Box display='flex' flexDirection='row' alignItems='center'
marginBottom={2}>
+ <div ref={showHideSectionRef} />
+ <Typography variant='body1' style={{ fontWeight: 'bold',
marginRight: 10 }}>
+ {sectionTitle}
+ </Typography>
+ {canHideSection && (
+ <Link style={{ cursor: 'pointer' }} onClick={() =>
setShowSection(visible => !visible)}>
+ { showSection ? "Hide" : "Show" }
+ </Link>
+ )}
+ </Box>
+ {showSection && children}
+ </Box>
+ );
+}
\ No newline at end of file
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerDialogHeader.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerDialogHeader.tsx
new file mode 100644
index 0000000000..59c464f0b3
--- /dev/null
+++
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerDialogHeader.tsx
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {Box, Typography} from "@material-ui/core";
+import React from "react";
+import Link from "@material-ui/core/Link";
+
+type LinkTextProps = {
+ text: string;
+ link: string;
+}
+const LinkText = ({ text, link }: LinkTextProps) => {
+ return (
+ <Link href={link} target="_blank" rel="noopener">
+ <Typography style={{ fontWeight: 'bold' }}
variant="inherit">{text}</Typography>
+ </Link>
+ );
+}
+export const RebalanceServerDialogHeader = () => {
+ return (
+ <Box>
+ <Typography style={{ fontWeight: "bold" }} variant="h6">Rebalance
Server</Typography>
+ <Typography variant="subtitle2">
+ Click <LinkText text='here'
link='https://docs.pinot.apache.org/operators/operating-pinot/rebalance/rebalance-servers'
/> for more details
+ </Typography>
+ </Box>
+ );
+}
\ No newline at end of file
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerOptions.ts
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerOptions.ts
new file mode 100644
index 0000000000..3aaf3a22fa
--- /dev/null
+++
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServer/RebalanceServerOptions.ts
@@ -0,0 +1,168 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+export type RebalanceServerOption = {
+ name: string;
+ label: string;
+ type: "BOOL" | "INTEGER" | "SELECT";
+ description: string;
+ defaultValue: string | boolean | number;
+ isAdvancedConfig: boolean;
+ isStatsGatheringConfig: boolean;
+ markWithWarningIcon: boolean;
+ allowedValues?: string[];
+ toolTip?: string;
+}
+
+export const rebalanceServerOptions: RebalanceServerOption[] = [
+ {
+ "name": "dryRun",
+ "defaultValue": false,
+ "label": "Dry Run",
+ "type": "BOOL",
+ "description": "If enabled, rebalance will not run but expected
changes that will occur will be returned",
+ "isAdvancedConfig": false,
+ "isStatsGatheringConfig": true,
+ "markWithWarningIcon": false
+ },
+ {
+ "name": "preChecks",
+ "defaultValue": false,
+ "type": "BOOL",
+ "label": "Pre-Checks",
+ "description": "If enabled, will perform some pre-checks to ensure
rebalance is safe, must enable dryRun to enable this",
+ "isAdvancedConfig": false,
+ "isStatsGatheringConfig": true,
+ "markWithWarningIcon": false
+ },
+ {
+ "name": "reassignInstances",
+ "defaultValue": true,
+ "type": "BOOL",
+ "label": "Reassign Instances",
+ "description": "If enabled, reassign the instances of the table before
making updates to the segment assignment",
+ "isAdvancedConfig": false,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": false
+ },
+ {
+ "name": "includeConsuming",
+ "defaultValue": true,
+ "type": "BOOL",
+ "label": "Include Consuming",
+ "description": "If enabled, CONSUMING segments will be included in the
rebalance of realtime tables. This is mandatory for for upsert/dedup tables",
+ "isAdvancedConfig": false,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": false
+ },
+ {
+ "name": "minimizeDataMovement",
+ "defaultValue": "ENABLE",
+ "type": "SELECT",
+ "allowedValues": ["ENABLE", "DISABLE", "DEFAULT"],
+ "label": "Minimize Data Movement",
+ "description": "If enabled, it reduces the segments that will be moved
by trying to minimize the changes to the instance assignment. Setting this to
default will fallback to the value of this flag in the TableConfig",
+ "isAdvancedConfig": false,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": true,
+ "toolTip": "Disabling minimizeDataMovement can cause a large amount of
data movement"
+ },
+ {
+ "name": "bootstrap",
+ "defaultValue": false,
+ "type": "BOOL",
+ "label": "Bootstrap",
+ "description": "If enabled, regardless of minimum segment movement,
reassign all segments in a round-robin fashion as if adding new segments to an
empty table",
+ "isAdvancedConfig": true,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": true,
+ "toolTip": "Enabling bootstrap can cause a large amount of data
movement"
+ },
+ {
+ "name": "downtime",
+ "defaultValue": false,
+ "type": "BOOL",
+ "label": "Downtime",
+ "description": "If enabled, rebalance will be performed with downtime.
This must be set to true if replication = 1",
+ "isAdvancedConfig": false,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": true,
+ "toolTip": "Enabling can cause downtime if replication > 1"
+ },
+ {
+ "name": "minAvailableReplicas",
+ "defaultValue": -1,
+ "type": "INTEGER",
+ "label": "Min Available Replicas",
+ "description": "For no-downtime rebalance, minimum number of replicas
to keep alive during rebalance, or maximum number of replicas allowed to be
unavailable if value is negative. Should not be 0 unless for downtime=true",
+ "isAdvancedConfig": false,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": false
+ },
+ {
+ "name": "lowDiskMode",
+ "defaultValue": false,
+ "type": "BOOL",
+ "label": "Low Disk Mode",
+ "description": "If enabled, perform rebalance by offloading segments
off servers prior to adding them. Can slow down rebalance and is recommended to
enable for scenarios which are low on disk capacity",
+ "isAdvancedConfig": true,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": false
+ },
+ {
+ "name": "bestEfforts",
+ "defaultValue": false,
+ "type": "BOOL",
+ "label": "Best Efforts",
+ "description": "If enabled, even if downtime=false do not fail
rebalance if IS-EV convergence fails within timeout or segments are in ERROR
state and continue rebalancing. This can cause downtime",
+ "isAdvancedConfig": true,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": true,
+ "toolTip": "Enabling can cause downtime even if downtime = true"
+ },
+ {
+ "name": "externalViewStabilizationTimeoutInMs",
+ "defaultValue": 3600000,
+ "type": "INTEGER",
+ "label": "External View Stabilization Timeout In Milliseconds",
+ "description": "How long to wait for EV-IS convergence, increase this
timeout for large tables (TBs in size)",
+ "isAdvancedConfig": true,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": false
+ },
+ {
+ "name": "maxAttempts",
+ "defaultValue": 3,
+ "type": "INTEGER",
+ "label": "Max Attempts",
+ "description": "Max number of attempts to rebalance",
+ "isAdvancedConfig": true,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": false
+ },
+ {
+ "name": "updateTargetTier",
+ "defaultValue": false,
+ "type": "BOOL",
+ "label": "Update Target Tier",
+ "description": "If enabled, update segment target tier as part of the
rebalance",
+ "isAdvancedConfig": true,
+ "isStatsGatheringConfig": false,
+ "markWithWarningIcon": false
+ }
+]
\ No newline at end of file
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServerTableOp.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServerTableOp.tsx
index 504e4200ce..7236530771 100644
---
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServerTableOp.tsx
+++
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/RebalanceServerTableOp.tsx
@@ -18,11 +18,32 @@
*/
import React from 'react';
-import { DialogContent, DialogContentText, FormControl, FormControlLabel,
Grid, Input, InputLabel, Switch, Tooltip} from '@material-ui/core';
+import {
+ DialogContentText,
+ FormControl,
+ FormControlLabel,
+ Grid,
+ Input,
+ InputLabel,
+ Switch,
+ Box,
+ Typography,
+ List,
+ ListItem,
+ ListItemText,
+ ListItemIcon,
+ Divider, Button
+} from '@material-ui/core';
import Dialog from '../../CustomDialog';
import PinotMethodUtils from '../../../utils/PinotMethodUtils';
import CustomCodemirror from '../../CustomCodemirror';
-import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';
+import {RebalanceServerDialogHeader} from
"./RebalanceServer/RebalanceServerDialogHeader";
+import {RebalanceServerConfigurationSection} from
"./RebalanceServer/RebalanceServerConfigurationSection";
+import Alert from "@material-ui/lab/Alert";
+import InfoOutlinedIcon from "@material-ui/icons/InfoOutlined";
+import {rebalanceServerOptions} from
"./RebalanceServer/RebalanceServerOptions";
+import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
+import {RebalanceServerConfigurationOption} from
"./RebalanceServer/RebalanceServerConfigurationOption";
type Props = {
tableType: string,
@@ -30,139 +51,99 @@ type Props = {
hideModal: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void
};
+const DryRunAction = ({ handleOnRun }: { handleOnRun: () => void }) => {
+ return (
+ <Button onClick={handleOnRun} variant="outlined" style={{ textTransform:
'none' }} color="primary">
+ Dry Run
+ </Button>
+ );
+}
+
export default function RebalanceServerTableOp({
hideModal,
tableName,
tableType
}: Props) {
const [rebalanceResponse, setRebalanceResponse] = React.useState(null)
- const [dryRun, setDryRun] = React.useState(false);
- const [reassignInstances, setReassignInstances] = React.useState(false);
- const [includeConsuming, setIncludeConsuming] = React.useState(false);
- const [bootstrap, setBootstrap] = React.useState(false);
- const [downtime, setDowntime] = React.useState(false);
- const [minAvailableReplicas, setMinAvailableReplicas] = React.useState("1");
- const [bestEfforts, setBestEfforts] = React.useState(false);
- const [lowDiskMode, setLowDiskMode] = React.useState(false);
+ const [rebalanceConfig, setRebalanceConfig] = React.useState(
+ rebalanceServerOptions.reduce((config, option) => ({ ...config,
[option.name]: option.defaultValue }), {})
+ );
const getData = () => {
return {
type: tableType,
- dryRun, reassignInstances, includeConsuming, bootstrap, downtime,
bestEfforts, lowDiskMode,
- minAvailableReplicas: parseInt(minAvailableReplicas, 10)
+ ...rebalanceConfig,
}
};
- const handleSave = async (event) => {
+ const handleSave = async () => {
const data = getData();
const response = await
PinotMethodUtils.rebalanceServersForTableOp(tableName, data);
setRebalanceResponse(response);
};
+ const handleDryRun = async () => {
+ const data = getData();
+ const response = await
PinotMethodUtils.rebalanceServersForTableOp(tableName, {
+ ...data,
+ dryRun: true,
+ preChecks: true
+ });
+ setRebalanceResponse(response);
+ };
+
+ const handleConfigChange = (config: { [key: string]: string | number |
boolean }) => {
+ setRebalanceConfig({
+ ...rebalanceConfig,
+ ...config
+ });
+ }
+
+
return (
<Dialog
+ showTitleDivider
+ showFooterDivider
+ size='md'
open={true}
handleClose={hideModal}
- title={(<>Rebalance Server <Tooltip interactive title={(<a
className={"tooltip-link"} target="_blank"
href="https://docs.pinot.apache.org/operators/operating-pinot/rebalance/rebalance-servers">Click
here for more details</a>)} arrow
placement="top"><InfoOutlinedIcon/></Tooltip></>)}
+ title={<RebalanceServerDialogHeader />}
handleSave={handleSave}
+ btnOkText='Rebalance'
showOkBtn={!rebalanceResponse}
+ moreActions={!rebalanceResponse ? <DryRunAction
handleOnRun={handleDryRun} /> : null}
>
- <DialogContent>
{!rebalanceResponse ?
- <Grid container spacing={2}>
- <Grid item xs={6}>
- <FormControlLabel
- control={
- <Switch
- checked={dryRun}
- onChange={() => setDryRun(!dryRun)}
- name="dryRun"
- color="primary"
- />
- }
- label="Dry Run"
- />
- <br/>
- <FormControlLabel
- control={
- <Switch
- checked={includeConsuming}
- onChange={() => setIncludeConsuming(!includeConsuming)}
- name="includeConsuming"
- color="primary"
- />
- }
- label="Include Consuming"
- />
- <br/>
- <FormControlLabel
- control={
- <Switch
- checked={downtime}
- onChange={() => setDowntime(!downtime)}
- name="downtime"
- color="primary"
- />
- }
- label="Downtime"
- />
- <br />
- <FormControlLabel
- control={
- <Switch
- checked={lowDiskMode}
- onChange={() => setLowDiskMode(!lowDiskMode)}
- name="lowDiskMode"
- color="primary"
- />
- }
- label="Low Disk Mode"
- />
- </Grid>
- <Grid item xs={6}>
- <FormControlLabel
- control={
- <Switch
- checked={reassignInstances}
- onChange={() => setReassignInstances(!reassignInstances)}
- name="reassignInstances"
- color="primary"
- />
- }
- label="Reassign Instances"
- />
- <br/>
- <FormControlLabel
- control={
- <Switch
- checked={bootstrap}
- onChange={() => setBootstrap(!bootstrap)}
- name="bootstrap"
- color="primary"
- />
- }
- label="Bootstrap"
- />
- <br/>
- <FormControlLabel
- control={
- <Switch
- checked={bestEfforts}
- onChange={() => setBestEfforts(!bestEfforts)}
- name="bestEfforts"
- color="primary"
- />
- }
- label="Best Efforts"
- />
- </Grid>
- <Grid item xs={6}>
- <FormControl fullWidth={true}>
- <InputLabel htmlFor="my-input">Minimum Available
Replicas</InputLabel>
- <Input id="my-input" type="number"
value={minAvailableReplicas} onChange={(e)=>
setMinAvailableReplicas(e.target.value)}/>
- </FormControl>
- </Grid>
- </Grid>
+ <Box flexDirection="column">
+ <RebalanceServerConfigurationSection sectionTitle='Before you
begin'>
+ <Alert color='info' icon={<InfoOutlinedIcon fontSize='small' />}>
+ <Typography variant='body2'>
+ It is strongly recommended to run once via "Dry Run" with
the options enabled prior to running the actual "Rebalance" operation.
+ This is needed to verify that rebalance will do what's
expected.
+ </Typography>
+ </Alert>
+ </RebalanceServerConfigurationSection>
+ <Divider style={{ marginBottom: 20 }} />
+ <RebalanceServerConfigurationSection sectionTitle='Basic Options'>
+ <Grid container spacing={2}>
+ {rebalanceServerOptions.filter(option =>
!option.isAdvancedConfig && !option.isStatsGatheringConfig).map((option) => (
+ <Grid item xs={12} key={`basic-options-${option.name}`}>
+ <RebalanceServerConfigurationOption option={option}
handleConfigChange={handleConfigChange} />
+ </Grid>
+ ))}
+ </Grid>
+ </RebalanceServerConfigurationSection>
+ <Divider style={{ marginBottom: 20 }}/>
+ <RebalanceServerConfigurationSection sectionTitle='Advanced
Options' canHideSection showSectionByDefault={false}>
+ <Grid container spacing={2}>
+ {rebalanceServerOptions.filter(option =>
option.isAdvancedConfig).map((option) => (
+ <Grid item xs={12} key={`advanced-options-${option.name}`}>
+ <RebalanceServerConfigurationOption option={option}
handleConfigChange={handleConfigChange} />
+ </Grid>
+ ))}
+ </Grid>
+ </RebalanceServerConfigurationSection>
+ </Box>
:
<React.Fragment>
<DialogContentText>
@@ -174,7 +155,6 @@ export default function RebalanceServerTableOp({
/>
</React.Fragment>
}
- </DialogContent>
</Dialog>
);
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]