]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Allow managing iSCSI Initiator after removing from group 37198/head
authorTiago Melo <tmelo@suse.com>
Wed, 16 Sep 2020 15:57:51 +0000 (15:57 +0000)
committerTiago Melo <tmelo@suse.com>
Wed, 21 Oct 2020 22:12:42 +0000 (22:12 +0000)
Fixes: https://tracker.ceph.com/issues/47445
Signed-off-by: Tiago Melo <tmelo@suse.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.ts

index 825e821144a6e79994593bf0248c7a2387d572fa..9dcdaedc0460a0891ba2b3849d9cd684e7cabfed 100644 (file)
                 <ng-container i18n>Group</ng-container>: {{ group.getValue('group_id') }}
                 <button type="button"
                         class="close"
-                        (click)="groups.removeAt(gi)">
+                        (click)="removeGroup(gi)">
                   <i [ngClass]="[icons.destroy]"></i>
                 </button>
               </div>
                         <cd-select [data]="group.getValue('members')"
                                    [options]="groupMembersSelections[gi]"
                                    [messages]="messages.groupInitiator"
-                                   (selection)="onGroupMemberSelection($event)"
+                                   (selection)="onGroupMemberSelection($event, gi)"
                                    elemClass="btn btn-light float-right">
                           <i [ngClass]="[icons.add]"></i>
                           <ng-container i18n>Add initiator</ng-container>
index fb6eef30e8a4482b60a0c8ecb21163b71726c271..f60471a0e86bcfd492f6e57b0d615a85b08267c2 100644 (file)
@@ -4,6 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms';
 import { ActivatedRoute } from '@angular/router';
 import { RouterTestingModule } from '@angular/router/testing';
 
+import { SelectOption } from 'app/shared/components/select/select-option.model';
 import { ToastrModule } from 'ngx-toastr';
 
 import { ActivatedRouteStub } from '../../../../testing/activated-route-stub';
@@ -329,6 +330,14 @@ describe('IscsiTargetFormComponent', () => {
       component.initiators.controls[0].patchValue({
         luns: ['rbd/disk_2']
       });
+      component.imagesInitiatorSelections[0] = [
+        {
+          description: '',
+          enabled: true,
+          name: 'rbd/disk_2',
+          selected: true
+        }
+      ];
       expect(component.initiators.controls[0].value).toEqual({
         auth: { mutual_password: '', mutual_user: '', password: '', user: '' },
         cdIsInGroup: false,
@@ -336,17 +345,19 @@ describe('IscsiTargetFormComponent', () => {
         luns: ['rbd/disk_2']
       });
 
-      component.addGroup();
       component.groups.controls[0].patchValue({
         group_id: 'foo',
         members: ['iqn.initiator']
       });
-      component.onGroupMemberSelection({
-        option: {
-          name: 'iqn.initiator',
-          selected: true
-        }
-      });
+      component.onGroupMemberSelection(
+        {
+          option: {
+            name: 'iqn.initiator',
+            selected: true
+          }
+        },
+        0
+      );
 
       expect(component.initiators.controls[0].value).toEqual({
         auth: { mutual_password: '', mutual_user: '', password: '', user: '' },
@@ -354,6 +365,14 @@ describe('IscsiTargetFormComponent', () => {
         client_iqn: 'iqn.initiator',
         luns: []
       });
+      expect(component.imagesInitiatorSelections[0]).toEqual([
+        {
+          description: '',
+          enabled: true,
+          name: 'rbd/disk_2',
+          selected: false
+        }
+      ]);
     });
 
     it('should disabled the initiator when selected', () => {
@@ -363,7 +382,7 @@ describe('IscsiTargetFormComponent', () => {
       ]);
 
       component.groupMembersSelections[0][0].selected = true;
-      component.onGroupMemberSelection({ option: { name: 'iqn.initiator', selected: true } });
+      component.onGroupMemberSelection({ option: { name: 'iqn.initiator', selected: true } }, 0);
 
       expect(component.groupMembersSelections).toEqual([
         [{ description: '', enabled: false, name: 'iqn.initiator', selected: true }],
@@ -371,6 +390,49 @@ describe('IscsiTargetFormComponent', () => {
       ]);
     });
 
+    describe('should remove from group', () => {
+      beforeEach(() => {
+        component.onGroupMemberSelection(
+          { option: new SelectOption(true, 'iqn.initiator', '') },
+          0
+        );
+        component.groupDiskSelections[0][0].selected = true;
+        component.groups.controls[0].patchValue({
+          disks: ['rbd/disk_2'],
+          members: ['iqn.initiator']
+        });
+
+        expect(component.initiators.value[0].luns).toEqual([]);
+        expect(component.imagesInitiatorSelections[0]).toEqual([
+          { description: '', enabled: true, name: 'rbd/disk_2', selected: false }
+        ]);
+        expect(component.initiators.value[0].cdIsInGroup).toBe(true);
+      });
+
+      it('should update initiator images when deselecting', () => {
+        component.onGroupMemberSelection(
+          { option: new SelectOption(false, 'iqn.initiator', '') },
+          0
+        );
+
+        expect(component.initiators.value[0].luns).toEqual(['rbd/disk_2']);
+        expect(component.imagesInitiatorSelections[0]).toEqual([
+          { description: '', enabled: true, name: 'rbd/disk_2', selected: true }
+        ]);
+        expect(component.initiators.value[0].cdIsInGroup).toBe(false);
+      });
+
+      it('should update initiator when removing', () => {
+        component.removeGroupInitiator(component.groups.controls[0] as CdFormGroup, 0, 0);
+
+        expect(component.initiators.value[0].luns).toEqual(['rbd/disk_2']);
+        expect(component.imagesInitiatorSelections[0]).toEqual([
+          { description: '', enabled: true, name: 'rbd/disk_2', selected: true }
+        ]);
+        expect(component.initiators.value[0].cdIsInGroup).toBe(false);
+      });
+    });
+
     it('should validate authentication', () => {
       const control = component.initiators.controls[0];
       const formHelper = new FormHelper(control as CdFormGroup);
index eefb0bca28fa9f1a7b98355ed1f08983d2a992e1..40e83117fb2f9f42ded8e654cc8361d1298e1183 100644 (file)
@@ -264,12 +264,12 @@ export class IscsiTargetFormComponent extends CdForm implements OnInit {
       // updatedInitiatorSelector()
     });
 
-    _.forEach(res.groups, (group) => {
+    (res.groups as any[]).forEach((group: any, group_index: number) => {
       const fg = this.addGroup();
       group.disks = _.map(group.disks, (disk) => `${disk.pool}/${disk.image}`);
       fg.patchValue(group);
       _.forEach(group.members, (member) => {
-        this.onGroupMemberSelection({ option: new SelectOption(true, member, '') });
+        this.onGroupMemberSelection({ option: new SelectOption(true, member, '') }, group_index);
       });
     });
   }
@@ -577,26 +577,44 @@ export class IscsiTargetFormComponent extends CdForm implements OnInit {
   }
 
   removeGroup(index: number) {
+    // Remove group and disk selections
     this.groups.removeAt(index);
+
+    // Free initiator from group
+    const selectedMembers = this.groupMembersSelections[index].filter((value) => value.selected);
+    selectedMembers.forEach((selection) => {
+      selection.selected = false;
+      this.onGroupMemberSelection({ option: selection }, index);
+    });
+
+    this.groupMembersSelections.splice(index, 1);
     this.groupDiskSelections.splice(index, 1);
   }
 
-  onGroupMemberSelection($event: any) {
+  onGroupMemberSelection($event: any, group_index: number) {
     const option = $event.option;
 
-    let initiator_index: number;
+    let luns: string[] = [];
+    if (!option.selected) {
+      const selectedDisks = this.groupDiskSelections[group_index].filter((value) => value.selected);
+      luns = selectedDisks.map((value) => value.name);
+    }
+
     this.initiators.controls.forEach((element, index) => {
       if (element.value.client_iqn === option.name) {
-        element.patchValue({ luns: [] });
+        element.patchValue({ luns: luns });
         element.get('cdIsInGroup').setValue(option.selected);
-        initiator_index = index;
-      }
-    });
 
-    // Members can only be at one group at a time, so when a member is selected
-    // in one group we need to disable its selection in other groups
-    _.forEach(this.groupMembersSelections, (group) => {
-      group[initiator_index].enabled = !option.selected;
+        // Members can only be at one group at a time, so when a member is selected
+        // in one group we need to disable its selection in other groups
+        _.forEach(this.groupMembersSelections, (group) => {
+          group[index].enabled = !option.selected;
+        });
+
+        this.imagesInitiatorSelections[index].forEach((image) => {
+          image.selected = luns.includes(image.name);
+        });
+      }
     });
   }
 
@@ -604,14 +622,7 @@ export class IscsiTargetFormComponent extends CdForm implements OnInit {
     const name = group.getValue('members')[member_index];
     group.getValue('members').splice(member_index, 1);
 
-    this.groupMembersSelections[group_index].forEach((value) => {
-      if (value.name === name) {
-        value.selected = false;
-      }
-    });
-    this.groupMembersSelections[group_index] = [...this.groupMembersSelections[group_index]];
-
-    this.onGroupMemberSelection({ option: new SelectOption(false, name, '') });
+    this.onGroupMemberSelection({ option: new SelectOption(false, name, '') }, group_index);
   }
 
   removeGroupDisk(group: CdFormGroup, disk_index: number, group_index: number) {