From: Pedro Gonzalez Gomez Date: Mon, 1 Aug 2022 20:17:29 +0000 (+0200) Subject: xmgr/dashboard: dashboard-v3: capacity card X-Git-Tag: v17.2.7~523^2~6 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=56526d4c334476e7583b9fbe3fb764417ff5eb08;p=ceph.git xmgr/dashboard: dashboard-v3: capacity card tracker: https://tracker.ceph.com/issues/57862 Signed-off-by: Pedro Gonzalez Gomez mgr/dashboard: fix openapi tox error Signed-off-by: Pedro Gonzalez Gomez mgr/dashboard: capacity-card set interval and display bytes used Signed-off-by: Pedro Gonzalez Gomez mgr/dashboard: Landing Page v3 Signed-off-by: Pedro Gonzalez Gomez (cherry picked from commit 95e20d27b3d0e861ff572481e9426f09e386c6d8) --- diff --git a/src/pybind/mgr/dashboard/controllers/cluster.py b/src/pybind/mgr/dashboard/controllers/cluster.py index d8170e672e99..5d776e063513 100644 --- a/src/pybind/mgr/dashboard/controllers/cluster.py +++ b/src/pybind/mgr/dashboard/controllers/cluster.py @@ -19,3 +19,7 @@ class Cluster(RESTController): parameters={'status': (str, 'Cluster Status')}) def singleton_set(self, status: str): ClusterModel(status).to_db() + + @RESTController.Collection('GET', 'capacity') + def get_capacity(self): + return ClusterModel.get_capacity() diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.html new file mode 100644 index 000000000000..ba8176beab3b --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.html @@ -0,0 +1,16 @@ +
+ + +
+
+
+
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.scss new file mode 100644 index 000000000000..64e7a9822e22 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.scss @@ -0,0 +1,22 @@ +@use './src/styles/chart-tooltip'; + +$canvas-width: 100%; +$canvas-height: 100%; + +.chart-container { + height: $canvas-height; + margin-left: auto; + margin-right: auto; + position: unset; + width: $canvas-width; +} + +.chart-canvas { + height: $canvas-height; + margin-left: auto; + margin-right: auto; + max-height: $canvas-height; + max-width: $canvas-width; + position: unset; + width: $canvas-width; +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.spec.ts new file mode 100644 index 000000000000..892913dab6be --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.spec.ts @@ -0,0 +1,27 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CssHelper } from '~/app/shared/classes/css-helper'; +import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe'; +import { configureTestBed } from '~/testing/unit-test-helper'; +import { DashboardPieComponent } from './dashboard-pie.component'; + +describe('DashboardPieComponent', () => { + let component: DashboardPieComponent; + let fixture: ComponentFixture; + + configureTestBed({ + schemas: [NO_ERRORS_SCHEMA], + declarations: [DashboardPieComponent], + providers: [CssHelper, DimlessBinaryPipe] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DashboardPieComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard.module.ts index 27ed0f2d7605..34d41ddb31ad 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard.module.ts @@ -9,6 +9,7 @@ import { ChartsModule } from 'ng2-charts'; import { SharedModule } from '~/app/shared/shared.module'; import { CephSharedModule } from '../shared/ceph-shared.module'; import { CardComponent } from './card/card.component'; +import { DashboardPieComponent } from './dashboard-pie/dashboard-pie.component'; import { DashboardComponent } from './dashboard/dashboard.component'; @NgModule({ @@ -24,6 +25,6 @@ import { DashboardComponent } from './dashboard/dashboard.component'; ReactiveFormsModule ], - declarations: [DashboardComponent, CardComponent] + declarations: [DashboardComponent, CardComponent, DashboardPieComponent] }) export class NewDashboardModule {} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.html index 8065bb860c6b..b910f2f856b7 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.html @@ -79,13 +79,11 @@ class="col-sm-3 px-3" [ngClass]="{'d-flex': flexHeight}"> - - - - + *ngIf="capacity && osdSettings"> + + diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.spec.ts index 8e981a933cc1..113ac8cfe956 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.spec.ts @@ -1,13 +1,18 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; import { BehaviorSubject, of } from 'rxjs'; import { ConfigurationService } from '~/app/shared/api/configuration.service'; import { MgrModuleService } from '~/app/shared/api/mgr-module.service'; +import { CssHelper } from '~/app/shared/classes/css-helper'; +import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe'; import { SummaryService } from '~/app/shared/services/summary.service'; import { configureTestBed } from '~/testing/unit-test-helper'; import { CardComponent } from '../card/card.component'; +import { DashboardPieComponent } from '../dashboard-pie/dashboard-pie.component'; import { DashboardComponent } from './dashboard.component'; export class SummaryServiceMock { @@ -47,9 +52,14 @@ describe('CardComponent', () => { }; configureTestBed({ - imports: [HttpClientTestingModule], - declarations: [DashboardComponent, CardComponent], - providers: [{ provide: SummaryService, useClass: SummaryServiceMock }] + imports: [RouterTestingModule, HttpClientTestingModule], + declarations: [DashboardComponent, CardComponent, DashboardPieComponent], + schemas: [NO_ERRORS_SCHEMA], + providers: [ + CssHelper, + DimlessBinaryPipe, + { provide: SummaryService, useClass: SummaryServiceMock } + ] }); beforeEach(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.ts index a43b319e00ad..1864c0e729a2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard/dashboard.component.ts @@ -1,8 +1,20 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import _ from 'lodash'; +import { Observable, Subscription } from 'rxjs'; +import { take } from 'rxjs/operators'; + +import { ClusterService } from '~/app/shared/api/cluster.service'; import { ConfigurationService } from '~/app/shared/api/configuration.service'; import { MgrModuleService } from '~/app/shared/api/mgr-module.service'; +import { OsdService } from '~/app/shared/api/osd.service'; import { DashboardDetails } from '~/app/shared/models/cd-details'; +import { Permissions } from '~/app/shared/models/permissions'; +import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; +import { + FeatureTogglesMap$, + FeatureTogglesService +} from '~/app/shared/services/feature-toggles.service'; import { SummaryService } from '~/app/shared/services/summary.service'; @Component({ diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cluster.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cluster.service.ts index 6b435d6ffed1..f5b8e4d7cc11 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cluster.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cluster.service.ts @@ -24,4 +24,8 @@ export class ClusterService { { headers: { Accept: 'application/vnd.ceph.api.v0.1+json' } } ); } + + getCapacity() { + return this.http.get(`${this.baseURL}/capacity`, {}); + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss b/src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss index 941f639a363c..f871b4ff80f8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss +++ b/src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss @@ -67,7 +67,6 @@ $body-color-bright: $light !default; $body-bg: $white !default; $body-color: $gray-900 !default; $body-bg-alt: $gray-200 !default; - // Health colors. $health-color-error: $red !default; $health-color-healthy: $green !default; @@ -82,7 +81,12 @@ $chart-color-yellow: #f6d173 !default; $chart-color-green: $green !default; $chart-color-gray: #ededed !default; $chart-color-cyan: $primary-500 !default; +$chart-color-light-gray: #f0f0f0 !default; +$chart-color-slight-dark-gray: #d7d7d7 !default; +$chart-color-dark-gray: #afafaf !default; +$chart-color-cyan: #73c5c5 !default; $chart-color-purple: #3c3d99 !default; +$chart-color-white: #fff !default; $chart-color-center-text: #151515 !default; $chart-color-center-text-description: #72767b !default; $chart-color-tooltip-background: $black !default; diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index 288d0beb3df7..eda3c2925bf2 100644 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -2137,6 +2137,28 @@ paths: summary: Update the cluster status tags: - Cluster + /api/cluster/capacity: + get: + parameters: [] + responses: + '200': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: OK + '400': + description: Operation exception. Please check the response body for details. + '401': + description: Unauthenticated access. Please login first. + '403': + description: Unauthorized access. Please check your permissions. + '500': + description: Unexpected error. Please check the response body for the stack + trace. + security: + - jwt: [] + tags: + - Cluster /api/cluster_conf: get: parameters: [] diff --git a/src/pybind/mgr/dashboard/services/cluster.py b/src/pybind/mgr/dashboard/services/cluster.py index a057f24381f7..fbb00bc73707 100644 --- a/src/pybind/mgr/dashboard/services/cluster.py +++ b/src/pybind/mgr/dashboard/services/cluster.py @@ -1,9 +1,16 @@ # -*- coding: utf-8 -*- from enum import Enum +from typing import NamedTuple from .. import mgr +class ClusterCapacity(NamedTuple): + total_avail_bytes: int + total_bytes: int + total_used_raw_bytes: int + + class ClusterModel: class Status(Enum): @@ -33,3 +40,10 @@ class ClusterModel: If the status is not set, assume it is already fully functional. """ return cls(status=mgr.get_store('cluster/status', cls.Status.POST_INSTALLED.name)) + + @classmethod + def get_capacity(cls) -> ClusterCapacity: + df = mgr.get('df') + return ClusterCapacity(total_avail_bytes=df['stats']['total_avail_bytes'], + total_bytes=df['stats']['total_bytes'], + total_used_raw_bytes=df['stats']['total_used_raw_bytes'])._asdict()