From ce82044908f30b124976b85363b85de6791105a8 Mon Sep 17 00:00:00 2001 From: Avan Thakkar Date: Wed, 21 Oct 2020 22:34:34 +0530 Subject: [PATCH] mgr/dashboard: update QoS values when editing a Pool/RBD image Fixes: https://tracker.ceph.com/issues/47900 Signed-off-by: Avan Thakkar --- .../integration/pools/pools.e2e-spec.ts | 10 ++++++++-- .../cypress/integration/pools/pools.po.ts | 18 ++++++++++++++++++ .../rbd-configuration-form.component.spec.ts | 17 +++++++++-------- .../rbd-configuration-form.component.ts | 16 ++++++++++++---- .../ceph/block/rbd-form/rbd-form.component.ts | 8 ++++---- .../ceph/pool/pool-form/pool-form.component.ts | 10 +++++----- 6 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/pools/pools.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/pools/pools.e2e-spec.ts index fd2217579a5..ff925b8a36e 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/integration/pools/pools.e2e-spec.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/integration/pools/pools.e2e-spec.ts @@ -2,7 +2,7 @@ import { PoolPageHelper } from './pools.po'; describe('Pools page', () => { const pools = new PoolPageHelper(); - const poolName = 'pool_e2e_pool/test'; + const poolName = 'pool_e2e_pool-test'; beforeEach(() => { cy.login(); @@ -31,7 +31,7 @@ describe('Pools page', () => { it('should create a pool', () => { pools.exist(poolName, false); pools.navigateTo('create'); - pools.create(poolName, 8); + pools.create(poolName, 8, 'rbd'); pools.exist(poolName, true); }); @@ -40,6 +40,12 @@ describe('Pools page', () => { pools.edit_pool_pg(poolName, 32); }); + it('should show updated configuration field values', () => { + pools.exist(poolName, true); + const bpsLimit = '4 B/s'; + pools.edit_pool_configuration(poolName, bpsLimit); + }); + it('should delete a pool', () => { pools.delete(poolName); }); diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/pools/pools.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/pools/pools.po.ts index 138bcd72d2f..ccf858b4120 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/integration/pools/pools.po.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/integration/pools/pools.po.ts @@ -47,6 +47,24 @@ export class PoolPageHelper extends PageHelper { } } + edit_pool_configuration(name: string, bpsLimit: string) { + this.navigateEdit(name); + + cy.get('.collapsible').click(); + cy.get('cd-rbd-configuration-form') + .get('input[name=rbd_qos_bps_limit]') + .clear() + .type(`${bpsLimit}`); + cy.get('cd-submit-button').click(); + + this.navigateEdit(name); + + cy.get('.collapsible').click(); + cy.get('cd-rbd-configuration-form') + .get('input[name=rbd_qos_bps_limit]') + .should('have.value', bpsLimit); + } + private setApplications(apps: string[]) { if (!apps || apps.length === 0) { return; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.spec.ts index ef55b4808ae..833a649daca 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.spec.ts @@ -1,8 +1,9 @@ -import { EventEmitter } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; +import { ReplaySubject } from 'rxjs'; + import { DirectivesModule } from '~/app/shared/directives/directives.module'; import { CdFormGroup } from '~/app/shared/forms/cd-form-group'; import { RbdConfigurationSourceField } from '~/app/shared/models/configuration'; @@ -66,7 +67,7 @@ describe('RbdConfigurationFormComponent', () => { describe('test loading of initial data for editing', () => { beforeEach(() => { - component.initializeData = new EventEmitter(); + component.initializeData = new ReplaySubject(1); fixture.detectChanges(); component.ngOnInit(); }); @@ -85,7 +86,7 @@ describe('RbdConfigurationFormComponent', () => { }); it('should load initial data into forms', () => { - component.initializeData.emit({ + component.initializeData.next({ initialData: [ { name: 'rbd_qos_bps_limit', @@ -100,7 +101,7 @@ describe('RbdConfigurationFormComponent', () => { }); it('should not load initial data if the source is not the pool itself', () => { - component.initializeData.emit({ + component.initializeData.next({ initialData: [ { name: 'rbd_qos_bps_limit', @@ -121,7 +122,7 @@ describe('RbdConfigurationFormComponent', () => { }); it('should not load initial data if the source is not the image itself', () => { - component.initializeData.emit({ + component.initializeData.next({ initialData: [ { name: 'rbd_qos_bps_limit', @@ -142,7 +143,7 @@ describe('RbdConfigurationFormComponent', () => { }); it('should always have formatted results', () => { - component.initializeData.emit({ + component.initializeData.next({ initialData: [ { name: 'rbd_qos_bps_limit', @@ -204,7 +205,7 @@ describe('RbdConfigurationFormComponent', () => { let data: any; beforeEach(() => { - component.initializeData = new EventEmitter(); + component.initializeData = new ReplaySubject(1); fixture.detectChanges(); component.ngOnInit(); data = { @@ -247,7 +248,7 @@ describe('RbdConfigurationFormComponent', () => { ], sourceType: RbdConfigurationSourceField.image }; - component.initializeData.emit(data); + component.initializeData.next(data); }); it('should return an empty object', () => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.ts index 5c282118c9b..3ced71f0264 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.ts @@ -1,6 +1,9 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; +import _ from 'lodash'; +import { ReplaySubject } from 'rxjs'; + import { Icons } from '~/app/shared/enum/icons.enum'; import { CdFormGroup } from '~/app/shared/forms/cd-form-group'; import { @@ -20,10 +23,10 @@ export class RbdConfigurationFormComponent implements OnInit { @Input() form: CdFormGroup; @Input() - initializeData: EventEmitter<{ + initializeData = new ReplaySubject<{ initialData: RbdConfigurationEntry[]; sourceType: RbdConfigurationSourceField; - }>; + }>(1); @Output() changes = new EventEmitter(); @@ -52,7 +55,6 @@ export class RbdConfigurationFormComponent implements OnInit { this.initializeData.subscribe((data: Record) => { this.initialData = data.initialData; const dataType = data.sourceType; - this.rbdConfigurationService.getWritableOptionFields().forEach((option) => { const optionData = data.initialData .filter((entry: Record) => entry.name === option.name) @@ -117,7 +119,13 @@ export class RbdConfigurationFormComponent implements OnInit { c.type === RbdConfigurationType.iops || c.type === RbdConfigurationType.bps ) { - control = new FormControl(0, Validators.min(0)); + let initialValue = 0; + _.forEach(this.initialData, (configList) => { + if (configList['name'] === c.name) { + initialValue = configList['value']; + } + }); + control = new FormControl(initialValue, Validators.min(0)); } else { throw new Error( `Type ${c.type} is unknown, you may need to add it to RbdConfiguration class` diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts index f98f790d680..1dc1df0dd3a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { FormControl, ValidatorFn, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; @@ -60,10 +60,10 @@ export class RbdFormComponent extends CdForm implements OnInit { allDataPools: Array = []; features: { [key: string]: RbdImageFeature }; featuresList: RbdImageFeature[] = []; - initializeConfigData = new EventEmitter<{ + initializeConfigData = new ReplaySubject<{ initialData: RbdConfigurationEntry[]; sourceType: RbdConfigurationSourceField; - }>(); + }>(1); pool: string; @@ -559,7 +559,7 @@ export class RbdFormComponent extends CdForm implements OnInit { .setValue(this.dimlessBinaryPipe.transform(response.stripe_unit)); this.rbdForm.get('stripingCount').setValue(response.stripe_count); /* Configuration */ - this.initializeConfigData.emit({ + this.initializeConfigData.next({ initialData: this.response.configuration, sourceType: RbdConfigurationSourceField.image }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.ts index ad70234dcea..bf4c206e2f4 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.ts @@ -1,10 +1,10 @@ -import { Component, EventEmitter, OnInit, Type, ViewChild } from '@angular/core'; +import { Component, OnInit, Type, ViewChild } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { NgbNav, NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; import _ from 'lodash'; -import { Observable, Subscription } from 'rxjs'; +import { Observable, ReplaySubject, Subscription } from 'rxjs'; import { CrushRuleService } from '~/app/shared/api/crush-rule.service'; import { ErasureCodeProfileService } from '~/app/shared/api/erasure-code-profile.service'; @@ -70,10 +70,10 @@ export class PoolFormComponent extends CdForm implements OnInit { current: Record = { rules: [] }; - initializeConfigData = new EventEmitter<{ + initializeConfigData = new ReplaySubject<{ initialData: RbdConfigurationEntry[]; sourceType: RbdConfigurationSourceField; - }>(); + }>(1); currentConfigurationValues: { [configKey: string]: any } = {}; action: string; resource: string; @@ -252,7 +252,7 @@ export class PoolFormComponent extends CdForm implements OnInit { } private initEditFormData(pool: Pool) { - this.initializeConfigData.emit({ + this.initializeConfigData.next({ initialData: pool.configuration, sourceType: RbdConfigurationSourceField.pool }); -- 2.39.5