Skip to content
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
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-13562-fixed-1775692362893.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Fixed
---

LKE version upgrade logic ([#13562](https://github.com/linode/manager/pull/13562))
115 changes: 93 additions & 22 deletions packages/manager/src/features/Kubernetes/kubeUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,31 +307,102 @@
const result = getNextVersion(currentVersion, versions);
expect(result).toEqual('2.00');
});
});

it('should get the next version when given a current enterprise version', () => {
const versions: KubernetesTieredVersion[] = [
{ id: 'v1.31.1+lke4', tier: 'enterprise' },
{ id: 'v1.31.6+lke2', tier: 'enterprise' },
{ id: 'v1.31.6+lke3', tier: 'enterprise' },
{ id: 'v1.31.8+lke1', tier: 'enterprise' },
];
const currentVersion = 'v1.31.6+lke2';

const result = getNextVersion(currentVersion, versions);
expect(result).toEqual('v1.31.6+lke3');
});
it('should get the next version when given a current enterprise version', () => {
const versions: KubernetesTieredVersion[] = [
{ id: 'v1.31.1+lke4', tier: 'enterprise' },
{ id: 'v1.31.6+lke2', tier: 'enterprise' },
{ id: 'v1.31.6+lke3', tier: 'enterprise' },
{ id: 'v1.31.8+lke1', tier: 'enterprise' },
];
const currentVersion = 'v1.31.6+lke2';

const result = getNextVersion(currentVersion, versions);
expect(result).toEqual('v1.31.6+lke3');
});

it('should get the next version when given an obsolete current version', () => {
const versions: KubernetesVersion[] = [
{ id: '1.16' },
{ id: '1.17' },
{ id: '1.18' },
];
const currentVersion = '1.15';

const result = getNextVersion(currentVersion, versions);
expect(result).toEqual('1.16');
});

it('should correctly sort enterprise versions across different minor versions', () => {
const versions: KubernetesTieredVersion[] = [
{ id: 'v1.31.8+lke5', tier: 'enterprise' },

Check warning on line 338 in packages/manager/src/features/Kubernetes/kubeUtils.test.ts

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Define a constant instead of duplicating this literal 8 times. Raw Output: {"ruleId":"sonarjs/no-duplicate-string","severity":1,"message":"Define a constant instead of duplicating this literal 8 times.","line":338,"column":15,"nodeType":"Literal","endLine":338,"endColumn":29}
{ id: 'v1.32.9+lke1', tier: 'enterprise' },

Check warning on line 339 in packages/manager/src/features/Kubernetes/kubeUtils.test.ts

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Define a constant instead of duplicating this literal 9 times. Raw Output: {"ruleId":"sonarjs/no-duplicate-string","severity":1,"message":"Define a constant instead of duplicating this literal 9 times.","line":339,"column":15,"nodeType":"Literal","endLine":339,"endColumn":29}
];
const currentVersion = 'v1.31.8+lke5';

const result = getNextVersion(currentVersion, versions);
expect(result).toEqual('v1.32.9+lke1');
});

it('should not suggest a downgrade when cluster version is higher than all available versions', () => {
const versions: KubernetesTieredVersion[] = [
{ id: 'v1.31.8+lke5', tier: 'enterprise' },
];
const currentVersion = 'v1.32.9+lke1';

const result = getNextVersion(currentVersion, versions);
expect(result).toBeNull();
});

it('should handle multi-digit lke release numbers correctly', () => {
const versions: KubernetesTieredVersion[] = [
{ id: 'v1.31.8+lke2', tier: 'enterprise' },
{ id: 'v1.31.8+lke5', tier: 'enterprise' },
{ id: 'v1.31.8+lke10', tier: 'enterprise' },
];
const currentVersion = 'v1.31.8+lke5';

it('should get the next version when given an obsolete current version', () => {
const versions: KubernetesVersion[] = [
{ id: '1.16' },
{ id: '1.17' },
{ id: '1.18' },
];
const currentVersion = '1.15';
const result = getNextVersion(currentVersion, versions);
expect(result).toEqual('v1.31.8+lke10');
});

const result = getNextVersion(currentVersion, versions);
expect(result).toEqual('1.16');
it('should handle multi-digit patch versions correctly', () => {
const versions: KubernetesTieredVersion[] = [
{ id: 'v1.32.9+lke1', tier: 'enterprise' },
{ id: 'v1.32.10+lke1', tier: 'enterprise' },
];
const currentVersion = 'v1.32.9+lke1';

const result = getNextVersion(currentVersion, versions);
expect(result).toEqual('v1.32.10+lke1');
});

it('should return null when the cluster is already on the latest version', () => {
const versions: KubernetesTieredVersion[] = [
{ id: 'v1.31.8+lke5', tier: 'enterprise' },
{ id: 'v1.32.9+lke1', tier: 'enterprise' },
];
const currentVersion = 'v1.32.9+lke1';

const result = getNextVersion(currentVersion, versions);
expect(result).toBeNull();
});

it('should return the correct next version for an obsolete enterprise version', () => {
const versions: KubernetesTieredVersion[] = [
{ id: 'v1.31.8+lke5', tier: 'enterprise' },
{ id: 'v1.32.9+lke1', tier: 'enterprise' },
];
const currentVersion = 'v1.30.0+lke1';

const result = getNextVersion(currentVersion, versions);
expect(result).toEqual('v1.31.8+lke5');
});

it('should return null when there are no versions available', () => {
const result = getNextVersion('v1.32.9+lke1', []);
expect(result).toBeNull();
});
});
});

Expand Down
27 changes: 12 additions & 15 deletions packages/manager/src/features/Kubernetes/kubeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,26 +137,23 @@ export const getNextVersion = (
if (versions.length === 0) {
return null;
}
const versionStrings = versions.map((v) => v.id).sort();
const versionStrings = versions
.map((v) => v.id)
.sort((a, b) => compareByKubernetesVersion(a, b, 'asc'));
const currentIdx = versionStrings.findIndex(
(thisVersion) => currentVersion === thisVersion
);
if (currentIdx < 0) {
// For now, assume that if nothing matches the user is on an obsolete version.
// According to the LKE team's deprecation policy, there will only ever be
// one such obsolete version, so this is safe. However, we'll eventually
// have a version.deprecated field to work with, which will be cleaner
// and safer.
//
// Example:
// API returns [1.16, 1.17, 1.18].
// You haven't upgraded in ages and your cluster is on 1.15.
// The next available upgrade would be 1.16, which is the first item in the list.
// Return that.
//
return versionStrings[0];
// The current version is not in the available versions list.
// This typically means the user is on an obsolete/deprecated version.
// Return the first available version that is actually newer than the current version
// to avoid suggesting a downgrade.
const nextHigherVersion = versionStrings.find(
(v) => compareByKubernetesVersion(v, currentVersion, 'asc') > 0
);
return nextHigherVersion ?? null;
}
if (currentIdx === versions.length - 1) {
if (currentIdx === versionStrings.length - 1) {
return null;
}
return versionStrings[currentIdx + 1];
Expand Down
Loading