]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
9a08d2fa9cb516e212778a2c12746b254eb887e7
[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     let allZonegroupZonesList = this.zonegroupList.map((zonegroup: RgwZonegroup) => {
141       return zonegroup['zones'];
142     });
143     const allZonegroupZonesInfo = allZonegroupZonesList.reduce(
144       (accumulator, value) => accumulator.concat(value),
145       []
146     );
147     const allZonegroupZonesNames = allZonegroupZonesInfo.map((zone) => {
148       return zone['name'];
149     });
150     this.allZoneNames = this.zoneList.map((zone: RgwZone) => {
151       return zone['name'];
152     });
153     this.allZoneNames = _.difference(this.allZoneNames, allZonegroupZonesNames);
154     if (this.action === 'create' && this.defaultsInfo['defaultRealmName'] !== null) {
155       this.multisiteZonegroupForm
156         .get('selectedRealm')
157         .setValue(this.defaultsInfo['defaultRealmName']);
158       if (this.disableMaster) {
159         this.multisiteZonegroupForm.get('master_zonegroup').disable();
160       }
161     }
162     if (this.action === 'edit') {
163       this.multisiteZonegroupForm.get('zonegroupName').setValue(this.info.data.name);
164       this.multisiteZonegroupForm.get('selectedRealm').setValue(this.info.data.parent);
165       this.multisiteZonegroupForm.get('default_zonegroup').setValue(this.info.data.is_default);
166       this.multisiteZonegroupForm.get('master_zonegroup').setValue(this.info.data.is_master);
167       this.multisiteZonegroupForm.get('zonegroup_endpoints').setValue(this.info.data.endpoints);
168
169       if (this.info.data.is_default) {
170         this.multisiteZonegroupForm.get('default_zonegroup').disable();
171       }
172       if (
173         !this.info.data.is_default &&
174         this.multisiteZonegroupForm.getValue('selectedRealm') !==
175           this.defaultsInfo['defaultRealmName']
176       ) {
177         this.multisiteZonegroupForm.get('default_zonegroup').disable();
178         this.disableDefault = true;
179       }
180       if (this.info.data.is_master || this.disableMaster) {
181         this.multisiteZonegroupForm.get('master_zonegroup').disable();
182       }
183
184       this.zonegroupZoneNames = this.info.data.zones.map((zone: { [x: string]: any }) => {
185         return zone['name'];
186       });
187       this.zgZoneNames = this.info.data.zones.map((zone: { [x: string]: any }) => {
188         return zone['name'];
189       });
190       this.zgZoneIds = this.info.data.zones.map((zone: { [x: string]: any }) => {
191         return zone['id'];
192       });
193       const uniqueZones = new Set(this.allZoneNames);
194       this.labelsOption = Array.from(uniqueZones).map((zone) => {
195         return { enabled: true, name: zone, selected: false, description: null };
196       });
197
198       this.info.data.placement_targets.forEach((target: object) => {
199         const fg = this.addPlacementTarget();
200         let data = {
201           placement_id: target['name'],
202           tags: target['tags'].join(','),
203           storage_class:
204             typeof target['storage_classes'] === 'string'
205               ? target['storage_classes']
206               : target['storage_classes'].join(',')
207         };
208         fg.patchValue(data);
209       });
210     }
211   }
212
213   submit() {
214     const values = this.multisiteZonegroupForm.getRawValue();
215     if (this.action === 'create') {
216       this.realm = new RgwRealm();
217       this.realm.name = values['selectedRealm'];
218       this.zonegroup = new RgwZonegroup();
219       this.zonegroup.name = values['zonegroupName'];
220       this.zonegroup.endpoints = values['zonegroup_endpoints'];
221       this.rgwZonegroupService
222         .create(this.realm, this.zonegroup, values['default_zonegroup'], values['master_zonegroup'])
223         .subscribe(
224           () => {
225             this.notificationService.show(
226               NotificationType.success,
227               $localize`Zonegroup: '${values['zonegroupName']}' created successfully`
228             );
229             this.activeModal.close();
230           },
231           () => {
232             this.multisiteZonegroupForm.setErrors({ cdSubmitButton: true });
233           }
234         );
235     } else if (this.action === 'edit') {
236       this.removedZones = _.difference(this.zgZoneNames, this.zonegroupZoneNames);
237       const masterZoneName = this.info.data.zones.filter(
238         (zone: any) => zone.id === this.info.data.master_zone
239       );
240       this.isRemoveMasterZone = this.removedZones.includes(masterZoneName[0].name);
241       if (this.isRemoveMasterZone) {
242         this.multisiteZonegroupForm.setErrors({ cdSubmitButton: true });
243         return;
244       }
245       this.addedZones = _.difference(this.zonegroupZoneNames, this.zgZoneNames);
246       this.realm = new RgwRealm();
247       this.realm.name = values['selectedRealm'];
248       this.zonegroup = new RgwZonegroup();
249       this.zonegroup.name = this.info.data.name;
250       this.newZonegroupName = values['zonegroupName'];
251       this.zonegroup.endpoints = values['zonegroup_endpoints'].toString();
252       this.zonegroup.placement_targets = values['placementTargets'];
253       this.rgwZonegroupService
254         .update(
255           this.realm,
256           this.zonegroup,
257           this.newZonegroupName,
258           values['default_zonegroup'],
259           values['master_zonegroup'],
260           this.removedZones,
261           this.addedZones
262         )
263         .subscribe(
264           () => {
265             this.notificationService.show(
266               NotificationType.success,
267               $localize`Zonegroup: '${values['zonegroupName']}' updated successfully`
268             );
269             this.activeModal.close();
270           },
271           () => {
272             this.multisiteZonegroupForm.setErrors({ cdSubmitButton: true });
273           }
274         );
275     }
276   }
277
278   addPlacementTarget() {
279     this.placementTargets = this.multisiteZonegroupForm.get('placementTargets') as FormArray;
280     const fg = new CdFormGroup({
281       placement_id: new FormControl('', {
282         validators: [Validators.required]
283       }),
284       tags: new FormControl(''),
285       storage_class: new FormControl([])
286     });
287     this.placementTargets.push(fg);
288     return fg;
289   }
290
291   trackByFn(index: number) {
292     return index;
293   }
294
295   removePlacementTarget(index: number) {
296     this.placementTargets = this.multisiteZonegroupForm.get('placementTargets') as FormArray;
297     this.placementTargets.removeAt(index);
298   }
299
300   showError(index: number, control: string, formDir: NgForm, x: string) {
301     return (<any>this.multisiteZonegroupForm.controls.placementTargets).controls[index].showError(
302       control,
303       formDir,
304       x
305     );
306   }
307 }