]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
b2b8862109fc46a2db8c8c35b24e055069cfd872
[ceph.git] /
1 import { Component, OnInit } from '@angular/core';
2 import { FormControl, Validators } from '@angular/forms';
3 import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
4 import { CdForm } from '~/app/shared/forms/cd-form';
5 import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
6 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
7 import _ from 'lodash';
8 import { ActivatedRoute, Router } from '@angular/router';
9 import { RgwStorageClassService } from '~/app/shared/api/rgw-storage-class.service';
10 import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service';
11 import {
12   ALLOW_READ_THROUGH_TEXT,
13   CLOUD_TIER,
14   DEFAULT_PLACEMENT,
15   MULTIPART_MIN_PART_TEXT,
16   MULTIPART_SYNC_THRESHOLD_TEXT,
17   PlacementTarget,
18   RequestModel,
19   RETAIN_HEAD_OBJECT_TEXT,
20   StorageClass,
21   Target,
22   TARGET_ACCESS_KEY_TEXT,
23   TARGET_ENDPOINT_TEXT,
24   TARGET_PATH_TEXT,
25   TARGET_REGION_TEXT,
26   TARGET_SECRET_KEY_TEXT,
27   TierTarget,
28   ZoneGroup,
29   ZoneGroupDetails
30 } from '../models/rgw-storage-class.model';
31 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
32 import { NotificationService } from '~/app/shared/services/notification.service';
33
34 @Component({
35   selector: 'cd-rgw-storage-class-form',
36   templateUrl: './rgw-storage-class-form.component.html',
37   styleUrls: ['./rgw-storage-class-form.component.scss']
38 })
39 export class RgwStorageClassFormComponent extends CdForm implements OnInit {
40   storageClassForm: CdFormGroup;
41   action: string;
42   resource: string;
43   editing: boolean;
44   targetPathText: string;
45   targetEndpointText: string;
46   targetRegionText: string;
47   showAdvanced: boolean = false;
48   defaultZoneGroup: string;
49   zonegroupNames: ZoneGroup[];
50   placementTargets: string[] = [];
51   multipartMinPartText: string;
52   multipartSyncThreholdText: string;
53   selectedZoneGroup: string;
54   defaultZonegroup: ZoneGroup;
55   zoneGroupDetails: ZoneGroupDetails;
56   targetSecretKeyText: string;
57   targetAccessKeyText: string;
58   retainHeadObjectText: string;
59   storageClassInfo: StorageClass;
60   tierTargetInfo: TierTarget;
61   allowReadThroughText: string;
62   allowReadThrough: boolean = false;
63
64   constructor(
65     public actionLabels: ActionLabelsI18n,
66     private formBuilder: CdFormBuilder,
67     private notificationService: NotificationService,
68     private rgwStorageService: RgwStorageClassService,
69     private rgwZoneGroupService: RgwZonegroupService,
70     private router: Router,
71     private route: ActivatedRoute
72   ) {
73     super();
74     this.resource = $localize`Tiering Storage Class`;
75     this.editing = this.router.url.startsWith(`/rgw/tiering/${URLVerbs.EDIT}`);
76     this.action = this.editing ? this.actionLabels.EDIT : this.actionLabels.CREATE;
77   }
78
79   ngOnInit() {
80     this.multipartMinPartText = MULTIPART_MIN_PART_TEXT;
81     this.multipartSyncThreholdText = MULTIPART_SYNC_THRESHOLD_TEXT;
82     this.targetPathText = TARGET_PATH_TEXT;
83     this.targetRegionText = TARGET_REGION_TEXT;
84     this.targetEndpointText = TARGET_ENDPOINT_TEXT;
85     this.targetAccessKeyText = TARGET_ACCESS_KEY_TEXT;
86     this.targetSecretKeyText = TARGET_SECRET_KEY_TEXT;
87     this.retainHeadObjectText = RETAIN_HEAD_OBJECT_TEXT;
88     this.allowReadThroughText = ALLOW_READ_THROUGH_TEXT;
89     this.createForm();
90     this.loadingReady();
91     this.loadZoneGroup();
92     if (this.editing) {
93       this.route.params.subscribe((params: StorageClass) => {
94         this.storageClassInfo = params;
95       });
96       this.rgwStorageService
97         .getPlacement_target(this.storageClassInfo.placement_target)
98         .subscribe((placementTargetInfo: PlacementTarget) => {
99           this.tierTargetInfo = this.getTierTargetByStorageClass(
100             placementTargetInfo,
101             this.storageClassInfo.storage_class
102           );
103           let response = this.tierTargetInfo.val.s3;
104           this.storageClassForm.get('zonegroup').disable();
105           this.storageClassForm.get('placement_target').disable();
106           this.storageClassForm.get('storage_class').disable();
107           this.storageClassForm.get('zonegroup').setValue(this.storageClassInfo.zonegroup_name);
108           this.storageClassForm.get('region').setValue(response.region);
109           this.storageClassForm
110             .get('placement_target')
111             .setValue(this.storageClassInfo.placement_target);
112           this.storageClassForm.get('endpoint').setValue(response.endpoint);
113           this.storageClassForm.get('storage_class').setValue(this.storageClassInfo.storage_class);
114           this.storageClassForm.get('access_key').setValue(response.access_key);
115           this.storageClassForm.get('secret_key').setValue(response.secret);
116           this.storageClassForm.get('target_path').setValue(response.target_path);
117           this.storageClassForm
118             .get('retain_head_object')
119             .setValue(this.tierTargetInfo?.val?.retain_head_object || false);
120           this.storageClassForm
121             .get('multipart_sync_threshold')
122             .setValue(response.multipart_sync_threshold || '');
123           this.storageClassForm
124             .get('multipart_min_part_size')
125             .setValue(response.multipart_min_part_size || '');
126           this.storageClassForm
127             .get('allow_read_through')
128             .setValue(this.tierTargetInfo?.val?.allow_read_through || false);
129         });
130     }
131     this.storageClassForm.get('allow_read_through').valueChanges.subscribe((value) => {
132       this.onAllowReadThroughChange(value);
133     });
134   }
135
136   createForm() {
137     this.storageClassForm = this.formBuilder.group({
138       storage_class: new FormControl('', {
139         validators: [Validators.required]
140       }),
141       zonegroup: new FormControl(this.selectedZoneGroup, {
142         validators: [Validators.required]
143       }),
144       region: new FormControl('', {
145         validators: [Validators.required]
146       }),
147       placement_target: new FormControl('', {
148         validators: [Validators.required]
149       }),
150       endpoint: new FormControl(null, {
151         validators: [Validators.required]
152       }),
153       access_key: new FormControl(null, Validators.required),
154       secret_key: new FormControl(null, Validators.required),
155       target_path: new FormControl('', {
156         validators: [Validators.required]
157       }),
158       retain_head_object: new FormControl(true),
159       multipart_sync_threshold: new FormControl(33554432),
160       multipart_min_part_size: new FormControl(33554432),
161       allow_read_through: new FormControl(false)
162     });
163   }
164
165   loadZoneGroup(): Promise<void> {
166     return new Promise((resolve, reject) => {
167       this.rgwZoneGroupService.getAllZonegroupsInfo().subscribe(
168         (data: ZoneGroupDetails) => {
169           this.zoneGroupDetails = data;
170           this.zonegroupNames = [];
171           this.placementTargets = [];
172           if (data.zonegroups && data.zonegroups.length > 0) {
173             this.zonegroupNames = data.zonegroups.map((zoneGroup: ZoneGroup) => {
174               return {
175                 id: zoneGroup.id,
176                 name: zoneGroup.name
177               };
178             });
179           }
180           this.defaultZonegroup = this.zonegroupNames.find(
181             (zonegroups: ZoneGroup) => zonegroups.id === data.default_zonegroup
182           );
183
184           this.storageClassForm.get('zonegroup').setValue(this.defaultZonegroup.name);
185           this.onZonegroupChange();
186           resolve();
187         },
188         (error) => reject(error)
189       );
190     });
191   }
192
193   onZonegroupChange() {
194     const zoneGroupControl = this.storageClassForm.get('zonegroup').value;
195     const selectedZoneGroup = this.zoneGroupDetails.zonegroups.find(
196       (zonegroup) => zonegroup.name === zoneGroupControl
197     );
198     const defaultPlacementTarget = selectedZoneGroup.placement_targets.find(
199       (target: Target) => target.name === DEFAULT_PLACEMENT
200     );
201     if (selectedZoneGroup) {
202       const placementTargetNames = selectedZoneGroup.placement_targets.map(
203         (target: Target) => target.name
204       );
205       this.placementTargets = placementTargetNames;
206     }
207     if (defaultPlacementTarget && !this.editing) {
208       this.storageClassForm.get('placement_target').setValue(defaultPlacementTarget.name);
209     } else {
210       this.storageClassForm
211         .get('placement_target')
212         .setValue(this.storageClassInfo.placement_target);
213     }
214   }
215
216   submitAction() {
217     const component = this;
218     const requestModel = this.buildRequest();
219     const storageclassName = this.storageClassForm.get('storage_class').value;
220     if (this.editing) {
221       this.rgwStorageService.editStorageClass(requestModel).subscribe(
222         () => {
223           this.notificationService.show(
224             NotificationType.success,
225             $localize`Updated Storage Class '${storageclassName}'`
226           );
227           this.goToListView();
228         },
229         () => {
230           component.storageClassForm.setErrors({ cdSubmitButton: true });
231         }
232       );
233     } else {
234       this.rgwStorageService.createStorageClass(requestModel).subscribe(
235         () => {
236           this.notificationService.show(
237             NotificationType.success,
238             $localize`Created Storage Class '${storageclassName}'`
239           );
240           this.goToListView();
241         },
242         () => {
243           component.storageClassForm.setErrors({ cdSubmitButton: true });
244         }
245       );
246     }
247   }
248
249   goToListView() {
250     this.router.navigate([`rgw/tiering`]);
251   }
252
253   getTierTargetByStorageClass(placementTargetInfo: PlacementTarget, storageClass: string) {
254     const tierTarget = placementTargetInfo.tier_targets.find(
255       (target: TierTarget) => target.val.storage_class === storageClass
256     );
257     return tierTarget;
258   }
259
260   onAllowReadThroughChange(checked: boolean): void {
261     this.allowReadThrough = checked;
262     if (this.allowReadThrough) {
263       this.storageClassForm.get('retain_head_object')?.setValue(true);
264       this.storageClassForm.get('retain_head_object')?.disable();
265     } else {
266       this.storageClassForm.get('retain_head_object')?.enable();
267     }
268   }
269
270   buildRequest() {
271     const rawFormValue = _.cloneDeep(this.storageClassForm.value);
272     const zoneGroup = this.storageClassForm.get('zonegroup').value;
273     const storageClass = this.storageClassForm.get('storage_class').value;
274     const placementId = this.storageClassForm.get('placement_target').value;
275     const headObject = this.storageClassForm.get('retain_head_object').value;
276     const requestModel: RequestModel = {
277       zone_group: zoneGroup,
278       placement_targets: [
279         {
280           tags: [],
281           placement_id: placementId,
282           storage_class: storageClass,
283           tier_type: CLOUD_TIER,
284           tier_config: {
285             endpoint: rawFormValue.endpoint,
286             access_key: rawFormValue.access_key,
287             secret: rawFormValue.secret_key,
288             target_path: rawFormValue.target_path,
289             retain_head_object: headObject,
290             allow_read_through: rawFormValue.allow_read_through,
291             region: rawFormValue.region,
292             multipart_sync_threshold: rawFormValue.multipart_sync_threshold,
293             multipart_min_part_size: rawFormValue.multipart_min_part_size
294           }
295         }
296       ]
297     };
298     return requestModel;
299   }
300 }