</div>
</div>
+ <!-- Quotas -->
+ <div>
+ <legend i18n>Quotas</legend>
+
+ <!-- Max Bytes -->
+ <div class="form-group"
+ [ngClass]="{'has-error': form.showError('max_bytes', formDir)}">
+ <label class="control-label col-sm-3"
+ for="max_bytes">
+ <ng-container i18n>Max bytes</ng-container>
+ <cd-helper>
+ <span i18n>Leave it blank or specify 0 to disable this quota.</span>
+ <br>
+ <span i18n>A valid quota should be greater than 0.</span>
+ </cd-helper>
+ </label>
+ <div class="col-sm-9">
+ <input class="form-control"
+ id="max_bytes"
+ name="max_bytes"
+ type="text"
+ formControlName="max_bytes"
+ i18n-placeholder
+ placeholder="e.g., 10GiB"
+ defaultUnit="GiB"
+ cdDimlessBinary>
+ </div>
+ </div>
+
+ <!-- Max Objects -->
+ <div class="form-group"
+ [ngClass]="{'has-error': form.showError('max_objects', formDir)}">
+ <label class="control-label col-sm-3"
+ for="max_objects">
+ <ng-container i18n>Max objects</ng-container>
+ <cd-helper>
+ <span i18n>Leave it blank or specify 0 to disable this quota.</span>
+ <br>
+ <span i18n>A valid quota should be greater than 0.</span>
+ </cd-helper>
+ </label>
+ <div class="col-sm-9">
+ <input class="form-control"
+ id="max_objects"
+ min="0"
+ name="max_objects"
+ type="number"
+ formControlName="max_objects">
+ <span class="help-block"
+ *ngIf="form.showError('max_objects', formDir, 'min')"
+ i18n>The value should be greater or equal to 0</span>
+ </div>
+ </div>
+ </div>
+
<!-- Pool configuration -->
<div [hidden]="form.get('poolType').value !== 'replicated' || data.applications.selected.indexOf('rbd') === -1">
<cd-rbd-configuration-form [form]="form"
expect(form.getValue('mode')).toBe('none');
});
+ it('validate quotas', () => {
+ formHelper.expectValid('max_bytes');
+ formHelper.expectValid('max_objects');
+ formHelper.expectValidChange('max_bytes', '10 Gib');
+ formHelper.expectValidChange('max_bytes', '');
+ formHelper.expectValidChange('max_objects', '');
+ formHelper.expectErrorChange('max_objects', -1, 'min');
+ });
+
describe('compression form', () => {
beforeEach(() => {
formHelper.setValue('poolType', 'replicated');
size: 2
});
});
+
+ it('with quotas', () => {
+ setMultipleValues({
+ name: 'RepPoolWithQuotas',
+ poolType: 'replicated',
+ max_bytes: 1024 * 1024,
+ max_objects: 3000,
+ pgNum: 8
+ });
+ testCreate({
+ pool: 'RepPoolWithQuotas',
+ pool_type: 'replicated',
+ quota_max_bytes: 1024 * 1024,
+ quota_max_objects: 3000,
+ pg_num: 8
+ });
+ });
});
it('pool with compression', () => {
pool.options.compression_required_ratio = 0.8;
pool.flags_names = 'someFlag1,someFlag2';
pool.application_metadata = ['rbd', 'rgw'];
+ pool.quota_max_bytes = 1024 * 1024 * 1024;
+ pool.quota_max_objects = 3000;
createCrushRule({ name: 'someRule' });
spyOn(poolService, 'get').and.callFake(() => of(pool));
'algorithm',
'minBlobSize',
'maxBlobSize',
- 'ratio'
+ 'ratio',
+ 'max_bytes',
+ 'max_objects'
];
enabled.forEach((controlName) => {
return expect(form.get(controlName).enabled).toBeTruthy();
expect(form.getValue('minBlobSize')).toBe('512 KiB');
expect(form.getValue('maxBlobSize')).toBe('1 MiB');
expect(form.getValue('ratio')).toBe(pool.options.compression_required_ratio);
+ expect(form.getValue('max_bytes')).toBe('1 GiB');
+ expect(form.getValue('max_objects')).toBe(pool.quota_max_objects);
});
it('updates pgs on every change', () => {
validators: [Validators.required, Validators.min(1)]
}),
ecOverwrites: new FormControl(false),
- compression: compressionForm
+ compression: compressionForm,
+ max_bytes: new FormControl(''),
+ max_objects: new FormControl(0, {
+ validators: [Validators.min(0)]
+ })
},
[
CdValidators.custom('form', () => null),
algorithm: pool.options.compression_algorithm,
minBlobSize: this.dimlessBinaryPipe.transform(pool.options.compression_min_blob_size),
maxBlobSize: this.dimlessBinaryPipe.transform(pool.options.compression_max_blob_size),
- ratio: pool.options.compression_required_ratio
+ ratio: pool.options.compression_required_ratio,
+ max_bytes: this.dimlessBinaryPipe.transform(pool.quota_max_bytes),
+ max_objects: pool.quota_max_objects
};
Object.keys(dataMap).forEach((controlName: string) => {
formControlName: 'erasureProfile',
attr: 'name'
},
- { externalFieldName: 'rule_name', formControlName: 'crushRule', attr: 'rule_name' }
+ { externalFieldName: 'rule_name', formControlName: 'crushRule', attr: 'rule_name' },
+ {
+ externalFieldName: 'quota_max_bytes',
+ formControlName: 'max_bytes',
+ replaceFn: this.formatter.toBytes,
+ editable: true,
+ resetValue: this.editing ? 0 : undefined
+ },
+ {
+ externalFieldName: 'quota_max_objects',
+ formControlName: 'max_objects',
+ editable: true,
+ resetValue: this.editing ? 0 : undefined
+ }
]);
if (this.info.is_all_bluestore) {