From 31055fab98f34d2812a6233da216400d15ddc195 Mon Sep 17 00:00:00 2001 From: avanthakkar Date: Mon, 17 Jul 2023 23:41:51 +0530 Subject: [PATCH] mgr/dashboard: cluster upgrade start UI Fixes: https://tracker.ceph.com/issues/61928 Signed-off-by: avanthakkar --- .../src/app/ceph/cluster/cluster.module.ts | 4 +- .../upgrade-start-modal.component.html | 49 ++++++++++++++ .../upgrade-start-modal.component.scss | 0 .../upgrade-start-modal.component.spec.ts | 30 +++++++++ .../upgrade-start-modal.component.ts | 66 +++++++++++++++++++ .../cluster/upgrade/upgrade.component.html | 1 + .../cluster/upgrade/upgrade.component.spec.ts | 2 +- .../ceph/cluster/upgrade/upgrade.component.ts | 20 +++++- .../app/shared/api/upgrade.service.spec.ts | 7 ++ .../src/app/shared/api/upgrade.service.ts | 4 ++ .../src/app/shared/constants/app.constants.ts | 3 + 11 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.html create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.scss create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.ts diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/cluster.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/cluster.module.ts index d8bfde368b975..c94244e0682cd 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/cluster.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/cluster.module.ts @@ -58,6 +58,7 @@ import { ServiceFormComponent } from './services/service-form/service-form.compo import { ServicesComponent } from './services/services.component'; import { TelemetryComponent } from './telemetry/telemetry.component'; import { UpgradeComponent } from './upgrade/upgrade.component'; +import { UpgradeStartModalComponent } from './upgrade/upgrade-form/upgrade-start-modal.component'; @NgModule({ imports: [ @@ -118,7 +119,8 @@ import { UpgradeComponent } from './upgrade/upgrade.component'; PlacementPipe, CreateClusterComponent, CreateClusterReviewComponent, - UpgradeComponent + UpgradeComponent, + UpgradeStartModalComponent ], providers: [NgbActiveModal] }) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.html new file mode 100644 index 0000000000000..be12716f0e660 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.html @@ -0,0 +1,49 @@ + + + Upgrade Cluster  + + + +
+ + + +
+
+
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.scss new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.spec.ts new file mode 100644 index 0000000000000..cb68a3f1f515c --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.spec.ts @@ -0,0 +1,30 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UpgradeComponent } from '../upgrade.component'; +import { configureTestBed } from '~/testing/unit-test-helper'; +import { UpgradeService } from '~/app/shared/api/upgrade.service'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { SharedModule } from '~/app/shared/shared.module'; + +describe('UpgradeComponent', () => { + let component: UpgradeComponent; + let fixture: ComponentFixture; + + configureTestBed({ + imports: [HttpClientTestingModule, SharedModule], + schemas: [NO_ERRORS_SCHEMA], + declarations: [UpgradeComponent], + providers: [UpgradeService] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(UpgradeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.ts new file mode 100644 index 0000000000000..c601b776f5672 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component.ts @@ -0,0 +1,66 @@ +import { Component, OnInit } from '@angular/core'; +import { FormControl, Validators } from '@angular/forms'; +import { Observable } from 'rxjs'; + +import { Icons } from '~/app/shared/enum/icons.enum'; +import { Permission } from '~/app/shared/models/permissions'; +import { ActionLabelsI18n } from '~/app/shared/constants/app.constants'; +import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { UpgradeService } from '~/app/shared/api/upgrade.service'; +import { UpgradeInfoInterface } from '~/app/shared/models/upgrade.interface'; +import { NotificationType } from '~/app/shared/enum/notification-type.enum'; +import { CdFormGroup } from '~/app/shared/forms/cd-form-group'; +import { NotificationService } from '~/app/shared/services/notification.service'; + +@Component({ + selector: 'cd-upgrade-start-modal.component', + templateUrl: './upgrade-start-modal.component.html', + styleUrls: ['./upgrade-start-modal.component.scss'] +}) +export class UpgradeStartModalComponent implements OnInit { + permission: Permission; + upgradeInfoError$: Observable; + upgradeInfo$: Observable; + upgradeForm: CdFormGroup; + icons = Icons; + versions: string[]; + + constructor( + public actionLabels: ActionLabelsI18n, + private authStorageService: AuthStorageService, + public activeModal: NgbActiveModal, + private upgradeService: UpgradeService, + private notificationService: NotificationService + ) { + this.permission = this.authStorageService.getPermissions().configOpt; + } + + ngOnInit() { + this.upgradeForm = new CdFormGroup({ + availableVersions: new FormControl(null, [Validators.required]) + }); + } + + startUpgrade() { + this.upgradeService.start(this.upgradeForm.getValue('availableVersions')).subscribe({ + next: () => { + this.notificationService.show( + NotificationType.success, + $localize`Started upgrading the cluster` + ); + }, + error: (error) => { + this.upgradeForm.setErrors({ cdSubmitButton: true }); + this.notificationService.show( + NotificationType.error, + $localize`Failed to start the upgrade`, + error + ); + }, + complete: () => { + this.activeModal.close(); + } + }); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.html index 49dab51cc28c5..dd8f66950b3b0 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.html @@ -40,6 +40,7 @@ id="upgrade" aria-label="Upgrade now" [disabled]="(healthData.mgr_map | mgrSummary).total <= 1" + (click)="startUpgradeModal()" i18n>Upgrade now diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.spec.ts index d0d3997d6d582..0250fe9b122db 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.spec.ts @@ -56,7 +56,7 @@ describe('UpgradeComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(UpgradeComponent); component = fixture.componentInstance; - upgradeInfoSpy = spyOn(TestBed.inject(UpgradeService), 'list'); + upgradeInfoSpy = spyOn(TestBed.inject(UpgradeService), 'list').and.callFake(() => of(null)); getHealthSpy = spyOn(TestBed.inject(HealthService), 'getMinimalHealth'); getHealthSpy.and.returnValue(of(healthPayload)); fixture.detectChanges(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.ts index e45914afd1a11..b779a213d6031 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.ts @@ -1,13 +1,16 @@ import { Component, OnInit } from '@angular/core'; import { Observable, of } from 'rxjs'; -import { catchError, ignoreElements } from 'rxjs/operators'; +import { catchError, ignoreElements, tap } from 'rxjs/operators'; import { HealthService } from '~/app/shared/api/health.service'; import { UpgradeService } from '~/app/shared/api/upgrade.service'; import { Icons } from '~/app/shared/enum/icons.enum'; import { Permission } from '~/app/shared/models/permissions'; import { UpgradeInfoInterface } from '~/app/shared/models/upgrade.interface'; import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { SummaryService } from '~/app/shared/services/summary.service'; +import { ModalService } from '~/app/shared/services/modal.service'; +import { UpgradeStartModalComponent } from './upgrade-form/upgrade-start-modal.component'; @Component({ selector: 'cd-upgrade', @@ -21,10 +24,13 @@ export class UpgradeComponent implements OnInit { permission: Permission; healthData$: Observable; fsid$: Observable; + modalRef: NgbModalRef; + upgradableVersions: string[]; icons = Icons; constructor( + private modalService: ModalService, private summaryService: SummaryService, private upgradeService: UpgradeService, private authStorageService: AuthStorageService, @@ -38,7 +44,11 @@ export class UpgradeComponent implements OnInit { const version = summary.version.replace('ceph version ', '').split('-'); this.version = version[0]; }); - this.upgradeInfo$ = this.upgradeService.list(); + this.upgradeInfo$ = this.upgradeService + .list() + .pipe( + tap((upgradeInfo: UpgradeInfoInterface) => (this.upgradableVersions = upgradeInfo.versions)) + ); this.upgradeInfoError$ = this.upgradeInfo$?.pipe( ignoreElements(), catchError((error) => of(error)) @@ -46,4 +56,10 @@ export class UpgradeComponent implements OnInit { this.healthData$ = this.healthService.getMinimalHealth(); this.fsid$ = this.healthService.getClusterFsid(); } + + startUpgradeModal() { + this.modalRef = this.modalService.show(UpgradeStartModalComponent, { + versions: this.upgradableVersions.sort() + }); + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/upgrade.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/upgrade.service.spec.ts index 3bfc2bef3829b..5acd490cfe764 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/upgrade.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/upgrade.service.spec.ts @@ -57,4 +57,11 @@ describe('UpgradeService', () => { expectedVersions ); }); + + it('should start the upgrade', () => { + service.start('18.1.0').subscribe(); + const req = httpTesting.expectOne('api/cluster/upgrade/start'); + expect(req.request.method).toBe('POST'); + expect(req.request.body).toEqual({ version: '18.1.0' }); + }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/upgrade.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/upgrade.service.ts index c510164148c72..6e713ae512299 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/upgrade.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/upgrade.service.ts @@ -41,4 +41,8 @@ export class UpgradeService extends ApiClient { upgradeInfo.versions = upgradableVersions; return upgradeInfo; } + + start(version: string) { + return this.http.post(`${this.baseURL}/start`, { version: version }); + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts index aec37abad607d..d299f59fefd0e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts @@ -140,6 +140,7 @@ export class ActionLabelsI18n { EXPORT: string; IMPORT: any; MIGRATE: string; + START_UPGRADE: string; constructor() { /* Create a new item */ @@ -215,6 +216,8 @@ export class ActionLabelsI18n { this.REMOVE_SCHEDULING = $localize`Remove Scheduling`; this.PROMOTE = $localize`Promote`; this.DEMOTE = $localize`Demote`; + + this.START_UPGRADE = $localize`Start Upgrade`; } } -- 2.39.5