]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
2172a301e2cad09a0146b2662a4f49648d419384
[ceph-ci.git] /
1 import { Component, OnInit } from '@angular/core';
2 import { FormArray, FormBuilder, FormControl, NgForm, Validators } from '@angular/forms';
3 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
4 import _ from 'lodash';
5 import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service';
6 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
7 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
8 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
9 import { CdValidators } from '~/app/shared/forms/cd-validators';
10 import { NotificationService } from '~/app/shared/services/notification.service';
11 import { RgwRealm, RgwZone, RgwZonegroup } from '../models/rgw-multisite';
12 import { Icons } from '~/app/shared/enum/icons.enum';
13 import { SelectOption } from '~/app/shared/components/select/select-option.model';
14
15 @Component({
16   selector: 'cd-rgw-multisite-zonegroup-form',
17   templateUrl: './rgw-multisite-zonegroup-form.component.html',
18   styleUrls: ['./rgw-multisite-zonegroup-form.component.scss']
19 })
20 export class RgwMultisiteZonegroupFormComponent implements OnInit {
21   readonly endpoints = /^((https?:\/\/)|(www.))(?:([a-zA-Z]+)|(\d+\.\d+.\d+.\d+)):\d{2,4}$/;
22   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;
23   readonly ipv6Rgx = /^(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}$/i;
24   action: string;
25   icons = Icons;
26   multisiteZonegroupForm: CdFormGroup;
27   editing = false;
28   resource: string;
29   realm: RgwRealm;
30   zonegroup: RgwZonegroup;
31   info: any;
32   defaultsInfo: string[] = [];
33   multisiteInfo: object[] = [];
34   realmList: RgwRealm[] = [];
35   zonegroupList: RgwZonegroup[] = [];
36   zonegroupNames: string[];
37   isMaster = false;
38   placementTargets: FormArray;
39   newZonegroupName: string;
40   zonegroupZoneNames: string[];
41   labelsOption: Array<SelectOption> = [];
42   zoneList: RgwZone[] = [];
43   allZoneNames: string[];
44   zgZoneNames: string[];
45   zgZoneIds: string[];
46   removedZones: string[];
47   isRemoveMasterZone = false;
48   addedZones: string[];
49   disableDefault = false;
50   disableMaster = false;
51
52   constructor(
53     public activeModal: NgbActiveModal,
54     public actionLabels: ActionLabelsI18n,
55     public rgwZonegroupService: RgwZonegroupService,
56     public notificationService: NotificationService,
57     private formBuilder: FormBuilder
58   ) {
59     this.action = this.editing
60       ? this.actionLabels.EDIT + this.resource
61       : this.actionLabels.CREATE + this.resource;
62     this.createForm();
63   }
64
65   createForm() {
66     this.multisiteZonegroupForm = new CdFormGroup({
67       default_zonegroup: new FormControl(false),
68       zonegroupName: new FormControl(null, {
69         validators: [
70           Validators.required,
71           CdValidators.custom('uniqueName', (zonegroupName: string) => {
72             return (
73               this.action === 'create' &&
74               this.zonegroupNames &&
75               this.zonegroupNames.indexOf(zonegroupName) !== -1
76             );
77           })
78         ]
79       }),
80       master_zonegroup: new FormControl(false),
81       selectedRealm: new FormControl(null),
82       zonegroup_endpoints: new FormControl(null, [
83         CdValidators.custom('endpoint', (value: string) => {
84           if (_.isEmpty(value)) {
85             return false;
86           } else {
87             if (value.includes(',')) {
88               value.split(',').forEach((url: string) => {
89                 return (
90                   !this.endpoints.test(url) && !this.ipv4Rgx.test(url) && !this.ipv6Rgx.test(url)
91                 );
92               });
93             } else {
94               return (
95                 !this.endpoints.test(value) &&
96                 !this.ipv4Rgx.test(value) &&
97                 !this.ipv6Rgx.test(value)
98               );
99             }
100             return false;
101           }
102         }),
103         Validators.required
104       ]),
105       placementTargets: this.formBuilder.array([])
106     });
107   }
108
109   ngOnInit(): void {
110     _.forEach(this.multisiteZonegroupForm.get('placementTargets'), (placementTarget) => {
111       const fg = this.addPlacementTarget();
112       fg.patchValue(placementTarget);
113     });
114     this.placementTargets = this.multisiteZonegroupForm.get('placementTargets') as FormArray;
115     this.realmList =
116       this.multisiteInfo[0] !== undefined && this.multisiteInfo[0].hasOwnProperty('realms')
117         ? this.multisiteInfo[0]['realms']
118         : [];
119     this.zonegroupList =
120       this.multisiteInfo[1] !== undefined && this.multisiteInfo[1].hasOwnProperty('zonegroups')
121         ? this.multisiteInfo[1]['zonegroups']
122         : [];
123     this.zonegroupList.forEach((zgp: any) => {
124       if (zgp.is_master === true && !_.isEmpty(zgp.realm_id)) {
125         this.isMaster = true;
126         this.disableMaster = true;
127       }
128     });
129     if (!this.isMaster) {
130       this.multisiteZonegroupForm.get('master_zonegroup').setValue(true);
131       this.multisiteZonegroupForm.get('master_zonegroup').disable();
132     }
133     this.zoneList =
134       this.multisiteInfo[2] !== undefined && this.multisiteInfo[2].hasOwnProperty('zones')
135         ? this.multisiteInfo[2]['zones']
136         : [];
137     this.zonegroupNames = this.zonegroupList.map((zonegroup) => {
138       return zonegroup['name'];
139     });
140     this.allZoneNames = this.zoneList.map((zone: RgwZone) => {
141       return zone['name'];
142     });
143     if (this.action === 'create' && this.defaultsInfo['defaultRealmName'] !== null) {
144       this.multisiteZonegroupForm
145         .get('selectedRealm')
146         .setValue(this.defaultsInfo['defaultRealmName']);
147       if (this.disableMaster) {
148         this.multisiteZonegroupForm.get('master_zonegroup').disable();
149       }
150     }
151     if (this.action === 'edit') {
152       this.multisiteZonegroupForm.get('zonegroupName').setValue(this.info.data.name);
153       this.multisiteZonegroupForm.get('selectedRealm').setValue(this.info.data.parent);
154       this.multisiteZonegroupForm.get('default_zonegroup').setValue(this.info.data.is_default);
155       this.multisiteZonegroupForm.get('master_zonegroup').setValue(this.info.data.is_master);
156       this.multisiteZonegroupForm.get('zonegroup_endpoints').setValue(this.info.data.endpoints);
157
158       if (this.info.data.is_default) {
159         this.multisiteZonegroupForm.get('default_zonegroup').disable();
160       }
161       if (
162         !this.info.data.is_default &&
163         this.multisiteZonegroupForm.getValue('selectedRealm') !==
164           this.defaultsInfo['defaultRealmName']
165       ) {
166         this.multisiteZonegroupForm.get('default_zonegroup').disable();
167         this.disableDefault = true;
168       }
169       if (this.info.data.is_master || this.disableMaster) {
170         this.multisiteZonegroupForm.get('master_zonegroup').disable();
171       }
172
173       this.zonegroupZoneNames = this.info.data.zones.map((zone: { [x: string]: any }) => {
174         return zone['name'];
175       });
176       this.zgZoneNames = this.info.data.zones.map((zone: { [x: string]: any }) => {
177         return zone['name'];
178       });
179       this.zgZoneIds = this.info.data.zones.map((zone: { [x: string]: any }) => {
180         return zone['id'];
181       });
182       const uniqueZones = new Set(this.allZoneNames);
183       this.labelsOption = Array.from(uniqueZones).map((zone) => {
184         return { enabled: true, name: zone, selected: false, description: null };
185       });
186
187       this.info.data.placement_targets.forEach((target: object) => {
188         const fg = this.addPlacementTarget();
189         let data = {
190           placement_id: target['name'],
191           tags: target['tags'].join(','),
192           storage_class:
193             typeof target['storage_classes'] === 'string'
194               ? target['storage_classes']
195               : target['storage_classes'].join(',')
196         };
197         fg.patchValue(data);
198       });
199     }
200   }
201
202   submit() {
203     const values = this.multisiteZonegroupForm.getRawValue();
204     if (this.action === 'create') {
205       this.realm = new RgwRealm();
206       this.realm.name = values['selectedRealm'];
207       this.zonegroup = new RgwZonegroup();
208       this.zonegroup.name = values['zonegroupName'];
209       this.zonegroup.endpoints = this.checkUrlArray(values['zonegroup_endpoints']);
210       this.rgwZonegroupService
211         .create(this.realm, this.zonegroup, values['default_zonegroup'], values['master_zonegroup'])
212         .subscribe(
213           () => {
214             this.notificationService.show(
215               NotificationType.success,
216               $localize`Zonegroup: '${values['zonegroupName']}' created successfully`
217             );
218             this.activeModal.close();
219           },
220           () => {
221             this.multisiteZonegroupForm.setErrors({ cdSubmitButton: true });
222           }
223         );
224     } else if (this.action === 'edit') {
225       this.removedZones = _.difference(this.zgZoneNames, this.zonegroupZoneNames);
226       const masterZoneName = this.info.data.zones.filter(
227         (zone: any) => zone.id === this.info.data.master_zone
228       );
229       this.isRemoveMasterZone = this.removedZones.includes(masterZoneName[0].name);
230       if (this.isRemoveMasterZone) {
231         this.multisiteZonegroupForm.setErrors({ cdSubmitButton: true });
232         return;
233       }
234       this.addedZones = _.difference(this.zonegroupZoneNames, this.zgZoneNames);
235       this.realm = new RgwRealm();
236       this.realm.name = values['selectedRealm'];
237       this.zonegroup = new RgwZonegroup();
238       this.zonegroup.name = this.info.data.name;
239       this.newZonegroupName = values['zonegroupName'];
240       this.zonegroup.endpoints =
241         values['zonegroup_endpoints'] === this.info.data.endpoints
242           ? values['zonegroup_endpoints']
243           : this.checkUrlArray(values['zonegroup_endpoints']);
244       this.zonegroup.placement_targets = values['placementTargets'];
245       this.rgwZonegroupService
246         .update(
247           this.realm,
248           this.zonegroup,
249           this.newZonegroupName,
250           values['default_zonegroup'],
251           values['master_zonegroup'],
252           this.removedZones,
253           this.addedZones
254         )
255         .subscribe(
256           () => {
257             this.notificationService.show(
258               NotificationType.success,
259               $localize`Zonegroup: '${values['zonegroupName']}' updated successfully`
260             );
261             this.activeModal.close();
262           },
263           () => {
264             this.multisiteZonegroupForm.setErrors({ cdSubmitButton: true });
265           }
266         );
267     }
268   }
269
270   checkUrlArray(endpoints: string) {
271     let endpointsArray = [];
272     if (endpoints.includes(',')) {
273       endpointsArray = endpoints.split(',');
274     } else {
275       endpointsArray.push(endpoints);
276     }
277     return endpointsArray;
278   }
279
280   addPlacementTarget() {
281     this.placementTargets = this.multisiteZonegroupForm.get('placementTargets') as FormArray;
282     const fg = new CdFormGroup({
283       placement_id: new FormControl('', {
284         validators: [Validators.required]
285       }),
286       tags: new FormControl(''),
287       storage_class: new FormControl([])
288     });
289     this.placementTargets.push(fg);
290     return fg;
291   }
292
293   trackByFn(index: number) {
294     return index;
295   }
296
297   removePlacementTarget(index: number) {
298     this.placementTargets = this.multisiteZonegroupForm.get('placementTargets') as FormArray;
299     this.placementTargets.removeAt(index);
300   }
301
302   showError(index: number, control: string, formDir: NgForm, x: string) {
303     return (<any>this.multisiteZonegroupForm.controls.placementTargets).controls[index].showError(
304       control,
305       formDir,
306       x
307     );
308   }
309 }