Skip to content

Commit 0c01a33

Browse files
authored
Merge pull request ceph#62611 from rhcs-dashboard/ec-fixes
mgr/dashboard: add enhancements for pool rulest Reviewed-by: Aashish Sharma <[email protected]>
2 parents 97234f4 + e9d40c3 commit 0c01a33

File tree

6 files changed

+56
-20
lines changed

6 files changed

+56
-20
lines changed

src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/crush-rule-form-modal/crush-rule-form-modal.component.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ describe('CrushRuleFormComponent', () => {
139139
});
140140

141141
it('should select all values automatically by selecting "ssd-host" as root', () => {
142+
formHelper.setValue('device_class', 'ssd', true);
142143
assert.valuesOnRootChange('ssd-host', 'osd', 'ssd');
143144
});
144145

@@ -149,7 +150,9 @@ describe('CrushRuleFormComponent', () => {
149150

150151
it('should override automatic selections', () => {
151152
assert.formFieldValues(get.nodeByName('default'), 'osd-rack', '');
153+
formHelper.setValue('device_class', 'ssd', true);
152154
assert.valuesOnRootChange('ssd-host', 'osd', 'ssd');
155+
formHelper.setValue('device_class', '', true);
153156
assert.valuesOnRootChange('mix-host', 'osd-rack', '');
154157
});
155158

@@ -160,6 +163,7 @@ describe('CrushRuleFormComponent', () => {
160163
});
161164

162165
it('should preselect device by domain selection', () => {
166+
formHelper.setValue('device_class', 'ssd', true);
163167
formHelper.setValue('failure_domain', 'osd', true);
164168
assert.formFieldValues(get.nodeByName('default'), 'osd', 'ssd');
165169
});
@@ -203,6 +207,7 @@ describe('CrushRuleFormComponent', () => {
203207
});
204208

205209
it('creates a rule with all fields', () => {
210+
formHelper.setValue('device_class', 'ssd', true);
206211
assert.valuesOnRootChange('ssd-host', 'osd', 'ssd');
207212
assert.creation(Mocks.getCrushRuleConfig('ssd-host-rule', 'ssd-host', 'osd', 'ssd'));
208213
});

src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/crush-rule-form-modal/crush-rule-form-modal.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ export class CrushRuleFormModalComponent extends CrushNodeSelectionClass impleme
7676
nodes,
7777
this.form.get('root'),
7878
this.form.get('failure_domain'),
79-
this.form.get('device_class')
79+
this.form.get('device_class'),
80+
false
8081
);
8182
this.names = names;
8283
});

src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form-modal.component.html

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@
8282
*ngIf="form.showError('k', frm, 'min')"
8383
i18n>Must be equal to or greater than 2.</span>
8484
<span class="invalid-feedback"
85-
*ngIf="form.showError('k', frm, 'max')"
85+
*ngIf="form.showError('k', frm, 'max') && form.getValue('crushFailureDomain') === CrushFailureDomains.Osd"
8686
i18n>Chunks (k+m) have exceeded the available OSDs of {{deviceCount}}.</span>
87+
<span class="invalid-feedback"
88+
*ngIf="form.showError('k', frm, 'max') && form.getValue('crushFailureDomain') === CrushFailureDomains.Host"
89+
i18n>Chunks (k+m+1) have exceeded the available hosts of {{deviceCount}}.</span>
8790
<span class="invalid-feedback"
8891
*ngIf="form.showError('k', frm, 'unequal')"
8992
i18n>For an equal distribution k has to be a multiple of (k+m)/l.</span>
@@ -119,8 +122,11 @@
119122
*ngIf="form.showError('m', frm, 'min')"
120123
i18n>Must be equal to or greater than 1.</span>
121124
<span class="invalid-feedback"
122-
*ngIf="form.showError('m', frm, 'max')"
125+
*ngIf="form.showError('m', frm, 'max') && form.getValue('crushFailureDomain') === CrushFailureDomains.Osd"
123126
i18n>Chunks (k+m) have exceeded the available OSDs of {{deviceCount}}.</span>
127+
<span class="invalid-feedback"
128+
*ngIf="form.showError('m', frm, 'max') && form.getValue('crushFailureDomain') === CrushFailureDomains.Host"
129+
i18n>Chunks (k+m+1) have exceeded the available hosts of {{deviceCount}}.</span>
124130
</div>
125131
</div>
126132

@@ -240,7 +246,8 @@
240246
<select class="form-select"
241247
id="crushFailureDomain"
242248
name="crushFailureDomain"
243-
formControlName="crushFailureDomain">
249+
formControlName="crushFailureDomain"
250+
(change)="onCrushFailureDomainChane()">
244251
<option *ngIf="!failureDomains"
245252
ngValue=""
246253
i18n>Loading...</option>

src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form-modal.component.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
1111
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
1212
import { CdValidators } from '~/app/shared/forms/cd-validators';
1313
import { CrushNode } from '~/app/shared/models/crush-node';
14-
import { ErasureCodeProfile } from '~/app/shared/models/erasure-code-profile';
14+
import { ErasureCodeProfile, CrushFailureDomains } from '~/app/shared/models/erasure-code-profile';
1515
import { FinishedTask } from '~/app/shared/models/finished-task';
1616
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
1717

@@ -47,6 +47,8 @@ export class ErasureCodeProfileFormModalComponent
4747
lrcGroups: number;
4848
lrcMultiK: number;
4949

50+
public CrushFailureDomains = CrushFailureDomains;
51+
5052
constructor(
5153
private formBuilder: CdFormBuilder,
5254
public activeModal: NgbActiveModal,
@@ -144,9 +146,12 @@ export class ErasureCodeProfileFormModalComponent
144146

145147
private baseValueValidation(dataChunk: boolean = false): boolean {
146148
return this.validValidation(() => {
149+
const kMSum =
150+
this.form.get('crushFailureDomain').value === CrushFailureDomains.Host
151+
? this.getKMSum() + 1
152+
: this.getKMSum();
147153
return (
148-
this.getKMSum() > this.deviceCount &&
149-
this.form.getValue('k') > this.form.getValue('m') === dataChunk
154+
kMSum > this.deviceCount && this.form.getValue('k') > this.form.getValue('m') === dataChunk
150155
);
151156
});
152157
}
@@ -469,4 +474,9 @@ export class ErasureCodeProfileFormModalComponent
469474
const value = this.form.getValue(name);
470475
ecp[differentApiAttributes[name] || name] = name === 'crushRoot' ? value.name : value;
471476
}
477+
478+
onCrushFailureDomainChane() {
479+
this.form.get('k').updateValueAndValidity();
480+
this.form.get('m').updateValueAndValidity();
481+
}
472482
}

src/pybind/mgr/dashboard/frontend/src/app/shared/classes/crush.node.selection.class.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AbstractControl } from '@angular/forms';
33
import _ from 'lodash';
44

55
import { CrushNode } from '../models/crush-node';
6+
import { CrushFailureDomains } from '../models/erasure-code-profile';
67

78
export class CrushNodeSelectionClass {
89
private nodes: CrushNode[] = [];
@@ -207,19 +208,26 @@ export class CrushNodeSelectionClass {
207208
}
208209

209210
private updateDevices(failureDomain: string = this.controls.failure.value) {
210-
const subNodes = _.flatten(
211-
this.failureDomains[failureDomain].map((node) =>
212-
CrushNodeSelectionClass.getSubNodes(node, this.idTree)
213-
)
214-
);
215-
this.allDevices = subNodes.filter((n) => n.device_class).map((n) => n.device_class);
216-
this.devices = _.uniq(this.allDevices).sort();
217-
const device =
218-
this.devices.length === 1
219-
? this.devices[0]
220-
: this.getIncludedCustomValue(this.controls.device, this.devices);
221-
if (this.autoDeviceUpdate) this.silentSet(this.controls.device, device);
222-
this.onDeviceChange(device);
211+
if (failureDomain === CrushFailureDomains.Host) {
212+
this.allDevices = this.failureDomains[failureDomain]
213+
.filter((fD) => fD.type)
214+
.map((fD) => fD.type);
215+
this.onDeviceChange('');
216+
} else {
217+
const subNodes = _.flatten(
218+
this.failureDomains[failureDomain].map((node) =>
219+
CrushNodeSelectionClass.getSubNodes(node, this.idTree)
220+
)
221+
);
222+
this.allDevices = subNodes.filter((n) => n.device_class).map((n) => n.device_class);
223+
this.devices = _.uniq(this.allDevices).sort();
224+
const device =
225+
this.devices.length === 1
226+
? this.devices[0]
227+
: this.getIncludedCustomValue(this.controls.device, this.devices);
228+
if (this.autoDeviceUpdate) this.silentSet(this.controls.device, device);
229+
this.onDeviceChange(device);
230+
}
223231
}
224232

225233
private onDeviceChange(deviceType: string = this.controls.device.value) {

src/pybind/mgr/dashboard/frontend/src/app/shared/models/erasure-code-profile.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,8 @@ export class ErasureCodeProfile {
1717
'crush-device-class'?: string;
1818
'directory'?: string;
1919
}
20+
21+
export enum CrushFailureDomains {
22+
Osd = 'osd',
23+
Host = 'host'
24+
}

0 commit comments

Comments
 (0)