diff --git a/python/spdk/sma/qos.py b/python/spdk/sma/qos.py new file mode 100644 index 000000000..ef3d1e02f --- /dev/null +++ b/python/spdk/sma/qos.py @@ -0,0 +1,59 @@ +import grpc + +from spdk.rpc.client import JSONRPCException +from .common import format_volume_id +from .proto import sma_pb2 + + +LIMIT_UNDEFINED = (1 << 64) - 1 + + +class QosException(Exception): + def __init__(self, code, message): + self.code = code + self.message = message + + +def set_volume_bdev_qos(client, params): + class BdevLimit: + def __init__(self, name, transform=lambda v: v): + self.name = name + self._transform = transform + + def get_value(self, value): + return self._transform(value) + + supported_limits = { + 'rw_iops': BdevLimit('rw_ios_per_sec', lambda v: v * 1000), + 'rd_bandwidth': BdevLimit('r_mbytes_per_sec'), + 'wr_bandwidth': BdevLimit('w_mbytes_per_sec'), + 'rw_bandwidth': BdevLimit('rw_mbytes_per_sec') + } + # Check that none of the unsupported fields aren't set either + if params.HasField('maximum'): + for field, value in params.maximum.ListFields(): + if field.name in supported_limits.keys(): + continue + if value != 0 and value != LIMIT_UNDEFINED: + raise QosException(grpc.StatusCode.INVALID_ARGUMENT, + f'Unsupported QoS limit: maximum.{field.name}') + try: + rpc_params = {'name': format_volume_id(params.volume_id)} + for name, limit in supported_limits.items(): + value = getattr(params.maximum, name) + if value != LIMIT_UNDEFINED: + rpc_params[limit.name] = limit.get_value(value) + client.call('bdev_set_qos_limit', rpc_params) + except JSONRPCException: + raise QosException(grpc.StatusCode.INTERNAL, 'Failed to set QoS') + + +def get_bdev_qos_capabilities(): + return sma_pb2.GetQosCapabilitiesResponse( + max_volume_caps=sma_pb2.GetQosCapabilitiesResponse.QosCapabilities( + rw_iops=True, + rw_bandwidth=True, + rd_bandwidth=True, + wr_bandwidth=True + ), + )