]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.html
899742549e663a62bda5ba6b22145621500a865d
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / block / iscsi-target-form / iscsi-target-form.component.html
1 <div class="cd-col-form">
2 <form name="targetForm"
3 #formDir="ngForm"
4 [formGroup]="targetForm"
5 novalidate
6 *ngIf="targetForm">
7 <div class="card">
8 <div i18n="form title|Example: Create Pool@@formTitle"
9 class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
10
11 <div class="card-body">
12 <!-- Target IQN -->
13 <div class="form-group row">
14 <label class="cd-col-form-label required"
15 for="target_iqn"
16 i18n>Target IQN</label>
17 <div class="cd-col-form-input">
18 <div class="input-group">
19 <input class="form-control"
20 type="text"
21 id="target_iqn"
22 name="target_iqn"
23 formControlName="target_iqn"
24 cdTrim />
25 <span class="input-group-append">
26 <button class="btn btn-light"
27 id="ecp-info-button"
28 type="button"
29 (click)="targetSettingsModal()">
30 <i [ngClass]="[icons.deepCheck]"
31 aria-hidden="true"></i>
32 </button>
33 </span>
34 </div>
35
36 <span class="invalid-feedback"
37 *ngIf="targetForm.showError('target_iqn', formDir, 'required')"
38 i18n>This field is required.</span>
39
40 <span class="invalid-feedback"
41 *ngIf="targetForm.showError('target_iqn', formDir, 'pattern')"
42 i18n>IQN has wrong pattern.</span>
43
44 <span class="invalid-feedback"
45 *ngIf="targetForm.showError('target_iqn', formDir, 'iqn')">
46 <ng-container i18n>An IQN has the following notation
47 'iqn.$year-$month.$reversedAddress:$definedName'</ng-container>
48 <br>
49 <ng-container i18n>For example: iqn.2016-06.org.dashboard:storage:disk.sn-a8675309</ng-container>
50 <br>
51 <a target="_blank"
52 href="https://en.wikipedia.org/wiki/ISCSI#Addressing"
53 i18n>More information</a>
54 </span>
55
56 <span class="form-text text-muted"
57 *ngIf="hasAdvancedSettings(targetForm.getValue('target_controls'))"
58 i18n>This target has modified advanced settings.</span>
59 <hr />
60 </div>
61 </div>
62
63 <!-- Portals -->
64 <div class="form-group row">
65 <label class="cd-col-form-label required"
66 for="portals"
67 i18n>Portals</label>
68 <div class="cd-col-form-input">
69
70 <ng-container *ngFor="let portal of portals.value; let i = index">
71 <div class="input-group cd-mb">
72 <input class="cd-form-control"
73 type="text"
74 [value]="portal"
75 disabled />
76 <span class="input-group-append">
77 <button class="btn btn-light"
78 type="button"
79 (click)="removePortal(i, portal)">
80 <i [ngClass]="[icons.destroy]"
81 aria-hidden="true"></i>
82 </button>
83 </span>
84 </div>
85 </ng-container>
86
87 <div class="row">
88 <div class="col-md-12">
89 <cd-select [data]="portals.value"
90 [options]="portalsSelections"
91 [messages]="messages.portals"
92 (selection)="onPortalSelection($event)"
93 elemClass="btn btn-light float-right">
94 <i [ngClass]="[icons.add]"></i>
95 <ng-container i18n>Add portal</ng-container>
96 </cd-select>
97 </div>
98 </div>
99
100 <input class="form-control"
101 type="hidden"
102 id="portals"
103 name="portals"
104 formControlName="portals" />
105
106 <span class="invalid-feedback"
107 *ngIf="targetForm.showError('portals', formDir, 'minGateways')"
108 i18n>At least {{ minimum_gateways }} gateways are required.</span>
109
110 <hr />
111 </div>
112 </div>
113
114 <!-- Images -->
115 <div class="form-group row">
116 <label class="cd-col-form-label"
117 for="disks"
118 i18n>Images</label>
119 <div class="cd-col-form-input">
120 <ng-container *ngFor="let image of targetForm.getValue('disks'); let i = index">
121 <div class="input-group cd-mb">
122 <input class="cd-form-control"
123 type="text"
124 [value]="image"
125 disabled />
126 <span class="input-group-append">
127 <div class="input-group-text"
128 *ngIf="api_version >= 1">lun: {{ imagesSettings[image]['lun'] }}</div>
129 <button class="btn btn-light"
130 type="button"
131 (click)="imageSettingsModal(image)">
132 <i [ngClass]="[icons.deepCheck]"
133 aria-hidden="true"></i>
134 </button>
135 <button class="btn btn-light"
136 type="button"
137 (click)="removeImage(i, image)">
138 <i [ngClass]="[icons.destroy]"
139 aria-hidden="true"></i>
140 </button>
141 </span>
142
143 </div>
144
145 <span class="form-text text-muted">
146 <ng-container *ngIf="backstores.length > 1"
147 i18n>Backstore: {{ imagesSettings[image].backstore | iscsiBackstore }}.&nbsp;</ng-container>
148
149 <ng-container *ngIf="hasAdvancedSettings(imagesSettings[image][imagesSettings[image].backstore])"
150 i18n>This image has modified settings.</ng-container>
151 </span>
152 </ng-container>
153
154 <input class="form-control"
155 type="hidden"
156 id="disks"
157 name="disks"
158 formControlName="disks" />
159
160 <span class="invalid-feedback"
161 *ngIf="targetForm.showError('disks', formDir, 'dupLunId')"
162 i18n>Duplicated LUN numbers.</span>
163
164 <span class="invalid-feedback"
165 *ngIf="targetForm.showError('disks', formDir, 'dupWwn')"
166 i18n>Duplicated WWN.</span>
167
168 <div class="row">
169 <div class="col-md-12">
170 <cd-select [data]="disks.value"
171 [options]="imagesSelections"
172 [messages]="messages.images"
173 (selection)="onImageSelection($event)"
174 elemClass="btn btn-light float-right">
175 <i [ngClass]="[icons.add]"></i>
176 <ng-container i18n>Add image</ng-container>
177 </cd-select>
178 </div>
179 </div>
180
181 <hr />
182 </div>
183 </div>
184
185 <!-- acl_enabled -->
186 <div class="form-group row">
187 <div class="cd-col-form-offset">
188 <div class="custom-control custom-checkbox">
189 <input type="checkbox"
190 class="custom-control-input"
191 formControlName="acl_enabled"
192 name="acl_enabled"
193 id="acl_enabled">
194 <label for="acl_enabled"
195 class="custom-control-label"
196 i18n>ACL authentication</label>
197 </div>
198
199 <hr />
200 </div>
201 </div>
202
203 <!-- Target level authentication was introduced in ceph-iscsi config v11 -->
204 <div formGroupName="auth"
205 *ngIf="cephIscsiConfigVersion > 10 && !targetForm.getValue('acl_enabled')">
206
207 <!-- Target user -->
208 <div class="form-group row">
209 <label class="cd-col-form-label"
210 for="target_user">
211 <ng-container i18n>User</ng-container>
212 </label>
213 <div class="cd-col-form-input">
214 <input class="form-control"
215 type="text"
216 id="target_user"
217 name="target_user"
218 formControlName="user" />
219
220 <span class="invalid-feedback"
221 *ngIf="targetForm.showError('user', formDir, 'required')"
222 i18n>This field is required.</span>
223
224 <span class="invalid-feedback"
225 *ngIf="targetForm.showError('user', formDir, 'pattern')"
226 i18n>Usernames must have a length of 8 to 64 characters and
227 can only contain letters, '.', '@', '-', '_' or ':'.</span>
228 </div>
229 </div>
230
231 <!-- Target password -->
232 <div class="form-group row">
233 <label class="cd-col-form-label"
234 for="target_password">
235 <ng-container i18n>Password</ng-container>
236 </label>
237 <div class="cd-col-form-input">
238 <div class="input-group">
239 <input class="form-control"
240 type="password"
241 autocomplete="new-password"
242 id="target_password"
243 name="target_password"
244 formControlName="password" />
245 <span class="input-group-append">
246 <button type="button"
247 class="btn btn-light"
248 cdPasswordButton="target_password">
249 </button>
250 <button type="button"
251 class="btn btn-light"
252 cdCopy2ClipboardButton="target_password">
253 </button>
254 </span>
255 </div>
256
257 <span class="invalid-feedback"
258 *ngIf="targetForm.showError('password', formDir, 'required')"
259 i18n>This field is required.</span>
260
261 <span class="invalid-feedback"
262 *ngIf="targetForm.showError('password', formDir, 'pattern')"
263 i18n>Passwords must have a length of 12 to 16 characters
264 and can only contain letters, '@', '-', '_' or '/'.</span>
265 </div>
266 </div>
267
268 <!-- Target mutual_user -->
269 <div class="form-group row">
270 <label class="cd-col-form-label"
271 for="target_mutual_user">
272 <ng-container i18n>Mutual User</ng-container>
273 </label>
274 <div class="cd-col-form-input">
275 <input class="form-control"
276 type="text"
277 id="target_mutual_user"
278 name="target_mutual_user"
279 formControlName="mutual_user" />
280
281 <span class="invalid-feedback"
282 *ngIf="targetForm.showError('mutual_user', formDir, 'required')"
283 i18n>This field is required.</span>
284
285 <span class="invalid-feedback"
286 *ngIf="targetForm.showError('mutual_user', formDir, 'pattern')"
287 i18n>Usernames must have a length of 8 to 64 characters and
288 can only contain letters, '.', '@', '-', '_' or ':'.</span>
289 </div>
290 </div>
291
292 <!-- Target mutual_password -->
293 <div class="form-group row">
294 <label class="cd-col-form-label"
295 for="target_mutual_password">
296 <ng-container i18n>Mutual Password</ng-container>
297 </label>
298 <div class="cd-col-form-input">
299 <div class="input-group">
300 <input class="form-control"
301 type="password"
302 autocomplete="new-password"
303 id="target_mutual_password"
304 name="target_mutual_password"
305 formControlName="mutual_password" />
306
307 <span class="input-group-append">
308 <button type="button"
309 class="btn btn-light"
310 cdPasswordButton="target_mutual_password">
311 </button>
312 <button type="button"
313 class="btn btn-light"
314 cdCopy2ClipboardButton="target_mutual_password">
315 </button>
316 </span>
317 </div>
318
319 <span class="invalid-feedback"
320 *ngIf="targetForm.showError('mutual_password', formDir, 'required')"
321 i18n>This field is required.</span>
322
323 <span class="invalid-feedback"
324 *ngIf="targetForm.showError('mutual_password', formDir, 'pattern')"
325 i18n>Passwords must have a length of 12 to 16 characters
326 and can only contain letters, '@', '-', '_' or '/'.</span>
327 </div>
328 </div>
329
330 </div>
331
332 <!-- Initiators -->
333 <div class="form-group row"
334 *ngIf="targetForm.getValue('acl_enabled')">
335 <label class="cd-col-form-label"
336 for="initiators"
337 i18n>Initiators</label>
338 <div class="cd-col-form-input"
339 formArrayName="initiators">
340 <div class="card mb-2"
341 *ngFor="let initiator of initiators.controls; let ii = index"
342 [formGroupName]="ii">
343 <div class="card-header">
344 <ng-container i18n>Initiator</ng-container>: {{ initiator.getValue('client_iqn') }}
345 <button type="button"
346 class="close"
347 (click)="removeInitiator(ii)">
348 <i [ngClass]="[icons.destroy]"></i>
349 </button>
350 </div>
351 <div class="card-body">
352 <!-- Initiator: Name -->
353 <div class="form-group row">
354 <label class="cd-col-form-label required"
355 for="client_iqn"
356 i18n>Client IQN</label>
357 <div class="cd-col-form-input">
358 <input class="form-control"
359 type="text"
360 formControlName="client_iqn"
361 cdTrim
362 (blur)="updatedInitiatorSelector()">
363
364 <span class="invalid-feedback"
365 *ngIf="initiator.showError('client_iqn', formDir, 'notUnique')"
366 i18n>Initiator IQN needs to be unique.</span>
367
368 <span class="invalid-feedback"
369 *ngIf="initiator.showError('client_iqn', formDir, 'required')"
370 i18n>This field is required.</span>
371
372 <span class="invalid-feedback"
373 *ngIf="initiator.showError('client_iqn', formDir, 'pattern')"
374 i18n>IQN has wrong pattern.</span>
375 </div>
376 </div>
377
378 <ng-container formGroupName="auth">
379 <!-- Initiator: User -->
380 <div class="form-group row">
381 <label class="cd-col-form-label"
382 for="user"
383 i18n>User</label>
384 <div class="cd-col-form-input">
385 <input [id]="'user' + ii"
386 class="form-control"
387 formControlName="user"
388 type="text">
389 <span class="invalid-feedback"
390 *ngIf="initiator.showError('user', formDir, 'required')"
391 i18n>This field is required.</span>
392
393 <span class="invalid-feedback"
394 *ngIf="initiator.showError('user', formDir, 'pattern')"
395 i18n>Usernames must have a length of 8 to 64 characters and
396 can only contain letters, '.', '@', '-', '_' or ':'.</span>
397 </div>
398 </div>
399
400 <!-- Initiator: Password -->
401 <div class="form-group row">
402 <label class="cd-col-form-label"
403 for="password"
404 i18n>Password</label>
405 <div class="cd-col-form-input">
406 <div class="input-group">
407 <input [id]="'password' + ii"
408 class="form-control"
409 formControlName="password"
410 type="password">
411
412 <span class="input-group-append">
413 <button type="button"
414 class="btn btn-light"
415 [cdPasswordButton]="'password' + ii">
416 </button>
417 <button type="button"
418 class="btn btn-light"
419 [cdCopy2ClipboardButton]="'password' + ii">
420 </button>
421 </span>
422 </div>
423 <span class="invalid-feedback"
424 *ngIf="initiator.showError('password', formDir, 'required')"
425 i18n>This field is required.</span>
426
427 <span class="invalid-feedback"
428 *ngIf="initiator.showError('password', formDir, 'pattern')"
429 i18n>Passwords must have a length of 12 to 16 characters
430 and can only contain letters, '@', '-', '_' or '/'.</span>
431 </div>
432 </div>
433
434
435 <!-- Initiator: mutual_user -->
436 <div class="form-group row">
437 <label class="cd-col-form-label"
438 for="mutual_user">
439 <ng-container i18n>Mutual User</ng-container>
440 </label>
441 <div class="cd-col-form-input">
442 <input [id]="'mutual_user' + ii"
443 class="form-control"
444 formControlName="mutual_user"
445 type="text">
446
447 <span class="invalid-feedback"
448 *ngIf="initiator.showError('mutual_user', formDir, 'required')"
449 i18n>This field is required.</span>
450
451 <span class="invalid-feedback"
452 *ngIf="initiator.showError('mutual_user', formDir, 'pattern')"
453 i18n>Usernames must have a length of 8 to 64 characters and
454 can only contain letters, '.', '@', '-', '_' or ':'.</span>
455 </div>
456 </div>
457
458 <!-- Initiator: mutual_password -->
459 <div class="form-group row">
460 <label class="cd-col-form-label"
461 for="mutual_password"
462 i18n>Mutual Password</label>
463 <div class="cd-col-form-input">
464 <div class="input-group">
465 <input [id]="'mutual_password' + ii"
466 class="form-control"
467 formControlName="mutual_password"
468 type="password">
469
470 <span class="input-group-append">
471 <button type="button"
472 class="btn btn-light"
473 [cdPasswordButton]="'mutual_password' + ii">
474 </button>
475 <button type="button"
476 class="btn btn-light"
477 [cdCopy2ClipboardButton]="'mutual_password' + ii">
478 </button>
479 </span>
480 </div>
481 <span class="invalid-feedback"
482 *ngIf="initiator.showError('mutual_password', formDir, 'required')"
483 i18n>This field is required.</span>
484
485 <span class="invalid-feedback"
486 *ngIf="initiator.showError('mutual_password', formDir, 'pattern')"
487 i18n>Passwords must have a length of 12 to 16 characters and
488 can only contain letters, '@', '-', '_' or '/'.</span>
489 </div>
490 </div>
491 </ng-container>
492
493 <!-- Initiator: Images -->
494 <div class="form-group row">
495 <label class="cd-col-form-label"
496 for="luns"
497 i18n>Images</label>
498 <div class="cd-col-form-input">
499 <ng-container *ngFor="let image of initiator.getValue('luns'); let li = index">
500 <div class="input-group cd-mb">
501 <input class="cd-form-control"
502 type="text"
503 [value]="image"
504 disabled />
505 <span class="input-group-append">
506 <button class="btn btn-light"
507 type="button"
508 (click)="removeInitiatorImage(initiator, li, ii, image)">
509 <i [ngClass]="[icons.destroy]"
510 aria-hidden="true"></i>
511 </button>
512 </span>
513 </div>
514 </ng-container>
515
516 <span *ngIf="initiator.getValue('cdIsInGroup')"
517 i18n>Initiator belongs to a group. Images will be configure in the group.</span>
518
519 <div class="row"
520 *ngIf="!initiator.getValue('cdIsInGroup')">
521 <div class="col-md-12">
522 <cd-select [data]="initiator.getValue('luns')"
523 [options]="imagesInitiatorSelections[ii]"
524 [messages]="messages.initiatorImage"
525 elemClass="btn btn-light float-right">
526 <i [ngClass]="[icons.add]"></i>
527 <ng-container i18n>Add image</ng-container>
528 </cd-select>
529 </div>
530 </div>
531 </div>
532 </div>
533 </div>
534 </div>
535
536 <div class="row">
537 <div class="col-md-12">
538 <span class="form-text text-muted"
539 *ngIf="initiators.controls.length === 0"
540 i18n>No items added.</span>
541
542 <button (click)="addInitiator(); false"
543 class="btn btn-light float-right">
544 <i [ngClass]="[icons.add]"></i>
545 <ng-container i18n>Add initiator</ng-container>
546 </button>
547 </div>
548 </div>
549
550 <hr />
551 </div>
552 </div>
553
554 <!-- Groups -->
555 <div class="form-group row"
556 *ngIf="targetForm.getValue('acl_enabled')">
557 <label class="cd-col-form-label"
558 for="initiators"
559 i18n>Groups</label>
560 <div class="cd-col-form-input"
561 formArrayName="groups">
562 <div class="card mb-2"
563 *ngFor="let group of groups.controls; let gi = index"
564 [formGroupName]="gi">
565 <div class="card-header">
566 <ng-container i18n>Group</ng-container>: {{ group.getValue('group_id') }}
567 <button type="button"
568 class="close"
569 (click)="groups.removeAt(gi)">
570 <i [ngClass]="[icons.destroy]"></i>
571 </button>
572 </div>
573 <div class="card-body">
574 <!-- Group: group_id -->
575 <div class="form-group row">
576 <label class="cd-col-form-label required"
577 for="group_id"
578 i18n>Name</label>
579 <div class="cd-col-form-input">
580 <input class="form-control"
581 type="text"
582 formControlName="group_id">
583 </div>
584 </div>
585
586 <!-- Group: members -->
587 <div class="form-group row">
588 <label class="cd-col-form-label"
589 for="members">
590 <ng-container i18n>Initiators</ng-container>
591 </label>
592 <div class="cd-col-form-input">
593 <ng-container *ngFor="let member of group.getValue('members'); let i = index">
594 <div class="input-group cd-mb">
595 <input class="cd-form-control"
596 type="text"
597 [value]="member"
598 disabled />
599 <span class="input-group-append">
600 <button class="btn btn-light"
601 type="button"
602 (click)="removeGroupInitiator(group, i, gi)">
603 <i [ngClass]="[icons.destroy]"
604 aria-hidden="true"></i>
605 </button>
606 </span>
607 </div>
608 </ng-container>
609
610 <div class="row">
611 <div class="col-md-12">
612 <cd-select [data]="group.getValue('members')"
613 [options]="groupMembersSelections[gi]"
614 [messages]="messages.groupInitiator"
615 (selection)="onGroupMemberSelection($event)"
616 elemClass="btn btn-light float-right">
617 <i [ngClass]="[icons.add]"></i>
618 <ng-container i18n>Add initiator</ng-container>
619 </cd-select>
620 </div>
621 </div>
622
623 <hr />
624 </div>
625 </div>
626
627 <!-- Group: disks -->
628 <div class="form-group row">
629 <label class="cd-col-form-label"
630 for="disks">
631 <ng-container i18n>Images</ng-container>
632 </label>
633 <div class="cd-col-form-input">
634 <ng-container *ngFor="let disk of group.getValue('disks'); let i = index">
635 <div class="input-group cd-mb">
636 <input class="cd-form-control"
637 type="text"
638 [value]="disk"
639 disabled />
640 <span class="input-group-append">
641 <button class="btn btn-light"
642 type="button"
643 (click)="removeGroupDisk(group, i, gi)">
644 <i [ngClass]="[icons.destroy]"
645 aria-hidden="true"></i>
646 </button>
647 </span>
648 </div>
649 </ng-container>
650
651 <div class="row">
652 <div class="col-md-12">
653 <cd-select [data]="group.getValue('disks')"
654 [options]="groupDiskSelections[gi]"
655 [messages]="messages.initiatorImage"
656 elemClass="btn btn-light float-right">
657 <i [ngClass]="[icons.add]"></i>
658 <ng-container i18n>Add image</ng-container>
659 </cd-select>
660 </div>
661 </div>
662
663 <hr />
664 </div>
665 </div>
666 </div>
667 </div>
668
669 <div class="row">
670 <div class="col-md-12">
671 <span class="form-text text-muted"
672 *ngIf="groups.controls.length === 0"
673 i18n>No items added.</span>
674
675 <button (click)="addGroup(); false"
676 class="btn btn-light float-right">
677 <i [ngClass]="[icons.add]"></i>
678 <ng-container i18n>Add group</ng-container>
679 </button>
680 </div>
681 </div>
682 </div>
683 </div>
684
685 </div>
686 <div class="card-footer">
687 <div class="button-group text-right">
688 <cd-submit-button (submitAction)="submit()"
689 i18n="form action button|Example: Create Pool@@formActionButton"
690 [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
691 <cd-back-button></cd-back-button>
692 </div>
693 </div>
694 </div>
695 </form>
696 </div>