1 import { Component, EventEmitter, OnInit, Output } from '@angular/core';
2 import { Validators } from '@angular/forms';
4 import { I18n } from '@ngx-translate/i18n-polyfill';
5 import { BsModalRef } from 'ngx-bootstrap/modal';
7 import { ErasureCodeProfileService } from '../../../shared/api/erasure-code-profile.service';
8 import { CrushNodeSelectionClass } from '../../../shared/classes/crush.node.selection.class';
9 import { ActionLabelsI18n } from '../../../shared/constants/app.constants';
10 import { CdFormBuilder } from '../../../shared/forms/cd-form-builder';
11 import { CdFormGroup } from '../../../shared/forms/cd-form-group';
12 import { CdValidators } from '../../../shared/forms/cd-validators';
13 import { CrushNode } from '../../../shared/models/crush-node';
14 import { ErasureCodeProfile } from '../../../shared/models/erasure-code-profile';
15 import { FinishedTask } from '../../../shared/models/finished-task';
16 import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
19 selector: 'cd-erasure-code-profile-form-modal',
20 templateUrl: './erasure-code-profile-form-modal.component.html',
21 styleUrls: ['./erasure-code-profile-form-modal.component.scss']
23 export class ErasureCodeProfileFormModalComponent extends CrushNodeSelectionClass
26 submitAction = new EventEmitter();
28 tooltips = this.ecpService.formTooltips;
30 LRC: 'lrc', // Locally Repairable Erasure Code
31 SHEC: 'shec', // Shingled Erasure Code
32 JERASURE: 'jerasure', // default
33 ISA: 'isa' // Intel Storage Acceleration
35 plugin = this.PLUGIN.JERASURE;
45 private formBuilder: CdFormBuilder,
46 public bsModalRef: BsModalRef,
47 private taskWrapper: TaskWrapperService,
48 private ecpService: ErasureCodeProfileService,
50 public actionLabels: ActionLabelsI18n
53 this.action = this.actionLabels.CREATE;
54 this.resource = this.i18n('EC Profile');
56 this.setJerasureDefaults();
60 this.form = this.formBuilder.group({
65 Validators.pattern('[A-Za-z0-9_-]+'),
68 (value: string) => this.names && this.names.indexOf(value) !== -1
72 plugin: [this.PLUGIN.JERASURE, [Validators.required]],
73 k: [1], // Will be replaced by plugin defaults
74 m: [1], // Will be replaced by plugin defaults
75 crushFailureDomain: ['host'],
76 crushRoot: ['default'], // default for all - is a list possible???
77 crushDeviceClass: [''], // set none to empty at submit - get list from configs?
79 // Only for 'jerasure' and 'isa' use
80 technique: ['reed_sol_van'],
81 // Only for 'jerasure' use
82 packetSize: [2048, [Validators.min(1)]],
84 l: [1, [Validators.required, Validators.min(1)]],
85 crushLocality: [''], // set to none at the end (same list as for failure domains)
86 // Only for 'shec' use
87 c: [1, [Validators.required, Validators.min(1)]]
89 this.form.get('plugin').valueChanges.subscribe((plugin) => this.onPluginChange(plugin));
92 onPluginChange(plugin: string) {
94 if (plugin === this.PLUGIN.JERASURE) {
95 this.setJerasureDefaults();
96 } else if (plugin === this.PLUGIN.LRC) {
97 this.setLrcDefaults();
98 } else if (plugin === this.PLUGIN.ISA) {
99 this.setIsaDefaults();
100 } else if (plugin === this.PLUGIN.SHEC) {
101 this.setShecDefaults();
105 private setNumberValidators(name: string, required: boolean) {
106 const validators = [Validators.min(1)];
108 validators.push(Validators.required);
110 this.form.get(name).setValidators(validators);
113 private setKMValidators(required: boolean) {
114 ['k', 'm'].forEach((name) => this.setNumberValidators(name, required));
117 private setJerasureDefaults() {
118 this.requiredControls = ['k', 'm'];
123 this.setKMValidators(true);
135 private setLrcDefaults() {
136 this.requiredControls = ['k', 'm', 'l'];
137 this.setKMValidators(true);
138 this.setNumberValidators('l', true);
146 private setIsaDefaults() {
147 this.requiredControls = [];
148 this.setKMValidators(false);
153 this.techniques = ['reed_sol_van', 'cauchy'];
156 private setShecDefaults() {
157 this.requiredControls = [];
158 this.setKMValidators(false);
166 private setDefaults(defaults: object) {
167 Object.keys(defaults).forEach((controlName) => {
168 if (this.form.get(controlName).pristine) {
169 this.form.silentSet(controlName, defaults[controlName]);
189 this.initCrushNodeSelection(
191 this.form.get('crushRoot'),
192 this.form.get('crushFailureDomain'),
193 this.form.get('crushDeviceClass')
195 this.plugins = plugins;
197 this.form.silentSet('directory', directory);
203 if (this.form.invalid) {
204 this.form.setErrors({ cdSubmitButton: true });
207 const profile = this.createJson();
209 .wrapTaskAroundCall({
210 task: new FinishedTask('ecp/create', { name: profile.name }),
211 call: this.ecpService.create(profile)
216 this.form.setErrors({ cdSubmitButton: true });
219 this.bsModalRef.hide();
220 this.submitAction.emit(profile);
225 private createJson() {
226 const pluginControls = {
227 technique: [this.PLUGIN.ISA, this.PLUGIN.JERASURE],
228 packetSize: [this.PLUGIN.JERASURE],
229 l: [this.PLUGIN.LRC],
230 crushLocality: [this.PLUGIN.LRC],
231 c: [this.PLUGIN.SHEC]
233 const ecp = new ErasureCodeProfile();
234 const plugin = this.form.getValue('plugin');
235 Object.keys(this.form.controls)
237 const pluginControl = pluginControls[name];
238 const value = this.form.getValue(name);
239 const usable = (pluginControl && pluginControl.includes(plugin)) || !pluginControl;
240 return usable && value && value !== '';
243 this.extendJson(name, ecp);
248 private extendJson(name: string, ecp: ErasureCodeProfile) {
249 const differentApiAttributes = {
250 crushFailureDomain: 'crush-failure-domain',
251 crushRoot: 'crush-root',
252 crushDeviceClass: 'crush-device-class',
253 packetSize: 'packetsize',
254 crushLocality: 'crush-locality'
256 const value = this.form.getValue(name);
257 ecp[differentApiAttributes[name] || name] = name === 'crushRoot' ? value.name : value;