class="form-header"
>
{{ action | titlecase }} {{ resource | upperFirst }}
+ @if (isStretchMode) {
+ <cd-help-text>
+ Stretch cluster is enabled. Only replicated pool type is supported in Stretch mode.
+ </cd-help-text>
+ }
</div>
<!-- Name -->
<div
>
Pool type
</legend>
+ @if (isStretchMode) {
+ <cds-tooltip
+ description="In stretch mode, only replicated pool type is supported."
+ placement="right"
+ [highContrast]="true"
+ [caret]="true"
+ >
+ <cds-radio-group
+ formControlName="poolType"
+ cdRequiredField="Pool type"
+ data-testid="pool-type-select"
+ >
+ @for (poolType of data.poolTypes; track poolType) {
+ <cds-radio
+ [value]="poolType"
+ [id]="poolType"
+ [disabled]="isStretchMode && !editing && poolType === 'erasure'"
+ (change)="data.erasureInfo = false; data.crushInfo = false;"
+ i18n
+ >
+ {{ poolType | upperFirst }}
+ </cds-radio>
+ }
+ </cds-radio-group>
+ </cds-tooltip>
+ } @else {
<cds-radio-group
formControlName="poolType"
cdRequiredField="Pool type"
<cds-radio
[value]="poolType"
[id]="poolType"
+ [disabled]="isStretchMode && !editing && poolType === 'erasure'"
(change)="data.erasureInfo = false; data.crushInfo = false;"
i18n
>
</cds-radio>
}
</cds-radio-group>
+ }
@if (form.showError('poolType', formDir, 'required')) {
<span
class="cds--form-requirement invalid-feedback"
}
</ng-template>
<ng-template #sizeWarning>
+ @if (isStretchMode) {
+ <span i18n>
+ The replicated size value is predefined for stretch cluster
+ </span>
+ }
@if (form.getValue('size') === 1) {
<span
class="text-warning-dark"
[columnNumbers]="{ lg: 13 }"
>
<cds-select
+ cdValidate
+ #crushRuleRef="cdValidate"
formControlName="crushRule"
label="Crush ruleset"
i18n-label
id="crushRule"
+ [invalid]="crushRuleRef.isInvalid"
+ [invalidText]="crushRuleError"
>
<option [value]="null"
i18n>-- Select a crush rule --
</option>
}
</cds-select>
+ <ng-template #crushRuleError>
+ @if (form.showError('crushRule', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
+ }
+ </ng-template>
</div>
} @else {
<div cdsCol>
import { PoolFormData } from './pool-form-data';
import { PoolEditModeResponseModel } from '../../block/mirroring/pool-edit-mode-modal/pool-edit-mode-response.model';
import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
+import { MonitorService } from '~/app/shared/api/monitor.service';
import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
interface FormFieldDescription {
resetValue?: any;
}
+interface MonitorResponse {
+ mon_status?: {
+ stretch_mode?: boolean;
+ };
+}
+
@Component({
selector: 'cd-pool-form',
templateUrl: './pool-form.component.html',
DEFAULT_RATIO = 0.875;
isApplicationsSelected = true;
msrCrush: boolean = false;
+ isStretchMode: boolean = false;
+
+ readonly DEFAULT_REPLICATED_MIN_SIZE = 1;
+ readonly DEFAULT_REPLICATED_MAX_SIZE = 3;
+ readonly STRETCH_REPLICATED_MIN_SIZE = 2;
+ readonly STRETCH_REPLICATED_MAX_SIZE = 4;
private modalSubscription: Subscription;
private crushRuleService: CrushRuleService,
public actionLabels: ActionLabelsI18n,
private rbdMirroringService: RbdMirroringService,
+ private monitorService: MonitorService,
private cdr: ChangeDetectorRef
) {
super();
}
ngOnInit() {
+ this.monitorService.getMonitor().subscribe((data: MonitorResponse) => {
+ this.isStretchMode = data?.mon_status?.stretch_mode || false;
+ if (this.isStretchMode) {
+ this.applyStretchModeRestrictions();
+ }
+ this.replicatedRuleChange();
+ });
this.poolService.getInfo().subscribe((info: PoolFormInfo) => {
this.initInfo(info);
if (this.editing) {
this.setListControlStatus('crushRule', rules);
}
this.replicatedRuleChange();
+ if (this.isStretchMode) {
+ this.applyStretchModeRestrictions();
+ }
this.pgCalc();
}
+ private applyStretchModeRestrictions() {
+ if (!this.editing && this.form.getValue('poolType') === 'erasure') {
+ this.form.silentSet('poolType', 'replicated');
+ this.poolTypeChange('replicated');
+ return;
+ }
+ if (this.editing) {
+ return;
+ }
+ const sizeControl = this.form.get('size');
+ if (this.isStretchMode) {
+ if (sizeControl.enabled) {
+ sizeControl.disable({ emitEvent: false });
+ }
+ } else if (sizeControl.disabled) {
+ sizeControl.enable({ emitEvent: false });
+ }
+ }
+
private setTypeBooleans(replicated: boolean, erasure: boolean) {
this.isReplicated = replicated;
this.isErasure = erasure;
return;
}
const control = this.form.get('size');
- let size = this.form.getValue('size') || 3;
+ let size =
+ this.form.getValue('size') ||
+ (this.isStretchMode ? this.STRETCH_REPLICATED_MAX_SIZE : this.DEFAULT_REPLICATED_MAX_SIZE);
const min = this.getMinSize();
const max = this.getMaxSize();
if (size < min) {
if (!this.info || this.info.osd_count < 1) {
return 0;
}
- return 1;
+ return this.isStretchMode ? this.STRETCH_REPLICATED_MIN_SIZE : this.DEFAULT_REPLICATED_MIN_SIZE;
}
getMaxSize(): number {
if (!this.info) {
return 0;
}
+ if (this.isStretchMode) return this.STRETCH_REPLICATED_MAX_SIZE;
if (!rule) {
- const osds = this.info.osd_count;
- const defaultSize = 3;
- return Math.min(osds, defaultSize);
+ return Math.min(this.info.osd_count, this.DEFAULT_REPLICATED_MAX_SIZE);
}
return rule.usable_size;
}