]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | import { Component, EventEmitter, OnInit } from '@angular/core'; |
2 | import { FormControl, ValidatorFn, Validators } from '@angular/forms'; | |
3 | import { ActivatedRoute, Router } from '@angular/router'; | |
4 | ||
5 | import { I18n } from '@ngx-translate/i18n-polyfill'; | |
6 | import * as _ from 'lodash'; | |
eafe8130 TL |
7 | import { AsyncSubject, Observable } from 'rxjs'; |
8 | import { switchMap } from 'rxjs/operators'; | |
11fdf7f2 TL |
9 | |
10 | import { PoolService } from '../../../shared/api/pool.service'; | |
11 | import { RbdService } from '../../../shared/api/rbd.service'; | |
12 | import { ActionLabelsI18n } from '../../../shared/constants/app.constants'; | |
13 | import { CdFormGroup } from '../../../shared/forms/cd-form-group'; | |
14 | import { | |
15 | RbdConfigurationEntry, | |
16 | RbdConfigurationSourceField | |
17 | } from '../../../shared/models/configuration'; | |
18 | import { FinishedTask } from '../../../shared/models/finished-task'; | |
19 | import { Permission } from '../../../shared/models/permissions'; | |
20 | import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe'; | |
21 | import { AuthStorageService } from '../../../shared/services/auth-storage.service'; | |
22 | import { FormatterService } from '../../../shared/services/formatter.service'; | |
23 | import { TaskWrapperService } from '../../../shared/services/task-wrapper.service'; | |
494da23a | 24 | import { RbdImageFeature } from './rbd-feature.interface'; |
11fdf7f2 TL |
25 | import { RbdFormCloneRequestModel } from './rbd-form-clone-request.model'; |
26 | import { RbdFormCopyRequestModel } from './rbd-form-copy-request.model'; | |
27 | import { RbdFormCreateRequestModel } from './rbd-form-create-request.model'; | |
28 | import { RbdFormEditRequestModel } from './rbd-form-edit-request.model'; | |
29 | import { RbdFormMode } from './rbd-form-mode.enum'; | |
30 | import { RbdFormResponseModel } from './rbd-form-response.model'; | |
31 | ||
32 | @Component({ | |
33 | selector: 'cd-rbd-form', | |
34 | templateUrl: './rbd-form.component.html', | |
35 | styleUrls: ['./rbd-form.component.scss'] | |
36 | }) | |
37 | export class RbdFormComponent implements OnInit { | |
38 | poolPermission: Permission; | |
39 | rbdForm: CdFormGroup; | |
11fdf7f2 TL |
40 | getDirtyConfigurationValues: ( |
41 | includeLocalField?: boolean, | |
42 | localField?: RbdConfigurationSourceField | |
43 | ) => RbdConfigurationEntry[]; | |
44 | ||
45 | pools: Array<string> = null; | |
46 | allPools: Array<string> = null; | |
47 | dataPools: Array<string> = null; | |
48 | allDataPools: Array<string> = null; | |
494da23a TL |
49 | features: { [key: string]: RbdImageFeature }; |
50 | featuresList: RbdImageFeature[] = []; | |
11fdf7f2 TL |
51 | initializeConfigData = new EventEmitter<{ |
52 | initialData: RbdConfigurationEntry[]; | |
53 | sourceType: RbdConfigurationSourceField; | |
54 | }>(); | |
55 | ||
56 | pool: string; | |
57 | ||
58 | advancedEnabled = false; | |
59 | ||
60 | public rbdFormMode = RbdFormMode; | |
61 | mode: RbdFormMode; | |
62 | ||
63 | response: RbdFormResponseModel; | |
64 | snapName: string; | |
65 | ||
66 | defaultObjectSize = '4 MiB'; | |
67 | ||
68 | objectSizes: Array<string> = [ | |
69 | '4 KiB', | |
70 | '8 KiB', | |
71 | '16 KiB', | |
72 | '32 KiB', | |
73 | '64 KiB', | |
74 | '128 KiB', | |
75 | '256 KiB', | |
76 | '512 KiB', | |
77 | '1 MiB', | |
78 | '2 MiB', | |
79 | '4 MiB', | |
80 | '8 MiB', | |
81 | '16 MiB', | |
82 | '32 MiB' | |
83 | ]; | |
84 | action: string; | |
85 | resource: string; | |
eafe8130 | 86 | private rbdImage = new AsyncSubject(); |
11fdf7f2 TL |
87 | |
88 | constructor( | |
89 | private authStorageService: AuthStorageService, | |
90 | private route: ActivatedRoute, | |
11fdf7f2 TL |
91 | private poolService: PoolService, |
92 | private rbdService: RbdService, | |
93 | private formatter: FormatterService, | |
94 | private taskWrapper: TaskWrapperService, | |
95 | private dimlessBinaryPipe: DimlessBinaryPipe, | |
96 | private i18n: I18n, | |
494da23a TL |
97 | public actionLabels: ActionLabelsI18n, |
98 | public router: Router | |
11fdf7f2 TL |
99 | ) { |
100 | this.poolPermission = this.authStorageService.getPermissions().pool; | |
101 | this.resource = this.i18n('RBD'); | |
102 | this.features = { | |
103 | 'deep-flatten': { | |
104 | desc: this.i18n('Deep flatten'), | |
105 | requires: null, | |
106 | allowEnable: false, | |
107 | allowDisable: true | |
108 | }, | |
109 | layering: { | |
110 | desc: this.i18n('Layering'), | |
111 | requires: null, | |
112 | allowEnable: false, | |
113 | allowDisable: false | |
114 | }, | |
115 | 'exclusive-lock': { | |
116 | desc: this.i18n('Exclusive lock'), | |
117 | requires: null, | |
118 | allowEnable: true, | |
119 | allowDisable: true | |
120 | }, | |
121 | 'object-map': { | |
122 | desc: this.i18n('Object map (requires exclusive-lock)'), | |
123 | requires: 'exclusive-lock', | |
124 | allowEnable: true, | |
494da23a TL |
125 | allowDisable: true, |
126 | initDisabled: true | |
11fdf7f2 TL |
127 | }, |
128 | journaling: { | |
129 | desc: this.i18n('Journaling (requires exclusive-lock)'), | |
130 | requires: 'exclusive-lock', | |
131 | allowEnable: true, | |
494da23a TL |
132 | allowDisable: true, |
133 | initDisabled: true | |
11fdf7f2 TL |
134 | }, |
135 | 'fast-diff': { | |
494da23a | 136 | desc: this.i18n('Fast diff (interlocked with object-map)'), |
11fdf7f2 TL |
137 | requires: 'object-map', |
138 | allowEnable: true, | |
494da23a TL |
139 | allowDisable: true, |
140 | interlockedWith: 'object-map', | |
141 | initDisabled: true | |
11fdf7f2 TL |
142 | } |
143 | }; | |
494da23a | 144 | this.featuresList = this.objToArray(this.features); |
11fdf7f2 | 145 | this.createForm(); |
494da23a TL |
146 | } |
147 | ||
148 | objToArray(obj: { [key: string]: any }) { | |
149 | return _.map(obj, (o, key) => Object.assign(o, { key: key })); | |
11fdf7f2 TL |
150 | } |
151 | ||
152 | createForm() { | |
11fdf7f2 TL |
153 | this.rbdForm = new CdFormGroup( |
154 | { | |
155 | parent: new FormControl(''), | |
156 | name: new FormControl('', { | |
157 | validators: [Validators.required, Validators.pattern(/^[^@/]+?$/)] | |
158 | }), | |
159 | pool: new FormControl(null, { | |
160 | validators: [Validators.required] | |
161 | }), | |
162 | useDataPool: new FormControl(false), | |
163 | dataPool: new FormControl(null), | |
164 | size: new FormControl(null, { | |
165 | updateOn: 'blur' | |
166 | }), | |
167 | obj_size: new FormControl(this.defaultObjectSize), | |
494da23a TL |
168 | features: new CdFormGroup( |
169 | this.featuresList.reduce((acc, e) => { | |
170 | acc[e.key] = new FormControl({ value: false, disabled: !!e.initDisabled }); | |
171 | return acc; | |
172 | }, {}) | |
173 | ), | |
11fdf7f2 TL |
174 | stripingUnit: new FormControl(null), |
175 | stripingCount: new FormControl(null, { | |
176 | updateOn: 'blur' | |
177 | }) | |
178 | }, | |
179 | this.validateRbdForm(this.formatter) | |
180 | ); | |
181 | } | |
182 | ||
183 | disableForEdit() { | |
184 | this.rbdForm.get('parent').disable(); | |
185 | this.rbdForm.get('pool').disable(); | |
186 | this.rbdForm.get('useDataPool').disable(); | |
187 | this.rbdForm.get('dataPool').disable(); | |
188 | this.rbdForm.get('obj_size').disable(); | |
189 | this.rbdForm.get('stripingUnit').disable(); | |
190 | this.rbdForm.get('stripingCount').disable(); | |
191 | } | |
192 | ||
193 | disableForClone() { | |
194 | this.rbdForm.get('parent').disable(); | |
195 | this.rbdForm.get('size').disable(); | |
196 | } | |
197 | ||
198 | disableForCopy() { | |
199 | this.rbdForm.get('parent').disable(); | |
200 | this.rbdForm.get('size').disable(); | |
201 | } | |
202 | ||
203 | ngOnInit() { | |
204 | if (this.router.url.startsWith('/block/rbd/edit')) { | |
205 | this.mode = this.rbdFormMode.editing; | |
206 | this.action = this.actionLabels.EDIT; | |
207 | this.disableForEdit(); | |
208 | } else if (this.router.url.startsWith('/block/rbd/clone')) { | |
209 | this.mode = this.rbdFormMode.cloning; | |
210 | this.disableForClone(); | |
211 | this.action = this.actionLabels.CLONE; | |
212 | } else if (this.router.url.startsWith('/block/rbd/copy')) { | |
213 | this.mode = this.rbdFormMode.copying; | |
214 | this.action = this.actionLabels.COPY; | |
215 | this.disableForCopy(); | |
216 | } else { | |
217 | this.action = this.actionLabels.CREATE; | |
218 | } | |
219 | if ( | |
220 | this.mode === this.rbdFormMode.editing || | |
221 | this.mode === this.rbdFormMode.cloning || | |
222 | this.mode === this.rbdFormMode.copying | |
223 | ) { | |
224 | this.route.params.subscribe((params: { pool: string; name: string; snap: string }) => { | |
225 | const poolName = decodeURIComponent(params.pool); | |
226 | const rbdName = decodeURIComponent(params.name); | |
227 | if (params.snap) { | |
228 | this.snapName = decodeURIComponent(params.snap); | |
229 | } | |
230 | this.rbdService.get(poolName, rbdName).subscribe((resp: RbdFormResponseModel) => { | |
231 | this.setResponse(resp, this.snapName); | |
eafe8130 | 232 | this.rbdImage.next(resp); |
11fdf7f2 TL |
233 | }); |
234 | }); | |
235 | } else { | |
494da23a | 236 | // New image |
11fdf7f2 TL |
237 | this.rbdService.defaultFeatures().subscribe((defaultFeatures: Array<string>) => { |
238 | this.setFeatures(defaultFeatures); | |
239 | }); | |
240 | } | |
241 | if (this.mode !== this.rbdFormMode.editing && this.poolPermission.read) { | |
242 | this.poolService | |
243 | .list(['pool_name', 'type', 'flags_names', 'application_metadata']) | |
244 | .then((resp) => { | |
245 | const pools = []; | |
246 | const dataPools = []; | |
247 | for (const pool of resp) { | |
248 | if (_.indexOf(pool.application_metadata, 'rbd') !== -1) { | |
249 | if (!pool.pool_name.includes('/')) { | |
250 | if (pool.type === 'replicated') { | |
251 | pools.push(pool); | |
252 | dataPools.push(pool); | |
253 | } else if ( | |
254 | pool.type === 'erasure' && | |
255 | pool.flags_names.indexOf('ec_overwrites') !== -1 | |
256 | ) { | |
257 | dataPools.push(pool); | |
258 | } | |
259 | } | |
260 | } | |
261 | } | |
262 | this.pools = pools; | |
263 | this.allPools = pools; | |
264 | this.dataPools = dataPools; | |
265 | this.allDataPools = dataPools; | |
266 | if (this.pools.length === 1) { | |
267 | const poolName = this.pools[0]['pool_name']; | |
268 | this.rbdForm.get('pool').setValue(poolName); | |
269 | this.onPoolChange(poolName); | |
270 | } | |
271 | }); | |
272 | } | |
494da23a TL |
273 | _.each(this.features, (feature) => { |
274 | this.rbdForm | |
275 | .get('features') | |
276 | .get(feature.key) | |
277 | .valueChanges.subscribe((value) => this.featureFormUpdate(feature.key, value)); | |
11fdf7f2 TL |
278 | }); |
279 | } | |
280 | ||
281 | onPoolChange(selectedPoolName) { | |
282 | const newDataPools = this.allDataPools.filter((dataPool: any) => { | |
283 | return dataPool.pool_name !== selectedPoolName; | |
284 | }); | |
285 | if (this.rbdForm.getValue('dataPool') === selectedPoolName) { | |
286 | this.rbdForm.get('dataPool').setValue(null); | |
287 | } | |
288 | this.dataPools = newDataPools; | |
289 | } | |
290 | ||
291 | onUseDataPoolChange() { | |
292 | if (!this.rbdForm.getValue('useDataPool')) { | |
293 | this.rbdForm.get('dataPool').setValue(null); | |
294 | this.onDataPoolChange(null); | |
295 | } | |
296 | } | |
297 | ||
298 | onDataPoolChange(selectedDataPoolName) { | |
299 | const newPools = this.allPools.filter((pool: any) => { | |
300 | return pool.pool_name !== selectedDataPoolName; | |
301 | }); | |
302 | if (this.rbdForm.getValue('pool') === selectedDataPoolName) { | |
303 | this.rbdForm.get('pool').setValue(null); | |
304 | } | |
305 | this.pools = newPools; | |
306 | } | |
307 | ||
308 | validateRbdForm(formatter: FormatterService): ValidatorFn { | |
309 | return (formGroup: CdFormGroup) => { | |
310 | // Data Pool | |
311 | const useDataPoolControl = formGroup.get('useDataPool'); | |
312 | const dataPoolControl = formGroup.get('dataPool'); | |
313 | let dataPoolControlErrors = null; | |
314 | if (useDataPoolControl.value && dataPoolControl.value == null) { | |
315 | dataPoolControlErrors = { required: true }; | |
316 | } | |
317 | dataPoolControl.setErrors(dataPoolControlErrors); | |
318 | // Size | |
319 | const sizeControl = formGroup.get('size'); | |
320 | const objectSizeControl = formGroup.get('obj_size'); | |
321 | const objectSizeInBytes = formatter.toBytes( | |
322 | objectSizeControl.value != null ? objectSizeControl.value : this.defaultObjectSize | |
323 | ); | |
324 | const stripingCountControl = formGroup.get('stripingCount'); | |
325 | const stripingCount = stripingCountControl.value != null ? stripingCountControl.value : 1; | |
326 | let sizeControlErrors = null; | |
327 | if (sizeControl.value === null) { | |
328 | sizeControlErrors = { required: true }; | |
329 | } else { | |
330 | const sizeInBytes = formatter.toBytes(sizeControl.value); | |
331 | if (stripingCount * objectSizeInBytes > sizeInBytes) { | |
332 | sizeControlErrors = { invalidSizeObject: true }; | |
333 | } | |
334 | } | |
335 | sizeControl.setErrors(sizeControlErrors); | |
336 | // Striping Unit | |
337 | const stripingUnitControl = formGroup.get('stripingUnit'); | |
338 | let stripingUnitControlErrors = null; | |
339 | if (stripingUnitControl.value === null && stripingCountControl.value !== null) { | |
340 | stripingUnitControlErrors = { required: true }; | |
341 | } else if (stripingUnitControl.value !== null) { | |
342 | const stripingUnitInBytes = formatter.toBytes(stripingUnitControl.value); | |
343 | if (stripingUnitInBytes > objectSizeInBytes) { | |
344 | stripingUnitControlErrors = { invalidStripingUnit: true }; | |
345 | } | |
346 | } | |
347 | stripingUnitControl.setErrors(stripingUnitControlErrors); | |
348 | // Striping Count | |
349 | let stripingCountControlErrors = null; | |
350 | if (stripingCountControl.value === null && stripingUnitControl.value !== null) { | |
351 | stripingCountControlErrors = { required: true }; | |
352 | } else if (stripingCount < 1) { | |
353 | stripingCountControlErrors = { min: true }; | |
354 | } | |
355 | stripingCountControl.setErrors(stripingCountControlErrors); | |
356 | return null; | |
357 | }; | |
358 | } | |
359 | ||
494da23a TL |
360 | protected getDependendChildFeatures(featureKey: string) { |
361 | return _.filter(this.features, (f) => f.requires === featureKey) || []; | |
362 | } | |
363 | ||
11fdf7f2 | 364 | deepBoxCheck(key, checked) { |
494da23a TL |
365 | const childFeatures = this.getDependendChildFeatures(key); |
366 | childFeatures.forEach((feature) => { | |
367 | const featureControl = this.rbdForm.get(feature.key); | |
368 | if (checked) { | |
369 | featureControl.enable({ emitEvent: false }); | |
370 | } else { | |
371 | featureControl.disable({ emitEvent: false }); | |
372 | featureControl.setValue(false, { emitEvent: false }); | |
373 | this.deepBoxCheck(feature.key, checked); | |
11fdf7f2 | 374 | } |
494da23a TL |
375 | |
376 | const featureFormGroup = this.rbdForm.get('features'); | |
377 | if (this.mode === this.rbdFormMode.editing && featureFormGroup.get(feature.key).enabled) { | |
378 | if (this.response.features_name.indexOf(feature.key) !== -1 && !feature.allowDisable) { | |
379 | featureFormGroup.get(feature.key).disable(); | |
380 | } else if ( | |
381 | this.response.features_name.indexOf(feature.key) === -1 && | |
382 | !feature.allowEnable | |
383 | ) { | |
384 | featureFormGroup.get(feature.key).disable(); | |
11fdf7f2 TL |
385 | } |
386 | } | |
387 | }); | |
388 | } | |
389 | ||
494da23a TL |
390 | interlockCheck(key, checked) { |
391 | // Adds a compatibility layer for Ceph cluster where the feature interlock of features hasn't | |
392 | // been implemented yet. It disables the feature interlock for images which only have one of | |
393 | // both interlocked features (at the time of this writing: object-map and fast-diff) enabled. | |
394 | const feature = this.featuresList.find((f) => f.key === key); | |
395 | if (this.response) { | |
396 | // Ignore `create` page | |
397 | const hasInterlockedFeature = feature.interlockedWith != null; | |
398 | const dependentInterlockedFeature = this.featuresList.find( | |
399 | (f) => f.interlockedWith === feature.key | |
400 | ); | |
401 | const isOriginFeatureEnabled = !!this.response.features_name.find((e) => e === feature.key); // in this case: fast-diff | |
402 | if (hasInterlockedFeature) { | |
403 | const isLinkedEnabled = !!this.response.features_name.find( | |
404 | (e) => e === feature.interlockedWith | |
405 | ); // depends: object-map | |
406 | if (isOriginFeatureEnabled !== isLinkedEnabled) { | |
407 | return; // Ignore incompatible setting because it's from a previous cluster version | |
408 | } | |
409 | } else if (dependentInterlockedFeature) { | |
410 | const isOtherInterlockedFeatureEnabled = !!this.response.features_name.find( | |
411 | (e) => e === dependentInterlockedFeature.key | |
412 | ); | |
413 | if (isOtherInterlockedFeatureEnabled !== isOriginFeatureEnabled) { | |
414 | return; // Ignore incompatible setting because it's from a previous cluster version | |
415 | } | |
416 | } | |
417 | } | |
418 | ||
419 | if (checked) { | |
420 | _.filter(this.features, (f) => f.interlockedWith === key).forEach((f) => | |
421 | this.rbdForm.get(f.key).setValue(true, { emitEvent: false }) | |
422 | ); | |
423 | } else { | |
424 | if (feature.interlockedWith) { | |
425 | // Don't skip emitting the event here, as it prevents `fast-diff` from | |
426 | // becoming disabled when manually unchecked. This is because it | |
427 | // triggers an update on `object-map` and if `object-map` doesn't emit, | |
428 | // `fast-diff` will not be automatically disabled. | |
429 | this.rbdForm | |
430 | .get('features') | |
431 | .get(feature.interlockedWith) | |
432 | .setValue(false); | |
433 | } | |
434 | } | |
435 | } | |
436 | ||
11fdf7f2 TL |
437 | featureFormUpdate(key, checked) { |
438 | if (checked) { | |
439 | const required = this.features[key].requires; | |
440 | if (required && !this.rbdForm.getValue(required)) { | |
494da23a | 441 | this.rbdForm.get(`features.${key}`).setValue(false); |
11fdf7f2 TL |
442 | return; |
443 | } | |
444 | } | |
445 | this.deepBoxCheck(key, checked); | |
494da23a | 446 | this.interlockCheck(key, checked); |
11fdf7f2 TL |
447 | } |
448 | ||
449 | setFeatures(features: Array<string>) { | |
450 | const featuresControl = this.rbdForm.get('features'); | |
451 | _.forIn(this.features, (feature) => { | |
452 | if (features.indexOf(feature.key) !== -1) { | |
453 | featuresControl.get(feature.key).setValue(true); | |
454 | } | |
494da23a | 455 | this.featureFormUpdate(feature.key, featuresControl.get(feature.key).value); |
11fdf7f2 TL |
456 | }); |
457 | } | |
458 | ||
459 | setResponse(response: RbdFormResponseModel, snapName: string) { | |
460 | this.response = response; | |
461 | if (this.mode === this.rbdFormMode.cloning) { | |
462 | this.rbdForm.get('parent').setValue(`${response.pool_name}/${response.name}@${snapName}`); | |
463 | } else if (this.mode === this.rbdFormMode.copying) { | |
464 | if (snapName) { | |
465 | this.rbdForm.get('parent').setValue(`${response.pool_name}/${response.name}@${snapName}`); | |
466 | } else { | |
467 | this.rbdForm.get('parent').setValue(`${response.pool_name}/${response.name}`); | |
468 | } | |
469 | } else if (response.parent) { | |
470 | const parent = response.parent; | |
471 | this.rbdForm | |
472 | .get('parent') | |
473 | .setValue(`${parent.pool_name}/${parent.image_name}@${parent.snap_name}`); | |
474 | } | |
475 | if (this.mode === this.rbdFormMode.editing) { | |
476 | this.rbdForm.get('name').setValue(response.name); | |
477 | } | |
478 | this.rbdForm.get('pool').setValue(response.pool_name); | |
479 | if (response.data_pool) { | |
480 | this.rbdForm.get('useDataPool').setValue(true); | |
481 | this.rbdForm.get('dataPool').setValue(response.data_pool); | |
482 | } | |
483 | this.rbdForm.get('size').setValue(this.dimlessBinaryPipe.transform(response.size)); | |
484 | this.rbdForm.get('obj_size').setValue(this.dimlessBinaryPipe.transform(response.obj_size)); | |
485 | this.setFeatures(response.features_name); | |
486 | this.rbdForm | |
487 | .get('stripingUnit') | |
488 | .setValue(this.dimlessBinaryPipe.transform(response.stripe_unit)); | |
489 | this.rbdForm.get('stripingCount').setValue(response.stripe_count); | |
490 | ||
491 | /* Configuration */ | |
492 | this.initializeConfigData.emit({ | |
493 | initialData: this.response.configuration, | |
494 | sourceType: RbdConfigurationSourceField.image | |
495 | }); | |
496 | } | |
497 | ||
498 | createRequest() { | |
499 | const request = new RbdFormCreateRequestModel(); | |
500 | request.pool_name = this.rbdForm.getValue('pool'); | |
501 | request.name = this.rbdForm.getValue('name'); | |
502 | request.size = this.formatter.toBytes(this.rbdForm.getValue('size')); | |
503 | request.obj_size = this.formatter.toBytes(this.rbdForm.getValue('obj_size')); | |
504 | _.forIn(this.features, (feature) => { | |
505 | if (this.rbdForm.getValue(feature.key)) { | |
506 | request.features.push(feature.key); | |
507 | } | |
508 | }); | |
509 | ||
510 | /* Striping */ | |
511 | request.stripe_unit = this.formatter.toBytes(this.rbdForm.getValue('stripingUnit')); | |
512 | request.stripe_count = this.rbdForm.getValue('stripingCount'); | |
513 | request.data_pool = this.rbdForm.getValue('dataPool'); | |
514 | ||
515 | /* Configuration */ | |
516 | request.configuration = this.getDirtyConfigurationValues(); | |
517 | ||
518 | return request; | |
519 | } | |
520 | ||
521 | createAction(): Observable<any> { | |
522 | const request = this.createRequest(); | |
523 | return this.taskWrapper.wrapTaskAroundCall({ | |
524 | task: new FinishedTask('rbd/create', { | |
525 | pool_name: request.pool_name, | |
526 | image_name: request.name | |
527 | }), | |
528 | call: this.rbdService.create(request) | |
529 | }); | |
530 | } | |
531 | ||
532 | editRequest() { | |
533 | const request = new RbdFormEditRequestModel(); | |
534 | request.name = this.rbdForm.getValue('name'); | |
535 | request.size = this.formatter.toBytes(this.rbdForm.getValue('size')); | |
536 | _.forIn(this.features, (feature) => { | |
537 | if (this.rbdForm.getValue(feature.key)) { | |
538 | request.features.push(feature.key); | |
539 | } | |
540 | }); | |
541 | ||
542 | request.configuration = this.getDirtyConfigurationValues(); | |
543 | ||
544 | return request; | |
545 | } | |
546 | ||
547 | cloneRequest(): RbdFormCloneRequestModel { | |
548 | const request = new RbdFormCloneRequestModel(); | |
549 | request.child_pool_name = this.rbdForm.getValue('pool'); | |
550 | request.child_image_name = this.rbdForm.getValue('name'); | |
551 | request.obj_size = this.formatter.toBytes(this.rbdForm.getValue('obj_size')); | |
552 | _.forIn(this.features, (feature) => { | |
553 | if (this.rbdForm.getValue(feature.key)) { | |
554 | request.features.push(feature.key); | |
555 | } | |
556 | }); | |
557 | ||
558 | /* Striping */ | |
559 | request.stripe_unit = this.formatter.toBytes(this.rbdForm.getValue('stripingUnit')); | |
560 | request.stripe_count = this.rbdForm.getValue('stripingCount'); | |
561 | request.data_pool = this.rbdForm.getValue('dataPool'); | |
562 | ||
563 | /* Configuration */ | |
564 | request.configuration = this.getDirtyConfigurationValues( | |
565 | true, | |
566 | RbdConfigurationSourceField.image | |
567 | ); | |
568 | ||
569 | return request; | |
570 | } | |
571 | ||
572 | editAction(): Observable<any> { | |
573 | return this.taskWrapper.wrapTaskAroundCall({ | |
574 | task: new FinishedTask('rbd/edit', { | |
575 | pool_name: this.response.pool_name, | |
576 | image_name: this.response.name | |
577 | }), | |
578 | call: this.rbdService.update(this.response.pool_name, this.response.name, this.editRequest()) | |
579 | }); | |
580 | } | |
581 | ||
582 | cloneAction(): Observable<any> { | |
583 | const request = this.cloneRequest(); | |
584 | return this.taskWrapper.wrapTaskAroundCall({ | |
585 | task: new FinishedTask('rbd/clone', { | |
586 | parent_pool_name: this.response.pool_name, | |
587 | parent_image_name: this.response.name, | |
588 | parent_snap_name: this.snapName, | |
589 | child_pool_name: request.child_pool_name, | |
590 | child_image_name: request.child_image_name | |
591 | }), | |
592 | call: this.rbdService.cloneSnapshot( | |
593 | this.response.pool_name, | |
594 | this.response.name, | |
595 | this.snapName, | |
596 | request | |
597 | ) | |
598 | }); | |
599 | } | |
600 | ||
601 | copyRequest(): RbdFormCopyRequestModel { | |
602 | const request = new RbdFormCopyRequestModel(); | |
603 | if (this.snapName) { | |
604 | request.snapshot_name = this.snapName; | |
605 | } | |
606 | request.dest_pool_name = this.rbdForm.getValue('pool'); | |
607 | request.dest_image_name = this.rbdForm.getValue('name'); | |
608 | request.obj_size = this.formatter.toBytes(this.rbdForm.getValue('obj_size')); | |
609 | _.forIn(this.features, (feature) => { | |
610 | if (this.rbdForm.getValue(feature.key)) { | |
611 | request.features.push(feature.key); | |
612 | } | |
613 | }); | |
614 | ||
615 | /* Striping */ | |
616 | request.stripe_unit = this.formatter.toBytes(this.rbdForm.getValue('stripingUnit')); | |
617 | request.stripe_count = this.rbdForm.getValue('stripingCount'); | |
618 | request.data_pool = this.rbdForm.getValue('dataPool'); | |
619 | ||
620 | /* Configuration */ | |
621 | request.configuration = this.getDirtyConfigurationValues( | |
622 | true, | |
623 | RbdConfigurationSourceField.image | |
624 | ); | |
625 | ||
626 | return request; | |
627 | } | |
628 | ||
629 | copyAction(): Observable<any> { | |
630 | const request = this.copyRequest(); | |
631 | ||
632 | return this.taskWrapper.wrapTaskAroundCall({ | |
633 | task: new FinishedTask('rbd/copy', { | |
634 | src_pool_name: this.response.pool_name, | |
635 | src_image_name: this.response.name, | |
636 | dest_pool_name: request.dest_pool_name, | |
637 | dest_image_name: request.dest_image_name | |
638 | }), | |
639 | call: this.rbdService.copy(this.response.pool_name, this.response.name, request) | |
640 | }); | |
641 | } | |
642 | ||
643 | submit() { | |
eafe8130 TL |
644 | if (!this.mode) { |
645 | this.rbdImage.next('create'); | |
11fdf7f2 | 646 | } |
eafe8130 TL |
647 | this.rbdImage.complete(); |
648 | this.rbdImage | |
649 | .pipe( | |
650 | switchMap(() => { | |
651 | if (this.mode === this.rbdFormMode.editing) { | |
652 | return this.editAction(); | |
653 | } else if (this.mode === this.rbdFormMode.cloning) { | |
654 | return this.cloneAction(); | |
655 | } else if (this.mode === this.rbdFormMode.copying) { | |
656 | return this.copyAction(); | |
657 | } else { | |
658 | return this.createAction(); | |
659 | } | |
660 | }) | |
661 | ) | |
662 | .subscribe( | |
663 | () => {}, | |
664 | () => this.rbdForm.setErrors({ cdSubmitButton: true }), | |
665 | () => this.router.navigate(['/block/rbd']) | |
666 | ); | |
11fdf7f2 TL |
667 | } |
668 | } |