Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VTAdmin: Add advanced workflow switchtraffic options #17658

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions go/vt/vtadmin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2824,16 +2824,6 @@ func (api *API) WorkflowSwitchTraffic(ctx context.Context, req *vtadminpb.Workfl
return nil, err
}

// Set the default options which are not supported in VTAdmin Web.
req.Request.TabletTypes = []topodatapb.TabletType{
topodatapb.TabletType_PRIMARY,
topodatapb.TabletType_REPLICA,
topodatapb.TabletType_RDONLY,
}
req.Request.Timeout = protoutil.DurationToProto(workflow.DefaultTimeout)
req.Request.MaxReplicationLagAllowed = protoutil.DurationToProto(vreplcommon.MaxReplicationLagDefault)
req.Request.EnableReverseReplication = true

return c.Vtctld.WorkflowSwitchTraffic(ctx, req.Request)
}

Expand Down
195 changes: 174 additions & 21 deletions web/vtadmin/src/components/routes/workflows/WorkflowActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
} from '../../../hooks/api';
import Toggle from '../../toggle/Toggle';
import { success } from '../../Snackbar';
import { vtadmin, vtctldata } from '../../../proto/vtadmin';
import { vtadmin, vtctldata, vttime } from '../../../proto/vtadmin';

Check warning on line 15 in web/vtadmin/src/components/routes/workflows/WorkflowActions.tsx

View workflow job for this annotation

GitHub Actions / lint

'vttime' is defined but never used

Check warning on line 15 in web/vtadmin/src/components/routes/workflows/WorkflowActions.tsx

View workflow job for this annotation

GitHub Actions / build

'vttime' is defined but never used
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these linter warnings not valid?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are and we should address them! 😄

import { getReverseWorkflow } from '../../../util/workflows';
import { Label } from '../../inputs/Label';
import { TextInput } from '../../TextInput';
import { MultiSelect } from '../../inputs/MultiSelect';
import { TABLET_TYPES } from '../../../util/tablets';

interface WorkflowActionsProps {
streamsByState: {
Expand Down Expand Up @@ -44,11 +48,31 @@
keepRoutingRoules: boolean;
}

interface SwitchTrafficOptions {
enableReverseReplication: boolean;
force: boolean;
initializeTargetSequences: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a boolean anymore after: #16860

maxReplicationLagAllowed: number;
timeout: number;
tabletTypes: number[];
}

const DefaultSwitchTrafficOptions: SwitchTrafficOptions = {
enableReverseReplication: true,
force: false,
initializeTargetSequences: false,
maxReplicationLagAllowed: 30,
timeout: 30,
tabletTypes: [1, 2, 3],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if we can use topodata.TabletTypes here instead of plain numbers 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to that! Sorry, I meant to come back and comment on this but then forgot. We should use the existing consts:

topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA, topodatapb.TabletType_RDONLY

};

const DefaultCancelWorkflowOptions: CancelWorkflowOptions = {
keepData: false,
keepRoutingRoules: false,
};

const TABLET_OPTIONS = [1, 2, 3];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about using topodata.TabletTypes here too!


const WorkflowActions: React.FC<WorkflowActionsProps> = ({
streamsByState,
workflows,
Expand All @@ -60,13 +84,15 @@
}) => {
const [currentDialog, setCurrentDialog] = useState<string>('');

const [completeMoveTablesOptions, SetCompleteMoveTablesOptions] = useState<CompleteMoveTablesOptions>(
const [completeMoveTablesOptions, setCompleteMoveTablesOptions] = useState<CompleteMoveTablesOptions>(
DefaultCompleteMoveTablesOptions
);

const [cancelWorkflowOptions, SetCancelWorkflowOptions] =
const [cancelWorkflowOptions, setCancelWorkflowOptions] =
useState<CancelWorkflowOptions>(DefaultCancelWorkflowOptions);

const [switchTrafficOptions, setSwitchTrafficOptions] = useState<SwitchTrafficOptions>(DefaultSwitchTrafficOptions);

const closeDialog = () => setCurrentDialog('');

const startWorkflowMutation = useStartWorkflow({ keyspace, clusterID, name });
Expand All @@ -79,6 +105,16 @@
keyspace: keyspace,
workflow: name,
direction: 0,
enable_reverse_replication: switchTrafficOptions.enableReverseReplication,
force: switchTrafficOptions.force,
max_replication_lag_allowed: {
seconds: switchTrafficOptions.maxReplicationLagAllowed,
},
timeout: {
seconds: switchTrafficOptions.timeout,
},
initialize_target_sequences: switchTrafficOptions.initializeTargetSequences,
tablet_types: switchTrafficOptions.tabletTypes,
},
});

Expand All @@ -88,6 +124,16 @@
keyspace: keyspace,
workflow: name,
direction: 1,
enable_reverse_replication: switchTrafficOptions.enableReverseReplication,
force: switchTrafficOptions.force,
max_replication_lag_allowed: {
seconds: switchTrafficOptions.maxReplicationLagAllowed,
},
timeout: {
seconds: switchTrafficOptions.timeout,
},
initialize_target_sequences: switchTrafficOptions.initializeTargetSequences,
tablet_types: switchTrafficOptions.tabletTypes,
},
});

Expand Down Expand Up @@ -126,7 +172,7 @@
}
);

const isMoveTablesWorkflow = workflowType === 'MoveTables';
const supportsComplete = workflowType.toLowerCase() === 'movetables' || workflowType.toLowerCase() === 'reshard';

const isRunning =
!(streamsByState['Error'] && streamsByState['Error'].length) &&
Expand All @@ -148,12 +194,123 @@

const isReverseWorkflow = name.endsWith('_reverse');

const switchTrafficDialogBody = (initializeTargetSequences: boolean = true) => {
return (
<div className="flex flex-col gap-2">
<Label
className="block w-full"
label="Timeout"
helpText={
'Specifies the maximum time to wait, in seconds, for VReplication to catch up on primary tablets. The traffic switch will be cancelled on timeout.'
}
>
<TextInput
onChange={(e) =>
setSwitchTrafficOptions((prevOptions) => ({
...prevOptions,
timeout: Number(e.target.value),
}))
}
value={switchTrafficOptions.timeout || ''}
type="number"
/>
</Label>
<Label
className="block w-full"
label="Max Replication Lag Allowed"
helpText={'Allow traffic to be switched only if VReplication lag is below this.'}
>
<TextInput
onChange={(e) =>
setSwitchTrafficOptions((prevOptions) => ({
...prevOptions,
maxReplicationLagAllowed: Number(e.target.value),
}))
}
value={switchTrafficOptions.maxReplicationLagAllowed || ''}
type="number"
/>
</Label>
<MultiSelect
className="block w-full"
inputClassName="block w-full"
items={TABLET_OPTIONS}
itemToString={(tt) => TABLET_TYPES[tt]}
selectedItems={switchTrafficOptions.tabletTypes}
label="Tablet Types"
helpText={'Tablet types to switch traffic for.'}
onChange={(types) => {
setSwitchTrafficOptions({ ...switchTrafficOptions, tabletTypes: types });
}}
placeholder="Select tablet types"
/>
<div className="flex justify-between items-center w-full">
<Label
label="Enable Reverse Replication"
helpText={
'Setup replication going back to the original source keyspace to support rolling back the traffic cutover.'
}
/>
<Toggle
className="mr-2"
enabled={switchTrafficOptions.enableReverseReplication}
onChange={() =>
setSwitchTrafficOptions((prevOptions) => ({
...prevOptions,
enableReverseReplication: !prevOptions.enableReverseReplication,
}))
}
/>
</div>
{initializeTargetSequences && (
<div className="flex justify-between items-center w-full">
<Label
label="Initialize Target Sequences"
helpText={
'When moving tables from an unsharded keyspace to a sharded keyspace, initialize any sequences that are being used on the target when switching writes. If the sequence table is not found, and the sequence table reference was fully qualified, then we will attempt to create the sequence table in that keyspace.'
}
/>
<Toggle
className="mr-2"
enabled={switchTrafficOptions.initializeTargetSequences}
onChange={() =>
setSwitchTrafficOptions((prevOptions) => ({
...prevOptions,
initializeTargetSequences: !prevOptions.initializeTargetSequences,
}))
}
/>
</div>
)}
<div className="flex justify-between items-center w-full">
<Label
label="Force"
helpText={`
Force the traffic switch even if some potentially non-critical actions cannot be
performed; for example the tablet refresh fails on some tablets in the keyspace.
WARNING: this should be used with extreme caution and only in emergency situations!`}
/>
<Toggle
className="mr-2"
enabled={switchTrafficOptions.force}
onChange={() =>
setSwitchTrafficOptions((prevOptions) => ({
...prevOptions,
force: !prevOptions.force,
}))
}
/>
</div>
</div>
);
};

return (
<div className="w-min inline-block">
<Dropdown dropdownButton={Icons.info}>
{!isReverseWorkflow && (
<>
{isMoveTablesWorkflow && isSwitched && (
{supportsComplete && isSwitched && (
<MenuItem onClick={() => setCurrentDialog('Complete MoveTables')}>Complete</MenuItem>
)}
{isRunning && (
Expand Down Expand Up @@ -219,10 +376,12 @@
}
/>
<WorkflowAction
className="sm:max-w-xl"
title="Switch Traffic"
confirmText="Switch"
loadingText="Switching"
mutation={switchTrafficMutation}
description={`Switch traffic for the ${name} workflow.`}
successText="Switched Traffic"
errorText={`Error occured while switching traffic for workflow ${name}`}
errorDescription={switchTrafficMutation.error ? switchTrafficMutation.error.message : ''}
Expand All @@ -236,17 +395,15 @@
)}
</div>
}
body={
<div className="text-sm mt-3">
Switch traffic for the <span className="font-mono bg-gray-300">{name}</span> workflow.
</div>
}
body={switchTrafficDialogBody(workflowType.toLowerCase() !== 'reshard')}
/>
<WorkflowAction
className="sm:max-w-xl"
title="Reverse Traffic"
confirmText="Reverse"
loadingText="Reversing"
mutation={reverseTrafficMutation}
description={`Reverse traffic for the ${name} workflow.`}
successText="Reversed Traffic"
errorText={`Error occured while reversing traffic for workflow ${name}`}
errorDescription={reverseTrafficMutation.error ? reverseTrafficMutation.error.message : ''}
Expand All @@ -260,11 +417,7 @@
)}
</div>
}
body={
<div className="text-sm mt-3">
Reverse traffic for the <span className="font-mono bg-gray-300">{name}</span> workflow.
</div>
}
body={switchTrafficDialogBody(false)}
/>
<WorkflowAction
className="sm:max-w-xl"
Expand Down Expand Up @@ -299,7 +452,7 @@
<Toggle
enabled={cancelWorkflowOptions.keepData}
onChange={() =>
SetCancelWorkflowOptions((prevOptions) => ({
setCancelWorkflowOptions((prevOptions) => ({
...prevOptions,
keepData: !prevOptions.keepData,
}))
Expand All @@ -316,7 +469,7 @@
<Toggle
enabled={cancelWorkflowOptions.keepRoutingRoules}
onChange={() =>
SetCancelWorkflowOptions((prevOptions) => ({
setCancelWorkflowOptions((prevOptions) => ({
...prevOptions,
keepRoutingRoules: !prevOptions.keepRoutingRoules,
}))
Expand All @@ -328,7 +481,7 @@
/>
<WorkflowAction
className="sm:max-w-xl"
title="Complete MoveTables"
title="Complete Workflow"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. We missed this when adding Reshard support. 🙂

description={`Complete the ${name} workflow.`}
confirmText="Complete"
loadingText="Completing"
Expand All @@ -351,7 +504,7 @@
<Toggle
enabled={completeMoveTablesOptions.keepData}
onChange={() =>
SetCompleteMoveTablesOptions((prevOptions) => ({
setCompleteMoveTablesOptions((prevOptions) => ({
...prevOptions,
keepData: !prevOptions.keepData,
}))
Expand All @@ -369,7 +522,7 @@
<Toggle
enabled={completeMoveTablesOptions.keepRoutingRoules}
onChange={() =>
SetCompleteMoveTablesOptions((prevOptions) => ({
setCompleteMoveTablesOptions((prevOptions) => ({
...prevOptions,
keepRoutingRoules: !prevOptions.keepRoutingRoules,
}))
Expand All @@ -388,7 +541,7 @@
<Toggle
enabled={completeMoveTablesOptions.renameTables}
onChange={() =>
SetCompleteMoveTablesOptions((prevOptions) => ({
setCompleteMoveTablesOptions((prevOptions) => ({
...prevOptions,
renameTables: !prevOptions.renameTables,
}))
Expand Down
2 changes: 1 addition & 1 deletion web/vtadmin/src/components/tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const Tooltip = ({ children, text }: TooltipProps) => {
});

return (
<Popover content={content} isOpen={isOpen}>
<Popover content={content} isOpen={isOpen} containerStyle={{ zIndex: '20' }}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use tailwind styling here?

{cloneChildren}
</Popover>
);
Expand Down
Loading