Adds disk config
Change-Id: If3e1765b659ead77f9cdaaa86ee8478a82bf67c0
This commit is contained in:
parent
4e94ec1a0a
commit
774b5aaa17
150
nova/api/openstack/contrib/diskconfig.py
Normal file
150
nova/api/openstack/contrib/diskconfig.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2011 OpenStack LLC.
|
||||||
|
#
|
||||||
|
# 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 json
|
||||||
|
|
||||||
|
from webob import exc
|
||||||
|
import webob
|
||||||
|
|
||||||
|
from nova import compute
|
||||||
|
from nova import exception
|
||||||
|
import nova.image
|
||||||
|
from nova import log as logging
|
||||||
|
from nova import network
|
||||||
|
from nova import rpc
|
||||||
|
from nova.api.openstack import faults
|
||||||
|
from nova.api.openstack import extensions
|
||||||
|
from nova.api.openstack import wsgi
|
||||||
|
|
||||||
|
LOG = logging.getLogger('nova.api.openstack.contrib.disk_config')
|
||||||
|
|
||||||
|
|
||||||
|
class DiskConfigController(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.compute_api = compute.API()
|
||||||
|
|
||||||
|
def _return_dict(self, server_id, managed_disk):
|
||||||
|
return {'server': {'id': server_id,
|
||||||
|
'managed_disk': managed_disk}}
|
||||||
|
|
||||||
|
def index(self, req, server_id):
|
||||||
|
context = req.environ['nova.context']
|
||||||
|
try:
|
||||||
|
server = self.compute_api.routing_get(context, server_id)
|
||||||
|
except exception.NotFound:
|
||||||
|
explanation = _("Server not found.")
|
||||||
|
return faults.Fault(exc.HTTPNotFound(explanation=explanation))
|
||||||
|
managed_disk = server['managed_disk'] or False
|
||||||
|
return self._return_dict(server_id, managed_disk)
|
||||||
|
|
||||||
|
def update(self, req, server_id, body=None):
|
||||||
|
if not body:
|
||||||
|
return faults.Fault(exc.HTTPUnprocessableEntity())
|
||||||
|
context = req.environ['nova.context']
|
||||||
|
try:
|
||||||
|
server = self.compute_api.routing_get(context, server_id)
|
||||||
|
except exception.NotFound:
|
||||||
|
explanation = _("Server not found.")
|
||||||
|
return faults.Fault(exc.HTTPNotFound(explanation=explanation))
|
||||||
|
|
||||||
|
managed_disk = str(body['server'].get('managed_disk', False)).lower()
|
||||||
|
managed_disk = managed_disk == 'true' or False
|
||||||
|
self.compute_api.update(context, server_id, managed_disk=managed_disk)
|
||||||
|
|
||||||
|
return self._return_dict(server_id, managed_disk)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageDiskConfigController(object):
|
||||||
|
def __init__(self, image_service=None):
|
||||||
|
self.compute_api = compute.API()
|
||||||
|
self._image_service = image_service or \
|
||||||
|
nova.image.get_default_image_service()
|
||||||
|
|
||||||
|
def _return_dict(self, image_id, managed_disk):
|
||||||
|
return {'image': {'id': image_id,
|
||||||
|
'managed_disk': managed_disk}}
|
||||||
|
|
||||||
|
def index(self, req, image_id):
|
||||||
|
context = req.environ['nova.context']
|
||||||
|
try:
|
||||||
|
image = self._image_service.show(context, image_id)
|
||||||
|
except (exception.NotFound, exception.InvalidImageRef):
|
||||||
|
explanation = _("Image not found.")
|
||||||
|
raise webob.exc.HTTPNotFound(explanation=explanation)
|
||||||
|
image_properties = image.get('properties', None)
|
||||||
|
if image_properties:
|
||||||
|
managed_disk = image_properties.get('managed_disk', False)
|
||||||
|
|
||||||
|
return self._return_dict(image_id, managed_disk)
|
||||||
|
|
||||||
|
|
||||||
|
class Diskconfig(extensions.ExtensionDescriptor):
|
||||||
|
def __init__(self):
|
||||||
|
super(Diskconfig, self).__init__()
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return "DiskConfig"
|
||||||
|
|
||||||
|
def get_alias(self):
|
||||||
|
return "OS-DCFG"
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
return "Disk Configuration support"
|
||||||
|
|
||||||
|
def get_namespace(self):
|
||||||
|
return "http://docs.openstack.org/ext/disk_config/api/v1.1"
|
||||||
|
|
||||||
|
def get_updated(self):
|
||||||
|
return "2011-08-31T00:00:00+00:00"
|
||||||
|
|
||||||
|
def _server_extension_controller(self):
|
||||||
|
metadata = {
|
||||||
|
"attributes": {
|
||||||
|
'managed_disk': ["server_id", "enabled"]}}
|
||||||
|
|
||||||
|
body_serializers = {
|
||||||
|
'application/xml': wsgi.XMLDictSerializer(metadata=metadata,
|
||||||
|
xmlns=wsgi.XMLNS_V11)}
|
||||||
|
serializer = wsgi.ResponseSerializer(body_serializers, None)
|
||||||
|
res = extensions.ResourceExtension(
|
||||||
|
'os-disk-config',
|
||||||
|
controller=DiskConfigController(),
|
||||||
|
collection_actions={'update': 'PUT'},
|
||||||
|
parent=dict(member_name='server', collection_name='servers'),
|
||||||
|
serializer=serializer)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def _image_extension_controller(self):
|
||||||
|
resources = []
|
||||||
|
metadata = {
|
||||||
|
"attributes": {
|
||||||
|
'managed_disk': ["image_id", "enabled"]}}
|
||||||
|
|
||||||
|
body_serializers = {
|
||||||
|
'application/xml': wsgi.XMLDictSerializer(metadata=metadata,
|
||||||
|
xmlns=wsgi.XMLNS_V11)}
|
||||||
|
serializer = wsgi.ResponseSerializer(body_serializers, None)
|
||||||
|
res = extensions.ResourceExtension(
|
||||||
|
'os-disk-config',
|
||||||
|
controller=ImageDiskConfigController(),
|
||||||
|
collection_actions={'update': 'PUT'},
|
||||||
|
parent=dict(member_name='image', collection_name='images'),
|
||||||
|
serializer=serializer)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
return [self._server_extension_controller(),
|
||||||
|
self._image_extension_controller()]
|
@ -0,0 +1,39 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright (c) 2011 OpenStack LLC.
|
||||||
|
#
|
||||||
|
# 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 sqlalchemy import Column, Integer, MetaData, Table, Boolean
|
||||||
|
|
||||||
|
meta = MetaData()
|
||||||
|
|
||||||
|
# temporary table for creating the new columns
|
||||||
|
|
||||||
|
instances = Table("instances", meta,
|
||||||
|
Column("id", Integer(), primary_key=True, nullable=False))
|
||||||
|
|
||||||
|
# The new column
|
||||||
|
|
||||||
|
managed_disk = Column("managed_disk", Boolean(create_constraint=False,
|
||||||
|
name=None))
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
instances.create_column(managed_disk)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migrate_engine):
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
instances.drop_column(managed_disk)
|
@ -241,6 +241,7 @@ class Instance(BASE, NovaBase):
|
|||||||
access_ip_v4 = Column(String(255))
|
access_ip_v4 = Column(String(255))
|
||||||
access_ip_v6 = Column(String(255))
|
access_ip_v6 = Column(String(255))
|
||||||
|
|
||||||
|
managed_disk = Column(Boolean())
|
||||||
progress = Column(Integer)
|
progress = Column(Integer)
|
||||||
|
|
||||||
|
|
||||||
|
156
nova/tests/api/openstack/contrib/test_diskconfig.py
Normal file
156
nova/tests/api/openstack/contrib/test_diskconfig.py
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
# Copyright 2011 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 json
|
||||||
|
import webob
|
||||||
|
|
||||||
|
from nova import compute
|
||||||
|
from nova import exception
|
||||||
|
from nova import image
|
||||||
|
from nova import test
|
||||||
|
from nova.api.openstack.contrib.diskconfig import DiskConfigController
|
||||||
|
from nova.api.openstack.contrib.diskconfig import ImageDiskConfigController
|
||||||
|
from nova.tests.api.openstack import fakes
|
||||||
|
|
||||||
|
|
||||||
|
class DiskConfigTest(test.TestCase):
|
||||||
|
|
||||||
|
def test_retrieve_disk_config(self):
|
||||||
|
def fake_compute_get(*args, **kwargs):
|
||||||
|
return {'managed_disk': True}
|
||||||
|
|
||||||
|
self.stubs.Set(compute.api.API, 'routing_get', fake_compute_get)
|
||||||
|
req = webob.Request.blank('/v1.1/openstack/servers/50/os-disk-config')
|
||||||
|
req.headers['Accept'] = 'application/json'
|
||||||
|
res = req.get_response(fakes.wsgi_app())
|
||||||
|
self.assertEqual(res.status_int, 200)
|
||||||
|
body = json.loads(res.body)
|
||||||
|
self.assertEqual(body['server']['managed_disk'], True)
|
||||||
|
self.assertEqual(int(body['server']['id']), 50)
|
||||||
|
|
||||||
|
def test_set_disk_config(self):
|
||||||
|
def fake_compute_get(*args, **kwargs):
|
||||||
|
return {'managed_disk': 'True'}
|
||||||
|
|
||||||
|
def fake_compute_update(*args, **kwargs):
|
||||||
|
return {'managed_disk': 'False'}
|
||||||
|
|
||||||
|
self.stubs.Set(compute.api.API, 'update', fake_compute_update)
|
||||||
|
self.stubs.Set(compute.api.API, 'routing_get', fake_compute_get)
|
||||||
|
|
||||||
|
req = webob.Request.blank('/v1.1/openstack/servers/50/os-disk-config')
|
||||||
|
req.method = 'PUT'
|
||||||
|
req.headers['Accept'] = 'application/json'
|
||||||
|
req.headers['Content-Type'] = 'application/json'
|
||||||
|
req.body = json.dumps({'server': {'managed_disk': False}})
|
||||||
|
|
||||||
|
res = req.get_response(fakes.wsgi_app())
|
||||||
|
self.assertEqual(res.status_int, 200)
|
||||||
|
body = json.loads(res.body)
|
||||||
|
self.assertEqual(body['server']['managed_disk'], False)
|
||||||
|
self.assertEqual(int(body['server']['id']), 50)
|
||||||
|
|
||||||
|
def test_retrieve_disk_config_bad_server_fails(self):
|
||||||
|
def fake_compute_get(*args, **kwargs):
|
||||||
|
raise exception.NotFound()
|
||||||
|
|
||||||
|
self.stubs.Set(compute.api.API, 'routing_get', fake_compute_get)
|
||||||
|
req = webob.Request.blank('/v1.1/openstack/servers/50/os-disk-config')
|
||||||
|
req.headers['Accept'] = 'application/json'
|
||||||
|
res = req.get_response(fakes.wsgi_app())
|
||||||
|
self.assertEqual(res.status_int, 404)
|
||||||
|
|
||||||
|
def test_set_disk_config_bad_server_fails(self):
|
||||||
|
self.called = False
|
||||||
|
|
||||||
|
def fake_compute_get(*args, **kwargs):
|
||||||
|
raise exception.NotFound()
|
||||||
|
|
||||||
|
def fake_compute_update(*args, **kwargs):
|
||||||
|
self.called = True
|
||||||
|
|
||||||
|
self.stubs.Set(compute.api.API, 'update', fake_compute_update)
|
||||||
|
self.stubs.Set(compute.api.API, 'routing_get', fake_compute_get)
|
||||||
|
|
||||||
|
req = webob.Request.blank('/v1.1/openstack/servers/50/os-disk-config')
|
||||||
|
req.method = 'PUT'
|
||||||
|
req.headers['Accept'] = 'application/json'
|
||||||
|
req.headers['Content-Type'] = 'application/json'
|
||||||
|
req.body = json.dumps({'server': {'managed_disk': False}})
|
||||||
|
|
||||||
|
res = req.get_response(fakes.wsgi_app())
|
||||||
|
self.assertEqual(res.status_int, 404)
|
||||||
|
self.assertEqual(self.called, False)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageDiskConfigTest(test.TestCase):
|
||||||
|
|
||||||
|
NOW_GLANCE_FORMAT = "2010-10-11T10:30:22"
|
||||||
|
NOW_API_FORMAT = "2010-10-11T10:30:22Z"
|
||||||
|
|
||||||
|
def test_image_get_disk_config(self):
|
||||||
|
self.flags(image_service='nova.image.glance.GlanceImageService')
|
||||||
|
fakes.stub_out_glance(self.stubs)
|
||||||
|
|
||||||
|
def fake_image_service_show(*args, **kwargs):
|
||||||
|
return {'properties': {'managed_disk': True}}
|
||||||
|
|
||||||
|
self.stubs.Set(image.glance.GlanceImageService, 'show',
|
||||||
|
fake_image_service_show)
|
||||||
|
|
||||||
|
req = webob.Request.blank('/v1.1/openstack/images/10/os-disk-config')
|
||||||
|
req.headers['Accept'] = 'application/json'
|
||||||
|
res = req.get_response(fakes.wsgi_app())
|
||||||
|
self.assertEqual(res.status_int, 200)
|
||||||
|
|
||||||
|
body = json.loads(res.body)
|
||||||
|
|
||||||
|
self.assertEqual(body['image']['managed_disk'], True)
|
||||||
|
self.assertEqual(int(body['image']['id']), 10)
|
||||||
|
|
||||||
|
def test_image_get_disk_config_no_image_fails(self):
|
||||||
|
self.flags(image_service='nova.image.glance.GlanceImageService')
|
||||||
|
fakes.stub_out_glance(self.stubs)
|
||||||
|
|
||||||
|
def fake_image_service_show(*args, **kwargs):
|
||||||
|
raise exception.NotFound()
|
||||||
|
|
||||||
|
self.stubs.Set(image.glance.GlanceImageService, 'show',
|
||||||
|
fake_image_service_show)
|
||||||
|
|
||||||
|
req = webob.Request.blank('/v1.1/openstack/images/10/os-disk-config')
|
||||||
|
req.headers['Accept'] = 'application/json'
|
||||||
|
res = req.get_response(fakes.wsgi_app())
|
||||||
|
self.assertEqual(res.status_int, 404)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _make_image_fixtures(cls):
|
||||||
|
image_id = 123
|
||||||
|
base_attrs = {'created_at': cls.NOW_GLANCE_FORMAT,
|
||||||
|
'updated_at': cls.NOW_GLANCE_FORMAT,
|
||||||
|
'deleted_at': None,
|
||||||
|
'deleted': False}
|
||||||
|
|
||||||
|
fixtures = []
|
||||||
|
|
||||||
|
def add_fixture(**kwargs):
|
||||||
|
kwargs.update(base_attrs)
|
||||||
|
fixtures.append(kwargs)
|
||||||
|
|
||||||
|
# Public image
|
||||||
|
add_fixture(id=1, name='snapshot', is_public=False,
|
||||||
|
status='active', properties={})
|
||||||
|
|
||||||
|
return fixtures
|
@ -102,6 +102,7 @@ class ExtensionControllerTest(test.TestCase):
|
|||||||
"VirtualInterfaces",
|
"VirtualInterfaces",
|
||||||
"Volumes",
|
"Volumes",
|
||||||
"VolumeTypes",
|
"VolumeTypes",
|
||||||
|
"DiskConfig",
|
||||||
]
|
]
|
||||||
self.ext_list.sort()
|
self.ext_list.sort()
|
||||||
|
|
||||||
|
@ -298,6 +298,9 @@ class FakeSessionForMigrationTests(fake.SessionBase):
|
|||||||
def VM_set_name_label(self, *args):
|
def VM_set_name_label(self, *args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def VDI_set_name_label(self, session_ref, vdi_ref, name_label):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def stub_out_migration_methods(stubs):
|
def stub_out_migration_methods(stubs):
|
||||||
def fake_create_snapshot(self, instance):
|
def fake_create_snapshot(self, instance):
|
||||||
|
@ -313,6 +313,11 @@ class VMHelper(HelperBase):
|
|||||||
% locals())
|
% locals())
|
||||||
return vdi_ref
|
return vdi_ref
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_vdi_name_label(cls, session, vdi_uuid, name_label):
|
||||||
|
vdi_ref = session.get_xenapi().VDI.get_by_uuid(vdi_uuid)
|
||||||
|
session.get_xenapi().VDI.set_name_label(vdi_ref, name_label)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_vdi_for_vm_safely(cls, session, vm_ref):
|
def get_vdi_for_vm_safely(cls, session, vm_ref):
|
||||||
"""Retrieves the primary VDI for a VM"""
|
"""Retrieves the primary VDI for a VM"""
|
||||||
@ -370,7 +375,8 @@ class VMHelper(HelperBase):
|
|||||||
return os.path.join(FLAGS.xenapi_sr_base_path, sr_uuid)
|
return os.path.join(FLAGS.xenapi_sr_base_path, sr_uuid)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def upload_image(cls, context, session, instance, vdi_uuids, image_id):
|
def upload_image(cls, context, session, instance, vdi_uuids, image_id,
|
||||||
|
options=None):
|
||||||
""" Requests that the Glance plugin bundle the specified VDIs and
|
""" Requests that the Glance plugin bundle the specified VDIs and
|
||||||
push them into Glance using the specified human-friendly name.
|
push them into Glance using the specified human-friendly name.
|
||||||
"""
|
"""
|
||||||
@ -388,7 +394,8 @@ class VMHelper(HelperBase):
|
|||||||
'glance_port': glance_port,
|
'glance_port': glance_port,
|
||||||
'sr_path': cls.get_sr_path(session),
|
'sr_path': cls.get_sr_path(session),
|
||||||
'os_type': os_type,
|
'os_type': os_type,
|
||||||
'auth_token': getattr(context, 'auth_token', None)}
|
'auth_token': getattr(context, 'auth_token', None),
|
||||||
|
'options': options}
|
||||||
|
|
||||||
kwargs = {'params': pickle.dumps(params)}
|
kwargs = {'params': pickle.dumps(params)}
|
||||||
task = session.async_call_plugin('glance', 'upload_vhd', kwargs)
|
task = session.async_call_plugin('glance', 'upload_vhd', kwargs)
|
||||||
@ -471,7 +478,7 @@ class VMHelper(HelperBase):
|
|||||||
|
|
||||||
# Set the name-label to ease debugging
|
# Set the name-label to ease debugging
|
||||||
vdi_ref = session.get_xenapi().VDI.get_by_uuid(os_vdi_uuid)
|
vdi_ref = session.get_xenapi().VDI.get_by_uuid(os_vdi_uuid)
|
||||||
primary_name_label = get_name_label_for_image(image)
|
primary_name_label = instance.name
|
||||||
session.get_xenapi().VDI.set_name_label(vdi_ref, primary_name_label)
|
session.get_xenapi().VDI.set_name_label(vdi_ref, primary_name_label)
|
||||||
|
|
||||||
cls._check_vdi_size(context, session, instance, os_vdi_uuid)
|
cls._check_vdi_size(context, session, instance, os_vdi_uuid)
|
||||||
@ -559,7 +566,7 @@ class VMHelper(HelperBase):
|
|||||||
_("Kernel/Ramdisk image is too large: %(vdi_size)d bytes, "
|
_("Kernel/Ramdisk image is too large: %(vdi_size)d bytes, "
|
||||||
"max %(max_size)d bytes") % locals())
|
"max %(max_size)d bytes") % locals())
|
||||||
|
|
||||||
name_label = get_name_label_for_image(image)
|
name_label = instance.name
|
||||||
vdi_ref = cls.create_vdi(session, sr_ref, name_label, vdi_size, False)
|
vdi_ref = cls.create_vdi(session, sr_ref, name_label, vdi_size, False)
|
||||||
# From this point we have a VDI on Xen host;
|
# From this point we have a VDI on Xen host;
|
||||||
# If anything goes wrong, we need to remember its uuid.
|
# If anything goes wrong, we need to remember its uuid.
|
||||||
@ -1156,11 +1163,6 @@ def _write_partition(virtual_size, dev):
|
|||||||
LOG.debug(_('Writing partition table %s done.'), dest)
|
LOG.debug(_('Writing partition table %s done.'), dest)
|
||||||
|
|
||||||
|
|
||||||
def get_name_label_for_image(image):
|
|
||||||
# TODO(sirp): This should eventually be the URI for the Glance image
|
|
||||||
return _('Glance image %s') % image
|
|
||||||
|
|
||||||
|
|
||||||
def _mount_filesystem(dev_path, dir):
|
def _mount_filesystem(dev_path, dir):
|
||||||
"""mounts the device specified by dev_path in dir"""
|
"""mounts the device specified by dev_path in dir"""
|
||||||
try:
|
try:
|
||||||
|
@ -549,12 +549,16 @@ class VMOps(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
template_vm_ref = None
|
template_vm_ref = None
|
||||||
|
options = None
|
||||||
|
if instance['managed_disk']:
|
||||||
|
options = {'managed_disk': instance['managed_disk']}
|
||||||
try:
|
try:
|
||||||
template_vm_ref, template_vdi_uuids =\
|
template_vm_ref, template_vdi_uuids =\
|
||||||
self._create_snapshot(instance)
|
self._create_snapshot(instance)
|
||||||
# call plugin to ship snapshot off to glance
|
# call plugin to ship snapshot off to glance
|
||||||
VMHelper.upload_image(context,
|
VMHelper.upload_image(context,
|
||||||
self._session, instance, template_vdi_uuids, image_id)
|
self._session, instance, template_vdi_uuids, image_id,
|
||||||
|
options)
|
||||||
finally:
|
finally:
|
||||||
if template_vm_ref:
|
if template_vm_ref:
|
||||||
self._destroy(instance, template_vm_ref,
|
self._destroy(instance, template_vm_ref,
|
||||||
@ -697,6 +701,11 @@ class VMOps(object):
|
|||||||
# Now we rescan the SR so we find the VHDs
|
# Now we rescan the SR so we find the VHDs
|
||||||
VMHelper.scan_default_sr(self._session)
|
VMHelper.scan_default_sr(self._session)
|
||||||
|
|
||||||
|
# Set name-label so we can find if we need to clean up a failed
|
||||||
|
# migration
|
||||||
|
VMHelper.set_vdi_name_label(self._session, new_cow_uuid,
|
||||||
|
instance.name)
|
||||||
|
|
||||||
return new_cow_uuid
|
return new_cow_uuid
|
||||||
|
|
||||||
def resize_instance(self, instance, vdi_uuid):
|
def resize_instance(self, instance, vdi_uuid):
|
||||||
|
@ -246,7 +246,7 @@ def _prepare_staging_area_for_upload(sr_path, staging_path, vdi_uuids):
|
|||||||
|
|
||||||
|
|
||||||
def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type,
|
def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type,
|
||||||
auth_token):
|
auth_token, options):
|
||||||
"""
|
"""
|
||||||
Create a tarball of the image and then stream that into Glance
|
Create a tarball of the image and then stream that into Glance
|
||||||
using chunked-transfer-encoded HTTP.
|
using chunked-transfer-encoded HTTP.
|
||||||
@ -293,6 +293,9 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type,
|
|||||||
'x-image-meta-container-format': 'ovf',
|
'x-image-meta-container-format': 'ovf',
|
||||||
'x-image-meta-property-os-type': os_type}
|
'x-image-meta-property-os-type': os_type}
|
||||||
|
|
||||||
|
if options.get('managed_disk'):
|
||||||
|
headers['x-image-meta-property-managed-disk'] = options['managed_disk']
|
||||||
|
|
||||||
# If we have an auth_token, set an x-auth-token header
|
# If we have an auth_token, set an x-auth-token header
|
||||||
if auth_token:
|
if auth_token:
|
||||||
ovf_headers['x-auth-token'] = auth_token
|
ovf_headers['x-auth-token'] = auth_token
|
||||||
@ -424,12 +427,13 @@ def upload_vhd(session, args):
|
|||||||
sr_path = params["sr_path"]
|
sr_path = params["sr_path"]
|
||||||
os_type = params["os_type"]
|
os_type = params["os_type"]
|
||||||
auth_token = params["auth_token"]
|
auth_token = params["auth_token"]
|
||||||
|
options = params["options"]
|
||||||
|
|
||||||
staging_path = _make_staging_area(sr_path)
|
staging_path = _make_staging_area(sr_path)
|
||||||
try:
|
try:
|
||||||
_prepare_staging_area_for_upload(sr_path, staging_path, vdi_uuids)
|
_prepare_staging_area_for_upload(sr_path, staging_path, vdi_uuids)
|
||||||
_upload_tarball(staging_path, image_id, glance_host, glance_port,
|
_upload_tarball(staging_path, image_id, glance_host, glance_port,
|
||||||
os_type, auth_token)
|
os_type, auth_token, options)
|
||||||
finally:
|
finally:
|
||||||
_cleanup_staging_area(staging_path)
|
_cleanup_staging_area(staging_path)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user