]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
f5721e11ab6d3e27b3880200803af7de059afc72
[ceph-ci.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   NamespaceEditRequest,
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
45   constructor(
46     public actionLabels: ActionLabelsI18n,
47     private authStorageService: AuthStorageService,
48     private taskWrapperService: TaskWrapperService,
49     private nvmeofService: NvmeofService,
50     private poolService: PoolService,
51     private rbdService: RbdService,
52     private router: Router,
53     private route: ActivatedRoute,
54     public activeModal: NgbActiveModal,
55     public formatterService: FormatterService,
56     public dimlessBinaryPipe: DimlessBinaryPipe
57   ) {
58     this.permission = this.authStorageService.getPermissions().nvmeof;
59     this.poolPermission = this.authStorageService.getPermissions().pool;
60     this.resource = $localize`Namespace`;
61     this.pageURL = 'block/nvmeof/subsystems';
62   }
63
64   init() {
65     this.createForm();
66     this.action = this.actionLabels.CREATE;
67     this.route.params.subscribe((params: { subsystem_nqn: string; nsid: string }) => {
68       this.subsystemNQN = params.subsystem_nqn;
69       this.nsid = params?.nsid;
70     });
71   }
72
73   initForEdit() {
74     this.edit = true;
75     this.action = this.actionLabels.EDIT;
76     this.nvmeofService
77       .getNamespace(this.subsystemNQN, this.nsid)
78       .subscribe((res: NvmeofSubsystemNamespace) => {
79         const convertedSize = this.dimlessBinaryPipe.transform(res.rbd_image_size).split(' ');
80         this.currentBytes = res.rbd_image_size;
81         this.nsForm.get('image').setValue(res.rbd_image_name);
82         this.nsForm.get('pool').setValue(res.rbd_pool_name);
83         this.nsForm.get('unit').setValue(convertedSize[1]);
84         this.nsForm.get('image_size').setValue(convertedSize[0]);
85         this.nsForm.get('image_size').addValidators(Validators.required);
86         this.nsForm.get('image').disable();
87         this.nsForm.get('pool').disable();
88       });
89   }
90
91   initForCreate() {
92     this.poolService.getList().subscribe((resp: Pool[]) => {
93       this.rbdPools = resp.filter(this.rbdService.isRBDPool);
94     });
95   }
96
97   ngOnInit() {
98     this.init();
99     if (this.router.url.includes('subsystems/(modal:edit')) {
100       this.initForEdit();
101     } else {
102       this.initForCreate();
103     }
104   }
105
106   createForm() {
107     this.nsForm = new CdFormGroup({
108       image: new UntypedFormControl(`nvme_ns_image:${Date.now()}`, {
109         validators: [Validators.required, Validators.pattern(/^[^@/]+?$/)]
110       }),
111       pool: new UntypedFormControl(null, {
112         validators: [Validators.required]
113       }),
114       image_size: new UntypedFormControl(1, [CdValidators.number(false), Validators.min(1)]),
115       unit: new UntypedFormControl(this.units[2])
116     });
117   }
118
119   buildRequest(): NamespaceCreateRequest | NamespaceEditRequest {
120     const image_size = this.nsForm.getValue('image_size');
121     const image_size_unit = this.nsForm.getValue('unit');
122     const request = {} as NamespaceCreateRequest | NamespaceEditRequest;
123     if (image_size) {
124       const key: string = this.edit ? 'rbd_image_size' : 'size';
125       const value: number = this.formatterService.toBytes(image_size + image_size_unit);
126       request[key] = value;
127     }
128     if (!this.edit) {
129       const image = this.nsForm.getValue('image');
130       const pool = this.nsForm.getValue('pool');
131       request['rbd_image_name'] = image;
132       request['rbd_pool'] = pool;
133     }
134     return request;
135   }
136
137   validateSize() {
138     const unit = this.nsForm.getValue('unit');
139     const image_size = this.nsForm.getValue('image_size');
140     if (image_size && unit) {
141       const bytes = this.formatterService.toBytes(image_size + unit);
142       return bytes <= this.currentBytes;
143     }
144     return null;
145   }
146
147   onSubmit() {
148     if (this.validateSize()) {
149       this.invalidSizeError = true;
150       this.nsForm.setErrors({ cdSubmitButton: true });
151     } else {
152       this.invalidSizeError = false;
153       const component = this;
154       const taskUrl: string = `nvmeof/namespace/${this.edit ? URLVerbs.EDIT : URLVerbs.CREATE}`;
155       const request = this.buildRequest();
156       let action: Observable<any>;
157
158       if (this.edit) {
159         action = this.taskWrapperService.wrapTaskAroundCall({
160           task: new FinishedTask(taskUrl, {
161             nqn: this.subsystemNQN,
162             nsid: this.nsid
163           }),
164           call: this.nvmeofService.updateNamespace(
165             this.subsystemNQN,
166             this.nsid,
167             request as NamespaceEditRequest
168           )
169         });
170       } else {
171         action = this.taskWrapperService.wrapTaskAroundCall({
172           task: new FinishedTask(taskUrl, {
173             nqn: this.subsystemNQN
174           }),
175           call: this.nvmeofService.createNamespace(
176             this.subsystemNQN,
177             request as NamespaceCreateRequest
178           )
179         });
180       }
181
182       action.subscribe({
183         error() {
184           component.nsForm.setErrors({ cdSubmitButton: true });
185         },
186         complete: () => {
187           this.router.navigate([this.pageURL, { outlets: { modal: null } }]);
188         }
189       });
190     }
191   }
192 }