Skip to content

Commit

Permalink
[backport v2.9.next1] Implement changes for Azure cloud provider for …
Browse files Browse the repository at this point in the history
…RKE2 (#11602)

* [backport] 11578 - Implement changes for Azure cloud provider for RKE2

- Disable Azure for k8s >= 1.30 versions
- Remove k8s versions >= 1.30 and Azure provider if condition is not verified
- Add warning banners
- Enable cloud provider in Edit mode to migrate Azure to External if k8s version is >= 1.27 , < 1.30
- Disable providers except External to migrate Azure
- Clean up code
- Hide warnings if cloud provider is hidden
- Update Basics.test.ts unit tests
- Fix semver versions check
- Update rke2.test.ts

Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>

* [backport] 11611 Fix Unsupported Azure warning message, show it only if Azure is an option

Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>

---------

Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
  • Loading branch information
torchiaf authored Aug 14, 2024
1 parent 7296914 commit 54074d1
Show file tree
Hide file tree
Showing 5 changed files with 382 additions and 19 deletions.
4 changes: 3 additions & 1 deletion shell/assets/translations/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1778,7 +1778,9 @@ cluster:
rke2-k3-reprovisioning: 'Making changes to cluster configuration may result in nodes reprovisioning. For more information see the <a href="{docsBase}/how-to-guides/new-user-guides/launch-kubernetes-with-rancher/rke1-vs-rke2-differences#cluster-api" target="_blank" rel="noopener nofollow">documentation</a>.'
desiredNodeGroupWarning: There are 0 nodes available to run the cluster agent. The cluster will not become active until at least one node is available.
haveArgInfo: Configuration information is not available for the selected Kubernetes version. The options available on this screen will be limited; you may want to use the YAML editor.
cloudProviderAddConfig: 'On Kubernetes 1.27 or greater, the Amazon Cloud Provider requires additional configuration. See <a href="https://ranchermanager.docs.rancher.com/how-to-guides/new-user-guides/kubernetes-clusters-in-rancher-setup/set-up-cloud-providers/amazon" target="_blank" rel="noopener noreferrer nofollow">the documentation</a> for more information.'
cloudProviderAddConfig: 'On Kubernetes 1.27 or greater, the <b>Amazon</b> Cloud Provider requires additional configuration. See <a href="https://ranchermanager.docs.rancher.com/how-to-guides/new-user-guides/kubernetes-clusters-in-rancher-setup/set-up-cloud-providers/amazon" target="_blank" rel="noopener noreferrer nofollow">the documentation</a> for more information.'
cloudProviderUnsupportedAzure: 'On Kubernetes 1.30 or greater, the <b>Azure</b> Cloud Provider has been removed. See <a href="https://ranchermanager.docs.rancher.com/how-to-guides/new-user-guides/kubernetes-clusters-in-rancher-setup/set-up-cloud-providers/azure" target="_blank" rel="noopener noreferrer nofollow">the documentation</a> for more information.'
cloudProviderMigrateAzure: 'On Kubernetes 1.30 or greater, the <b>Azure</b> Cloud Provider has been removed. To upgrade Kubernetes, the cluster should be migrated to External provider first.<br> See <a href="https://ranchermanager.docs.rancher.com/how-to-guides/new-user-guides/kubernetes-clusters-in-rancher-setup/set-up-cloud-providers/azure" target="_blank" rel="noopener noreferrer nofollow">the documentation</a> for more information.'
machinePoolError: |-
{count, plural,
=1 { {pool_name}: The provided value for {fields} was not found in the list of expected values. This can happen with clusters provisioned outside of Rancher or when options for the provider have changed. }
Expand Down
99 changes: 86 additions & 13 deletions shell/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,36 @@ const defaultComputed = {
const mockAgentArgs = { 'cloud-provider-name': { options: [], profile: { options: [{ anything: 'yes' }] } } };
const mockServerArgs = { disable: {}, cni: { options: [] } };

const rke2Versions =
[
{
id: 'v1.25.0+rke2r1', value: 'v1.25.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.24.0+rke2r1', value: 'v1.24.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.23.0+rke2r1', value: 'v1.23.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
}
];
const rke2Versions = [
{
id: 'v1.31.0+rke2r1', value: 'v1.31.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.30.0+rke2r1', value: 'v1.30.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.29.1+rke2r1', value: 'v1.29.1+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.25.0+rke2r1', value: 'v1.25.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.24.0+rke2r1', value: 'v1.24.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.23.0+rke2r1', value: 'v1.23.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
}
];
const k3sVersions = [
{
id: 'v1.31.0+k3s1', value: 'v1.31.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.30.0+k3s1', value: 'v1.30.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.29.1+k3s1', value: 'v1.29.1+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.25.0+k3s1', value: 'v1.25.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
},
Expand Down Expand Up @@ -88,7 +105,7 @@ const newOffValue = { ipv6: { enabled: false } };
const bmOnValue = { bandwidthManager: { enabled: true } };
const bmOffValue = { bandwidthManager: { enabled: false } };

function createBasicsTab(version : string, userChartValues: any) {
function createBasicsTab(version : string, userChartValues: any, options = {}) {
const k8s = mockVersionOptions.find((v) => v.id === version) || mockVersionOptions[0];
const label = 'whatever';
const wrapper = mount(Basics, {
Expand Down Expand Up @@ -122,6 +139,7 @@ function createBasicsTab(version : string, userChartValues: any) {
showCloudProvider: false,
unsupportedCloudProvider: false,
cloudProviderOptions: [{ label: 'Default - RKE2 Embedded', value: '' }],
...options
},
computed: defaultComputed,
mocks: {
Expand Down Expand Up @@ -470,4 +488,59 @@ describe('component: Basics', () => {

expect(JSON.stringify(latest)).toStrictEqual(expected);
});

it.each([
['create', true, true, '%cluster.banner.cloudProviderUnsupportedAzure%'],
['create', false, true, undefined],
['create', true, false, undefined],
['edit', true, true, undefined],
['view', true, true, undefined],
])('should display Unsupported Azure provider warning message', (mode, showCloudProvider, isAzureProviderUnsupported, warningMessage) => {
const wrapper = createBasicsTab('v1.31.0+rke2r1', {}, {
mode,
showCloudProvider,
isAzureProviderUnsupported,
canAzureMigrateOnEdit: true
});

const cloudProviderUnsupportedAzureWarningMessage = wrapper.find('[data-testid="clusterBasics__showCloudProviderUnsupportedAzureWarning"]')?.element?.textContent;

expect(cloudProviderUnsupportedAzureWarningMessage).toBe(warningMessage);
});

it.each([
['edit', true, true, '%cluster.banner.cloudProviderMigrateAzure%'],
['edit', false, true, undefined],
['edit', true, false, undefined],
['create', true, true, undefined],
['view', true, true, undefined],
])('should display Azure Migration warning message', (mode, showCloudProvider, canAzureMigrateOnEdit, warningMessage) => {
const wrapper = createBasicsTab('v1.31.0+rke2r1', {}, {
mode,
showCloudProvider,
canAzureMigrateOnEdit,
isAzureProviderUnsupported: true,
});

const cloudProviderMigrateAzureWarningMessage = wrapper.find('[data-testid="clusterBasics__showCloudProviderMigrateAzureWarning"]')?.element?.textContent;

expect(cloudProviderMigrateAzureWarningMessage).toBe(warningMessage);
});

it.each([
['create', true, false],
['edit', false, true],
['edit', true, false],
['view', true, false],
])('should disable Cloud Provider', (mode, canAzureMigrateOnEdit, disabled) => {
const wrapper = createBasicsTab('v1.31.0+rke2r1', {}, {
mode,
showCloudProvider: true,
canAzureMigrateOnEdit,
});

const cloudProvider = wrapper.find('[data-testid="clusterBasics__cloudProvider"]');

expect(cloudProvider.props().disabled).toBe(disabled);
});
});
209 changes: 209 additions & 0 deletions shell/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const defaultStubs = {
BadgeState: true,
Checkbox: true,
ClusterMembershipEditor: true,
ClusterAppearance: true,
DrainOptions: true,
LabeledInput: true,
Labels: true,
Expand Down Expand Up @@ -53,11 +54,23 @@ const defaultStubs = {
const mockAgentArgs = { 'cloud-provider-name': { options: [], profile: { options: [{ anything: 'yes' }] } } };

const defaultComputed = {
appsOSWarning() {
return false;
},
showForm() {
return true;
},
versionOptions() {
return [
{
id: 'v1.31.0+rke2r1', value: 'v1.31.0+rke2r1', serverArgs: {}, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.30.0+rke2r1', value: 'v1.30.0+rke2r1', serverArgs: {}, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.29.1+rke2r1', value: 'v1.29.1+rke2r1', serverArgs: {}, agentArgs: mockAgentArgs, charts: {}
},
{
id: 'v1.25.0+rke2r1', value: 'v1.25.0+rke2r1', serverArgs: {}, agentArgs: mockAgentArgs, charts: {}
},
Expand Down Expand Up @@ -332,4 +345,200 @@ describe('component: rke2', () => {
expect(agent.element).toBeDefined();
});
});

it.each([
['v1.25.0+k3s1', [{ value: 'aws' }, { value: 'azure' }], 'azure', true],
['v1.31.0+k3s1', [{ value: 'aws' }, { value: 'azure' }], 'harvester', true],
['v1.29.0+k3s1', [{ value: 'aws' }, { value: 'azure' }], 'harvester', false],
['v1.31.0+k3s1', [{ value: 'aws' }], 'azure', false],
])('should set isAzureProviderUnsupported', (k8s, providerOptions, cloudProvider, value) => {
const wrapper = mount(rke2, {
propsData: {
mode: _CREATE,
value: {
spec: {
...defaultSpec,
kubernetesVersion: k8s
},
agentConfig: { 'cloud-provider-name': cloudProvider }
},
provider: 'custom'
},
data: () => ({}),
computed: {
...defaultComputed,
cloudProviderOptions: () => providerOptions
},
mocks: {
...defaultMocks,
$store: { dispatch: () => jest.fn(), getters: defaultGetters },
},
stubs: defaultStubs
});

expect((wrapper.vm as any).isAzureProviderUnsupported).toBe(value);
});

it.each([
['edit', 'v1.31.0+k3s1', 'azure', false],
['edit', 'v1.26.0+k3s1', 'azure', false],
['edit', 'v1.28.0+k3s1', 'harvester', false],
['edit', 'v1.28.0+k3s1', 'azure', true],
['create', 'v1.28.0+k3s1', 'azure', false],
['view', 'v1.28.0+k3s1', 'azure', false],
])('should set canAzureMigrateOnEdit', (mode, k8s, liveCloudProvider, value) => {
const wrapper = mount(rke2, {
propsData: {
mode,
liveValue: {
spec: {
...defaultSpec,
kubernetesVersion: k8s
},
agentConfig: { 'cloud-provider-name': liveCloudProvider }
},
value: {
spec: {
...defaultSpec,
kubernetesVersion: k8s
},
agentConfig: { 'cloud-provider-name': liveCloudProvider }
},
provider: 'custom'
},
data: () => ({}),
computed: defaultComputed,
mocks: {
...defaultMocks,
$store: { dispatch: () => jest.fn(), getters: defaultGetters },
},
stubs: defaultStubs
});

expect((wrapper.vm as any).canAzureMigrateOnEdit).toBe(value);
});

it.each([
['', 'v1.32.0+rke2r1', 'amazon', 'v1.32.0+rke2r1'],
['', 'v1.29.0+rke2r1', 'amazon', 'v1.29.0+rke2r1'],
['', 'v1.29.0+rke2r1', 'azure', 'v1.29.0+rke2r1'],
['not', 'v1.31.0+rke2r1', 'azure', undefined],
])('should %p include version %p if Cloud Provider is %p', async(_, k8s, liveCloudProvider, value) => {
const wrapper = mount(rke2, {
propsData: {
mode: 'create',
value: {
spec: {
...defaultSpec,
kubernetesVersion: k8s
},
agentConfig: { 'cloud-provider-name': liveCloudProvider }
},
provider: 'custom'
},
data: () => ({}),
computed: {
appsOSWarning: () => false,
showForm: () => false,
},
mocks: {
...defaultMocks,
$store: { dispatch: () => jest.fn(), getters: defaultGetters },
},
stubs: defaultStubs
});

wrapper.setData({
rke2Versions: [{
id: k8s,
version: k8s,
serverArgs: true
}]
});

expect((wrapper.vm as any).versionOptions[0]?.value).toBe(value);
});

it.each([
['enable', 'v1.28.0+rke2r1', false],
['disable', 'v1.32.0+rke2r1', true],
])('should %p Azure provider option if version is %p', async(_, k8s, value) => {
const wrapper = mount(rke2, {
propsData: {
mode: 'create',
value: {
spec: {
...defaultSpec,
kubernetesVersion: k8s
},
agentConfig: { 'cloud-provider-name': 'azure' }
},
provider: 'custom'
},
data: () => ({
agentArgs: {
'cloud-provider-name': {
options: [
'azure',
'amazon'
]
}
}
}),
computed: defaultComputed,
mocks: {
...defaultMocks,
$store: { dispatch: () => jest.fn(), getters: defaultGetters },
},
stubs: defaultStubs
});

const azureOption = (wrapper.vm as any).cloudProviderOptions.find((o: any) => o.value === 'azure');

expect(azureOption.disabled).toBe(value);
});

it.each([
['enable', 'azure', 'v1.28.0+rke2r1', false], // azure provider / current
['enable', 'external', 'v1.28.0+rke2r1', false], // external provider
['enable', 'azure', 'v1.26.0+rke2r1', false], // version mismatch
['disable', 'amazon', 'v1.26.0+rke2r1', true],
['enable', '', 'v1.28.0+rke2r1', true], // default provider
])('should %p provider option %p in edit mode if live provider is Azure and 1.27 <= k8s < 1.30', async(_, cloudProvider, k8s, value) => {
const wrapper = mount(rke2, {
propsData: {
mode: 'edit',
value: {
spec: {
...defaultSpec,
kubernetesVersion: k8s
},
agentConfig: { 'cloud-provider-name': 'azure' }
},
provider: 'custom'
},
data: () => ({
canAzureMigrateOnEdit: true,
agentArgs: {
'cloud-provider-name': {
options: [
'azure',
'amazon',
'external'
]
}
}
}),
computed: defaultComputed,
mocks: {
...defaultMocks,
$store: { dispatch: () => jest.fn(), getters: defaultGetters },
},
stubs: defaultStubs
});

const azureOption = (wrapper.vm as any).cloudProviderOptions.find((o: any) => o.value === cloudProvider);

expect(azureOption.disabled).toBe(value);
});
});
Loading

0 comments on commit 54074d1

Please sign in to comment.