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