]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
3dda1b83069f6b5f8e4a7c20e087f15ced1a3aae
[ceph.git] /
1 import { Component, OnInit } from '@angular/core';
2 import { UntypedFormControl, Validators } from '@angular/forms';
3 import { ActivatedRoute, Router } from '@angular/router';
4 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
5 import {
6   NamespaceCreateRequest,
7   NamespaceUpdateRequest,
8   NvmeofService
9 } from '~/app/shared/api/nvmeof.service';
10 import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
11 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
12 import { FinishedTask } from '~/app/shared/models/finished-task';
13 import { NvmeofSubsystemNamespace } from '~/app/shared/models/nvmeof';
14 import { Permission } from '~/app/shared/models/permissions';
15 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
16 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
17 import { Pool } from '../../pool/pool';
18 import { PoolService } from '~/app/shared/api/pool.service';
19 import { RbdService } from '~/app/shared/api/rbd.service';
20 import { FormatterService } from '~/app/shared/services/formatter.service';
21 import { Observable } from 'rxjs';
22 import { CdValidators } from '~/app/shared/forms/cd-validators';
23 import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
24
25 @Component({
26   selector: 'cd-nvmeof-namespaces-form',
27   templateUrl: './nvmeof-namespaces-form.component.html',
28   styleUrls: ['./nvmeof-namespaces-form.component.scss']
29 })
30 export class NvmeofNamespacesFormComponent implements OnInit {
31   action: string;
32   permission: Permission;
33   poolPermission: Permission;
34   resource: string;
35   pageURL: string;
36   edit: boolean = false;
37   nsForm: CdFormGroup;
38   subsystemNQN: string;
39   rbdPools: Array<Pool> = null;
40   units: Array<string> = ['KiB', 'MiB', 'GiB', 'TiB'];
41   nsid: string;
42   currentBytes: number;
43   invalidSizeError: boolean;
44   group: string;
45
46   constructor(
47     public actionLabels: ActionLabelsI18n,
48     private authStorageService: AuthStorageService,
49     private taskWrapperService: TaskWrapperService,
50     private nvmeofService: NvmeofService,
51     private poolService: PoolService,
52     private rbdService: RbdService,
53     private router: Router,
54     private route: ActivatedRoute,
55     public activeModal: NgbActiveModal,
56     public formatterService: FormatterService,
57     public dimlessBinaryPipe: DimlessBinaryPipe
58   ) {
59     this.permission = this.authStorageService.getPermissions().nvmeof;
60     this.poolPermission = this.authStorageService.getPermissions().pool;
61     this.resource = $localize`Namespace`;
62     this.pageURL = 'block/nvmeof/subsystems';
63   }
64
65   init() {
66     this.route.queryParams.subscribe((params) => {
67       this.group = params?.['group'];
68     });
69     this.createForm();
70     this.action = this.actionLabels.CREATE;
71     this.route.params.subscribe((params: { subsystem_nqn: string; nsid: string }) => {
72       this.subsystemNQN = params.subsystem_nqn;
73       this.nsid = params?.nsid;
74     });
75   }
76
77   initForEdit() {
78     this.edit = true;
79     this.action = this.actionLabels.EDIT;
80     this.nvmeofService
81       .getNamespace(this.subsystemNQN, this.nsid, this.group)
82       .subscribe((res: NvmeofSubsystemNamespace) => {
83         const convertedSize = this.dimlessBinaryPipe.transform(res.rbd_image_size).split(' ');
84         this.currentBytes = res.rbd_image_size;
85         this.nsForm.get('image').setValue(res.rbd_image_name);
86         this.nsForm.get('pool').setValue(res.rbd_pool_name);
87         this.nsForm.get('unit').setValue(convertedSize[1]);
88         this.nsForm.get('image_size').setValue(convertedSize[0]);
89         this.nsForm.get('image_size').addValidators(Validators.required);
90         this.nsForm.get('image').disable();
91         this.nsForm.get('pool').disable();
92       });
93   }
94
95   initForCreate() {
96     this.poolService.getList().subscribe((resp: Pool[]) => {
97       this.rbdPools = resp.filter(this.rbdService.isRBDPool);
98     });
99   }
100
101   ngOnInit() {
102     this.init();
103     if (this.router.url.includes('subsystems/(modal:edit')) {
104       this.initForEdit();
105     } else {
106       this.initForCreate();
107     }
108   }
109
110   createForm() {
111     this.nsForm = new CdFormGroup({
112       image: new UntypedFormControl(`nvme_ns_image:${Date.now()}`, {
113         validators: [Validators.required, Validators.pattern(/^[^@/]+?$/)]
114       }),
115       pool: new UntypedFormControl(null, {
116         validators: [Validators.required]
117       }),
118       image_size: new UntypedFormControl(1, [CdValidators.number(false), Validators.min(1)]),
119       unit: new UntypedFormControl(this.units[2])
120     });
121   }
122
123   updateRequest(rbdImageSize: number): NamespaceUpdateRequest {
124     const request: NamespaceUpdateRequest = {
125       gw_group: this.group,
126       rbd_image_size: rbdImageSize
127     };
128     return request;
129   }
130
131   createRequest(rbdImageSize: number): NamespaceCreateRequest {
132     const image = this.nsForm.getValue('image');
133     const pool = this.nsForm.getValue('pool');
134     const request: NamespaceCreateRequest = {
135       gw_group: this.group,
136       rbd_image_name: image,
137       rbd_pool: pool
138     };
139     if (rbdImageSize) {
140       request['rbd_image_size'] = rbdImageSize;
141     }
142     return request;
143   }
144
145   buildRequest() {
146     const image_size = this.nsForm.getValue('image_size');
147     let rbdImageSize: number = null;
148     if (image_size) {
149       const image_size_unit = this.nsForm.getValue('unit');
150       const value: number = this.formatterService.toBytes(image_size + image_size_unit);
151       rbdImageSize = value;
152     }
153     if (this.edit) {
154       return this.updateRequest(rbdImageSize);
155     } else {
156       return this.createRequest(rbdImageSize);
157     }
158   }
159
160   validateSize() {
161     const unit = this.nsForm.getValue('unit');
162     const image_size = this.nsForm.getValue('image_size');
163     if (image_size && unit) {
164       const bytes = this.formatterService.toBytes(image_size + unit);
165       return bytes <= this.currentBytes;
166     }
167     return null;
168   }
169
170   onSubmit() {
171     if (this.validateSize()) {
172       this.invalidSizeError = true;
173       this.nsForm.setErrors({ cdSubmitButton: true });
174     } else {
175       this.invalidSizeError = false;
176       const component = this;
177       const taskUrl: string = `nvmeof/namespace/${this.edit ? URLVerbs.EDIT : URLVerbs.CREATE}`;
178       const request: NamespaceCreateRequest | NamespaceUpdateRequest = this.buildRequest();
179       let action: Observable<any>;
180
181       if (this.edit) {
182         action = this.taskWrapperService.wrapTaskAroundCall({
183           task: new FinishedTask(taskUrl, {
184             nqn: this.subsystemNQN,
185             nsid: this.nsid
186           }),
187           call: this.nvmeofService.updateNamespace(
188             this.subsystemNQN,
189             this.nsid,
190             request as NamespaceUpdateRequest
191           )
192         });
193       } else {
194         action = this.taskWrapperService.wrapTaskAroundCall({
195           task: new FinishedTask(taskUrl, {
196             nqn: this.subsystemNQN
197           }),
198           call: this.nvmeofService.createNamespace(
199             this.subsystemNQN,
200             request as NamespaceCreateRequest
201           )
202         });
203       }
204
205       action.subscribe({
206         error() {
207           component.nsForm.setErrors({ cdSubmitButton: true });
208         },
209         complete: () => {
210           this.router.navigate([this.pageURL, { outlets: { modal: null } }]);
211         }
212       });
213     }
214   }
215 }