]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
a0edcd95b49aa439cb79269aa113e9880c9f2750
[ceph-ci.git] /
1 import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
2 import {
3   TreeComponent,
4   ITreeOptions,
5   TreeModel,
6   TreeNode,
7   TREE_ACTIONS
8 } from '@circlon/angular-tree-component';
9 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
10 import _ from 'lodash';
11 import { forkJoin, Subscription } from 'rxjs';
12 import { RgwRealmService } from '~/app/shared/api/rgw-realm.service';
13 import { RgwZoneService } from '~/app/shared/api/rgw-zone.service';
14 import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service';
15 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
16 import { ActionLabelsI18n, TimerServiceInterval } from '~/app/shared/constants/app.constants';
17 import { Icons } from '~/app/shared/enum/icons.enum';
18 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
19 import { CdTableAction } from '~/app/shared/models/cd-table-action';
20 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
21 import { Permission } from '~/app/shared/models/permissions';
22 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
23 import { ModalService } from '~/app/shared/services/modal.service';
24 import { NotificationService } from '~/app/shared/services/notification.service';
25 import { TimerService } from '~/app/shared/services/timer.service';
26 import { RgwRealm, RgwZone, RgwZonegroup } from '../models/rgw-multisite';
27 import { RgwMultisiteZoneDeletionFormComponent } from '../models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component';
28 import { RgwMultisiteZonegroupDeletionFormComponent } from '../models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component';
29 import { RgwMultisiteRealmFormComponent } from '../rgw-multisite-realm-form/rgw-multisite-realm-form.component';
30 import { RgwMultisiteZoneFormComponent } from '../rgw-multisite-zone-form/rgw-multisite-zone-form.component';
31 import { RgwMultisiteZonegroupFormComponent } from '../rgw-multisite-zonegroup-form/rgw-multisite-zonegroup-form.component';
32
33 @Component({
34   selector: 'cd-rgw-multisite-details',
35   templateUrl: './rgw-multisite-details.component.html',
36   styleUrls: ['./rgw-multisite-details.component.scss']
37 })
38 export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit {
39   private sub = new Subscription();
40
41   @ViewChild('tree') tree: TreeComponent;
42
43   messages = {
44     noDefaultRealm: $localize`Please create a default realm first to enable this feature`,
45     noMasterZone: $localize`Please create a master zone for each zonegroups to enable this feature`
46   };
47
48   icons = Icons;
49   permission: Permission;
50   selection = new CdTableSelection();
51   createTableActions: CdTableAction[];
52   loadingIndicator = true;
53   nodes: object[] = [];
54   treeOptions: ITreeOptions = {
55     useVirtualScroll: true,
56     nodeHeight: 22,
57     levelPadding: 20,
58     actionMapping: {
59       mouse: {
60         click: this.onNodeSelected.bind(this)
61       }
62     }
63   };
64   modalRef: NgbModalRef;
65
66   realms: RgwRealm[] = [];
67   zonegroups: RgwZonegroup[] = [];
68   zones: RgwZone[] = [];
69   metadata: any;
70   metadataTitle: string;
71   bsModalRef: NgbModalRef;
72   realmIds: string[] = [];
73   zoneIds: string[] = [];
74   defaultRealmId = '';
75   defaultZonegroupId = '';
76   defaultZoneId = '';
77   multisiteInfo: object[] = [];
78   defaultsInfo: string[] = [];
79   title: string = 'Edit';
80
81   constructor(
82     private modalService: ModalService,
83     private timerService: TimerService,
84     private authStorageService: AuthStorageService,
85     public actionLabels: ActionLabelsI18n,
86     public timerServiceVariable: TimerServiceInterval,
87     public rgwRealmService: RgwRealmService,
88     public rgwZonegroupService: RgwZonegroupService,
89     public rgwZoneService: RgwZoneService,
90     private notificationService: NotificationService
91   ) {
92     this.permission = this.authStorageService.getPermissions().rgw;
93     const createRealmAction: CdTableAction = {
94       permission: 'create',
95       icon: Icons.add,
96       name: this.actionLabels.CREATE + ' Realm',
97       click: () => this.openModal('realm')
98     };
99     const createZonegroupAction: CdTableAction = {
100       permission: 'create',
101       icon: Icons.add,
102       name: this.actionLabels.CREATE + ' Zonegroup',
103       click: () => this.openModal('zonegroup'),
104       disable: () => this.getDisable()
105     };
106     const createZoneAction: CdTableAction = {
107       permission: 'create',
108       icon: Icons.add,
109       name: this.actionLabels.CREATE + ' Zone',
110       click: () => this.openModal('zone')
111     };
112     this.createTableActions = [createRealmAction, createZonegroupAction, createZoneAction];
113   }
114
115   openModal(entity: any, edit = false) {
116     const entityName = edit ? entity.data.type : entity;
117     const action = edit ? 'edit' : 'create';
118     const initialState = {
119       resource: entityName,
120       action: action,
121       info: entity,
122       defaultsInfo: this.defaultsInfo,
123       multisiteInfo: this.multisiteInfo
124     };
125     if (entityName === 'realm') {
126       this.bsModalRef = this.modalService.show(RgwMultisiteRealmFormComponent, initialState, {
127         size: 'lg'
128       });
129     } else if (entityName === 'zonegroup') {
130       this.bsModalRef = this.modalService.show(RgwMultisiteZonegroupFormComponent, initialState, {
131         size: 'lg'
132       });
133     } else {
134       this.bsModalRef = this.modalService.show(RgwMultisiteZoneFormComponent, initialState, {
135         size: 'lg'
136       });
137     }
138   }
139
140   ngOnInit() {
141     const observables = [
142       this.rgwRealmService.getAllRealmsInfo(),
143       this.rgwZonegroupService.getAllZonegroupsInfo(),
144       this.rgwZoneService.getAllZonesInfo()
145     ];
146     this.sub = this.timerService
147       .get(() => forkJoin(observables), this.timerServiceVariable.TIMER_SERVICE_PERIOD * 2)
148       .subscribe(
149         (multisiteInfo: [object, object, object]) => {
150           this.multisiteInfo = multisiteInfo;
151           this.loadingIndicator = false;
152           this.nodes = this.abstractTreeData(multisiteInfo);
153         },
154         (_error) => {}
155       );
156   }
157
158   ngOnDestroy() {
159     this.sub.unsubscribe();
160   }
161
162   private abstractTreeData(multisiteInfo: [object, object, object]): any[] {
163     let allNodes: object[] = [];
164     let rootNodes = {};
165     let firstChildNodes = {};
166     let allFirstChildNodes = [];
167     let secondChildNodes = {};
168     let allSecondChildNodes: {}[] = [];
169     this.realms = multisiteInfo[0]['realms'];
170     this.zonegroups = multisiteInfo[1]['zonegroups'];
171     this.zones = multisiteInfo[2]['zones'];
172     this.defaultRealmId = multisiteInfo[0]['default_realm'];
173     this.defaultZonegroupId = multisiteInfo[1]['default_zonegroup'];
174     this.defaultZoneId = multisiteInfo[2]['default_zone'];
175     this.defaultsInfo = this.getDefaultsEntities(
176       this.defaultRealmId,
177       this.defaultZonegroupId,
178       this.defaultZoneId
179     );
180     if (this.realms.length > 0) {
181       // get tree for realm -> zonegroup -> zone
182       for (const realm of this.realms) {
183         const result = this.rgwRealmService.getRealmTree(realm, this.defaultRealmId);
184         rootNodes = result['nodes'];
185         this.realmIds = this.realmIds.concat(result['realmIds']);
186         for (const zonegroup of this.zonegroups) {
187           if (zonegroup.realm_id === realm.id) {
188             firstChildNodes = this.rgwZonegroupService.getZonegroupTree(
189               zonegroup,
190               this.defaultZonegroupId,
191               realm
192             );
193             for (const zone of zonegroup.zones) {
194               const zoneResult = this.rgwZoneService.getZoneTree(
195                 zone,
196                 this.defaultZoneId,
197                 zonegroup,
198                 realm
199               );
200               secondChildNodes = zoneResult['nodes'];
201               this.zoneIds = this.zoneIds.concat(zoneResult['zoneIds']);
202               allSecondChildNodes.push(secondChildNodes);
203               secondChildNodes = {};
204             }
205             firstChildNodes['children'] = allSecondChildNodes;
206             allSecondChildNodes = [];
207             allFirstChildNodes.push(firstChildNodes);
208             firstChildNodes = {};
209           }
210         }
211         rootNodes['children'] = allFirstChildNodes;
212         allNodes.push(rootNodes);
213         firstChildNodes = {};
214         secondChildNodes = {};
215         rootNodes = {};
216         allFirstChildNodes = [];
217         allSecondChildNodes = [];
218       }
219     }
220     if (this.zonegroups.length > 0) {
221       // get tree for zonegroup -> zone (standalone zonegroups that don't match a realm eg(initial default))
222       for (const zonegroup of this.zonegroups) {
223         if (!this.realmIds.includes(zonegroup.realm_id)) {
224           rootNodes = this.rgwZonegroupService.getZonegroupTree(zonegroup, this.defaultZonegroupId);
225           for (const zone of zonegroup.zones) {
226             const zoneResult = this.rgwZoneService.getZoneTree(zone, this.defaultZoneId, zonegroup);
227             firstChildNodes = zoneResult['nodes'];
228             this.zoneIds = this.zoneIds.concat(zoneResult['zoneIds']);
229             allFirstChildNodes.push(firstChildNodes);
230             firstChildNodes = {};
231           }
232           rootNodes['children'] = allFirstChildNodes;
233           allNodes.push(rootNodes);
234           firstChildNodes = {};
235           rootNodes = {};
236           allFirstChildNodes = [];
237         }
238       }
239     }
240     if (this.zones.length > 0) {
241       // get tree for standalone zones(zones that do not belong to a zonegroup)
242       for (const zone of this.zones) {
243         if (this.zoneIds.length > 0 && !this.zoneIds.includes(zone.id)) {
244           const zoneResult = this.rgwZoneService.getZoneTree(zone, this.defaultZoneId);
245           rootNodes = zoneResult['nodes'];
246           allNodes.push(rootNodes);
247           rootNodes = {};
248         }
249       }
250     }
251     if (this.realms.length < 1 && this.zonegroups.length < 1 && this.zones.length < 1) {
252       return [
253         {
254           name: 'No nodes!'
255         }
256       ];
257     }
258     this.realmIds = [];
259     this.zoneIds = [];
260     return allNodes;
261   }
262
263   getDefaultsEntities(
264     defaultRealmId: string,
265     defaultZonegroupId: string,
266     defaultZoneId: string
267   ): any {
268     const defaultRealm = this.realms.find((x: { id: string }) => x.id === defaultRealmId);
269     const defaultZonegroup = this.zonegroups.find(
270       (x: { id: string }) => x.id === defaultZonegroupId
271     );
272     const defaultZone = this.zones.find((x: { id: string }) => x.id === defaultZoneId);
273     const defaultRealmName = defaultRealm !== undefined ? defaultRealm.name : null;
274     const defaultZonegroupName = defaultZonegroup !== undefined ? defaultZonegroup.name : null;
275     const defaultZoneName = defaultZone !== undefined ? defaultZone.name : null;
276     return {
277       defaultRealmName: defaultRealmName,
278       defaultZonegroupName: defaultZonegroupName,
279       defaultZoneName: defaultZoneName
280     };
281   }
282
283   onNodeSelected(tree: TreeModel, node: TreeNode) {
284     TREE_ACTIONS.ACTIVATE(tree, node, true);
285     this.metadataTitle = node.data.name;
286     this.metadata = node.data.info;
287     node.data.show = true;
288   }
289
290   onUpdateData() {
291     this.tree.treeModel.expandAll();
292   }
293
294   getDisable() {
295     let isMasterZone = true;
296     if (this.defaultRealmId === '') {
297       return this.messages.noDefaultRealm;
298     } else {
299       this.zonegroups.forEach((zgp: any) => {
300         if (_.isEmpty(zgp.master_zone)) {
301           isMasterZone = false;
302         }
303       });
304       if (!isMasterZone) {
305         this.title =
306           'Please create a master zone for each existing zonegroup to enable this feature';
307         return this.messages.noMasterZone;
308       } else {
309         this.title = 'Edit';
310         return false;
311       }
312     }
313   }
314
315   delete(node: TreeNode) {
316     if (node.data.type === 'realm') {
317       this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
318         itemDescription: $localize`${node.data.type} ${node.data.name}`,
319         itemNames: [`${node.data.name}`],
320         submitAction: () => {
321           this.rgwRealmService.delete(node.data.name).subscribe(
322             () => {
323               this.modalRef.close();
324               this.notificationService.show(
325                 NotificationType.success,
326                 $localize`Realm: '${node.data.name}' deleted successfully`
327               );
328             },
329             () => {
330               this.modalRef.componentInstance.stopLoadingSpinner();
331             }
332           );
333         }
334       });
335     } else if (node.data.type === 'zonegroup') {
336       this.modalRef = this.modalService.show(RgwMultisiteZonegroupDeletionFormComponent, {
337         zonegroup: node.data
338       });
339     } else if (node.data.type === 'zone') {
340       this.modalRef = this.modalService.show(RgwMultisiteZoneDeletionFormComponent, {
341         zone: node.data
342       });
343     }
344   }
345 }