From 8b27f0b74b1b5da8594c7f75792b775254e78043 Mon Sep 17 00:00:00 2001 From: Tiago Melo Date: Tue, 5 Feb 2019 12:01:05 +0000 Subject: [PATCH] mgr/dashboard: Add iSCSI discovery authentication UI Fixes: https://tracker.ceph.com/issues/38021 Signed-off-by: Tiago Melo --- .../src/app/ceph/block/block.module.ts | 7 +- ...scsi-target-discovery-modal.component.html | 142 ++++++++++++++++++ ...scsi-target-discovery-modal.component.scss | 0 ...i-target-discovery-modal.component.spec.ts | 82 ++++++++++ .../iscsi-target-discovery-modal.component.ts | 113 ++++++++++++++ .../iscsi-target-list.component.html | 9 ++ .../iscsi-target-list.component.ts | 5 + .../src/app/shared/api/iscsi.service.spec.ts | 19 +++ .../src/app/shared/api/iscsi.service.ts | 8 + .../frontend/src/locale/messages.xlf | 127 +++++++++++++--- 10 files changed, 492 insertions(+), 20 deletions(-) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.scss create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.ts diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/block.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/block.module.ts index d5bbbb9cc036e..b21930172a7f3 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/block.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/block.module.ts @@ -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 index 0000000000000..4a18220c66c5f --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html @@ -0,0 +1,142 @@ + + Discovery Authentication + + +
+ + + +
+
+
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 index 0000000000000..e69de29bb2d1d 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 index 0000000000000..5b8b5602e8e73 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.spec.ts @@ -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; + 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 index 0000000000000..27b9e186b2a72 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.ts @@ -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(); + } + ); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html index 33edc9660ac66..aef54596c5f02 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html @@ -29,6 +29,15 @@ [selection]="selection" [tableActions]="tableActions"> + + { 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'); + }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/iscsi.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/iscsi.service.ts index 8bdb1a61fd99b..0149872830788 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/iscsi.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/iscsi.service.ts @@ -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); + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf b/src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf index c3c1ad3115d87..3c79928e592f3 100644 --- a/src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf +++ b/src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf @@ -349,6 +349,10 @@ app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component.html 38 + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 137 + app/shared/components/confirmation-modal/confirmation-modal.component.html 21 @@ -437,6 +441,22 @@ app/ceph/block/iscsi-target-form/iscsi-target-form.component.html 326 + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 25 + + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 60 + + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 84 + + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 119 + app/ceph/block/rbd-form/rbd-form.component.html 49 @@ -681,6 +701,10 @@ app/ceph/block/iscsi-target-form/iscsi-target-form.component.html 223 + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 17 + Usernames must have a length of 8 to 64 characters and can only contain letters, '.', '@', '-', '_' or ':'. @@ -698,6 +722,10 @@ app/ceph/block/iscsi-target-form/iscsi-target-form.component.html 245 + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 39 + app/core/auth/user-form/user-form.component.html 42 @@ -715,12 +743,20 @@ app/ceph/block/iscsi-target-form/iscsi-target-form.component.html 281 + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 74 + Mutual Password app/ceph/block/iscsi-target-form/iscsi-target-form.component.html 305 + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 98 + Passwords must have a length of 12 to 16 characters and can only contain letters, '@', '-' or '_'. @@ -830,6 +866,59 @@ app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component.html 25 + + Discovery Authentication + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 3 + + + Usernames must have a length of 8 to 64 characters and + can only contain letters, '.', '@', '-', '_' or ':'. + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 29 + + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 88 + + + Passwords must have a length of 12 to 16 characters + and can only contain letters, '@', '-' or '_'. + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 64 + + + Passwords must have a length of 12 to 16 characters and + can only contain letters, '@', '-' or '_'. + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 123 + + + Submit + + app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html + 133 + + + app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.html + 34 + + + app/ceph/cluster/osd/osd-recv-speed-modal/osd-recv-speed-modal.component.html + 87 + + + app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.html + 21 + + + app/ceph/block/mirroring/pool-edit-peer-modal/pool-edit-peer-modal.component.html + 106 + Please consult the documentation on how to configure and enable the iSCSI Targets management functionality. @@ -849,6 +938,12 @@ app/ceph/block/iscsi-target-list/iscsi-target-list.component.html 4 + + Set discovery authentication + + app/ceph/block/iscsi-target-list/iscsi-target-list.component.html + 39 + {VAR_SELECT, select, editing {Edit} cloning {Clone} copying {Copy} other {Add} } @@ -1261,24 +1356,6 @@ app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.html 3 - - Submit - - app/ceph/cluster/osd/osd-flags-modal/osd-flags-modal.component.html - 34 - - - app/ceph/cluster/osd/osd-recv-speed-modal/osd-recv-speed-modal.component.html - 87 - - - app/ceph/cluster/osd/osd-scrub-modal/osd-scrub-modal.component.html - 21 - - - app/ceph/block/mirroring/pool-edit-peer-modal/pool-edit-peer-modal.component.html - 106 - OSD Recovery Priority @@ -3553,6 +3630,20 @@ 1 + + Discovery authentication was updated. + + src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.ts + 1 + + + + Discovery authentication + + src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.ts + 1 + + There are no portals available. -- 2.39.5