Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-13539-tests-1775850586793.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@linode/manager': Tests
---

Mock `databaseResizeGenerationalPlans` feature flag to false for resize-database.spec.ts ([#13539](https://github.com/linode/manager/pull/13539))
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Generational plans changes for Databases ([#13539](https://github.com/linode/manager/pull/13539))
35 changes: 20 additions & 15 deletions packages/manager/cypress/e2e/core/databases/resize-database.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
/**
* @file DBaaS integration tests for resize operations.
*/
import {
ClusterSize,
DatabaseStatus,
RegionAvailability,
} from '@linode/api-v4';
import { accountFactory } from '@src/factories';
import {
databaseConfigurationsResize,
Expand All @@ -20,13 +12,22 @@ import {
mockResize,
mockResizeProvisioningDatabase,
} from 'support/intercepts/databases';
import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags';
import { mockGetRegionAvailability } from 'support/intercepts/regions';
import { ui } from 'support/ui';
import { randomIp, randomNumber, randomString } from 'support/util/random';
import { getRegionById } from 'support/util/regions';

import { databaseFactory } from 'src/factories/databases';

/**
* @file DBaaS integration tests for resize operations.
*/
import type {
ClusterSize,
DatabaseStatus,
RegionAvailability,
} from '@linode/api-v4';
import type { DatabaseClusterConfiguration } from 'support/constants/databases';

/**
Expand Down Expand Up @@ -63,16 +64,20 @@ const resizeDatabase = (initialLabel: string) => {
* @param clusterSize - Database Cluster Size
*/
const getNodes = (clusterSize: number) => {
const nodes =
clusterSize == 1
? 'Primary (1 Node)'
: clusterSize == 2
? 'Primary (+1 Node)'
: 'Primary (+2 Nodes)';
return nodes;
return clusterSize === 1
? 'Primary (1 Node)'
: clusterSize === 2
? 'Primary (+1 Node)'
: 'Primary (+2 Nodes)';
};

describe('Resizing existing clusters', () => {
beforeEach(() => {
mockAppendFeatureFlags({
databaseResizeGenerationalPlans: false,
});
});

databaseConfigurationsResize.forEach(
(configuration: DatabaseClusterConfiguration) => {
describe(`Resizes a ${configuration.linodeType} ${configuration.engine} v${configuration.version}.x ${configuration.clusterSize}-node cluster`, () => {
Expand Down
4 changes: 4 additions & 0 deletions packages/manager/src/dev-tools/FeatureFlagTool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ const options: { flag: keyof Flags; label: string }[] = [
{ flag: 'supportTicketSeverity', label: 'Support Ticket Severity' },
{ flag: 'dbaasV2', label: 'Databases V2 Beta' },
{ flag: 'dbaasV2MonitorMetrics', label: 'Databases V2 Monitor' },
{
flag: 'databaseResizeGenerationalPlans',
label: 'Database Resize Generational Plans',
},
{ flag: 'databasePgBouncer', label: 'Database PgBouncer' },
{ flag: 'databaseResize', label: 'Database Resize' },
{ flag: 'databaseAdvancedConfig', label: 'Database Advanced Config' },
Expand Down
1 change: 1 addition & 0 deletions packages/manager/src/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ export interface Flags {
databasePgBouncer: boolean;
databasePremium: boolean;
databaseResize: boolean;
databaseResizeGenerationalPlans: boolean;
databaseRestrictPlanResize: boolean;
databases: boolean;
databaseVpc: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { ErrorMessage } from 'src/components/ErrorMessage';
import { LandingHeader } from 'src/components/LandingHeader';
import { getRestrictedResourceText } from 'src/features/Account/utils';
import { getIsLimitedAvailability } from 'src/features/components/PlansPanel/utils';
import {
getIsLimitedAvailability,
useShouldDisablePremiumPlansTab,
} from 'src/features/components/PlansPanel/utils';
import { DatabaseClusterData } from 'src/features/Databases/DatabaseCreate/DatabaseClusterData';
import {
StyledBtnCtn,
Expand Down Expand Up @@ -252,11 +255,15 @@ export const DatabaseCreate = () => {
}
};

const shouldDisablePremiumPlansTab = useShouldDisablePremiumPlansTab({
types: dbtypes,
});

if (regionsLoading || !regionsData || enginesLoading || typesLoading) {
return <CircleProgress />;
}

if (regionsError || typesError || enginesError) {
if (regionsError || enginesError || typesError) {
return <ErrorState errorText="An unexpected error occurred." />;
}

Expand Down Expand Up @@ -312,6 +319,9 @@ export const DatabaseCreate = () => {
<StyledPlansPanel
data-qa-select-plan
disabled={isRestricted}
disabledTabs={
shouldDisablePremiumPlansTab ? ['premium'] : undefined
}
error={fieldState.error?.message}
flow="database"
handleTabChange={handleTabChange}
Expand All @@ -321,6 +331,11 @@ export const DatabaseCreate = () => {
regionsData={regionsData}
selectedId={field.value}
selectedRegionID={region}
tabDisabledMessage={
shouldDisablePremiumPlansTab
? 'Premium CPUs are now called G7 Dedicated plans.'
: undefined
}
types={displayTypes}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ describe('database resize', () => {
beta: false,
enabled: true,
},
databasePremium: true,
};

it('resize button should be disabled when no input is provided in the form', async () => {
Expand Down Expand Up @@ -485,45 +486,6 @@ describe('database resize', () => {
});
});

describe('should disable Shared Plans Tab for 2 nodes cluster', () => {
const database = databaseFactory.build({
cluster_size: 2,
type: 'g6-dedicated-8',
});
it('should disable Shared Plans Tab', async () => {
const standardTypes = [
databaseTypeFactory.build({
class: 'nanode',
id: 'g6-nanode-1',
label: `Nanode 1 GB`,
memory: 1024,
}),
];
server.use(
http.get('*/databases/types', () => {
return HttpResponse.json(
makeResourcePage([...dedicatedTypes, ...standardTypes])
);
}),
http.get('*/account', () => {
const account = accountFactory.build();
return HttpResponse.json(account);
})
);

const { getByTestId, getByText } = renderWithTheme(
<DatabaseDetailContext.Provider
value={{ database, engine, isResizeEnabled }}
>
<DatabaseResize />
</DatabaseDetailContext.Provider>
);
expect(getByTestId(loadingTestId)).toBeInTheDocument();
await waitForElementToBeRemoved(getByTestId(loadingTestId));
expect(getByText('Shared CPU')).toHaveAttribute('aria-disabled', 'true');
});
});

describe('on rendering resize when databaseRestrictPlanResize feature flag is enabled', () => {
beforeEach(() => {
const standardTypes = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@
} from 'src/features/Databases/utilities';
import { typeLabelDetails } from 'src/features/Linodes/presentation';
import { useFlags } from 'src/hooks/useFlags';
import { useIsGenerationalPlansEnabled } from 'src/utilities/linodes';

import {
RESIZE_DISABLED_DEDICATED_SHARED_PLAN_TABS_TEXT,
RESIZE_DISABLED_NON_G7_DEDICATED_SHARED_PLAN_TABS_TEXT,
RESIZE_DISABLED_PREMIUM_PLAN_TAB_TEXT,
RESIZE_DISABLED_SHARED_PLAN_TAB_LEGACY_TEXT,
} from '../../constants';
import { useDatabaseDetailContext } from '../DatabaseDetailContext';
import {
Expand Down Expand Up @@ -112,45 +113,62 @@
(type: DatabaseType) => type.id === database.type
);

const isDisabledSharedTab = database.cluster_size === 2;

const premiumRestrictedTabsCopy =
currentPlanType?.class === 'premium'
? RESIZE_DISABLED_DEDICATED_SHARED_PLAN_TABS_TEXT
: RESIZE_DISABLED_PREMIUM_PLAN_TAB_TEXT;

const restrictPlanTypes = () => {
if (currentPlanType?.class === 'premium') {
return ['shared', 'dedicated'];
} else {
return ['premium'];
}
};
const { isGenerationalPlansEnabled } = useIsGenerationalPlansEnabled(
dbTypes,
currentPlanType?.class
);

const disabledTabsConfig: {
disabledTabs: string[];
disabledTabsCopy: string;
} = React.useMemo(() => {
// For new database clusters, restrict plan types based on the current plan
if (isDefaultDatabase(database) && flags.databaseRestrictPlanResize) {
if (
!flags.databaseRestrictPlanResize ||
(flags.databaseResizeGenerationalPlans &&
currentPlanType?.class === 'premium')
) {
return {
disabledTabsCopy: premiumRestrictedTabsCopy,
disabledTabs: restrictPlanTypes(),
disabledTabs: [],
disabledTabsCopy: '',
};
}
// Disable shared tab for legacy database clusters when cluster size is 2
if (!isNewDatabaseGA && isDisabledSharedTab) {

if (!isGenerationalPlansEnabled && currentPlanType?.class === 'premium') {
return {
disabledTabs: ['shared', 'dedicated'],
disabledTabsCopy: RESIZE_DISABLED_DEDICATED_SHARED_PLAN_TABS_TEXT,
};
}

if (isGenerationalPlansEnabled && currentPlanType?.class === 'premium') {
return {
disabledTabsCopy: RESIZE_DISABLED_SHARED_PLAN_TAB_LEGACY_TEXT,
disabledTabs: ['shared'],
disabledTabsCopy:
RESIZE_DISABLED_NON_G7_DEDICATED_SHARED_PLAN_TABS_TEXT,
};
}

if (
isGenerationalPlansEnabled &&
flags.databaseResizeGenerationalPlans &&
currentPlanType?.class !== 'premium'
) {
return {
disabledTabs: ['premium'],
disabledTabsCopy: 'Premium CPUs are now called G7 Dedicated plans.',
};
}

return {
disabledTabs: [],
disabledTabsCopy: '',
disabledTabs: ['premium'],
disabledTabsCopy: RESIZE_DISABLED_PREMIUM_PLAN_TAB_TEXT,
};
}, [database, flags, isNewDatabaseGA]);
}, [
currentPlanType?.class,
flags.databaseResizeGenerationalPlans,
flags.databaseRestrictPlanResize,
isGenerationalPlansEnabled,
]);

const { enqueueSnackbar } = useSnackbar();

Expand Down Expand Up @@ -314,13 +332,34 @@
setSelectedTab(initialTab);
}, []);

const disabledPlans = isSmallerOrEqualCurrentPlan(
const disabledPlansDueToDiskSize = isSmallerOrEqualCurrentPlan(
currentPlan?.id,
database?.used_disk_size_gb,
displayTypes,
isNewDatabaseGA
);

// @TODO remove dbaas resize class type restriction sometime post-release when we support resizing across different plans

Check warning on line 342 in packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Complete the task associated to this "TODO" comment. Raw Output: {"ruleId":"sonarjs/todo-tag","severity":1,"message":"Complete the task associated to this \"TODO\" comment.","line":342,"column":7,"nodeType":null,"messageId":"completeTODO","endLine":342,"endColumn":11}
const isCurrentPlanAPremiumPlan =
currentPlan?.class.includes('premium') ||
currentPlan?.id.includes('g7-dedicated');

Check warning on line 345 in packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Define a constant instead of duplicating this literal 3 times. Raw Output: {"ruleId":"sonarjs/no-duplicate-string","severity":1,"message":"Define a constant instead of duplicating this literal 3 times.","line":345,"column":30,"nodeType":"Literal","endLine":345,"endColumn":44}

const disabledResizeToPremiumPlans =
!flags.databaseResizeGenerationalPlans && !isCurrentPlanAPremiumPlan
? displayTypes.filter(
(type) =>
type.class.includes('premium') || type.id.includes('g7-dedicated')
)
: [];

const disabledResizeFromPremiumPlans =
!flags.databaseResizeGenerationalPlans && isCurrentPlanAPremiumPlan
? displayTypes.filter(
(type) =>
!type.class.includes('premium') && !type.id.includes('g7-dedicated')
)
: [];

const shouldSubmitBeDisabled = React.useMemo(() => {
return !summaryText;
}, [summaryText]);
Expand Down Expand Up @@ -405,7 +444,10 @@
currentPlanHeading={currentPlan?.heading}
data-qa-select-plan
disabled={disabled}
disabledSmallerPlans={disabledPlans}
// @TODO remove dbaas resize class type restriction sometime post-release when we support resizing across different plans

Check warning on line 447 in packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Complete the task associated to this "TODO" comment. Raw Output: {"ruleId":"sonarjs/todo-tag","severity":1,"message":"Complete the task associated to this \"TODO\" comment.","line":447,"column":15,"nodeType":null,"messageId":"completeTODO","endLine":447,"endColumn":19}
disabledResizeFromPremiumPlans={disabledResizeFromPremiumPlans}
disabledResizeToPremiumPlans={disabledResizeToPremiumPlans}
disabledSmallerPlans={disabledPlansDueToDiskSize}
disabledTabs={disabledTabsConfig.disabledTabs}
flow="database"
handleTabChange={handleTabChange}
Expand Down
4 changes: 2 additions & 2 deletions packages/manager/src/features/Databases/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export const RESIZE_DISABLED_PREMIUM_PLAN_TAB_TEXT =
export const RESIZE_DISABLED_DEDICATED_SHARED_PLAN_TABS_TEXT =
'Resizing to a Shared CPU or a Dedicated CPU plan is not available for database clusters on a Premium CPU plan.';

export const RESIZE_DISABLED_SHARED_PLAN_TAB_LEGACY_TEXT =
'Resizing a 2-node cluster is only allowed with Dedicated plans.';
export const RESIZE_DISABLED_NON_G7_DEDICATED_SHARED_PLAN_TABS_TEXT =
'Resizing to a Shared CPU or a non-G7 Dedicated CPU plan is not available for database clusters on a Premium CPU plan.';

export const BACKUPS_MAX_TIME_EXCEEDED_VALIDATON_TEXT =
'Select a time from the past.';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,8 @@ export const PlanContainer = (props: PlanContainerProps) => {
} = props;
const location = useLocation();
const flags = useFlags();
const { isGenerationalPlansEnabled } = useIsGenerationalPlansEnabled(
plans,
planType
);
const { isGenerationalPlansEnabled, hasG7DedicatedPlans } =
useIsGenerationalPlansEnabled(plans, planType);

// Show the Transfer column if, for any plan, the api returned data and we're not in the Database Create flow
const showTransfer =
Expand All @@ -135,8 +133,11 @@ export const PlanContainer = (props: PlanContainerProps) => {
const isDatabaseResizeFlow =
location.pathname.match(/\/databases\/.*\/(\d+\/resize)/)?.[0] ===
location.pathname;
const shouldDisplayNoRegionSelectedMessage =
!selectedRegionId && !isDatabaseCreateFlow && !isDatabaseResizeFlow;

const shouldDisplayNoRegionSelectedMessage = Boolean(
(!selectedRegionId && !isDatabaseCreateFlow) ||
(isDatabaseCreateFlow && hasG7DedicatedPlans && !selectedRegionId)
);

const isDatabaseGA =
!flags.dbaasV2?.beta &&
Expand Down
Loading
Loading