125 lines
4.6 KiB
Python
125 lines
4.6 KiB
Python
# Copyright (c) 2022, Dell Inc. or its subsidiaries. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
# See the LICENSE file for details.
|
|
#
|
|
# This file is part of NVMe STorage Appliance Services (nvme-stas).
|
|
#
|
|
# Authors: Martin Belanger <Martin.Belanger@dell.com>
|
|
#
|
|
'''This module defines the Transport Identifier Object, which is used
|
|
throughout nvme-stas to uniquely identify a Controller'''
|
|
|
|
import hashlib
|
|
from staslib import conf
|
|
|
|
|
|
class TID: # pylint: disable=too-many-instance-attributes
|
|
'''Transport Identifier'''
|
|
|
|
RDMA_IP_PORT = '4420'
|
|
DISC_IP_PORT = '8009'
|
|
|
|
def __init__(self, cid: dict):
|
|
'''@param cid: Controller Identifier. A dictionary with the following
|
|
contents.
|
|
{
|
|
# Transport parameters
|
|
'transport': str, # [mandatory]
|
|
'traddr': str, # [mandatory]
|
|
'subsysnqn': str, # [mandatory]
|
|
'trsvcid': str, # [optional]
|
|
'host-traddr': str, # [optional]
|
|
'host-iface': str, # [optional]
|
|
'host-nqn': str, # [optional]
|
|
|
|
# Connection parameters
|
|
'dhchap-ctrl-secret': str, # [optional]
|
|
'hdr-digest': str, # [optional]
|
|
'data-digest': str, # [optional]
|
|
'nr-io-queues': str, # [optional]
|
|
'nr-write-queues': str, # [optional]
|
|
'nr-poll-queues': str, # [optional]
|
|
'queue-size': str, # [optional]
|
|
'kato': str, # [optional]
|
|
'reconnect-delay': str, # [optional]
|
|
'ctrl-loss-tmo': str, # [optional]
|
|
'disable-sqflow': str, # [optional]
|
|
}
|
|
'''
|
|
self._cfg = {
|
|
k: v
|
|
for k, v in cid.items()
|
|
if k not in ('transport', 'traddr', 'subsysnqn', 'trsvcid', 'host-traddr', 'host-iface')
|
|
}
|
|
self._transport = cid.get('transport', '')
|
|
self._traddr = cid.get('traddr', '')
|
|
self._trsvcid = ''
|
|
if self._transport in ('tcp', 'rdma'):
|
|
trsvcid = cid.get('trsvcid', None)
|
|
self._trsvcid = (
|
|
trsvcid if trsvcid else (TID.RDMA_IP_PORT if self._transport == 'rdma' else TID.DISC_IP_PORT)
|
|
)
|
|
sysconf = conf.SysConf()
|
|
self._host_traddr = cid.get('host-traddr', '')
|
|
self._host_iface = '' if conf.SvcConf().ignore_iface else cid.get('host-iface', '')
|
|
self._host_nqn = cid.get('host-nqn', sysconf.hostnqn)
|
|
self._subsysnqn = cid.get('subsysnqn', '')
|
|
self._key = (
|
|
self._transport,
|
|
self._traddr,
|
|
self._trsvcid,
|
|
self._subsysnqn,
|
|
self._host_traddr,
|
|
self._host_iface,
|
|
self._host_nqn,
|
|
)
|
|
self._hash = int.from_bytes(
|
|
hashlib.md5(''.join(self._key).encode('utf-8')).digest(), 'big'
|
|
) # We need a consistent hash between restarts
|
|
self._id = f'({self._transport}, {self._traddr}, {self._trsvcid}{", " + self._subsysnqn if self._subsysnqn else ""}{", " + self._host_iface if self._host_iface else ""}{", " + self._host_traddr if self._host_traddr else ""})' # pylint: disable=line-too-long
|
|
|
|
host_traddr = property(lambda self: self._host_traddr)
|
|
host_iface = property(lambda self: self._host_iface)
|
|
subsysnqn = property(lambda self: self._subsysnqn)
|
|
transport = property(lambda self: self._transport)
|
|
host_nqn = property(lambda self: self._host_nqn)
|
|
trsvcid = property(lambda self: self._trsvcid)
|
|
traddr = property(lambda self: self._traddr)
|
|
cfg = property(lambda self: self._cfg)
|
|
|
|
def as_dict(self):
|
|
'''Return object members as a dictionary'''
|
|
data = {
|
|
'traddr': self.traddr,
|
|
'trsvcid': self.trsvcid,
|
|
'transport': self.transport,
|
|
'subsysnqn': self.subsysnqn,
|
|
'host-iface': self.host_iface,
|
|
'host-traddr': self.host_traddr,
|
|
}
|
|
|
|
# When migrating an old last known config, some members may not
|
|
# exist. Therefore retrieve them with getattr() to avoid a crash.
|
|
cfg = getattr(self, '_cfg', None)
|
|
if cfg:
|
|
data.update(cfg)
|
|
|
|
sysconf = conf.SysConf()
|
|
data['host-nqn'] = getattr(self, '_host_nqn', sysconf.hostnqn)
|
|
|
|
return data
|
|
|
|
def __str__(self):
|
|
return self._id
|
|
|
|
def __repr__(self):
|
|
return self._id
|
|
|
|
def __eq__(self, other):
|
|
return isinstance(other, self.__class__) and self._key == other._key
|
|
|
|
def __ne__(self, other):
|
|
return not isinstance(other, self.__class__) or self._key != other._key
|
|
|
|
def __hash__(self):
|
|
return self._hash
|