Skip to content

Commit

Permalink
[PLAT-15288] Use set_dbs endpoint when editing table selection for db…
Browse files Browse the repository at this point in the history
… scoped DR configs

Summary:
For DB scoped DR configs, we have a different endpoint for the edit table flow.
Instead of set_tables, the client should send a request to the `set_dbs` endpoint instead.

This diff also modifies the form field for the set_dbs request and edit xCluster config form by changing the
`databases` to `dbs`. This change is made to stay consistent with the `dbs` field used during db scoped DR creation.

Test Plan:
Verify that user is able to add databases to and remove databases from a db scoped DR config.
Verify that the YBA UI still uses set_tables endpoint when the config is not db scoped.

Reviewers: rmadhavan, cwang, hzare, vbansal

Reviewed By: cwang

Subscribers: yugaware

Differential Revision: https://phorge.dev.yugabyte.com/D38026
  • Loading branch information
Jethro-M committed Sep 17, 2024
1 parent 84f3fab commit c7af74d
Show file tree
Hide file tree
Showing 21 changed files with 69 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void run() {
if (!CollectionUtils.isEmpty(taskParams().getTableIdsToRemove())) {
createSubTaskToRemoveTables(xClusterConfig, sourceUniverse);
}
} else if (editFormData.databases != null) { // Used for DB scoped replication only.
} else if (editFormData.dbs != null) { // Used for DB scoped replication only.
if (!xClusterConfig.getType().equals(ConfigType.Db)) {
throw new IllegalArgumentException(
"The databases must be provided only for DB scoped replication");
Expand Down Expand Up @@ -148,9 +148,9 @@ public void run() {
xClusterConfig.updateStatusForTables(
tablesInPendingStatus, XClusterTableConfig.Status.Failed);
}
if (editFormData.databases != null) {
if (editFormData.dbs != null) {
// Set databases in updating status to failed.
Set<String> dbIds = editFormData.databases;
Set<String> dbIds = editFormData.dbs;
Set<String> namespacesInPendingStatus =
xClusterConfig.getNamespaceIdsInStatus(
dbIds, X_CLUSTER_NAMESPACE_CONFIG_PENDING_STATUS_LIST);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -785,12 +785,12 @@ public class GlobalConfKeys extends RuntimeConfigKeysModule {
"It indicates whether creating disaster recovery configs are enabled",
ConfDataType.BooleanType,
ImmutableList.of(ConfKeyTags.PUBLIC));
public static final ConfKeyInfo<Boolean> dbScopedXClusterEnabled =
public static final ConfKeyInfo<Boolean> dbScopedXClusterCreationEnabled =
new ConfKeyInfo<>(
"yb.xcluster.db_scoped.enabled",
"yb.xcluster.db_scoped.creationEnabled",
ScopeType.GLOBAL,
"Flag to enable db scoped xcluster replication",
"If flag is enabled, allows DR support with db scoped xcluster replication",
"Flag to enable db scoped xCluster replication creation",
"If flag is enabled, allows DR creation with db scoped xCluster replication",
ConfDataType.BooleanType,
ImmutableList.of(ConfKeyTags.INTERNAL));
public static final ConfKeyInfo<Boolean> xclusterEnableAutoFlagValidation =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,14 @@ public Result create(UUID customerUUID, Http.Request request) {
}

boolean isDbScoped =
confGetter.getGlobalConf(GlobalConfKeys.dbScopedXClusterEnabled) || createForm.dbScoped;
if (!confGetter.getGlobalConf(GlobalConfKeys.dbScopedXClusterEnabled) && createForm.dbScoped) {
confGetter.getGlobalConf(GlobalConfKeys.dbScopedXClusterCreationEnabled)
|| createForm.dbScoped;
if (!confGetter.getGlobalConf(GlobalConfKeys.dbScopedXClusterCreationEnabled)
&& createForm.dbScoped) {
throw new PlatformServiceException(
BAD_REQUEST,
"Support for db scoped disaster recovery configs is disabled in YBA. You may enable it "
+ "by setting yb.xcluster.db_scoped.enabled to true in the application.conf");
+ "by setting yb.xcluster.db_scoped.creationEnabled to true in the application.conf");
}

if (isDbScoped) {
Expand Down Expand Up @@ -1632,7 +1634,7 @@ public Result setDatabases(UUID customerUUID, UUID drConfigUuid, Http.Request re
}
DrConfigSetDatabasesForm setDatabasesForm = parseSetDatabasesForm(customerUUID, request);
Set<String> existingDatabaseIds = xClusterConfig.getDbIds();
Set<String> newDatabaseIds = setDatabasesForm.databases;
Set<String> newDatabaseIds = setDatabasesForm.dbs;
Set<String> databaseIdsToAdd = Sets.difference(newDatabaseIds, existingDatabaseIds);
Set<String> databaseIdsToRemove = Sets.difference(existingDatabaseIds, newDatabaseIds);
if (databaseIdsToAdd.isEmpty() && databaseIdsToRemove.isEmpty()) {
Expand Down Expand Up @@ -1756,7 +1758,7 @@ private DrConfigSetDatabasesForm parseSetDatabasesForm(UUID customerUUID, Http.R
DrConfigSetDatabasesForm formData =
formFactory.getFormDataOrBadRequest(
request.body().asJson(), DrConfigSetDatabasesForm.class);
formData.databases = XClusterConfigTaskBase.convertUuidStringsToIdStringSet(formData.databases);
formData.dbs = XClusterConfigTaskBase.convertUuidStringsToIdStringSet(formData.dbs);
return formData;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ static XClusterConfigTaskParams getSetDatabasesTaskParams(
Set<String> databaseIdsToRemove) {

XClusterConfigEditFormData editForm = new XClusterConfigEditFormData();
editForm.databases = databaseIds;
editForm.dbs = databaseIds;

return new XClusterConfigTaskParams(
xClusterConfig, bootstrapParams, editForm, databaseIdsToAdd, databaseIdsToRemove);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ public class DrConfigSetDatabasesForm {
example = "[\"000033df000030008000000000004006\", \"000033df00003000800000000000400b\"]")
@YbaApi(visibility = YbaApi.YbaApiVisibility.PREVIEW, sinceYBAVersion = "2.23.0.0")
@Required
public Set<String> databases;
public Set<String> dbs;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class XClusterConfigEditFormData {
value = "WARNING: This is a preview API that could change. Source universe database IDs",
example = "[\"000033df000030008000000000004006\", \"000033df00003000800000000000400b\"]")
@YbaApi(visibility = YbaApi.YbaApiVisibility.PREVIEW, sinceYBAVersion = "2.23.0.0")
public Set<String> databases;
public Set<String> dbs;

@ApiModelProperty(
value =
Expand Down
2 changes: 1 addition & 1 deletion managed/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ yb {

xcluster {
db_scoped {
enabled = false
creationEnabled = false
}
bootstrap_producer_timeout = 2 minutes
k8s_tls_support = true
Expand Down
4 changes: 2 additions & 2 deletions managed/src/main/resources/swagger-strict.json
Original file line number Diff line number Diff line change
Expand Up @@ -5227,7 +5227,7 @@
"DrConfigSetDatabasesForm" : {
"description" : "dr config set databases form",
"properties" : {
"databases" : {
"dbs" : {
"description" : "WARNING: This is a preview API that could change. Source universe database IDs",
"example" : "[\"000033df000030008000000000004006\", \"000033df00003000800000000000400b\"]",
"items" : {
Expand Down Expand Up @@ -16083,7 +16083,7 @@
"$ref" : "#/definitions/BootstrapParams",
"description" : "Parameters needed for the bootstrap flow including backup/restore"
},
"databases" : {
"dbs" : {
"description" : "WARNING: This is a preview API that could change. Source universe database IDs",
"example" : "[\"000033df000030008000000000004006\", \"000033df00003000800000000000400b\"]",
"items" : {
Expand Down
4 changes: 2 additions & 2 deletions managed/src/main/resources/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -5262,7 +5262,7 @@
"DrConfigSetDatabasesForm" : {
"description" : "dr config set databases form",
"properties" : {
"databases" : {
"dbs" : {
"description" : "WARNING: This is a preview API that could change. Source universe database IDs",
"example" : "[\"000033df000030008000000000004006\", \"000033df00003000800000000000400b\"]",
"items" : {
Expand Down Expand Up @@ -16236,7 +16236,7 @@
"$ref" : "#/definitions/BootstrapParams",
"description" : "Parameters needed for the bootstrap flow including backup/restore"
},
"databases" : {
"dbs" : {
"description" : "WARNING: This is a preview API that could change. Source universe database IDs",
"example" : "[\"000033df000030008000000000004006\", \"000033df00003000800000000000400b\"]",
"items" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void setupDrDbScoped() {
runtimeConfService.setKey(
customer.getUuid(),
ScopedRuntimeConfig.GLOBAL_SCOPE_UUID,
GlobalConfKeys.dbScopedXClusterEnabled.getKey(),
GlobalConfKeys.dbScopedXClusterCreationEnabled.getKey(),
"true",
true);

Expand Down Expand Up @@ -283,10 +283,10 @@ public void testDrDbScopedUpdate() throws InterruptedException {

List<String> updateNamespaceNames = Arrays.asList("dbcolocated");
DrConfigSetDatabasesForm setDatabasesFormData = new DrConfigSetDatabasesForm();
setDatabasesFormData.databases = new HashSet<String>();
setDatabasesFormData.dbs = new HashSet<String>();
for (TableInfoForm.NamespaceInfoResp namespace : namespaceInfo) {
if (updateNamespaceNames.contains(namespace.name)) {
setDatabasesFormData.databases.add(namespace.namespaceUUID.toString());
setDatabasesFormData.dbs.add(namespace.namespaceUUID.toString());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,12 @@ public void setUp() {
}

@Test
// Runtime config `yb.xcluster.db_scoped.enabled` = true and db scoped parameter is passed in
// as true for request body.
// Runtime config `yb.xcluster.db_scoped.creationEnabled` = true and db scoped parameter is passed
// in as true for request body.
public void testCreateDbScopedSuccess() {
settableRuntimeConfigFactory
.globalRuntimeConf()
.setValue("yb.xcluster.db_scoped.enabled", "true");
.setValue("yb.xcluster.db_scoped.creationEnabled", "true");
DrConfigCreateForm data = createDefaultCreateForm("dbScopedDR", true);
UUID taskUUID = buildTaskInfo(null, TaskType.CreateDrConfig);
when(mockCommissioner.submit(any(), any())).thenReturn(taskUUID);
Expand All @@ -230,11 +230,11 @@ public void testCreateDbScopedSuccess() {
}

@Test
// Runtime config `yb.xcluster.db_scoped.enabled` = true with no parameter.
// Runtime config `yb.xcluster.db_scoped.creationEnabled` = true with no parameter.
public void testSetDatabasesSuccess() {
settableRuntimeConfigFactory
.globalRuntimeConf()
.setValue("yb.xcluster.db_scoped.enabled", "true");
.setValue("yb.xcluster.db_scoped.creationEnabled", "true");
DrConfigCreateForm data = createDefaultCreateForm("dbScopedDR", null);
UUID taskUUID = buildTaskInfo(null, TaskType.CreateDrConfig);
when(mockCommissioner.submit(any(), any())).thenReturn(taskUUID);
Expand All @@ -254,7 +254,7 @@ public void testSetDatabasesSuccess() {
assertNotNull(drConfig);
UUID drConfigId = drConfig.getUuid();
DrConfigSetDatabasesForm setDatabasesData = new DrConfigSetDatabasesForm();
setDatabasesData.databases = new HashSet<>(Set.of("db1", "db2"));
setDatabasesData.dbs = new HashSet<>(Set.of("db1", "db2"));
XClusterConfig xClusterConfig = drConfig.getActiveXClusterConfig();
xClusterConfig.updateStatus(XClusterConfigStatusType.Running);
drConfig.setState(State.Replicating);
Expand All @@ -276,7 +276,7 @@ public void testSetDatabasesSuccess() {
assertOk(result);

// Try adding a database and deleting a database.
setDatabasesData.databases = new HashSet<>(Set.of("db2", "db3"));
setDatabasesData.dbs = new HashSet<>(Set.of("db2", "db3"));
xClusterConfig = drConfig.getActiveXClusterConfig();
xClusterConfig.updateStatus(XClusterConfigStatusType.Running);

Expand All @@ -297,11 +297,11 @@ public void testSetDatabasesSuccess() {
}

@Test
// Runtime config `yb.xcluster.db_scoped.enabled` = true with no parameter.
// Runtime config `yb.xcluster.db_scoped.creationEnabled` = true with no parameter.
public void testSetDatabasesFailureNoChange() {
settableRuntimeConfigFactory
.globalRuntimeConf()
.setValue("yb.xcluster.db_scoped.enabled", "true");
.setValue("yb.xcluster.db_scoped.creationEnabled", "true");
DrConfigCreateForm data = createDefaultCreateForm("dbScopedDR", null);
UUID taskUUID = buildTaskInfo(null, TaskType.CreateDrConfig);
when(mockCommissioner.submit(any(), any())).thenReturn(taskUUID);
Expand All @@ -320,7 +320,7 @@ public void testSetDatabasesFailureNoChange() {
assertNotNull(drConfig);
UUID drConfigId = drConfig.getUuid();
DrConfigSetDatabasesForm setDatabasesData = new DrConfigSetDatabasesForm();
setDatabasesData.databases = new HashSet<>(Set.of(namespaceId));
setDatabasesData.dbs = new HashSet<>(Set.of(namespaceId));
XClusterConfig xClusterConfig = drConfig.getActiveXClusterConfig();
xClusterConfig.updateStatus(XClusterConfigStatusType.Running);
xClusterConfig.updateStatusForNamespace(namespaceId, XClusterNamespaceConfig.Status.Running);
Expand All @@ -347,11 +347,11 @@ public void testSetDatabasesFailureNoChange() {
}

@Test
// Runtime config `yb.xcluster.db_scoped.enabled` = true with no parameter.
// Runtime config `yb.xcluster.db_scoped.creationEnabled` = true with no parameter.
public void testSetDatabasesFailureNoDbs() {
settableRuntimeConfigFactory
.globalRuntimeConf()
.setValue("yb.xcluster.db_scoped.enabled", "true");
.setValue("yb.xcluster.db_scoped.creationEnabled", "true");
DrConfigCreateForm data = createDefaultCreateForm("dbScopedDR", null);
UUID taskUUID = buildTaskInfo(null, TaskType.CreateDrConfig);
when(mockCommissioner.submit(any(), any())).thenReturn(taskUUID);
Expand All @@ -377,7 +377,7 @@ public void testSetDatabasesFailureNoDbs() {
drConfig.update();

// Try giving an empty list.
setDatabasesData.databases = new HashSet<>();
setDatabasesData.dbs = new HashSet<>();
xClusterConfig = drConfig.getActiveXClusterConfig();
xClusterConfig.updateStatus(XClusterConfigStatusType.Running);
Exception exception =
Expand All @@ -397,12 +397,12 @@ public void testSetDatabasesFailureNoDbs() {
}

@Test
// Runtime config `yb.xcluster.db_scoped.enabled` is disabled but db scoped parameter is passed in
// as true for request body.
// Runtime config `yb.xcluster.db_scoped.creationEnabled` is disabled but db scoped parameter is
// passed in as true for request body.
public void testCreateDbScopedDisabledFailure() {
settableRuntimeConfigFactory
.globalRuntimeConf()
.setValue("yb.xcluster.db_scoped.enabled", "false");
.setValue("yb.xcluster.db_scoped.creationEnabled", "false");
DrConfigCreateForm data = createDefaultCreateForm("dbScopedDR", true);
buildTaskInfo(null, TaskType.CreateDrConfig);

Expand Down
2 changes: 1 addition & 1 deletion managed/ui/src/components/xcluster/ReplicationUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ export const getEnabledConfigActions = (
isXClusterConfigAllBidirectional: boolean,
drConfigState?: DrConfigState
): XClusterConfigAction[] => {
if (drConfigState === DrConfigState.ERROR) {
if (drConfigState === DrConfigState.FAILED) {
// When DR config is in error state, we only allow the DR config delete operation.
return [];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const DrConfigStateLabel = ({ drConfig, variant = 'body2' }: DrConfigStat
</YBTooltip>
</Typography>
);
case DrConfigState.ERROR:
case DrConfigState.FAILED:
return (
<Typography
variant={variant}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf

const isDbScopedEnabled =
runtimeConfigEntries.find(
(config: any) => config.key === RuntimeConfigKey.XCLUSTER_DB_SCOPED_FEATURE_FLAG
(config: any) => config.key === RuntimeConfigKey.XCLUSTER_DB_SCOPED_CREATION_FEATURE_FLAG
)?.value ?? false;

const onSubmit: SubmitHandler<CreateDrConfigFormValues> = async (formValues) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const DrConfigState = {
SWITCHOVER_IN_PROGRESS: 'Switchover in Progress',
FAILOVER_IN_PROGRESS: 'Failover in Progress',
HALTED: 'Halted',
ERROR: 'Error'
FAILED: 'Failed'
} as const;
export type DrConfigState = typeof DrConfigState[keyof typeof DrConfigState];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import { YBButton, YBModal, YBModalProps } from '../../../../redesign/components
import {
api,
drConfigQueryKey,
runtimeConfigQueryKey,
universeQueryKey,
xClusterQueryKey
} from '../../../../redesign/helpers/api';
import { assertUnreachableCase, handleServerError } from '../../../../utils/errorHandlingUtils';
import { YBErrorIndicator, YBLoading } from '../../../common/indicators';
import { XClusterConfigAction, XClusterTableStatus } from '../../constants';
import { XClusterConfigAction, XClusterConfigType, XClusterTableStatus } from '../../constants';
import {
formatUuidForXCluster,
getCategorizedNeedBootstrapPerTableResponse,
getInConfigTableUuidsToTableDetailsMap,
getXClusterConfigTableType,
Expand Down Expand Up @@ -114,19 +114,19 @@ export const EditTablesModal = (props: EditTablesModalProps) => {
universeQueryKey.namespaces(xClusterConfigQuery.data?.sourceUniverseUUID),
() => api.fetchUniverseNamespaces(xClusterConfigQuery.data?.sourceUniverseUUID)
);
const customerUuid = localStorage.getItem('customerId') ?? '';
const runtimeConfigQuery = useQuery(runtimeConfigQueryKey.customerScope(customerUuid), () =>
api.fetchRuntimeConfigs(customerUuid, true)
);

const editTableMutation = useMutation(
(formValues: EditTablesFormValues) => {
const bootstrapRequiredTableUuids =
categorizedNeedBootstrapPerTableResponse?.bootstrapTableUuids ?? [];
return props.isDrInterface
? api.updateTablesInDr(props.drConfigUuid, {
tables: formValues.tableUuids
})
? xClusterConfigQuery.data?.type === XClusterConfigType.DB_SCOPED
? api.updateDbsInDr(props.drConfigUuid, {
dbs: formValues.namespaceUuids.map(formatUuidForXCluster)
})
: api.updateTablesInDr(props.drConfigUuid, {
tables: formValues.tableUuids
})
: editXClusterConfigTables(xClusterConfigUuid, {
tables: formValues.tableUuids,
autoIncludeIndexTables: shouldAutoIncludeIndexTables(xClusterConfigQuery.data),
Expand Down Expand Up @@ -192,9 +192,7 @@ export const EditTablesModal = (props: EditTablesModalProps) => {
sourceUniverseQuery.isLoading ||
sourceUniverseQuery.isIdle ||
sourceUniverseNamespacesQuery.isLoading ||
sourceUniverseNamespacesQuery.isIdle ||
runtimeConfigQuery.isLoading ||
runtimeConfigQuery.isIdle
sourceUniverseNamespacesQuery.isIdle
) {
return (
<YBModal title={modalTitle} submitTestId={`${MODAL_NAME}-SubmitButton`} {...modalProps}>
Expand Down Expand Up @@ -225,17 +223,14 @@ export const EditTablesModal = (props: EditTablesModalProps) => {
!targetUniverseUuid ||
sourceUniverseQuery.isError ||
sourceUniverseNamespacesQuery.isError ||
!xClusterConfigTableType ||
runtimeConfigQuery.isError
!xClusterConfigTableType
) {
const errorMessage = !xClusterConfig.sourceUniverseUUID
? t('error.undefinedSourceUniverseUuid')
: !xClusterConfig.targetUniverseUUID
? t('error.undefinedTargetUniverseUuid')
: !xClusterConfigTableType
? t('error.undefinedXClusterTableType', { keyPrefix: TRANSLATION_KEY_PREFIX_XCLUSTER })
: runtimeConfigQuery.isError
? t('failedToFetchCustomerRuntimeConfig', { keyPrefix: 'queryError' })
: t('error.fetchSourceUniverseDetailsFailure');
return (
<YBModal title={modalTitle} submitTestId={`${MODAL_NAME}-SubmitButton`} {...modalProps}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const getEnabledDrConfigActions = (
case DrConfigState.INITIALIZING:
case DrConfigState.SWITCHOVER_IN_PROGRESS:
case DrConfigState.FAILOVER_IN_PROGRESS:
case DrConfigState.ERROR:
case DrConfigState.FAILED:
return [DrConfigAction.DELETE];
case DrConfigState.REPLICATING:
return [
Expand Down
Loading

0 comments on commit c7af74d

Please sign in to comment.