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

Disable downgrades (all engines) and major upgrades (PSMDB, PG) #473

Merged
merged 15 commits into from
Jul 9, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@
import { StepHeader } from '../step-header/step-header.tsx';
import { DEFAULT_NODES } from './first-step.constants.ts';
import { Messages } from './first-step.messages.ts';
import { generateShortUID } from './utils.ts';
import {
filterAvailableDbVersionsForDbEngineEdition,
generateShortUID,
} from './utils.ts';
import { useDatabasePageDefaultValues } from '../../../useDatabaseFormDefaultValues.ts';

export const FirstStep = ({ loadingDefaultsForEdition }: StepProps) => {
const mode = useDatabasePageMode();

const {
defaultValues: { [DbWizardFormFields.dbVersion]: defaultDbVersion },
} = useDatabasePageDefaultValues(mode);
const { watch, setValue, getFieldState, resetField, getValues, trigger } =
useFormContext();

Expand All @@ -57,7 +63,7 @@
useDbEngines(dbNamespace);
const dbEngine = dbTypeToDbEngine(dbType);

const [dbVersions, setDbVersions] = useState(
const [dbEngineData, setDbEngineData] = useState(
dbEngines.find((engine) => engine.type === dbEngine)
);

Expand All @@ -70,23 +76,31 @@
[setValue]
);

const setDbVersionsForEngine = useCallback(() => {
const newVersions = dbEngines.find((engine) => engine.type === dbEngine);
const setDbEngineDataForEngineType = useCallback(() => {
const newEngineData = dbEngines.find((engine) => engine.type === dbEngine);

if (newEngineData && mode === 'edit') {
const validVersions = filterAvailableDbVersionsForDbEngineEdition(
newEngineData,
defaultDbVersion
);
newEngineData.availableVersions.engine = validVersions;
}

setDbVersions(newVersions);
}, [dbEngine, dbEngines]);
setDbEngineData(newEngineData);
}, [dbEngine, dbEngines, defaultDbVersion]);

Check warning on line 91 in ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.tsx

View workflow job for this annotation

GitHub Actions / CI_checks (lint)

React Hook useCallback has a missing dependency: 'mode'. Either include it or remove the dependency array

const updateDbVersions = useCallback(() => {
const { isDirty: dbVersionDirty } = getFieldState(
DbWizardFormFields.dbVersion
);
setDbVersionsForEngine();
setDbEngineDataForEngineType();

// Safety check
if (
dbVersionDirty ||
!dbVersions ||
!dbVersions.availableVersions.engine.length
!dbEngineData ||
!dbEngineData.availableVersions.engine.length
) {
return;
}
Expand All @@ -95,7 +109,7 @@
((mode === 'edit' || mode === 'restoreFromBackup') && !dbVersion) ||
mode === 'new'
) {
const recommendedVersion = dbVersions.availableVersions.engine
const recommendedVersion = dbEngineData.availableVersions.engine
.slice()
.reverse()
.find((version) => version.status === DbEngineToolStatus.RECOMMENDED);
Expand All @@ -104,15 +118,15 @@
DbWizardFormFields.dbVersion,
recommendedVersion
? recommendedVersion.version
: dbVersions.availableVersions.engine[0].version
: dbEngineData.availableVersions.engine[0].version
);
}
}, [
dbVersion,
dbVersions,
dbEngineData,
getFieldState,
mode,
setDbVersionsForEngine,
setDbEngineDataForEngineType,
setValue,
]);

Expand Down Expand Up @@ -200,8 +214,8 @@
}, [clusterInfo]);

useEffect(() => {
setDbVersionsForEngine();
}, [setDbVersionsForEngine]);
setDbEngineDataForEngineType();
}, [setDbEngineDataForEngineType]);

useEffect(() => {
const { isTouched: k8sNamespaceTouched } = getFieldState(
Expand Down Expand Up @@ -285,7 +299,7 @@
disabled: mode === 'restoreFromBackup',
}}
>
{dbVersions?.availableVersions.engine.map((version) => (
{dbEngineData?.availableVersions.engine.map((version) => (
<MenuItem value={version.version} key={version.version}>
{version.version}
</MenuItem>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { DbEngine, DbEngineType } from 'shared-types/dbEngines.types';
import { filterAvailableDbVersionsForDbEngineEdition } from './utils';

const generateDbEngineWithVersions = (
versions: string[],
type: DbEngineType
): DbEngine =>
({
availableVersions: {
engine: versions.map((version) => ({ version })),
},
type,
}) as unknown as DbEngine;

describe('Wizard first step::utils', () => {
describe('filterAvailableDbVersionsForDbEngineEdition', () => {
it('should rule out downgrades', () => {
expect(
filterAvailableDbVersionsForDbEngineEdition(
generateDbEngineWithVersions(
['5.0.0', '4.0.0', '4.3.9', '4.4.1'],
DbEngineType.PXC
),
'4.4.0'
).map(({ version }) => version)
).toEqual(['5.0.0', '4.4.1']);
});

it('should coerce PG versions to semver', () => {
expect(
filterAvailableDbVersionsForDbEngineEdition(
generateDbEngineWithVersions(
['13.0', '14.0', '14.1', '15.0'],
DbEngineType.POSTGRESQL
),
'14.1'
).map(({ version }) => version)
).toEqual(['14.1']);
});

it('should allow major upgrades for PXC', () => {
expect(
filterAvailableDbVersionsForDbEngineEdition(
generateDbEngineWithVersions(
['5.0.0', '4.0.0', '4.3.9', '4.4.1'],
DbEngineType.PXC
),
'4.4.0'
).map(({ version }) => version)
).toEqual(['5.0.0', '4.4.1']);
});

it('should rule out major upgrades/downgrades for PSMDB/PG', () => {
expect(
filterAvailableDbVersionsForDbEngineEdition(
generateDbEngineWithVersions(
[
'1.0.0',
'1.2.0',
'2.3.3',
'2.5.0',
'2.9.0',
'3.1.0',
'4.3.0',
'5.4.1',
],
DbEngineType.PSMDB
),
'2.3.0'
).map(({ version }) => version)
).toEqual(['2.3.3', '2.5.0', '2.9.0']);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
// 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
import { gte, coerce } from 'semver';
import { DbEngine, DbEngineType } from 'shared-types/dbEngines.types';

// limitations under the License.
export const generateShortUID = (): string => {
const firstPart = `000${((Math.random() * 46656) | 0).toString(36)}`.slice(
Expand All @@ -22,3 +25,34 @@ export const generateShortUID = (): string => {

return `${firstPart}${secondPart}`.slice(0, 3);
};

export const filterAvailableDbVersionsForDbEngineEdition = (
dbEngine: DbEngine,
currentVersion: string
) => {
let versions = dbEngine.availableVersions.engine || [];
const currentSemverVersion = coerce(currentVersion);
const dbType = dbEngine.type;

if (!currentSemverVersion) {
return versions;
}

const currentMajor = currentSemverVersion.major;

// Filter out downgrades
versions = versions.filter(({ version }) => {
const semverVersion = coerce(version);
return semverVersion ? gte(semverVersion, currentSemverVersion) : true;
});

// If the engine is PSMDB or PG, major version upgrades are also ruled out
if ([DbEngineType.PSMDB, DbEngineType.POSTGRESQL].includes(dbType)) {
versions = versions.filter(({ version }) => {
const semverVersion = coerce(version);
return semverVersion ? semverVersion.major === currentMajor : true;
});
}

return versions;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { MRT_ColumnDef } from 'material-react-table';
import { Button } from '@mui/material';
import { Table } from '@percona/ui-lib';
import semverCoerce from 'semver/functions/coerce';
import semverMajor from 'semver/functions/major';
import {
DbEngineToolStatus,
OperatorUpgradeDb,
Expand Down Expand Up @@ -73,9 +72,10 @@ const ClusterStatusTable = ({
const currentMajor = currenEngineVersion.major;
const availableVersions = dbEngine.availableVersions.engine
.filter(({ version, status }) => {
const semver = semverCoerce(version);
return (
status === DbEngineToolStatus.RECOMMENDED &&
semverMajor(version) === currentMajor
semver?.major === currentMajor
);
})
.map(({ version }) => version);
Expand Down
Loading