Skip to content

Commit 3a9091b

Browse files
committed
[PLAT-14456] Add UI for configuring continuous backup
Summary: This diff adds the ability to configure continuous backup (presented to users as "automated platform backups" on the YBA UI) from the YBA platform admin tab. The user is able to create and edit their continuous backup configuration from this page. To disable the automatic backup, users need to delete remove the continuous backup configuration. The UI support for this is also included in this diff. After the changes in this diff, the platform HA sub-tabs are now presented as vertical tabs under a new "Platform High Availability" sub-tab. The new continuous backup feature can be found under the "Automated Platform Backups". This diff also implements a new backup storage config select field according to the latest design spec. The component name is `BackupStorageConfigSelect`. The new select field includes a menu action for creating a new storage config (implemented as a redirect modal to the backup storage config page) and also a separate prompt component which appears if users have no storage configs at all. The component handles the customer config fetching and filters for the storage configs internally. The entire continuous backup UI is hidden behind a runtime config feature flag `yb.ui.feature_flags.continuous_platform_backups` which must be enabled first. By default this is turned off. Test Plan: Review UX with design team. Create and edit continuous backup configs. Verify component behaviour of the new backup storage config select component. {F389613} {F328823} {F328819} {F389614} Reviewers: rmadhavan, kkannan, muthu Reviewed By: rmadhavan Subscribers: yugaware Differential Revision: https://phorge.dev.yugabyte.com/D41320
1 parent e75d999 commit 3a9091b

File tree

67 files changed

+1853
-350
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1853
-350
lines changed

managed/src/main/java/com/yugabyte/yw/common/config/GlobalConfKeys.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,4 +1861,13 @@ public class GlobalConfKeys extends RuntimeConfigKeysModule {
18611861
"Enable performing automatic rollback of edit operation (if possible)",
18621862
ConfDataType.BooleanType,
18631863
ImmutableList.of(ConfKeyTags.PUBLIC));
1864+
public static final ConfKeyInfo<Boolean> enableContinuousPlatformBackups =
1865+
new ConfKeyInfo<>(
1866+
"yb.ui.feature_flags.continuous_platform_backups",
1867+
ScopeType.GLOBAL,
1868+
"Enable new YBA platform backup and restore UI",
1869+
"Exposes a new subtab on the platform administration page where users can enable"
1870+
+ " automated platform backups.",
1871+
ConfDataType.BooleanType,
1872+
ImmutableList.of(ConfKeyTags.INTERNAL));
18641873
}

managed/src/main/resources/reference.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ yb {
213213
off_cluster_pitr_enabled=false
214214
enable_path_style_access=false
215215
enable_earlyoom=false
216+
continuous_platform_backups=false
216217
}
217218

218219
xcluster {

managed/ui/src/components/administration/Administration.tsx

Lines changed: 40 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,16 @@ import { RouteComponentProps } from 'react-router-dom';
88
import { fetchGlobalRunTimeConfigs } from '../../api/admin';
99
import { YBTabsPanel, YBTabsWithLinksPanel } from '../panels';
1010
import { isAvailable, showOrRedirect } from '../../utils/LayoutUtils';
11-
import { HAReplication } from '../ha';
1211
import { AlertConfigurationContainer } from '../alerts';
1312
import { UserManagementContainer } from '../users';
1413
import { RuntimeConfigContainer } from '../advanced';
15-
import { HAInstancesContainer } from '../ha/instances/HAInstanceContainer';
16-
import { HaMetrics } from '../ha/HaMetrics';
1714
import ListCACerts from '../customCACerts/ListCACerts';
1815
import { RBACContainer } from '../../redesign/features/rbac/RBACContainer';
1916
import { RbacValidator } from '../../redesign/features/rbac/common/RbacApiPermValidator';
2017
import { ApiPermissionMap } from '../../redesign/features/rbac/ApiAndUserPermMapping';
2118
import { isRbacEnabled } from '../../redesign/features/rbac/common/RbacUtils';
22-
import { useLoadHAConfiguration } from '../ha/hooks/useLoadHAConfiguration';
19+
import { ContinuousBackup } from '../../redesign/features/continuous-backup/ContinuousBackup';
20+
import { PlatformHa } from '../../redesign/features/platform-ha/PlatformHa';
2321

2422
import './Administration.scss';
2523

@@ -36,35 +34,33 @@ interface Store {
3634
};
3735
}
3836

39-
interface FetureFlags {
37+
interface FeatureFlags {
4038
released: any;
4139
test: any;
4240
}
4341

4442
interface FeatureStore {
45-
featureFlags: FetureFlags;
43+
featureFlags: FeatureFlags;
4644
}
4745

48-
// string values will be used in URL
49-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
50-
enum AdministrationTabs {
51-
HA = 'ha',
52-
AC = 'alertConfig'
53-
}
46+
const AdministrationTabs = {
47+
HA: 'ha',
48+
AC: 'alertConfig'
49+
} as const;
50+
type AdministrationTabs = typeof AdministrationTabs[keyof typeof AdministrationTabs];
5451

55-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
56-
enum HighAvailabilityTabs {
57-
REPLICATION = 'replication',
58-
INSTANCES = 'instances',
59-
METRICS = 'metrics'
60-
}
52+
const PlatformHaAndBackupsTabs = {
53+
PLATFORM_HA: 'platformHa',
54+
CONTINUOUS_BACKUP: 'continuousBackup'
55+
} as const;
56+
type PlatformHaAndBackupsTabs = typeof PlatformHaAndBackupsTabs[keyof typeof PlatformHaAndBackupsTabs];
6157

62-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
63-
enum AlertConfigurationTabs {
64-
Creation = 'alertCreation'
65-
}
58+
const AlertConfigurationTabs = {
59+
Creation: 'alertCreation'
60+
} as const;
61+
type AlertConfigurationTabs = typeof AlertConfigurationTabs[keyof typeof AlertConfigurationTabs];
6662

67-
const USER_MANAGAEMENT_TAB = {
63+
const USER_MANAGEMENT_TAB = {
6864
title: 'User Management',
6965
id: 'user-management',
7066
defaultTab: 'users'
@@ -78,23 +74,20 @@ const ADVANCED_TAB = {
7874

7975
interface RouteParams {
8076
tab: AdministrationTabs;
81-
section: HighAvailabilityTabs | AlertConfigurationTabs;
77+
section: PlatformHaAndBackupsTabs | AlertConfigurationTabs;
8278
}
8379

8480
const customerSelector: Selector<Store, Customer> = (state) => state.customer.currentCustomer;
85-
const featureFlags: Selector<FeatureStore, FetureFlags> = (state) => state.featureFlags;
81+
const featureFlags: Selector<FeatureStore, FeatureFlags> = (state) => state.featureFlags;
8682

8783
export const Administration: FC<RouteComponentProps<{}, RouteParams>> = ({ params }) => {
8884
const currentCustomer = useSelector(customerSelector);
8985
const { test, released } = useSelector(featureFlags);
9086
const globalRuntimeConfigs = useQuery(['globalRuntimeConfigs'], () =>
9187
fetchGlobalRunTimeConfigs(true).then((res: any) => res.data)
9288
);
93-
const { config, isNoHAConfigExists } = useLoadHAConfiguration({
94-
loadSchedule: false,
95-
autoRefresh: true
96-
});
97-
const isCongifUIEnabled =
89+
90+
const isRuntimeConfigUiEnabled =
9891
globalRuntimeConfigs?.data?.configEntries?.find(
9992
(c: any) => c.key === 'yb.runtime_conf_ui.enable_for_all'
10093
)?.value === 'true' ||
@@ -131,54 +124,36 @@ export const Administration: FC<RouteComponentProps<{}, RouteParams>> = ({ param
131124
) : null;
132125
};
133126

134-
const currentInstance = config?.instances.find((instance) => instance.is_local);
127+
const isContinuousBackupsUiEnable =
128+
globalRuntimeConfigs?.data?.configEntries?.find(
129+
(runtimeConfig: any) =>
130+
runtimeConfig.key === 'yb.ui.feature_flags.continuous_platform_backups'
131+
)?.value === 'true';
135132
const getHighAvailabilityTab = () => {
136133
return isAvailable(currentCustomer.data.features, 'administration.highAvailability') ? (
137-
<Tab eventKey="ha" title="High Availability" key="high-availability" unmountOnExit>
134+
<Tab eventKey="ha" title="Platform HA and Backups" key="high-availability" unmountOnExit>
138135
<RbacValidator accessRequiredOn={ApiPermissionMap.GET_HA_CONFIG}>
139136
<YBTabsPanel
140-
defaultTab={HighAvailabilityTabs.REPLICATION}
137+
defaultTab={PlatformHaAndBackupsTabs.PLATFORM_HA}
141138
activeTab={params.section}
142139
routePrefix={`/admin/${AdministrationTabs.HA}/`}
143140
id="administration-ha-subtab"
144141
className="config-tabs"
145142
>
146143
<Tab
147-
eventKey={HighAvailabilityTabs.REPLICATION}
148-
title={
149-
<span>
150-
<i className="fa fa-clone tab-logo" aria-hidden="true" /> Replication
151-
Configuration
152-
</span>
153-
}
154-
unmountOnExit
155-
>
156-
<HAReplication />
157-
</Tab>
158-
<Tab
159-
eventKey={HighAvailabilityTabs.INSTANCES}
160-
title={
161-
<span>
162-
<i className="fa fa-codepen tab-logo" aria-hidden="true"></i> Instance
163-
Configuration
164-
</span>
165-
}
144+
eventKey={PlatformHaAndBackupsTabs.PLATFORM_HA}
145+
title="Platform High Availability"
166146
unmountOnExit
167147
>
168-
<HAInstancesContainer />
148+
<PlatformHa />
169149
</Tab>
170-
{currentInstance?.is_leader && !isNoHAConfigExists && (
150+
{isContinuousBackupsUiEnable && (
171151
<Tab
172-
eventKey={HighAvailabilityTabs.METRICS}
173-
title={
174-
<span>
175-
<i className="fa fa-line-chart tab-logo" aria-hidden="true" />
176-
Metrics
177-
</span>
178-
}
152+
eventKey={PlatformHaAndBackupsTabs.CONTINUOUS_BACKUP}
153+
title="Automated Platform Backups"
179154
unmountOnExit
180155
>
181-
<HaMetrics />
156+
<ContinuousBackup />
182157
</Tab>
183158
)}
184159
</YBTabsPanel>
@@ -188,7 +163,7 @@ export const Administration: FC<RouteComponentProps<{}, RouteParams>> = ({ param
188163
};
189164

190165
const getUserManagementTab = () => {
191-
const { id, title, defaultTab } = USER_MANAGAEMENT_TAB;
166+
const { id, title, defaultTab } = USER_MANAGEMENT_TAB;
192167
return (
193168
<Tab eventKey={id} title={title} key={id} unmountOnExit>
194169
<UserManagementContainer
@@ -231,7 +206,7 @@ export const Administration: FC<RouteComponentProps<{}, RouteParams>> = ({ param
231206

232207
return (
233208
<div>
234-
<h2 className="content-title">Platform Configuration</h2>
209+
<h2 className="content-title">Platform Administration</h2>
235210
<YBTabsWithLinksPanel
236211
defaultTab={defaultTab}
237212
activeTab={params.tab}
@@ -243,7 +218,7 @@ export const Administration: FC<RouteComponentProps<{}, RouteParams>> = ({ param
243218
{getAlertTab()}
244219
{!isRbacEnabled() && getUserManagementTab()}
245220
{getCustomCACertsTab()}
246-
{isCongifUIEnabled && getAdvancedTab()}
221+
{isRuntimeConfigUiEnabled && getAdvancedTab()}
247222
{isRbacEnabled() && getRbacTab()}
248223
</YBTabsWithLinksPanel>
249224
</div>

managed/ui/src/components/backupv2/common/BackupAPI.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
BACKUP_API_TYPES,
1919
Backup_Options_Type,
2020
ICommonBackupInfo,
21-
IStorageConfig,
21+
CustomerConfig,
2222
ITable,
2323
ThrottleParameters,
2424
IBackupEditParams
@@ -216,7 +216,7 @@ export function editBackup(values: IBackupEditParams) {
216216
return axios.put(requestUrl, values);
217217
}
218218

219-
export const assignStorageConfig = (backup: IBackup, storageConfig: IStorageConfig) => {
219+
export const assignStorageConfig = (backup: IBackup, storageConfig: CustomerConfig) => {
220220
const cUUID = localStorage.getItem('customerId');
221221
const requestUrl = `${ROOT_URL}/customers/${cUUID}/backups/${backup.commonBackupInfo.backupUUID}`;
222222
return axios.put(requestUrl, {
@@ -296,5 +296,5 @@ export function deleteIncrementalBackup(incrementalBackup: ICommonBackupInfo) {
296296
export const fetchStorageConfigs = () => {
297297
const cUUID = localStorage.getItem('customerId');
298298
const requestUrl = `${ROOT_URL}/customers/${cUUID}/configs`;
299-
return axios.get<IStorageConfig[]>(requestUrl);
299+
return axios.get<CustomerConfig[]>(requestUrl);
300300
};

managed/ui/src/components/backupv2/common/BackupUtils.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import React, { useState } from 'react';
1111
import moment from 'moment';
1212
import { useSelector } from 'react-redux';
1313
import { keyBy, mapValues, capitalize, lowerCase, find } from 'lodash';
14-
import { Backup_Options_Type, IBackup, IStorageConfig, IUniverse } from './IBackup';
14+
import { Backup_Options_Type, IBackup, CustomerConfig, IUniverse } from './IBackup';
1515
import { Backup_States } from '../common/IBackup';
1616
import { Alert } from 'react-bootstrap';
1717
import { TableType } from '../../../redesign/helpers/dtos';
@@ -166,7 +166,7 @@ export const RESTORE_IN_PROGRESS_MSG = (
166166
progress.
167167
</Alert>
168168
);
169-
export const convertBackupToFormValues = (backup: IBackup, storage_config: IStorageConfig) => {
169+
export const convertBackupToFormValues = (backup: IBackup, storage_config: CustomerConfig) => {
170170
const formValues = {
171171
use_cron_expression: false,
172172
cron_expression: '',
@@ -241,7 +241,10 @@ export const convertBackupToFormValues = (backup: IBackup, storage_config: IStor
241241
};
242242

243243
export const isBackupPITREnabled = (runtimeConfigs: RunTimeConfig) => {
244-
return find(runtimeConfigs?.configEntries, (config) => config.key === BACKUP_PITR_ENABLED)?.value === 'true';
244+
return (
245+
find(runtimeConfigs?.configEntries, (config) => config.key === BACKUP_PITR_ENABLED)?.value ===
246+
'true'
247+
);
245248
};
246249

247250
export const isPathStyleAccess = (runtimeConfigs: RunTimeConfig) => {

0 commit comments

Comments
 (0)