]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
5960abc1594f2e08e8c8a890ffbb3c6e18e1f8b6
[ceph-ci.git] /
1 import { Component, OnDestroy, OnInit } from '@angular/core';
2 import { UntypedFormControl, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms';
3
4 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
5 import _ from 'lodash';
6 import { concat, forkJoin, Observable, Subscription } from 'rxjs';
7 import { last } from 'rxjs/operators';
8
9 import { Pool } from '~/app/ceph/pool/pool';
10 import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
11 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
12 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
13 import { FinishedTask } from '~/app/shared/models/finished-task';
14 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
15
16 @Component({
17   selector: 'cd-bootstrap-import-modal',
18   templateUrl: './bootstrap-import-modal.component.html',
19   styleUrls: ['./bootstrap-import-modal.component.scss']
20 })
21 export class BootstrapImportModalComponent implements OnInit, OnDestroy {
22   siteName: string;
23   pools: any[] = [];
24   token: string;
25
26   subs: Subscription;
27
28   importBootstrapForm: CdFormGroup;
29
30   directions: Array<any> = [
31     { key: 'rx-tx', desc: 'Bidirectional' },
32     { key: 'rx', desc: 'Unidirectional (receive-only)' }
33   ];
34
35   constructor(
36     public activeModal: NgbActiveModal,
37     public actionLabels: ActionLabelsI18n,
38     private rbdMirroringService: RbdMirroringService,
39     private taskWrapper: TaskWrapperService
40   ) {
41     this.createForm();
42   }
43
44   createForm() {
45     this.importBootstrapForm = new CdFormGroup({
46       siteName: new UntypedFormControl('', {
47         validators: [Validators.required]
48       }),
49       direction: new UntypedFormControl('rx-tx', {}),
50       pools: new UntypedFormGroup(
51         {},
52         {
53           validators: [this.validatePools()]
54         }
55       ),
56       token: new UntypedFormControl('', {
57         validators: [Validators.required, this.validateToken()]
58       })
59     });
60   }
61
62   ngOnInit() {
63     this.rbdMirroringService.getSiteName().subscribe((response: any) => {
64       this.importBootstrapForm.get('siteName').setValue(response.site_name);
65     });
66
67     this.subs = this.rbdMirroringService.subscribeSummary((data) => {
68       const pools = data.content_data.pools;
69       this.pools = pools.reduce((acc: any[], pool: Pool) => {
70         acc.push({
71           name: pool['name'],
72           mirror_mode: pool['mirror_mode']
73         });
74         return acc;
75       }, []);
76
77       const poolsControl = this.importBootstrapForm.get('pools') as UntypedFormGroup;
78       _.each(this.pools, (pool) => {
79         const poolName = pool['name'];
80         const mirroring_disabled = pool['mirror_mode'] === 'disabled';
81         const control = poolsControl.controls[poolName];
82         if (control) {
83           if (mirroring_disabled && control.disabled) {
84             control.enable();
85           } else if (!mirroring_disabled && control.enabled) {
86             control.disable();
87             control.setValue(true);
88           }
89         } else {
90           poolsControl.addControl(
91             poolName,
92             new UntypedFormControl({ value: !mirroring_disabled, disabled: !mirroring_disabled })
93           );
94         }
95       });
96     });
97   }
98
99   ngOnDestroy() {
100     if (this.subs) {
101       this.subs.unsubscribe();
102     }
103   }
104
105   validatePools(): ValidatorFn {
106     return (poolsControl: UntypedFormGroup): { [key: string]: any } => {
107       let checkedCount = 0;
108       _.each(poolsControl.controls, (control) => {
109         if (control.value === true) {
110           ++checkedCount;
111         }
112       });
113
114       if (checkedCount > 0) {
115         return null;
116       }
117
118       return { requirePool: true };
119     };
120   }
121
122   validateToken(): ValidatorFn {
123     return (token: UntypedFormControl): { [key: string]: any } => {
124       try {
125         if (JSON.parse(atob(token.value))) {
126           return null;
127         }
128       } catch (error) {}
129       return { invalidToken: true };
130     };
131   }
132
133   import() {
134     const bootstrapPoolNames: string[] = [];
135     const poolNames: string[] = [];
136     const poolsControl = this.importBootstrapForm.get('pools') as UntypedFormGroup;
137     _.each(poolsControl.controls, (control, poolName) => {
138       if (control.value === true) {
139         bootstrapPoolNames.push(poolName);
140         if (!control.disabled) {
141           poolNames.push(poolName);
142         }
143       }
144     });
145
146     const poolModeRequest = {
147       mirror_mode: 'image'
148     };
149
150     let apiActionsObs: Observable<any> = concat(
151       this.rbdMirroringService.setSiteName(this.importBootstrapForm.getValue('siteName')),
152       forkJoin(
153         poolNames.map((poolName) => this.rbdMirroringService.updatePool(poolName, poolModeRequest))
154       )
155     );
156
157     apiActionsObs = bootstrapPoolNames
158       .reduce((obs, poolName) => {
159         return concat(
160           obs,
161           this.rbdMirroringService.importBootstrapToken(
162             poolName,
163             this.importBootstrapForm.getValue('direction'),
164             this.importBootstrapForm.getValue('token')
165           )
166         );
167       }, apiActionsObs)
168       .pipe(last());
169
170     const finishHandler = () => {
171       this.rbdMirroringService.refresh();
172       this.importBootstrapForm.setErrors({ cdSubmitButton: true });
173     };
174
175     const taskObs = this.taskWrapper.wrapTaskAroundCall({
176       task: new FinishedTask('rbd/mirroring/bootstrap/import', {}),
177       call: apiActionsObs
178     });
179     taskObs.subscribe({
180       error: finishHandler,
181       complete: () => {
182         finishHandler();
183         this.activeModal.close();
184       }
185     });
186   }
187 }