Skip to content
10 changes: 8 additions & 2 deletions drivers/LinstorSR.py
Original file line number Diff line number Diff line change
Expand Up @@ -2585,7 +2585,8 @@ def _start_persistent_http_server(volume_name):
# Use a timeout call because XAPI may be unusable on startup
# or if the host has been ejected. So in this case the call can
# block indefinitely.
session = util.timeout(5, util.get_localAPI_session)
api_session = util.timeout(5, util.ApiSession, "SM-ha-linstor-http-server")
session = api_session.session
host_ip = util.get_this_host_address(session)
except:
Comment thread
Wescoeur marked this conversation as resolved.
# Fallback using the XHA file if session not available.
Expand All @@ -2594,6 +2595,8 @@ def _start_persistent_http_server(volume_name):
raise Exception(
'Cannot start persistent HTTP server: no XAPI session, nor XHA config file'
)
finally:
api_session.logout()

arguments = [
'http-disk-server',
Expand Down Expand Up @@ -2669,7 +2672,8 @@ def _start_persistent_nbd_server(self, volume_name):
device_size = 256 * 1024 * 1024

try:
session = util.timeout(5, util.get_localAPI_session)
api_session = util.timeout(5, util.ApiSession, "SM-ha-linstor-nbd-server")
session = api_session.session
ips = util.get_host_addresses(session)
except Exception as e:
Comment thread
Wescoeur marked this conversation as resolved.
_, ips = get_ips_from_xha_config_file()
Expand All @@ -2678,6 +2682,8 @@ def _start_persistent_nbd_server(self, volume_name):
'Cannot start persistent NBD server: no XAPI session, nor XHA config file ({})'.format(e)
)
ips = ips.values()
finally:
api_session.logout()

arguments = [
'nbd-http-server',
Expand Down
2 changes: 1 addition & 1 deletion drivers/XE_SR_ERRORCODES.xml
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@

<!-- Agent database query errors 150+ -->
<code>
<name>APISession</name>
<name>ApiSession</name>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nambrok For additional comment.

  1. I don't think we should change this field here (it would create a style inconsistent with the others below).
  2. IMHO We should specify this error code in the ApiSession class in the event of a connection failure to the XAPI.

<description>Failed to initialize XMLRPC connection</description>
<value>150</value>
</code>
Expand Down
24 changes: 10 additions & 14 deletions drivers/blktap2.py
Original file line number Diff line number Diff line change
Expand Up @@ -882,17 +882,18 @@ def abort_linstor_gc(drbd_path: str) -> bool:

openers = get_all_volume_openers(volume_name, "0")

session = util.timeout(5, util.get_localAPI_session)
api_session = util.timeout(5, util.ApiSession, "SM-blktap2-abort_linstor_gc")
try:
srs = util.get_linstor_srs_uuid(session)
srs = util.get_linstor_srs_uuid(api_session.session)
pbd_ref = util.find_pbd_ref_from_dconf_value(
session, srs, "group-name", group_name, LinstorVolumeManager.build_group_name
api_session.session, srs, "group-name", group_name,
LinstorVolumeManager.build_group_name,
)
if pbd_ref:
pbd_rec = session.xenapi.PBD.get_record(pbd_ref)
pbd_rec = api_session.session.xenapi.PBD.get_record(pbd_ref)

sr_ref = pbd_rec["SR"]
sr_uuid = session.xenapi.SR.get_uuid(sr_ref)
sr_uuid = api_session.session.xenapi.SR.get_uuid(sr_ref)

import cleanup # pylint: disable=C0415
if cleanup.LinstorSR.abort_gc_from_openers_sr(sr_uuid, openers):
Expand All @@ -902,7 +903,7 @@ def abort_linstor_gc(drbd_path: str) -> bool:

util.SMlog(f"Unable to run tapdisk, openers of DRBD resource `{drbd_path}`: {openers}")
finally:
session.xenapi.session.logout()
api_session.logout()

return False

Expand Down Expand Up @@ -1153,14 +1154,9 @@ def get_o_direct_capability(self, options):

@classmethod
def from_cli(cls, uuid):
session = XenAPI.xapi_local()
session.xenapi.login_with_password('root', '', '', 'SM')

target = sm.VDI.from_uuid(session, uuid)
driver_info = target.sr.srcmd.driver_info

session.xenapi.session.logout()

with util.ApiSession("SM-blktap2") as session:
target = sm.VDI.from_uuid(session, uuid)
driver_info = target.sr.srcmd.driver_info
return cls(uuid, target, driver_info)

@staticmethod
Expand Down
83 changes: 36 additions & 47 deletions drivers/cleanup.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,18 +299,12 @@ class XAPI:
class LookupError(util.SMException):
pass

@staticmethod
def getSession():
session = XenAPI.xapi_local()
session.xenapi.login_with_password(XAPI.USER, '', '', 'SM')
return session

def __init__(self, session, srUuid):
self.sessionPrivate = False
self.session = session
self._api_session = None
if self.session is None:
self.session = self.getSession()
self.sessionPrivate = True
self._api_session = util.ApiSession("SM-GC")
self.session = self._api_session.session
self._srRef = self.session.xenapi.SR.get_by_uuid(srUuid)
self.srRecord = self.session.xenapi.SR.get_record(self._srRef)
self.hostUuid = util.get_this_host()
Expand All @@ -319,8 +313,8 @@ def __init__(self, session, srUuid):
self.task_progress = {"coalescable": 0, "done": 0}

def __del__(self):
if self.sessionPrivate:
self.session.xenapi.session.logout()
if self._api_session:
self._api_session.logout()

@property
def srRef(self):
Expand Down Expand Up @@ -2127,32 +2121,31 @@ def msg_cleared(self, xapi_session, msg_ref):
return msg is None

def check_no_space_candidates(self):
xapi_session = self.xapi.getSession()

msg_id = self.xapi.srRecord["sm_config"].get(VDI.DB_GC_NO_SPACE)
if self.no_space_candidates:
if msg_id is None or self.msg_cleared(xapi_session, msg_id):
util.SMlog("Could not coalesce due to a lack of space "
f"in SR {self.uuid}")
msg_body = ("Unable to perform data coalesce due to a lack "
f"of space in SR {self.uuid}")
msg_id = xapi_session.xenapi.message.create(
'SM_GC_NO_SPACE',
3,
"SR",
self.uuid,
msg_body)
xapi_session.xenapi.SR.remove_from_sm_config(
self.xapi.srRef, VDI.DB_GC_NO_SPACE)
xapi_session.xenapi.SR.add_to_sm_config(
self.xapi.srRef, VDI.DB_GC_NO_SPACE, msg_id)

for candidate in self.no_space_candidates.values():
candidate.setConfig(VDI.DB_GC_NO_SPACE, msg_id)
elif msg_id is not None:
# Everything was coalescable, remove the message
xapi_session.xenapi.SR.remove_from_sm_config(self.xapi.srRef, VDI.DB_GC_NO_SPACE)
xapi_session.xenapi.message.destroy(msg_id)
with util.ApiSession("SM-GC-check_no_space") as xapi_session:
msg_id = self.xapi.srRecord["sm_config"].get(VDI.DB_GC_NO_SPACE)
if self.no_space_candidates:
if msg_id is None or self.msg_cleared(xapi_session, msg_id):
util.SMlog("Could not coalesce due to a lack of space "
f"in SR {self.uuid}")
msg_body = ("Unable to perform data coalesce due to a lack "
f"of space in SR {self.uuid}")
msg_id = xapi_session.xenapi.message.create(
'SM_GC_NO_SPACE',
3,
"SR",
self.uuid,
msg_body)
xapi_session.xenapi.SR.remove_from_sm_config(
self.xapi.srRef, VDI.DB_GC_NO_SPACE)
xapi_session.xenapi.SR.add_to_sm_config(
self.xapi.srRef, VDI.DB_GC_NO_SPACE, msg_id)

for candidate in self.no_space_candidates.values():
candidate.setConfig(VDI.DB_GC_NO_SPACE, msg_id)
elif msg_id is not None:
# Everything was coalescable, remove the message
xapi_session.xenapi.SR.remove_from_sm_config(self.xapi.srRef, VDI.DB_GC_NO_SPACE)
xapi_session.xenapi.message.destroy(msg_id)

def clear_no_space_msg(self, vdi):
msg_id = None
Expand Down Expand Up @@ -3935,16 +3928,12 @@ def _abort_gc_from_openers(uuid: str, is_vdi_uuid: bool, openers: "LinstorVolume
if node_name == hostname:
continue

with util.timeout(5):
session = XAPI.getSession()
try:
sr_uuid = util.get_sr_uuid_from_vdi_uuid(session, uuid) if is_vdi_uuid else uuid
util.SMlog(f"LINSTOR volume is coalescing on `{sr_uuid}`. We're going to interrupt the GC...")
return util.strtobool(session.xenapi.host.call_plugin(
util.get_master_ref(session), MANAGER_PLUGIN, "abortGc", {"srUuid": sr_uuid}
))
finally:
session.xenapi.session.logout()
with util.timeout(5), util.ApiSession("SM-GC-coalescing") as session:
sr_uuid = util.get_sr_uuid_from_vdi_uuid(session, uuid) if is_vdi_uuid else uuid
util.SMlog(f"LINSTOR volume is coalescing on `{sr_uuid}`. We're going to interrupt the GC...")
return util.strtobool(session.xenapi.host.call_plugin(
util.get_master_ref(session), MANAGER_PLUGIN, "abortGc", {"srUuid": sr_uuid}
))
return False


Expand Down
9 changes: 3 additions & 6 deletions drivers/coalesce-leaf
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,9 @@ def main():
print(USAGE_STRING % sys.argv[0])
sys.exit(-1)

session = XenAPI.xapi_local()
session.xenapi.login_with_password('root', '', '', 'SM')
atexit.register(session.xenapi.session.logout)

ret, messages = vm_leaf_coalesce(session, uuid)
if len(messages):
with util.ApiSession("SM-coalesce-leaf") as session:
ret, messages = vm_leaf_coalesce(session, uuid)
if messages:
print("\n".join(messages))
sys.exit(ret)

Expand Down
12 changes: 3 additions & 9 deletions drivers/lcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

import util
from sm_typing import override

import os
Expand Down Expand Up @@ -199,7 +200,6 @@ def from_uuid(cls, sr_uuid):

@classmethod
def from_session(cls, session):
import util
import SR as sm

host_ref = util.get_localhost_ref(session)
Expand All @@ -221,12 +221,8 @@ def from_session(cls, session):

@classmethod
def from_cli(cls):
import XenAPI # pylint: disable=import-error

session = XenAPI.xapi_local()
session.xenapi.login_with_password('root', '', '', 'SM')

return cls.from_session(session)
with util.ApiSession("SM-local-cache") as session:
return cls.from_session(session)

def statvfs(self):
return os.statvfs(self.sr_path)
Expand All @@ -239,8 +235,6 @@ def _fast_find_nodes(self):
return list(found)

def xapi_vfs_stats(self):
import util

f = self.statvfs()
if not f.f_frsize:
raise util.SMException("Cache FS does not report utilization.")
Expand Down
22 changes: 5 additions & 17 deletions drivers/linstorcowutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,19 +648,10 @@ def clear(self):
self.linstor = None
self.vdi_type_to_cowutil = {}

class Load:
def __init__(self, session):
self.session = session

def cleanup(self):
if self.session:
self.session.xenapi.session.logout()
self.session = None

def __init__(self, uri, group_name) -> None:
self._uri = uri
self._group_name = group_name
self._loads: List[MultiLinstorCowUtil.Load] = []
self._loads: List[util.ApiSession] = []
self._executor_data = self.ExecutorData()

def __del__(self):
Expand All @@ -687,8 +678,7 @@ def get_local_cowutil(self, vdi_type):
return instance

def _init_executor_thread(self):
session = util.get_localAPI_session()
load = self.Load(session)
api_session = util.ApiSession("SM-linstorvhdutil")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to see if we can get automatically the file+function name in the session name, this will reduce maintenance in case of changes (see, for example it should be SM-linstorcowutil now) and also it would allow to not specify everytime the name of the sesion.

This is a suggestion but ain't blocking for me, could even be addressed in a separate PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer having an explicit session name; logs indicating a session aren't necessarily debug logs. They serve as a label that is human-readable and can be independent of the implementation. If we want to be more precise here, it would be SM-linstor-multi-cow-util here.

try:
linstor = LinstorVolumeManager(
self._uri,
Expand All @@ -697,18 +687,16 @@ def _init_executor_thread(self):
logger=util.SMlog
)
self._executor_data.linstor = linstor
self._executor_data.session = session
self._executor_data.session = api_session.session
except:
self._executor_data.clear()
load.cleanup()
raise

self._loads.append(load)
self._loads.append(api_session)

def _cleanup(self):
for load in self._loads:
try:
load.cleanup()
load.logout()
except Exception as e:
util.SMlog(f"Failed to clean load executor: {e}")
self._loads.clear()
47 changes: 23 additions & 24 deletions drivers/linstorvolumemanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,28 +101,27 @@ def get_all_volume_openers(resource_name, volume) -> LinstorVolumeOpeners:
volume = str(volume)
openers = {}

session = util.get_localAPI_session()

hosts = session.xenapi.host.get_all_records()
for host_ref, host_record in hosts.items():
node_name = host_record['hostname']
try:
if not session.xenapi.host_metrics.get_record(
host_record['metrics']
)['live']:
# Ensure we call plugin on online hosts only.
continue
with util.ApiSession("SM-get-linstor-volume-openers") as session:
hosts = session.xenapi.host.get_all_records()
for host_ref, host_record in hosts.items():
node_name = host_record['hostname']
try:
if not session.xenapi.host_metrics.get_record(
host_record['metrics']
)['live']:
# Ensure we call plugin on online hosts only.
continue

openers[node_name] = json.loads(
session.xenapi.host.call_plugin(host_ref, PLUGIN, PLUGIN_CMD, {
'resourceName': resource_name,
'volume': volume
})
)
except Exception as e:
util.SMlog('Failed to get openers of `{}` on `{}`: {}'.format(
resource_name, node_name, e
))
openers[node_name] = json.loads(
session.xenapi.host.call_plugin(host_ref, PLUGIN, PLUGIN_CMD, {
'resourceName': resource_name,
'volume': volume
})
)
except Exception as e:
util.SMlog('Failed to get openers of `{}` on `{}`: {}'.format(
resource_name, node_name, e
))

return openers

Expand Down Expand Up @@ -191,7 +190,7 @@ def get_controller_node_name():
if res:
return res.groups()[0]

session = util.timeout(5, util.get_localAPI_session)
session = util.timeout(5, util.ApiSession, "SM-get-linstor-controller-node-name").session

for host_ref, host_record in session.xenapi.host.get_all_records().items():
node_name = host_record['hostname']
Expand All @@ -214,7 +213,7 @@ def get_controller_node_name():
def demote_drbd_resource(node_name, resource_name):
PLUGIN_CMD = 'demoteDrbdResource'

session = util.timeout(5, util.get_localAPI_session)
session = util.timeout(5, util.ApiSession, "SM-demote-drbd-resource").session

for host_ref, host_record in session.xenapi.host.get_all_records().items():
if host_record['hostname'] != node_name:
Expand Down Expand Up @@ -1411,7 +1410,7 @@ def destroy(self):
# It needs to be done locally by each host so we go through the linstor-manager plugin.
# If we don't do this sometimes, the destroy will fail when trying to destroy the resource groups with:
# "linstor-manager:destroy error: Failed to destroy SP `xcp-sr-linstor_group_thin_device` on node `r620-s2`: The specified storage pool 'xcp-sr-linstor_group_thin_device' on node 'r620-s2' can not be deleted as volumes / snapshot-volumes are still using it."
session = util.timeout(5, util.get_localAPI_session)
session = util.timeout(5, util.ApiSession, "SM-linstor-destroy").session
for host_ref in session.xenapi.host.get_all():
try:
response = session.xenapi.host.call_plugin(
Expand Down
Loading