raise DashboardException(msg='Target already exists',
code='target_already_exists',
component='iscsi')
- IscsiTarget._validate(target_iqn, portals, disks)
+ IscsiTarget._validate(target_iqn, portals, disks, groups)
IscsiTarget._create(target_iqn, target_controls, acl_enabled, portals, disks, clients,
groups, 0, 100, config)
raise DashboardException(msg='Target IQN already in use',
code='target_iqn_already_in_use',
component='iscsi')
- IscsiTarget._validate(new_target_iqn, portals, disks)
+ IscsiTarget._validate(new_target_iqn, portals, disks, groups)
config = IscsiTarget._delete(target_iqn, config, 0, 50, new_target_iqn, target_controls,
portals, disks, clients, groups)
IscsiTarget._create(new_target_iqn, target_controls, acl_enabled, portals, disks, clients,
return False
@staticmethod
- def _validate(target_iqn, portals, disks):
+ def _validate(target_iqn, portals, disks, groups):
if not target_iqn:
raise DashboardException(msg='Target IQN is required',
code='target_iqn_required',
IscsiTarget._validate_image(pool, image, backstore, required_rbd_features,
supported_rbd_features)
+ initiators = []
+ for group in groups:
+ initiators = initiators + group['members']
+ if len(initiators) != len(set(initiators)):
+ raise DashboardException(msg='Each initiator can only be part of 1 group at a time',
+ code='initiator_in_multiple_groups',
+ component='iscsi')
+
@staticmethod
def _validate_image(pool, image, backstore, required_rbd_features, supported_rbd_features):
try:
beforeEach(() => {
component.targetForm.patchValue({ disks: ['rbd/disk_2'], acl_enabled: true });
component.addGroup().patchValue({ name: 'group_1' });
+ component.addGroup().patchValue({ name: 'group_2' });
component.onImageSelection({ option: { name: 'rbd/disk_2', selected: true } });
component.addInitiator();
[{ description: '', name: 'rbd/disk_2', selected: false, enabled: true }]
]);
expect(component.groupMembersSelections).toEqual([
+ [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }],
[{ description: '', name: 'iqn.initiator', selected: false, enabled: true }]
]);
});
it('should update data when changing an initiator name', () => {
expect(component.groupMembersSelections).toEqual([
+ [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }],
[{ description: '', name: 'iqn.initiator', selected: false, enabled: true }]
]);
component.updatedInitiatorSelector();
expect(component.groupMembersSelections).toEqual([
+ [{ description: '', name: 'iqn.initiator_new', selected: false, enabled: true }],
[{ description: '', name: 'iqn.initiator_new', selected: false, enabled: true }]
]);
});
group_id: 'foo',
members: []
});
- expect(component.groupMembersSelections).toEqual([[]]);
+ expect(component.groupMembersSelections).toEqual([[], []]);
expect(component.imagesInitiatorSelections).toEqual([]);
});
luns: []
});
});
+
+ it('should disabled the initiator when selected', () => {
+ expect(component.groupMembersSelections).toEqual([
+ [{ description: '', enabled: true, name: 'iqn.initiator', selected: false }],
+ [{ description: '', enabled: true, name: 'iqn.initiator', selected: false }]
+ ]);
+
+ component.groupMembersSelections[0][0].selected = true;
+ component.onGroupMemberSelection({ option: { name: 'iqn.initiator', selected: true } });
+
+ expect(component.groupMembersSelections).toEqual([
+ [{ description: '', enabled: false, name: 'iqn.initiator', selected: true }],
+ [{ description: '', enabled: false, name: 'iqn.initiator', selected: false }]
+ ]);
+ });
});
describe('should submit request', () => {
_.forEach(res.groups, (group) => {
const fg = this.addGroup();
- console.log(group);
group.disks = _.map(group.disks, (disk) => `${disk.pool}/${disk.image}`);
fg.patchValue(group);
_.forEach(group.members, (member) => {
const initiators = _.map(
this.initiators.value,
- (initiator) => new SelectOption(false, initiator.client_iqn, '')
+ (initiator) => new SelectOption(false, initiator.client_iqn, '', !initiator.cdIsInGroup)
);
this.groupMembersSelections.push(initiators);
onGroupMemberSelection($event) {
const option = $event.option;
- this.initiators.controls.forEach((element) => {
+ let initiator_index: number;
+ this.initiators.controls.forEach((element, index) => {
if (element.value.client_iqn === option.name) {
element.patchValue({ 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;
+ });
}
removeGroupInitiator(group, member_index, group_index) {
response['groups'] = []
self._update_iscsi_target(create_request, update_request, response)
+ @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
+ def test_add_client_to_multiple_groups(self, _validate_image_mock):
+ target_iqn = "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw16"
+ create_request = copy.deepcopy(iscsi_target_request)
+ create_request['target_iqn'] = target_iqn
+ create_request['groups'].append(copy.deepcopy(create_request['groups'][0]))
+ create_request['groups'][1]['group_id'] = 'mygroup2'
+ self._post('/api/iscsi/target', create_request)
+ self.assertStatus(400)
+ self.assertJsonBody({
+ 'detail': 'Each initiator can only be part of 1 group at a time',
+ 'code': 'initiator_in_multiple_groups',
+ 'component': 'iscsi'
+ })
+
def _update_iscsi_target(self, create_request, update_request, response):
self._post('/api/iscsi/target', create_request)
self.assertStatus(201)