summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/tests/test_xenapi.py68
-rw-r--r--nova/tests/virt/xenapi/imageupload/__init__.py0
-rw-r--r--nova/tests/virt/xenapi/imageupload/test_glance.py74
-rw-r--r--nova/virt/xenapi/imageupload/__init__.py0
-rw-r--r--nova/virt/xenapi/imageupload/glance.py54
-rw-r--r--nova/virt/xenapi/vm_utils.py29
-rw-r--r--nova/virt/xenapi/vmops.py25
7 files changed, 165 insertions, 85 deletions
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index 067e28a13..aa640810b 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -19,7 +19,6 @@
import ast
import base64
import contextlib
-import cPickle as pickle
import functools
import os
import re
@@ -48,6 +47,7 @@ from nova.virt.xenapi import agent
from nova.virt.xenapi import driver as xenapi_conn
from nova.virt.xenapi import fake as xenapi_fake
from nova.virt.xenapi import host
+from nova.virt.xenapi.imageupload import glance
from nova.virt.xenapi import pool
from nova.virt.xenapi import pool_states
from nova.virt.xenapi import vm_utils
@@ -431,15 +431,29 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
{'task_state': task_states.IMAGE_UPLOADING,
'expected_state': task_states.IMAGE_PENDING_UPLOAD}}]
func_call_matcher = matchers.FunctionCallMatcher(expected_calls)
+ image_id = "my_snapshot_id"
stubs.stubout_instance_snapshot(self.stubs)
stubs.stubout_is_snapshot(self.stubs)
# Stubbing out firewall driver as previous stub sets alters
# xml rpc result parsing
stubs.stubout_firewall_driver(self.stubs, self.conn)
+
instance = self._create_instance()
- image_id = "my_snapshot_id"
+ self.fake_upload_called = False
+
+ def fake_image_upload(_self, ctx, session, inst, vdi_uuids,
+ img_id):
+ self.fake_upload_called = True
+ self.assertEqual(ctx, self.context)
+ self.assertEqual(inst, instance)
+ self.assertTrue(isinstance(vdi_uuids, list))
+ self.assertEqual(img_id, image_id)
+
+ self.stubs.Set(glance.GlanceStore, 'upload_image',
+ fake_image_upload)
+
self.conn.snapshot(self.context, instance, image_id,
func_call_matcher.call)
@@ -469,6 +483,8 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
name_label = vdi_rec["name_label"]
self.assert_(not name_label.endswith('snapshot'))
+ self.assertTrue(self.fake_upload_called)
+
def create_vm_record(self, conn, os_type, name):
instances = conn.list_instances()
self.assertEquals(instances, [name])
@@ -2574,54 +2590,6 @@ class SwapXapiHostTestCase(test.TestCase):
"http://someserver", 'otherserver'))
-class VmUtilsTestCase(test.TestCase):
- """Unit tests for xenapi utils."""
-
- def test_upload_image(self):
- def fake_instance_system_metadata_get(context, uuid):
- return dict(image_a=1, image_b=2, image_c='c', d='d')
-
- def fake_get_sr_path(session):
- return "foo"
-
- class FakeInstance(dict):
- def __init__(self):
- super(FakeInstance, self).__init__({
- 'auto_disk_config': 'auto disk config',
- 'os_type': 'os type'})
-
- def __missing__(self, item):
- return "whatever"
-
- class FakeSession(object):
- def call_plugin(session_self, service, command, kwargs):
- self.kwargs = kwargs
-
- def call_plugin_serialized(session_self, service, command, *args,
- **kwargs):
- self.kwargs = kwargs
-
- def fake_dumps(thing):
- return thing
-
- self.stubs.Set(db, "instance_system_metadata_get",
- fake_instance_system_metadata_get)
- self.stubs.Set(vm_utils, "get_sr_path", fake_get_sr_path)
- self.stubs.Set(pickle, "dumps", fake_dumps)
-
- ctx = context.get_admin_context()
-
- instance = FakeInstance()
- session = FakeSession()
- vm_utils.upload_image(ctx, session, instance, "vmi uuids", "image id")
-
- actual = self.kwargs['properties']
- # Inheritance happens in another place, now
- expected = dict(auto_disk_config='auto disk config',
- os_type='os type')
- self.assertEquals(expected, actual)
-
-
class XenAPILiveMigrateTestCase(stubs.XenAPITestBase):
"""Unit tests for live_migration."""
def setUp(self):
diff --git a/nova/tests/virt/xenapi/imageupload/__init__.py b/nova/tests/virt/xenapi/imageupload/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/nova/tests/virt/xenapi/imageupload/__init__.py
diff --git a/nova/tests/virt/xenapi/imageupload/test_glance.py b/nova/tests/virt/xenapi/imageupload/test_glance.py
new file mode 100644
index 000000000..b0518228d
--- /dev/null
+++ b/nova/tests/virt/xenapi/imageupload/test_glance.py
@@ -0,0 +1,74 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack LLC.
+# 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 mox
+
+from nova import context
+from nova import test
+from nova.virt.xenapi.imageupload import glance
+from nova.virt.xenapi import vm_utils
+
+
+class TestGlanceStore(test.TestCase):
+ def setUp(self):
+ super(TestGlanceStore, self).setUp()
+ self.store = glance.GlanceStore()
+ self.mox = mox.Mox()
+
+ def tearDown(self):
+ super(TestGlanceStore, self).tearDown()
+
+ def test_upload_image(self):
+ glance_host = '0.1.2.3'
+ glance_port = 8143
+ glance_use_ssl = False
+ sr_path = '/fake/sr/path'
+ self.flags(glance_host=glance_host)
+ self.flags(glance_port=glance_port)
+ self.flags(glance_api_insecure=glance_use_ssl)
+
+ def fake_get_sr_path(*_args, **_kwargs):
+ return sr_path
+
+ self.stubs.Set(vm_utils, 'get_sr_path', fake_get_sr_path)
+
+ ctx = context.RequestContext('user', 'project', auth_token='foobar')
+ properties = {
+ 'auto_disk_config': True,
+ 'os_type': 'default',
+ }
+ image_id = 'fake_image_uuid'
+ vdi_uuids = ['fake_vdi_uuid']
+ instance = {'uuid': 'blah'}
+ instance.update(properties)
+
+ params = {'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': 'foobar',
+ 'properties': properties}
+ session = self.mox.CreateMockAnything()
+ session.call_plugin_serialized('glance', 'upload_vhd', **params)
+ self.mox.ReplayAll()
+
+ self.store.upload_image(ctx, session, instance, vdi_uuids, image_id)
+
+ self.mox.VerifyAll()
diff --git a/nova/virt/xenapi/imageupload/__init__.py b/nova/virt/xenapi/imageupload/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/nova/virt/xenapi/imageupload/__init__.py
diff --git a/nova/virt/xenapi/imageupload/glance.py b/nova/virt/xenapi/imageupload/glance.py
new file mode 100644
index 000000000..adc06f65b
--- /dev/null
+++ b/nova/virt/xenapi/imageupload/glance.py
@@ -0,0 +1,54 @@
+# Copyright 2013 OpenStack, LLC
+# 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 nova.image import glance
+from nova.openstack.common import cfg
+import nova.openstack.common.log as logging
+from nova.virt.xenapi import vm_utils
+
+LOG = logging.getLogger(__name__)
+
+CONF = cfg.CONF
+
+
+class GlanceStore(object):
+
+ def upload_image(self, context, session, instance, vdi_uuids, image_id):
+ """Requests that the Glance plugin bundle the specified VDIs and
+ push them into Glance using the specified human-friendly name.
+ """
+ # NOTE(sirp): Currently we only support uploading images as VHD, there
+ # is no RAW equivalent (yet)
+ LOG.debug(_("Asking xapi to upload to glance %(vdi_uuids)s as"
+ " ID %(image_id)s"), locals(), instance=instance)
+
+ glance_api_servers = glance.get_api_servers()
+ glance_host, glance_port, glance_use_ssl = glance_api_servers.next()
+
+ properties = {
+ 'auto_disk_config': instance['auto_disk_config'],
+ 'os_type': instance['os_type'] or CONF.default_os_type,
+ }
+
+ params = {'vdi_uuids': vdi_uuids,
+ 'image_id': image_id,
+ 'glance_host': glance_host,
+ 'glance_port': glance_port,
+ 'glance_use_ssl': glance_use_ssl,
+ 'sr_path': vm_utils.get_sr_path(session),
+ 'auth_token': getattr(context, 'auth_token', None),
+ 'properties': properties}
+
+ session.call_plugin_serialized('glance', 'upload_vhd', **params)
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 582a9320a..fe4ce9409 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -715,35 +715,6 @@ def _find_cached_image(session, image_id, sr_ref):
return cached_images.get(image_id)
-def upload_image(context, session, instance, vdi_uuids, image_id):
- """Requests that the Glance plugin bundle the specified VDIs and
- push them into Glance using the specified human-friendly name.
- """
- # NOTE(sirp): Currently we only support uploading images as VHD, there
- # is no RAW equivalent (yet)
- LOG.debug(_("Asking xapi to upload %(vdi_uuids)s as"
- " ID %(image_id)s"), locals(), instance=instance)
-
- glance_api_servers = glance.get_api_servers()
- glance_host, glance_port, glance_use_ssl = glance_api_servers.next()
-
- properties = {
- 'auto_disk_config': instance['auto_disk_config'],
- 'os_type': instance['os_type'] or CONF.default_os_type,
- }
-
- params = {'vdi_uuids': vdi_uuids,
- 'image_id': image_id,
- 'glance_host': glance_host,
- 'glance_port': glance_port,
- 'glance_use_ssl': glance_use_ssl,
- 'sr_path': get_sr_path(session),
- 'auth_token': getattr(context, 'auth_token', None),
- 'properties': properties}
-
- session.call_plugin_serialized('glance', 'upload_vhd', **params)
-
-
def resize_disk(session, instance, vdi_ref, instance_type):
# Copy VDI over to something we can resize
# NOTE(jerdfelt): Would be nice to just set vdi_ref to read/write
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 4a8372cda..8d3a3bed2 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -59,7 +59,10 @@ xenapi_vmops_opts = [
'to go to running state'),
cfg.StrOpt('xenapi_vif_driver',
default='nova.virt.xenapi.vif.XenAPIBridgeDriver',
- help='The XenAPI VIF driver using XenServer Network APIs.')
+ help='The XenAPI VIF driver using XenServer Network APIs.'),
+ cfg.StrOpt('xenapi_image_upload_handler',
+ default='nova.virt.xenapi.imageupload.glance.GlanceStore',
+ help='Object Store Driver used to handle image uploads.'),
]
CONF = cfg.CONF
@@ -161,6 +164,11 @@ class VMOps(object):
self.vif_driver = vif_impl(xenapi_session=self._session)
self.default_root_dev = '/dev/sda'
+ msg = _("Importing image upload handler: %s")
+ LOG.debug(msg % CONF.xenapi_image_upload_handler)
+ self.image_upload_handler = importutils.import_object(
+ CONF.xenapi_image_upload_handler)
+
@property
def agent_enabled(self):
return not CONF.xenapi_disable_agent
@@ -661,9 +669,11 @@ class VMOps(object):
coalesce together, so, we must wait for this coalescing to occur to
get a stable representation of the data on disk.
- 3. Push-to-glance: Once coalesced, we call a plugin on the XenServer
- that will bundle the VHDs together and then push the bundle into
- Glance.
+ 3. Push-to-data-store: Once coalesced, we call a plugin on the
+ XenServer that will bundle the VHDs together and then push the
+ bundle. Depending on the configured value of
+ 'xenapi_image_upload_handler', image data may be pushed to
+ Glance or the specified data store.
"""
vm_ref = self._get_vm_opaque_ref(instance)
@@ -674,8 +684,11 @@ class VMOps(object):
update_task_state) as vdi_uuids:
update_task_state(task_state=task_states.IMAGE_UPLOADING,
expected_state=task_states.IMAGE_PENDING_UPLOAD)
- vm_utils.upload_image(
- context, self._session, instance, vdi_uuids, image_id)
+ self.image_upload_handler.upload_image(context,
+ self._session,
+ instance,
+ vdi_uuids,
+ image_id)
LOG.debug(_("Finished snapshot and upload for VM"),
instance=instance)