]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
03c14c43c752ee047658ae42f03ff7e8e140d15d
[ceph-ci.git] /
1 import { Component, OnInit } from '@angular/core';
2 import { UntypedFormControl, Validators } from '@angular/forms';
3 import { NgbActiveModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
4 import _ from 'lodash';
5 import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
6 import { RgwUserService } from '~/app/shared/api/rgw-user.service';
7 import { RgwZoneService } from '~/app/shared/api/rgw-zone.service';
8 import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service';
9 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
10 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
11 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
12 import { CdValidators } from '~/app/shared/forms/cd-validators';
13 import { NotificationService } from '~/app/shared/services/notification.service';
14 import { RgwRealm, RgwZone, RgwZonegroup, SystemKey } from '../models/rgw-multisite';
15 import { ModalService } from '~/app/shared/services/modal.service';
16
17 @Component({
18   selector: 'cd-rgw-multisite-zone-form',
19   templateUrl: './rgw-multisite-zone-form.component.html',
20   styleUrls: ['./rgw-multisite-zone-form.component.scss']
21 })
22 export class RgwMultisiteZoneFormComponent implements OnInit {
23   readonly endpoints = /^((https?:\/\/)|(www.))(?:([a-zA-Z]+)|(\d+\.\d+.\d+.\d+)):\d{2,4}$/;
24   readonly ipv4Rgx = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i;
25   readonly ipv6Rgx = /^(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}$/i;
26   action: string;
27   info: any;
28   multisiteZoneForm: CdFormGroup;
29   editing = false;
30   resource: string;
31   realm: RgwRealm;
32   zonegroup: RgwZonegroup;
33   zone: RgwZone;
34   defaultsInfo: string[] = [];
35   multisiteInfo: object[] = [];
36   zonegroupList: RgwZonegroup[] = [];
37   zoneList: RgwZone[] = [];
38   zoneNames: string[];
39   users: any;
40   placementTargets: any;
41   zoneInfo: RgwZone;
42   poolList: object[] = [];
43   storageClassList: object[] = [];
44   disableDefault: boolean = false;
45   disableMaster: boolean = false;
46   isMetadataSync: boolean = false;
47   isMasterZone: boolean;
48   isDefaultZone: boolean;
49   syncStatusTimedOut: boolean = false;
50   bsModalRef: NgbModalRef;
51   createSystemUser: boolean = false;
52   master_zone_of_master_zonegroup: RgwZone;
53   masterZoneUser: any;
54   access_key: any;
55   master_zonegroup_of_realm: RgwZonegroup;
56   compressionTypes = ['lz4', 'zlib', 'snappy'];
57   userListReady: boolean = false;
58
59   constructor(
60     public activeModal: NgbActiveModal,
61     public actionLabels: ActionLabelsI18n,
62     public rgwMultisiteService: RgwMultisiteService,
63     public rgwZoneService: RgwZoneService,
64     public rgwZoneGroupService: RgwZonegroupService,
65     public notificationService: NotificationService,
66     public rgwUserService: RgwUserService,
67     public modalService: ModalService
68   ) {
69     this.action = this.editing
70       ? this.actionLabels.EDIT + this.resource
71       : this.actionLabels.CREATE + this.resource;
72     this.createForm();
73   }
74
75   createForm() {
76     this.multisiteZoneForm = new CdFormGroup({
77       zoneName: new UntypedFormControl(null, {
78         validators: [
79           Validators.required,
80           CdValidators.custom('uniqueName', (zoneName: string) => {
81             return (
82               this.action === 'create' && this.zoneNames && this.zoneNames.indexOf(zoneName) !== -1
83             );
84           })
85         ]
86       }),
87       default_zone: new UntypedFormControl(false),
88       master_zone: new UntypedFormControl(false),
89       selectedZonegroup: new UntypedFormControl(null),
90       zone_endpoints: new UntypedFormControl(null, {
91         validators: [
92           CdValidators.custom('endpoint', (value: string) => {
93             if (_.isEmpty(value)) {
94               return false;
95             } else {
96               if (value.includes(',')) {
97                 value.split(',').forEach((url: string) => {
98                   return (
99                     !this.endpoints.test(url) && !this.ipv4Rgx.test(url) && !this.ipv6Rgx.test(url)
100                   );
101                 });
102               } else {
103                 return (
104                   !this.endpoints.test(value) &&
105                   !this.ipv4Rgx.test(value) &&
106                   !this.ipv6Rgx.test(value)
107                 );
108               }
109               return false;
110             }
111           }),
112           Validators.required
113         ]
114       }),
115       access_key: new UntypedFormControl('', {}),
116       secret_key: new UntypedFormControl('', {}),
117       placementTarget: new UntypedFormControl(null),
118       placementDataPool: new UntypedFormControl(''),
119       placementIndexPool: new UntypedFormControl(null),
120       placementDataExtraPool: new UntypedFormControl(null),
121       storageClass: new UntypedFormControl(null),
122       storageDataPool: new UntypedFormControl(null),
123       storageCompression: new UntypedFormControl(null)
124     });
125   }
126
127   onZoneGroupChange(zonegroupName: string) {
128     let zg = new RgwZonegroup();
129     zg.name = zonegroupName;
130     this.rgwZoneGroupService.get(zg).subscribe((zonegroup: RgwZonegroup) => {
131       if (_.isEmpty(zonegroup.master_zone)) {
132         this.multisiteZoneForm.get('master_zone').setValue(true);
133         this.multisiteZoneForm.get('master_zone').disable();
134         this.disableMaster = false;
135       } else if (!_.isEmpty(zonegroup.master_zone) && this.action === 'create') {
136         this.multisiteZoneForm.get('master_zone').setValue(false);
137         this.multisiteZoneForm.get('master_zone').disable();
138         this.disableMaster = true;
139       }
140     });
141     if (
142       this.multisiteZoneForm.getValue('selectedZonegroup') !==
143       this.defaultsInfo['defaultZonegroupName']
144     ) {
145       this.disableDefault = true;
146       this.multisiteZoneForm.get('default_zone').disable();
147     }
148   }
149
150   ngOnInit(): void {
151     this.zonegroupList =
152       this.multisiteInfo[1] !== undefined && this.multisiteInfo[1].hasOwnProperty('zonegroups')
153         ? this.multisiteInfo[1]['zonegroups']
154         : [];
155     this.zoneList =
156       this.multisiteInfo[2] !== undefined && this.multisiteInfo[2].hasOwnProperty('zones')
157         ? this.multisiteInfo[2]['zones']
158         : [];
159     this.zoneNames = this.zoneList.map((zone) => {
160       return zone['name'];
161     });
162     if (this.action === 'create') {
163       if (this.defaultsInfo['defaultZonegroupName'] !== undefined) {
164         this.multisiteZoneForm
165           .get('selectedZonegroup')
166           .setValue(this.defaultsInfo['defaultZonegroupName']);
167         this.onZoneGroupChange(this.defaultsInfo['defaultZonegroupName']);
168       }
169     }
170     if (this.action === 'edit') {
171       this.placementTargets =
172         this.info.data?.parent || this.info.parent
173           ? (this.info.data?.parentNode || this.info.parent.data)?.placement_targets
174           : [];
175       this.rgwZoneService.getPoolNames().subscribe((pools: object[]) => {
176         this.poolList = pools;
177       });
178       this.multisiteZoneForm.get('zoneName').setValue(this.info.data.name);
179       this.multisiteZoneForm.get('selectedZonegroup').setValue(this.info.data.parent);
180       this.multisiteZoneForm.get('default_zone').setValue(this.info.data.is_default);
181       this.multisiteZoneForm.get('master_zone').setValue(this.info.data.is_master);
182       this.multisiteZoneForm.get('zone_endpoints').setValue(this.info.data.endpoints.toString());
183       this.multisiteZoneForm.get('access_key').setValue(this.info.data.access_key);
184       this.multisiteZoneForm.get('secret_key').setValue(this.info.data.secret_key);
185       this.multisiteZoneForm
186         .get('placementTarget')
187         .setValue((this.info.data?.parentNode || this.info.parent.data)?.default_placement);
188       this.getZonePlacementData(this.multisiteZoneForm.getValue('placementTarget'));
189       if (this.info.data.is_default) {
190         this.isDefaultZone = true;
191         this.multisiteZoneForm.get('default_zone').disable();
192       }
193       if (this.info.data.is_master) {
194         this.isMasterZone = true;
195         this.multisiteZoneForm.get('master_zone').disable();
196       }
197       const zone = new RgwZone();
198       zone.name = this.info.data.name;
199       this.onZoneGroupChange(this.info.data.parent);
200     }
201     if (
202       this.multisiteZoneForm.getValue('selectedZonegroup') !==
203       this.defaultsInfo['defaultZonegroupName']
204     ) {
205       this.disableDefault = true;
206       this.multisiteZoneForm.get('default_zone').disable();
207     }
208   }
209
210   getZonePlacementData(placementTarget: string) {
211     this.zone = new RgwZone();
212     this.zone.name = this.info.data.name;
213     this.rgwZoneService.get(this.zone).subscribe((zoneInfo: RgwZone) => {
214       this.zoneInfo = zoneInfo;
215       if (this.zoneInfo && this.zoneInfo['placement_pools']) {
216         const placementPoolKeys = this.zoneInfo['placement_pools'].map((plc_pool) => plc_pool.key);
217         this.placementTargets = this.placementTargets.filter((placement: { name: string }) =>
218           placementPoolKeys.includes(placement.name)
219         );
220         this.zoneInfo['placement_pools'].forEach((plc_pool) => {
221           if (plc_pool.key === placementTarget) {
222             let storageClasses = plc_pool.val.storage_classes;
223             this.storageClassList = Object.entries(storageClasses).map(([key, value]) => ({
224               key,
225               value
226             }));
227             let placementDataPool = storageClasses['STANDARD']
228               ? storageClasses['STANDARD']['data_pool']
229               : '';
230             let placementIndexPool = plc_pool.val.index_pool;
231             let placementDataExtraPool = plc_pool.val.data_extra_pool;
232             this.poolList.push({ poolname: placementDataPool });
233             this.poolList.push({ poolname: placementIndexPool });
234             this.poolList.push({ poolname: placementDataExtraPool });
235             this.multisiteZoneForm.get('storageClass').setValue(this.storageClassList[0]['key']);
236             this.getStorageClassData(this.storageClassList[0]['key']);
237             this.multisiteZoneForm.get('placementDataPool').setValue(placementDataPool);
238             this.multisiteZoneForm.get('placementIndexPool').setValue(placementIndexPool);
239             this.multisiteZoneForm.get('placementDataExtraPool').setValue(placementDataExtraPool);
240           }
241         });
242       }
243     });
244   }
245
246   getStorageClassData(storageClass: string) {
247     let storageClassSelected = this.storageClassList.find((sc) => sc['key'] === storageClass);
248     this.poolList.push({ poolname: storageClassSelected['value']['data_pool'] });
249     this.multisiteZoneForm
250       .get('storageDataPool')
251       .setValue(storageClassSelected['value']['data_pool']);
252     this.multisiteZoneForm
253       .get('storageCompression')
254       .setValue(storageClassSelected['value']['compression_type']);
255   }
256
257   submit() {
258     const values = this.multisiteZoneForm.getRawValue();
259     if (this.action === 'create') {
260       this.zonegroup = new RgwZonegroup();
261       this.zonegroup.name = values['selectedZonegroup'];
262       this.zone = new RgwZone();
263       this.zone.name = values['zoneName'];
264       this.zone.endpoints = values['zone_endpoints'];
265       this.zone.system_key = new SystemKey();
266       this.zone.system_key.access_key = values['access_key'];
267       this.zone.system_key.secret_key = values['secret_key'];
268       this.rgwZoneService
269         .create(
270           this.zone,
271           this.zonegroup,
272           values['default_zone'],
273           values['master_zone'],
274           this.zone.endpoints
275         )
276         .subscribe(
277           () => {
278             this.notificationService.show(
279               NotificationType.success,
280               $localize`Zone: '${values['zoneName']}' created successfully`
281             );
282             this.activeModal.close();
283           },
284           () => {
285             this.multisiteZoneForm.setErrors({ cdSubmitButton: true });
286           }
287         );
288     } else if (this.action === 'edit') {
289       this.zonegroup = new RgwZonegroup();
290       this.zonegroup.name = values['selectedZonegroup'];
291       this.zone = new RgwZone();
292       this.zone.name = this.info.data.name;
293       this.zone.endpoints = values['zone_endpoints'];
294       this.zone.system_key = new SystemKey();
295       this.zone.system_key.access_key = values['access_key'];
296       this.zone.system_key.secret_key = values['secret_key'];
297       this.rgwZoneService
298         .update(
299           this.zone,
300           this.zonegroup,
301           values['zoneName'],
302           values['default_zone'],
303           values['master_zone'],
304           this.zone.endpoints,
305           values['placementTarget'],
306           values['placementDataPool'],
307           values['placementIndexPool'],
308           values['placementDataExtraPool'],
309           values['storageClass'],
310           values['storageDataPool'],
311           values['storageCompression']
312         )
313         .subscribe(
314           () => {
315             this.notificationService.show(
316               NotificationType.success,
317               $localize`Zone: '${values['zoneName']}' updated successfully`
318             );
319             this.activeModal.close();
320           },
321           () => {
322             this.multisiteZoneForm.setErrors({ cdSubmitButton: true });
323           }
324         );
325     }
326   }
327 }