summaryrefslogtreecommitdiffstats
path: root/src/pybind
diff options
context:
space:
mode:
authorPedro Gonzalez Gomez <pegonzal@redhat.com>2024-05-15 20:23:46 +0200
committerGitHub <noreply@github.com>2024-05-15 20:23:46 +0200
commit196e2c9605b3a293d1e01e071f919d0b74a4d651 (patch)
tree42e71f67d38b8bfbbc9f5de0561944822adb5748 /src/pybind
parentMerge PR #57478 into main (diff)
parentmgr/dashboard: add upgrade notification (diff)
downloadceph-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')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.html2
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.spec.ts4
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.ts32
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html5
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts14
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/api/upgrade.service.ts34
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts7
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.html26
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.scss0
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.spec.ts24
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/components/upgradable/upgradable.component.ts57
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();
+ }
+}