diff options
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.html')
-rw-r--r-- | src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.html | 692 |
1 files changed, 692 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.html new file mode 100644 index 000000000..852866a86 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.html @@ -0,0 +1,692 @@ +<div class="cd-col-form" + *cdFormLoading="loading"> + <form name="targetForm" + #formDir="ngForm" + [formGroup]="targetForm" + novalidate> + <div class="card"> + <div i18n="form title" + class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div> + + <div class="card-body"> + <!-- Target IQN --> + <div class="form-group row"> + <label class="cd-col-form-label required" + for="target_iqn" + i18n>Target IQN</label> + <div class="cd-col-form-input"> + <div class="input-group"> + <input class="form-control" + type="text" + id="target_iqn" + name="target_iqn" + formControlName="target_iqn" + cdTrim /> + <span class="input-group-append"> + <button class="btn btn-light" + id="ecp-info-button" + type="button" + (click)="targetSettingsModal()"> + <i [ngClass]="[icons.deepCheck]" + aria-hidden="true"></i> + </button> + </span> + </div> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('target_iqn', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('target_iqn', formDir, 'pattern')" + i18n>IQN has wrong pattern.</span> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('target_iqn', formDir, 'iqn')"> + <ng-container i18n>An IQN has the following notation + 'iqn.$year-$month.$reversedAddress:$definedName'</ng-container> + <br> + <ng-container i18n>For example: iqn.2016-06.org.dashboard:storage:disk.sn-a8675309</ng-container> + <br> + <a target="_blank" + href="https://en.wikipedia.org/wiki/ISCSI#Addressing" + i18n>More information</a> + </span> + + <span class="form-text text-muted" + *ngIf="hasAdvancedSettings(targetForm.getValue('target_controls'))" + i18n>This target has modified advanced settings.</span> + <hr /> + </div> + </div> + + <!-- Portals --> + <div class="form-group row"> + <label class="cd-col-form-label required" + for="portals" + i18n>Portals</label> + <div class="cd-col-form-input"> + + <ng-container *ngFor="let portal of portals.value; let i = index"> + <div class="input-group cd-mb"> + <input class="cd-form-control" + type="text" + [value]="portal" + disabled /> + <span class="input-group-append"> + <button class="btn btn-light" + type="button" + (click)="removePortal(i, portal)"> + <i [ngClass]="[icons.destroy]" + aria-hidden="true"></i> + </button> + </span> + </div> + </ng-container> + + <div class="row"> + <div class="col-md-12"> + <cd-select [data]="portals.value" + [options]="portalsSelections" + [messages]="messages.portals" + (selection)="onPortalSelection($event)" + elemClass="btn btn-light float-right"> + <i [ngClass]="[icons.add]"></i> + <ng-container i18n>Add portal</ng-container> + </cd-select> + </div> + </div> + + <input class="form-control" + type="hidden" + id="portals" + name="portals" + formControlName="portals" /> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('portals', formDir, 'minGateways')" + i18n>At least {{ minimum_gateways }} gateways are required.</span> + + <hr /> + </div> + </div> + + <!-- Images --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="disks" + i18n>Images</label> + <div class="cd-col-form-input"> + <ng-container *ngFor="let image of targetForm.getValue('disks'); let i = index"> + <div class="input-group cd-mb"> + <input class="cd-form-control" + type="text" + [value]="image" + disabled /> + <span class="input-group-append"> + <div class="input-group-text" + *ngIf="api_version >= 1">lun: {{ imagesSettings[image]['lun'] }}</div> + <button class="btn btn-light" + type="button" + (click)="imageSettingsModal(image)"> + <i [ngClass]="[icons.deepCheck]" + aria-hidden="true"></i> + </button> + <button class="btn btn-light" + type="button" + (click)="removeImage(i, image)"> + <i [ngClass]="[icons.destroy]" + aria-hidden="true"></i> + </button> + </span> + + </div> + + <span class="form-text text-muted"> + <ng-container *ngIf="backstores.length > 1" + i18n>Backstore: {{ imagesSettings[image].backstore | iscsiBackstore }}. </ng-container> + + <ng-container *ngIf="hasAdvancedSettings(imagesSettings[image][imagesSettings[image].backstore])" + i18n>This image has modified settings.</ng-container> + </span> + </ng-container> + + <input class="form-control" + type="hidden" + id="disks" + name="disks" + formControlName="disks" /> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('disks', formDir, 'dupLunId')" + i18n>Duplicated LUN numbers.</span> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('disks', formDir, 'dupWwn')" + i18n>Duplicated WWN.</span> + + <div class="row"> + <div class="col-md-12"> + <cd-select [data]="disks.value" + [options]="imagesSelections" + [messages]="messages.images" + (selection)="onImageSelection($event)" + elemClass="btn btn-light float-right"> + <i [ngClass]="[icons.add]"></i> + <ng-container i18n>Add image</ng-container> + </cd-select> + </div> + </div> + + <hr /> + </div> + </div> + + <!-- acl_enabled --> + <div class="form-group row"> + <div class="cd-col-form-offset"> + <div class="custom-control custom-checkbox"> + <input type="checkbox" + class="custom-control-input" + formControlName="acl_enabled" + name="acl_enabled" + id="acl_enabled"> + <label for="acl_enabled" + class="custom-control-label" + i18n>ACL authentication</label> + </div> + + <hr /> + </div> + </div> + + <!-- Target level authentication was introduced in ceph-iscsi config v11 --> + <div formGroupName="auth" + *ngIf="cephIscsiConfigVersion > 10 && !targetForm.getValue('acl_enabled')"> + + <!-- Target user --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="target_user"> + <ng-container i18n>User</ng-container> + </label> + <div class="cd-col-form-input"> + <input class="form-control" + type="text" + autocomplete="off" + id="target_user" + name="target_user" + formControlName="user" /> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('user', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('user', formDir, 'pattern')" + i18n>User names must have a length of 8 to 64 characters and can contain + alphanumeric characters, '.', '@', '-', '_' or ':'.</span> + </div> + </div> + + <!-- Target password --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="target_password"> + <ng-container i18n>Password</ng-container> + </label> + <div class="cd-col-form-input"> + <div class="input-group"> + <input class="form-control" + type="password" + autocomplete="new-password" + id="target_password" + name="target_password" + formControlName="password" /> + <span class="input-group-append"> + <button type="button" + class="btn btn-light" + cdPasswordButton="target_password"> + </button> + <cd-copy-2-clipboard-button source="target_password"> + </cd-copy-2-clipboard-button> + </span> + </div> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('password', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('password', formDir, 'pattern')" + i18n>Passwords must have a length of 12 to 16 characters and can contain + alphanumeric characters, '@', '-', '_' or '/'.</span> + </div> + </div> + + <!-- Target mutual_user --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="target_mutual_user"> + <ng-container i18n>Mutual User</ng-container> + </label> + <div class="cd-col-form-input"> + <input class="form-control" + type="text" + autocomplete="off" + id="target_mutual_user" + name="target_mutual_user" + formControlName="mutual_user" /> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('mutual_user', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('mutual_user', formDir, 'pattern')" + i18n>User names must have a length of 8 to 64 characters and can contain + alphanumeric characters, '.', '@', '-', '_' or ':'.</span> + </div> + </div> + + <!-- Target mutual_password --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="target_mutual_password"> + <ng-container i18n>Mutual Password</ng-container> + </label> + <div class="cd-col-form-input"> + <div class="input-group"> + <input class="form-control" + type="password" + autocomplete="new-password" + id="target_mutual_password" + name="target_mutual_password" + formControlName="mutual_password" /> + + <span class="input-group-append"> + <button type="button" + class="btn btn-light" + cdPasswordButton="target_mutual_password"> + </button> + <cd-copy-2-clipboard-button source="target_mutual_password"> + </cd-copy-2-clipboard-button> + </span> + </div> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('mutual_password', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="targetForm.showError('mutual_password', formDir, 'pattern')" + i18n>Passwords must have a length of 12 to 16 characters and can contain + alphanumeric characters, '@', '-', '_' or '/'.</span> + </div> + </div> + + </div> + + <!-- Initiators --> + <div class="form-group row" + *ngIf="targetForm.getValue('acl_enabled')"> + <label class="cd-col-form-label" + for="initiators" + i18n>Initiators</label> + <div class="cd-col-form-input" + formArrayName="initiators"> + <div class="card mb-2" + *ngFor="let initiator of initiators.controls; let ii = index" + [formGroup]="initiator"> + <div class="card-header"> + <ng-container i18n>Initiator</ng-container>: {{ initiator.getValue('client_iqn') }} + <button type="button" + class="close" + (click)="removeInitiator(ii)"> + <i [ngClass]="[icons.destroy]"></i> + </button> + </div> + <div class="card-body"> + <!-- Initiator: Name --> + <div class="form-group row"> + <label class="cd-col-form-label required" + for="client_iqn" + i18n>Client IQN</label> + <div class="cd-col-form-input"> + <input class="form-control" + type="text" + formControlName="client_iqn" + cdTrim + (blur)="updatedInitiatorSelector()"> + + <span class="invalid-feedback" + *ngIf="initiator.showError('client_iqn', formDir, 'notUnique')" + i18n>Initiator IQN needs to be unique.</span> + + <span class="invalid-feedback" + *ngIf="initiator.showError('client_iqn', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="initiator.showError('client_iqn', formDir, 'pattern')" + i18n>IQN has wrong pattern.</span> + </div> + </div> + + <ng-container formGroupName="auth"> + <!-- Initiator: User --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="user" + i18n>User</label> + <div class="cd-col-form-input"> + <input [id]="'user' + ii" + class="form-control" + formControlName="user" + autocomplete="off" + type="text"> + <span class="invalid-feedback" + *ngIf="initiator.showError('user', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="initiator.showError('user', formDir, 'pattern')" + i18n>User names must have a length of 8 to 64 characters and can contain + alphanumeric characters, '.', '@', '-', '_' or ':'.</span> + </div> + </div> + + <!-- Initiator: Password --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="password" + i18n>Password</label> + <div class="cd-col-form-input"> + <div class="input-group"> + <input [id]="'password' + ii" + class="form-control" + formControlName="password" + autocomplete="new-password" + type="password"> + + <span class="input-group-append"> + <button type="button" + class="btn btn-light" + [cdPasswordButton]="'password' + ii"> + </button> + <cd-copy-2-clipboard-button [source]="'password' + ii"> + </cd-copy-2-clipboard-button> + </span> + </div> + <span class="invalid-feedback" + *ngIf="initiator.showError('password', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="initiator.showError('password', formDir, 'pattern')" + i18n>Passwords must have a length of 12 to 16 characters and can contain + alphanumeric characters, '@', '-', '_' or '/'.</span> + </div> + </div> + + + <!-- Initiator: mutual_user --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="mutual_user"> + <ng-container i18n>Mutual User</ng-container> + </label> + <div class="cd-col-form-input"> + <input [id]="'mutual_user' + ii" + class="form-control" + formControlName="mutual_user" + autocomplete="off" + type="text"> + + <span class="invalid-feedback" + *ngIf="initiator.showError('mutual_user', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="initiator.showError('mutual_user', formDir, 'pattern')" + i18n>User names must have a length of 8 to 64 characters and can contain + alphanumeric characters, '.', '@', '-', '_' or ':'.</span> + </div> + </div> + + <!-- Initiator: mutual_password --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="mutual_password" + i18n>Mutual Password</label> + <div class="cd-col-form-input"> + <div class="input-group"> + <input [id]="'mutual_password' + ii" + class="form-control" + formControlName="mutual_password" + autocomplete="new-password" + type="password"> + + <span class="input-group-append"> + <button type="button" + class="btn btn-light" + [cdPasswordButton]="'mutual_password' + ii"> + </button> + <cd-copy-2-clipboard-button [source]="'mutual_password' + ii"> + </cd-copy-2-clipboard-button> + </span> + </div> + <span class="invalid-feedback" + *ngIf="initiator.showError('mutual_password', formDir, 'required')" + i18n>This field is required.</span> + + <span class="invalid-feedback" + *ngIf="initiator.showError('mutual_password', formDir, 'pattern')" + i18n>Passwords must have a length of 12 to 16 characters and can contain + alphanumeric characters, '@', '-', '_' or '/'.</span> + </div> + </div> + </ng-container> + + <!-- Initiator: Images --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="luns" + i18n>Images</label> + <div class="cd-col-form-input"> + <ng-container *ngFor="let image of initiator.getValue('luns'); let li = index"> + <div class="input-group cd-mb"> + <input class="cd-form-control" + type="text" + [value]="image" + disabled /> + <span class="input-group-append"> + <button class="btn btn-light" + type="button" + (click)="removeInitiatorImage(initiator, li, ii, image)"> + <i [ngClass]="[icons.destroy]" + aria-hidden="true"></i> + </button> + </span> + </div> + </ng-container> + + <span *ngIf="initiator.getValue('cdIsInGroup')" + i18n>Initiator belongs to a group. Images will be configure in the group.</span> + + <div class="row" + *ngIf="!initiator.getValue('cdIsInGroup')"> + <div class="col-md-12"> + <cd-select [data]="initiator.getValue('luns')" + [options]="imagesInitiatorSelections[ii]" + [messages]="messages.initiatorImage" + elemClass="btn btn-light float-right"> + <i [ngClass]="[icons.add]"></i> + <ng-container i18n>Add image</ng-container> + </cd-select> + </div> + </div> + </div> + </div> + </div> + </div> + + <div class="row"> + <div class="col-md-12"> + <span class="form-text text-muted" + *ngIf="initiators.controls.length === 0" + i18n>No items added.</span> + + <button (click)="addInitiator(); false" + class="btn btn-light float-right"> + <i [ngClass]="[icons.add]"></i> + <ng-container i18n>Add initiator</ng-container> + </button> + </div> + </div> + + <hr /> + </div> + </div> + + <!-- Groups --> + <div class="form-group row" + *ngIf="targetForm.getValue('acl_enabled')"> + <label class="cd-col-form-label" + for="initiators" + i18n>Groups</label> + <div class="cd-col-form-input" + formArrayName="groups"> + <div class="card mb-2" + *ngFor="let group of groups.controls; let gi = index" + [formGroup]="group"> + <div class="card-header"> + <ng-container i18n>Group</ng-container>: {{ group.getValue('group_id') }} + <button type="button" + class="close" + (click)="removeGroup(gi)"> + <i [ngClass]="[icons.destroy]"></i> + </button> + </div> + <div class="card-body"> + <!-- Group: group_id --> + <div class="form-group row"> + <label class="cd-col-form-label required" + for="group_id" + i18n>Name</label> + <div class="cd-col-form-input"> + <input class="form-control" + type="text" + formControlName="group_id"> + </div> + </div> + + <!-- Group: members --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="members"> + <ng-container i18n>Initiators</ng-container> + </label> + <div class="cd-col-form-input"> + <ng-container *ngFor="let member of group.getValue('members'); let i = index"> + <div class="input-group cd-mb"> + <input class="cd-form-control" + type="text" + [value]="member" + disabled /> + <span class="input-group-append"> + <button class="btn btn-light" + type="button" + (click)="removeGroupInitiator(group, i, gi)"> + <i [ngClass]="[icons.destroy]" + aria-hidden="true"></i> + </button> + </span> + </div> + </ng-container> + + <div class="row"> + <div class="col-md-12"> + <cd-select [data]="group.getValue('members')" + [options]="groupMembersSelections[gi]" + [messages]="messages.groupInitiator" + (selection)="onGroupMemberSelection($event, gi)" + elemClass="btn btn-light float-right"> + <i [ngClass]="[icons.add]"></i> + <ng-container i18n>Add initiator</ng-container> + </cd-select> + </div> + </div> + + <hr /> + </div> + </div> + + <!-- Group: disks --> + <div class="form-group row"> + <label class="cd-col-form-label" + for="disks"> + <ng-container i18n>Images</ng-container> + </label> + <div class="cd-col-form-input"> + <ng-container *ngFor="let disk of group.getValue('disks'); let i = index"> + <div class="input-group cd-mb"> + <input class="cd-form-control" + type="text" + [value]="disk" + disabled /> + <span class="input-group-append"> + <button class="btn btn-light" + type="button" + (click)="removeGroupDisk(group, i, gi)"> + <i [ngClass]="[icons.destroy]" + aria-hidden="true"></i> + </button> + </span> + </div> + </ng-container> + + <div class="row"> + <div class="col-md-12"> + <cd-select [data]="group.getValue('disks')" + [options]="groupDiskSelections[gi]" + [messages]="messages.initiatorImage" + elemClass="btn btn-light float-right"> + <i [ngClass]="[icons.add]"></i> + <ng-container i18n>Add image</ng-container> + </cd-select> + </div> + </div> + + <hr /> + </div> + </div> + </div> + </div> + + <div class="row"> + <div class="col-md-12"> + <span class="form-text text-muted" + *ngIf="groups.controls.length === 0" + i18n>No items added.</span> + + <button (click)="addGroup(); false" + class="btn btn-light float-right"> + <i [ngClass]="[icons.add]"></i> + <ng-container i18n>Add group</ng-container> + </button> + </div> + </div> + </div> + </div> + + </div> + <div class="card-footer"> + <cd-form-button-panel (submitActionEvent)="submit()" + [form]="targetForm" + [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)" + wrappingClass="text-right"></cd-form-button-panel> + </div> + </div> + </form> +</div> |