Merge "Remove XenAPI driver"
This commit is contained in:
commit
3120df1745
@ -1,507 +0,0 @@
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import contextlib
|
||||
|
||||
import mock
|
||||
import mox
|
||||
import six
|
||||
|
||||
from cinder.db import api as db_api
|
||||
from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.volume import configuration as conf
|
||||
from cinder.volume.drivers.xenapi import lib
|
||||
from cinder.volume.drivers.xenapi import sm as driver
|
||||
from cinder.volume.drivers.xenapi import tools
|
||||
|
||||
|
||||
class MockContext(object):
|
||||
def __init__(ctxt, auth_token):
|
||||
ctxt.auth_token = auth_token
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def simple_context(value):
|
||||
yield value
|
||||
|
||||
|
||||
def get_configured_driver(server='ignore_server', path='ignore_path'):
|
||||
configuration = mox.MockObject(conf.Configuration)
|
||||
configuration.xenapi_nfs_server = server
|
||||
configuration.xenapi_nfs_serverpath = path
|
||||
configuration.append_config_values(mox.IgnoreArg())
|
||||
configuration.volume_dd_blocksize = '1M'
|
||||
return driver.XenAPINFSDriver(configuration=configuration)
|
||||
|
||||
|
||||
class DriverTestCase(test.TestCase):
|
||||
|
||||
def assert_flag(self, flagname):
|
||||
self.assertTrue(hasattr(driver.CONF, flagname))
|
||||
|
||||
def test_config_options(self):
|
||||
self.assert_flag('xenapi_connection_url')
|
||||
self.assert_flag('xenapi_connection_username')
|
||||
self.assert_flag('xenapi_connection_password')
|
||||
self.assert_flag('xenapi_nfs_server')
|
||||
self.assert_flag('xenapi_nfs_serverpath')
|
||||
self.assert_flag('xenapi_sr_base_path')
|
||||
|
||||
def test_do_setup(self):
|
||||
mock = mox.Mox()
|
||||
mock.StubOutWithMock(driver, 'xenapi_lib')
|
||||
mock.StubOutWithMock(driver, 'xenapi_opts')
|
||||
|
||||
configuration = mox.MockObject(conf.Configuration)
|
||||
configuration.xenapi_connection_url = 'url'
|
||||
configuration.xenapi_connection_username = 'user'
|
||||
configuration.xenapi_connection_password = 'pass'
|
||||
configuration.append_config_values(mox.IgnoreArg())
|
||||
|
||||
session_factory = object()
|
||||
nfsops = object()
|
||||
|
||||
driver.xenapi_lib.SessionFactory('url', 'user', 'pass').AndReturn(
|
||||
session_factory)
|
||||
|
||||
driver.xenapi_lib.NFSBasedVolumeOperations(
|
||||
session_factory).AndReturn(nfsops)
|
||||
|
||||
drv = driver.XenAPINFSDriver(configuration=configuration)
|
||||
|
||||
mock.ReplayAll()
|
||||
drv.do_setup('context')
|
||||
mock.VerifyAll()
|
||||
|
||||
self.assertEqual(nfsops, drv.nfs_ops)
|
||||
|
||||
def test_create_volume(self):
|
||||
mock = mox.Mox()
|
||||
|
||||
ops = mock.CreateMock(lib.NFSBasedVolumeOperations)
|
||||
drv = get_configured_driver('server', 'path')
|
||||
drv.nfs_ops = ops
|
||||
|
||||
volume_details = dict(
|
||||
sr_uuid='sr_uuid',
|
||||
vdi_uuid='vdi_uuid'
|
||||
)
|
||||
ops.create_volume(
|
||||
'server', 'path', 1, 'name', 'desc').AndReturn(volume_details)
|
||||
|
||||
mock.ReplayAll()
|
||||
result = drv.create_volume(dict(
|
||||
size=1, display_name='name', display_description='desc'))
|
||||
mock.VerifyAll()
|
||||
|
||||
self.assertEqual(dict(provider_location='sr_uuid/vdi_uuid'), result)
|
||||
|
||||
def test_delete_volume(self):
|
||||
mock = mox.Mox()
|
||||
|
||||
ops = mock.CreateMock(lib.NFSBasedVolumeOperations)
|
||||
drv = get_configured_driver('server', 'path')
|
||||
drv.nfs_ops = ops
|
||||
|
||||
ops.delete_volume('server', 'path', 'sr_uuid', 'vdi_uuid')
|
||||
|
||||
mock.ReplayAll()
|
||||
drv.delete_volume(dict(provider_location='sr_uuid/vdi_uuid'))
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_create_export_does_not_raise_exception(self):
|
||||
configuration = conf.Configuration([])
|
||||
drv = driver.XenAPINFSDriver(configuration=configuration)
|
||||
drv.create_export('context', 'volume')
|
||||
|
||||
def test_remove_export_does_not_raise_exception(self):
|
||||
configuration = conf.Configuration([])
|
||||
drv = driver.XenAPINFSDriver(configuration=configuration)
|
||||
drv.remove_export('context', 'volume')
|
||||
|
||||
def test_initialize_connection(self):
|
||||
mock = mox.Mox()
|
||||
|
||||
drv = get_configured_driver('server', 'path')
|
||||
|
||||
mock.ReplayAll()
|
||||
result = drv.initialize_connection(
|
||||
dict(
|
||||
display_name='name',
|
||||
display_description='desc',
|
||||
provider_location='sr_uuid/vdi_uuid'),
|
||||
'connector'
|
||||
)
|
||||
mock.VerifyAll()
|
||||
|
||||
self.assertEqual(
|
||||
dict(
|
||||
driver_volume_type='xensm',
|
||||
data=dict(
|
||||
name_label='name',
|
||||
name_description='desc',
|
||||
sr_uuid='sr_uuid',
|
||||
vdi_uuid='vdi_uuid',
|
||||
sr_type='nfs',
|
||||
server='server',
|
||||
serverpath='path',
|
||||
introduce_sr_keys=['sr_type', 'server', 'serverpath']
|
||||
)
|
||||
),
|
||||
result
|
||||
)
|
||||
|
||||
def test_initialize_connection_null_values(self):
|
||||
mock = mox.Mox()
|
||||
|
||||
drv = get_configured_driver('server', 'path')
|
||||
|
||||
mock.ReplayAll()
|
||||
result = drv.initialize_connection(
|
||||
dict(
|
||||
display_name=None,
|
||||
display_description=None,
|
||||
provider_location='sr_uuid/vdi_uuid'),
|
||||
'connector'
|
||||
)
|
||||
mock.VerifyAll()
|
||||
|
||||
self.assertEqual(
|
||||
dict(
|
||||
driver_volume_type='xensm',
|
||||
data=dict(
|
||||
name_label='',
|
||||
name_description='',
|
||||
sr_uuid='sr_uuid',
|
||||
vdi_uuid='vdi_uuid',
|
||||
sr_type='nfs',
|
||||
server='server',
|
||||
serverpath='path',
|
||||
introduce_sr_keys=['sr_type', 'server', 'serverpath']
|
||||
)
|
||||
),
|
||||
result
|
||||
)
|
||||
|
||||
def _setup_mock_driver(self, server, serverpath, sr_base_path="_srbp"):
|
||||
mock = mox.Mox()
|
||||
|
||||
drv = get_configured_driver(server, serverpath)
|
||||
ops = mock.CreateMock(lib.NFSBasedVolumeOperations)
|
||||
db = mock.CreateMock(db_api)
|
||||
drv.nfs_ops = ops
|
||||
drv.db = db
|
||||
|
||||
mock.StubOutWithMock(driver, 'CONF')
|
||||
driver.CONF.xenapi_nfs_server = server
|
||||
driver.CONF.xenapi_nfs_serverpath = serverpath
|
||||
driver.CONF.xenapi_sr_base_path = sr_base_path
|
||||
|
||||
return mock, drv
|
||||
|
||||
def test_create_snapshot(self):
|
||||
mock, drv = self._setup_mock_driver('server', 'serverpath')
|
||||
|
||||
snapshot = dict(
|
||||
volume_id="volume-id",
|
||||
display_name="snapshot-name",
|
||||
display_description="snapshot-desc",
|
||||
volume=dict(provider_location="sr-uuid/vdi-uuid"))
|
||||
|
||||
drv.nfs_ops.copy_volume(
|
||||
"server", "serverpath", "sr-uuid", "vdi-uuid",
|
||||
"snapshot-name", "snapshot-desc"
|
||||
).AndReturn(dict(sr_uuid="copied-sr", vdi_uuid="copied-vdi"))
|
||||
|
||||
mock.ReplayAll()
|
||||
result = drv.create_snapshot(snapshot)
|
||||
mock.VerifyAll()
|
||||
self.assertEqual(
|
||||
dict(provider_location="copied-sr/copied-vdi"),
|
||||
result)
|
||||
|
||||
def test_create_volume_from_snapshot(self):
|
||||
mock, drv = self._setup_mock_driver('server', 'serverpath')
|
||||
|
||||
snapshot = dict(
|
||||
provider_location='src-sr-uuid/src-vdi-uuid')
|
||||
volume = dict(
|
||||
display_name='tgt-name', name_description='tgt-desc')
|
||||
|
||||
drv.nfs_ops.copy_volume(
|
||||
"server", "serverpath", "src-sr-uuid", "src-vdi-uuid",
|
||||
"tgt-name", "tgt-desc"
|
||||
).AndReturn(dict(sr_uuid="copied-sr", vdi_uuid="copied-vdi"))
|
||||
|
||||
mock.ReplayAll()
|
||||
result = drv.create_volume_from_snapshot(volume, snapshot)
|
||||
mock.VerifyAll()
|
||||
|
||||
self.assertEqual(
|
||||
dict(provider_location='copied-sr/copied-vdi'), result)
|
||||
|
||||
def test_delete_snapshot(self):
|
||||
mock, drv = self._setup_mock_driver('server', 'serverpath')
|
||||
|
||||
snapshot = dict(
|
||||
provider_location='src-sr-uuid/src-vdi-uuid')
|
||||
|
||||
drv.nfs_ops.delete_volume(
|
||||
"server", "serverpath", "src-sr-uuid", "src-vdi-uuid")
|
||||
|
||||
mock.ReplayAll()
|
||||
drv.delete_snapshot(snapshot)
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_copy_volume_to_image_xenserver_case(self):
|
||||
mock, drv = self._setup_mock_driver(
|
||||
'server', 'serverpath', '/var/run/sr-mount')
|
||||
|
||||
mock.StubOutWithMock(drv, '_use_glance_plugin_to_upload_volume')
|
||||
mock.StubOutWithMock(driver.image_utils, 'is_xenserver_format')
|
||||
context = MockContext('token')
|
||||
|
||||
driver.image_utils.is_xenserver_format('image_meta').AndReturn(True)
|
||||
|
||||
drv._use_glance_plugin_to_upload_volume(
|
||||
context, 'volume', 'image_service', 'image_meta').AndReturn(
|
||||
'result')
|
||||
mock.ReplayAll()
|
||||
|
||||
result = drv.copy_volume_to_image(
|
||||
context, "volume", "image_service", "image_meta")
|
||||
self.assertEqual('result', result)
|
||||
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_copy_volume_to_image_non_xenserver_case(self):
|
||||
mock, drv = self._setup_mock_driver(
|
||||
'server', 'serverpath', '/var/run/sr-mount')
|
||||
|
||||
mock.StubOutWithMock(drv, '_use_image_utils_to_upload_volume')
|
||||
mock.StubOutWithMock(driver.image_utils, 'is_xenserver_format')
|
||||
context = MockContext('token')
|
||||
|
||||
driver.image_utils.is_xenserver_format('image_meta').AndReturn(False)
|
||||
|
||||
drv._use_image_utils_to_upload_volume(
|
||||
context, 'volume', 'image_service', 'image_meta').AndReturn(
|
||||
'result')
|
||||
mock.ReplayAll()
|
||||
|
||||
result = drv.copy_volume_to_image(
|
||||
context, "volume", "image_service", "image_meta")
|
||||
self.assertEqual('result', result)
|
||||
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_use_image_utils_to_upload_volume(self):
|
||||
mock, drv = self._setup_mock_driver(
|
||||
'server', 'serverpath', '/var/run/sr-mount')
|
||||
|
||||
volume = dict(provider_location='sr-uuid/vdi-uuid')
|
||||
context = MockContext('token')
|
||||
|
||||
mock.StubOutWithMock(driver.image_utils, 'upload_volume')
|
||||
|
||||
drv.nfs_ops.volume_attached_here(
|
||||
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', True).AndReturn(
|
||||
simple_context('device'))
|
||||
|
||||
driver.image_utils.upload_volume(
|
||||
context, 'image_service', 'image_meta', 'device')
|
||||
|
||||
mock.ReplayAll()
|
||||
drv._use_image_utils_to_upload_volume(
|
||||
context, volume, "image_service", "image_meta")
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_use_glance_plugin_to_upload_volume(self):
|
||||
mock, drv = self._setup_mock_driver(
|
||||
'server', 'serverpath', '/var/run/sr-mount')
|
||||
|
||||
volume = dict(provider_location='sr-uuid/vdi-uuid')
|
||||
context = MockContext('token')
|
||||
|
||||
mock.StubOutWithMock(driver.glance, 'get_api_servers')
|
||||
|
||||
driver.glance.get_api_servers().AndReturn((x for x in ['glancesrv']))
|
||||
|
||||
drv.nfs_ops.use_glance_plugin_to_upload_volume(
|
||||
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', 'glancesrv',
|
||||
'image-id', 'token', '/var/run/sr-mount')
|
||||
|
||||
mock.ReplayAll()
|
||||
drv._use_glance_plugin_to_upload_volume(
|
||||
context, volume, "image_service", {"id": "image-id"})
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_copy_image_to_volume_xenserver_case(self):
|
||||
mock, drv = self._setup_mock_driver(
|
||||
'server', 'serverpath', '/var/run/sr-mount')
|
||||
|
||||
mock.StubOutWithMock(drv, '_use_glance_plugin_to_copy_image_to_volume')
|
||||
mock.StubOutWithMock(driver.image_utils, 'is_xenserver_image')
|
||||
context = MockContext('token')
|
||||
|
||||
driver.image_utils.is_xenserver_image(
|
||||
context, 'image_service', 'image_id').AndReturn(True)
|
||||
drv._use_glance_plugin_to_copy_image_to_volume(
|
||||
context, 'volume', 'image_service', 'image_id').AndReturn('result')
|
||||
mock.ReplayAll()
|
||||
result = drv.copy_image_to_volume(
|
||||
context, "volume", "image_service", "image_id")
|
||||
self.assertEqual('result', result)
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_copy_image_to_volume_non_xenserver_case(self):
|
||||
mock, drv = self._setup_mock_driver(
|
||||
'server', 'serverpath', '/var/run/sr-mount')
|
||||
|
||||
mock.StubOutWithMock(drv, '_use_image_utils_to_pipe_bytes_to_volume')
|
||||
mock.StubOutWithMock(driver.image_utils, 'is_xenserver_image')
|
||||
context = MockContext('token')
|
||||
|
||||
driver.image_utils.is_xenserver_image(
|
||||
context, 'image_service', 'image_id').AndReturn(False)
|
||||
drv._use_image_utils_to_pipe_bytes_to_volume(
|
||||
context, 'volume', 'image_service', 'image_id').AndReturn(True)
|
||||
mock.ReplayAll()
|
||||
drv.copy_image_to_volume(
|
||||
context, "volume", "image_service", "image_id")
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_use_image_utils_to_pipe_bytes_to_volume(self):
|
||||
mock, drv = self._setup_mock_driver(
|
||||
'server', 'serverpath', '/var/run/sr-mount')
|
||||
|
||||
volume = dict(provider_location='sr-uuid/vdi-uuid', size=1)
|
||||
context = MockContext('token')
|
||||
|
||||
mock.StubOutWithMock(driver.image_utils, 'fetch_to_raw')
|
||||
|
||||
drv.nfs_ops.volume_attached_here(
|
||||
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', False).AndReturn(
|
||||
simple_context('device'))
|
||||
|
||||
driver.image_utils.fetch_to_raw(
|
||||
context, 'image_service', 'image_id', 'device', mox.IgnoreArg(),
|
||||
size=1)
|
||||
|
||||
mock.ReplayAll()
|
||||
drv._use_image_utils_to_pipe_bytes_to_volume(
|
||||
context, volume, "image_service", "image_id")
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_use_glance_plugin_to_copy_image_to_volume_success(self):
|
||||
mock, drv = self._setup_mock_driver(
|
||||
'server', 'serverpath', '/var/run/sr-mount')
|
||||
|
||||
volume = dict(
|
||||
provider_location='sr-uuid/vdi-uuid',
|
||||
size=2)
|
||||
|
||||
mock.StubOutWithMock(driver.glance, 'get_api_servers')
|
||||
|
||||
driver.glance.get_api_servers().AndReturn((x for x in ['glancesrv']))
|
||||
|
||||
drv.nfs_ops.use_glance_plugin_to_overwrite_volume(
|
||||
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', 'glancesrv',
|
||||
'image_id', 'token', '/var/run/sr-mount').AndReturn(True)
|
||||
|
||||
drv.nfs_ops.resize_volume(
|
||||
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', 2)
|
||||
|
||||
mock.ReplayAll()
|
||||
drv._use_glance_plugin_to_copy_image_to_volume(
|
||||
MockContext('token'), volume, "ignore", "image_id")
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_use_glance_plugin_to_copy_image_to_volume_fail(self):
|
||||
mock, drv = self._setup_mock_driver(
|
||||
'server', 'serverpath', '/var/run/sr-mount')
|
||||
|
||||
volume = dict(
|
||||
provider_location='sr-uuid/vdi-uuid',
|
||||
size=2)
|
||||
|
||||
mock.StubOutWithMock(driver.glance, 'get_api_servers')
|
||||
|
||||
driver.glance.get_api_servers().AndReturn((x for x in ['glancesrv']))
|
||||
|
||||
drv.nfs_ops.use_glance_plugin_to_overwrite_volume(
|
||||
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', 'glancesrv',
|
||||
'image_id', 'token', '/var/run/sr-mount').AndReturn(False)
|
||||
|
||||
mock.ReplayAll()
|
||||
|
||||
self.assertRaises(
|
||||
exception.ImageCopyFailure,
|
||||
lambda: drv._use_glance_plugin_to_copy_image_to_volume(
|
||||
MockContext('token'), volume, "ignore", "image_id"))
|
||||
|
||||
mock.VerifyAll()
|
||||
|
||||
def test_get_volume_stats_reports_required_keys(self):
|
||||
drv = get_configured_driver()
|
||||
|
||||
stats = drv.get_volume_stats()
|
||||
|
||||
required_metrics = [
|
||||
'volume_backend_name', 'vendor_name', 'driver_version',
|
||||
'storage_protocol', 'total_capacity_gb', 'free_capacity_gb',
|
||||
'reserved_percentage'
|
||||
]
|
||||
|
||||
for metric in required_metrics:
|
||||
self.assertIn(metric, stats)
|
||||
|
||||
def test_get_volume_stats_reports_unknown_cap(self):
|
||||
drv = get_configured_driver()
|
||||
|
||||
stats = drv.get_volume_stats()
|
||||
|
||||
self.assertEqual('unknown', stats['free_capacity_gb'])
|
||||
|
||||
def test_reported_driver_type(self):
|
||||
drv = get_configured_driver()
|
||||
|
||||
stats = drv.get_volume_stats()
|
||||
|
||||
self.assertEqual('xensm', stats['storage_protocol'])
|
||||
|
||||
|
||||
class ToolsTest(test.TestCase):
|
||||
@mock.patch('cinder.volume.drivers.xenapi.tools._stripped_first_line_of')
|
||||
def test_get_this_vm_uuid(self, mock_read_first_line):
|
||||
mock_read_first_line.return_value = 'someuuid'
|
||||
self.assertEqual('someuuid', tools.get_this_vm_uuid())
|
||||
mock_read_first_line.assert_called_once_with('/sys/hypervisor/uuid')
|
||||
|
||||
def test_stripped_first_line_of(self):
|
||||
mock_context_manager = mock.Mock()
|
||||
mock_context_manager.__enter__ = mock.Mock(
|
||||
return_value=six.StringIO(' blah \n second line \n'))
|
||||
mock_context_manager.__exit__ = mock.Mock(return_value=False)
|
||||
mock_open = mock.Mock(return_value=mock_context_manager)
|
||||
|
||||
with mock.patch('__builtin__.open', mock_open):
|
||||
self.assertEqual(
|
||||
'blah', tools._stripped_first_line_of('/somefile'))
|
||||
|
||||
mock_open.assert_called_once_with('/somefile', 'rb')
|
@ -1,542 +0,0 @@
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import pickle
|
||||
|
||||
from cinder.openstack.common import units
|
||||
from cinder.volume.drivers.xenapi import tools
|
||||
|
||||
|
||||
class XenAPIException(Exception):
|
||||
def __init__(self, original_exception):
|
||||
super(XenAPIException, self).__init__(original_exception)
|
||||
self.original_exception = original_exception
|
||||
|
||||
|
||||
class OperationsBase(object):
|
||||
def __init__(self, xenapi_session):
|
||||
self.session = xenapi_session
|
||||
|
||||
def call_xenapi(self, method, *args):
|
||||
return self.session.call_xenapi(method, *args)
|
||||
|
||||
|
||||
class VMOperations(OperationsBase):
|
||||
def get_by_uuid(self, vm_uuid):
|
||||
return self.call_xenapi('VM.get_by_uuid', vm_uuid)
|
||||
|
||||
def get_vbds(self, vm_uuid):
|
||||
return self.call_xenapi('VM.get_VBDs', vm_uuid)
|
||||
|
||||
|
||||
class VBDOperations(OperationsBase):
|
||||
def create(self, vm_ref, vdi_ref, userdevice, bootable, mode, type,
|
||||
empty, other_config):
|
||||
vbd_rec = dict(
|
||||
VM=vm_ref,
|
||||
VDI=vdi_ref,
|
||||
userdevice=str(userdevice),
|
||||
bootable=bootable,
|
||||
mode=mode,
|
||||
type=type,
|
||||
empty=empty,
|
||||
other_config=other_config,
|
||||
qos_algorithm_type='',
|
||||
qos_algorithm_params=dict()
|
||||
)
|
||||
return self.call_xenapi('VBD.create', vbd_rec)
|
||||
|
||||
def destroy(self, vbd_ref):
|
||||
self.call_xenapi('VBD.destroy', vbd_ref)
|
||||
|
||||
def get_device(self, vbd_ref):
|
||||
return self.call_xenapi('VBD.get_device', vbd_ref)
|
||||
|
||||
def plug(self, vbd_ref):
|
||||
return self.call_xenapi('VBD.plug', vbd_ref)
|
||||
|
||||
def unplug(self, vbd_ref):
|
||||
return self.call_xenapi('VBD.unplug', vbd_ref)
|
||||
|
||||
def get_vdi(self, vbd_ref):
|
||||
return self.call_xenapi('VBD.get_VDI', vbd_ref)
|
||||
|
||||
|
||||
class PoolOperations(OperationsBase):
|
||||
def get_all(self):
|
||||
return self.call_xenapi('pool.get_all')
|
||||
|
||||
def get_default_SR(self, pool_ref):
|
||||
return self.call_xenapi('pool.get_default_SR', pool_ref)
|
||||
|
||||
|
||||
class PbdOperations(OperationsBase):
|
||||
def get_all(self):
|
||||
return self.call_xenapi('PBD.get_all')
|
||||
|
||||
def unplug(self, pbd_ref):
|
||||
self.call_xenapi('PBD.unplug', pbd_ref)
|
||||
|
||||
def create(self, host_ref, sr_ref, device_config):
|
||||
return self.call_xenapi(
|
||||
'PBD.create',
|
||||
dict(
|
||||
host=host_ref,
|
||||
SR=sr_ref,
|
||||
device_config=device_config
|
||||
)
|
||||
)
|
||||
|
||||
def plug(self, pbd_ref):
|
||||
self.call_xenapi('PBD.plug', pbd_ref)
|
||||
|
||||
|
||||
class SrOperations(OperationsBase):
|
||||
def get_all(self):
|
||||
return self.call_xenapi('SR.get_all')
|
||||
|
||||
def get_record(self, sr_ref):
|
||||
return self.call_xenapi('SR.get_record', sr_ref)
|
||||
|
||||
def forget(self, sr_ref):
|
||||
self.call_xenapi('SR.forget', sr_ref)
|
||||
|
||||
def scan(self, sr_ref):
|
||||
self.call_xenapi('SR.scan', sr_ref)
|
||||
|
||||
def create(self, host_ref, device_config, name_label, name_description,
|
||||
sr_type, physical_size=None, content_type=None,
|
||||
shared=False, sm_config=None):
|
||||
return self.call_xenapi(
|
||||
'SR.create',
|
||||
host_ref,
|
||||
device_config,
|
||||
physical_size or '0',
|
||||
name_label or '',
|
||||
name_description or '',
|
||||
sr_type,
|
||||
content_type or '',
|
||||
shared,
|
||||
sm_config or dict()
|
||||
)
|
||||
|
||||
def introduce(self, sr_uuid, name_label, name_description, sr_type,
|
||||
content_type=None, shared=False, sm_config=None):
|
||||
return self.call_xenapi(
|
||||
'SR.introduce',
|
||||
sr_uuid,
|
||||
name_label or '',
|
||||
name_description or '',
|
||||
sr_type,
|
||||
content_type or '',
|
||||
shared,
|
||||
sm_config or dict()
|
||||
)
|
||||
|
||||
def get_uuid(self, sr_ref):
|
||||
return self.get_record(sr_ref)['uuid']
|
||||
|
||||
def get_name_label(self, sr_ref):
|
||||
return self.get_record(sr_ref)['name_label']
|
||||
|
||||
def get_name_description(self, sr_ref):
|
||||
return self.get_record(sr_ref)['name_description']
|
||||
|
||||
def destroy(self, sr_ref):
|
||||
self.call_xenapi('SR.destroy', sr_ref)
|
||||
|
||||
|
||||
class VdiOperations(OperationsBase):
|
||||
def get_all(self):
|
||||
return self.call_xenapi('VDI.get_all')
|
||||
|
||||
def get_record(self, vdi_ref):
|
||||
return self.call_xenapi('VDI.get_record', vdi_ref)
|
||||
|
||||
def get_by_uuid(self, vdi_uuid):
|
||||
return self.call_xenapi('VDI.get_by_uuid', vdi_uuid)
|
||||
|
||||
def get_uuid(self, vdi_ref):
|
||||
return self.get_record(vdi_ref)['uuid']
|
||||
|
||||
def create(self, sr_ref, size, vdi_type,
|
||||
sharable=False, read_only=False, other_config=None):
|
||||
return self.call_xenapi('VDI.create',
|
||||
dict(SR=sr_ref,
|
||||
virtual_size=str(size),
|
||||
type=vdi_type,
|
||||
sharable=sharable,
|
||||
read_only=read_only,
|
||||
other_config=other_config or dict()))
|
||||
|
||||
def destroy(self, vdi_ref):
|
||||
self.call_xenapi('VDI.destroy', vdi_ref)
|
||||
|
||||
def copy(self, vdi_ref, sr_ref):
|
||||
return self.call_xenapi('VDI.copy', vdi_ref, sr_ref)
|
||||
|
||||
def resize(self, vdi_ref, size):
|
||||
return self.call_xenapi('VDI.resize', vdi_ref, str(size))
|
||||
|
||||
|
||||
class HostOperations(OperationsBase):
|
||||
def get_record(self, host_ref):
|
||||
return self.call_xenapi('host.get_record', host_ref)
|
||||
|
||||
def get_uuid(self, host_ref):
|
||||
return self.get_record(host_ref)['uuid']
|
||||
|
||||
|
||||
class XenAPISession(object):
|
||||
def __init__(self, session, exception_to_convert):
|
||||
self._session = session
|
||||
self._exception_to_convert = exception_to_convert
|
||||
self.handle = self._session.handle
|
||||
self.PBD = PbdOperations(self)
|
||||
self.SR = SrOperations(self)
|
||||
self.VDI = VdiOperations(self)
|
||||
self.host = HostOperations(self)
|
||||
self.pool = PoolOperations(self)
|
||||
self.VBD = VBDOperations(self)
|
||||
self.VM = VMOperations(self)
|
||||
|
||||
def close(self):
|
||||
return self.call_xenapi('logout')
|
||||
|
||||
@contextlib.contextmanager
|
||||
def exception_converter(self):
|
||||
try:
|
||||
yield None
|
||||
except self._exception_to_convert as e:
|
||||
raise XenAPIException(e)
|
||||
|
||||
def call_xenapi(self, method, *args):
|
||||
with self.exception_converter():
|
||||
return self._session.xenapi_request(method, args)
|
||||
|
||||
def call_plugin(self, host_ref, plugin, function, args):
|
||||
with self.exception_converter():
|
||||
return self._session.xenapi.host.call_plugin(
|
||||
host_ref, plugin, function, args)
|
||||
|
||||
def get_pool(self):
|
||||
return self.call_xenapi('session.get_pool', self.handle)
|
||||
|
||||
def get_this_host(self):
|
||||
return self.call_xenapi('session.get_this_host', self.handle)
|
||||
|
||||
|
||||
class CompoundOperations(object):
|
||||
def unplug_pbds_from_sr(self, sr_ref):
|
||||
sr_rec = self.SR.get_record(sr_ref)
|
||||
for pbd_ref in sr_rec.get('PBDs', []):
|
||||
self.PBD.unplug(pbd_ref)
|
||||
|
||||
def unplug_pbds_and_forget_sr(self, sr_ref):
|
||||
self.unplug_pbds_from_sr(sr_ref)
|
||||
self.SR.forget(sr_ref)
|
||||
|
||||
def create_new_vdi(self, sr_ref, size_in_gigabytes):
|
||||
return self.VDI.create(sr_ref,
|
||||
to_bytes(size_in_gigabytes),
|
||||
'User', )
|
||||
|
||||
|
||||
def to_bytes(size_in_gigs):
|
||||
return size_in_gigs * units.Gi
|
||||
|
||||
|
||||
class NFSOperationsMixIn(CompoundOperations):
|
||||
def is_nfs_sr(self, sr_ref):
|
||||
return self.SR.get_record(sr_ref).get('type') == 'nfs'
|
||||
|
||||
@contextlib.contextmanager
|
||||
def new_sr_on_nfs(self, host_ref, server, serverpath,
|
||||
name_label=None, name_description=None):
|
||||
|
||||
device_config = dict(
|
||||
server=server,
|
||||
serverpath=serverpath
|
||||
)
|
||||
name_label = name_label or ''
|
||||
name_description = name_description or ''
|
||||
sr_type = 'nfs'
|
||||
|
||||
sr_ref = self.SR.create(
|
||||
host_ref,
|
||||
device_config,
|
||||
name_label,
|
||||
name_description,
|
||||
sr_type,
|
||||
)
|
||||
yield sr_ref
|
||||
|
||||
self.unplug_pbds_and_forget_sr(sr_ref)
|
||||
|
||||
def plug_nfs_sr(self, host_ref, server, serverpath, sr_uuid,
|
||||
name_label=None, name_description=None):
|
||||
|
||||
device_config = dict(
|
||||
server=server,
|
||||
serverpath=serverpath
|
||||
)
|
||||
sr_type = 'nfs'
|
||||
|
||||
sr_ref = self.SR.introduce(
|
||||
sr_uuid,
|
||||
name_label,
|
||||
name_description,
|
||||
sr_type,
|
||||
)
|
||||
|
||||
pbd_ref = self.PBD.create(
|
||||
host_ref,
|
||||
sr_ref,
|
||||
device_config
|
||||
)
|
||||
|
||||
self.PBD.plug(pbd_ref)
|
||||
|
||||
return sr_ref
|
||||
|
||||
def connect_volume(self, server, serverpath, sr_uuid, vdi_uuid):
|
||||
host_ref = self.get_this_host()
|
||||
sr_ref = self.plug_nfs_sr(
|
||||
host_ref,
|
||||
server,
|
||||
serverpath,
|
||||
sr_uuid
|
||||
)
|
||||
self.SR.scan(sr_ref)
|
||||
vdi_ref = self.VDI.get_by_uuid(vdi_uuid)
|
||||
return dict(sr_ref=sr_ref, vdi_ref=vdi_ref)
|
||||
|
||||
def copy_vdi_to_sr(self, vdi_ref, sr_ref):
|
||||
return self.VDI.copy(vdi_ref, sr_ref)
|
||||
|
||||
|
||||
class ContextAwareSession(XenAPISession):
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
|
||||
class OpenStackXenAPISession(ContextAwareSession,
|
||||
NFSOperationsMixIn):
|
||||
pass
|
||||
|
||||
|
||||
def connect(url, user, password):
|
||||
import XenAPI
|
||||
session = XenAPI.Session(url)
|
||||
session.login_with_password(user, password)
|
||||
return OpenStackXenAPISession(session, XenAPI.Failure)
|
||||
|
||||
|
||||
class SessionFactory(object):
|
||||
def __init__(self, url, user, password):
|
||||
self.url = url
|
||||
self.user = user
|
||||
self.password = password
|
||||
|
||||
def get_session(self):
|
||||
return connect(self.url, self.user, self.password)
|
||||
|
||||
|
||||
class XapiPluginProxy(object):
|
||||
def __init__(self, session_factory, plugin_name):
|
||||
self._session_factory = session_factory
|
||||
self._plugin_name = plugin_name
|
||||
|
||||
def call(self, function, *plugin_args, **plugin_kwargs):
|
||||
plugin_params = dict(args=plugin_args, kwargs=plugin_kwargs)
|
||||
args = dict(params=pickle.dumps(plugin_params))
|
||||
|
||||
with self._session_factory.get_session() as session:
|
||||
host_ref = session.get_this_host()
|
||||
result = session.call_plugin(
|
||||
host_ref, self._plugin_name, function, args)
|
||||
|
||||
return pickle.loads(result)
|
||||
|
||||
|
||||
class GlancePluginProxy(XapiPluginProxy):
|
||||
def __init__(self, session_factory):
|
||||
super(GlancePluginProxy, self).__init__(session_factory, 'glance')
|
||||
|
||||
def download_vhd(self, image_id, glance_host, glance_port, glance_use_ssl,
|
||||
uuid_stack, sr_path, auth_token):
|
||||
return self.call(
|
||||
'download_vhd',
|
||||
image_id=image_id,
|
||||
glance_host=glance_host,
|
||||
glance_port=glance_port,
|
||||
glance_use_ssl=glance_use_ssl,
|
||||
uuid_stack=uuid_stack,
|
||||
sr_path=sr_path,
|
||||
auth_token=auth_token)
|
||||
|
||||
def upload_vhd(self, vdi_uuids, image_id, glance_host, glance_port,
|
||||
glance_use_ssl, sr_path, auth_token, properties):
|
||||
return self.call(
|
||||
'upload_vhd',
|
||||
vdi_uuids=vdi_uuids,
|
||||
image_id=image_id,
|
||||
glance_host=glance_host,
|
||||
glance_port=glance_port,
|
||||
glance_use_ssl=glance_use_ssl,
|
||||
sr_path=sr_path,
|
||||
auth_token=auth_token,
|
||||
properties=properties)
|
||||
|
||||
|
||||
class NFSBasedVolumeOperations(object):
|
||||
def __init__(self, session_factory):
|
||||
self._session_factory = session_factory
|
||||
self.glance_plugin = GlancePluginProxy(session_factory)
|
||||
|
||||
def create_volume(self, server, serverpath, size,
|
||||
name=None, description=None):
|
||||
with self._session_factory.get_session() as session:
|
||||
host_ref = session.get_this_host()
|
||||
with session.new_sr_on_nfs(host_ref, server, serverpath,
|
||||
name, description) as sr_ref:
|
||||
vdi_ref = session.create_new_vdi(sr_ref, size)
|
||||
|
||||
return dict(
|
||||
sr_uuid=session.SR.get_uuid(sr_ref),
|
||||
vdi_uuid=session.VDI.get_uuid(vdi_ref)
|
||||
)
|
||||
|
||||
def delete_volume(self, server, serverpath, sr_uuid, vdi_uuid):
|
||||
with self._session_factory.get_session() as session:
|
||||
refs = session.connect_volume(
|
||||
server, serverpath, sr_uuid, vdi_uuid)
|
||||
|
||||
session.VDI.destroy(refs['vdi_ref'])
|
||||
sr_ref = refs['sr_ref']
|
||||
session.unplug_pbds_from_sr(sr_ref)
|
||||
session.SR.destroy(sr_ref)
|
||||
|
||||
def connect_volume(self, server, serverpath, sr_uuid, vdi_uuid):
|
||||
with self._session_factory.get_session() as session:
|
||||
refs = session.connect_volume(
|
||||
server, serverpath, sr_uuid, vdi_uuid)
|
||||
|
||||
return session.VDI.get_uuid(refs['vdi_ref'])
|
||||
|
||||
def disconnect_volume(self, vdi_uuid):
|
||||
with self._session_factory.get_session() as session:
|
||||
vdi_ref = session.VDI.get_by_uuid(vdi_uuid)
|
||||
vdi_rec = session.VDI.get_record(vdi_ref)
|
||||
sr_ref = vdi_rec['SR']
|
||||
session.unplug_pbds_and_forget_sr(sr_ref)
|
||||
|
||||
def copy_volume(self, server, serverpath, sr_uuid, vdi_uuid,
|
||||
name=None, description=None):
|
||||
with self._session_factory.get_session() as session:
|
||||
src_refs = session.connect_volume(
|
||||
server, serverpath, sr_uuid, vdi_uuid)
|
||||
try:
|
||||
host_ref = session.get_this_host()
|
||||
|
||||
with session.new_sr_on_nfs(host_ref, server, serverpath,
|
||||
name, description) as target_sr_ref:
|
||||
target_vdi_ref = session.copy_vdi_to_sr(
|
||||
src_refs['vdi_ref'], target_sr_ref)
|
||||
|
||||
dst_refs = dict(
|
||||
sr_uuid=session.SR.get_uuid(target_sr_ref),
|
||||
vdi_uuid=session.VDI.get_uuid(target_vdi_ref)
|
||||
)
|
||||
|
||||
finally:
|
||||
session.unplug_pbds_and_forget_sr(src_refs['sr_ref'])
|
||||
|
||||
return dst_refs
|
||||
|
||||
def resize_volume(self, server, serverpath, sr_uuid, vdi_uuid,
|
||||
size_in_gigabytes):
|
||||
self.connect_volume(server, serverpath, sr_uuid, vdi_uuid)
|
||||
|
||||
try:
|
||||
with self._session_factory.get_session() as session:
|
||||
vdi_ref = session.VDI.get_by_uuid(vdi_uuid)
|
||||
session.VDI.resize(vdi_ref, to_bytes(size_in_gigabytes))
|
||||
finally:
|
||||
self.disconnect_volume(vdi_uuid)
|
||||
|
||||
def use_glance_plugin_to_overwrite_volume(self, server, serverpath,
|
||||
sr_uuid, vdi_uuid, glance_server,
|
||||
image_id, auth_token,
|
||||
sr_base_path):
|
||||
self.connect_volume(server, serverpath, sr_uuid, vdi_uuid)
|
||||
|
||||
uuid_stack = [vdi_uuid]
|
||||
glance_host, glance_port, glance_use_ssl = glance_server
|
||||
|
||||
try:
|
||||
result = self.glance_plugin.download_vhd(
|
||||
image_id, glance_host, glance_port, glance_use_ssl, uuid_stack,
|
||||
os.path.join(sr_base_path, sr_uuid), auth_token)
|
||||
finally:
|
||||
self.disconnect_volume(vdi_uuid)
|
||||
|
||||
if len(result) != 1 or result['root']['uuid'] != vdi_uuid:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def use_glance_plugin_to_upload_volume(self, server, serverpath,
|
||||
sr_uuid, vdi_uuid, glance_server,
|
||||
image_id, auth_token, sr_base_path):
|
||||
self.connect_volume(server, serverpath, sr_uuid, vdi_uuid)
|
||||
|
||||
vdi_uuids = [vdi_uuid]
|
||||
glance_host, glance_port, glance_use_ssl = glance_server
|
||||
|
||||
try:
|
||||
self.glance_plugin.upload_vhd(
|
||||
vdi_uuids, image_id, glance_host, glance_port, glance_use_ssl,
|
||||
os.path.join(sr_base_path, sr_uuid), auth_token, dict())
|
||||
finally:
|
||||
self.disconnect_volume(vdi_uuid)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def volume_attached_here(self, server, serverpath, sr_uuid, vdi_uuid,
|
||||
readonly=True):
|
||||
self.connect_volume(server, serverpath, sr_uuid, vdi_uuid)
|
||||
|
||||
with self._session_factory.get_session() as session:
|
||||
vm_uuid = tools.get_this_vm_uuid()
|
||||
vm_ref = session.VM.get_by_uuid(vm_uuid)
|
||||
vdi_ref = session.VDI.get_by_uuid(vdi_uuid)
|
||||
vbd_ref = session.VBD.create(
|
||||
vm_ref, vdi_ref, userdevice='autodetect', bootable=False,
|
||||
mode='RO' if readonly else 'RW', type='disk', empty=False,
|
||||
other_config=dict())
|
||||
session.VBD.plug(vbd_ref)
|
||||
device = session.VBD.get_device(vbd_ref)
|
||||
try:
|
||||
yield "/dev/" + device
|
||||
finally:
|
||||
session.VBD.unplug(vbd_ref)
|
||||
session.VBD.destroy(vbd_ref)
|
||||
self.disconnect_volume(vdi_uuid)
|
@ -1,270 +0,0 @@
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from cinder import exception
|
||||
from cinder.image import glance
|
||||
from cinder.image import image_utils
|
||||
from cinder.openstack.common import log as logging
|
||||
from cinder.volume import driver
|
||||
from cinder.volume.drivers.xenapi import lib as xenapi_lib
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
xenapi_opts = [
|
||||
cfg.StrOpt('xenapi_connection_url',
|
||||
default=None,
|
||||
help='URL for XenAPI connection'),
|
||||
cfg.StrOpt('xenapi_connection_username',
|
||||
default='root',
|
||||
help='Username for XenAPI connection'),
|
||||
cfg.StrOpt('xenapi_connection_password',
|
||||
default=None,
|
||||
help='Password for XenAPI connection',
|
||||
secret=True),
|
||||
cfg.StrOpt('xenapi_sr_base_path',
|
||||
default='/var/run/sr-mount',
|
||||
help='Base path to the storage repository'),
|
||||
]
|
||||
|
||||
xenapi_nfs_opts = [
|
||||
cfg.StrOpt('xenapi_nfs_server',
|
||||
default=None,
|
||||
help='NFS server to be used by XenAPINFSDriver'),
|
||||
cfg.StrOpt('xenapi_nfs_serverpath',
|
||||
default=None,
|
||||
help='Path of exported NFS, used by XenAPINFSDriver'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(xenapi_opts)
|
||||
CONF.register_opts(xenapi_nfs_opts)
|
||||
|
||||
|
||||
class XenAPINFSDriver(driver.VolumeDriver):
|
||||
|
||||
VERSION = "1.0.0"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(XenAPINFSDriver, self).__init__(*args, **kwargs)
|
||||
self.configuration.append_config_values(xenapi_opts)
|
||||
self.configuration.append_config_values(xenapi_nfs_opts)
|
||||
|
||||
def do_setup(self, context):
|
||||
session_factory = xenapi_lib.SessionFactory(
|
||||
self.configuration.xenapi_connection_url,
|
||||
self.configuration.xenapi_connection_username,
|
||||
self.configuration.xenapi_connection_password
|
||||
)
|
||||
self.nfs_ops = xenapi_lib.NFSBasedVolumeOperations(session_factory)
|
||||
|
||||
def create_cloned_volume(self, volume, src_vref):
|
||||
raise NotImplementedError()
|
||||
|
||||
def create_volume(self, volume):
|
||||
volume_details = self.nfs_ops.create_volume(
|
||||
self.configuration.xenapi_nfs_server,
|
||||
self.configuration.xenapi_nfs_serverpath,
|
||||
volume['size'],
|
||||
volume['display_name'],
|
||||
volume['display_description']
|
||||
)
|
||||
location = "%(sr_uuid)s/%(vdi_uuid)s" % volume_details
|
||||
return dict(provider_location=location)
|
||||
|
||||
def create_export(self, context, volume):
|
||||
pass
|
||||
|
||||
def delete_volume(self, volume):
|
||||
sr_uuid, vdi_uuid = volume['provider_location'].split('/')
|
||||
|
||||
self.nfs_ops.delete_volume(
|
||||
self.configuration.xenapi_nfs_server,
|
||||
self.configuration.xenapi_nfs_serverpath,
|
||||
sr_uuid,
|
||||
vdi_uuid
|
||||
)
|
||||
|
||||
def remove_export(self, context, volume):
|
||||
pass
|
||||
|
||||
def initialize_connection(self, volume, connector):
|
||||
sr_uuid, vdi_uuid = volume['provider_location'].split('/')
|
||||
|
||||
return dict(
|
||||
driver_volume_type='xensm',
|
||||
data=dict(
|
||||
name_label=volume['display_name'] or '',
|
||||
name_description=volume['display_description'] or '',
|
||||
sr_uuid=sr_uuid,
|
||||
vdi_uuid=vdi_uuid,
|
||||
sr_type='nfs',
|
||||
server=self.configuration.xenapi_nfs_server,
|
||||
serverpath=self.configuration.xenapi_nfs_serverpath,
|
||||
introduce_sr_keys=['sr_type', 'server', 'serverpath']
|
||||
)
|
||||
)
|
||||
|
||||
def terminate_connection(self, volume, connector, **kwargs):
|
||||
pass
|
||||
|
||||
def check_for_setup_error(self):
|
||||
"""To override superclass' method."""
|
||||
|
||||
def create_volume_from_snapshot(self, volume, snapshot):
|
||||
return self._copy_volume(
|
||||
snapshot, volume['display_name'], volume['name_description'])
|
||||
|
||||
def create_snapshot(self, snapshot):
|
||||
volume = snapshot['volume']
|
||||
return self._copy_volume(
|
||||
volume, snapshot['display_name'], snapshot['display_description'])
|
||||
|
||||
def _copy_volume(self, volume, target_name, target_desc):
|
||||
sr_uuid, vdi_uuid = volume['provider_location'].split('/')
|
||||
|
||||
volume_details = self.nfs_ops.copy_volume(
|
||||
self.configuration.xenapi_nfs_server,
|
||||
self.configuration.xenapi_nfs_serverpath,
|
||||
sr_uuid,
|
||||
vdi_uuid,
|
||||
target_name,
|
||||
target_desc
|
||||
)
|
||||
location = "%(sr_uuid)s/%(vdi_uuid)s" % volume_details
|
||||
return dict(provider_location=location)
|
||||
|
||||
def delete_snapshot(self, snapshot):
|
||||
self.delete_volume(snapshot)
|
||||
|
||||
def ensure_export(self, context, volume):
|
||||
pass
|
||||
|
||||
def copy_image_to_volume(self, context, volume, image_service, image_id):
|
||||
if image_utils.is_xenserver_image(context, image_service, image_id):
|
||||
return self._use_glance_plugin_to_copy_image_to_volume(
|
||||
context, volume, image_service, image_id)
|
||||
|
||||
return self._use_image_utils_to_pipe_bytes_to_volume(
|
||||
context, volume, image_service, image_id)
|
||||
|
||||
def _use_image_utils_to_pipe_bytes_to_volume(self, context, volume,
|
||||
image_service, image_id):
|
||||
sr_uuid, vdi_uuid = volume['provider_location'].split('/')
|
||||
with self.nfs_ops.volume_attached_here(CONF.xenapi_nfs_server,
|
||||
CONF.xenapi_nfs_serverpath,
|
||||
sr_uuid, vdi_uuid,
|
||||
False) as device:
|
||||
image_utils.fetch_to_raw(context,
|
||||
image_service,
|
||||
image_id,
|
||||
device,
|
||||
self.configuration.volume_dd_blocksize,
|
||||
size=volume['size'])
|
||||
|
||||
def _use_glance_plugin_to_copy_image_to_volume(self, context, volume,
|
||||
image_service, image_id):
|
||||
sr_uuid, vdi_uuid = volume['provider_location'].split('/')
|
||||
|
||||
api_servers = glance.get_api_servers()
|
||||
glance_server = api_servers.next()
|
||||
auth_token = context.auth_token
|
||||
|
||||
overwrite_result = self.nfs_ops.use_glance_plugin_to_overwrite_volume(
|
||||
CONF.xenapi_nfs_server,
|
||||
CONF.xenapi_nfs_serverpath,
|
||||
sr_uuid,
|
||||
vdi_uuid,
|
||||
glance_server,
|
||||
image_id,
|
||||
auth_token,
|
||||
CONF.xenapi_sr_base_path)
|
||||
|
||||
if overwrite_result is False:
|
||||
raise exception.ImageCopyFailure(reason='Overwriting volume '
|
||||
'failed.')
|
||||
|
||||
self.nfs_ops.resize_volume(
|
||||
CONF.xenapi_nfs_server,
|
||||
CONF.xenapi_nfs_serverpath,
|
||||
sr_uuid,
|
||||
vdi_uuid,
|
||||
volume['size'])
|
||||
|
||||
def copy_volume_to_image(self, context, volume, image_service, image_meta):
|
||||
if image_utils.is_xenserver_format(image_meta):
|
||||
return self._use_glance_plugin_to_upload_volume(
|
||||
context, volume, image_service, image_meta)
|
||||
|
||||
return self._use_image_utils_to_upload_volume(
|
||||
context, volume, image_service, image_meta)
|
||||
|
||||
def _use_image_utils_to_upload_volume(self, context, volume, image_service,
|
||||
image_meta):
|
||||
sr_uuid, vdi_uuid = volume['provider_location'].split('/')
|
||||
with self.nfs_ops.volume_attached_here(CONF.xenapi_nfs_server,
|
||||
CONF.xenapi_nfs_serverpath,
|
||||
sr_uuid, vdi_uuid,
|
||||
True) as device:
|
||||
image_utils.upload_volume(context,
|
||||
image_service,
|
||||
image_meta,
|
||||
device)
|
||||
|
||||
def _use_glance_plugin_to_upload_volume(self, context, volume,
|
||||
image_service, image_meta):
|
||||
image_id = image_meta['id']
|
||||
|
||||
sr_uuid, vdi_uuid = volume['provider_location'].split('/')
|
||||
|
||||
api_servers = glance.get_api_servers()
|
||||
glance_server = api_servers.next()
|
||||
auth_token = context.auth_token
|
||||
|
||||
self.nfs_ops.use_glance_plugin_to_upload_volume(
|
||||
CONF.xenapi_nfs_server,
|
||||
CONF.xenapi_nfs_serverpath,
|
||||
sr_uuid,
|
||||
vdi_uuid,
|
||||
glance_server,
|
||||
image_id,
|
||||
auth_token,
|
||||
CONF.xenapi_sr_base_path)
|
||||
|
||||
def get_volume_stats(self, refresh=False):
|
||||
if refresh or not self._stats:
|
||||
data = {}
|
||||
|
||||
backend_name = self.configuration.safe_get('volume_backend_name')
|
||||
data["volume_backend_name"] = backend_name or 'XenAPINFS',
|
||||
data['vendor_name'] = 'Open Source',
|
||||
data['driver_version'] = self.VERSION
|
||||
data['storage_protocol'] = 'xensm'
|
||||
data['total_capacity_gb'] = 'unknown'
|
||||
data['free_capacity_gb'] = 'unknown'
|
||||
data['reserved_percentage'] = 0
|
||||
self._stats = data
|
||||
|
||||
return self._stats
|
||||
|
||||
def backup_volume(self, context, backup, backup_service):
|
||||
"""Create a new backup from an existing volume."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def restore_backup(self, context, backup, volume, backup_service):
|
||||
"""Restore an existing backup to a new or existing volume."""
|
||||
raise NotImplementedError()
|
@ -1,7 +0,0 @@
|
||||
def _stripped_first_line_of(filename):
|
||||
with open(filename, 'rb') as f:
|
||||
return f.readline().strip()
|
||||
|
||||
|
||||
def get_this_vm_uuid():
|
||||
return _stripped_first_line_of('/sys/hypervisor/uuid')
|
@ -2152,29 +2152,6 @@
|
||||
#windows_iscsi_lun_path=C:\iSCSIVirtualDisks
|
||||
|
||||
|
||||
#
|
||||
# Options defined in cinder.volume.drivers.xenapi.sm
|
||||
#
|
||||
|
||||
# NFS server to be used by XenAPINFSDriver (string value)
|
||||
#xenapi_nfs_server=<None>
|
||||
|
||||
# Path of exported NFS, used by XenAPINFSDriver (string value)
|
||||
#xenapi_nfs_serverpath=<None>
|
||||
|
||||
# URL for XenAPI connection (string value)
|
||||
#xenapi_connection_url=<None>
|
||||
|
||||
# Username for XenAPI connection (string value)
|
||||
#xenapi_connection_username=root
|
||||
|
||||
# Password for XenAPI connection (string value)
|
||||
#xenapi_connection_password=<None>
|
||||
|
||||
# Base path to the storage repository (string value)
|
||||
#xenapi_sr_base_path=/var/run/sr-mount
|
||||
|
||||
|
||||
#
|
||||
# Options defined in cinder.volume.drivers.zadara
|
||||
#
|
||||
|
Loading…
x
Reference in New Issue
Block a user