未验证 提交 1e540b0f 编写于 作者: Y YongxueHong 提交者: GitHub

Merge pull request #2295 from zhencliu/nbd_export

Support nbd image export with internal server and qemu-nbd
"""
Module for providing interfaces for exporting local image with
qemu-nbd and qemu internal nbd server.
Available classes:
- QemuNBDExportImage: Export local image with qemu-nbd
- InternalNBDExportImage: Export image with vm qemu internal nbd server
Available methods:
- create_image: Create a local image with qemu-img or
with user defined command
- export_image: Export the local image
- stop_export: Stop exporting image
- list_exported_image: List nbd image with qemu-nbd
- hotplug_tls: Hotplug tls creds object for internal nbd server
- hotplug_image: Hotplug local image to be exported
- get_export_name: Get export name for internal nbd export
- start_nbd_server: Start internal nbd server
- add_nbd_image: Add image to internal nbd server
- remove_nbd_image: Remove image from internal nbd server
- stop_nbd_server: Stop internal nbd server
"""
import os
import signal
import logging
from avocado.utils import process
from avocado.core import exceptions
from virttest import nbd
from virttest import data_dir
from virttest import qemu_storage
from virttest import utils_misc
from virttest import qemu_devices
class NBDExportImage(object):
"""NBD local image export base class"""
def __init__(self, params, local_image):
"""
Initialize object.
:param local_image: local image tag
:param params: dictionary containing all test parameters.
"""
self._tag = local_image
self._params = params
self._image_params = self._params.object_params(self._tag)
def create_image(self):
if self._image_params.get('create_image_cmd'):
result = process.run(self._image_params['create_image_cmd'],
ignore_status=True, shell=True)
elif not self._image_params.get_boolean("force_create_image"):
_, result = qemu_storage.QemuImg(self._image_params,
data_dir.get_data_dir(),
self._tag).create(self._params)
if result.exit_status != 0:
raise exceptions.TestFail('Failed to create image, error: %s'
% result.stderr.decode())
def export_image(self):
raise NotImplementedError()
def stop_export(self):
raise NotImplementedError()
class QemuNBDExportImage(NBDExportImage):
"""Export local image with qemu-nbd command"""
def __init__(self, params, local_image):
super(QemuNBDExportImage, self).__init__(params, local_image)
self._qemu_nbd = utils_misc.get_qemu_nbd_binary(self._params)
filename_repr = 'json' if self._image_params.get(
'nbd_export_format') == 'luks' else 'filename'
self._local_filename = qemu_storage.get_image_repr(
self._tag, self._image_params,
data_dir.get_data_dir(), filename_repr)
self._nbd_server_pid = None
def export_image(self):
logging.info("Export image with qemu-nbd")
self._nbd_server_pid = nbd.export_image(self._qemu_nbd,
self._local_filename,
self._tag, self._image_params)
if self._nbd_server_pid is None:
raise exceptions.TestFail('Failed to export image')
def list_exported_image(self, nbd_image, nbd_image_params):
logging.info("List the nbd image with qemu-nbd")
result = nbd.list_exported_image(self._qemu_nbd, nbd_image,
nbd_image_params)
if result.exit_status != 0:
raise exceptions.TestFail('Failed to list nbd image: %s'
% result.stderr.decode())
def stop_export(self):
if self._nbd_server_pid is not None:
try:
# when qemu-nbd crashes unexpectedly, we can handle it
os.kill(self._nbd_server_pid, signal.SIGKILL)
except Exception as e:
logging.warn("Error occurred when killing nbd server: %s"
% str(e))
finally:
self._nbd_server_pid = None
class InternalNBDExportImage(NBDExportImage):
"""Export image with qemu internal nbd server"""
def __init__(self, vm, params, local_image):
super(InternalNBDExportImage, self).__init__(params, local_image)
self._tls_creds_id = None
self._node_name = None
self._image_devices = None
self._vm = vm
def get_export_name(self):
"""export name is the node name if nbd_export_name is not set"""
return self._image_params['nbd_export_name'] if self._image_params.get(
'nbd_export_name') else self._node_name
def hotplug_image(self):
"""Hotplug the image to be exported"""
devices = self._vm.devices.images_define_by_params(self._tag,
self._image_params,
'disk')
# Only hotplug protocol and format node and the related objects
devices.pop()
self._node_name = devices[-1].get_qid()
self._image_devices = devices
logging.info("Plug devices(without image device driver)")
for dev in devices:
ret = self._vm.devices.simple_hotplug(dev, self._vm.monitor)
if not ret[1]:
raise exceptions.TestFail("Failed to hotplug device '%s': %s."
% (dev, ret[0]))
def hotplug_tls(self):
"""Hotplug tls creds object for nbd server"""
if self._image_params.get('nbd_unix_socket'):
logging.info('TLS is only supported with IP')
elif self._image_params.get('nbd_server_tls_creds'):
logging.info("Plug server tls creds device")
self._tls_creds_id = '%s_server_tls_creds' % self._tag
dev = qemu_devices.qdevices.QObject('tls-creds-x509')
dev.set_param("id", self._tls_creds_id)
dev.set_param("endpoint", "server")
dev.set_param("dir", self._image_params['nbd_server_tls_creds'])
ret = self._vm.devices.simple_hotplug(dev, self._vm.monitor)
if not ret[1]:
raise exceptions.TestFail("Failed to hotplug device '%s': %s."
% (dev, ret[0]))
def start_nbd_server(self):
"""Start internal nbd server"""
server = {
'type': 'unix',
'path': self._image_params['nbd_unix_socket']
} if self._image_params.get('nbd_unix_socket') else {
'type': 'inet',
'host': '0.0.0.0',
'port': self._image_params.get('nbd_port', '10809')
}
logging.info("Start internal nbd server")
return self._vm.monitor.nbd_server_start(server, self._tls_creds_id)
def add_nbd_image(self, node_name=None):
"""
Add an image(to be exported) to internal nbd server.
:param node_name: block node name, the node might be hotplugged
by other utils, or the node has already been
present in VM.
"""
if node_name:
self._node_name = node_name
logging.info("Add image node to nbd server")
return self._vm.monitor.nbd_server_add(
self._node_name,
self._image_params.get('nbd_export_name'),
self._image_params.get('nbd_export_writable'),
self._image_params.get('nbd_export_bitmap'))
def remove_nbd_image(self):
"""Remove the exported image from internal nbd server"""
logging.info("Remove image from nbd server")
return self._vm.monitor.nbd_server_remove(
self.get_export_name(),
self._image_params.get('nbd_remove_mode')
)
def stop_nbd_server(self):
"""Stop internal nbd server, it also unregisters all devices"""
logging.info("Stop nbd server")
return self._vm.monitor.nbd_server_stop()
def export_image(self):
"""
For internal nbd server, in order to export an image, start the
internal nbd server first, then add a local image to server.
"""
self.start_nbd_server()
self.add_nbd_image()
def stop_export(self):
self.remove_nbd_image()
self.stop_nbd_server()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册