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';
6 NamespaceCreateRequest,
7 NamespaceUpdateRequest,
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 { forkJoin, Observable } from 'rxjs';
22 import { CdValidators } from '~/app/shared/forms/cd-validators';
23 import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
24 import { HttpResponse } from '@angular/common/http';
27 selector: 'cd-nvmeof-namespaces-form',
28 templateUrl: './nvmeof-namespaces-form.component.html',
29 styleUrls: ['./nvmeof-namespaces-form.component.scss']
31 export class NvmeofNamespacesFormComponent implements OnInit {
33 permission: Permission;
34 poolPermission: Permission;
37 edit: boolean = false;
40 rbdPools: Array<Pool> = null;
41 units: Array<string> = ['KiB', 'MiB', 'GiB', 'TiB'];
44 invalidSizeError: boolean;
46 MAX_NAMESPACE_CREATE: number = 5;
47 MIN_NAMESPACE_CREATE: number = 1;
48 requiredInvalidText: string = $localize`This field is required`;
49 nsCountInvalidText: string = $localize`The namespace count should be between 1 and 5`;
52 public actionLabels: ActionLabelsI18n,
53 private authStorageService: AuthStorageService,
54 private taskWrapperService: TaskWrapperService,
55 private nvmeofService: NvmeofService,
56 private poolService: PoolService,
57 private rbdService: RbdService,
58 private router: Router,
59 private route: ActivatedRoute,
60 public activeModal: NgbActiveModal,
61 public formatterService: FormatterService,
62 public dimlessBinaryPipe: DimlessBinaryPipe
64 this.permission = this.authStorageService.getPermissions().nvmeof;
65 this.poolPermission = this.authStorageService.getPermissions().pool;
66 this.resource = $localize`Namespace`;
67 this.pageURL = 'block/nvmeof/subsystems';
71 this.route.queryParams.subscribe((params) => {
72 this.group = params?.['group'];
75 this.action = this.actionLabels.CREATE;
76 this.route.params.subscribe((params: { subsystem_nqn: string; nsid: string }) => {
77 this.subsystemNQN = params.subsystem_nqn;
78 this.nsid = params?.nsid;
84 this.action = this.actionLabels.EDIT;
86 .getNamespace(this.subsystemNQN, this.nsid, this.group)
87 .subscribe((res: NvmeofSubsystemNamespace) => {
88 const convertedSize = this.dimlessBinaryPipe.transform(res.rbd_image_size).split(' ');
89 this.currentBytes = res.rbd_image_size;
90 this.nsForm.get('image').setValue(res.rbd_image_name);
91 this.nsForm.get('pool').setValue(res.rbd_pool_name);
92 this.nsForm.get('unit').setValue(convertedSize[1]);
93 this.nsForm.get('image_size').setValue(convertedSize[0]);
94 this.nsForm.get('image_size').addValidators(Validators.required);
95 this.nsForm.get('image').disable();
96 this.nsForm.get('pool').disable();
101 this.poolService.getList().subscribe((resp: Pool[]) => {
102 this.rbdPools = resp.filter(this.rbdService.isRBDPool);
104 if (this.rbdPools?.length) {
105 this.nsForm.get('pool').setValue(this.rbdPools[0].pool_name);
111 if (this.router.url.includes('subsystems/(modal:edit')) {
114 this.initForCreate();
119 this.nsForm = new CdFormGroup({
120 pool: new UntypedFormControl(null, {
121 validators: [Validators.required]
123 image_size: new UntypedFormControl(1, [CdValidators.number(false), Validators.min(1)]),
124 unit: new UntypedFormControl(this.units[2]),
125 nsCount: new UntypedFormControl(this.MAX_NAMESPACE_CREATE, [
127 Validators.max(this.MAX_NAMESPACE_CREATE),
128 Validators.min(this.MIN_NAMESPACE_CREATE)
133 buildUpdateRequest(rbdImageSize: number): Observable<HttpResponse<Object>> {
134 const request: NamespaceUpdateRequest = {
135 gw_group: this.group,
136 rbd_image_size: rbdImageSize
138 return this.nvmeofService.updateNamespace(
141 request as NamespaceUpdateRequest
146 return Math.random().toString(36).substring(2);
149 buildCreateRequest(rbdImageSize: number, nsCount: number): Observable<HttpResponse<Object>>[] {
150 const pool = this.nsForm.getValue('pool');
151 const requests: Observable<HttpResponse<Object>>[] = [];
153 for (let i = 1; i <= nsCount; i++) {
154 const request: NamespaceCreateRequest = {
155 gw_group: this.group,
156 rbd_image_name: `nvme_${pool}_${this.group}_${this.randomString()}`,
160 request['rbd_image_size'] = rbdImageSize;
162 requests.push(this.nvmeofService.createNamespace(this.subsystemNQN, request));
169 const unit = this.nsForm.getValue('unit');
170 const image_size = this.nsForm.getValue('image_size');
171 if (image_size && unit) {
172 const bytes = this.formatterService.toBytes(image_size + unit);
173 return bytes <= this.currentBytes;
179 if (this.validateSize()) {
180 this.invalidSizeError = true;
181 this.nsForm.setErrors({ cdSubmitButton: true });
183 this.invalidSizeError = false;
184 const component = this;
185 const taskUrl: string = `nvmeof/namespace/${this.edit ? URLVerbs.EDIT : URLVerbs.CREATE}`;
186 const image_size = this.nsForm.getValue('image_size');
187 const nsCount = this.nsForm.getValue('nsCount');
188 let action: Observable<HttpResponse<Object>>;
189 let rbdImageSize: number = null;
192 const image_size_unit = this.nsForm.getValue('unit');
193 const value: number = this.formatterService.toBytes(image_size + image_size_unit);
194 rbdImageSize = value;
197 action = this.taskWrapperService.wrapTaskAroundCall({
198 task: new FinishedTask(taskUrl, {
199 nqn: this.subsystemNQN,
202 call: this.buildUpdateRequest(rbdImageSize)
205 action = this.taskWrapperService.wrapTaskAroundCall({
206 task: new FinishedTask(taskUrl, {
207 nqn: this.subsystemNQN,
210 call: forkJoin(this.buildCreateRequest(rbdImageSize, nsCount))
216 component.nsForm.setErrors({ cdSubmitButton: true });
219 this.router.navigate([this.pageURL, { outlets: { modal: null } }]);