]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
0a8e598f6e73b1311e1ba066e079120df287e1f6
[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
80   constructor(
81     private modalService: ModalService,
82     private timerService: TimerService,
83     private authStorageService: AuthStorageService,
84     public actionLabels: ActionLabelsI18n,
85     public timerServiceVariable: TimerServiceInterval,
86     public rgwRealmService: RgwRealmService,
87     public rgwZonegroupService: RgwZonegroupService,
88     public rgwZoneService: RgwZoneService,
89     private notificationService: NotificationService
90   ) {
91     this.permission = this.authStorageService.getPermissions().rgw;
92     const createRealmAction: CdTableAction = {
93       permission: 'create',
94       icon: Icons.add,
95       name: this.actionLabels.CREATE + ' Realm',
96       click: () => this.openModal('realm')
97     };
98     const createZonegroupAction: CdTableAction = {
99       permission: 'create',
100       icon: Icons.add,
101       name: this.actionLabels.CREATE + ' Zonegroup',
102       click: () => this.openModal('zonegroup'),
103       disable: () => this.getDisable()
104     };
105     const createZoneAction: CdTableAction = {
106       permission: 'create',
107       icon: Icons.add,
108       name: this.actionLabels.CREATE + ' Zone',
109       click: () => this.openModal('zone')
110     };
111     this.createTableActions = [createRealmAction, createZonegroupAction, createZoneAction];
112   }
113
114   openModal(entity: any, edit = false) {
115     const entityName = edit ? entity.data.type : entity;
116     const action = edit ? 'edit' : 'create';
117     const initialState = {
118       resource: entityName,
119       action: action,
120       info: entity,
121       defaultsInfo: this.defaultsInfo,
122       multisiteInfo: this.multisiteInfo
123     };
124     if (entityName === 'realm') {
125       this.bsModalRef = this.modalService.show(RgwMultisiteRealmFormComponent, initialState, {
126         size: 'lg'
127       });
128     } else if (entityName === 'zonegroup') {
129       this.bsModalRef = this.modalService.show(RgwMultisiteZonegroupFormComponent, initialState, {
130         size: 'lg'
131       });
132     } else {
133       this.bsModalRef = this.modalService.show(RgwMultisiteZoneFormComponent, initialState, {
134         size: 'lg'
135       });
136     }
137   }
138
139   ngOnInit() {
140     const observables = [
141       this.rgwRealmService.getAllRealmsInfo(),
142       this.rgwZonegroupService.getAllZonegroupsInfo(),
143       this.rgwZoneService.getAllZonesInfo()
144     ];
145     this.sub = this.timerService
146       .get(() => forkJoin(observables), this.timerServiceVariable.TIMER_SERVICE_PERIOD * 2)
147       .subscribe(
148         (multisiteInfo: [object, object, object]) => {
149           this.multisiteInfo = multisiteInfo;
150           this.loadingIndicator = false;
151           this.nodes = this.abstractTreeData(multisiteInfo);
152         },
153         (_error) => {}
154       );
155   }
156
157   ngOnDestroy() {
158     this.sub.unsubscribe();
159   }
160
161   private abstractTreeData(multisiteInfo: [object, object, object]): any[] {
162     let allNodes: object[] = [];
163     let rootNodes = {};
164     let firstChildNodes = {};
165     let allFirstChildNodes = [];
166     let secondChildNodes = {};
167     let allSecondChildNodes: {}[] = [];
168     this.realms = multisiteInfo[0]['realms'];
169     this.zonegroups = multisiteInfo[1]['zonegroups'];
170     this.zones = multisiteInfo[2]['zones'];
171     this.defaultRealmId = multisiteInfo[0]['default_realm'];
172     this.defaultZonegroupId = multisiteInfo[1]['default_zonegroup'];
173     this.defaultZoneId = multisiteInfo[2]['default_zone'];
174     this.defaultsInfo = this.getDefaultsEntities(
175       this.defaultRealmId,
176       this.defaultZonegroupId,
177       this.defaultZoneId
178     );
179     if (this.realms.length > 0) {
180       // get tree for realm -> zonegroup -> zone
181       for (const realm of this.realms) {
182         const result = this.rgwRealmService.getRealmTree(realm, this.defaultRealmId);
183         rootNodes = result['nodes'];
184         this.realmIds = this.realmIds.concat(result['realmIds']);
185         for (const zonegroup of this.zonegroups) {
186           if (zonegroup.realm_id === realm.id) {
187             firstChildNodes = this.rgwZonegroupService.getZonegroupTree(
188               zonegroup,
189               this.defaultZonegroupId,
190               realm
191             );
192             for (const zone of zonegroup.zones) {
193               const zoneResult = this.rgwZoneService.getZoneTree(
194                 zone,
195                 this.defaultZoneId,
196                 zonegroup,
197                 realm
198               );
199               secondChildNodes = zoneResult['nodes'];
200               this.zoneIds = this.zoneIds.concat(zoneResult['zoneIds']);
201               allSecondChildNodes.push(secondChildNodes);
202               secondChildNodes = {};
203             }
204             firstChildNodes['children'] = allSecondChildNodes;
205             allSecondChildNodes = [];
206             allFirstChildNodes.push(firstChildNodes);
207             firstChildNodes = {};
208           }
209         }
210         rootNodes['children'] = allFirstChildNodes;
211         allNodes.push(rootNodes);
212         firstChildNodes = {};
213         secondChildNodes = {};
214         rootNodes = {};
215         allFirstChildNodes = [];
216         allSecondChildNodes = [];
217       }
218     }
219     if (this.zonegroups.length > 0) {
220       // get tree for zonegroup -> zone (standalone zonegroups that don't match a realm eg(initial default))
221       for (const zonegroup of this.zonegroups) {
222         if (!this.realmIds.includes(zonegroup.realm_id)) {
223           rootNodes = this.rgwZonegroupService.getZonegroupTree(zonegroup, this.defaultZonegroupId);
224           for (const zone of zonegroup.zones) {
225             const zoneResult = this.rgwZoneService.getZoneTree(zone, this.defaultZoneId, zonegroup);
226             firstChildNodes = zoneResult['nodes'];
227             this.zoneIds = this.zoneIds.concat(zoneResult['zoneIds']);
228             allFirstChildNodes.push(firstChildNodes);
229             firstChildNodes = {};
230           }
231           rootNodes['children'] = allFirstChildNodes;
232           allNodes.push(rootNodes);
233           firstChildNodes = {};
234           rootNodes = {};
235           allFirstChildNodes = [];
236         }
237       }
238     }
239     if (this.zones.length > 0) {
240       // get tree for standalone zones(zones that do not belong to a zonegroup)
241       for (const zone of this.zones) {
242         if (this.zoneIds.length > 0 && !this.zoneIds.includes(zone.id)) {
243           const zoneResult = this.rgwZoneService.getZoneTree(zone, this.defaultZoneId);
244           rootNodes = zoneResult['nodes'];
245           allNodes.push(rootNodes);
246           rootNodes = {};
247         }
248       }
249     }
250     if (this.realms.length < 1 && this.zonegroups.length < 1 && this.zones.length < 1) {
251       return [
252         {
253           name: 'No nodes!'
254         }
255       ];
256     }
257     this.realmIds = [];
258     this.zoneIds = [];
259     return allNodes;
260   }
261
262   getDefaultsEntities(
263     defaultRealmId: string,
264     defaultZonegroupId: string,
265     defaultZoneId: string
266   ): any {
267     const defaultRealm = this.realms.find((x: { id: string }) => x.id === defaultRealmId);
268     const defaultZonegroup = this.zonegroups.find(
269       (x: { id: string }) => x.id === defaultZonegroupId
270     );
271     const defaultZone = this.zones.find((x: { id: string }) => x.id === defaultZoneId);
272     const defaultRealmName = defaultRealm !== undefined ? defaultRealm.name : null;
273     const defaultZonegroupName = defaultZonegroup !== undefined ? defaultZonegroup.name : null;
274     const defaultZoneName = defaultZone !== undefined ? defaultZone.name : null;
275     return {
276       defaultRealmName: defaultRealmName,
277       defaultZonegroupName: defaultZonegroupName,
278       defaultZoneName: defaultZoneName
279     };
280   }
281
282   onNodeSelected(tree: TreeModel, node: TreeNode) {
283     TREE_ACTIONS.ACTIVATE(tree, node, true);
284     this.metadataTitle = node.data.name;
285     this.metadata = node.data.info;
286     node.data.show = true;
287   }
288
289   onUpdateData() {
290     this.tree.treeModel.expandAll();
291   }
292
293   getDisable() {
294     if (this.defaultRealmId === '') {
295       return this.messages.noDefaultRealm;
296     } else {
297       let isMasterZone = true;
298       this.zonegroups.forEach((zgp: any) => {
299         if (_.isEmpty(zgp.master_zone)) {
300           isMasterZone = false;
301         }
302       });
303       if (!isMasterZone) {
304         return this.messages.noMasterZone;
305       } else {
306         return false;
307       }
308     }
309   }
310
311   delete(node: TreeNode) {
312     if (node.data.type === 'realm') {
313       this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
314         itemDescription: $localize`${node.data.type} ${node.data.name}`,
315         itemNames: [`${node.data.name}`],
316         submitAction: () => {
317           this.rgwRealmService.delete(node.data.name).subscribe(
318             () => {
319               this.modalRef.close();
320               this.notificationService.show(
321                 NotificationType.success,
322                 $localize`Realm: '${node.data.name}' deleted successfully`
323               );
324             },
325             () => {
326               this.modalRef.componentInstance.stopLoadingSpinner();
327             }
328           );
329         }
330       });
331     } else if (node.data.type === 'zonegroup') {
332       this.modalRef = this.modalService.show(RgwMultisiteZonegroupDeletionFormComponent, {
333         zonegroup: node.data
334       });
335     } else if (node.data.type === 'zone') {
336       this.modalRef = this.modalService.show(RgwMultisiteZoneDeletionFormComponent, {
337         zone: node.data
338       });
339     }
340   }
341 }