sma: volume attach/detach
This patch implements the Volume(Attach|Detach) methods. Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com> Change-Id: I639f1e7b6d4d5a3e52795f9c8b1ae890407e2375 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/10277 Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
2ea8747935
commit
ae60344eb7
@ -1,5 +1,6 @@
|
|||||||
import grpc
|
import grpc
|
||||||
import logging
|
import logging
|
||||||
|
import uuid
|
||||||
from spdk.rpc.client import JSONRPCException
|
from spdk.rpc.client import JSONRPCException
|
||||||
from .device import DeviceManager, DeviceException
|
from .device import DeviceManager, DeviceException
|
||||||
from ..common import format_volume_id
|
from ..common import format_volume_id
|
||||||
@ -124,5 +125,80 @@ class NvmfTcpDeviceManager(DeviceManager):
|
|||||||
else:
|
else:
|
||||||
logging.info(f'Tried to delete a non-existing device: {nqn}')
|
logging.info(f'Tried to delete a non-existing device: {nqn}')
|
||||||
|
|
||||||
|
def _find_bdev(self, client, guid):
|
||||||
|
try:
|
||||||
|
return client.call('bdev_get_bdevs', {'name': guid})[0]
|
||||||
|
except JSONRPCException:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@_check_transport
|
||||||
|
def attach_volume(self, request):
|
||||||
|
nqn = self._get_nqn_from_handle(request.device_handle)
|
||||||
|
volume_id = format_volume_id(request.volume.volume_id)
|
||||||
|
if volume_id is None:
|
||||||
|
raise DeviceException(grpc.StatusCode.INVALID_ARGUMENT,
|
||||||
|
'Invalid volume ID')
|
||||||
|
try:
|
||||||
|
with self._client() as client:
|
||||||
|
bdev = self._find_bdev(client, volume_id)
|
||||||
|
if bdev is None:
|
||||||
|
raise DeviceException(grpc.StatusCode.NOT_FOUND,
|
||||||
|
'Invalid volume GUID')
|
||||||
|
subsystems = client.call('nvmf_get_subsystems')
|
||||||
|
for subsys in subsystems:
|
||||||
|
if subsys['nqn'] == nqn:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise DeviceException(grpc.StatusCode.NOT_FOUND,
|
||||||
|
'Invalid device handle')
|
||||||
|
if bdev['name'] not in [ns['name'] for ns in subsys['namespaces']]:
|
||||||
|
result = client.call('nvmf_subsystem_add_ns',
|
||||||
|
{'nqn': nqn,
|
||||||
|
'namespace': {
|
||||||
|
'bdev_name': bdev['name']}})
|
||||||
|
if not result:
|
||||||
|
raise DeviceException(grpc.StatusCode.INTERNAL,
|
||||||
|
'Failed to attach volume')
|
||||||
|
except JSONRPCException:
|
||||||
|
raise DeviceException(grpc.StatusCode.INTERNAL,
|
||||||
|
'Failed to attach volume')
|
||||||
|
|
||||||
|
@_check_transport
|
||||||
|
def detach_volume(self, request):
|
||||||
|
nqn = self._get_nqn_from_handle(request.device_handle)
|
||||||
|
volume = format_volume_id(request.volume_id)
|
||||||
|
if volume is None:
|
||||||
|
raise DeviceException(grpc.StatusCode.INVALID_ARGUMENT,
|
||||||
|
'Invalid volume ID')
|
||||||
|
try:
|
||||||
|
with self._client() as client:
|
||||||
|
bdev = self._find_bdev(client, volume)
|
||||||
|
if bdev is None:
|
||||||
|
logging.info(f'Tried to detach non-existing volume: {volume}')
|
||||||
|
return
|
||||||
|
|
||||||
|
subsystems = client.call('nvmf_get_subsystems')
|
||||||
|
for subsys in subsystems:
|
||||||
|
if subsys['nqn'] == nqn:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
logging.info(f'Tried to detach volume: {volume} from non-existing ' +
|
||||||
|
f'device: {nqn}')
|
||||||
|
return
|
||||||
|
|
||||||
|
for ns in subsys['namespaces']:
|
||||||
|
if ns['name'] != bdev['name']:
|
||||||
|
continue
|
||||||
|
result = client.call('nvmf_subsystem_remove_ns',
|
||||||
|
{'nqn': nqn,
|
||||||
|
'nsid': ns['nsid']})
|
||||||
|
if not result:
|
||||||
|
raise DeviceException(grpc.StatusCode.INTERNAL,
|
||||||
|
'Failed to detach volume')
|
||||||
|
break
|
||||||
|
except JSONRPCException:
|
||||||
|
raise DeviceException(grpc.StatusCode.INTERNAL,
|
||||||
|
'Failed to detach volume')
|
||||||
|
|
||||||
def owns_device(self, handle):
|
def owns_device(self, handle):
|
||||||
return handle.startswith('nvmf-tcp')
|
return handle.startswith('nvmf-tcp')
|
||||||
|
@ -73,3 +73,31 @@ class StorageManagementAgent(pb2_grpc.StorageManagementAgentServicer):
|
|||||||
context.set_details('Method is not implemented by selected device type')
|
context.set_details('Method is not implemented by selected device type')
|
||||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@_grpc_method
|
||||||
|
def AttachVolume(self, request, context):
|
||||||
|
response = pb2.AttachVolumeResponse()
|
||||||
|
try:
|
||||||
|
device = self._find_device_by_handle(request.device_handle)
|
||||||
|
if device is None:
|
||||||
|
raise DeviceException(grpc.StatusCode.NOT_FOUND, 'Invalid device handle')
|
||||||
|
device.attach_volume(request)
|
||||||
|
except DeviceException as ex:
|
||||||
|
context.set_details(ex.message)
|
||||||
|
context.set_code(ex.code)
|
||||||
|
except NotImplementedError:
|
||||||
|
context.set_details('Method is not implemented by selected device type')
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
return response
|
||||||
|
|
||||||
|
@_grpc_method
|
||||||
|
def DetachVolume(self, request, context):
|
||||||
|
response = pb2.DetachVolumeResponse()
|
||||||
|
try:
|
||||||
|
device = self._find_device_by_handle(request.device_handle)
|
||||||
|
if device is not None:
|
||||||
|
device.detach_volume(request)
|
||||||
|
except DeviceException as ex:
|
||||||
|
context.set_details(ex.message)
|
||||||
|
context.set_code(ex.code)
|
||||||
|
return response
|
||||||
|
Loading…
Reference in New Issue
Block a user