Merge pull request #37087 from tspmelo/wip-iscsi-logged-in

Reviewed-by: Laura Paduano <lpaduano@suse.com>
Reviewed-by: Ricardo Marques <rimarques@suse.com>
This commit is contained in:
Lenz Grimmer 2020-09-21 11:45:19 +02:00 committed by GitHub
commit 0c9e31cf6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 157 additions and 39 deletions

View File

@ -384,35 +384,48 @@ class IscsiTarget(RESTController):
deleted_groups = []
for group_id in list(target_config['groups'].keys()):
if IscsiTarget._group_deletion_required(target, new_target_iqn, new_target_controls,
new_groups, group_id, new_clients,
new_disks):
new_groups, group_id):
deleted_groups.append(group_id)
IscsiClient.instance(gateway_name=gateway_name).delete_group(target_iqn,
group_id)
else:
group = IscsiTarget._get_group(new_groups, group_id)
old_group_disks = set(target_config['groups'][group_id]['disks'].keys())
new_group_disks = {'{}/{}'.format(x['pool'], x['image']) for x in group['disks']}
local_deleted_disks = list(old_group_disks - new_group_disks)
old_group_members = set(target_config['groups'][group_id]['members'])
new_group_members = set(group['members'])
local_deleted_members = list(old_group_members - new_group_members)
if local_deleted_disks or local_deleted_members:
IscsiClient.instance(gateway_name=gateway_name).update_group(
target_iqn, group_id, local_deleted_members, local_deleted_disks)
TaskManager.current_task().inc_progress(task_progress_inc)
deleted_clients = []
deleted_client_luns = []
for client_iqn, client_config in target_config['clients'].items():
if IscsiTarget._client_deletion_required(target, new_target_iqn, new_target_controls,
new_clients, client_iqn,
deleted_groups):
new_clients, client_iqn):
deleted_clients.append(client_iqn)
IscsiClient.instance(gateway_name=gateway_name).delete_client(target_iqn,
client_iqn)
else:
for image_id in list(client_config.get('luns', {}).keys()):
if IscsiTarget._client_lun_deletion_required(target, client_iqn, image_id,
new_clients):
new_clients, new_groups):
deleted_client_luns.append((client_iqn, image_id))
IscsiClient.instance(gateway_name=gateway_name).delete_client_lun(
target_iqn, client_iqn, image_id)
TaskManager.current_task().inc_progress(task_progress_inc)
for image_id in target_config['disks']:
if IscsiTarget._target_lun_deletion_required(target, new_target_iqn,
new_target_controls,
new_disks, image_id):
new_target_controls, new_disks, image_id):
all_clients = target_config['clients'].keys()
not_deleted_clients = [c for c in all_clients if c not in deleted_clients]
not_deleted_clients = [c for c in all_clients if c not in deleted_clients
and not IscsiTarget._client_in_group(target['groups'], c)
and not IscsiTarget._client_in_group(new_groups, c)]
for client_iqn in not_deleted_clients:
client_image_ids = target_config['clients'][client_iqn]['luns'].keys()
for client_image_id in client_image_ids:
@ -447,28 +460,12 @@ class IscsiTarget(RESTController):
@staticmethod
def _group_deletion_required(target, new_target_iqn, new_target_controls,
new_groups, group_id, new_clients, new_disks):
new_groups, group_id):
if IscsiTarget._target_deletion_required(target, new_target_iqn, new_target_controls):
return True
new_group = IscsiTarget._get_group(new_groups, group_id)
if not new_group:
return True
old_group = IscsiTarget._get_group(target['groups'], group_id)
if new_group != old_group:
return True
# Check if any client inside this group has changed
for client_iqn in new_group['members']:
if IscsiTarget._client_deletion_required(target, new_target_iqn, new_target_controls,
new_clients, client_iqn,
[]):
return True
# Check if any disk inside this group has changed
for disk in new_group['disks']:
image_id = '{}/{}'.format(disk['pool'], disk['image'])
if IscsiTarget._target_lun_deletion_required(target, new_target_iqn,
new_target_controls,
new_disks, image_id):
return True
return False
@staticmethod
@ -480,29 +477,45 @@ class IscsiTarget(RESTController):
@staticmethod
def _client_deletion_required(target, new_target_iqn, new_target_controls,
new_clients, client_iqn, deleted_groups):
new_clients, client_iqn):
if IscsiTarget._target_deletion_required(target, new_target_iqn, new_target_controls):
return True
new_client = IscsiTarget._get_client(new_clients, client_iqn)
if not new_client:
return True
# Check if client belongs to a groups that has been deleted
for group in target['groups']:
if group['group_id'] in deleted_groups and client_iqn in group['members']:
return False
@staticmethod
def _client_in_group(groups, client_iqn):
for group in groups:
if client_iqn in group['members']:
return True
return False
@staticmethod
def _client_lun_deletion_required(target, client_iqn, image_id, new_clients):
def _client_lun_deletion_required(target, client_iqn, image_id, new_clients, new_groups):
new_client = IscsiTarget._get_client(new_clients, client_iqn)
if not new_client:
return True
# Disks inherited from groups must be considered
was_in_group = IscsiTarget._client_in_group(target['groups'], client_iqn)
is_in_group = IscsiTarget._client_in_group(new_groups, client_iqn)
if not was_in_group and is_in_group:
return True
if is_in_group:
return False
new_lun = IscsiTarget._get_disk(new_client.get('luns', []), image_id)
if not new_lun:
return True
old_client = IscsiTarget._get_client(target['clients'], client_iqn)
if not old_client:
return False
old_lun = IscsiTarget._get_disk(old_client.get('luns', []), image_id)
return new_lun != old_lun
@ -673,15 +686,9 @@ class IscsiTarget(RESTController):
target_config = config['targets'][target_iqn]
target = IscsiTarget._config_to_target(target_iqn, config)
deleted_groups = []
for group_id in list(target_config['groups'].keys()):
if IscsiTarget._group_deletion_required(target, new_target_iqn, new_target_controls,
new_groups, group_id, new_clients,
new_disks):
deleted_groups.append(group_id)
for client_iqn in list(target_config['clients'].keys()):
if IscsiTarget._client_deletion_required(target, new_target_iqn, new_target_controls,
new_clients, client_iqn, deleted_groups):
new_clients, client_iqn):
client_info = IscsiClient.instance(gateway_name=gateway).get_clientinfo(target_iqn,
client_iqn)
if client_info.get('state', {}).get('LOGGED_IN', []):
@ -807,8 +814,15 @@ class IscsiTarget(RESTController):
pool = lun['pool']
image = lun['image']
image_id = '{}/{}'.format(pool, image)
# Disks inherited from groups must be considered
group_disks = []
for group in groups:
if client_iqn in group['members']:
group_disks = ['{}/{}'.format(x['pool'], x['image'])
for x in group['disks']]
if not target_config or client_iqn not in target_config['clients'] or \
image_id not in target_config['clients'][client_iqn]['luns']:
(image_id not in target_config['clients'][client_iqn]['luns']
and image_id not in group_disks):
IscsiClient.instance(gateway_name=gateway_name).create_client_lun(
target_iqn, client_iqn, image_id)
TaskManager.current_task().inc_progress(task_progress_inc)
@ -818,7 +832,14 @@ class IscsiTarget(RESTController):
image_ids = []
for disk in group['disks']:
image_ids.append('{}/{}'.format(disk['pool'], disk['image']))
if not target_config or group_id not in target_config['groups']:
if target_config and group_id in target_config['groups']:
old_members = target_config['groups'][group_id]['members']
old_disks = target_config['groups'][group_id]['disks'].keys()
if not target_config or group_id not in target_config['groups'] or \
list(set(group['members']) - set(old_members)) or \
list(set(image_ids) - set(old_disks)):
IscsiClient.instance(gateway_name=gateway_name).create_group(
target_iqn, group_id, members, image_ids)
TaskManager.current_task().inc_progress(task_progress_inc)

View File

@ -205,6 +205,15 @@ class IscsiClient(RestClient):
'disks': ','.join(image_ids)
})
@RestClient.api_put('/api/hostgroup/{target_iqn}/{group_name}')
def update_group(self, target_iqn, group_name, members, image_ids, request=None):
logger.debug("iSCSI[%s] Updating group: %s/%s", self.gateway_name, target_iqn, group_name)
return request({
'action': 'remove',
'members': ','.join(members),
'disks': ','.join(image_ids)
})
@RestClient.api_delete('/api/hostgroup/{target_iqn}/{group_name}')
def delete_group(self, target_iqn, group_name, request=None):
logger.debug("[%s] Deleting group: %s/%s", self.gateway_name, target_iqn, group_name)

View File

@ -517,6 +517,74 @@ class IscsiTestController(ControllerTestCase, KVStoreMockMixin):
response['clients'].pop(0)
self._update_iscsi_target(create_request, update_request, 200, None, response)
@mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
def test_add_image_to_group_with_client_logged_in(self, _validate_image_mock):
client_info = {
'alias': '',
'ip_address': [],
'state': {'LOGGED_IN': ['node1']}
}
new_disk = {"pool": "rbd", "image": "lun1"}
# pylint: disable=protected-access
IscsiClientMock._instance.clientinfo = client_info
target_iqn = "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw21"
create_request = copy.deepcopy(iscsi_target_request)
create_request['target_iqn'] = target_iqn
update_request = copy.deepcopy(create_request)
update_request['new_target_iqn'] = target_iqn
update_request['groups'][0]['disks'].append(new_disk)
response = copy.deepcopy(iscsi_target_response)
response['target_iqn'] = target_iqn
response['groups'][0]['disks'].insert(0, new_disk)
for client in response['clients']:
client['info'] = client_info
self._update_iscsi_target(create_request, update_request, 200, None, response)
@mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
def test_add_image_to_initiator_with_client_logged_in(self, _validate_image_mock):
client_info = {
'alias': '',
'ip_address': [],
'state': {'LOGGED_IN': ['node1']}
}
new_disk = {"pool": "rbd", "image": "lun2"}
# pylint: disable=protected-access
IscsiClientMock._instance.clientinfo = client_info
target_iqn = "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw22"
create_request = copy.deepcopy(iscsi_target_request)
create_request['target_iqn'] = target_iqn
update_request = copy.deepcopy(create_request)
update_request['new_target_iqn'] = target_iqn
update_request['clients'][0]['luns'].append(new_disk)
response = copy.deepcopy(iscsi_target_response)
response['target_iqn'] = target_iqn
response['clients'][0]['luns'].append(new_disk)
for client in response['clients']:
client['info'] = client_info
self._update_iscsi_target(create_request, update_request, 200, None, response)
@mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
def test_remove_image_from_group_with_client_logged_in(self, _validate_image_mock):
client_info = {
'alias': '',
'ip_address': [],
'state': {'LOGGED_IN': ['node1']}
}
# pylint: disable=protected-access
IscsiClientMock._instance.clientinfo = client_info
target_iqn = "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw23"
create_request = copy.deepcopy(iscsi_target_request)
create_request['target_iqn'] = target_iqn
update_request = copy.deepcopy(create_request)
update_request['new_target_iqn'] = target_iqn
update_request['groups'][0]['disks'] = []
response = copy.deepcopy(iscsi_target_response)
response['target_iqn'] = target_iqn
response['groups'][0]['disks'] = []
for client in response['clients']:
client['info'] = client_info
self._update_iscsi_target(create_request, update_request, 200, None, response)
def _update_iscsi_target(self, create_request, update_request, update_response_code,
update_response, response):
self._task_post('/api/iscsi/target', create_request)
@ -839,6 +907,26 @@ class IscsiClientMock(object):
target_config['groups'][group_name]['disks'][image_id] = {}
target_config['groups'][group_name]['members'] = members
def update_group(self, target_iqn, group_name, members, image_ids):
target_config = self.config['targets'][target_iqn]
group = target_config['groups'][group_name]
old_members = group['members']
disks = group['disks']
target_config['groups'][group_name] = {
"disks": {},
"members": []
}
for image_id in disks.keys():
if image_id not in image_ids:
target_config['groups'][group_name]['disks'][image_id] = {}
new_members = []
for member_iqn in old_members:
if member_iqn not in members:
new_members.append(member_iqn)
target_config['groups'][group_name]['members'] = new_members
def delete_group(self, target_iqn, group_name):
target_config = self.config['targets'][target_iqn]
del target_config['groups'][group_name]