]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/blob
6e3218b47f7210162ddb9a2ac51a63d3f6473a61
[ceph.git] /
1 import { Component, EventEmitter, OnInit, Output } from '@angular/core';
2 import { Validators } from '@angular/forms';
3
4 import { BsModalRef } from 'ngx-bootstrap/modal';
5
6 import { ErasureCodeProfileService } from '../../../shared/api/erasure-code-profile.service';
7 import { CdFormBuilder } from '../../../shared/forms/cd-form-builder';
8 import { CdFormGroup } from '../../../shared/forms/cd-form-group';
9 import { CdValidators } from '../../../shared/forms/cd-validators';
10 import { ErasureCodeProfile } from '../../../shared/models/erasure-code-profile';
11 import { FinishedTask } from '../../../shared/models/finished-task';
12 import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
13 import { ErasureCodeProfileFormTooltips } from './erasure-code-profile-form-tooltips';
14
15 @Component({
16   selector: 'cd-erasure-code-profile-form',
17   templateUrl: './erasure-code-profile-form.component.html',
18   styleUrls: ['./erasure-code-profile-form.component.scss']
19 })
20 export class ErasureCodeProfileFormComponent implements OnInit {
21   @Output()
22   submitAction = new EventEmitter();
23
24   form: CdFormGroup;
25   failureDomains: string[];
26   plugins: string[];
27   names: string[];
28   techniques: string[];
29   requiredControls: string[] = [];
30   devices: string[] = [];
31   tooltips = new ErasureCodeProfileFormTooltips();
32
33   PLUGIN = {
34     LRC: 'lrc', // Locally Repairable Erasure Code
35     SHEC: 'shec', // Shingled Erasure Code
36     JERASURE: 'jerasure', // default
37     ISA: 'isa' // Intel Storage Acceleration
38   };
39   plugin = this.PLUGIN.JERASURE;
40
41   constructor(
42     private formBuilder: CdFormBuilder,
43     public bsModalRef: BsModalRef,
44     private taskWrapper: TaskWrapperService,
45     private ecpService: ErasureCodeProfileService
46   ) {
47     this.createForm();
48     this.setJerasureDefaults();
49   }
50
51   createForm() {
52     this.form = this.formBuilder.group({
53       name: [
54         null,
55         [
56           Validators.required,
57           Validators.pattern('[A-Za-z0-9_-]+'),
58           CdValidators.custom(
59             'uniqueName',
60             (value) => this.names && this.names.indexOf(value) !== -1
61           )
62         ]
63       ],
64       plugin: [this.PLUGIN.JERASURE, [Validators.required]],
65       k: [1], // Will be replaced by plugin defaults
66       m: [1], // Will be replaced by plugin defaults
67       crushFailureDomain: ['host'],
68       crushRoot: ['default'], // default for all - is a list possible???
69       crushDeviceClass: [''], // set none to empty at submit - get list from configs?
70       directory: [''],
71       // Only for 'jerasure' and 'isa' use
72       technique: ['reed_sol_van'],
73       // Only for 'jerasure' use
74       packetSize: [2048, [Validators.min(1)]],
75       // Only for 'lrc' use
76       l: [1, [Validators.required, Validators.min(1)]],
77       crushLocality: [''], // set to none at the end (same list as for failure domains)
78       // Only for 'shec' use
79       c: [1, [Validators.required, Validators.min(1)]]
80     });
81     this.form.get('plugin').valueChanges.subscribe((plugin) => this.onPluginChange(plugin));
82   }
83
84   onPluginChange(plugin) {
85     this.plugin = plugin;
86     if (plugin === this.PLUGIN.JERASURE) {
87       this.setJerasureDefaults();
88     } else if (plugin === this.PLUGIN.LRC) {
89       this.setLrcDefaults();
90     } else if (plugin === this.PLUGIN.ISA) {
91       this.setIsaDefaults();
92     } else if (plugin === this.PLUGIN.SHEC) {
93       this.setShecDefaults();
94     }
95   }
96
97   private setNumberValidators(name: string, required: boolean) {
98     const validators = [Validators.min(1)];
99     if (required) {
100       validators.push(Validators.required);
101     }
102     this.form.get(name).setValidators(validators);
103   }
104
105   private setKMValidators(required: boolean) {
106     ['k', 'm'].forEach((name) => this.setNumberValidators(name, required));
107   }
108
109   private setJerasureDefaults() {
110     this.requiredControls = ['k', 'm'];
111     this.setDefaults({
112       k: 4,
113       m: 2
114     });
115     this.setKMValidators(true);
116     this.techniques = [
117       'reed_sol_van',
118       'reed_sol_r6_op',
119       'cauchy_orig',
120       'cauchy_good',
121       'liberation',
122       'blaum_roth',
123       'liber8tion'
124     ];
125   }
126
127   private setLrcDefaults() {
128     this.requiredControls = ['k', 'm', 'l'];
129     this.setKMValidators(true);
130     this.setNumberValidators('l', true);
131     this.setDefaults({
132       k: 4,
133       m: 2,
134       l: 3
135     });
136   }
137
138   private setIsaDefaults() {
139     this.requiredControls = [];
140     this.setKMValidators(false);
141     this.setDefaults({
142       k: 7,
143       m: 3
144     });
145     this.techniques = ['reed_sol_van', 'cauchy'];
146   }
147
148   private setShecDefaults() {
149     this.requiredControls = [];
150     this.setKMValidators(false);
151     this.setDefaults({
152       k: 4,
153       m: 3,
154       c: 2
155     });
156   }
157
158   private setDefaults(defaults: object) {
159     Object.keys(defaults).forEach((controlName) => {
160       if (this.form.get(controlName).pristine) {
161         this.form.silentSet(controlName, defaults[controlName]);
162       }
163     });
164   }
165
166   ngOnInit() {
167     this.ecpService
168       .getInfo()
169       .subscribe(
170         ({
171           failure_domains,
172           plugins,
173           names,
174           directory,
175           devices
176         }: {
177           failure_domains: string[];
178           plugins: string[];
179           names: string[];
180           directory: string;
181           devices: string[];
182         }) => {
183           this.failureDomains = failure_domains;
184           this.plugins = plugins;
185           this.names = names;
186           this.devices = devices;
187           this.form.silentSet('directory', directory);
188         }
189       );
190   }
191
192   private createJson() {
193     const pluginControls = {
194       technique: [this.PLUGIN.ISA, this.PLUGIN.JERASURE],
195       packetSize: [this.PLUGIN.JERASURE],
196       l: [this.PLUGIN.LRC],
197       crushLocality: [this.PLUGIN.LRC],
198       c: [this.PLUGIN.SHEC]
199     };
200     const ecp = new ErasureCodeProfile();
201     const plugin = this.form.getValue('plugin');
202     Object.keys(this.form.controls)
203       .filter((name) => {
204         const pluginControl = pluginControls[name];
205         const control = this.form.get(name);
206         const usable = (pluginControl && pluginControl.includes(plugin)) || !pluginControl;
207         return (
208           usable &&
209           (control.dirty || this.requiredControls.includes(name)) &&
210           this.form.getValue(name)
211         );
212       })
213       .forEach((name) => {
214         this.extendJson(name, ecp);
215       });
216     return ecp;
217   }
218
219   private extendJson(name: string, ecp: ErasureCodeProfile) {
220     const differentApiAttributes = {
221       crushFailureDomain: 'crush-failure-domain',
222       crushRoot: 'crush-root',
223       crushDeviceClass: 'crush-device-class',
224       packetSize: 'packetsize',
225       crushLocality: 'crush-locality'
226     };
227     ecp[differentApiAttributes[name] || name] = this.form.getValue(name);
228   }
229
230   onSubmit() {
231     if (this.form.invalid) {
232       this.form.setErrors({ cdSubmitButton: true });
233       return;
234     }
235     const profile = this.createJson();
236     this.taskWrapper
237       .wrapTaskAroundCall({
238         task: new FinishedTask('ecp/create', { name: profile.name }),
239         call: this.ecpService.create(profile)
240       })
241       .subscribe(
242         undefined,
243         (resp) => {
244           this.form.setErrors({ cdSubmitButton: true });
245         },
246         () => {
247           this.bsModalRef.hide();
248           this.submitAction.emit(profile);
249         }
250       );
251   }
252 }