XenAPI: deprecate the config for image handler class path
This commit is to deprecate the config of image_upload_handler which need to be configured with a class path string. And we should make download handler be configurable to be consistent with the upload handler. So it contains the following changes: 1. deprecate the option of "image_upload_handler". 2. added a new option of "image_handler" which will be used to choose a short name from the supported image handler plugins. The proper handler will be loaded at runtime basing on the option setting. TODO(jianghuaw): For the legacy handler of VdiThroughDevStore which has no download function implemented. For downloading, it is handled in a different way (call xenapi.vm_utils._stream_disk()). We keep it as it is now. In the future, we should consider to move _stream_disk to VdiThroughDevStore's download(). Change-Id: I37860e63de32d988525cdc32440fe711777263e6 Blueprint: xenapi-image-handler-option-improvement
This commit is contained in:
parent
dd2232c446
commit
238b89b36e
|
@ -449,7 +449,16 @@ Related options:
|
|||
"""),
|
||||
# TODO(dharinic): Make this, a stevedore plugin
|
||||
cfg.StrOpt('image_upload_handler',
|
||||
default='nova.virt.xenapi.image.glance.GlanceStore',
|
||||
default='',
|
||||
deprecated_for_removal=True,
|
||||
deprecated_since='18.0.0',
|
||||
deprecated_reason="""
|
||||
Instead of setting the class path here, we will use short names
|
||||
to represent image handlers. The download and upload handlers
|
||||
must also be matching. So another new option "image_handler"
|
||||
will be used to set the short name for a specific image handler
|
||||
for both image download and upload.
|
||||
""",
|
||||
help="""
|
||||
Dom0 plugin driver used to handle image uploads.
|
||||
|
||||
|
@ -460,6 +469,25 @@ Images, and snapshots from XenServer need to be uploaded to the data
|
|||
store for use. image_upload_handler takes in a value for the Dom0
|
||||
plugin driver. This driver is then called to uplaod images to the
|
||||
GlanceStore.
|
||||
"""),
|
||||
cfg.StrOpt('image_handler',
|
||||
default='direct_vhd',
|
||||
choices=('direct_vhd', 'vdi_local_dev'),
|
||||
help="""
|
||||
The plugin used to handle image uploads and downloads.
|
||||
|
||||
Provide a short name representing an image driver required to
|
||||
handle the image between compute host and glance.
|
||||
|
||||
Description for the allowed values:
|
||||
* ``direct_vhd``: This plugin directly processes the VHD files in XenServer
|
||||
SR(Storage Repository). So this plugin only works when the host's SR
|
||||
type is file system based e.g. ext, nfs.
|
||||
* ``vdi_local_dev``: This plugin implements an image handler which attaches
|
||||
the instance's VDI as a local disk to the VM where the OpenStack Compute
|
||||
service runs in. It uploads the raw disk to glance when creating image;
|
||||
When booting an instance from a glance image, it downloads the image and
|
||||
streams it into the disk which is attached to the compute VM.
|
||||
"""),
|
||||
]
|
||||
|
||||
|
|
|
@ -689,6 +689,10 @@ class ImageDeleteConflict(NovaException):
|
|||
msg_fmt = _("Conflict deleting image. Reason: %(reason)s.")
|
||||
|
||||
|
||||
class ImageHandlerUnsupported(NovaException):
|
||||
msg_fmt = _("Error: unsupported image handler %(image_handler)s.")
|
||||
|
||||
|
||||
class PreserveEphemeralNotSupported(Invalid):
|
||||
msg_fmt = _("The current driver does not support "
|
||||
"preserving ephemeral partitions.")
|
||||
|
|
|
@ -41,7 +41,8 @@ def stubout_firewall_driver(stubs, conn):
|
|||
|
||||
|
||||
def stubout_instance_snapshot(stubs):
|
||||
def fake_fetch_image(context, session, instance, name_label, image, type):
|
||||
def fake_fetch_image(context, session, instance, name_label, image, type,
|
||||
image_handler):
|
||||
return {'root': dict(uuid=_make_fake_vdi(), file=None),
|
||||
'kernel': dict(uuid=_make_fake_vdi(), file=None),
|
||||
'ramdisk': dict(uuid=_make_fake_vdi(), file=None)}
|
||||
|
|
|
@ -40,6 +40,7 @@ from nova.tests import uuidsentinel as uuids
|
|||
from nova.virt import hardware
|
||||
from nova.virt.xenapi import driver as xenapi_conn
|
||||
from nova.virt.xenapi import fake
|
||||
from nova.virt.xenapi.image import utils as image_utils
|
||||
from nova.virt.xenapi import vm_utils
|
||||
import time
|
||||
|
||||
|
@ -222,6 +223,8 @@ class FetchVhdImageTestCase(VMUtilsTestBase):
|
|||
self.context.auth_token = 'auth_token'
|
||||
self.session = FakeSession()
|
||||
self.instance = {"uuid": "uuid"}
|
||||
self.image_handler = image_utils.get_image_handler(
|
||||
CONF.xenserver.image_handler)
|
||||
self.flags(group='glance', api_servers=['http://localhost:9292'])
|
||||
|
||||
make_uuid_stack_patcher = mock.patch.object(
|
||||
|
@ -274,7 +277,8 @@ class FetchVhdImageTestCase(VMUtilsTestBase):
|
|||
self._stub_glance_download_vhd()
|
||||
|
||||
result = vm_utils._fetch_vhd_image(self.context, self.session,
|
||||
self.instance, 'image_id')
|
||||
self.instance, 'image_id',
|
||||
self.image_handler)
|
||||
|
||||
self.assertEqual("vdi", result['root']['uuid'])
|
||||
mock_safe_find_sr.assert_called_once_with(self.session)
|
||||
|
@ -300,7 +304,7 @@ class FetchVhdImageTestCase(VMUtilsTestBase):
|
|||
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
vm_utils._fetch_vhd_image, self.context, self.session,
|
||||
self.instance, 'image_id')
|
||||
self.instance, 'image_id', self.image_handler)
|
||||
|
||||
mock_safe_find_sr.assert_called_once_with(self.session)
|
||||
mock_scan_sr.assert_called_once_with(self.session, "sr")
|
||||
|
@ -315,7 +319,8 @@ class FetchVhdImageTestCase(VMUtilsTestBase):
|
|||
self._stub_glance_download_vhd(raise_exc=RuntimeError)
|
||||
|
||||
self.assertRaises(RuntimeError, vm_utils._fetch_vhd_image,
|
||||
self.context, self.session, self.instance, 'image_id')
|
||||
self.context, self.session, self.instance, 'image_id',
|
||||
self.image_handler)
|
||||
self._assert_call_plugin_serialized_with_retry()
|
||||
self._assert_make_uuid_stack_and_get_sr_path()
|
||||
|
||||
|
@ -549,7 +554,8 @@ class CreateCachedImageTestCase(VMUtilsTestBase):
|
|||
self.assertEqual((False, {'root': {'uuid': 'vdi_uuid', 'file': None}}),
|
||||
vm_utils._create_cached_image('context', self.session,
|
||||
'instance', 'name', 'uuid',
|
||||
vm_utils.ImageType.DISK_VHD))
|
||||
vm_utils.ImageType.DISK_VHD,
|
||||
'image_handler'))
|
||||
|
||||
@mock.patch.object(vm_utils, '_safe_copy_vdi', return_value='new_vdi_ref')
|
||||
def test_no_cow(self, mock_safe_copy_vdi, mock_safe_find_sr):
|
||||
|
@ -559,7 +565,8 @@ class CreateCachedImageTestCase(VMUtilsTestBase):
|
|||
self.assertEqual((False, {'root': {'uuid': 'vdi_uuid', 'file': None}}),
|
||||
vm_utils._create_cached_image('context', self.session,
|
||||
'instance', 'name', 'uuid',
|
||||
vm_utils.ImageType.DISK_VHD))
|
||||
vm_utils.ImageType.DISK_VHD,
|
||||
'image_handler'))
|
||||
|
||||
def test_no_cow_no_ext(self, mock_safe_find_sr):
|
||||
self.flags(use_cow_images=False)
|
||||
|
@ -569,7 +576,8 @@ class CreateCachedImageTestCase(VMUtilsTestBase):
|
|||
self.assertEqual((False, {'root': {'uuid': 'vdi_uuid', 'file': None}}),
|
||||
vm_utils._create_cached_image('context', self.session,
|
||||
'instance', 'name', 'uuid',
|
||||
vm_utils.ImageType.DISK_VHD))
|
||||
vm_utils.ImageType.DISK_VHD,
|
||||
'image_handler'))
|
||||
|
||||
@mock.patch.object(vm_utils, '_clone_vdi', return_value='new_vdi_ref')
|
||||
@mock.patch.object(vm_utils, '_fetch_image',
|
||||
|
@ -583,7 +591,8 @@ class CreateCachedImageTestCase(VMUtilsTestBase):
|
|||
self.assertEqual((True, {'root': {'uuid': 'vdi_uuid', 'file': None}}),
|
||||
vm_utils._create_cached_image('context', self.session,
|
||||
'instance', 'name', 'uuid',
|
||||
vm_utils.ImageType.DISK_VHD))
|
||||
vm_utils.ImageType.DISK_VHD,
|
||||
'image_handler'))
|
||||
|
||||
|
||||
class DestroyCachedImageTestCase(VMUtilsTestBase):
|
||||
|
@ -909,7 +918,8 @@ class VDIOtherConfigTestCase(VMUtilsTestBase):
|
|||
self.session.VDI_get_other_config = lambda vdi: {}
|
||||
|
||||
vm_utils.create_image(self.context, self.session, self.fake_instance,
|
||||
'myvdi', 'image1', vm_utils.ImageType.DISK_VHD)
|
||||
'myvdi', 'image1', vm_utils.ImageType.DISK_VHD,
|
||||
'image_handler')
|
||||
|
||||
expected = {'nova_disk_type': 'root',
|
||||
'nova_instance_uuid': 'aaaa-bbbb-cccc-dddd'}
|
||||
|
|
|
@ -25,6 +25,8 @@ except ImportError:
|
|||
from eventlet import greenthread
|
||||
import mock
|
||||
from os_xenapi.client import host_xenstore
|
||||
from oslo_utils import importutils
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
|
||||
from nova.compute import power_state
|
||||
|
@ -43,6 +45,7 @@ from nova import utils
|
|||
from nova.virt import fake
|
||||
from nova.virt.xenapi import agent as xenapi_agent
|
||||
from nova.virt.xenapi import fake as xenapi_fake
|
||||
from nova.virt.xenapi.image import utils as image_utils
|
||||
from nova.virt.xenapi import vm_utils
|
||||
from nova.virt.xenapi import vmops
|
||||
from nova.virt.xenapi import volume_utils
|
||||
|
@ -218,6 +221,88 @@ class VMOpsTestCase(VMOpsTestBase):
|
|||
try_auto_config.assert_called_once_with(self._vmops._session,
|
||||
'fake-ref', instance.flavor.root_gb)
|
||||
|
||||
@mock.patch.object(vm_utils, 'snapshot_attached_here')
|
||||
@mock.patch.object(timeutils, 'delta_seconds')
|
||||
@mock.patch.object(timeutils, 'utcnow')
|
||||
@mock.patch.object(image_utils, 'get_image_handler')
|
||||
def test_snapshot_using_image_handler(self,
|
||||
mock_get_image_handler,
|
||||
mock_utcnow,
|
||||
mock_delta_seconds,
|
||||
mock_snapshot_attached_here):
|
||||
mock_utcnow.side_effect = ['fake_start', 'fake_end']
|
||||
self.flags(image_handler='direct_vhd', group='xenserver')
|
||||
mock_get_image_handler.return_value = mock.Mock()
|
||||
|
||||
class FakeVdiUuid(object):
|
||||
def __enter__(self):
|
||||
pass
|
||||
|
||||
def __exit__(self, Type, value, traceback):
|
||||
pass
|
||||
|
||||
fake_vdi_uuid = FakeVdiUuid()
|
||||
mock_snapshot_attached_here.return_value = fake_vdi_uuid
|
||||
self._setup_mock_vmops()
|
||||
vmops = self._vmops
|
||||
with mock.patch.object(vmops, '_get_vm_opaque_ref',
|
||||
return_value='fake_ref') as mock_get_opa_ref:
|
||||
fake_instance = {'name': 'fake_name'}
|
||||
|
||||
vmops.snapshot('fake_ctx', fake_instance, 'fake_image_id',
|
||||
mock.Mock())
|
||||
|
||||
vmops.image_handler.upload_image.assert_called_once_with(
|
||||
'fake_ctx', vmops._session, fake_instance,
|
||||
'fake_image_id', None)
|
||||
mock_get_opa_ref.assert_called_once_with(fake_instance)
|
||||
mock_delta_seconds.assert_called_once_with('fake_start',
|
||||
'fake_end')
|
||||
self.assertEqual(mock_utcnow.call_count, 2)
|
||||
|
||||
@mock.patch.object(vm_utils, 'snapshot_attached_here')
|
||||
@mock.patch.object(timeutils, 'delta_seconds')
|
||||
@mock.patch.object(timeutils, 'utcnow')
|
||||
@mock.patch.object(image_utils, 'get_image_handler')
|
||||
@mock.patch.object(importutils, 'import_object')
|
||||
def test_snapshot_using_upload_image_handler(self,
|
||||
mock_import_object,
|
||||
mock_get_image_handler,
|
||||
mock_utcnow,
|
||||
mock_delta_seconds,
|
||||
mock_snapshot_attached_here):
|
||||
mock_utcnow.side_effect = ['fake_start', 'fake_end']
|
||||
self.flags(image_upload_handler='image_upload_handler',
|
||||
group='xenserver')
|
||||
mock_get_image_handler.return_value = mock.Mock()
|
||||
|
||||
class FakeVdiUuid(object):
|
||||
def __enter__(self):
|
||||
pass
|
||||
|
||||
def __exit__(self, Type, value, traceback):
|
||||
pass
|
||||
|
||||
fake_vdi_uuid = FakeVdiUuid()
|
||||
mock_snapshot_attached_here.return_value = fake_vdi_uuid
|
||||
mock_import_object.return_value = mock.Mock()
|
||||
self._setup_mock_vmops()
|
||||
vmops = self._vmops
|
||||
with mock.patch.object(vmops, '_get_vm_opaque_ref',
|
||||
return_value='fake_ref') as mock_get_opa_ref:
|
||||
fake_instance = {'name': 'fake_name'}
|
||||
|
||||
vmops.snapshot('fake_ctx', fake_instance, 'fake_image_id',
|
||||
mock.Mock())
|
||||
|
||||
vmops.image_upload_handler.upload_image.assert_called_once_with(
|
||||
'fake_ctx', vmops._session, fake_instance,
|
||||
'fake_image_id', None)
|
||||
mock_get_opa_ref.assert_called_once_with(fake_instance)
|
||||
mock_delta_seconds.assert_called_once_with('fake_start',
|
||||
'fake_end')
|
||||
self.assertEqual(mock_utcnow.call_count, 2)
|
||||
|
||||
|
||||
class InjectAutoDiskConfigTestCase(VMOpsTestBase):
|
||||
def test_inject_auto_disk_config_when_present(self):
|
||||
|
|
|
@ -16,11 +16,23 @@
|
|||
import shutil
|
||||
import tarfile
|
||||
|
||||
from oslo_utils import importutils
|
||||
|
||||
from nova import exception
|
||||
from nova import image
|
||||
|
||||
_VDI_FORMAT_RAW = 1
|
||||
|
||||
IMAGE_API = image.API()
|
||||
IMAGE_HANDLERS = {'direct_vhd': 'glance.GlanceStore',
|
||||
'vdi_local_dev': 'vdi_through_dev.VdiThroughDevStore'}
|
||||
|
||||
|
||||
def get_image_handler(handler_name):
|
||||
if handler_name not in IMAGE_HANDLERS:
|
||||
raise exception.ImageHandlerUnsupported(image_handler=handler_name)
|
||||
return importutils.import_object('nova.virt.xenapi.image.'
|
||||
'%s' % IMAGE_HANDLERS[handler_name])
|
||||
|
||||
|
||||
class GlanceImage(object):
|
||||
|
|
|
@ -34,7 +34,6 @@ from os_xenapi.client import vm_management
|
|||
from oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import importutils
|
||||
from oslo_utils import strutils
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import units
|
||||
|
@ -1227,7 +1226,7 @@ def _get_image_vdi_label(image_id):
|
|||
|
||||
|
||||
def _create_cached_image(context, session, instance, name_label,
|
||||
image_id, image_type):
|
||||
image_id, image_type, image_handler):
|
||||
sr_ref = safe_find_sr(session)
|
||||
sr_type = session.call_xenapi('SR.get_type', sr_ref)
|
||||
|
||||
|
@ -1244,7 +1243,7 @@ def _create_cached_image(context, session, instance, name_label,
|
|||
if cache_vdi_ref is None:
|
||||
downloaded = True
|
||||
vdis = _fetch_image(context, session, instance, name_label,
|
||||
image_id, image_type)
|
||||
image_id, image_type, image_handler)
|
||||
|
||||
cache_vdi_ref = session.call_xenapi(
|
||||
'VDI.get_by_uuid', vdis['root']['uuid'])
|
||||
|
@ -1289,7 +1288,7 @@ def _create_cached_image(context, session, instance, name_label,
|
|||
|
||||
|
||||
def create_image(context, session, instance, name_label, image_id,
|
||||
image_type):
|
||||
image_type, image_handler):
|
||||
"""Creates VDI from the image stored in the local cache. If the image
|
||||
is not present in the cache, it streams it from glance.
|
||||
|
||||
|
@ -1320,10 +1319,10 @@ def create_image(context, session, instance, name_label, image_id,
|
|||
if cache:
|
||||
downloaded, vdis = _create_cached_image(context, session, instance,
|
||||
name_label, image_id,
|
||||
image_type)
|
||||
image_type, image_handler)
|
||||
else:
|
||||
vdis = _fetch_image(context, session, instance, name_label,
|
||||
image_id, image_type)
|
||||
image_id, image_type, image_handler)
|
||||
downloaded = True
|
||||
duration = timeutils.delta_seconds(start_time, timeutils.utcnow())
|
||||
|
||||
|
@ -1341,14 +1340,16 @@ def create_image(context, session, instance, name_label, image_id,
|
|||
return vdis
|
||||
|
||||
|
||||
def _fetch_image(context, session, instance, name_label, image_id, image_type):
|
||||
def _fetch_image(context, session, instance, name_label, image_id, image_type,
|
||||
image_handler):
|
||||
"""Fetch image from glance based on image type.
|
||||
|
||||
Returns: A single filename if image_type is KERNEL or RAMDISK
|
||||
A list of dictionaries that describe VDIs, otherwise
|
||||
"""
|
||||
if image_type == ImageType.DISK_VHD:
|
||||
vdis = _fetch_vhd_image(context, session, instance, image_id)
|
||||
vdis = _fetch_vhd_image(context, session, instance, image_id,
|
||||
image_handler)
|
||||
else:
|
||||
if CONF.xenserver.independent_compute:
|
||||
raise exception.NotSupportedWithOption(
|
||||
|
@ -1375,12 +1376,6 @@ def _make_uuid_stack():
|
|||
return [uuidutils.generate_uuid() for i in range(MAX_VDI_CHAIN_SIZE)]
|
||||
|
||||
|
||||
def _default_download_handler():
|
||||
# TODO(sirp): This should be configurable like upload_handler
|
||||
return importutils.import_object(
|
||||
'nova.virt.xenapi.image.glance.GlanceStore')
|
||||
|
||||
|
||||
def get_compression_level():
|
||||
level = CONF.xenserver.image_compression_level
|
||||
if level is not None and (level < 1 or level > 9):
|
||||
|
@ -1389,20 +1384,15 @@ def get_compression_level():
|
|||
return level
|
||||
|
||||
|
||||
def _fetch_vhd_image(context, session, instance, image_id):
|
||||
def _fetch_vhd_image(context, session, instance, image_id, image_handler):
|
||||
"""Tell glance to download an image and put the VHDs into the SR
|
||||
|
||||
Returns: A list of dictionaries that describe VDIs
|
||||
"""
|
||||
LOG.debug("Asking xapi to fetch vhd image %s", image_id,
|
||||
instance=instance)
|
||||
|
||||
handler = _default_download_handler()
|
||||
|
||||
try:
|
||||
vdis = handler.download_image(context, session, instance, image_id)
|
||||
except Exception:
|
||||
raise
|
||||
vdis = image_handler.download_image(
|
||||
context, session, instance, image_id)
|
||||
|
||||
# Ensure we can see the import VHDs as VDIs
|
||||
scan_default_sr(session)
|
||||
|
|
|
@ -57,6 +57,7 @@ from nova.virt import configdrive
|
|||
from nova.virt import driver as virt_driver
|
||||
from nova.virt import firewall
|
||||
from nova.virt.xenapi import agent as xapi_agent
|
||||
from nova.virt.xenapi.image import utils as image_utils
|
||||
from nova.virt.xenapi import vm_utils
|
||||
from nova.virt.xenapi import volume_utils
|
||||
from nova.virt.xenapi import volumeops
|
||||
|
@ -150,10 +151,22 @@ class VMOps(object):
|
|||
self.vif_driver = vif_impl(xenapi_session=self._session)
|
||||
self.default_root_dev = '/dev/sda'
|
||||
|
||||
LOG.debug("Importing image upload handler: %s",
|
||||
CONF.xenserver.image_upload_handler)
|
||||
self.image_upload_handler = importutils.import_object(
|
||||
CONF.xenserver.image_upload_handler)
|
||||
image_handler_cfg = CONF.xenserver.image_handler
|
||||
self.image_handler = image_utils.get_image_handler(image_handler_cfg)
|
||||
# TODO(jianghuaw): Remove these lines relative to the deprecated
|
||||
# option of "image_upload_handler" in the next release - Stein.
|
||||
self.image_upload_handler = None
|
||||
image_upload_handler_cfg = CONF.xenserver.image_upload_handler
|
||||
if image_upload_handler_cfg:
|
||||
# If *image_upload_handler* is explicitly configured, it
|
||||
# means it indends to use non-default image upload handler.
|
||||
# In order to avoid mis-using the default image_handler which
|
||||
# may have different behavor than the explicitly configured
|
||||
# handler, we keep using *image_upload_handler*.
|
||||
LOG.warning("Deprecated: importing image upload handler: %s",
|
||||
image_upload_handler_cfg)
|
||||
self.image_upload_handler = importutils.import_object(
|
||||
image_upload_handler_cfg)
|
||||
|
||||
def agent_enabled(self, instance):
|
||||
if CONF.xenserver.disable_agent:
|
||||
|
@ -356,8 +369,9 @@ class VMOps(object):
|
|||
# If we didn't get a root VDI from volumes,
|
||||
# then use the Glance image as the root device
|
||||
if 'root' not in vdis:
|
||||
create_image_vdis = vm_utils.create_image(context, self._session,
|
||||
instance, name_label, image_meta.id, image_type)
|
||||
create_image_vdis = vm_utils.create_image(
|
||||
context, self._session, instance, name_label, image_meta.id,
|
||||
image_type, self.image_handler)
|
||||
vdis.update(create_image_vdis)
|
||||
|
||||
# Fetch VDI refs now so we don't have to fetch the ref multiple times
|
||||
|
@ -1029,12 +1043,23 @@ class VMOps(object):
|
|||
post_snapshot_callback=update_task_state) as vdi_uuids:
|
||||
update_task_state(task_state=task_states.IMAGE_UPLOADING,
|
||||
expected_state=task_states.IMAGE_PENDING_UPLOAD)
|
||||
self.image_upload_handler.upload_image(context,
|
||||
self._session,
|
||||
instance,
|
||||
image_id,
|
||||
vdi_uuids,
|
||||
)
|
||||
if self.image_upload_handler:
|
||||
# TODO(jianghuaw): remove this branch once the
|
||||
# deprecated option of "image_upload_handler"
|
||||
# gets removed in the next release - Stein.
|
||||
self.image_upload_handler.upload_image(context,
|
||||
self._session,
|
||||
instance,
|
||||
image_id,
|
||||
vdi_uuids,
|
||||
)
|
||||
else:
|
||||
self.image_handler.upload_image(context,
|
||||
self._session,
|
||||
instance,
|
||||
image_id,
|
||||
vdi_uuids,
|
||||
)
|
||||
|
||||
duration = timeutils.delta_seconds(start_time, timeutils.utcnow())
|
||||
LOG.debug("Finished snapshot and upload for VM, duration: "
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Add a new option of ``image_handler`` in the ``xenapi`` section for
|
||||
configuring the image handler plugin which will be used by XenServer
|
||||
to download or upload images. The value for this option should be a
|
||||
short name representing a supported handler.
|
||||
|
||||
The following are the short names and description of the plugins which
|
||||
they represent:
|
||||
|
||||
* ``direct_vhd``
|
||||
|
||||
This plugin directly processes the VHD files in XenServer SR(Storage
|
||||
Repository). So this plugin only works when the host's SR type is
|
||||
file system based e.g. ext, nfs. This is the default plugin.
|
||||
|
||||
* ``vdi_local_dev``
|
||||
|
||||
This plugin implements an image upload method which attaches the VDI
|
||||
as a local disk in the VM in which the OpenStack Compute service runs.
|
||||
It uploads the raw disk to glance when creating an image; When booting
|
||||
an instance from a glance image, it downloads the image and streams it
|
||||
into the disk which is attached to the compute VM.
|
||||
|
||||
deprecations:
|
||||
- |
|
||||
The ``image_upload_handler`` option in the ``xenserver`` conf section
|
||||
has been deprecated. Please use the new option of ``image_handler`` to
|
||||
configure the image handler which is used to download or upload images.
|
Loading…
Reference in New Issue