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