]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
d380f08bcc0f65191c6681fba1604d28546acb0b
[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   CLOUD_TIER,
13   DEFAULT_PLACEMENT,
14   PlacementTarget,
15   RequestModel,
16   StorageClass,
17   Target,
18   TierTarget,
19   ZoneGroup,
20   ZoneGroupDetails
21 } from '../models/rgw-storage-class.model';
22 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
23 import { NotificationService } from '~/app/shared/services/notification.service';
24
25 @Component({
26   selector: 'cd-rgw-storage-class-form',
27   templateUrl: './rgw-storage-class-form.component.html',
28   styleUrls: ['./rgw-storage-class-form.component.scss']
29 })
30 export class RgwStorageClassFormComponent extends CdForm implements OnInit {
31   storageClassForm: CdFormGroup;
32   action: string;
33   resource: string;
34   editing: boolean;
35   targetPathText: string;
36   targetEndpointText: string;
37   targetRegionText: string;
38   showAdvanced: boolean = false;
39   defaultZoneGroup: string;
40   zonegroupNames: ZoneGroup[];
41   placementTargets: string[] = [];
42   multipartMinPartText: string;
43   multipartSyncThreholdText: string;
44   selectedZoneGroup: string;
45   defaultZonegroup: ZoneGroup;
46   zoneGroupDetails: ZoneGroupDetails;
47   targetSecretKeyText: string;
48   targetAccessKeyText: string;
49   retainHeadObjectText: string;
50   storageClassInfo: StorageClass;
51   tierTargetInfo: TierTarget;
52
53   constructor(
54     public actionLabels: ActionLabelsI18n,
55     private formBuilder: CdFormBuilder,
56     private notificationService: NotificationService,
57     private rgwStorageService: RgwStorageClassService,
58     private rgwZoneGroupService: RgwZonegroupService,
59     private router: Router,
60     private route: ActivatedRoute
61   ) {
62     super();
63     this.resource = $localize`Tiering Storage Class`;
64     this.editing = this.router.url.startsWith(`/rgw/tiering/${URLVerbs.EDIT}`);
65     this.action = this.editing ? this.actionLabels.EDIT : this.actionLabels.CREATE;
66   }
67
68   ngOnInit() {
69     this.multipartMinPartText =
70       'It specifies that objects this size or larger are transitioned to the cloud using multipart upload.';
71     this.multipartSyncThreholdText =
72       'It specifies the minimum part size to use when transitioning objects using multipart upload.';
73     this.targetPathText =
74       'Target Path refers to the storage location (e.g., bucket or container) in the cloud where data will be stored.';
75     this.targetRegionText = 'The region of the remote cloud service where storage is located.';
76     this.targetEndpointText = 'The URL endpoint of the remote cloud service for accessing storage.';
77     this.targetAccessKeyText =
78       "To view or copy your access key, go to your cloud service's user management or credentials section, find your user profile, and locate the access key. You can view and copy the key by following the instructions provided.";
79
80     this.targetSecretKeyText =
81       "To view or copy your secret key, go to your cloud service's user management or credentials section, find your user profile, and locate the access key. You can view and copy the key by following the instructions provided.";
82     this.retainHeadObjectText =
83       'Retain object metadata after transition to the cloud (default: deleted).';
84     this.createForm();
85     this.loadingReady();
86     this.loadZoneGroup();
87     if (this.editing) {
88       this.route.params.subscribe((params: StorageClass) => {
89         this.storageClassInfo = params;
90       });
91       this.rgwStorageService
92         .getPlacement_target(this.storageClassInfo.placement_target)
93         .subscribe((placementTargetInfo: PlacementTarget) => {
94           this.tierTargetInfo = this.getTierTargetByStorageClass(
95             placementTargetInfo,
96             this.storageClassInfo.storage_class
97           );
98           let response = this.tierTargetInfo.val.s3;
99           this.storageClassForm.get('zonegroup').disable();
100           this.storageClassForm.get('placement_target').disable();
101           this.storageClassForm.get('storage_class').disable();
102           this.storageClassForm.get('zonegroup').setValue(this.storageClassInfo.zonegroup_name);
103           this.storageClassForm.get('region').setValue(response.region);
104           this.storageClassForm
105             .get('placement_target')
106             .setValue(this.storageClassInfo.placement_target);
107           this.storageClassForm.get('endpoint').setValue(response.endpoint);
108           this.storageClassForm.get('storage_class').setValue(this.storageClassInfo.storage_class);
109           this.storageClassForm.get('access_key').setValue(response.access_key);
110           this.storageClassForm.get('secret_key').setValue(response.access_key);
111           this.storageClassForm.get('target_path').setValue(response.target_path);
112           this.storageClassForm
113             .get('retain_head_object')
114             .setValue(response.retain_head_object || false);
115           this.storageClassForm
116             .get('multipart_sync_threshold')
117             .setValue(response.multipart_sync_threshold || '');
118           this.storageClassForm
119             .get('multipart_min_part_size')
120             .setValue(response.multipart_min_part_size || '');
121         });
122     }
123   }
124
125   createForm() {
126     this.storageClassForm = this.formBuilder.group({
127       storage_class: new FormControl('', {
128         validators: [Validators.required]
129       }),
130       zonegroup: new FormControl(this.selectedZoneGroup, {
131         validators: [Validators.required]
132       }),
133       region: new FormControl('', {
134         validators: [Validators.required]
135       }),
136       placement_target: new FormControl('', {
137         validators: [Validators.required]
138       }),
139       endpoint: new FormControl(null, {
140         validators: [Validators.required]
141       }),
142       access_key: new FormControl(null, Validators.required),
143       secret_key: new FormControl(null, Validators.required),
144       target_path: new FormControl('', {
145         validators: [Validators.required]
146       }),
147       retain_head_object: new FormControl(false),
148       multipart_sync_threshold: new FormControl(33554432),
149       multipart_min_part_size: new FormControl(33554432)
150     });
151   }
152
153   loadZoneGroup(): Promise<void> {
154     return new Promise((resolve, reject) => {
155       this.rgwZoneGroupService.getAllZonegroupsInfo().subscribe(
156         (data: ZoneGroupDetails) => {
157           this.zoneGroupDetails = data;
158           this.zonegroupNames = [];
159           this.placementTargets = [];
160           if (data.zonegroups && data.zonegroups.length > 0) {
161             this.zonegroupNames = data.zonegroups.map((zoneGroup: ZoneGroup) => {
162               return {
163                 id: zoneGroup.id,
164                 name: zoneGroup.name
165               };
166             });
167           }
168           this.defaultZonegroup = this.zonegroupNames.find(
169             (zonegroups: ZoneGroup) => zonegroups.id === data.default_zonegroup
170           );
171
172           this.storageClassForm.get('zonegroup').setValue(this.defaultZonegroup.name);
173           this.onZonegroupChange();
174           resolve();
175         },
176         (error) => reject(error)
177       );
178     });
179   }
180
181   onZonegroupChange() {
182     const zoneGroupControl = this.storageClassForm.get('zonegroup').value;
183     const selectedZoneGroup = this.zoneGroupDetails.zonegroups.find(
184       (zonegroup) => zonegroup.name === zoneGroupControl
185     );
186     const defaultPlacementTarget = selectedZoneGroup.placement_targets.find(
187       (target: Target) => target.name === DEFAULT_PLACEMENT
188     );
189     if (selectedZoneGroup) {
190       const placementTargetNames = selectedZoneGroup.placement_targets.map(
191         (target: Target) => target.name
192       );
193       this.placementTargets = placementTargetNames;
194     }
195     if (defaultPlacementTarget && !this.editing) {
196       this.storageClassForm.get('placement_target').setValue(defaultPlacementTarget.name);
197     } else {
198       this.storageClassForm
199         .get('placement_target')
200         .setValue(this.storageClassInfo.placement_target);
201     }
202   }
203
204   submitAction() {
205     const component = this;
206     const requestModel = this.buildRequest();
207     const storageclassName = this.storageClassForm.get('storage_class').value;
208     if (this.editing) {
209       this.rgwStorageService.editStorageClass(requestModel).subscribe(
210         () => {
211           this.notificationService.show(
212             NotificationType.success,
213             $localize`Updated Storage Class '${storageclassName}'`
214           );
215           this.goToListView();
216         },
217         () => {
218           component.storageClassForm.setErrors({ cdSubmitButton: true });
219         }
220       );
221     } else {
222       this.rgwStorageService.createStorageClass(requestModel).subscribe(
223         () => {
224           this.notificationService.show(
225             NotificationType.success,
226             $localize`Created Storage Class '${storageclassName}'`
227           );
228           this.goToListView();
229         },
230         () => {
231           component.storageClassForm.setErrors({ cdSubmitButton: true });
232         }
233       );
234     }
235   }
236
237   goToListView() {
238     this.router.navigate([`rgw/tiering`]);
239   }
240
241   getTierTargetByStorageClass(placementTargetInfo: PlacementTarget, storageClass: string) {
242     const tierTarget = placementTargetInfo.tier_targets.find(
243       (target: TierTarget) => target.val.storage_class === storageClass
244     );
245     return tierTarget;
246   }
247
248   buildRequest() {
249     const rawFormValue = _.cloneDeep(this.storageClassForm.value);
250     const zoneGroup = this.storageClassForm.get('zonegroup').value;
251     const storageClass = this.storageClassForm.get('storage_class').value;
252     const placementId = this.storageClassForm.get('placement_target').value;
253     const requestModel: RequestModel = {
254       zone_group: zoneGroup,
255       placement_targets: [
256         {
257           tags: [],
258           placement_id: placementId,
259           storage_class: storageClass,
260           tier_type: CLOUD_TIER,
261           tier_config: {
262             endpoint: rawFormValue.endpoint,
263             access_key: rawFormValue.access_key,
264             secret: rawFormValue.secret_key,
265             target_path: rawFormValue.target_path,
266             retain_head_object: rawFormValue.retain_head_object,
267             region: rawFormValue.region,
268             multipart_sync_threshold: rawFormValue.multipart_sync_threshold,
269             multipart_min_part_size: rawFormValue.multipart_min_part_size
270           }
271         }
272       ]
273     };
274     return requestModel;
275   }
276 }