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