From 95e20d27b3d0e861ff572481e9426f09e386c6d8 Mon Sep 17 00:00:00 2001 From: Pedro Gonzalez Gomez Date: Mon, 1 Aug 2022 22:17:29 +0200 Subject: [PATCH] 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 --- .../mgr/dashboard/controllers/cluster.py | 4 +++ .../dashboard-pie.component.html | 16 +++++++++++ .../dashboard-pie.component.scss | 22 +++++++++++++++ .../dashboard-pie.component.spec.ts | 27 +++++++++++++++++++ .../ceph/new-dashboard/dashboard.module.ts | 3 ++- .../dashboard/dashboard.component.html | 12 ++++----- .../dashboard/dashboard.component.spec.ts | 16 ++++++++--- .../dashboard/dashboard.component.ts | 14 +++++++++- .../src/app/shared/api/cluster.service.ts | 4 +++ .../styles/defaults/_bootstrap-defaults.scss | 6 ++++- src/pybind/mgr/dashboard/openapi.yaml | 22 +++++++++++++++ src/pybind/mgr/dashboard/services/cluster.py | 14 ++++++++++ 12 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.html create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.scss create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/new-dashboard/dashboard-pie/dashboard-pie.component.spec.ts diff --git a/src/pybind/mgr/dashboard/controllers/cluster.py b/src/pybind/mgr/dashboard/controllers/cluster.py index d8170e672e992..5d776e063513d 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 0000000000000..ba8176beab3b5 --- /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 0000000000000..64e7a9822e22d --- /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 0000000000000..892913dab6bea --- /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 27ed0f2d76054..34d41ddb31adb 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 8065bb860c6ba..b910f2f856b79 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 8e981a933cc1b..113ac8cfe956f 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 a43b319e00ad6..1864c0e729a24 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 6b435d6ffed1d..f5b8e4d7cc118 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 941f639a363c1..f871b4ff80f8e 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 d607cfb066884..a85740ef56df6 100644 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -2145,6 +2145,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/user: get: description: "\n Get list of ceph users and its respective data\n \ diff --git a/src/pybind/mgr/dashboard/services/cluster.py b/src/pybind/mgr/dashboard/services/cluster.py index a057f24381f78..fbb00bc737070 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() -- 2.39.5