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

feat(versioning): aws-eks-addon versioning added #33301

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions lib/modules/versioning/api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as awsEksAddon from './aws-eks-addon';
import * as amazonMachineImage from './aws-machine-image';
import * as azureRestApi from './azure-rest-api';
import * as bazelModule from './bazel-module';
Expand Down Expand Up @@ -45,6 +46,7 @@ import * as unity3d from './unity3d';
const api = new Map<string, VersioningApi | VersioningApiConstructor>();
export default api;

api.set(awsEksAddon.id, awsEksAddon.api);
api.set(amazonMachineImage.id, amazonMachineImage.api);
api.set(azureRestApi.id, azureRestApi.api);
api.set(bazelModule.id, bazelModule.api);
Expand Down
105 changes: 105 additions & 0 deletions lib/modules/versioning/aws-eks-addon/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import aws from '.';

describe('modules/versioning/aws-eks-addon/index', () => {
describe('parse(version)', () => {
it('should return 1.23.7 and release version', () => {
expect(aws.getMajor('v1.20.7-eksbuild.1')).toBe(1);
expect(aws.getMinor('v1.23.7-eksbuild.1')).toBe(23);
expect(aws.getPatch('v1.20.7-eksbuild.1')).toBe(7);
});
});

describe('isValid(version)', () => {
it('should return true', () => {
expect(aws.isValid('v1.11.7-eksbuild.23')).toBeTruthy();
});

it('should return false', () => {
expect(aws.isValid('v1.11.7-noneksbuild.23')).toBeFalsy();
});
});

describe('isVersion(version)', () => {
it('should return true', () => {
expect(aws.isVersion('v1.11.7-eksbuild.1')).toBeTruthy();
});

it('should return false', () => {
expect(aws.isVersion('v1.11.7')).toBeFalsy();
});
});

describe('isCompatible(version)', () => {
it.each`
input | expected
${''} | ${false}
${'abrakadabra'} | ${false}
${'v1.11.7'} | ${false}
${'v1.11.7.6'} | ${false}
${'v1.11.7-noneksbuild'} | ${false}
${'v1.11.7-noneksbuild.1'} | ${false}
${'v1.11.7-eksbuild'} | ${false}
${'v1.11.7.3-eksbuild.1'} | ${false}
`('isCompatible("$input") === $expected', ({ input, expected }) => {
const actual = aws.isCompatible(input);
expect(actual).toBe(expected);
});
});

describe('isCompatible(version,range)', () => {
it('should return true', () => {
expect(
aws.isCompatible('v1.11.7-eksbuild.1', 'v1.2.7-eksbuild.1'),
).toBeTruthy();
});

it('should return false', () => {
expect(
aws.isCompatible('v1.11.7-eksbuild.1', 'v1.11.7-noneksbuild.1'),
).toBeFalsy();
});
});

describe('isGreaterThan(version1, version2)', () => {
it('should return true', () => {
expect(
aws.isGreaterThan('v1.11.7-eksbuild.1', 'v1.11.7-eksbuild.0'),
).toBeTrue();
expect(
aws.isGreaterThan('v1.20.7-eksbuild.2', 'v1.20.7-eksbuild.1'),
).toBeTrue();
expect(
aws.isGreaterThan('v1.22.7-eksbuild.2', 'v1.20.7-eksbuild.1'),
).toBeTrue();
expect(aws.isGreaterThan('v1.22.7-eksbuild.2', 'v1.22.7')).toBeTrue();
expect(aws.isGreaterThan('v1.20.7-eksbuild.1', 'v2.0.0')).toBeTrue();
});

it('should return false', () => {
expect(
aws.isGreaterThan('v1.20.7-eksbuild.1', 'v1.20.7-eksbuild.2'),
).toBeFalsy();
expect(
aws.isGreaterThan('v1.20.7-eksbuild.1', 'v2.0.0-eksbuild.1'),
).toBeFalsy();
});
});

it('getSatisfyingVersion', () => {
expect(
aws.getSatisfyingVersion(['v1.20.7-eksbuild.1'], 'v1.20.7-eksbuild.1'),
).toBe('v1.20.7-eksbuild.1');
expect(
aws.getSatisfyingVersion(
['v1.20.7-eksbuild.1', 'v1.20.7-eksbuild.2', 'v1.20.7-eksbuild.7'],
'v1.20.7-eksbuild.3',
),
).toBeNull();
expect(
aws.getSatisfyingVersion(
['v1.20.7-eksbuild.1', 'v1.20.7-eksbuild.2'],
'v1.20.7-eksbuild.3',
),
).toBeNull();
});
});
60 changes: 60 additions & 0 deletions lib/modules/versioning/aws-eks-addon/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { regEx } from '../../../util/regex';
import { coerceString } from '../../../util/string';
import type { GenericVersion } from '../generic';
import { GenericVersioningApi } from '../generic';
import type { VersioningApi } from '../types';

export const id = 'aws-eks-addon';
export const displayName = 'aws-eks-addon';

export const urls = [];

export const supportsRanges = false;

const versionPattern = regEx(
'^[vV]?(\\d+(?:\\.\\d+)*)(?<metadata>-eksbuild\\.\\d+)?$',
ivankatliarchuk marked this conversation as resolved.
Show resolved Hide resolved
);

class AwsEKSAddonVersioningApi extends GenericVersioningApi {
protected _parse(version: string): GenericVersion | null {
if (!version) {
return null;
}
const matches: RegExpExecArray | null = versionPattern.exec(version);
ivankatliarchuk marked this conversation as resolved.
Show resolved Hide resolved
if (!matches) {
return null;
}
const [, prefix, suffix] = matches;
if (!suffix) {
return null;
}
const release: number[] = prefix.split('.').map(Number);
if (release.length !== 3) {
return null;
}
return { release, suffix };
}

protected override _compare(version: string, other: string): number {
const compare: number = super._compare(version, other);
if (compare !== 0) {
return compare;
}
const parsed1: GenericVersion | null = this._parse(version);
const parsed2: GenericVersion | null = this._parse(other);

const suffix1 = coerceString(parsed1?.suffix);
const suffix2 = coerceString(parsed2?.suffix);
return suffix1.localeCompare(suffix2);
}

override isCompatible(version: string, current: string): boolean {
const parsed1: GenericVersion | null = this._parse(version);
const parsed2: GenericVersion | null = this._parse(current);
ivankatliarchuk marked this conversation as resolved.
Show resolved Hide resolved
return !!(parsed1 && parsed2);
}
}

export const api: VersioningApi = new AwsEKSAddonVersioningApi();

export default api;
18 changes: 18 additions & 0 deletions lib/modules/versioning/aws-eks-addon/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
AWS versioning syntax is used for EKS Addon updates.

It is based off [Semantic Versioning 2.0](https://semver.org) but with a subset of addon `build metadata` syntax.

At the moment every ESK Addon that matches the regex `^[vV]?(\d+(?:\.\d+)*)(-eksbuild\.\d+)?$` is considered a valid "release".

**Key Points about EKS Addon Versioning**

1. Versioning Scheme: Add-ons typically follow a semantic versioning scheme (e.g., Major.Minor.Patch). This helps in understanding the significance of changes between versions:

- `Major`: Indicates significant changes or breaking API changes for plugin version.
- `Minor`: Introduces new features or enhancements for plugin version.
- `Patch`: Includes bug fixes and minor improvements for plugin version.
- `Build Metadata` : It helps differentiate this particular release from others that might have been built independently.

2. Default Versions: When creating a new EKS cluster, AWS often selects a default version for each addon based on the cluster's Kubernetes version and other factors. This default version is usually the most stable and recommended for the specific cluster configuration

3. Build metadata. Example `eksbuild.1`. The `eksbuild.1` part signifies a specific build or release within the `1.19.0` version, likely managed by the EKS build system. It helps differentiate this particular release from others that might have been built independently. The build metadata provides additional context about the specific release, which can be useful for tracking and troubleshooting.
Loading