mirror of
https://github.com/ceph/ceph
synced 2025-02-15 23:07:55 +00:00
mgr/dashboard: Manage PG autoscaling (#31417)
Reviewed-by: Tiago Melo <tmelo@suse.com>
This commit is contained in:
commit
72c63fe228
@ -67,8 +67,27 @@
|
||||
</div>
|
||||
|
||||
<div *ngIf="form.getValue('poolType')">
|
||||
<!-- Pg number -->
|
||||
<!-- PG Autoscale Mode -->
|
||||
<div class="form-group row">
|
||||
<label i18n
|
||||
class="col-form-label col-sm-3"
|
||||
for="pgAutoscaleMode">PG Autoscale</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control custom-select"
|
||||
id="pgAutoscaleMode"
|
||||
name="pgAutoscaleMode"
|
||||
formControlName="pgAutoscaleMode">
|
||||
<option *ngFor="let mode of pgAutoscaleModes"
|
||||
[value]="mode">
|
||||
{{ mode }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pg number -->
|
||||
<div class="form-group row"
|
||||
*ngIf="form.getValue('pgAutoscaleMode') !== 'on'">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="pgNum">
|
||||
<ng-container i18n>Placement groups</ng-container>
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
i18nProviders
|
||||
} from '../../../../testing/unit-test-helper';
|
||||
import { NotFoundComponent } from '../../../core/not-found/not-found.component';
|
||||
import { ConfigurationService } from '../../../shared/api/configuration.service';
|
||||
import { ErasureCodeProfileService } from '../../../shared/api/erasure-code-profile.service';
|
||||
import { PoolService } from '../../../shared/api/pool.service';
|
||||
import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
|
||||
@ -39,6 +40,7 @@ describe('PoolFormComponent', () => {
|
||||
let component: PoolFormComponent;
|
||||
let fixture: ComponentFixture<PoolFormComponent>;
|
||||
let poolService: PoolService;
|
||||
let configurationService: ConfigurationService;
|
||||
let form: CdFormGroup;
|
||||
let router: Router;
|
||||
let ecpService: ErasureCodeProfileService;
|
||||
@ -162,6 +164,10 @@ describe('PoolFormComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
setUpPoolComponent();
|
||||
configurationService = TestBed.get(ConfigurationService);
|
||||
spyOn(configurationService, 'get').and.callFake(() => [
|
||||
{ default: 'off', enum_values: ['on', 'warn', 'off'], value: [] }
|
||||
]);
|
||||
poolService = TestBed.get(PoolService);
|
||||
spyOn(poolService, 'getInfo').and.callFake(() => [component.info]);
|
||||
ecpService = TestBed.get(ErasureCodeProfileService);
|
||||
|
@ -7,6 +7,7 @@ import * as _ from 'lodash';
|
||||
import { BsModalService } from 'ngx-bootstrap/modal';
|
||||
import { forkJoin, Subscription } from 'rxjs';
|
||||
|
||||
import { ConfigurationService } from '../../../shared/api/configuration.service';
|
||||
import { ErasureCodeProfileService } from '../../../shared/api/erasure-code-profile.service';
|
||||
import { PoolService } from '../../../shared/api/pool.service';
|
||||
import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
|
||||
@ -67,6 +68,7 @@ export class PoolFormComponent implements OnInit {
|
||||
action: string;
|
||||
resource: string;
|
||||
icons = Icons;
|
||||
pgAutoscaleModes: string[];
|
||||
|
||||
constructor(
|
||||
private dimlessBinaryPipe: DimlessBinaryPipe,
|
||||
@ -74,6 +76,7 @@ export class PoolFormComponent implements OnInit {
|
||||
private router: Router,
|
||||
private modalService: BsModalService,
|
||||
private poolService: PoolService,
|
||||
private configurationService: ConfigurationService,
|
||||
private authStorageService: AuthStorageService,
|
||||
private formatter: FormatterService,
|
||||
private bsModalService: BsModalService,
|
||||
@ -148,6 +151,7 @@ export class PoolFormComponent implements OnInit {
|
||||
pgNum: new FormControl('', {
|
||||
validators: [Validators.required, Validators.min(1)]
|
||||
}),
|
||||
pgAutoscaleMode: new FormControl(null),
|
||||
ecOverwrites: new FormControl(false),
|
||||
compression: compressionForm,
|
||||
max_bytes: new FormControl(''),
|
||||
@ -160,17 +164,23 @@ export class PoolFormComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
forkJoin(this.poolService.getInfo(), this.ecpService.list()).subscribe(
|
||||
(data: [PoolFormInfo, ErasureCodeProfile[]]) => {
|
||||
this.initInfo(data[0]);
|
||||
this.initEcp(data[1]);
|
||||
if (this.editing) {
|
||||
this.initEditMode();
|
||||
}
|
||||
this.listenToChanges();
|
||||
this.setComplexValidators();
|
||||
forkJoin(
|
||||
this.configurationService.get('osd_pool_default_pg_autoscale_mode'),
|
||||
this.poolService.getInfo(),
|
||||
this.ecpService.list()
|
||||
).subscribe((data: [any, PoolFormInfo, ErasureCodeProfile[]]) => {
|
||||
const pgAutoscaleConfig = data[0];
|
||||
this.pgAutoscaleModes = pgAutoscaleConfig.enum_values;
|
||||
const defaultPgAutoscaleMode = this.configurationService.getValue(pgAutoscaleConfig, 'mon');
|
||||
this.form.silentSet('pgAutoscaleMode', defaultPgAutoscaleMode);
|
||||
this.initInfo(data[1]);
|
||||
this.initEcp(data[2]);
|
||||
if (this.editing) {
|
||||
this.initEditMode();
|
||||
}
|
||||
);
|
||||
this.listenToChanges();
|
||||
this.setComplexValidators();
|
||||
});
|
||||
}
|
||||
|
||||
private initInfo(info: PoolFormInfo) {
|
||||
@ -221,6 +231,7 @@ export class PoolFormComponent implements OnInit {
|
||||
),
|
||||
size: pool.size,
|
||||
erasureProfile: this.ecProfiles.find((ecp) => ecp.name === pool.erasure_code_profile),
|
||||
pgAutoscaleMode: pool.pg_autoscale_mode,
|
||||
pgNum: pool.pg_num,
|
||||
ecOverwrites: pool.flags_names.includes('ec_overwrites'),
|
||||
mode: pool.options.compression_mode,
|
||||
@ -530,7 +541,17 @@ export class PoolFormComponent implements OnInit {
|
||||
|
||||
this.assignFormFields(pool, [
|
||||
{ externalFieldName: 'pool_type', formControlName: 'poolType' },
|
||||
{ externalFieldName: 'pg_num', formControlName: 'pgNum', editable: true },
|
||||
{
|
||||
externalFieldName: 'pg_autoscale_mode',
|
||||
formControlName: 'pgAutoscaleMode',
|
||||
editable: true
|
||||
},
|
||||
{
|
||||
externalFieldName: 'pg_num',
|
||||
formControlName: 'pgNum',
|
||||
replaceFn: (value) => (this.form.getValue('pgAutoscaleMode') === 'on' ? 1 : value),
|
||||
editable: true
|
||||
},
|
||||
this.form.getValue('poolType') === 'replicated'
|
||||
? { externalFieldName: 'size', formControlName: 'size' }
|
||||
: {
|
||||
|
@ -77,4 +77,23 @@ describe('ConfigurationService', () => {
|
||||
const reg = httpTesting.expectOne('api/cluster_conf/testOption?section=testSection');
|
||||
expect(reg.request.method).toBe('DELETE');
|
||||
});
|
||||
|
||||
it('should get value', () => {
|
||||
const config = {
|
||||
default: 'a',
|
||||
value: [
|
||||
{ section: 'global', value: 'b' },
|
||||
{ section: 'mon', value: 'c' },
|
||||
{ section: 'mon.1', value: 'd' },
|
||||
{ section: 'mds', value: 'e' }
|
||||
]
|
||||
};
|
||||
expect(service.getValue(config, 'mon.1')).toBe('d');
|
||||
expect(service.getValue(config, 'mon')).toBe('c');
|
||||
expect(service.getValue(config, 'mds.1')).toBe('e');
|
||||
expect(service.getValue(config, 'mds')).toBe('e');
|
||||
expect(service.getValue(config, 'osd')).toBe('b');
|
||||
config.value = [];
|
||||
expect(service.getValue(config, 'osd')).toBe('a');
|
||||
});
|
||||
});
|
||||
|
@ -10,6 +10,30 @@ import { ApiModule } from './api.module';
|
||||
export class ConfigurationService {
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
private findValue(config, section: string) {
|
||||
if (!config.value) {
|
||||
return undefined;
|
||||
}
|
||||
return config.value.find((v) => v.section === section);
|
||||
}
|
||||
|
||||
getValue(config, section: string) {
|
||||
let val = this.findValue(config, section);
|
||||
if (!val) {
|
||||
const indexOfDot = section.indexOf('.');
|
||||
if (indexOfDot !== -1) {
|
||||
val = this.findValue(config, section.substring(0, indexOfDot));
|
||||
}
|
||||
}
|
||||
if (!val) {
|
||||
val = this.findValue(config, 'global');
|
||||
}
|
||||
if (val) {
|
||||
return val.value;
|
||||
}
|
||||
return config.default;
|
||||
}
|
||||
|
||||
getConfigData() {
|
||||
return this.http.get('api/cluster_conf/');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user