diff options
author | Pedro Gonzalez Gomez <pegonzal@redhat.com> | 2024-05-15 20:23:46 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-15 20:23:46 +0200 |
commit | 196e2c9605b3a293d1e01e071f919d0b74a4d651 (patch) | |
tree | 42e71f67d38b8bfbbc9f5de0561944822adb5748 /src/pybind | |
parent | Merge PR #57478 into main (diff) | |
parent | mgr/dashboard: add upgrade notification (diff) | |
download | ceph-196e2c9605b3a293d1e01e071f919d0b74a4d651.tar.xz ceph-196e2c9605b3a293d1e01e071f919d0b74a4d651.zip |
Merge pull request #56349 from rhcs-dashboard/add-landing-page-upgrade-notification
mgr/dashboard: add upgrade notification
Reviewed-by: Ankush Behl <cloudbehl@gmail.com>
Reviewed-by: Nizamudeen A <nia@redhat.com>
Diffstat (limited to 'src/pybind')
11 files changed, 175 insertions, 30 deletions
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 b1867c3bb0c..5db15a42b51 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 @@ -22,7 +22,7 @@ <ng-template #inProgress> <h5 i18n> <i [ngClass]="[icons.spin, icons.spinner]"></i> - Upgrade in progress {{executingTasks?.progress}}% + Upgrading {{executingTasks?.progress}}% </h5> </ng-template> </ng-container> 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 46b1d99204c..8c3e1c9eb28 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 @@ -68,7 +68,9 @@ describe('UpgradeComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(UpgradeComponent); component = fixture.componentInstance; - upgradeInfoSpy = spyOn(TestBed.inject(UpgradeService), 'list').and.callFake(() => of(null)); + upgradeInfoSpy = spyOn(TestBed.inject(UpgradeService), 'listCached').and.callFake(() => + of(null) + ); getHealthSpy = spyOn(TestBed.inject(HealthService), 'getMinimalHealth'); upgradeStatusSpy = spyOn(TestBed.inject(UpgradeService), 'status'); getHealthSpy.and.returnValue(of(healthPayload)); 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 0f1f2318a5e..80ae0c4aada 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,6 +1,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Observable, ReplaySubject, Subscription, of } from 'rxjs'; -import { catchError, publishReplay, refCount, shareReplay, switchMap, tap } from 'rxjs/operators'; +import { catchError, shareReplay, switchMap } from 'rxjs/operators'; import { DaemonService } from '~/app/shared/api/daemon.service'; import { HealthService } from '~/app/shared/api/health.service'; import { UpgradeService } from '~/app/shared/api/upgrade.service'; @@ -13,8 +13,6 @@ import { UpgradeInfoInterface } from '~/app/shared/models/upgrade.interface'; import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { NotificationService } from '~/app/shared/services/notification.service'; 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'; import { ExecutingTask } from '~/app/shared/models/executing-task'; import { Router } from '@angular/router'; import { RefreshIntervalService } from '~/app/shared/services/refresh-interval.service'; @@ -43,9 +41,9 @@ export class UpgradeComponent implements OnInit, OnDestroy { upgradeStatus$: Observable<any>; subject = new ReplaySubject<any>(); + private subs = new Subscription(); constructor( - private modalService: ModalService, private summaryService: SummaryService, private upgradeService: UpgradeService, private healthService: HealthService, @@ -76,22 +74,21 @@ export class UpgradeComponent implements OnInit, OnDestroy { } ]; - this.summaryService.subscribe((summary) => { - const version = summary.version.replace('ceph version ', '').split('-'); - this.version = version[0]; - this.executingTasks = summary.executing_tasks.filter((tasks) => - tasks.name.includes('progress/Upgrade') - )[0]; - }); + this.subs.add( + this.summaryService.subscribe((summary) => { + const version = summary.version.replace('ceph version ', '').split('-'); + this.version = version[0]; + this.executingTasks = summary.executing_tasks.filter((tasks) => + tasks.name.includes('progress/Upgrade') + )[0]; + }) + ); this.interval = this.refreshIntervalService.intervalData$.subscribe(() => { this.fetchStatus(); }); - this.info$ = this.upgradeService.list().pipe( - tap((upgradeInfo: UpgradeInfoInterface) => (this.upgradableVersions = upgradeInfo.versions)), - publishReplay(1), - refCount(), + this.info$ = this.upgradeService.listCached().pipe( catchError((err) => { err.preventDefault(); this.errorMessage = $localize`Not retrieving upgrades`; @@ -110,9 +107,7 @@ export class UpgradeComponent implements OnInit, OnDestroy { } startUpgradeModal() { - this.modalRef = this.modalService.show(UpgradeStartModalComponent, { - versions: this.upgradableVersions - }); + this.modalRef = this.upgradeService.startUpgradeModal(); } fetchStatus() { @@ -141,5 +136,6 @@ export class UpgradeComponent implements OnInit, OnDestroy { ngOnDestroy() { this.interval?.unsubscribe(); + this.subs?.unsubscribe(); } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html index 17df92f3f24..46aa67721dd 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html @@ -17,7 +17,10 @@ <dt>Orchestrator</dt> <dd i18n>{{ detailsCardData.orchestrator || 'Orchestrator is not available' }}</dd> <dt>Ceph version</dt> - <dd>{{ detailsCardData.cephVersion }}</dd> + <dd> + {{ detailsCardData.cephVersion }} + <cd-upgradable></cd-upgradable> + </dd> <dt>Cluster API</dt> <dd> <a routerLink="/api-docs" diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts index 9b3c050064f..aa3190bc1c5 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts @@ -78,6 +78,7 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit hardwareSummary$: Observable<any>; hardwareSubject = new BehaviorSubject<any>([]); managedByConfig$: Observable<any>; + private subs = new Subscription(); constructor( private summaryService: SummaryService, @@ -133,6 +134,7 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit ngOnDestroy() { this.interval.unsubscribe(); this.prometheusService.unsubscribe(); + this.subs?.unsubscribe(); } getHealth() { @@ -152,11 +154,13 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit this.orchestratorService.getName().subscribe((data: string) => { this.detailsCardData.orchestrator = data; }); - this.summaryService.subscribe((summary) => { - const version = summary.version.replace('ceph version ', '').split(' '); - this.detailsCardData.cephVersion = - version[0] + ' ' + version.slice(2, version.length).join(' '); - }); + this.subs.add( + this.summaryService.subscribe((summary) => { + const version = summary.version.replace('ceph version ', '').split(' '); + this.detailsCardData.cephVersion = + version[0] + ' ' + version.slice(2, version.length).join(' '); + }) + ); } getCapacityCardData() { 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 9aa25aa1614..3a2e6dc0fad 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 @@ -1,10 +1,15 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { ApiClient } from './api-client'; -import { map } from 'rxjs/operators'; +import { map, shareReplay, tap } from 'rxjs/operators'; import { SummaryService } from '../services/summary.service'; import { UpgradeInfoInterface, UpgradeStatusInterface } from '../models/upgrade.interface'; import { Observable } from 'rxjs'; +import { UpgradeStartModalComponent } from '~/app/ceph/cluster/upgrade/upgrade-form/upgrade-start-modal.component'; +import { ModalService } from '../services/modal.service'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; + +const CACHE_SIZE = 1; @Injectable({ providedIn: 'root' @@ -25,7 +30,14 @@ export class UpgradeService extends ApiClient { 'nfs' ]; - constructor(private http: HttpClient, private summaryService: SummaryService) { + _listData$: Observable<UpgradeInfoInterface>; + _upgradableVersions: string[]; + + constructor( + private http: HttpClient, + private summaryService: SummaryService, + private modalService: ModalService + ) { super(); } @@ -75,4 +87,22 @@ export class UpgradeService extends ApiClient { status(): Observable<UpgradeStatusInterface> { return this.http.get<UpgradeStatusInterface>(`${this.baseURL}/status`); } + + listCached(): Observable<UpgradeInfoInterface> { + if (!this._listData$) { + this._listData$ = this.list().pipe( + tap( + (upgradeInfo: UpgradeInfoInterface) => (this._upgradableVersions = upgradeInfo.versions) + ), + shareReplay(CACHE_SIZE) + ); + } + return this._listData$; + } + + startUpgradeModal(): NgbModalRef { + return this.modalService.show(UpgradeStartModalComponent, { + versions: this._upgradableVersions + }); + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts index d70776dfd86..d6943b0c71a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts @@ -56,6 +56,7 @@ import { VerticalNavigationComponent } from './vertical-navigation/vertical-navi import { CardGroupComponent } from './card-group/card-group.component'; import { HelpTextComponent } from './help-text/help-text.component'; import { FormAdvancedFieldsetComponent } from './form-advanced-fieldset/form-advanced-fieldset.component'; +import { UpgradableComponent } from './upgradable/upgradable.component'; @NgModule({ imports: [ @@ -115,7 +116,8 @@ import { FormAdvancedFieldsetComponent } from './form-advanced-fieldset/form-adv VerticalNavigationComponent, CardGroupComponent, HelpTextComponent, - FormAdvancedFieldsetComponent + FormAdvancedFieldsetComponent, + UpgradableComponent ], providers: [], exports: [ @@ -152,7 +154,8 @@ import { FormAdvancedFieldsetComponent } from './form-advanced-fieldset/form-adv VerticalNavigationComponent, CardGroupComponent, HelpTextComponent, - FormAdvancedFieldsetComponent + FormAdvancedFieldsetComponent, + UpgradableComponent ] }) export class ComponentsModule {} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.html new file mode 100644 index 00000000000..173df9b6871 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.html @@ -0,0 +1,26 @@ +<div *ngIf="upgradeStatus$ | async as status; else isUpgradable"> + <ng-container *ngIf="status.is_paused || status.in_progress; else isUpgradable"> + <h5 *ngIf="status.is_paused; else inProgress" + i18n> + Upgrade is paused + </h5> + <ng-template #inProgress> + <a href="#/upgrade/progress" + i18n> + <i [ngClass]="[icons.spin, icons.spinner]"></i> + Upgrading {{executingTask?.progress}}% + </a> + </ng-template> + </ng-container> +</div> + +<ng-template #isUpgradable> + <div *ngIf="upgradeInfo$ | async as info" + i18n> + <h5 *ngIf="info.versions.length > 0" + (click)="upgradeModal()"> + <i [ngClass]="icons.up"></i> + Upgrade available + </h5> + </div> +</ng-template> diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.scss new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.scss diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.spec.ts new file mode 100644 index 00000000000..11fa498c9b4 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UpgradableComponent } from './upgradable.component'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; + +describe('UpgradableComponent', () => { + let component: UpgradableComponent; + let fixture: ComponentFixture<UpgradableComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [UpgradableComponent], + imports: [HttpClientTestingModule] + }).compileComponents(); + + fixture = TestBed.createComponent(UpgradableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.ts new file mode 100644 index 00000000000..d478df25d8a --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.ts @@ -0,0 +1,57 @@ +import { Component } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { Observable, Subscription } from 'rxjs'; +import { UpgradeService } from '../../api/upgrade.service'; +import { UpgradeInfoInterface, UpgradeStatusInterface } from '../../models/upgrade.interface'; +import { OrchestratorService } from '../../api/orchestrator.service'; +import { Icons } from '~/app/shared/enum/icons.enum'; +import { SummaryService } from '../../services/summary.service'; +import { ExecutingTask } from '../../models/executing-task'; + +@Component({ + selector: 'cd-upgradable', + templateUrl: './upgradable.component.html', + styleUrls: ['./upgradable.component.scss'] +}) +export class UpgradableComponent { + orchAvailable: boolean = false; + upgradeInfo$: Observable<UpgradeInfoInterface>; + upgradeStatus$: Observable<UpgradeStatusInterface>; + upgradeModalRef: NgbModalRef; + executingTask: ExecutingTask; + private subs = new Subscription(); + + icons = Icons; + + constructor( + private orchestratorService: OrchestratorService, + private summaryService: SummaryService, + private upgradeService: UpgradeService + ) {} + + ngOnInit() { + this.orchestratorService.status().subscribe((status: any) => { + this.orchAvailable = status.available; + if (this.orchAvailable && status.upgrade_status?.available) { + this.upgradeInfo$ = this.upgradeService.listCached(); + this.upgradeStatus$ = this.upgradeService.status(); + } + }); + + this.subs.add( + this.summaryService.subscribe((summary) => { + this.executingTask = summary.executing_tasks.filter((tasks) => + tasks.name.includes('progress/Upgrade') + )[0]; + }) + ); + } + + ngOnDestroy() { + this.subs?.unsubscribe(); + } + + upgradeModal() { + this.upgradeModalRef = this.upgradeService.startUpgradeModal(); + } +} |