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