Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/middlewared/middlewared/api/v25_10_0/iscsi_extent.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class IscsiExtentCreate(IscsiExtentEntry):
naa: Excluded = excluded_field()
vendor: Excluded = excluded_field()
locked: Excluded = excluded_field()
defer: bool = False


class IscsiExtentCreateArgs(BaseModel):
Expand Down Expand Up @@ -74,6 +75,7 @@ class IscsiExtentDeleteArgs(BaseModel):
id: int
remove: bool = False
force: bool = False
defer: bool = False


class IscsiExtentDeleteResult(BaseModel):
Expand Down
2 changes: 2 additions & 0 deletions src/middlewared/middlewared/api/v25_10_0/iscsi_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class IscsiTargetValidateNameResult(BaseModel):
class IscsiTargetCreate(IscsiTargetEntry):
id: Excluded = excluded_field()
rel_tgt_id: Excluded = excluded_field()
defer: bool = False


class IscsiTargetCreateArgs(BaseModel):
Expand Down Expand Up @@ -90,6 +91,7 @@ class IscsiTargetDeleteArgs(BaseModel):
id: int
force: bool = False
delete_extents: bool = False
defer: bool = False


class IscsiTargetDeleteResult(BaseModel):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class IscsiTargetToExtentEntry(BaseModel):
class IscsiTargetToExtentCreate(IscsiTargetToExtentEntry):
id: Excluded = excluded_field()
lunid: int | None = None
defer: bool = False


class IscsiTargetToExtentCreateArgs(BaseModel):
Expand All @@ -34,7 +35,7 @@ class IscsiTargetToExtentCreateResult(BaseModel):


class IscsiTargetToExtentUpdate(IscsiTargetToExtentEntry, metaclass=ForUpdateMetaclass):
pass
defer: bool = False


class IscsiTargetToExtentUpdateArgs(BaseModel):
Expand All @@ -49,6 +50,7 @@ class IscsiTargetToExtentUpdateResult(BaseModel):
class IscsiTargetToExtentDeleteArgs(BaseModel):
id: int
force: bool = False
defer: bool = False


class IscsiTargetToExtentDeleteResult(BaseModel):
Expand Down
26 changes: 20 additions & 6 deletions src/middlewared/middlewared/plugins/iscsi_/extents.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ async def do_create(self, data):

`ro` when set to true prevents the initiator from writing to this LUN.
"""
defer = False
try:
defer = data.pop('defer')
except KeyError:
pass

await self.validate(data)
verrors = ValidationErrors()
await self.clean(data, 'iscsi_extent_create', verrors)
Expand Down Expand Up @@ -133,6 +139,12 @@ async def do_update(self, audit_callback, id_, data):
"""
Update iSCSI Extent of `id`.
"""
defer = False
try:
defer = data.pop('defer')
except KeyError:
pass

verrors = ValidationErrors()
old = await self.get_instance(id_)
audit_callback(old['name'])
Expand Down Expand Up @@ -169,10 +181,11 @@ async def do_update(self, audit_callback, id_, data):
{'prefix': self._config.datastore_prefix}
)

await self._service_change('iscsitarget', 'reload')
if not defer:
await self._service_change('iscsitarget', 'reload')

# scstadmin can have issues when modifying an existing extent, re-run
await self._service_change('iscsitarget', 'reload')
# scstadmin can have issues when modifying an existing extent, re-run
await self._service_change('iscsitarget', 'reload')

return await self.get_instance(id_)

Expand All @@ -182,7 +195,7 @@ async def do_update(self, audit_callback, id_, data):
audit='Delete iSCSI extent',
audit_callback=True
)
async def do_delete(self, audit_callback, id_, remove, force):
async def do_delete(self, audit_callback, id_, remove, force, defer):
"""
Delete iSCSI Extent of `id`.

Expand Down Expand Up @@ -210,7 +223,7 @@ async def do_delete(self, audit_callback, id_, remove, force):
raise CallError(f'Failed to remove extent file: {delete!r}')

for target_to_extent in target_to_extents:
await self.middleware.call('iscsi.targetextent.delete', target_to_extent['id'], force)
await self.middleware.call('iscsi.targetextent.delete', target_to_extent['id'], force, defer)

# This change is being made in conjunction with threads_num being specified in scst.conf
if data['type'] == 'DISK' and data['path'].startswith('zvol/'):
Expand All @@ -226,7 +239,8 @@ async def do_delete(self, audit_callback, id_, remove, force):
'datastore.delete', self._config.datastore, id_
)
finally:
await self._service_change('iscsitarget', 'reload')
if not defer:
await self._service_change('iscsitarget', 'reload')
if all([await self.middleware.call("iscsi.global.alua_enabled"),
await self.middleware.call('failover.remote_connected')]):
await self.middleware.call('iscsi.alua.wait_for_alua_settled')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ async def delete(self, attachments):
for te in await self.middleware.call('iscsi.targetextent.query', [['target', 'in', orphan_targets_ids]]):
orphan_targets_ids.discard(te['target'])
for target_id in orphan_targets_ids:
await self.middleware.call('iscsi.target.delete', target_id, True)
await self.middleware.call('iscsi.target.delete', target_id, True, True)

await self._service_change('iscsitarget', 'reload')

Expand Down
28 changes: 22 additions & 6 deletions src/middlewared/middlewared/plugins/iscsi_/target_to_extent.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ async def do_create(self, audit_callback, data):

`lunid` will be automatically assigned if it is not provided based on the `target`.
"""
defer = False
try:
defer = data.pop('defer')
except KeyError:
pass

# It is unusual to do a audit_callback on a do_create, but we want to perform
# more extensive operations than is usual for a create ... because the parameters
# supplied as so opaque to the user.
Expand All @@ -68,7 +74,9 @@ async def do_create(self, audit_callback, data):
{'prefix': self._config.datastore_prefix}
)

await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})
if not defer:
await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})

if await self.middleware.call("iscsi.global.alua_enabled") and await self.middleware.call('failover.remote_connected'):
await self.middleware.call(
'failover.call_remote', 'service.control', ['RELOAD', 'iscsitarget'], {'job': True},
Expand Down Expand Up @@ -106,6 +114,12 @@ async def do_update(self, audit_callback, id_, data):
"""
Update Associated Target of `id`.
"""
defer = False
try:
defer = data.pop('defer')
except KeyError:
pass

verrors = ValidationErrors()
old = await self.get_instance(id_)
audit_callback(await self._mapping_summary(old))
Expand All @@ -121,7 +135,8 @@ async def do_update(self, audit_callback, id_, data):
'datastore.update', self._config.datastore, id_, new,
{'prefix': self._config.datastore_prefix})

await self._service_change('iscsitarget', 'reload')
if not defer:
await self._service_change('iscsitarget', 'reload')

return await self.get_instance(id_)

Expand All @@ -131,7 +146,7 @@ async def do_update(self, audit_callback, id_, data):
audit='Delete iSCSI target/LUN/extent mapping',
audit_callback=True
)
async def do_delete(self, audit_callback, id_, force):
async def do_delete(self, audit_callback, id_, force, defer):
"""
Delete Associated Target of `id`.
"""
Expand All @@ -150,9 +165,10 @@ async def do_delete(self, audit_callback, id_, force):
'datastore.delete', self._config.datastore, id_
)

# Reload the target, so that the LUN is removed from what is being offered ... including
# on the internal target, if this is an ALUA system.
await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})
if not defer:
# Reload the target, so that the LUN is removed from what is being offered ... including
# on the internal target, if this is an ALUA system.
await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})

# Next, perform any necessary fixup on the STANDBY system if ALUA is enabled.
if await self.middleware.call("iscsi.global.alua_enabled") and await self.middleware.call('failover.remote_connected'):
Expand Down
32 changes: 24 additions & 8 deletions src/middlewared/middlewared/plugins/iscsi_/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ async def do_create(self, data):
`auth_networks` is a list of IP/CIDR addresses which are allowed to use this initiator. If all networks are
to be allowed, this field should be left empty.
"""
defer = False
try:
defer = data.pop('defer')
except KeyError:
pass

verrors = ValidationErrors()
await self.__validate(verrors, data, 'iscsi_target_create')
verrors.check()
Expand All @@ -136,8 +142,9 @@ async def do_create(self, data):
await self.middleware.call('datastore.delete', self._config.datastore, pk)
raise e

# First process the local (MASTER) config
await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})
if not defer:
# First process the local (MASTER) config
await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})

# Then process the remote (BACKUP) config if we are HA and ALUA is enabled.
if await self.middleware.call("iscsi.global.alua_enabled") and await self.middleware.call('failover.remote_connected'):
Expand Down Expand Up @@ -318,6 +325,12 @@ async def do_update(self, audit_callback, id_, data):
"""
Update iSCSI Target of `id`.
"""
defer = False
try:
defer = data.pop('defer')
except KeyError:
pass

old = await self.get_instance(id_)
audit_callback(old['name'])
new = old.copy()
Expand Down Expand Up @@ -350,8 +363,9 @@ async def do_update(self, audit_callback, id_, data):
if remove_fcport:
await self.__remove_target_fcport(id_)

# First process the local (MASTER) config
await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})
if not defer:
# First process the local (MASTER) config
await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})

# Then process the BACKUP config if we are HA and ALUA is enabled.
alua_enabled = await self.middleware.call("iscsi.global.alua_enabled")
Expand Down Expand Up @@ -389,7 +403,7 @@ async def do_update(self, audit_callback, id_, data):
audit='Delete iSCSI target',
audit_callback=True
)
async def do_delete(self, audit_callback, id_, force, delete_extents):
async def do_delete(self, audit_callback, id_, force, delete_extents, defer):
"""
Delete iSCSI Target of `id`.

Expand All @@ -404,9 +418,9 @@ async def do_delete(self, audit_callback, id_, force, delete_extents):
else:
raise CallError(f'Target {target["name"]} is in use.')
for target_to_extent in await self.middleware.call('iscsi.targetextent.query', [['target', '=', id_]]):
await self.middleware.call('iscsi.targetextent.delete', target_to_extent['id'], force)
await self.middleware.call('iscsi.targetextent.delete', target_to_extent['id'], force, defer)
if delete_extents:
await self.middleware.call('iscsi.extent.delete', target_to_extent['extent'], False, force)
await self.middleware.call('iscsi.extent.delete', target_to_extent['extent'], False, force, defer)

# If the target was being used for FC then we may also need to clear the
# Fibre Channel port mapping
Expand All @@ -428,7 +442,9 @@ async def do_delete(self, audit_callback, id_, force, delete_extents):
await self.middleware.call('iscsi.alua.wait_for_alua_settled')

await self.middleware.call('iscsi.target.remove_target', target["name"])
await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})

if not defer:
await self._service_change('iscsitarget', 'reload', options={'ha_propagate': False})

return rv

Expand Down