]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
2fbe1163ef841d840a102ee8d1c9b4f9d58d20cc
[ceph.git] /
1 import { Component, OnInit } from '@angular/core';
2 import { Location } from '@angular/common';
3 import { UntypedFormControl, Validators } from '@angular/forms';
4 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
5 import { Subscription, forkJoin } from 'rxjs';
6 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
7 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
8 import { WizardStepModel } from '~/app/shared/models/wizard-steps';
9 import { WizardStepsService } from '~/app/shared/services/wizard-steps.service';
10 import { RgwDaemonService } from '~/app/shared/api/rgw-daemon.service';
11 import { RgwDaemon } from '../models/rgw-daemon';
12 import { MultiClusterService } from '~/app/shared/api/multi-cluster.service';
13 import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
14 import { Icons } from '~/app/shared/enum/icons.enum';
15 import { SelectOption } from '~/app/shared/components/select/select-option.model';
16 import _ from 'lodash';
17 import { SelectMessages } from '~/app/shared/components/select/select-messages.model';
18 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
19 import { NotificationService } from '~/app/shared/services/notification.service';
20 import { ActivatedRoute } from '@angular/router';
21 import { map, switchMap } from 'rxjs/operators';
22 import { BaseModal, Step } from 'carbon-components-angular';
23 import { SummaryService } from '~/app/shared/services/summary.service';
24 import { ExecutingTask } from '~/app/shared/models/executing-task';
25 import {
26   STEP_TITLES_MULTI_CLUSTER_CONFIGURED,
27   STEP_TITLES_SINGLE_CLUSTER
28 } from './multisite-wizard-steps.enum';
29
30 @Component({
31   selector: 'cd-rgw-multisite-wizard',
32   templateUrl: './rgw-multisite-wizard.component.html',
33   styleUrls: ['./rgw-multisite-wizard.component.scss']
34 })
35 export class RgwMultisiteWizardComponent extends BaseModal implements OnInit {
36   multisiteSetupForm: CdFormGroup;
37   currentStep: WizardStepModel;
38   currentStepSub: Subscription;
39   permissions: Permissions;
40   stepTitles: Step[] = STEP_TITLES_MULTI_CLUSTER_CONFIGURED.map((title) => ({
41     label: title
42   }));
43   stepsToSkip: { [steps: string]: boolean } = {};
44   daemons: RgwDaemon[] = [];
45   selectedCluster = '';
46   clusterDetailsArray: any;
47   isMultiClusterConfigured = false;
48   exportTokenForm: CdFormGroup;
49   realms: any;
50   loading = false;
51   pageURL: string;
52   icons = Icons;
53   rgwEndpoints: { value: any[]; options: any[]; messages: any };
54   executingTask: ExecutingTask;
55   setupCompleted = false;
56
57   constructor(
58     private wizardStepsService: WizardStepsService,
59     public activeModal: NgbActiveModal,
60     public actionLabels: ActionLabelsI18n,
61     private rgwDaemonService: RgwDaemonService,
62     private multiClusterService: MultiClusterService,
63     private rgwMultisiteService: RgwMultisiteService,
64     public notificationService: NotificationService,
65     private route: ActivatedRoute,
66     private summaryService: SummaryService,
67     private location: Location
68   ) {
69     super();
70     this.pageURL = 'rgw/multisite/configuration';
71     this.currentStepSub = this.wizardStepsService
72       .getCurrentStep()
73       .subscribe((step: WizardStepModel) => {
74         this.currentStep = step;
75       });
76     this.currentStep.stepIndex = 0;
77     this.createForm();
78     this.rgwEndpoints = {
79       value: [],
80       options: [],
81       messages: new SelectMessages({
82         empty: $localize`There are no endpoints.`,
83         filter: $localize`Select endpoints`
84       })
85     };
86   }
87
88   ngOnInit(): void {
89     this.open = this.route.outlet === 'modal';
90     this.rgwDaemonService
91       .list()
92       .pipe(
93         switchMap((daemons) => {
94           this.daemons = daemons;
95           const daemonStatsObservables = daemons.map((daemon) =>
96             this.rgwDaemonService.get(daemon.id).pipe(
97               map((daemonStats) => ({
98                 hostname: daemon.server_hostname,
99                 port: daemon.port,
100                 frontendConfig: daemonStats['rgw_metadata']['frontend_config#0']
101               }))
102             )
103           );
104           return forkJoin(daemonStatsObservables);
105         })
106       )
107       .subscribe((daemonStatsArray) => {
108         this.rgwEndpoints.value = daemonStatsArray.map((daemonStats) => {
109           const protocol = daemonStats.frontendConfig.includes('ssl_port') ? 'https' : 'http';
110           return `${protocol}://${daemonStats.hostname}:${daemonStats.port}`;
111         });
112         const options: SelectOption[] = this.rgwEndpoints.value.map(
113           (endpoint: string) => new SelectOption(false, endpoint, '')
114         );
115         this.rgwEndpoints.options = [...options];
116       });
117
118     this.multiClusterService.getCluster().subscribe((clusters) => {
119       this.clusterDetailsArray = Object.values(clusters['config'])
120         .flat()
121         .filter((cluster) => cluster['url'] !== clusters['current_url']);
122       this.isMultiClusterConfigured = this.clusterDetailsArray.length > 0;
123       if (!this.isMultiClusterConfigured) {
124         this.stepTitles = STEP_TITLES_SINGLE_CLUSTER.map((title) => ({
125           label: title
126         }));
127         this.stepTitles.forEach((steps, index) => {
128           steps.onClick = () => (this.currentStep.stepIndex = index);
129         });
130       } else {
131         this.selectedCluster = this.clusterDetailsArray[0]['name'];
132       }
133       this.wizardStepsService.setTotalSteps(this.stepTitles.length);
134     });
135
136     this.summaryService.subscribe((summary) => {
137       this.executingTask = summary.executing_tasks.filter((tasks) =>
138         tasks.name.includes('progress/Multisite-Setup')
139       )[0];
140     });
141
142     this.stepTitles.forEach((stepTitle) => {
143       this.stepsToSkip[stepTitle.label] = false;
144     });
145   }
146
147   createForm() {
148     this.multisiteSetupForm = new CdFormGroup({
149       realmName: new UntypedFormControl('default_realm', {
150         validators: [Validators.required]
151       }),
152       zonegroupName: new UntypedFormControl('default_zonegroup', {
153         validators: [Validators.required]
154       }),
155       zonegroup_endpoints: new UntypedFormControl(null, [Validators.required]),
156       zoneName: new UntypedFormControl('default_zone', {
157         validators: [Validators.required]
158       }),
159       zone_endpoints: new UntypedFormControl(null, {
160         validators: [Validators.required]
161       }),
162       username: new UntypedFormControl('default_system_user', {
163         validators: [Validators.required]
164       }),
165       cluster: new UntypedFormControl(null, {
166         validators: [Validators.required]
167       }),
168       replicationZoneName: new UntypedFormControl('new_replicated_zone', {
169         validators: [Validators.required]
170       })
171     });
172
173     if (!this.isMultiClusterConfigured) {
174       this.exportTokenForm = new CdFormGroup({});
175     }
176   }
177
178   showSubmitButtonLabel() {
179     if (this.wizardStepsService.isLastStep()) {
180       if (!this.setupCompleted) {
181         if (this.isMultiClusterConfigured) {
182           return $localize`Configure Multi-Site`;
183         } else {
184           return $localize`Export Multi-Site token`;
185         }
186       } else {
187         return $localize`Close`;
188       }
189     } else {
190       return $localize`Next`;
191     }
192   }
193
194   showCancelButtonLabel() {
195     return !this.wizardStepsService.isFirstStep()
196       ? this.actionLabels.BACK
197       : this.actionLabels.CANCEL;
198   }
199
200   onNextStep() {
201     if (!this.wizardStepsService.isLastStep()) {
202       this.wizardStepsService.moveToNextStep();
203     } else {
204       if (this.setupCompleted) {
205         this.closeModal();
206       } else {
207         this.onSubmit();
208       }
209     }
210     this.wizardStepsService.getCurrentStep().subscribe((step: WizardStepModel) => {
211       this.currentStep = step;
212       if (this.currentStep.stepIndex === 2 && this.isMultiClusterConfigured) {
213         this.stepsToSkip['Select Cluster'] = false;
214       }
215     });
216   }
217
218   onSubmit() {
219     this.loading = true;
220     const values = this.multisiteSetupForm.getRawValue();
221     const realmName = values['realmName'];
222     const zonegroupName = values['zonegroupName'];
223     const zonegroupEndpoints = this.rgwEndpoints.value.join(',');
224     const zoneName = values['zoneName'];
225     const zoneEndpoints = this.rgwEndpoints.value.join(',');
226     const username = values['username'];
227     if (!this.isMultiClusterConfigured || this.stepsToSkip['Select Cluster']) {
228       this.rgwMultisiteService
229         .setUpMultisiteReplication(
230           realmName,
231           zonegroupName,
232           zonegroupEndpoints,
233           zoneName,
234           zoneEndpoints,
235           username
236         )
237         .subscribe((data: object[]) => {
238           this.setupCompleted = true;
239           this.rgwMultisiteService.setRestartGatewayMessage(false);
240           this.loading = false;
241           this.realms = data;
242           this.showSuccessNotification();
243         });
244     } else {
245       const cluster = values['cluster'];
246       const replicationZoneName = values['replicationZoneName'];
247       this.rgwMultisiteService
248         .setUpMultisiteReplication(
249           realmName,
250           zonegroupName,
251           zonegroupEndpoints,
252           zoneName,
253           zoneEndpoints,
254           username,
255           cluster,
256           replicationZoneName,
257           this.clusterDetailsArray
258         )
259         .subscribe(
260           () => {
261             this.setupCompleted = true;
262             this.rgwMultisiteService.setRestartGatewayMessage(false);
263             this.loading = false;
264             this.showSuccessNotification();
265           },
266           () => {
267             this.multisiteSetupForm.setErrors({ cdSubmitButton: true });
268           }
269         );
270     }
271   }
272
273   showSuccessNotification() {
274     this.notificationService.show(
275       NotificationType.success,
276       $localize`Multi-site setup completed successfully.`
277     );
278   }
279
280   onPreviousStep() {
281     if (!this.wizardStepsService.isFirstStep()) {
282       this.wizardStepsService.moveToPreviousStep();
283     } else {
284       this.location.back();
285     }
286   }
287
288   onSkip() {
289     const stepTitle = this.stepTitles[this.currentStep.stepIndex];
290     this.stepsToSkip[stepTitle.label] = true;
291     this.onNextStep();
292   }
293
294   closeModal(): void {
295     this.location.back();
296   }
297 }