RKE1 Clusters unsupported (#14226)

* Make RKE1 Unsupported

* Fix for unit tests

* Update a11y test for removed RKE1 toggle switch

* Fix missing import

* Remove RKE templates and related tests

* Fix lint and tidy up

* Removed unused code

* Updates e2e tests

* Tidy up e2e tests

* Fix lint

* Prevent edit of RKE1 cluster

* Remove RKE1 settings

* Fix lint with removed settings

* Remove e2e test for removed setting

* Remove unused e2e po

* Remove toggle switch from a11y test
This commit is contained in:
Neil MacDougall 2025-05-29 13:07:00 +01:00 committed by GitHub
parent 17233d82f8
commit c0ea22f63b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 99 additions and 2053 deletions

View File

@ -2,171 +2,49 @@ export const providersList = [
{
clusterProviderQueryParam: 'amazoneks',
label: 'Amazon EKS',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke2'
},
]
},
{
clusterProviderQueryParam: 'azureaks',
label: 'Azure AKS',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke2'
},
]
},
{
clusterProviderQueryParam: 'googlegke',
label: 'Google GKE',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke2'
},
]
},
{
clusterProviderQueryParam: 'amazonec2',
label: 'Amazon EC2',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke1'
},
]
},
{
clusterProviderQueryParam: 'azure',
label: 'Azure',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke1'
},
]
},
{
clusterProviderQueryParam: 'digitalocean',
label: 'DigitalOcean',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke1'
},
]
},
{
clusterProviderQueryParam: 'azureaks',
label: 'Azure AKS',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke2'
},
]
},
{
clusterProviderQueryParam: 'harvester',
label: 'Harvester',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke1'
},
]
},
{
clusterProviderQueryParam: 'linode',
label: 'Linode',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke1'
},
]
},
{
clusterProviderQueryParam: 'azure',
label: 'Azure',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke1'
},
]
},
{
clusterProviderQueryParam: 'vmwarevsphere',
label: 'VMware vSphere',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2',
label: 'VMware vSphere',
},
{
rkeType: 'rke1',
loads: 'rke1',
label: 'vSphere',
},
]
},
{
clusterProviderQueryParam: 'custom',
label: 'Custom',
conditions: [
{
rkeType: 'rke2',
loads: 'rke2'
},
{
rkeType: 'rke1',
loads: 'rke1'
},
]
},
];

View File

@ -1,16 +0,0 @@
import EmberComponentPo from '@/cypress/e2e/po/components/ember/ember-component.po';
import EmberInputPo from '@/cypress/e2e/po/components/ember/ember-input.po';
export default class EmberFormRkeTemplatesPo extends EmberComponentPo {
templateDetails(index): EmberInputPo {
return new EmberInputPo(`.horizontal-form .row:nth-of-type(1) input:nth-child(${ index })`);
}
create() {
return this.self().contains('[data-testid="save-cancel-rke1"] button', 'Create').click();
}
save() {
return this.self().contains('[data-testid="save-cancel-rke1"] button', 'Save').click();
}
}

View File

@ -1,11 +0,0 @@
import ClusterManagerDetailPagePo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail.po';
import ResourceDetailPo from '@/cypress/e2e/po/edit/resource-detail.po';
/**
* Detail page for an RKE1 amazon EC2 cluster
*/
export default class ClusterManagerDetailRke1AmazonEc2PagePo extends ClusterManagerDetailPagePo {
resourceDetail() {
return new ResourceDetailPo(this.self());
}
}

View File

@ -1,11 +0,0 @@
import ClusterManagerDetailPagePo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail.po';
import ResourceDetailPo from '@/cypress/e2e/po/edit/resource-detail.po';
/**
* Detail page for an RKE1 azure cluster
*/
export default class ClusterManagerDetailRke1AzurePagePo extends ClusterManagerDetailPagePo {
resourceDetail() {
return new ResourceDetailPo(this.self());
}
}

View File

@ -1,8 +0,0 @@
import ClusterManagerDetailPagePo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail.po';
/**
* Detail page for an RKE1 custom cluster
*/
export default class ClusterManagerDetailRke1CustomPagePo extends ClusterManagerDetailPagePo {
}

View File

@ -1,81 +0,0 @@
import PagePo from '@/cypress/e2e/po/pages/page.po';
import ClusterManagerCreatePagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create.po';
import EmberInputPo from '@/cypress/e2e/po/components/ember/ember-input.po';
import ClusterManagerCreateRKE1PagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create-rke1.po';
import EmberAccordionPo from '@/cypress/e2e/po/components/ember/ember-accordion.po';
import EmberFormMembersPo from '@/cypress/e2e/po/components/ember/ember-form-members.po';
import EmberCheckboxInputPo from '@/cypress/e2e/po/components/ember/ember-checkbox-input.po';
import EmberSelectPo from '@/cypress/e2e/po/components/ember/ember-select.po';
import EmberTextareaPo from '@/cypress/e2e/po/components/ember/ember-textarea.po';
import EmberModalAddNodeTemplateAwsPo from '@/cypress/e2e/po/components/ember/ember-modal-add-node-template-aws.po';
import EmberFormNodePoolsPo from '@/cypress/e2e/po/components/ember/ember-form-node-pools.po';
import EmberKubernetesOptionsPo from '@/cypress/e2e/po/components/ember/ember-kubernetes-options.po';
/**
* Create page for an RKE1 amazonec2 cluster
*/
export default class ClusterManagerCreateRke1Amazonec2PagePo extends ClusterManagerCreateRKE1PagePo {
static url(clusterId: string) {
return `${ ClusterManagerCreatePagePo.url(clusterId) }/create?type=amazonec2`;
}
static goTo(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> {
return PagePo.goTo(ClusterManagerCreateRke1Amazonec2PagePo.url(clusterId));
}
goToAmazonec2ClusterCreation(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> {
return PagePo.goTo(`${ ClusterManagerCreatePagePo.url(clusterId) }?type=amazonec2`);
}
clusterName(): EmberInputPo {
return new EmberInputPo('[data-testid="form-name-description__name"]');
}
addDescriptionButtonClick() {
cy.iFrame().find('.pull-right.text-small a').contains('Add a Description').click();
}
clusterDescription():EmberTextareaPo {
return new EmberTextareaPo('.ember-text-area.description.ember-view');
}
nodePoolTable(): EmberFormNodePoolsPo {
return new EmberFormNodePoolsPo('div.ember-view');
}
kubernetesOptions(): EmberKubernetesOptionsPo {
return new EmberKubernetesOptionsPo('div.ember-view');
}
addNodeTemplate() {
return cy.iFrame().find('button').contains('Add Node Template').click();
}
addNodeTemplateForm(): EmberModalAddNodeTemplateAwsPo {
return new EmberModalAddNodeTemplateAwsPo();
}
memberRoles(): EmberAccordionPo {
return new EmberAccordionPo('cru-cluster__members');
}
memberRolesFormMembers(): EmberFormMembersPo {
return new EmberFormMembersPo('[data-testid="cru-cluster__members__form"]') ;
}
clusterTemplateCheckbox(): EmberCheckboxInputPo {
return new EmberCheckboxInputPo('.cluster-template-select');
}
nodeTemplateDropdown(): EmberSelectPo {
return new EmberSelectPo('.main-row .new-select > select');
}
rkeTemplateAndRevisionDropdown(): EmberSelectPo {
return new EmberSelectPo('.new-select > select');
}
selectedOption(): EmberSelectPo {
return new EmberSelectPo('.new-select > select option:selected');
}
}

View File

@ -1,72 +0,0 @@
import PagePo from '@/cypress/e2e/po/pages/page.po';
import ClusterManagerCreatePagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create.po';
import EmberInputPo from '@/cypress/e2e/po/components/ember/ember-input.po';
import ClusterManagerCreateRKE1PagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create-rke1.po';
import EmberAccordionPo from '@/cypress/e2e/po/components/ember/ember-accordion.po';
import EmberFormMembersPo from '@/cypress/e2e/po/components/ember/ember-form-members.po';
import EmberCheckboxInputPo from '@/cypress/e2e/po/components/ember/ember-checkbox-input.po';
import EmberSelectPo from '@/cypress/e2e/po/components/ember/ember-select.po';
import EmberFormNodePoolsPo from '@/cypress/e2e/po/components/ember/ember-form-node-pools.po';
import EmberKubernetesOptionsPo from '@/cypress/e2e/po/components/ember/ember-kubernetes-options.po';
import EmberModalAddNodeTemplateAzurePo from '@/cypress/e2e/po/components/ember/ember-modal-add-node-template-azure.po';
/**
* Create page for an RKE1 azure cluster
*/
export default class ClusterManagerCreateRke1AzurePagePo extends ClusterManagerCreateRKE1PagePo {
static url(clusterId: string) {
return `${ ClusterManagerCreatePagePo.url(clusterId) }/create?type=amazonec2`;
}
static goTo(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> {
return PagePo.goTo(ClusterManagerCreateRke1AzurePagePo.url(clusterId));
}
goToAmazonec2ClusterCreation(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> {
return PagePo.goTo(`${ ClusterManagerCreatePagePo.url(clusterId) }?type=amazonec2`);
}
clusterName(): EmberInputPo {
return new EmberInputPo('[data-testid="form-name-description__name"]');
}
nodePoolTable(): EmberFormNodePoolsPo {
return new EmberFormNodePoolsPo('div.ember-view');
}
kubernetesOptions(): EmberKubernetesOptionsPo {
return new EmberKubernetesOptionsPo('div.ember-view');
}
addNodeTemplate() {
return cy.iFrame().find('button').contains('Add Node Template').click();
}
addNodeTemplateForm(): EmberModalAddNodeTemplateAzurePo {
return new EmberModalAddNodeTemplateAzurePo();
}
memberRoles(): EmberAccordionPo {
return new EmberAccordionPo('cru-cluster__members');
}
memberRolesFormMembers(): EmberFormMembersPo {
return new EmberFormMembersPo('[data-testid="cru-cluster__members__form"]') ;
}
clusterTemplateCheckbox(): EmberCheckboxInputPo {
return new EmberCheckboxInputPo('.cluster-template-select');
}
nodeTemplateDropdown(): EmberSelectPo {
return new EmberSelectPo('.main-row .new-select > select');
}
rkeTemplateAndRevisionDropdown(): EmberSelectPo {
return new EmberSelectPo('.new-select > select');
}
selectedOption(): EmberSelectPo {
return new EmberSelectPo('.new-select > select option:selected');
}
}

View File

@ -1,73 +0,0 @@
import PagePo from '@/cypress/e2e/po/pages/page.po';
import ClusterManagerCreatePagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create.po';
import EmberInputPo from '@/cypress/e2e/po/components/ember/ember-input.po';
import ClusterManagerCreateRKE1PagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create-rke1.po';
import EmberAccordionPo from '@/cypress/e2e/po/components/ember/ember-accordion.po';
import EmberFormMembersPo from '@/cypress/e2e/po/components/ember/ember-form-members.po';
import EmberCheckboxInputPo from '@/cypress/e2e/po/components/ember/ember-checkbox-input.po';
import EmberSelectPo from '@/cypress/e2e/po/components/ember/ember-select.po';
/**
* Create page for an RKE1 custom cluster
*/
export default class ClusterManagerCreateRke1CustomPagePo extends ClusterManagerCreateRKE1PagePo {
static url(clusterId: string) {
return `${ ClusterManagerCreateRKE1PagePo.url(clusterId) }/create?type=custom`;
}
static goTo(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> {
return PagePo.goTo(ClusterManagerCreateRke1CustomPagePo.url(clusterId));
}
goToCustomClusterCreation(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> {
return PagePo.goTo(`${ ClusterManagerCreatePagePo.url(clusterId) }?type=custom`);
}
// Create/Edit Page
clusterName(): EmberInputPo {
return new EmberInputPo('[data-testid="form-name-description__name"]');
}
memberRoles(): EmberAccordionPo {
return new EmberAccordionPo('cru-cluster__members');
}
memberRolesFormMembers(): EmberFormMembersPo {
return new EmberFormMembersPo('[data-testid="cru-cluster__members__form"]') ;
}
clusterTemplateCheckbox(): EmberCheckboxInputPo {
return new EmberCheckboxInputPo('.cluster-template-select');
}
rkeTemplateAndRevisionDropdown(): EmberSelectPo {
return new EmberSelectPo('.new-select > select');
}
selectedOption(): EmberSelectPo {
return new EmberSelectPo('.new-select > select option:selected');
}
// Roles Page
nodeCommand(): EmberAccordionPo {
return new EmberAccordionPo('cluster-driver__role');
}
etcdRole() {
return this.nodeCommand().content().find('div.row > div:nth-of-type(1) > label > input');
}
cpRole() {
return this.nodeCommand().content().find('div.row > div:nth-of-type(2) > label > input');
}
workerRole() {
return this.nodeCommand().content().find('div.row > div:nth-of-type(3) > label > input');
}
registrationCommand() {
return this.nodeCommand().content().find('#registration-command');
}
}

View File

@ -1,50 +0,0 @@
import PagePo from '@/cypress/e2e/po/pages/page.po';
import ClusterManagerCreatePagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create.po';
import NameNsDescription from '@/cypress/e2e/po/components/name-ns-description.po';
import { CypressChainable } from '@/cypress/e2e/po/po.types';
/**
* RKE1 flavour of ClusterManagerCreatePagePo
*
* This structure is bit tricky. The page covers selecting an RKE and cluster type AND the rke specific create/edit page
*
* The rke create/edit page in this case is ember
*/
export default abstract class ClusterManagerCreateRKE1PagePo extends ClusterManagerCreatePagePo {
static url(clusterId: string) {
return `${ ClusterManagerCreatePagePo.url(clusterId) }/create`;
}
static goTo(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> {
return PagePo.goTo(ClusterManagerCreateRKE1PagePo.url(clusterId));
}
// Form
nameNsDescription(): NameNsDescription {
throw new Error('RKE2 only');
}
create(): CypressChainable {
throw new Error('RKE2 only');
}
save(): CypressChainable {
throw new Error('RKE2 only');
}
createRKE1(): CypressChainable {
return cy.iFrame().find('[data-testid="save-cancel-rke1"] button').contains('Create').click();
}
saveRKE1(): CypressChainable {
return cy.iFrame().find('[data-testid="save-cancel-rke1"] button').contains('Save').click();
}
next() {
return cy.iFrame().find('button').contains('Next').click();
}
done() {
return cy.iFrame().find('[data-testid="driver-rke__done"]').click();
}
}

View File

@ -1,4 +1,3 @@
import ToggleSwitchPo from '@/cypress/e2e/po/components/toggle-switch.po';
import ClusterManagerCreateImportPagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/cluster-create-import.po';
import BannersPo from '@/cypress/e2e/po/components/banners.po';
@ -22,22 +21,10 @@ export default class ClusterManagerCreatePagePo extends ClusterManagerCreateImpo
super(ClusterManagerCreatePagePo.createPath(clusterId, queryParams));
}
rke1PageTitle(): Cypress.Chainable<string> {
return cy.iFrame().find('.header h1').invoke('text');
}
rke2PageTitle(): Cypress.Chainable<string> {
return this.self().find('.primaryheader h1').invoke('text');
}
rkeToggle() {
return new ToggleSwitchPo('.toggle-container', this.self());
}
rkeToggleExistance(assertion: string) {
this.self().find('.toggle-container').should(assertion);
}
gridElementExistanceByName(name: string, assertion: string) {
return this.self().contains('.grid .name', name, { timeout: 10000 }).should(assertion);
}
@ -66,11 +53,7 @@ export default class ClusterManagerCreatePagePo extends ClusterManagerCreateImpo
return this.self().get('.checkbox-label').contains('Insecure:');
}
customClusterRegistrationCmd(cmd: string, rkeType?: number) {
if (rkeType === 1) {
return `ssh -i custom_node_rke1.key -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" root@${ Cypress.env('customNodeIpRke1') } \"nohup ${ cmd }\"`;
}
customClusterRegistrationCmd(cmd: string) {
return `ssh -i custom_node.key -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" root@${ Cypress.env('customNodeIp') } \"nohup ${ cmd }\"`;
}

View File

@ -1,39 +0,0 @@
import PagePo from '@/cypress/e2e/po/pages/page.po';
import EmberSortableTablePo from '@/cypress/e2e/po/components/ember/ember-sortable-table.po';
import ProductNavPo from '@/cypress/e2e/po/side-bars/product-side-nav.po';
import BurgerMenuPo from '@/cypress/e2e/po/side-bars/burger-side-menu.po';
import EmberModalAddNodeTemplateAwsPo from '@/cypress/e2e/po/components/ember/ember-modal-add-node-template-aws.po';
export default class NodeTemplatesPagePo extends PagePo {
private static createPath(clusterId: string) {
return `/c/${ clusterId }/manager/pages/node-templates`;
}
static goTo(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> {
return super.goTo(NodeTemplatesPagePo.createPath(clusterId));
}
constructor(clusterId = '_') {
super(NodeTemplatesPagePo.createPath(clusterId));
}
static navTo() {
const sideNav = new ProductNavPo();
BurgerMenuPo.burgerMenuNavToMenubyLabel('Cluster Management');
sideNav.groups().contains('RKE1 Configuration').click();
sideNav.navToSideMenuEntryByLabel('Node Templates');
}
addNodeTemplateModal(): EmberModalAddNodeTemplateAwsPo {
return new EmberModalAddNodeTemplateAwsPo();
}
list(): EmberSortableTablePo {
return new EmberSortableTablePo('.sortable-table');
}
addTemplate() {
return cy.iFrame().contains('.right-buttons .btn', 'Add Template');
}
}

View File

@ -1,48 +0,0 @@
import PagePo from '@/cypress/e2e/po/pages/page.po';
import EmberSortableTablePo from '@/cypress/e2e/po/components/ember/ember-sortable-table.po';
import EmberSelectPo from '@/cypress/e2e/po/components/ember/ember-select.po';
import EmberFormRkeTemplatesPo from '@/cypress/e2e/po/components/ember/ember-form-rke-templates.po';
import ProductNavPo from '@/cypress/e2e/po/side-bars/product-side-nav.po';
import BurgerMenuPo from '@/cypress/e2e/po/side-bars/burger-side-menu.po';
export default class RkeTemplatesPagePo extends PagePo {
private static createPath(clusterId: string) {
return `/c/${ clusterId }/manager/pages/rke-templates`;
}
static goTo(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> {
return super.goTo(RkeTemplatesPagePo.createPath(clusterId));
}
constructor(clusterId = '_') {
super(RkeTemplatesPagePo.createPath(clusterId));
}
static navTo() {
const sideNav = new ProductNavPo();
BurgerMenuPo.burgerMenuNavToMenubyLabel('Cluster Management');
sideNav.groups().contains('RKE1 Configuration').click();
sideNav.navToSideMenuEntryByLabel('RKE Templates');
}
addTemplate() {
return cy.iFrame().contains('.right-buttons .btn', 'Add Template');
}
groupRow(): EmberSortableTablePo {
return new EmberSortableTablePo('table.sortable-table .group-row');
}
mainRow(): EmberSortableTablePo {
return new EmberSortableTablePo('table.sortable-table .main-row');
}
actionMenu(): EmberSelectPo {
return new EmberSelectPo('.ember-basic-dropdown-content');
}
form(): EmberFormRkeTemplatesPo {
return new EmberFormRkeTemplatesPo('form.horizontal-form');
}
}

View File

@ -515,17 +515,11 @@ describe('Shell a11y testing', { tags: ['@adminUser', '@accessibility'] }, () =>
createClusterPage.waitForPage();
loadingPo.checkNotExists();
createClusterPage.rkeToggle().checkVisible();
cy.injectAxe();
cy.checkPageAccessibility();
cy.injectAxe();
// check rke toggle
createClusterPage.rkeToggle().get('.switch').then((el) => {
cy.checkElementAccessibility(el);
});
});
it('Cluster - Create Digital Ocean Cloud Credential', () => {
@ -534,7 +528,6 @@ describe('Shell a11y testing', { tags: ['@adminUser', '@accessibility'] }, () =>
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
clusterList.createCluster();
createClusterPage.rkeToggle().set('RKE2/K3s');
createClusterPage.selectCreate(2);
loadingPo.checkNotExists();
createClusterPage.rke2PageTitle().should('include', 'Create DigitalOcean');

View File

@ -280,42 +280,6 @@ describe('Settings', { testIsolation: 'off' }, () => {
.should('eq', rancherLogoWidth);
});
it('can update cluster-template-enforcement', { tags: ['@globalSettings', '@adminUser'] }, () => {
// Update setting
SettingsPagePo.navTo();
settingsPage.editSettingsByLabel('cluster-template-enforcement');
const settingsEdit = settingsPage.editSettings('local', 'cluster-template-enforcement');
settingsEdit.waitForPage();
settingsEdit.title().contains('Setting: cluster-template-enforcement').should('be.visible');
settingsEdit.settingsRadioBtn().set(0);
settingsEdit.saveAndWait('cluster-template-enforcement').then(({ request, response }) => {
expect(response?.statusCode).to.eq(200);
expect(request.body).to.have.property('value', settings['cluster-template-enforcement'].new);
expect(response?.body).to.have.property('value', settings['cluster-template-enforcement'].new);
});
settingsPage.waitForPage();
settingsPage.settingsValue('cluster-template-enforcement').contains(settings['cluster-template-enforcement'].new);
// Reset
SettingsPagePo.navTo();
settingsPage.waitForPage();
settingsPage.editSettingsByLabel('cluster-template-enforcement');
settingsEdit.waitForPage();
settingsEdit.title().contains('Setting: cluster-template-enforcement').should('be.visible');
settingsEdit.useDefaultButton().click();
settingsEdit.saveAndWait('cluster-template-enforcement').then(({ request, response }) => {
expect(response?.statusCode).to.eq(200);
expect(request.body).to.have.property('value', settings['cluster-template-enforcement'].original);
expect(response?.body).to.have.property('value', settings['cluster-template-enforcement'].original);
});
settingsPage.waitForPage();
settingsPage.settingsValue('cluster-template-enforcement').contains(settings['cluster-template-enforcement'].original);
});
it('can update hide-local-cluster', { tags: ['@globalSettings', '@adminUser'] }, () => {
// Update setting
SettingsPagePo.navTo();
@ -407,7 +371,6 @@ describe('Settings', { testIsolation: 'off' }, () => {
clusterList.createCluster();
createRKE2ClusterPage.waitForPage();
createRKE2ClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2ClusterPage.selectCustom(0);
createRKE2ClusterPage.clusterConfigurationTabs().clickTabWithSelector('[data-testid="btn-rke2-calico"]');

View File

@ -49,7 +49,6 @@ describe('RKE2 Cilium CNI', () => {
clusterList.checkIsCurrentPage();
clusterList.createCluster();
createRKE2ClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2ClusterPage.goToDigitalOceanCreation('_');
createRKE2ClusterPage.waitForPage();
createRKE2ClusterPage.nameNsDescription().name().set(clusterName);
@ -105,7 +104,6 @@ describe('RKE2 Cilium CNI', () => {
clusterList.checkIsCurrentPage();
clusterList.createCluster();
createRKE2ClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2ClusterPage.goToDigitalOceanCreation('_');
createRKE2ClusterPage.waitForPage();
createRKE2ClusterPage.nameNsDescription().name().set(clusterName);

View File

@ -209,7 +209,6 @@ describe('Cloud Credential', { testIsolation: 'off' }, () => {
clusterList.checkIsCurrentPage();
clusterList.createCluster();
createRKE2AzureClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2AzureClusterPage.selectCreate(1);
createRKE2AzureClusterPage.rke2PageTitle().should('include', 'Create Azure');
createRKE2AzureClusterPage.waitForPage('type=azure&rkeType=rke2');

View File

@ -39,7 +39,6 @@ describe('Cluster List', { tags: ['@manager', '@adminUser'] }, () => {
clusterList.createCluster();
createRKE2ClusterPage.waitForPage();
createRKE2ClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2ClusterPage.selectCustom(0);
createRKE2ClusterPage.title().then((title) => {
expect(title.replace(/\s+/g, ' ')).to.contain('Cluster: Create Custom');

View File

@ -5,7 +5,6 @@ import { providersList } from '@/cypress/e2e/blueprints/manager/clusterProviderU
import ClusterManagerListPagePo from '@/cypress/e2e/po/pages/cluster-manager/cluster-manager-list.po';
import ClusterDashboardPagePo from '@/cypress/e2e/po/pages/explorer/cluster-dashboard.po';
import ClusterManagerDetailRke2CustomPagePo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail-rke2-custom.po';
import ClusterManagerDetailSnapshotsPo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail-snapshots.po';
import ClusterManagerDetailImportedGenericPagePo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail-import-generic.po';
import ClusterManagerCreateRke2CustomPagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create-rke2-custom.po';
import ClusterManagerEditRke2CustomPagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/edit/cluster-edit-rke2-custom.po';
@ -15,13 +14,10 @@ import ClusterManagerNamespacePagePo from '@/cypress/e2e/po/pages/cluster-manage
import PromptRemove from '@/cypress/e2e/po/prompts/promptRemove.po';
import * as path from 'path';
import * as jsyaml from 'js-yaml';
import ClusterManagerCreateRke1CustomPagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create-rke1-custom.po';
import Shell from '@/cypress/e2e/po/components/shell.po';
import BurgerMenuPo from '@/cypress/e2e/po/side-bars/burger-side-menu.po';
import { snapshot } from '@/cypress/e2e/blueprints/manager/cluster-snapshots';
import HomePagePo from '@/cypress/e2e/po/pages/home.po';
import { nodeDriveResponse } from '@/cypress/e2e/tests/pages/manager/mock-responses';
import ProductNavPo from '@/cypress/e2e/po/side-bars/product-side-nav.po';
import TabbedPo from '@/cypress/e2e/po/components/tabbed.po';
import LoadingPo from '@/cypress/e2e/po/components/loading.po';
import { EXTRA_LONG_TIMEOUT_OPT, MEDIUM_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts';
@ -38,7 +34,6 @@ const namespace = 'fleet-default';
const type = 'provisioning.cattle.io.cluster';
const importType = 'cluster';
const clusterNamePartial = `${ runPrefix }-create`;
const rke1CustomName = `${ clusterNamePartial }-rke1-custom`;
const rke2CustomName = `${ clusterNamePartial }-rke2-custom`;
const importGenericName = `${ clusterNamePartial }-import-generic`;
let reenableAKS = false;
@ -54,46 +49,6 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
cy.login();
});
// testing https://github.com/rancher/dashboard/issues/9823
it('Toggling the feature flag "rke1-ui" to false should not display RKE toggle on cluster creation screen and hide RKE1 resources from nav', () => {
cy.fetchRevision().then((revision) => {
cy.intercept('GET', 'v1/management.cattle.io.features?*', {
type: 'collection',
resourceType: 'management.cattle.io.feature',
revision,
data: [
{
id: 'rke1-ui',
type: 'management.cattle.io.feature',
kind: 'Feature',
spec: { value: false },
status: {
default: true,
description: 'Disable RKE1 provisioning',
dynamic: false,
lockedValue: false
}
}
]
}).as('featuresGet');
const clusterCreate = new ClusterManagerCreatePagePo();
clusterCreate.goTo();
clusterCreate.waitForPage();
// seems like the waitForPage does await for full DOM render, so let's wait for a simple assertion
// like "gridElementExists" to make sure we aren't creating a fake assertion with the toggle
clusterCreate.gridElementExistanceByName('Linode', 'exist');
clusterCreate.rkeToggleExistance('not.exist');
const sideNav = new ProductNavPo();
// check that the nav group isn't visible anymore
sideNav.navToSideMenuGroupByLabelExistence('RKE1 Configuration', 'not.exist');
});
});
it('deactivating a kontainer driver should hide its card from the cluster creation page', () => {
cy.intercept('GET', '/v3/kontainerdrivers').as('getKontainerDrivers');
cy.intercept('POST', 'v3/kontainerDrivers/azurekubernetesservice?action=deactivate').as('deactivateDriver');
@ -167,7 +122,6 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
clusterCreatePage.waitForPage();
cy.wait('@kontainerDrivers');
clusterCreatePage.rkeToggleExistance('exist');
clusterCreatePage.gridElementExistanceByName('Azure AKS', 'not.exist');
clusterCreatePage.gridElementGroupTitles().should('have.length', 2);
@ -178,21 +132,17 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
clusterCreatePage.gridElementGroupTitles().eq(1).should('contain.text', 'Use existing nodes');
});
describe('All providers', () => {
describe('RKE2 providers', () => {
providersList.forEach((prov) => {
prov.conditions.forEach((condition) => {
it(`should be able to access cluster creation for provider ${ prov.label } with rke type ${ condition.rkeType } via url`, () => {
const clusterCreate = new ClusterManagerCreatePagePo();
it(`should be able to access RKE2 cluster creation for provider ${ prov.label } via url`, () => {
const clusterCreate = new ClusterManagerCreatePagePo();
clusterCreate.goTo(`type=${ prov.clusterProviderQueryParam }&rkeType=${ condition.rkeType }`);
clusterCreate.waitForPage();
clusterCreate.goTo(`type=${ prov.clusterProviderQueryParam }&rkeType=rke2`);
clusterCreate.waitForPage();
loadingPo.checkNotExists();
const fnName = condition.loads === 'rke1' ? 'rke1PageTitle' : 'rke2PageTitle';
const evaluation = condition.loads === 'rke1' ? `Add Cluster - ${ condition.label ? condition.label : prov.label }` : `Create ${ condition.label ? condition.label : prov.label }`;
loadingPo.checkNotExists();
clusterCreate[fnName]().should('contain', evaluation);
});
clusterCreate.rke2PageTitle().should('contain', `Create ${ prov.label }`);
});
});
});
@ -232,16 +182,8 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
createRKE2ClusterPage.waitForPage();
// Test for https://github.com/rancher/dashboard/issues/9823 (default is feature flag 'rke1-ui' = true)
createRKE2ClusterPage.rkeToggleExistance('exist');
const sideNav = new ProductNavPo();
sideNav.navToSideMenuGroupByLabelExistence('RKE1 Configuration', 'exist');
// EO test for https://github.com/rancher/dashboard/issues/9823
createRKE2ClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2ClusterPage.selectCustom(0);
createRKE2ClusterPage.nameNsDescription().name().set(rke2CustomName);
@ -345,8 +287,6 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
createRKE2ClusterPage.waitForPage();
createRKE2ClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2ClusterPage.selectCustom(0);
createRKE2ClusterPage.nameNsDescription().name().set('abc');
@ -426,167 +366,6 @@ describe('Cluster Manager', { testIsolation: 'off', tags: ['@manager', '@adminUs
});
});
});
const createClusterRKE1Page = new ClusterManagerCreateRke1CustomPagePo();
describe('RKE1 Custom', { tags: ['@jenkins'] }, () => {
it('can create new cluster', () => {
clusterList.goTo();
clusterList.checkIsCurrentPage();
clusterList.createCluster();
createClusterRKE1Page.waitForPage();
createClusterRKE1Page.rkeToggle().set('RKE1');
createClusterRKE1Page.selectCustom(0);
loadingPo.checkNotExists(MEDIUM_TIMEOUT_OPT);
createClusterRKE1Page.clusterName().set(rke1CustomName);
// Test Custom Cluster Roles -------------------------
const roles = [{
label: 'Create Projects',
roleTemplateId: 'projects-create'
}, {
label: 'Manage Cluster Catalogs',
roleTemplateId: 'clustercatalogs-manage'
}, {
label: 'Manage Navlinks',
roleTemplateId: 'navlinks-manage'
}, {
label: 'Manage Storage',
roleTemplateId: 'storage-manage'
}];
createClusterRKE1Page.memberRoles().checkExists();
createClusterRKE1Page.memberRoles().expand();
createClusterRKE1Page.memberRolesFormMembers().addMember();
createClusterRKE1Page.memberRolesFormMembers().setNewMemberWithCustomRoles('admin', roles);
cy.intercept('POST', '/v3/clusterroletemplatebinding').as('binding');
// -------------------------
createClusterRKE1Page.next();
let found = 0;
for (let i = 0; i < roles.length; i++) {
cy.wait('@binding').then((res: any) => {
if (roles.find((r) => r.roleTemplateId === res.response.body.roleTemplateId)) {
found++;
}
if (i === roles.length - 1) {
expect(roles.length).equal(found);
}
});
}
createClusterRKE1Page.nodeCommand().checkExists();
createClusterRKE1Page.etcdRole().click();
createClusterRKE1Page.cpRole().click();
createClusterRKE1Page.registrationCommand().then(($value) => {
const registrationCommand = $value.text().replace('sudo', '');
cy.log(registrationCommand);
cy.exec(`echo ${ Cypress.env('customNodeKeyRke1') } | base64 -d > custom_node_rke1.key && chmod 600 custom_node_rke1.key`).then((result) => {
cy.log('Creating the custom_node_rke1.key');
cy.log(result.stderr);
cy.log(result.stdout);
expect(result.code).to.eq(0);
});
cy.exec(`head custom_node_rke1.key`).then((result) => {
cy.log(result.stdout);
cy.log(result.stderr);
expect(result.code).to.eq(0);
});
cy.exec(createClusterRKE1Page.customClusterRegistrationCmd(registrationCommand, 1), { failOnNonZeroExit: false, timeout: 120000 }).then((result) => {
cy.log(result.stderr);
cy.log(result.stdout);
});
});
createClusterRKE1Page.done();
clusterList.waitForPage();
clusterList.sortableTable().rowElementWithName(rke1CustomName).should('exist');
clusterList.list().state(rke1CustomName).should('contain.text', 'Provisioning');
clusterList.list().state(rke1CustomName).contains('Active', { timeout: 500000 }); // super long timeout needed for cluster provisioning to complete
});
// it.skip('can create new snapshots', () => {
// });
it('can show snapshots list', () => {
clusterList.goToClusterListAndGetClusterDetails(rke1CustomName).then((cluster) => {
const snapshots = new ClusterManagerDetailSnapshotsPo(undefined, cluster.id);
// We want to show 2 elements in the snapshots tab
const snapshotId1 = 'ml-mkhz4';
const snapshotId2 = 'ml-mkhz5';
// Intercept first request with limit 1, this should triggers depaginate mechanism and make a second request to fetch second snapshot.
cy.intercept({
method: 'GET',
path: '/v3/etcdbackups',
}, (req) => {
req.query = { limit: '1' };
req.continue((res) => {
res.body.pagination = {
first: `${ req.url }&marker=${ cluster.id }%3A${ cluster.id }-${ snapshotId1 }`,
next: `${ req.url }&marker=${ cluster.id }%3A${ cluster.id }-${ snapshotId2 }`,
last: `${ req.url }&marker=${ cluster.id }%3A${ cluster.id }-${ snapshotId2 }`,
limit: 1,
total: 2,
partial: true
};
res.body.data = [
snapshot(cluster.id, snapshotId1),
];
});
});
// Intercept second request
cy.intercept({
method: 'GET',
path: `/v3/etcdbackups?limit=1&marker=${ cluster.id }%3A${ cluster.id }-${ snapshotId2 }`,
}, (req) => {
req.continue((res) => {
res.body.data = [
snapshot(cluster.id, snapshotId2),
];
});
});
snapshots.goTo();
snapshots.waitForPage();
snapshots.list().resourceTable().sortableTable().groupElementWithName('Location')
.should('have.length', 1); // 1 group row
snapshots.list().resourceTable().sortableTable().rowElements()
.should('have.length.gte', 2); // 2 main rows
});
});
// it.skip('can delete snapshots', () => {
// });
it('can delete cluster', () => {
clusterList.goTo();
clusterList.list().actionMenu(rke1CustomName).getMenuItem('Delete').click();
const promptRemove = new PromptRemove();
promptRemove.confirm(rke1CustomName);
promptRemove.remove();
clusterList.sortableTable().rowElementWithName(rke1CustomName, MEDIUM_TIMEOUT_OPT).should('not.exist', MEDIUM_TIMEOUT_OPT);
});
});
});
describe('Imported', { tags: ['@jenkins', '@importedCluster'] }, () => {

View File

@ -1,271 +0,0 @@
import HomePagePo from '@/cypress/e2e/po/pages/home.po';
import ClusterManagerCreateRke1Amazonec2PagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create-rke1-amazonec2.po';
import ClusterManagerListPagePo from '@/cypress/e2e/po/pages/cluster-manager/cluster-manager-list.po';
import ClusterManagerDetailRke1AmazonEc2PagePo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail-rke1-amazon.po';
import PromptRemove from '@/cypress/e2e/po/prompts/promptRemove.po';
import LoadingPo from '@/cypress/e2e/po/components/loading.po';
import EmberBannersPo from '@/cypress/e2e/po/components/ember/ember-banners.po';
import { LONG_TIMEOUT_OPT, MEDIUM_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts';
/******
* Running this test will delete node templates and cloud credentials resources from the target cluster
******/
// will only run this in jenkins pipeline where cloud credentials are stored
describe('Deploy RKE1 cluster using node driver on Amazon EC2', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => {
const clusterList = new ClusterManagerListPagePo();
const createRKE1ClusterPage = new ClusterManagerCreateRke1Amazonec2PagePo();
const loadingPo = new LoadingPo('.loading-indicator');
let removeNodeTemplate = false;
let cloudcredentialId = '';
let nodeTemplateId = '';
let clusterId = '';
const k8sVersions = [];
const homePage = new HomePagePo();
const homeClusterList = homePage.list();
before(() => {
cy.login();
HomePagePo.goTo();
// clean up amazon node templates and cloud credentials
cy.getRancherResource('v3', 'nodetemplate', null, null).then((resp: Cypress.Response<any>) => {
const body = resp.body;
if (body.pagination['total'] > 0) {
body.data.forEach((item: any) => {
if (item.driver === 'amazonec2') {
const id = item['id'];
cy.deleteNodeTemplate(id);
} else {
cy.log('There are no existing amazonec2 node templates to delete');
}
});
}
});
cy.getRancherResource('v3', 'cloudcredentials', null, null).then((resp: Cypress.Response<any>) => {
const body = resp.body;
if (body.pagination['total'] > 0) {
body.data.forEach((item: any) => {
if (item.amazonec2credentialConfig) {
const id = item.id;
cy.deleteRancherResource('v3', 'cloudcredentials', id);
} else {
cy.log('There are no existing amazon cloud credentials to delete');
}
});
}
});
});
beforeEach(() => {
cy.viewport(1440, 900);
cy.createE2EResourceName('rke1ec2cluster').as('rke1Ec2ClusterName');
cy.createE2EResourceName('rke1ec2clusterdesc').as('rke1Ec2ClusterDescription');
cy.createE2EResourceName('template').as('templateName');
cy.createE2EResourceName('node').as('nodeName');
});
it('can create an RKE1 cluster using Amazon cloud provider', function() {
const addNodeTemplateForm = createRKE1ClusterPage.addNodeTemplateForm();
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
clusterList.createCluster();
createRKE1ClusterPage.rkeToggle().set('RKE1');
createRKE1ClusterPage.selectCreate(0);
createRKE1ClusterPage.waitForPage('type=amazonec2&rkeType=rke1');
loadingPo.checkNotExists();
createRKE1ClusterPage.rke1PageTitle().should('contain', 'Add Cluster - Amazon EC2');
createRKE1ClusterPage.addNodeTemplate();
// create amazon ec2 cloud credential and node template
addNodeTemplateForm.accessKey().set(Cypress.env('awsAccessKey'));
addNodeTemplateForm.secretKey().set(Cypress.env('awsSecretKey'), true);
addNodeTemplateForm.defaultRegion().selectMenuItemByOption('us-west-1');
addNodeTemplateForm.defaultRegion().checkOptionSelected('us-west-1');
cy.intercept('POST', '/v3/cloudcredential').as('createCloudCred');
addNodeTemplateForm.create();
cy.wait('@createCloudCred').then((req) => {
expect(req.response?.statusCode).to.equal(201);
cloudcredentialId = req.response?.body.id;
});
addNodeTemplateForm.selectNetwork(2).set();
addNodeTemplateForm.nextButton('Next: Select a Security Group').click();
addNodeTemplateForm.nextButton('Next: Set Instance options').click();
addNodeTemplateForm.templateName().set(this.templateName);
cy.intercept('POST', '/v3/nodetemplate').as('createTemplate');
addNodeTemplateForm.create();
cy.wait('@createTemplate').then((req) => {
expect(req.response?.statusCode).to.equal(201);
nodeTemplateId = req.response?.body.id;
removeNodeTemplate = true;
});
addNodeTemplateForm.checkNotExists();
// Create cluster
createRKE1ClusterPage.waitForPage('type=amazonec2&rkeType=rke1');
createRKE1ClusterPage.rke1PageTitle().should('contain', 'Add Cluster - Amazon EC2');
createRKE1ClusterPage.clusterName().set(this.rke1Ec2ClusterName);
createRKE1ClusterPage.addDescriptionButtonClick();
createRKE1ClusterPage.clusterDescription().set(this.rke1Ec2ClusterDescription);
createRKE1ClusterPage.nodePoolTable().name(1).set(this.nodeName);
createRKE1ClusterPage.nodePoolTable().count(1).set('1');
createRKE1ClusterPage.nodePoolTable().template(1).checkOptionSelected(this.templateName);
createRKE1ClusterPage.nodePoolTable().etcd(1).set();
createRKE1ClusterPage.nodePoolTable().controlPlane(1).set();
createRKE1ClusterPage.nodePoolTable().worker(1).checkOptionSelected();
// Get kubernetes version options and store them in variables
createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().getOptions().each((el) => {
k8sVersions.push(el.text().trim());
})
.then(() => {
createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().selectMenuItemByOption(k8sVersions[0]);
});
cy.intercept('POST', 'v3/cluster?_replace=true').as('createRke1Cluster');
createRKE1ClusterPage.createRKE1();
cy.wait('@createRke1Cluster').then(({ response }) => {
expect(response?.statusCode).to.eq(201);
expect(response?.body).to.have.property('type', 'cluster');
expect(response?.body).to.have.property('name', this.rke1Ec2ClusterName);
expect(response?.body.rancherKubernetesEngineConfig).to.have.property('kubernetesVersion', k8sVersions[0]);
clusterId = response?.body.id;
});
clusterList.waitForPage();
clusterList.list().state(this.rke1Ec2ClusterName).should('contain.text', 'Provisioning');
});
it('can see details of cluster in cluster list', function() {
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
// check Architecture
// testing https://github.com/rancher/dashboard/issues/10831
clusterList.list().version(this.rke1Ec2ClusterName).should('contain.text', '—').and('not.contain.text', 'Unknown');
// check states
clusterList.list().state(this.rke1Ec2ClusterName).contains('Waiting', { timeout: 700000 });
clusterList.list().state(this.rke1Ec2ClusterName).contains('Active', { timeout: 700000 });
// check k8s version
clusterList.sortableTable().rowWithName(this.rke1Ec2ClusterName).column(3).contains('—', { timeout: 15000 })
.should('not.exist');
clusterList.list().version(this.rke1Ec2ClusterName).then((el) => {
const shortVersion = k8sVersions[0].split('-');
expect(el.text().trim()).contains(shortVersion[0]);
});
// check provider
clusterList.list().provider(this.rke1Ec2ClusterName).should('contain.text', 'Amazon EC2');
clusterList.list().providerSubType(this.rke1Ec2ClusterName).should('contain.text', 'RKE1');
// check machines
clusterList.list().machines(this.rke1Ec2ClusterName).should('contain.text', '1');
// check cluster details page > machine pools
const clusterDetails = new ClusterManagerDetailRke1AmazonEc2PagePo(undefined, clusterId);
clusterList.list().name(this.rke1Ec2ClusterName).click();
clusterDetails.waitForPage(null, 'node-pools');
clusterDetails.resourceDetail().title().should('contain', this.rke1Ec2ClusterName);
clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(this.nodeName)
.next('tr.main-row')
.should('contain.text', 'Active');
// https://github.com/rancher/dashboard/issues/10441 - covering RKE1/ember world descriptions
HomePagePo.navTo();
const desc = homeClusterList.resourceTable().sortableTable().rowWithName(this.rke1Ec2ClusterName).column(1)
.get('.cluster-description');
desc.contains(this.rke1Ec2ClusterDescription);
});
it('can add a node to the cluster', function() {
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
// cluster details page
const clusterDetails = new ClusterManagerDetailRke1AmazonEc2PagePo(undefined, clusterId);
clusterList.list().actionMenu(this.rke1Ec2ClusterName).getMenuItem('Edit Config').click();
clusterDetails.waitForPage('mode=edit');
clusterDetails.resourceDetail().title().should('contain', this.rke1Ec2ClusterName);
loadingPo.checkNotExists();
createRKE1ClusterPage.nodePoolTable().addNodePool();
createRKE1ClusterPage.nodePoolTable().name(1).set(this.nodeName);
const emberBanner = new EmberBannersPo('div.banner.bg-error');
// check error displays when node pool name is not unique
emberBanner.bannerContent().invoke('text').then((el) => {
expect(el.trim()).eq('Node pools must have unique name prefixes');
});
createRKE1ClusterPage.nodePoolTable().name(1).set(`${ this.nodeName }-2`);
createRKE1ClusterPage.nodePoolTable().count(1).set('1');
createRKE1ClusterPage.nodePoolTable().template(1).checkOptionSelected(this.templateName);
createRKE1ClusterPage.nodePoolTable().controlPlane(1).set();
createRKE1ClusterPage.nodePoolTable().worker(1).checkOptionSelected();
// save changes
cy.intercept('POST', `/v3/nodepool`).as('updateCluster');
createRKE1ClusterPage.saveRKE1();
cy.wait('@updateCluster').its('response.statusCode').should('eq', 201);
clusterList.waitForPage();
// check states on cluster details page > machine pools
clusterList.list().name(this.rke1Ec2ClusterName).click();
clusterDetails.waitForPage(null, 'node-pools');
clusterDetails.resourceDetail().title().should('contain', this.rke1Ec2ClusterName);
clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`)
.next('tr.main-row')
.should('contain.text', 'Provisioning');
clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`)
.next('tr.main-row', { timeout: 360000 })
.should('contain.text', 'Registering');
clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`)
.next('tr.main-row', { timeout: 360000 })
.should('contain.text', 'Active');
});
it('can delete an Amazon EC2 RKE1 cluster', function() {
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
clusterList.list().actionMenu(this.rke1Ec2ClusterName).getMenuItem('Delete').click();
clusterList.sortableTable().rowNames('.cluster-link').then((rows: any) => {
const promptRemove = new PromptRemove();
promptRemove.confirm(this.rke1Ec2ClusterName);
promptRemove.remove();
clusterList.waitForPage();
clusterList.list().state(this.rke1Ec2ClusterName).contains('Removing', LONG_TIMEOUT_OPT);
clusterList.sortableTable().checkRowCount(false, rows.length - 1, MEDIUM_TIMEOUT_OPT);
clusterList.sortableTable().rowNames('.cluster-link').should('not.contain', this.rke1Ec2ClusterName);
});
});
after('clean up', () => {
// delete cluster: needed here in case the delete test fails
cy.deleteRancherResource('v1', 'provisioning.cattle.io.clusters', `fleet-default/${ clusterId }`, false);
if (removeNodeTemplate) {
// delete node template
cy.deleteNodeTemplate(nodeTemplateId).then(() => {
// delete cloud cred
cy.deleteRancherResource('v3', 'cloudCredentials', cloudcredentialId);
});
}
});
});

View File

@ -55,7 +55,6 @@ describe('Deploy RKE2 cluster using node driver on Amazon EC2', { testIsolation:
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
clusterList.createCluster();
createRKE2ClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2ClusterPage.selectCreate(0);
loadingPo.checkNotExists();
createRKE2ClusterPage.rke2PageTitle().should('include', 'Create Amazon EC2');

View File

@ -1,253 +0,0 @@
import HomePagePo from '@/cypress/e2e/po/pages/home.po';
import ClusterManagerCreateRke1AzurePagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create-rke1-azure.po';
import ClusterManagerListPagePo from '@/cypress/e2e/po/pages/cluster-manager/cluster-manager-list.po';
import ClusterManagerDetailRke1AzurePagePo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail-rke1-azure.po';
import PromptRemove from '@/cypress/e2e/po/prompts/promptRemove.po';
import LoadingPo from '@/cypress/e2e/po/components/loading.po';
import EmberBannersPo from '@/cypress/e2e/po/components/ember/ember-banners.po';
import { LONG_TIMEOUT_OPT, MEDIUM_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts';
/******
* Running this test will delete node templates and cloud credentials resources from the target cluster
******/
// will only run this in jenkins pipeline where cloud credentials are stored
describe('Deploy RKE1 cluster using node driver on Azure', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => {
const clusterList = new ClusterManagerListPagePo();
const createRKE1ClusterPage = new ClusterManagerCreateRke1AzurePagePo();
const loadingPo = new LoadingPo('.loading-indicator');
let removeNodeTemplate = false;
let cloudcredentialId = '';
let nodeTemplateId = '';
let clusterId = '';
const k8sVersions = [];
before(() => {
cy.login();
HomePagePo.goTo();
// clean up azure node templates and cloud credentials
cy.getRancherResource('v3', 'nodetemplate', null, null).then((resp: Cypress.Response<any>) => {
const body = resp.body;
if (body.pagination['total'] > 0) {
body.data.forEach((item: any) => {
if (item.driver === 'azure') {
const id = item['id'];
cy.deleteNodeTemplate(id, 60000);
} else {
cy.log('There are no existing azure node templates to delete');
}
});
}
});
cy.getRancherResource('v3', 'cloudcredentials', null, null).then((resp: Cypress.Response<any>) => {
const body = resp.body;
if (body.pagination['total'] > 0) {
body.data.forEach((item: any) => {
if (item.azurecredentialConfig) {
const id = item.id;
cy.deleteRancherResource('v3', 'cloudcredentials', id);
} else {
cy.log('There are no existing azure cloud credentials to delete');
}
});
}
});
});
beforeEach(() => {
cy.viewport(1440, 900);
cy.createE2EResourceName('rke1azurecluster').as('rke1AzureClusterName');
cy.createE2EResourceName('template').as('templateName');
cy.createE2EResourceName('node').as('nodeName');
});
it('can create an RKE1 cluster using Azure cloud provider', function() {
const addNodeTemplateForm = createRKE1ClusterPage.addNodeTemplateForm();
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
clusterList.createCluster();
createRKE1ClusterPage.rkeToggle().set('RKE1');
createRKE1ClusterPage.selectCreate(1);
createRKE1ClusterPage.waitForPage('type=azure&rkeType=rke1');
loadingPo.checkNotExists();
createRKE1ClusterPage.rke1PageTitle().should('contain', 'Add Cluster - Azure');
createRKE1ClusterPage.addNodeTemplate();
// create azure cloud credential and node template
addNodeTemplateForm.subscriptionId().set(Cypress.env('azureSubscriptionId'));
addNodeTemplateForm.clientId().set(Cypress.env('azureClientId'), true);
addNodeTemplateForm.clientSecret().set(Cypress.env('azureClientSecret'), true);
cy.intercept('POST', '/v3/cloudcredential').as('createCloudCred');
addNodeTemplateForm.create();
cy.wait('@createCloudCred').then((req) => {
expect(req.response?.statusCode).to.equal(201);
cloudcredentialId = req.response?.body.id;
});
addNodeTemplateForm.nextButton('Next: Authenticate & configure nodes').click();
addNodeTemplateForm.region().checkOptionSelected('West US');
addNodeTemplateForm.image().set('canonical:0001-com-ubuntu-server-jammy:22_04-lts:latest');
addNodeTemplateForm.templateName().set(this.templateName);
cy.intercept('POST', '/v3/nodetemplate').as('createTemplate');
addNodeTemplateForm.create();
cy.wait('@createTemplate').then((req) => {
expect(req.response?.statusCode).to.equal(201);
nodeTemplateId = req.response?.body.id;
removeNodeTemplate = true;
});
addNodeTemplateForm.checkNotExists();
// Create cluster
createRKE1ClusterPage.waitForPage('type=azure&rkeType=rke1');
createRKE1ClusterPage.rke1PageTitle().should('contain', 'Add Cluster - Azure');
createRKE1ClusterPage.clusterName().set(this.rke1AzureClusterName);
createRKE1ClusterPage.nodePoolTable().name(1).set(this.nodeName);
createRKE1ClusterPage.nodePoolTable().count(1).set('1');
createRKE1ClusterPage.nodePoolTable().template(1).checkOptionSelected(this.templateName);
createRKE1ClusterPage.nodePoolTable().etcd(1).set();
createRKE1ClusterPage.nodePoolTable().controlPlane(1).set();
createRKE1ClusterPage.nodePoolTable().worker(1).checkOptionSelected();
// Get kubernetes version options and store them in variables
createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().getOptions().each((el) => {
k8sVersions.push(el.text().trim());
})
.then(() => {
createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().selectMenuItemByOption(k8sVersions[0]);
});
cy.intercept('POST', 'v3/cluster?_replace=true').as('createRke1Cluster');
createRKE1ClusterPage.createRKE1();
cy.wait('@createRke1Cluster').then(({ response }) => {
expect(response?.statusCode).to.eq(201);
expect(response?.body).to.have.property('type', 'cluster');
expect(response?.body).to.have.property('name', this.rke1AzureClusterName);
expect(response?.body.rancherKubernetesEngineConfig).to.have.property('kubernetesVersion', k8sVersions[0]);
clusterId = response?.body.id;
});
clusterList.waitForPage();
clusterList.list().state(this.rke1AzureClusterName).should('contain.text', 'Provisioning');
});
it('can see details of cluster in cluster list', function() {
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
// check states
clusterList.list().state(this.rke1AzureClusterName).contains('Waiting', { timeout: 700000 });
clusterList.list().state(this.rke1AzureClusterName).contains('Active', { timeout: 700000 });
// check k8s version
clusterList.sortableTable().rowWithName(this.rke1AzureClusterName).column(3).contains('—', { timeout: 15000 })
.should('not.exist');
clusterList.list().version(this.rke1AzureClusterName).then((el) => {
const shortVersion = k8sVersions[0].split('-');
expect(el.text().trim()).contains(shortVersion[0]);
});
// check provider
clusterList.list().provider(this.rke1AzureClusterName).should('contain.text', 'Azure');
clusterList.list().providerSubType(this.rke1AzureClusterName).should('contain.text', 'RKE1');
// check machines
clusterList.list().machines(this.rke1AzureClusterName).should('contain.text', '1');
// check cluster details page > machine pools
const clusterDetails = new ClusterManagerDetailRke1AzurePagePo(undefined, clusterId);
clusterList.list().name(this.rke1AzureClusterName).click();
clusterDetails.waitForPage(null, 'node-pools');
clusterDetails.resourceDetail().title().should('contain', this.rke1AzureClusterName);
clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(this.nodeName)
.next('tr.main-row')
.should('contain.text', 'Active');
});
it('can add a node to the cluster', function() {
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
// cluster details page
const clusterDetails = new ClusterManagerDetailRke1AzurePagePo(undefined, clusterId);
clusterList.list().actionMenu(this.rke1AzureClusterName).getMenuItem('Edit Config').click();
clusterDetails.waitForPage('mode=edit');
clusterDetails.resourceDetail().title().should('contain', this.rke1AzureClusterName);
loadingPo.checkNotExists();
createRKE1ClusterPage.nodePoolTable().addNodePool();
createRKE1ClusterPage.nodePoolTable().name(1).set(this.nodeName);
const emberBanner = new EmberBannersPo('div.banner.bg-error');
// check error displays when node pool name is not unique
emberBanner.bannerContent().invoke('text').then((el) => {
expect(el.trim()).eq('Node pools must have unique name prefixes');
});
createRKE1ClusterPage.nodePoolTable().name(1).set(`${ this.nodeName }-2`);
createRKE1ClusterPage.nodePoolTable().count(1).set('1');
createRKE1ClusterPage.nodePoolTable().template(1).checkOptionSelected(this.templateName);
createRKE1ClusterPage.nodePoolTable().controlPlane(1).set();
createRKE1ClusterPage.nodePoolTable().worker(1).checkOptionSelected();
// save changes
cy.intercept('POST', `/v3/nodepool`).as('updateCluster');
createRKE1ClusterPage.saveRKE1();
cy.wait('@updateCluster').its('response.statusCode').should('eq', 201);
clusterList.waitForPage();
// check states on cluster details page > machine pools
clusterList.list().name(this.rke1AzureClusterName).click();
clusterDetails.waitForPage(null, 'node-pools');
clusterDetails.resourceDetail().title().should('contain', this.rke1AzureClusterName);
clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`)
.next('tr.main-row')
.should('contain.text', 'Provisioning');
clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`)
.next('tr.main-row', { timeout: 360000 })
.should('contain', 'Registering');
clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`)
.next('tr.main-row', { timeout: 360000 })
.should('contain', 'Active');
});
it('can delete an Azure RKE1 cluster', function() {
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
clusterList.list().actionMenu(this.rke1AzureClusterName).getMenuItem('Delete').click();
clusterList.sortableTable().rowNames('.cluster-link').then((rows: any) => {
const promptRemove = new PromptRemove();
promptRemove.confirm(this.rke1AzureClusterName);
promptRemove.remove();
clusterList.waitForPage();
clusterList.list().state(this.rke1AzureClusterName).contains('Removing', LONG_TIMEOUT_OPT);
clusterList.sortableTable().checkRowCount(false, rows.length - 1, MEDIUM_TIMEOUT_OPT);
clusterList.sortableTable().rowNames('.cluster-link').should('not.contain', this.rke1AzureClusterName);
});
});
after('clean up', () => {
// delete cluster: needed here in case the delete test fails
cy.deleteRancherResource('v1', 'provisioning.cattle.io.clusters', `fleet-default/${ clusterId }`, false);
if (removeNodeTemplate) {
// delete node template
cy.deleteNodeTemplate(nodeTemplateId).then(() => {
// delete cloud cred
cy.deleteRancherResource('v3', 'cloudCredentials', cloudcredentialId);
});
}
});
});

View File

@ -52,7 +52,6 @@ describe('Deploy RKE2 cluster using node driver on Azure', { testIsolation: 'off
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
clusterList.createCluster();
createRKE2ClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2ClusterPage.selectCreate(1);
createRKE2ClusterPage.rke2PageTitle().should('include', 'Create Azure');
createRKE2ClusterPage.waitForPage('type=azure&rkeType=rke2');
@ -90,7 +89,6 @@ describe('Deploy RKE2 cluster using node driver on Azure', { testIsolation: 'off
ClusterManagerListPagePo.navTo();
clusterList.waitForPage();
clusterList.createCluster();
createRKE2ClusterPage.rkeToggle().set('RKE2/K3s');
createRKE2ClusterPage.selectCreate(1);
createRKE2ClusterPage.rke2PageTitle().should('include', 'Create Azure');
createRKE2ClusterPage.waitForPage('type=azure&rkeType=rke2');

View File

@ -1,144 +0,0 @@
import ClusterManagerListPagePo from '@/cypress/e2e/po/pages/cluster-manager/cluster-manager-list.po';
import NodeTemplatesPagePo from '@/cypress/e2e/po/pages/cluster-manager/node-templates.po';
import ClusterManagerCreateRke1Amazonec2PagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create-rke1-amazonec2.po';
import EmberModalPo from '@/cypress/e2e/po/components/ember/ember-modal.po';
// will only run this in jenkins pipeline where cloud credentials are stored
describe('Node Templates', { testIsolation: 'off', tags: ['@manager', '@jenkins', '@adminUser'] }, () => {
const nodeTemplatesPage = new NodeTemplatesPagePo();
const clusterList = new ClusterManagerListPagePo();
let cloudCredentialId = '';
before(() => {
cy.login();
});
beforeEach(() => {
cy.viewport(1440, 900);
cy.createE2EResourceName('nodeTemplates').as('nodeTemplateName');
cy.createE2EResourceName('cloudCredential').as('cloudCredentialName');
});
let removeCloudCred = false;
it('can create a node template for Amazon EC2 and should display on RKE1 cluster creation page', function() {
cy.createAwsCloudCredentials('fleet-default', this.cloudCredentialName, 'us-west-2', Cypress.env('awsAccessKey'), Cypress.env('awsSecretKey')).then((resp: Cypress.Response<any>) => {
cloudCredentialId = resp.body.id;
removeCloudCred = true;
});
NodeTemplatesPagePo.navTo();
nodeTemplatesPage.waitForPage();
nodeTemplatesPage.addTemplate().click();
nodeTemplatesPage.addNodeTemplateModal().serviceProviderOptions('Amazon EC2').should('have.class', 'active');
nodeTemplatesPage.addNodeTemplateModal().nextButton('Next: Authenticate & configure nodes').click();
nodeTemplatesPage.addNodeTemplateModal().selectNetwork(2).set();
nodeTemplatesPage.addNodeTemplateModal().nextButton('Next: Select a Security Group').click();
nodeTemplatesPage.addNodeTemplateModal().selectSecurityGroups(2).set();
nodeTemplatesPage.addNodeTemplateModal().serviceProviderOptions('Amazon EC2').should('have.class', 'active');
nodeTemplatesPage.addNodeTemplateModal().nextButton('Next: Set Instance options').click();
nodeTemplatesPage.addNodeTemplateModal().templateName().set(this.nodeTemplateName);
cy.intercept('POST', '/v3/nodetemplate').as('createTemplate');
nodeTemplatesPage.addNodeTemplateModal().create();
cy.wait('@createTemplate');
nodeTemplatesPage.waitForPage();
nodeTemplatesPage.list().rowWithName(this.nodeTemplateName).should('be.visible');
// check RKE template displays as an option on the RKE cluster create page
clusterList.goTo();
clusterList.checkIsCurrentPage();
clusterList.createCluster();
const createClusterRKE1Page = new ClusterManagerCreateRke1Amazonec2PagePo();
createClusterRKE1Page.waitForPage();
createClusterRKE1Page.rkeToggle().set('RKE1');
createClusterRKE1Page.selectCreate(0);
createClusterRKE1Page.nodeTemplateDropdown().selectMenuItemByOption(this.nodeTemplateName);
createClusterRKE1Page.selectedOption().checkOptionSelected(this.nodeTemplateName);
});
it('can edit a node template', function() {
NodeTemplatesPagePo.navTo();
nodeTemplatesPage.waitForPage();
nodeTemplatesPage.list().rowWithName(this.nodeTemplateName).should('be.visible');
nodeTemplatesPage.list().rowActionMenuOpen(this.nodeTemplateName);
nodeTemplatesPage.list().actionMenu().selectMenuItemByLabel('Edit');
nodeTemplatesPage.addNodeTemplateModal().nextButton('Next: Authenticate & configure nodes').click();
nodeTemplatesPage.addNodeTemplateModal().nextButton('Next: Select a Security Group').click();
nodeTemplatesPage.addNodeTemplateModal().nextButton('Next: Set Instance options').click();
nodeTemplatesPage.addNodeTemplateModal().templateName().set(`${ this.nodeTemplateName }-edit`);
cy.intercept('PUT', '/v3/nodeTemplates/**').as('editTemplate');
nodeTemplatesPage.addNodeTemplateModal().save();
cy.wait('@editTemplate');
nodeTemplatesPage.waitForPage();
nodeTemplatesPage.list().rowWithName(`${ this.nodeTemplateName }-edit`).should('be.visible');
});
it('can clone a node template', function() {
NodeTemplatesPagePo.navTo();
nodeTemplatesPage.waitForPage();
nodeTemplatesPage.list().rowWithName(`${ this.nodeTemplateName }-edit`).should('be.visible');
nodeTemplatesPage.list().rowActionMenuOpen(`${ this.nodeTemplateName }-edit`);
nodeTemplatesPage.list().actionMenu().selectMenuItemByLabel('Clone');
nodeTemplatesPage.addNodeTemplateModal().nextButton('Next: Authenticate & configure nodes').click();
nodeTemplatesPage.addNodeTemplateModal().nextButton('Next: Select a Security Group').click();
nodeTemplatesPage.addNodeTemplateModal().nextButton('Next: Set Instance options').click();
nodeTemplatesPage.addNodeTemplateModal().templateName().set(`${ this.nodeTemplateName }-clone`);
cy.intercept('POST', '/v3/nodetemplate').as('cloneTemplate');
nodeTemplatesPage.addNodeTemplateModal().save();
cy.wait('@cloneTemplate');
nodeTemplatesPage.waitForPage();
nodeTemplatesPage.list().rowWithName(`${ this.nodeTemplateName }-clone`).should('be.visible');
});
it('can delete a node template', function() {
NodeTemplatesPagePo.navTo();
nodeTemplatesPage.waitForPage();
// delete clone node template
nodeTemplatesPage.list().rowWithName(`${ this.nodeTemplateName }-clone`).should('be.visible');
nodeTemplatesPage.list().rowActionMenuOpen(`${ this.nodeTemplateName }-clone`);
nodeTemplatesPage.list().actionMenu().selectMenuItemByLabel('Delete');
const promptRemove = new EmberModalPo();
cy.intercept('DELETE', '/v3/nodeTemplates/**').as('deleteNodeTemplate');
promptRemove.delete();
cy.wait('@deleteNodeTemplate');
nodeTemplatesPage.waitForPage();
// check list details
cy.contains(`${ this.nodeTemplateName }-clone`).should('not.exist');
});
it('can delete a node template via bulk actions', function() {
NodeTemplatesPagePo.navTo();
nodeTemplatesPage.waitForPage();
// delete original node template
nodeTemplatesPage.list().rowWithName(`${ this.nodeTemplateName }-edit`).click();
nodeTemplatesPage.list().bulkActions('Delete').click();
const promptRemove = new EmberModalPo();
cy.intercept('DELETE', '/v3/nodeTemplates/**').as('deleteNodeTemplate');
promptRemove.delete();
cy.wait('@deleteNodeTemplate');
nodeTemplatesPage.waitForPage();
// check list details
cy.contains(`${ this.nodeTemplateName }-edit`).should('not.exist');
});
after('clean up', () => {
if (removeCloudCred) {
// delete cloud cred
cy.deleteRancherResource('v3', 'cloudCredentials', cloudCredentialId);
}
});
});

View File

@ -35,7 +35,6 @@ describe('Registries for RKE2', { tags: ['@manager', '@adminUser'] }, () => {
clusterList.createCluster();
createCustomClusterPage.waitForPage();
createCustomClusterPage.rkeToggle().set('RKE2/K3s');
createCustomClusterPage.selectCustom(0);
@ -101,7 +100,6 @@ describe('Registries for RKE2', { tags: ['@manager', '@adminUser'] }, () => {
clusterList.createCluster();
createCustomClusterPage.waitForPage();
createCustomClusterPage.rkeToggle().set('RKE2/K3s');
createCustomClusterPage.selectCustom(0);

View File

@ -1,107 +0,0 @@
import ClusterManagerListPagePo from '@/cypress/e2e/po/pages/cluster-manager/cluster-manager-list.po';
import ClusterManagerCreateRke1CustomPagePo from '@/cypress/e2e/po/edit/provisioning.cattle.io.cluster/create/cluster-create-rke1-custom.po';
import RkeTemplatesPagePo from '@/cypress/e2e/po/pages/cluster-manager/rke-templates.po';
import EmberModalPo from '@/cypress/e2e/po/components/ember/ember-modal.po';
describe('RKE Templates', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@ember'] }, () => {
const rkeTemplatesPage = new RkeTemplatesPagePo();
const clusterList = new ClusterManagerListPagePo();
const promptRemove = new EmberModalPo();
before(() => {
cy.login();
});
beforeEach(() => {
cy.viewport(1440, 900);
cy.createE2EResourceName('rkeTemplate').as('rkeTemplateName');
cy.createE2EResourceName('rkeRevision').as('rkeRevisionName');
});
it('can create RKE template and should display on RKE1 cluster creation page', function() {
RkeTemplatesPagePo.navTo();
rkeTemplatesPage.waitForPage();
rkeTemplatesPage.addTemplate().click();
rkeTemplatesPage.form().templateDetails(3).set(this.rkeTemplateName);
rkeTemplatesPage.form().templateDetails(2).set(this.rkeRevisionName);
cy.intercept('POST', '/v3/clustertemplate').as('createTemplate');
rkeTemplatesPage.form().create();
cy.wait('@createTemplate');
rkeTemplatesPage.waitForPage();
rkeTemplatesPage.groupRow().groupRowWithName(this.rkeTemplateName).should('be.visible');
rkeTemplatesPage.groupRow().rowWithinGroupByName(this.rkeTemplateName, this.rkeRevisionName).should('be.visible');
// check RKE template displays as an option on the RKE custom cluster create page
clusterList.goTo();
clusterList.checkIsCurrentPage();
clusterList.createCluster();
const createClusterRKE1Page = new ClusterManagerCreateRke1CustomPagePo();
createClusterRKE1Page.waitForPage();
createClusterRKE1Page.rkeToggle().set('RKE1');
createClusterRKE1Page.selectCustom(0);
createClusterRKE1Page.clusterTemplateCheckbox().set();
createClusterRKE1Page.rkeTemplateAndRevisionDropdown().selectMenuItemByOption(this.rkeTemplateName);
createClusterRKE1Page.selectedOption().checkOptionSelected(this.rkeTemplateName);
createClusterRKE1Page.selectedOption().checkOptionSelected(this.rkeRevisionName, 1);
});
it('can disable RKE template revision', function() {
RkeTemplatesPagePo.navTo();
rkeTemplatesPage.waitForPage();
rkeTemplatesPage.mainRow().rowActionMenuOpen(this.rkeRevisionName);
cy.intercept('POST', '/v3/clusterTemplateRevisions/*').as('disableTemplateRevision');
rkeTemplatesPage.actionMenu().selectMenuItemByLabel('Disable');
cy.wait('@disableTemplateRevision');
rkeTemplatesPage.mainRow().state(this.rkeRevisionName).contains('Active').should('not.exist');
rkeTemplatesPage.mainRow().state(this.rkeRevisionName).should('contain.text', 'Disabled');
});
it('can enable RKE template revision', function() {
RkeTemplatesPagePo.navTo();
rkeTemplatesPage.waitForPage();
rkeTemplatesPage.mainRow().rowActionMenuOpen(this.rkeRevisionName);
cy.intercept('POST', '/v3/clusterTemplateRevisions/*').as('enableTemplateRevision');
rkeTemplatesPage.actionMenu().selectMenuItemByLabel('Enable');
cy.wait('@enableTemplateRevision');
rkeTemplatesPage.mainRow().state(this.rkeRevisionName).contains('Disabled').should('not.exist');
rkeTemplatesPage.mainRow().state(this.rkeRevisionName).should('contain.text', 'Active');
});
it('can clone RKE template revision', function() {
RkeTemplatesPagePo.navTo();
rkeTemplatesPage.waitForPage();
rkeTemplatesPage.groupRow().groupRowWithName(this.rkeTemplateName).should('be.visible');
rkeTemplatesPage.mainRow().rowActionMenuOpen(this.rkeRevisionName);
rkeTemplatesPage.actionMenu().selectMenuItemByLabel('Clone Revision');
rkeTemplatesPage.form().templateDetails(2).set(`${ this.rkeRevisionName }-2`);
cy.intercept('PUT', '/v3/clusterTemplates/*').as('cloneTemplateRevision');
rkeTemplatesPage.form().save();
cy.wait('@cloneTemplateRevision');
rkeTemplatesPage.groupRow().rowWithinGroupByName(this.rkeTemplateName, `${ this.rkeRevisionName }-2`);
});
it('can delete RKE template revision', function() {
RkeTemplatesPagePo.navTo();
rkeTemplatesPage.waitForPage();
rkeTemplatesPage.mainRow().rowActionMenuOpen(`${ this.rkeRevisionName }-2`);
rkeTemplatesPage.actionMenu().selectMenuItemByLabel(`Delete`);
cy.intercept('DELETE', '/v3/clusterTemplateRevisions/*').as('deleteTemplateRevision');
promptRemove.delete();
cy.wait('@deleteTemplateRevision').its('response.statusCode').should('eq', 204);
rkeTemplatesPage.mainRow().rowWithName(`${ this.rkeRevisionName }-2`).should('not.exist');
});
it('can delete RKE template group', function() {
RkeTemplatesPagePo.navTo();
rkeTemplatesPage.waitForPage();
rkeTemplatesPage.groupRow().groupRowActionMenuOpen(this.rkeTemplateName);
rkeTemplatesPage.actionMenu().selectMenuItemByLabel(`Delete`);
cy.intercept('DELETE', '/v3/clusterTemplates/*').as('deleteTemplate');
promptRemove.delete();
cy.wait('@deleteTemplate').its('response.statusCode').should('eq', 204);
rkeTemplatesPage.groupRow().groupRowWithName(this.rkeTemplateName).should('not.exist');
});
});

View File

@ -181,7 +181,6 @@ nav:
restoreSnapshot: Restore Snapshot
rotateCertificates: Rotate Certificates
rotateEncryptionKeys: Rotate Encryption Keys
saveAsRKETemplate: Save as RKE Template
takeSnapshot: Take Snapshot
seeAllClusters: See all clusters
seeAllClustersCollapsed: See all
@ -1936,9 +1935,8 @@ cluster:
=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. }
other { {pool_name}: The provided values for {fields} were 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. }
}
rke1DeprecationMessage: 'Rancher Kubernetes Engine (RKE / RKE1) will reach end of life on July 31, 2025. Rancher 2.12.0 and later will no longer support provisioning or managing downstream RKE1 clusters. We recommend replatforming RKE1 clusters to RKE2 to ensure continued support and security updates. Learn more about the transition <a href="https://www.suse.com/support/kb/doc/?id=000021518" target="_blank" rel="noopener noreferrer nofollow">here</a>.'
rke1DeprecationShortMessage: Rancher Kubernetes Engine (RKE / RKE1) will reach end of life on July 31, 2025. Rancher 2.12.0 and later will no longer support provisioning or managing downstream RKE1 clusters.
rkeTemplateUpgrade: Template revision {name} available for upgrade
rke1DeprecationMessage: 'Rancher Kubernetes Engine (RKE / RKE1) has reached end of life and these clusters are no longer supported. We recommend replatforming RKE1 clusters to RKE2 to ensure continued support and security updates. Learn more about the transition <a href="https://www.suse.com/support/kb/doc/?id=000021518" target="_blank" rel="noopener noreferrer nofollow">here</a>.'
rke1Unsupported: RKE1 Clusters are no longer supported
cloudCredentials:
renew: Renew Cloud Credentials
expired: Cloud Credential expired, please Renew Cloud Credentials
@ -4981,12 +4979,6 @@ promptRollback:
multipleWorkloadError: "Only one workload can be rolled back at a time."
singleRevisionBanner: There are no revisions to roll back to.
promptSaveAsRKETemplate:
title: Convert {cluster} to new RKE Template
name: Cluster Template Name
description: Create a new RKE cluster template and initial revision from the current cluster configuration.
warning: This will modify the cluster, setting it up to use the newly created cluster template and revision. This can not be undone.
promptRotateEncryptionKey:
title: Rotate Encryption Keys
description: The last backup {name} was performed on {date}

View File

@ -137,7 +137,6 @@ nav:
restoreSnapshot: 还原快照
rotateCertificates: 轮换证书
rotateEncryptionKeys: 轮换加密密钥
saveAsRKETemplate: 保存为 RKE 模板
takeSnapshot: 拍摄快照
group:
cluster: 集群
@ -1669,7 +1668,6 @@ cluster:
rke2-k3-reprovisioning: '更改集群配置可能导致节点重新配置。详情请参见 <a target="blank" href="{docsBase}/how-to-guides/new-user-guides/launch-kubernetes-with-rancher/rke1-vs-rke2-differences#cluster-api" target="_blank" rel="noopener nofollow">文档</a>。'
desiredNodeGroupWarning: 没有可用于运行 Cluster Agent 的节点。要让集群变为 Active 状态,至少需要有 1 个可用的节点。
haveArgInfo: 所选 Kubernetes 版本的配置信息不可用。此屏幕中可用的选项将受到限制,你可能需要使用 YAML 编辑器。
rkeTemplateUpgrade: 模板修订版 {name} 可用于升级
availabilityWarnings:
node: 节点 {name} 处于非活动状态
@ -4447,12 +4445,6 @@ promptRollback:
multipleWorkloadError: "一次只能回滚一个工作负载。"
singleRevisionBanner: 没有可用于回滚的修订版本。
promptSaveAsRKETemplate:
title: 将 {cluster} 转换为新的 RKE 模板
name: 集群模板名称
description: 创建新的集群模板,并使用当前集群配置发起修改。
warning: 此操作将对集群进行修改,即把新创建的集群模板和修改应用到集群中。此操作不能撤销。
promptRotateEncryptionKey:
title: 轮换加密密钥
description: 上次备份 {name} 的备份时间为 {date}

View File

@ -14,7 +14,6 @@ import GitRepoForceUpdateDialog from '@shell/dialog/GitRepoForceUpdateDialog.vue
import RollbackWorkloadDialog from '@shell/dialog/RollbackWorkloadDialog.vue';
import RotateCertificatesDialog from '@shell/dialog/RotateCertificatesDialog.vue';
import RotateEncryptionKeyDialog from '@shell/dialog/RotateEncryptionKeyDialog.vue';
import SaveAsRKETemplateDialog from '@shell/dialog/SaveAsRKETemplateDialog.vue';
import ScaleMachineDownDialog from '@shell/dialog/ScaleMachineDownDialog.vue';
import ScalePoolDownDialog from '@shell/dialog/ScalePoolDownDialog.vue';
import SloDialog from '@shell/dialog/SloDialog.vue';
@ -100,7 +99,6 @@ describe('component: PromptModal', () => {
['RollbackWorkloadDialog', RollbackWorkloadDialog],
['RotateCertificatesDialog', RotateCertificatesDialog],
['RotateEncryptionKeyDialog', RotateEncryptionKeyDialog],
['SaveAsRKETemplateDialog', SaveAsRKETemplateDialog],
['SloDialog', SloDialog],
['AddCustomBadgeDialog', AddCustomBadgeDialog],
['ScaleMachineDownDialog', ScaleMachineDownDialog],

View File

@ -70,10 +70,10 @@ export default {
data-testid="unavailable-machines-alert-icon"
/>
<i
v-if="row.rkeTemplateUpgrade"
v-clean-tooltip="t('cluster.rkeTemplateUpgrade', { name: row.rkeTemplateUpgrade })"
class="template-upgrade-icon icon-alert icon"
data-testid="rke-template-upgrade-alert-icon"
v-if="row.isRke1"
v-clean-tooltip="t('cluster.rke1Unsupported')"
class="rke1-unsupported-icon icon-warning icon"
data-testid="rke1-unsupported-icon"
/>
<i
v-if="row.hasError && statusErrorConditions.length > 0"
@ -106,12 +106,9 @@ export default {
.mytooltip ul {
outline: 1px dashed red;
}
.template-upgrade-icon {
border: 1px solid var(--warning);
border-radius: 50%;
.rke1-unsupported-icon {
color: var(--warning);
margin-left: 4px;
font-size: 14px;
padding: 2px;
}
</style>

View File

@ -1,37 +0,0 @@
<script>
export default {
props: {
value: {
type: Object,
required: true
},
}
};
</script>
<template>
<div class="rke-template">
<span>{{ value.displayName }}</span>
<i
v-if="value.upgrade"
v-clean-tooltip="t('cluster.rkeTemplateUpgrade', { name: value.upgrade })"
class="template-upgrade-icon icon-alert icon"
/>
</div>
</template>
<style lang="scss" scoped>
.rke-template {
align-items: center;
display: inline-flex;
.template-upgrade-icon {
border: 1px solid var(--warning);
border-radius: 50%;
color: var(--warning);
margin-left: 4px;
font-size: 14px;
padding: 2px;
}
}
</style>

View File

@ -3,7 +3,6 @@ import ClusterLink from '@shell/components/formatter/ClusterLink.vue';
describe('component: ClusterLink', () => {
const UNAVAILABLE_MACHINES_ICON_SELECTOR = '[data-testid="unavailable-machines-alert-icon"]';
const TEMPLATE_UPGRADE_ICON_SELECTOR = '[data-testid="rke-template-upgrade-alert-icon"]';
const CONDITION_HAS_ERROR_ICON_SELECTOR = '[data-testid="conditions-has-error-icon"]';
describe('unavailable machines alert icon', () => {
@ -20,10 +19,9 @@ describe('component: ClusterLink', () => {
const wrapper = mount(ClusterLink, {
props: {
row: {
hasError: false,
status: {},
hasError: false,
status: {},
unavailableMachines,
rkeTemplateUpgrade: undefined
},
reference: 'any',
value: 'any'
@ -36,34 +34,6 @@ describe('component: ClusterLink', () => {
);
});
describe('template upgrade alert icon', () => {
const testCases = [
[undefined, false],
['any', true],
];
it.each(testCases)(
'should show/hide properly based on rkeTemplateUpgrade',
(rkeTemplateUpgrade, expected) => {
const wrapper = mount(ClusterLink, {
props: {
row: {
hasError: false,
status: {},
unavailableMachines: 0,
rkeTemplateUpgrade
},
reference: 'any',
value: 'any'
}
});
const el = wrapper.find(TEMPLATE_UPGRADE_ICON_SELECTOR);
expect(el.exists()).toBe(expected);
}
);
});
describe('conditions has error icon', () => {
const MOCKED_CONDITIONS_1 = [{
status: '', type: 'Ready', reason: 'Waiting', error: true // When the only existing error has a type "Ready" and reason "Waiting"

View File

@ -8,7 +8,7 @@ import {
SNAPSHOT,
VIRTUAL_TYPES
} from '@shell/config/types';
import { MULTI_CLUSTER, RKE1_UI } from '@shell/store/features';
import { MULTI_CLUSTER } from '@shell/store/features';
import { DSL } from '@shell/store/type-map';
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
@ -101,28 +101,6 @@ export function init(store) {
exact: true
});
virtualType({
ifFeature: RKE1_UI,
labelKey: 'manager.rkeTemplates.label',
name: 'rke-templates',
group: 'Root',
namespaced: false,
icon: 'globe',
route: { name: 'c-cluster-manager-pages-page', params: { cluster: 'local', page: 'rke-templates' } },
exact: true
});
virtualType({
ifFeature: RKE1_UI,
labelKey: 'manager.nodeTemplates.label',
name: 'rke-node-templates',
group: 'Root',
namespaced: false,
icon: 'globe',
route: { name: 'c-cluster-manager-pages-page', params: { cluster: 'local', page: 'node-templates' } },
exact: true
});
virtualType({
ifHaveType: MANAGEMENT.CLUSTER_PROXY_CONFIG,
labelKey: 'manager.jwtAuthentication.label',
@ -139,11 +117,6 @@ export function init(store) {
'rke-node-drivers',
], 'drivers');
basicType([
'rke-templates',
'rke-node-templates'
], 'RKE1Configuration');
weightType(CAPI.MACHINE_DEPLOYMENT, 4, true);
weightType(CAPI.MACHINE_SET, 3, true);
weightType(CAPI.MACHINE, 2, true);

View File

@ -50,14 +50,12 @@ export const SETTING = {
FIRST_LOGIN: 'first-login',
INGRESS_IP_DOMAIN: 'ingress-ip-domain',
SERVER_URL: 'server-url',
RKE_METADATA_CONFIG: 'rke-metadata-config',
EULA_AGREED: 'eula-agreed',
AUTH_USER_INFO_MAX_AGE_SECONDS: 'auth-user-info-max-age-seconds',
AUTH_USER_SESSION_TTL_MINUTES: 'auth-user-session-ttl-minutes',
AUTH_USER_INFO_RESYNC_CRON: 'auth-user-info-resync-cron',
AUTH_LOCAL_VALIDATE_DESC: 'auth-password-requirements-description',
PASSWORD_MIN_LENGTH: 'password-min-length', // CATTLE_PASSWORD_MIN_LENGTH
CLUSTER_TEMPLATE_ENFORCEMENT: 'cluster-template-enforcement',
UI_INDEX: 'ui-index',
UI_DASHBOARD_INDEX: 'ui-dashboard-index',
UI_DASHBOARD_HARVESTER_LEGACY_PLUGIN: 'ui-dashboard-harvester-legacy-plugin',
@ -148,7 +146,6 @@ export const ALLOWED_SETTINGS: GlobalSetting = {
[SETTING.KUBECONFIG_DEFAULT_TOKEN_TTL_MINUTES]: { kind: 'integer' },
[SETTING.AUTH_USER_INFO_RESYNC_CRON]: {},
[SETTING.SERVER_URL]: { kind: 'url', canReset: true },
[SETTING.RKE_METADATA_CONFIG]: { kind: 'json' },
[SETTING.SYSTEM_DEFAULT_REGISTRY]: {},
[SETTING.UI_INDEX]: {},
[SETTING.UI_DASHBOARD_INDEX]: {},
@ -156,10 +153,9 @@ export const ALLOWED_SETTINGS: GlobalSetting = {
kind: 'enum',
options: ['dynamic', 'true', 'false']
},
[SETTING.BRAND]: { canReset: true },
[SETTING.CLUSTER_TEMPLATE_ENFORCEMENT]: { kind: 'boolean' },
[SETTING.HIDE_LOCAL_CLUSTER]: { kind: 'boolean' },
[SETTING.AGENT_TLS_MODE]: {
[SETTING.BRAND]: { canReset: true },
[SETTING.HIDE_LOCAL_CLUSTER]: { kind: 'boolean' },
[SETTING.AGENT_TLS_MODE]: {
kind: 'enum',
options: ['strict', 'system-store'],
warning: 'agent-tls-mode'

View File

@ -448,7 +448,7 @@ export default {
showSnapshots() {
if (this.value.isRke1) {
return this.$store.getters['rancher/canList'](NORMAN.ETCD_BACKUP) && this.extDetailTabs.snapshots;
return false;
} else if (this.value.isRke2) {
return this.$store.getters['management/canList'](SNAPSHOT) && this.extDetailTabs.snapshots;
}
@ -456,6 +456,10 @@ export default {
return false;
},
isRke1() {
return this.value.isRke1;
},
showEksNodeGroupWarning() {
if ( this.value.provisioner === 'EKS' && this.value.state !== STATES_ENUM.ACTIVE) {
const desiredTotal = this.value.eksNodeGroups.filter((g) => g.desiredSize === 0);
@ -495,8 +499,14 @@ export default {
},
mgmtNodeSchemaHeaders() {
// Remove Cluster name being a link
const RKE1_NAME_COL = {
...NAME_COL,
formatter: undefined
};
const headers = [
STATE, NAME_COL,
STATE, RKE1_NAME_COL,
{
name: 'node-name',
labelKey: 'tableHeaders.machineNodeName',
@ -967,7 +977,7 @@ export default {
</div>
</div>
<div
v-if="group.ref"
v-if="group.ref && !isRke1"
class="right group-header-buttons"
>
<MachineSummaryGraph

View File

@ -1,139 +0,0 @@
<script>
import AsyncButton from '@shell/components/AsyncButton';
import { Card } from '@components/Card';
import { Banner } from '@components/Banner';
import { LabeledInput } from '@components/Form/LabeledInput';
import { exceptionToErrorsArray } from '@shell/utils/error';
const DEFAULT_REVISION = 'v1';
export default {
emits: ['close'],
components: {
Card,
AsyncButton,
Banner,
LabeledInput,
},
props: {
cluster: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return { errors: [], name: '' };
},
mounted() {
this.$nextTick(() => {
this.$refs.templateName.focus();
});
},
methods: {
close() {
this.$emit('close');
},
async apply(buttonDone) {
try {
await this.$store.dispatch('rancher/request', {
url: `/v3/clusters/${ escape(this.cluster.name) }?action=saveAsTemplate`,
method: 'post',
data: {
clusterTemplateName: this.name,
clusterTemplateRevisionName: DEFAULT_REVISION
},
});
buttonDone(true);
this.close();
// Take the user to the RKE Templates view
this.$router.replace({
name: 'c-cluster-manager-pages-page',
params: {
cluster: 'local',
page: 'rke-templates'
}
});
} catch (err) {
this.errors = exceptionToErrorsArray(err);
buttonDone(false);
}
}
}
};
</script>
<template>
<Card
class="prompt-restore"
:show-highlight-border="false"
>
<template #title>
<h4
v-clean-html="t('promptSaveAsRKETemplate.title', { cluster: cluster.displayName }, true)"
class="text-default-text"
/>
</template>
<template #body>
<div class="pl-10 pr-10">
<form>
<p class="pt-10 pb-10">
{{ t('promptSaveAsRKETemplate.description') }}
</p>
<Banner
color="warning"
label-key="promptSaveAsRKETemplate.warning"
/>
<LabeledInput
ref="templateName"
v-model:value="name"
:label="t('promptSaveAsRKETemplate.name')"
:required="true"
/>
</form>
</div>
</template>
<template #actions>
<div class="buttons">
<button
class="btn role-secondary mr-10"
@click="close"
>
{{ t('generic.cancel') }}
</button>
<AsyncButton
mode="create"
:disabled="name.length <= 0"
@click="apply"
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</div>
</template>
</Card>
</template>
<style lang='scss' scoped>
.prompt-restore {
margin: 0;
}
.buttons {
display: flex;
justify-content: flex-end;
width: 100%;
}
</style>

View File

@ -5,17 +5,16 @@ import { Banner } from '@components/Banner';
import CruResource from '@shell/components/CruResource';
import SelectIconGrid from '@shell/components/SelectIconGrid';
import EmberPage from '@shell/components/EmberPage';
import { ToggleSwitch } from '@components/Form/ToggleSwitch';
import {
CHART, FROM_CLUSTER, SUB_TYPE, RKE_TYPE, _EDIT, _IMPORT, _CONFIG, _VIEW
} from '@shell/config/query-params';
import { mapGetters } from 'vuex';
import { sortBy } from '@shell/utils/sort';
import { PROVISIONER, _RKE1, _RKE2 } from '@shell/store/prefs';
import { PROVISIONER, _RKE2 } from '@shell/store/prefs';
import { filterAndArrangeCharts } from '@shell/store/catalog';
import { CATALOG, CAPI as CAPI_ANNOTATIONS } from '@shell/config/labels-annotations';
import { CAPI, MANAGEMENT, DEFAULT_WORKSPACE } from '@shell/config/types';
import { mapFeature, RKE2 as RKE2_FEATURE, RKE1_UI } from '@shell/store/features';
import { mapFeature, RKE2 as RKE2_FEATURE } from '@shell/store/features';
import { allHash } from '@shell/utils/promise';
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
import { ELEMENTAL_PRODUCT_NAME, ELEMENTAL_CLUSTER_PROVIDER } from '../../config/elemental-types';
@ -25,7 +24,6 @@ import { DRIVER_TO_IMPORT } from '@shell/models/management.cattle.io.kontainerdr
const SORT_GROUPS = {
template: 1,
kontainer: 2,
rke1: 3,
rke2: 3,
register: 4,
custom: 5,
@ -49,7 +47,6 @@ export default {
Loading,
Rke2Config,
SelectIconGrid,
ToggleSwitch,
Banner
},
@ -105,6 +102,7 @@ export default {
hash.kontainerDrivers = this.$store.dispatch('management/findAll', { type: MANAGEMENT.KONTAINER_DRIVER });
}
// Not sure if needed for legacy hosted cluster?
if ( this.value.id && !this.value.isRke2 ) {
// These are needed to resolve references in the mgmt cluster -> node pool -> node template to figure out what provider the cluster is using
// so that the edit iframe for ember pages can go to the right place.
@ -217,7 +215,6 @@ export default {
this.$store.dispatch('prefs/set', { key: PROVISIONER, value });
}
},
_RKE1: () => _RKE1,
_RKE2: () => _RKE2,
emberLink() {
@ -282,8 +279,7 @@ export default {
return '';
},
rke2Enabled: mapFeature(RKE2_FEATURE),
rke1UiEnabled: mapFeature(RKE1_UI),
rke2Enabled: mapFeature(RKE2_FEATURE),
// todo nb is this info stored anywhere else..?
selectedSubType() {
@ -292,16 +288,6 @@ export default {
provisioner: {
get() {
// This can incorrectly return rke1 instead
// of rke2 for cluster owners.
if ( !this.rke2Enabled ) {
return _RKE1;
}
if ( !this.rke1UiEnabled ) {
return _RKE2;
}
return this.preferredProvisioner;
},
@ -311,11 +297,11 @@ export default {
},
isRke1() {
return this.provisioner === _RKE1;
return this.value.isRke1;
},
isRke2() {
return this.value.isRke2 || !this.isRke1;
return this.value.isRke2;
},
templateOptions() {
@ -360,20 +346,13 @@ export default {
if (isElementalActive) {
// !this.subType means we are on the /create screen - we only want to show for rke2
// if a subType is selected, always add the ELEMENTAL_CLUSTER_PROVIDER type to cover edit scenarios
if ((!this.subType && !this.isRke1) || this.subType) {
if ((!this.subType && this.isRke2) || this.subType) {
addType(this.$plugin, ELEMENTAL_CLUSTER_PROVIDER, 'custom2', false);
}
}
if (this.isRke1 ) {
machineTypes.forEach((type) => {
const id = type.spec.displayName || type.id;
addType(this.$plugin, id, _RKE1, false, `/g/clusters/add/launch/${ id }`, this.iconClasses[id], type);
});
addType(this.$plugin, 'custom', 'custom1', false, '/g/clusters/add/launch/custom');
} else {
// Only add the RKE2 options if RKE2 is enabled
if (this.rke2Enabled) {
machineTypes.forEach((type) => {
const id = type.spec.displayName || type.id;
@ -385,11 +364,6 @@ export default {
}
// Add from extensions
this.extensions.forEach((ext) => {
// if the rke toggle is set to rke1, don't add extensions that specify rke2 group
// default group is rke2
if (!this.isRke2 && (ext.group === _RKE2 || !ext.group)) {
return;
}
// Do not show the extension provisioner on the import cluster page unless its explicitly set to do so
if (isImport && !ext.showImport) {
return;
@ -504,7 +478,7 @@ export default {
},
firstNodeDriverItem() {
return this.groupedSubTypes.findIndex((obj) => [_RKE1, _RKE2].includes(obj.name));
return this.groupedSubTypes.findIndex((obj) => [_RKE2].includes(obj.name));
},
firstCustomClusterItem() {
@ -522,18 +496,6 @@ export default {
},
methods: {
showRkeToggle(i) {
if (this.isImport || !this.rke2Enabled) {
return false;
}
if (this.firstNodeDriverItem >= 0) {
return i === this.firstNodeDriverItem;
}
return i === this.firstCustomClusterItem;
},
loadStylesheet(url, id) {
if ( !id ) {
console.error('loadStylesheet called without an id'); // eslint-disable-line no-console
@ -620,6 +582,14 @@ export default {
<template>
<Loading v-if="$fetchState.pending" />
<div
v-else-if="isRke1"
>
<Banner
color="warning"
label-key="cluster.banner.rke1DeprecationMessage"
/>
</div>
<div
v-else-if="emberLink"
class="embed"
@ -653,27 +623,8 @@ export default {
style="width: 100%;"
>
<h4>
<div
v-if="showRkeToggle(i) && rke1UiEnabled"
class="grouped-type"
>
<ToggleSwitch
v-model:value="provisioner"
data-testid="cluster-manager-create-rke-switch"
class="rke-switch"
:off-value="_RKE1"
:off-label="t('cluster.toggle.v1')"
:on-value="_RKE2"
:on-label="t('cluster.toggle.v2')"
/>
</div>
{{ obj.label }}
</h4>
<Banner
v-if="provisioner === _RKE1 && i === 1"
color="warning"
label-key="cluster.banner.rke1DeprecationShortMessage"
/>
<SelectIconGrid
:rows="obj.types"
key-field="id"

View File

@ -106,10 +106,6 @@ export default class MgmtCluster extends SteveModel {
return null;
}
get rkeTemplateVersion() {
return this.spec?.clusterTemplateRevisionName;
}
get providerForEmberParam() {
// Ember wants one word called provider to tell what component to show, but has much indirect mapping to figure out what it is.
let provider;
@ -136,14 +132,6 @@ export default class MgmtCluster extends SteveModel {
}
get emberEditPath() {
let clusterTemplateRevision;
// If the RKE1 cluster is created from an RKE template, we need
// to get the template version to pass into the Ember UI for
// the iFramed edit cluster form
if (this.rkeTemplateVersion) {
clusterTemplateRevision = this.rkeTemplateVersion;
}
const provider = this.providerForEmberParam;
// Avoid passing falsy values as query parameters
@ -153,10 +141,6 @@ export default class MgmtCluster extends SteveModel {
qp['provider'] = provider;
}
if (clusterTemplateRevision) {
qp['clusterTemplateRevision'] = clusterTemplateRevision;
}
// Copied out of https://github.com/rancher/ui/blob/20f56dc54c4fc09b5f911e533cb751c13609adaf/app/models/cluster.js#L844
if ( provider === 'import' && isEmpty(this.eksConfig) && isEmpty(this.gkeConfig) ) {
qp.importProvider = 'other';
@ -168,10 +152,6 @@ export default class MgmtCluster extends SteveModel {
qp.importProvider = KONTAINER_TO_DRIVER[provider];
}
if ( this.clusterTemplateRevisionId ) {
qp.clusterTemplateRevision = this.clusterTemplateRevisionId;
}
const path = addParams(`/c/${ escape(this.id) }/edit`, qp);
return path;

View File

@ -4,37 +4,22 @@ import {
} from '@shell/config/types';
import { NAME as EXPLORER } from '@shell/config/product/explorer';
import { listNodeRoles } from '@shell/models/cluster/node';
import { insertAt } from '@shell/utils/array';
import { downloadUrl } from '@shell/utils/download';
import findLast from 'lodash/findLast';
import HybridModel from '@shell/plugins/steve/hybrid-class';
import { notOnlyOfRole } from '@shell/models/cluster.x-k8s.io.machine';
const RKE1_ALLOWED_ACTIONS = [
'goToViewYaml',
'download',
'viewInApi'
];
export default class MgmtNode extends HybridModel {
get _availableActions() {
const out = super._availableActions;
const downloadKeys = {
action: 'downloadKeys',
enabled: !!this.norman?.links?.nodeConfig,
icon: 'icon icon-fw icon-download',
label: this.t('node.actions.downloadNodeConfig'),
};
const scaleDown = {
action: 'scaleDown',
bulkAction: 'scaleDown',
enabled: !!this.canScaleDown,
icon: 'icon icon-minus icon-fw',
label: this.t('node.actions.scaleDown'),
bulkable: true,
};
insertAt(out, 0, { divider: true });
insertAt(out, 0, downloadKeys);
insertAt(out, 0, scaleDown);
return out;
return out.filter((a) => a.divider || RKE1_ALLOWED_ACTIONS.includes(a.action));
}
get kubeNodeName() {

View File

@ -3,7 +3,19 @@ import { sortBy } from '@shell/utils/sort';
import HybridModel from '@shell/plugins/steve/hybrid-class';
import { notOnlyOfRole } from '@shell/models/cluster.x-k8s.io.machine';
const RKE1_ALLOWED_ACTIONS = [
'goToViewYaml',
'download',
'viewInApi'
];
export default class MgmtNodePool extends HybridModel {
get _availableActions() {
const out = super._availableActions;
return out.filter((a) => a.divider || RKE1_ALLOWED_ACTIONS.includes(a.action));
}
get nodeTemplateId() {
return (this.spec?.nodeTemplateName || '').replace(/:/, '/');
}

View File

@ -12,6 +12,14 @@ import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
import { CAPI as CAPI_ANNOTATIONS, NODE_ARCHITECTURE } from '@shell/config/labels-annotations';
import { KEV1 } from '@shell/models/management.cattle.io.kontainerdriver';
const RKE1_ALLOWED_ACTIONS = [
'openShell',
'downloadKubeConfig',
'copyKubeConfig',
'download',
'viewInApi'
];
/**
* Class representing Cluster resource.
* @extends SteveModel
@ -41,17 +49,6 @@ export default class ProvCluster extends SteveModel {
},
].filter((x) => !!x.content);
// RKE Template details
const rkeTemplate = this.rkeTemplate;
if (rkeTemplate) {
out.push({
label: this.t('cluster.detail.rkeTemplate'),
formatter: 'RKETemplateName',
content: rkeTemplate,
});
}
if (!this.machineProvider) {
out.splice(1, 1);
@ -105,17 +102,6 @@ export default class ProvCluster extends SteveModel {
const canSnapshot = ready && ((this.isRke2 && this.canUpdate) || (this.isRke1 && this.mgmt?.hasAction('backupEtcd')));
const clusterTemplatesSchema = this.$getters['schemaFor']('management.cattle.io.clustertemplate');
let canUpdateClusterTemplate = false;
if (clusterTemplatesSchema && (clusterTemplatesSchema.resourceMethods?.includes('blocked-PUT') || clusterTemplatesSchema.resourceMethods?.includes('PUT'))) {
canUpdateClusterTemplate = true;
}
const normanClusterSaveTemplateAction = !!this.normanCluster?.actions?.saveAsTemplate;
const canSaveRKETemplate = this.isRke1 && this.mgmt?.status?.driver === 'rancherKubernetesEngine' && !this.mgmt?.spec?.clusterTemplateName && this.hasLink('update') && canUpdateClusterTemplate && normanClusterSaveTemplateAction;
const actions = [
// Note: Actions are not supported in the Steve API, so we check
// available actions for RKE1 clusters, but not RKE2 clusters.
@ -158,12 +144,7 @@ export default class ProvCluster extends SteveModel {
action: 'rotateEncryptionKey',
label: this.$rootGetters['i18n/t']('nav.rotateEncryptionKeys'),
icon: 'icon icon-refresh',
enabled: canEditRKE2cluster || (this.isRke1 && this.mgmt?.hasAction('rotateEncryptionKey') && ready)
}, {
action: 'saveAsRKETemplate',
label: this.$rootGetters['i18n/t']('nav.saveAsRKETemplate'),
icon: 'icon icon-folder',
enabled: canSaveRKETemplate,
enabled: canEditRKE2cluster
}, { divider: true }];
// Harvester Cluster 1:1 Harvester Cloud Cred
@ -190,6 +171,15 @@ export default class ProvCluster extends SteveModel {
}
}
// If RKE1, then remove most of the actions
if (this.isRke1) {
all.forEach((action) => {
if (!action.divider && !RKE1_ALLOWED_ACTIONS.includes(action.action)) {
action.enabled = false;
}
});
}
// If we have a helper that wants to modify the available actions, let it do it
if (this.customProvisionerHelper?.availableActions) {
// Provider can either modify the provided list or return one of its own
@ -813,13 +803,6 @@ export default class ProvCluster extends SteveModel {
this.$dispatch('promptRestore', [resource]);
}
saveAsRKETemplate(cluster = this) {
this.$dispatch('promptModal', {
componentProps: { cluster },
component: 'SaveAsRKETemplateDialog'
});
}
rotateCertificates(cluster = this) {
this.$dispatch('promptModal', {
componentProps: { cluster },
@ -861,40 +844,11 @@ export default class ProvCluster extends SteveModel {
return {
displayName: `${ template.spec?.displayName }/${ revision.spec?.displayName }`,
upgrade: this.rkeTemplateUpgrade,
template,
revision,
};
}
get rkeTemplateUpgrade() {
if (!this.isRke1 || !this.mgmt) {
// Not an RKE! cluster or no management cluster available
return false;
}
if (!this.mgmt.spec?.clusterTemplateRevisionName) {
// Cluster does not use an RKE template
return false;
}
const clusterTemplateRevisionName = this.mgmt.spec.clusterTemplateRevisionName.replace(':', '/');
// Get all of the template revisions for this template
const revisions = this.$rootGetters['management/all'](MANAGEMENT.RKE_TEMPLATE_REVISION).filter((t) => t.spec.enabled && t.spec.clusterTemplateName === this.mgmt.spec.clusterTemplateName);
if (revisions.length <= 1) {
// Only one template revision
return false;
}
revisions.sort((a, b) => {
return parseInt(a.metadata.resourceVersion, 10) - parseInt(b.metadata.resourceVersion, 10);
}).reverse();
return revisions[0].id !== clusterTemplateRevisionName ? revisions[0].spec?.displayName : false;
}
get _stateObj() {
if (!this.isRke2) {
return this.mgmt?.stateObj || this.metadata?.state;

View File

@ -671,6 +671,11 @@ export default defineComponent({
v-clean-tooltip="row.unavailableMachines"
class="conditions-alert-icon icon-alert icon"
/>
<i
v-if="row.isRke1"
v-clean-tooltip="t('cluster.rke1Unsupported')"
class="rke1-unsupported-icon icon-warning icon"
/>
</p>
<p
v-if="row.description"
@ -824,6 +829,11 @@ export default defineComponent({
color: var(--error);
margin-left: 4px;
}
.rke1-unsupported-icon {
color: var(--warning);
margin-left: 4px;
}
}
// Hide the side-panel showing links when the screen is small

View File

@ -28,7 +28,6 @@ export const mapFeature = function(name) {
export const MULTI_CLUSTER = create('multi-cluster-management', true);
export const LEGACY = create('legacy', false);
export const RKE2 = create('rke2', true);
export const RKE1_UI = create('rke1-ui', true);
export const UNSUPPORTED_STORAGE_DRIVERS = create('unsupported-storage-drivers', false);
export const FLEET = create('continuous-delivery', true);
export const HARVESTER = create('harvester', true);