1 import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
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 { RgwMultisiteMigrateComponent } from '../rgw-multisite-migrate/rgw-multisite-migrate.component';
28 import { RgwMultisiteZoneDeletionFormComponent } from '../models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component';
29 import { RgwMultisiteZonegroupDeletionFormComponent } from '../models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component';
30 import { RgwMultisiteRealmFormComponent } from '../rgw-multisite-realm-form/rgw-multisite-realm-form.component';
31 import { RgwMultisiteZoneFormComponent } from '../rgw-multisite-zone-form/rgw-multisite-zone-form.component';
32 import { RgwMultisiteZonegroupFormComponent } from '../rgw-multisite-zonegroup-form/rgw-multisite-zonegroup-form.component';
35 selector: 'cd-rgw-multisite-details',
36 templateUrl: './rgw-multisite-details.component.html',
37 styleUrls: ['./rgw-multisite-details.component.scss']
39 export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit {
40 private sub = new Subscription();
42 @ViewChild('tree') tree: TreeComponent;
45 noDefaultRealm: $localize`Please create a default realm first to enable this feature`,
46 noMasterZone: $localize`Please create a master zone for each zonegroup to enable this feature`,
47 disableMigrate: $localize`Deployment is already migrated to multi-site system.`
51 permission: Permission;
52 selection = new CdTableSelection();
53 createTableActions: CdTableAction[];
54 migrateTableAction: CdTableAction[];
55 loadingIndicator = true;
57 treeOptions: ITreeOptions = {
58 useVirtualScroll: true,
63 click: this.onNodeSelected.bind(this)
67 modalRef: NgbModalRef;
69 realms: RgwRealm[] = [];
70 zonegroups: RgwZonegroup[] = [];
71 zones: RgwZone[] = [];
73 metadataTitle: string;
74 bsModalRef: NgbModalRef;
75 realmIds: string[] = [];
76 zoneIds: string[] = [];
78 defaultZonegroupId = '';
80 multisiteInfo: object[] = [];
81 defaultsInfo: string[] = [];
82 showMigrateAction: boolean = false;
83 editTitle: string = 'Edit';
84 deleteTitle: string = 'Delete';
87 private modalService: ModalService,
88 private timerService: TimerService,
89 private authStorageService: AuthStorageService,
90 public actionLabels: ActionLabelsI18n,
91 public timerServiceVariable: TimerServiceInterval,
92 public rgwRealmService: RgwRealmService,
93 public rgwZonegroupService: RgwZonegroupService,
94 public rgwZoneService: RgwZoneService,
95 private notificationService: NotificationService
97 this.permission = this.authStorageService.getPermissions().rgw;
98 const createRealmAction: CdTableAction = {
101 name: this.actionLabels.CREATE + ' Realm',
102 click: () => this.openModal('realm')
104 const createZonegroupAction: CdTableAction = {
105 permission: 'create',
107 name: this.actionLabels.CREATE + ' Zonegroup',
108 click: () => this.openModal('zonegroup'),
109 disable: () => this.getDisable()
111 const createZoneAction: CdTableAction = {
112 permission: 'create',
114 name: this.actionLabels.CREATE + ' Zone',
115 click: () => this.openModal('zone')
117 const migrateMultsiteAction: CdTableAction = {
119 icon: Icons.exchange,
120 name: this.actionLabels.MIGRATE,
121 click: () => this.openMigrateModal()
123 this.createTableActions = [createRealmAction, createZonegroupAction, createZoneAction];
124 this.migrateTableAction = [migrateMultsiteAction];
127 openModal(entity: any, edit = false) {
128 const entityName = edit ? entity.data.type : entity;
129 const action = edit ? 'edit' : 'create';
130 const initialState = {
131 resource: entityName,
134 defaultsInfo: this.defaultsInfo,
135 multisiteInfo: this.multisiteInfo
137 if (entityName === 'realm') {
138 this.bsModalRef = this.modalService.show(RgwMultisiteRealmFormComponent, initialState, {
141 } else if (entityName === 'zonegroup') {
142 this.bsModalRef = this.modalService.show(RgwMultisiteZonegroupFormComponent, initialState, {
146 this.bsModalRef = this.modalService.show(RgwMultisiteZoneFormComponent, initialState, {
153 const initialState = {
154 multisiteInfo: this.multisiteInfo
156 this.bsModalRef = this.modalService.show(RgwMultisiteMigrateComponent, initialState, {
162 const observables = [
163 this.rgwRealmService.getAllRealmsInfo(),
164 this.rgwZonegroupService.getAllZonegroupsInfo(),
165 this.rgwZoneService.getAllZonesInfo()
167 this.sub = this.timerService
168 .get(() => forkJoin(observables), this.timerServiceVariable.TIMER_SERVICE_PERIOD * 2)
170 (multisiteInfo: [object, object, object]) => {
171 this.multisiteInfo = multisiteInfo;
172 this.loadingIndicator = false;
173 this.nodes = this.abstractTreeData(multisiteInfo);
180 this.sub.unsubscribe();
183 private abstractTreeData(multisiteInfo: [object, object, object]): any[] {
184 let allNodes: object[] = [];
186 let firstChildNodes = {};
187 let allFirstChildNodes = [];
188 let secondChildNodes = {};
189 let allSecondChildNodes: {}[] = [];
190 this.realms = multisiteInfo[0]['realms'];
191 this.zonegroups = multisiteInfo[1]['zonegroups'];
192 this.zones = multisiteInfo[2]['zones'];
193 this.defaultRealmId = multisiteInfo[0]['default_realm'];
194 this.defaultZonegroupId = multisiteInfo[1]['default_zonegroup'];
195 this.defaultZoneId = multisiteInfo[2]['default_zone'];
196 this.defaultsInfo = this.getDefaultsEntities(
198 this.defaultZonegroupId,
201 if (this.realms.length > 0) {
202 // get tree for realm -> zonegroup -> zone
203 for (const realm of this.realms) {
204 const result = this.rgwRealmService.getRealmTree(realm, this.defaultRealmId);
205 rootNodes = result['nodes'];
206 this.realmIds = this.realmIds.concat(result['realmIds']);
207 for (const zonegroup of this.zonegroups) {
208 if (zonegroup.realm_id === realm.id) {
209 firstChildNodes = this.rgwZonegroupService.getZonegroupTree(
211 this.defaultZonegroupId,
214 for (const zone of zonegroup.zones) {
215 const zoneResult = this.rgwZoneService.getZoneTree(
221 secondChildNodes = zoneResult['nodes'];
222 this.zoneIds = this.zoneIds.concat(zoneResult['zoneIds']);
223 allSecondChildNodes.push(secondChildNodes);
224 secondChildNodes = {};
226 firstChildNodes['children'] = allSecondChildNodes;
227 allSecondChildNodes = [];
228 allFirstChildNodes.push(firstChildNodes);
229 firstChildNodes = {};
232 rootNodes['children'] = allFirstChildNodes;
233 allNodes.push(rootNodes);
234 firstChildNodes = {};
235 secondChildNodes = {};
237 allFirstChildNodes = [];
238 allSecondChildNodes = [];
241 if (this.zonegroups.length > 0) {
242 // get tree for zonegroup -> zone (standalone zonegroups that don't match a realm eg(initial default))
243 for (const zonegroup of this.zonegroups) {
244 if (!this.realmIds.includes(zonegroup.realm_id)) {
245 rootNodes = this.rgwZonegroupService.getZonegroupTree(zonegroup, this.defaultZonegroupId);
246 for (const zone of zonegroup.zones) {
247 const zoneResult = this.rgwZoneService.getZoneTree(zone, this.defaultZoneId, zonegroup);
248 firstChildNodes = zoneResult['nodes'];
249 this.zoneIds = this.zoneIds.concat(zoneResult['zoneIds']);
250 allFirstChildNodes.push(firstChildNodes);
251 firstChildNodes = {};
253 rootNodes['children'] = allFirstChildNodes;
254 allNodes.push(rootNodes);
255 firstChildNodes = {};
257 allFirstChildNodes = [];
261 if (this.zones.length > 0) {
262 // get tree for standalone zones(zones that do not belong to a zonegroup)
263 for (const zone of this.zones) {
264 if (this.zoneIds.length > 0 && !this.zoneIds.includes(zone.id)) {
265 const zoneResult = this.rgwZoneService.getZoneTree(zone, this.defaultZoneId);
266 rootNodes = zoneResult['nodes'];
267 allNodes.push(rootNodes);
272 if (this.realms.length < 1 && this.zonegroups.length < 1 && this.zones.length < 1) {
281 this.getDisableMigrate();
286 defaultRealmId: string,
287 defaultZonegroupId: string,
288 defaultZoneId: string
290 const defaultRealm = this.realms.find((x: { id: string }) => x.id === defaultRealmId);
291 const defaultZonegroup = this.zonegroups.find(
292 (x: { id: string }) => x.id === defaultZonegroupId
294 const defaultZone = this.zones.find((x: { id: string }) => x.id === defaultZoneId);
295 const defaultRealmName = defaultRealm !== undefined ? defaultRealm.name : null;
296 const defaultZonegroupName = defaultZonegroup !== undefined ? defaultZonegroup.name : null;
297 const defaultZoneName = defaultZone !== undefined ? defaultZone.name : null;
299 defaultRealmName: defaultRealmName,
300 defaultZonegroupName: defaultZonegroupName,
301 defaultZoneName: defaultZoneName
305 onNodeSelected(tree: TreeModel, node: TreeNode) {
306 TREE_ACTIONS.ACTIVATE(tree, node, true);
307 this.metadataTitle = node.data.name;
308 this.metadata = node.data.info;
309 node.data.show = true;
313 this.tree.treeModel.expandAll();
317 let isMasterZone = true;
318 if (this.defaultRealmId === '') {
319 return this.messages.noDefaultRealm;
321 this.zonegroups.forEach((zgp: any) => {
322 if (_.isEmpty(zgp.master_zone)) {
323 isMasterZone = false;
328 'Please create a master zone for each existing zonegroup to enable this feature';
329 return this.messages.noMasterZone;
331 this.editTitle = 'Edit';
337 getDisableMigrate() {
339 this.realms.length === 0 &&
340 this.zonegroups.length === 1 &&
341 this.zonegroups[0].name === 'default' &&
342 this.zones.length === 1 &&
343 this.zones[0].name === 'default'
345 this.showMigrateAction = true;
347 this.showMigrateAction = false;
349 return this.showMigrateAction;
352 isDeleteDisabled(node: TreeNode): boolean {
353 let disable: boolean = false;
354 let masterZonegroupCount: number = 0;
355 if (node.data.type === 'realm' && node.data.is_default && this.realms.length < 2) {
359 if (node.data.type === 'zonegroup') {
360 if (this.zonegroups.length < 2) {
361 this.deleteTitle = 'You can not delete the only zonegroup available';
363 } else if (node.data.is_default) {
364 this.deleteTitle = 'You can not delete the default zonegroup';
366 } else if (node.data.is_master) {
367 for (let zonegroup of this.zonegroups) {
368 if (zonegroup.is_master === true) {
369 masterZonegroupCount++;
370 if (masterZonegroupCount > 1) break;
373 if (masterZonegroupCount < 2) {
374 this.deleteTitle = 'You can not delete the only master zonegroup available';
380 if (node.data.type === 'zone') {
381 if (this.zones.length < 2) {
382 this.deleteTitle = 'You can not delete the only zone available';
384 } else if (node.data.is_default) {
385 this.deleteTitle = 'You can not delete the default zone';
387 } else if (node.data.is_master && node.data.zone_zonegroup.zones.length < 2) {
389 'You can not delete the master zone as there are no more zones in this zonegroup';
395 this.deleteTitle = 'Delete';
401 delete(node: TreeNode) {
402 if (node.data.type === 'realm') {
403 this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
404 itemDescription: $localize`${node.data.type} ${node.data.name}`,
405 itemNames: [`${node.data.name}`],
406 submitAction: () => {
407 this.rgwRealmService.delete(node.data.name).subscribe(
409 this.modalRef.close();
410 this.notificationService.show(
411 NotificationType.success,
412 $localize`Realm: '${node.data.name}' deleted successfully`
416 this.modalRef.componentInstance.stopLoadingSpinner();
421 } else if (node.data.type === 'zonegroup') {
422 this.modalRef = this.modalService.show(RgwMultisiteZonegroupDeletionFormComponent, {
425 } else if (node.data.type === 'zone') {
426 this.modalRef = this.modalService.show(RgwMultisiteZoneDeletionFormComponent, {