]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Add iSCSI discovery authentication UI 26320/head
authorTiago Melo <tmelo@suse.com>
Tue, 5 Feb 2019 12:01:05 +0000 (12:01 +0000)
committerTiago Melo <tmelo@suse.com>
Tue, 12 Feb 2019 09:29:07 +0000 (09:29 +0000)
Fixes: https://tracker.ceph.com/issues/38021
Signed-off-by: Tiago Melo <tmelo@suse.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/block.module.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/iscsi.service.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/iscsi.service.ts
src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf

index d5bbbb9cc036e4055b46e344f94d41c409e20bf5..b21930172a7f3ffd8976e214b430fe30a0752d33 100644 (file)
@@ -14,6 +14,7 @@ import { TooltipModule } from 'ngx-bootstrap/tooltip';
 import { SharedModule } from '../../shared/shared.module';
 import { IscsiTabsComponent } from './iscsi-tabs/iscsi-tabs.component';
 import { IscsiTargetDetailsComponent } from './iscsi-target-details/iscsi-target-details.component';
+import { IscsiTargetDiscoveryModalComponent } from './iscsi-target-discovery-modal/iscsi-target-discovery-modal.component';
 import { IscsiTargetFormComponent } from './iscsi-target-form/iscsi-target-form.component';
 import { IscsiTargetImageSettingsModalComponent } from './iscsi-target-image-settings-modal/iscsi-target-image-settings-modal.component';
 import { IscsiTargetIqnSettingsModalComponent } from './iscsi-target-iqn-settings-modal/iscsi-target-iqn-settings-modal.component';
@@ -40,7 +41,8 @@ import { RbdTrashRestoreModalComponent } from './rbd-trash-restore-modal/rbd-tra
     RbdTrashPurgeModalComponent,
     IscsiTargetDetailsComponent,
     IscsiTargetImageSettingsModalComponent,
-    IscsiTargetIqnSettingsModalComponent
+    IscsiTargetIqnSettingsModalComponent,
+    IscsiTargetDiscoveryModalComponent
   ],
   imports: [
     CommonModule,
@@ -74,7 +76,8 @@ import { RbdTrashRestoreModalComponent } from './rbd-trash-restore-modal/rbd-tra
     IscsiTargetDetailsComponent,
     IscsiTargetFormComponent,
     IscsiTargetImageSettingsModalComponent,
-    IscsiTargetIqnSettingsModalComponent
+    IscsiTargetIqnSettingsModalComponent,
+    IscsiTargetDiscoveryModalComponent
   ]
 })
 export class BlockModule {}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html
new file mode 100644 (file)
index 0000000..4a18220
--- /dev/null
@@ -0,0 +1,142 @@
+<cd-modal [modalRef]="bsModalRef">
+  <ng-container class="modal-title"
+                i18n>Discovery Authentication</ng-container>
+
+  <ng-container class="modal-content">
+    <form name="discoveryForm"
+          class="form-horizontal"
+          #formDir="ngForm"
+          [formGroup]="discoveryForm"
+          novalidate>
+      <div class="modal-body">
+        <!-- User -->
+        <div class="form-group"
+             [ngClass]="{'has-error': discoveryForm.showError('user', formDir)}">
+          <label class="control-label col-sm-4"
+                 for="user"
+                 i18n>User</label>
+          <div class="col-sm-8">
+            <input id="user"
+                   class="form-control"
+                   formControlName="user"
+                   type="text">
+            <span class="help-block"
+                  *ngIf="discoveryForm.showError('user', formDir, 'required')"
+                  i18n>This field is required.</span>
+
+            <span class="help-block"
+                  *ngIf="discoveryForm.showError('user', formDir, 'pattern')"
+                  i18n>Usernames must have a length of 8 to 64 characters and
+              can only contain letters, '.', '@', '-', '_' or ':'.</span>
+          </div>
+        </div>
+
+        <!-- Password -->
+        <div class="form-group"
+             [ngClass]="{'has-error': discoveryForm.showError('password', formDir)}">
+          <label class="control-label col-sm-4"
+                 for="password"
+                 i18n>Password</label>
+          <div class="col-sm-8">
+            <div class="input-group">
+              <input id="password"
+                     class="form-control"
+                     formControlName="password"
+                     type="password">
+
+              <span class="input-group-btn">
+                <button type="button"
+                        class="btn btn-default"
+                        cdPasswordButton="password">
+                </button>
+                <button type="button"
+                        class="btn btn-default"
+                        cdCopy2ClipboardButton="password">
+                </button>
+              </span>
+            </div>
+            <span class="help-block"
+                  *ngIf="discoveryForm.showError('password', formDir, 'required')"
+                  i18n>This field is required.</span>
+
+            <span class="help-block"
+                  *ngIf="discoveryForm.showError('password', formDir, 'pattern')"
+                  i18n>Passwords must have a length of 12 to 16 characters
+              and can only contain letters, '@', '-' or '_'.</span>
+          </div>
+        </div>
+
+        <!-- mutual_user -->
+        <div class="form-group"
+             [ngClass]="{'has-error': discoveryForm.showError('mutual_user', formDir)}">
+          <label class="control-label col-sm-4"
+                 for="mutual_user">
+            <ng-container i18n>Mutual User</ng-container>
+          </label>
+          <div class="col-sm-8">
+            <input id="mutual_user"
+                   class="form-control"
+                   formControlName="mutual_user"
+                   type="text">
+
+            <span class="help-block"
+                  *ngIf="discoveryForm.showError('mutual_user', formDir, 'required')"
+                  i18n>This field is required.</span>
+
+            <span class="help-block"
+                  *ngIf="discoveryForm.showError('mutual_user', formDir, 'pattern')"
+                  i18n>Usernames must have a length of 8 to 64 characters and
+              can only contain letters, '.', '@', '-', '_' or ':'.</span>
+          </div>
+        </div>
+
+        <!-- mutual_password -->
+        <div class="form-group"
+             [ngClass]="{'has-error': discoveryForm.showError('mutual_password', formDir)}">
+          <label class="control-label col-sm-4"
+                 for="mutual_password"
+                 i18n>Mutual Password</label>
+          <div class="col-sm-8">
+            <div class="input-group">
+              <input id="mutual_password"
+                     class="form-control"
+                     formControlName="mutual_password"
+                     type="mutual_password">
+
+              <span class="input-group-btn">
+                <button type="button"
+                        class="btn btn-default"
+                        cdPasswordButton="mutual_password">
+                </button>
+                <button type="button"
+                        class="btn btn-default"
+                        cdCopy2ClipboardButton="mutual_password">
+                </button>
+              </span>
+            </div>
+            <span class="help-block"
+                  *ngIf="discoveryForm.showError('mutual_password', formDir, 'required')"
+                  i18n>This field is required.</span>
+
+            <span class="help-block"
+                  *ngIf="discoveryForm.showError('mutual_password', formDir, 'pattern')"
+                  i18n>Passwords must have a length of 12 to 16 characters and
+              can only contain letters, '@', '-' or '_'.</span>
+          </div>
+        </div>
+      </div>
+
+      <div class="modal-footer">
+        <div class="button-group text-right">
+          <cd-submit-button (submitAction)="submitAction()"
+                            [form]="discoveryForm"
+                            i18n>Submit</cd-submit-button>
+
+          <button class="btn btn-link btn-sm"
+                  (click)="bsModalRef.hide()"
+                  i18n>Cancel</button>
+        </div>
+      </div>
+    </form>
+  </ng-container>
+</cd-modal>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.scss
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.spec.ts
new file mode 100644 (file)
index 0000000..5b8b560
--- /dev/null
@@ -0,0 +1,82 @@
+import {
+  HttpClientTestingModule,
+  HttpTestingController,
+  TestRequest
+} from '@angular/common/http/testing';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+
+import { ToastModule } from 'ng2-toastr';
+import { BsModalRef } from 'ngx-bootstrap/modal';
+
+import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
+import { SharedModule } from '../../../shared/shared.module';
+import { IscsiTargetDiscoveryModalComponent } from './iscsi-target-discovery-modal.component';
+
+describe('IscsiTargetDiscoveryModalComponent', () => {
+  let component: IscsiTargetDiscoveryModalComponent;
+  let fixture: ComponentFixture<IscsiTargetDiscoveryModalComponent>;
+  let httpTesting: HttpTestingController;
+  let req: TestRequest;
+
+  configureTestBed({
+    declarations: [IscsiTargetDiscoveryModalComponent],
+    imports: [HttpClientTestingModule, ReactiveFormsModule, SharedModule, ToastModule.forRoot()],
+    providers: [i18nProviders, BsModalRef]
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(IscsiTargetDiscoveryModalComponent);
+    component = fixture.componentInstance;
+    httpTesting = TestBed.get(HttpTestingController);
+    fixture.detectChanges();
+    req = httpTesting.expectOne('api/iscsi/discoveryauth');
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  it('should create form', () => {
+    expect(component.discoveryForm.value).toEqual({
+      user: '',
+      password: '',
+      mutual_user: '',
+      mutual_password: ''
+    });
+  });
+
+  it('should patch form', () => {
+    req.flush({
+      user: 'foo',
+      password: 'bar',
+      mutual_user: 'mutual_foo',
+      mutual_password: 'mutual_bar'
+    });
+    expect(component.discoveryForm.value).toEqual({
+      user: 'foo',
+      password: 'bar',
+      mutual_user: 'mutual_foo',
+      mutual_password: 'mutual_bar'
+    });
+  });
+
+  it('should submit new values', () => {
+    component.discoveryForm.patchValue({
+      user: 'new_user',
+      password: 'new_pass',
+      mutual_user: 'mutual_new_user',
+      mutual_password: 'mutual_new_pass'
+    });
+    component.submitAction();
+
+    const submit_req = httpTesting.expectOne('api/iscsi/discoveryauth');
+    expect(submit_req.request.method).toBe('PUT');
+    expect(submit_req.request.body).toEqual({
+      user: 'new_user',
+      password: 'new_pass',
+      mutual_user: 'mutual_new_user',
+      mutual_password: 'mutual_new_pass'
+    });
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.ts
new file mode 100644 (file)
index 0000000..27b9e18
--- /dev/null
@@ -0,0 +1,113 @@
+import { Component, OnInit } from '@angular/core';
+import { FormControl, Validators } from '@angular/forms';
+
+import { I18n } from '@ngx-translate/i18n-polyfill';
+import { BsModalRef } from 'ngx-bootstrap/modal';
+
+import { IscsiService } from '../../../shared/api/iscsi.service';
+import { NotificationType } from '../../../shared/enum/notification-type.enum';
+import { CdFormGroup } from '../../../shared/forms/cd-form-group';
+import { CdValidators } from '../../../shared/forms/cd-validators';
+import { NotificationService } from '../../../shared/services/notification.service';
+
+@Component({
+  selector: 'cd-iscsi-target-discovery-modal',
+  templateUrl: './iscsi-target-discovery-modal.component.html',
+  styleUrls: ['./iscsi-target-discovery-modal.component.scss']
+})
+export class IscsiTargetDiscoveryModalComponent implements OnInit {
+  discoveryForm: CdFormGroup;
+
+  USER_REGEX = /[\w\.:@_-]{8,64}/;
+  PASSWORD_REGEX = /[\w@\-_]{12,16}/;
+
+  constructor(
+    public bsModalRef: BsModalRef,
+    private iscsiService: IscsiService,
+    private notificationService: NotificationService,
+    private i18n: I18n
+  ) {
+    this.discoveryForm = new CdFormGroup({
+      user: new FormControl(''),
+      password: new FormControl(''),
+      mutual_user: new FormControl(''),
+      mutual_password: new FormControl('')
+    });
+
+    CdValidators.validateIf(
+      this.discoveryForm.get('user'),
+      () =>
+        this.discoveryForm.getValue('password') ||
+        this.discoveryForm.getValue('mutual_user') ||
+        this.discoveryForm.getValue('mutual_password'),
+      [Validators.required],
+      [Validators.pattern(this.USER_REGEX)],
+      [
+        this.discoveryForm.get('password'),
+        this.discoveryForm.get('mutual_user'),
+        this.discoveryForm.get('mutual_password')
+      ]
+    );
+
+    CdValidators.validateIf(
+      this.discoveryForm.get('password'),
+      () =>
+        this.discoveryForm.getValue('user') ||
+        this.discoveryForm.getValue('mutual_user') ||
+        this.discoveryForm.getValue('mutual_password'),
+      [Validators.required],
+      [Validators.pattern(this.PASSWORD_REGEX)],
+      [
+        this.discoveryForm.get('user'),
+        this.discoveryForm.get('mutual_user'),
+        this.discoveryForm.get('mutual_password')
+      ]
+    );
+
+    CdValidators.validateIf(
+      this.discoveryForm.get('mutual_user'),
+      () => this.discoveryForm.getValue('mutual_password'),
+      [Validators.required],
+      [Validators.pattern(this.USER_REGEX)],
+      [
+        this.discoveryForm.get('user'),
+        this.discoveryForm.get('password'),
+        this.discoveryForm.get('mutual_password')
+      ]
+    );
+
+    CdValidators.validateIf(
+      this.discoveryForm.get('mutual_password'),
+      () => this.discoveryForm.getValue('mutual_user'),
+      [Validators.required],
+      [Validators.pattern(this.PASSWORD_REGEX)],
+      [
+        this.discoveryForm.get('user'),
+        this.discoveryForm.get('password'),
+        this.discoveryForm.get('mutual_user')
+      ]
+    );
+  }
+
+  ngOnInit() {
+    this.iscsiService.getDiscovery().subscribe((auth) => {
+      this.discoveryForm.patchValue(auth);
+    });
+  }
+
+  submitAction() {
+    this.iscsiService.updateDiscovery(this.discoveryForm.value).subscribe(
+      () => {
+        this.notificationService.show(
+          NotificationType.success,
+          this.i18n('Discovery authentication was updated.'),
+          this.i18n('Discovery authentication')
+        );
+        this.bsModalRef.hide();
+      },
+      () => {
+        this.bsModalRef.hide();
+      }
+    );
+  }
+}
index 33edc9660ac667d8113ae515d139ba824bee5f6f..aef54596c5f02705fad7887bcf7a47618adba5b6 100644 (file)
                       [selection]="selection"
                       [tableActions]="tableActions">
     </cd-table-actions>
+
+    <button class="btn btn-sm btn-default btn-label"
+            type="button"
+            (click)="configureDiscoveryAuth()">
+      <i class="fa fa-fw fa-key-modern"
+         aria-hidden="true">
+      </i>
+      <ng-container i18n>Set discovery authentication</ng-container>
+    </button>
   </div>
 
   <cd-iscsi-target-details cdTableDetail
index 6024274f6e374f2344184259517c7c899d62f0a7..f5150d12b90f169164b1a16f7d5b616db91e2b83 100644 (file)
@@ -18,6 +18,7 @@ import { AuthStorageService } from '../../../shared/services/auth-storage.servic
 import { SummaryService } from '../../../shared/services/summary.service';
 import { TaskListService } from '../../../shared/services/task-list.service';
 import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
+import { IscsiTargetDiscoveryModalComponent } from '../iscsi-target-discovery-modal/iscsi-target-discovery-modal.component';
 
 @Component({
   selector: 'cd-iscsi-target-list',
@@ -170,4 +171,8 @@ export class IscsiTargetListComponent implements OnInit, OnDestroy {
       }
     });
   }
+
+  configureDiscoveryAuth() {
+    this.modalService.show(IscsiTargetDiscoveryModalComponent, {});
+  }
 }
index 8554914c891b97bbc2e519000b7897e6ece6cb54..fee52375eda7feb5b64d4b52413b180aacab68be 100644 (file)
@@ -62,4 +62,23 @@ describe('IscsiService', () => {
     const req = httpTesting.expectOne('api/iscsi/target/target_iqn');
     expect(req.request.method).toBe('DELETE');
   });
+
+  it('should call getDiscovery', () => {
+    service.getDiscovery().subscribe();
+    const req = httpTesting.expectOne('api/iscsi/discoveryauth');
+    expect(req.request.method).toBe('GET');
+  });
+
+  it('should call updateDiscovery', () => {
+    service
+      .updateDiscovery({
+        user: 'foo',
+        password: 'bar',
+        mutual_user: 'mutual_foo',
+        mutual_password: 'mutual_bar'
+      })
+      .subscribe();
+    const req = httpTesting.expectOne('api/iscsi/discoveryauth');
+    expect(req.request.method).toBe('PUT');
+  });
 });
index 8bdb1a61fd99bf4ed345c092a98b15a0c8af5a10..014987283078809e2f0ee2627cb75c720e540bcb 100644 (file)
@@ -83,4 +83,12 @@ export class IscsiService {
   deleteTarget(targetIqn) {
     return this.http.delete(`api/iscsi/target/${targetIqn}`, { observe: 'response' });
   }
+
+  getDiscovery() {
+    return this.http.get(`api/iscsi/discoveryauth`);
+  }
+
+  updateDiscovery(auth) {
+    return this.http.put(`api/iscsi/discoveryauth`, auth);
+  }
 }
index c3c1ad3115d87d5477dad70fa6ff0c6e1ae4b620..3c79928e592f304d17a689fe54022a29436e9d9b 100644 (file)
           <context context-type="sourcefile">app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component.html</context>
           <context context-type="linenumber">38</context>
         </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">137</context>
+        </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">app/shared/components/confirmation-modal/confirmation-modal.component.html</context>
           <context context-type="linenumber">21</context>
           <context context-type="sourcefile">app/ceph/block/iscsi-target-form/iscsi-target-form.component.html</context>
           <context context-type="linenumber">326</context>
         </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">25</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">60</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">84</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">119</context>
+        </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">app/ceph/block/rbd-form/rbd-form.component.html</context>
           <context context-type="linenumber">49</context>
           <context context-type="sourcefile">app/ceph/block/iscsi-target-form/iscsi-target-form.component.html</context>
           <context context-type="linenumber">223</context>
         </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
       </trans-unit><trans-unit id="bbf0b34a3fcc80800fcb44b9e1e86931a530dfe3" datatype="html">
         <source>Usernames must have a length of 8 to 64 characters and
                         can only contain letters, &apos;.&apos;, &apos;@&apos;, &apos;-&apos;, &apos;_&apos; or &apos;:&apos;.</source>
           <context context-type="sourcefile">app/ceph/block/iscsi-target-form/iscsi-target-form.component.html</context>
           <context context-type="linenumber">245</context>
         </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">39</context>
+        </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">app/core/auth/user-form/user-form.component.html</context>
           <context context-type="linenumber">42</context>
           <context context-type="sourcefile">app/ceph/block/iscsi-target-form/iscsi-target-form.component.html</context>
           <context context-type="linenumber">281</context>
         </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">74</context>
+        </context-group>
       </trans-unit><trans-unit id="0cf73dbebe99b737c4d288788182fc356e3c93d3" datatype="html">
         <source>Mutual Password</source>
         <context-group purpose="location">
           <context context-type="sourcefile">app/ceph/block/iscsi-target-form/iscsi-target-form.component.html</context>
           <context context-type="linenumber">305</context>
         </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">98</context>
+        </context-group>
       </trans-unit><trans-unit id="c58e136a292acf8ebccfa6d777fdff9f392b6ee2" datatype="html">
         <source>Passwords must have a length of 12 to 16 characters and
                         can only contain letters, &apos;@&apos;, &apos;-&apos; or &apos;_&apos;.</source>
           <context context-type="sourcefile">app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component.html</context>
           <context context-type="linenumber">25</context>
         </context-group>
+      </trans-unit><trans-unit id="6803e31b7395d94934e091a49a9524026b59b018" datatype="html">
+        <source>Discovery Authentication</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">3</context>
+        </context-group>
+      </trans-unit><trans-unit id="0214f773f8e394f50f953f39962e352d7863e959" datatype="html">
+        <source>Usernames must have a length of 8 to 64 characters and
+              can only contain letters, &apos;.&apos;, &apos;@&apos;, &apos;-&apos;, &apos;_&apos; or &apos;:&apos;.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">29</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">88</context>
+        </context-group>
+      </trans-unit><trans-unit id="fcbd385c9738f3c376e7f0935c9ac1ae6f863476" datatype="html">
+        <source>Passwords must have a length of 12 to 16 characters
+              and can only contain letters, &apos;@&apos;, &apos;-&apos; or &apos;_&apos;.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">64</context>
+        </context-group>
+      </trans-unit><trans-unit id="fd0c0472536d61ac9f5bc62d5f9ed01673cf3603" datatype="html">
+        <source>Passwords must have a length of 12 to 16 characters and
+              can only contain letters, &apos;@&apos;, &apos;-&apos; or &apos;_&apos;.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">123</context>
+        </context-group>
+      </trans-unit><trans-unit id="71c77bb8cecdf11ec3eead24dd1ba506573fa9cd" datatype="html">
+        <source>Submit</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html</context>
+          <context context-type="linenumber">133</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.html</context>
+          <context context-type="linenumber">34</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/cluster/osd/osd-recv-speed-modal/osd-recv-speed-modal.component.html</context>
+          <context context-type="linenumber">87</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.html</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/mirroring/pool-edit-peer-modal/pool-edit-peer-modal.component.html</context>
+          <context context-type="linenumber">106</context>
+        </context-group>
       </trans-unit><trans-unit id="53a583cd5f15059cc958b7d547f72cc78f68e123" datatype="html">
         <source>Please consult the <x id="START_LINK" ctype="x-a" equiv-text="&lt;a&gt;"/>documentation<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>
     on how to configure and enable the iSCSI Targets management functionality.</source>
           <context context-type="sourcefile">app/ceph/block/iscsi-target-list/iscsi-target-list.component.html</context>
           <context context-type="linenumber">4</context>
         </context-group>
+      </trans-unit><trans-unit id="8f4c079a38df7c3b64a4dfe8daa4d02aeffefbfa" datatype="html">
+        <source>Set discovery authentication</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/ceph/block/iscsi-target-list/iscsi-target-list.component.html</context>
+          <context context-type="linenumber">39</context>
+        </context-group>
       </trans-unit><trans-unit id="beb1391a148bd032914f49a2665dcc414a5d56d0" datatype="html">
         <source>{VAR_SELECT, select, editing {Edit} cloning {Clone} copying {Copy} other {Add} }</source>
         <context-group purpose="location">
           <context context-type="sourcefile">app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.html</context>
           <context context-type="linenumber">3</context>
         </context-group>
-      </trans-unit><trans-unit id="71c77bb8cecdf11ec3eead24dd1ba506573fa9cd" datatype="html">
-        <source>Submit</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.html</context>
-          <context context-type="linenumber">34</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">app/ceph/cluster/osd/osd-recv-speed-modal/osd-recv-speed-modal.component.html</context>
-          <context context-type="linenumber">87</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.html</context>
-          <context context-type="linenumber">21</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">app/ceph/block/mirroring/pool-edit-peer-modal/pool-edit-peer-modal.component.html</context>
-          <context context-type="linenumber">106</context>
-        </context-group>
       </trans-unit><trans-unit id="c35f9c5f268a514b970cc55e9a5dc4bed0988e7f" datatype="html">
         <source>OSD Recovery Priority</source>
         <context-group purpose="location">
           <context context-type="linenumber">1</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="bfd67d01ffc87759d7f29ecb67e64ec6c1672fdd" datatype="html">
+        <source>Discovery authentication was updated.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="8414a5cb9d71cc1b21b10e4a9d1f2dad558f3361" datatype="html">
+        <source>Discovery authentication</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="dd4ab758afd5fd5a6c6a25b2b30ff99d0c00e9ad" datatype="html">
         <source>There are no portals available.</source>
         <context-group purpose="location">