Merge "VMware: spawn refactor - phase 1 - fetch_image"

This commit is contained in:
Jenkins 2014-05-18 12:24:36 +00:00 committed by Gerrit Code Review
commit 2a5fd1257a
7 changed files with 265 additions and 85 deletions

View File

@ -65,10 +65,8 @@ def set_stubs(stubs):
"""Set the stubs."""
stubs.Set(network_util, 'get_network_with_the_name',
fake.fake_get_network)
stubs.Set(vmware_images, 'fetch_image', fake.fake_fetch_image)
stubs.Set(vmware_images, 'get_vmdk_size_and_properties',
fake.fake_get_vmdk_size_and_properties)
stubs.Set(vmware_images, 'upload_image', fake.fake_upload_image)
stubs.Set(driver.VMwareAPISession, "_get_vim_object",
fake_get_vim_object)
stubs.Set(driver.VMwareAPISession, "_is_vim_object",

57
nova/tests/virt/vmwareapi/test_configdrive.py Normal file → Executable file
View File

@ -13,11 +13,15 @@
# License for the specific language governing permissions and limitations
# under the License.
import contextlib
import copy
import fixtures
import mock
import mox
from nova import context
from nova.image import glance
from nova import test
import nova.tests.image.fake
from nova.tests import utils
@ -25,6 +29,7 @@ from nova.tests.virt.vmwareapi import stubs
from nova.virt import fake
from nova.virt.vmwareapi import driver
from nova.virt.vmwareapi import fake as vmwareapi_fake
from nova.virt.vmwareapi import read_write_util
from nova.virt.vmwareapi import vm_util
from nova.virt.vmwareapi import vmops
from nova.virt.vmwareapi import vmware_images
@ -47,13 +52,10 @@ class ConfigDriveTestCase(test.NoDBTestCase):
nova.tests.image.fake.stub_out_image_service(self.stubs)
self.conn = driver.VMwareVCDriver(fake.FakeVirtAPI)
self.network_info = utils.get_test_network_info()
self.image = {
'id': 'c1c8ce3d-c2e0-4247-890c-ccf5cc1c004c',
'disk_format': 'vmdk',
'size': 512,
}
self.vim = vmwareapi_fake.FakeVim()
self.node_name = '%s(%s)' % (self.conn.dict_mors.keys()[0],
cluster_name)
image_ref = nova.tests.image.fake.get_valid_image_id()
self.test_instance = {'node': 'test_url',
'vm_state': 'building',
'project_id': 'fake',
@ -68,7 +70,7 @@ class ConfigDriveTestCase(test.NoDBTestCase):
'flavor': 'm1.large',
'vcpus': 4,
'root_gb': 80,
'image_ref': '1',
'image_ref': image_ref,
'host': 'fake_host',
'task_state':
'scheduling',
@ -78,6 +80,15 @@ class ConfigDriveTestCase(test.NoDBTestCase):
'node': self.node_name,
'metadata': []}
(image_service, image_id) = glance.get_remote_image_service(context,
image_ref)
metadata = image_service.show(context, image_id)
self.image = {
'id': image_ref,
'disk_format': 'vmdk',
'size': int(metadata['size']),
}
class FakeInstanceMetadata(object):
def __init__(self, instance, content=None, extra_md=None):
pass
@ -109,11 +120,43 @@ class ConfigDriveTestCase(test.NoDBTestCase):
def _spawn_vm(self, injected_files=[], admin_password=None,
block_device_info=None):
self.conn.spawn(self.context, self.instance, self.image,
read_file_handle = mock.MagicMock()
write_file_handle = mock.MagicMock()
self.image_ref = self.instance['image_ref']
def fake_read_handle(read_iter):
return read_file_handle
def fake_write_handle(host, dc_name, ds_name, cookies,
file_path, file_size, scheme="https"):
self.assertEqual('dc1', dc_name)
self.assertEqual('ds1', ds_name)
self.assertEqual('Fake-CookieJar', cookies)
split_file_path = file_path.split('/')
self.assertEqual('vmware_temp', split_file_path[0])
self.assertEqual(self.image_ref, split_file_path[2])
self.assertEqual(('%s-flat.vmdk' % self.image_ref),
split_file_path[3])
self.assertEqual(int(self.image['size']), file_size)
return write_file_handle
with contextlib.nested(
mock.patch.object(read_write_util, 'VMwareHTTPWriteFile',
side_effect=fake_write_handle),
mock.patch.object(read_write_util, 'GlanceFileRead',
side_effect=fake_read_handle),
mock.patch.object(vmware_images, 'start_transfer')
) as (fake_http_write, fake_glance_read, fake_start_transfer):
self.conn.spawn(self.context, self.instance, self.image,
injected_files=injected_files,
admin_password=admin_password,
network_info=self.network_info,
block_device_info=block_device_info)
fake_start_transfer.assert_called_once_with(self.context,
read_file_handle, self.image['size'],
write_file_handle=write_file_handle)
def test_create_vm_with_config_drive_verify_method_invocation(self):
self.instance = copy.deepcopy(self.test_instance)

122
nova/tests/virt/vmwareapi/test_driver_api.py Normal file → Executable file
View File

@ -37,6 +37,7 @@ from nova.compute import task_states
from nova.compute import vm_states
from nova import context
from nova import exception
from nova.image import glance
from nova.openstack.common import jsonutils
from nova.openstack.common import timeutils
from nova.openstack.common import units
@ -56,6 +57,7 @@ from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import fake as vmwareapi_fake
from nova.virt.vmwareapi import imagecache
from nova.virt.vmwareapi import read_write_util
from nova.virt.vmwareapi import vim
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
@ -319,16 +321,23 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
self.context = context.RequestContext(self.user_id, self.project_id)
stubs.set_stubs(self.stubs)
vmwareapi_fake.reset()
nova.tests.image.fake.stub_out_image_service(self.stubs)
self.conn = driver.VMwareESXDriver(fake.FakeVirtAPI)
self.vim = vmwareapi_fake.FakeVim()
# NOTE(vish): none of the network plugging code is actually
# being tested
self.network_info = utils.get_test_network_info()
image_ref = nova.tests.image.fake.get_valid_image_id()
(image_service, image_id) = glance.get_remote_image_service(
self.context, image_ref)
metadata = image_service.show(self.context, image_id)
self.image = {
'id': 'c1c8ce3d-c2e0-4247-890c-ccf5cc1c004c',
'id': image_ref,
'disk_format': 'vmdk',
'size': 512,
'size': int(metadata['size']),
}
self.fake_image_uuid = self.image['id']
nova.tests.image.fake.stub_out_image_service(self.stubs)
self.vnc_host = 'test_url'
self._set_exception_vars()
@ -347,7 +356,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
'instance_type': 'm1.large',
'vcpus': 4,
'root_gb': 80,
'image_ref': '1',
'image_ref': self.image['id'],
'host': 'fake_host',
'task_state':
'scheduling',
@ -453,7 +462,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
'swap': self.type_data['swap'],
}
if set_image_ref:
values['image_ref'] = "fake_image_uuid"
values['image_ref'] = self.fake_image_uuid
self.instance_node = node
self.uuid = uuid
self.instance = fake_instance.fake_instance_obj(
@ -462,17 +471,48 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
def _create_vm(self, node=None, num_instances=1, uuid=None,
instance_type='m1.large', powered_on=True):
"""Create and spawn the VM."""
read_file_handle = mock.MagicMock()
write_file_handle = mock.MagicMock()
def fake_read_handle(read_iter):
return read_file_handle
def _fake_write_mock(host, dc_name, ds_name, cookies,
file_path, file_size, scheme="https"):
self.vim.fake_transfer_file(ds_name=ds_name,
file_path=file_path)
image_ref = self.image['id']
self.assertIn(dc_name, ['dc1', 'dc2'])
self.assertIn(ds_name, ['ds1', 'ds2'])
self.assertEqual('Fake-CookieJar', cookies)
split_file_path = file_path.split('/')
self.assertEqual('vmware_temp', split_file_path[0])
self.assertEqual(image_ref, split_file_path[2])
self.assertEqual(int(self.image['size']), file_size)
return write_file_handle
if not node:
node = self.node_name
self._create_instance(node=node, uuid=uuid,
instance_type=instance_type)
self.assertIsNone(vm_util.vm_ref_cache_get(self.uuid))
self.conn.spawn(self.context, self.instance, self.image,
injected_files=[], admin_password=None,
network_info=self.network_info,
block_device_info=None)
self._check_vm_record(num_instances=num_instances,
powered_on=powered_on)
with contextlib.nested(
mock.patch.object(read_write_util, 'VMwareHTTPWriteFile',
_fake_write_mock),
mock.patch.object(read_write_util, 'GlanceFileRead',
fake_read_handle),
mock.patch.object(vmware_images, 'start_transfer')
) as (fake_http_write, fake_glance_read, fake_start_transfer):
self.conn.spawn(self.context, self.instance, self.image,
injected_files=[], admin_password=None,
network_info=self.network_info,
block_device_info=None)
fake_start_transfer.assert_called_once_with(self.context,
read_file_handle, self.image['size'],
write_file_handle=write_file_handle)
self._check_vm_record(num_instances=num_instances,
powered_on=powered_on)
self.assertIsNotNone(vm_util.vm_ref_cache_get(self.uuid))
def _check_vm_record(self, num_instances=1, powered_on=True):
@ -560,8 +600,8 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
self.assertEqual(len(uuids), 0)
def _cached_files_exist(self, exists=True):
cache = ('[%s] vmware_base/fake_image_uuid/fake_image_uuid.vmdk' %
self.ds)
cache = ('[%s] vmware_base/%s/%s.vmdk' %
(self.ds, self.fake_image_uuid, self.fake_image_uuid))
if exists:
self.assertTrue(vmwareapi_fake.get_file(cache))
else:
@ -574,8 +614,8 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
self._create_vm()
inst_file_path = '[%s] %s/%s.vmdk' % (self.ds, self.uuid, self.uuid)
cache = ('[%s] vmware_base/fake_image_uuid/fake_image_uuid.vmdk' %
self.ds)
cache = ('[%s] vmware_base/%s/%s.vmdk' %
(self.ds, self.fake_image_uuid, self.fake_image_uuid))
self.assertTrue(vmwareapi_fake.get_file(inst_file_path))
self._cached_files_exist()
@ -583,18 +623,19 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
"""Test image disk is cached when use_linked_clone is True."""
self.flags(use_linked_clone=True, group='vmware')
self._create_vm()
file = ('[%s] vmware_base/fake_image_uuid/fake_image_uuid.vmdk' %
self.ds)
root = ('[%s] vmware_base/fake_image_uuid/fake_image_uuid.80.vmdk' %
self.ds)
file = '[%s] vmware_base/%s/%s.vmdk' % (self.ds, self.fake_image_uuid,
self.fake_image_uuid)
root = '[%s] vmware_base/%s/%s.80.vmdk' % (self.ds,
self.fake_image_uuid,
self.fake_image_uuid)
self.assertTrue(vmwareapi_fake.get_file(file))
self.assertTrue(vmwareapi_fake.get_file(root))
def _iso_disk_type_created(self, instance_type='m1.large'):
self.image['disk_format'] = 'iso'
self._create_vm(instance_type=instance_type)
file = ('[%s] vmware_base/fake_image_uuid/fake_image_uuid.iso' %
self.ds)
file = '[%s] vmware_base/%s/%s.iso' % (self.ds, self.fake_image_uuid,
self.fake_image_uuid)
self.assertTrue(vmwareapi_fake.get_file(file))
def test_iso_disk_type_created(self):
@ -609,7 +650,8 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
def test_iso_disk_cdrom_attach(self):
self.iso_path = (
'[%s] vmware_base/fake_image_uuid/fake_image_uuid.iso' % self.ds)
'[%s] vmware_base/%s/%s.iso' % (self.ds, self.fake_image_uuid,
self.fake_image_uuid))
def fake_attach_cdrom(vm_ref, instance, data_store_ref,
iso_uploaded_path):
@ -623,8 +665,8 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
def test_iso_disk_cdrom_attach_with_config_drive(self):
self.flags(force_config_drive=True)
self.iso_path = [
('[%s] vmware_base/fake_image_uuid/fake_image_uuid.iso' %
self.ds),
'[%s] vmware_base/%s/%s.iso' %
(self.ds, self.fake_image_uuid, self.fake_image_uuid),
'[%s] fake-config-drive' % self.ds]
self.iso_unit_nos = [0, 1]
self.iso_index = 0
@ -757,8 +799,8 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
self._check_vm_info(info, power_state.RUNNING)
def test_spawn_disk_extend_exists(self):
root = ('[%s] vmware_base/fake_image_uuid/fake_image_uuid.80.vmdk' %
self.ds)
root = ('[%s] vmware_base/%s/%s.80.vmdk' %
(self.ds, self.fake_image_uuid, self.fake_image_uuid))
self.root = root
def _fake_extend(instance, requested_size, name, dc_ref):
@ -796,7 +838,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
self.wait_task = self.conn._session._wait_for_task
self.call_method = self.conn._session._call_method
self.task_ref = None
id = 'fake_image_uuid'
id = self.fake_image_uuid
cached_image = '[%s] vmware_base/%s/%s.80.vmdk' % (self.ds,
id, id)
tmp_file = '[%s] vmware_base/%s/%s.80-flat.vmdk' % (self.ds,
@ -1399,8 +1441,21 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
fake_power_on_instance)
self.stubs.Set(self.conn._volumeops, "attach_disk_to_vm",
fake_attach_disk_to_vm)
self.conn.rescue(self.context, self.instance, self.network_info,
self.image, None)
def _fake_http_write(host, data_center_name, datastore_name,
cookies, file_path, file_size, scheme="https"):
self.vim.fake_transfer_file(ds_name=datastore_name,
file_path=file_path)
with contextlib.nested(
mock.patch.object(read_write_util, 'VMwareHTTPWriteFile',
_fake_http_write),
mock.patch.object(read_write_util, 'GlanceFileRead'),
mock.patch.object(vmware_images, 'start_transfer')
) as (http_write, glance_read, fake_start_transfer):
self.conn.rescue(self.context, self.instance, self.network_info,
self.image, 'fake-password')
info = self.conn.get_info({'name': '1-rescue',
'uuid': '%s-rescue' % self.uuid,
'node': self.instance_node})
@ -1794,8 +1849,9 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
_fake_get_timestamp_filename)
def _timestamp_file_exists(self, exists=True):
timestamp = ('[%s] vmware_base/fake_image_uuid/%s/' %
(self.ds, self._get_timestamp_filename()))
timestamp = ('[%s] vmware_base/%s/%s/' %
(self.ds, self.fake_image_uuid,
self._get_timestamp_filename()))
if exists:
self.assertTrue(vmwareapi_fake.get_file(timestamp))
else:
@ -1826,8 +1882,8 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
def test_timestamp_file_removed_aging(self):
self._timestamp_file_removed()
ts = self._get_timestamp_filename()
ts_path = ('[%s] vmware_base/fake_image_uuid/%s/' %
(self.ds, ts))
ts_path = ('[%s] vmware_base/%s/%s/' %
(self.ds, self.fake_image_uuid, ts))
vmwareapi_fake._add_file(ts_path)
self._timestamp_file_exists()
all_instances = [self.instance]

View File

@ -0,0 +1,95 @@
# Copyright (c) 2014 VMware, Inc.
# 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.
"""
Test suite for vmware_images.
"""
import contextlib
import mock
from nova import test
import nova.tests.image.fake
from nova.virt.vmwareapi import read_write_util
from nova.virt.vmwareapi import vmware_images
class VMwareImagesTestCase(test.NoDBTestCase):
"""Unit tests for Vmware API connection calls."""
def setUp(self):
super(VMwareImagesTestCase, self).setUp()
def tearDown(self):
super(VMwareImagesTestCase, self).tearDown()
def test_fetch_image(self):
"""Test fetching images."""
dc_name = 'fake-dc'
file_path = 'fake_file'
ds_name = 'ds1'
host = mock.MagicMock()
context = mock.MagicMock()
image_data = {
'id': nova.tests.image.fake.get_valid_image_id(),
'disk_format': 'vmdk',
'size': 512,
}
read_file_handle = mock.MagicMock()
write_file_handle = mock.MagicMock()
read_iter = mock.MagicMock()
instance = {}
instance['image_ref'] = image_data['id']
instance['uuid'] = 'fake-uuid'
def fake_read_handle(read_iter):
return read_file_handle
def fake_write_handle(host, dc_name, ds_name, cookies,
file_path, file_size):
return write_file_handle
def fake_download(context, image_id):
return read_iter
def fake_image_show(context, image_id):
return image_data
with contextlib.nested(
mock.patch.object(read_write_util, 'GlanceFileRead',
side_effect=fake_read_handle),
mock.patch.object(read_write_util, 'VMwareHTTPWriteFile',
side_effect=fake_write_handle),
mock.patch.object(vmware_images, 'start_transfer'),
mock.patch.object(nova.image.glance.GlanceImageService, 'show',
side_effect=fake_image_show),
mock.patch.object(nova.image.glance.GlanceImageService,
'download', side_effect=fake_download),
) as (glance_read, http_write, start_transfer, image_show,
image_download):
vmware_images.fetch_image(context, instance,
host, dc_name,
ds_name, file_path)
glance_read.assert_called_once_with(read_iter)
http_write.assert_called_once_with(host, dc_name, ds_name, None,
file_path, image_data['size'])
start_transfer.assert_called_once_with(
context, read_file_handle,
image_data['size'],
write_file_handle=write_file_handle)
image_download.assert_called_once_with(context, instance['image_ref'])
image_show.assert_called_once_with(context, instance['image_ref'])

View File

@ -946,14 +946,6 @@ def get_file(file_path):
return file_path in _db_content.get("files")
def fake_fetch_image(context, image, instance, **kwargs):
"""Fakes fetch image call. Just adds a reference to the db for the file."""
ds_name = kwargs.get("datastore_name")
file_path = kwargs.get("file_path")
ds_file_path = "[" + ds_name + "] " + file_path
_add_file(ds_file_path)
def fake_upload_image(context, image, instance, **kwargs):
"""Fakes the upload of an image."""
pass
@ -1272,6 +1264,13 @@ class FakeVim(object):
task_mdo = create_task(method, "success")
return task_mdo.obj
def fake_transfer_file(self, ds_name, file_path):
"""Fakes fetch image call.
Just adds a reference to the db for the file.
"""
ds_file_path = "[" + ds_name + "] " + file_path
_add_file(ds_file_path)
def _make_dir(self, method, *args, **kwargs):
"""Creates a directory in the datastore."""
ds_path = kwargs.get("name")

32
nova/virt/vmwareapi/vmops.py Normal file → Executable file
View File

@ -278,30 +278,6 @@ class VMwareVMOps(object):
vnc_port = vm_util.get_vnc_port(self._session)
self._set_vnc_config(client_factory, instance, vnc_port)
def _fetch_image_on_datastore(upload_name):
"""Fetch image from Glance to datastore."""
LOG.debug(_("Downloading image file data %(image_ref)s to the "
"data store %(data_store_name)s") %
{'image_ref': instance['image_ref'],
'data_store_name': data_store_name},
instance=instance)
vmware_images.fetch_image(
context,
instance['image_ref'],
instance,
host=self._session._host_ip,
data_center_name=dc_info.name,
datastore_name=data_store_name,
cookies=cookies,
file_path=upload_name)
LOG.debug(_("Downloaded image file data %(image_ref)s to "
"%(upload_name)s on the data store "
"%(data_store_name)s") %
{'image_ref': instance['image_ref'],
'upload_name': upload_name,
'data_store_name': data_store_name},
instance=instance)
def _copy_virtual_disk(source, dest):
"""Copy a sparse virtual disk to a thin virtual disk."""
# Copy a sparse virtual disk to a thin virtual disk. This is also
@ -431,7 +407,13 @@ class VMwareVMOps(object):
else:
upload_file_name = sparse_uploaded_vmdk_name
_fetch_image_on_datastore(upload_file_name)
vmware_images.fetch_image(context,
instance,
self._session._host_ip,
dc_info.name,
data_store_name,
upload_file_name,
cookies=cookies)
if not is_iso and disk_type == "sparse":
# Copy the sparse virtual disk to a thin virtual disk.

View File

@ -113,25 +113,32 @@ def upload_iso_to_datastore(iso_path, instance, **kwargs):
instance=instance)
def fetch_image(context, image, instance, **kwargs):
def fetch_image(context, instance, host, dc_name, ds_name, file_path,
cookies=None):
"""Download image from the glance image server."""
LOG.debug(_("Downloading image %s from glance image server") % image,
image_ref = instance['image_ref']
LOG.debug("Downloading image file data %(image_ref)s to the "
"data store %(data_store_name)s",
{'image_ref': image_ref,
'data_store_name': ds_name},
instance=instance)
(image_service, image_id) = glance.get_remote_image_service(context, image)
(image_service, image_id) = glance.get_remote_image_service(context,
image_ref)
metadata = image_service.show(context, image_id)
file_size = int(metadata['size'])
read_iter = image_service.download(context, image_id)
read_file_handle = read_write_util.GlanceFileRead(read_iter)
write_file_handle = read_write_util.VMwareHTTPWriteFile(
kwargs.get("host"),
kwargs.get("data_center_name"),
kwargs.get("datastore_name"),
kwargs.get("cookies"),
kwargs.get("file_path"),
file_size)
host, dc_name, ds_name, cookies, file_path, file_size)
start_transfer(context, read_file_handle, file_size,
write_file_handle=write_file_handle)
LOG.debug(_("Downloaded image %s from glance image server") % image,
LOG.debug("Downloaded image file data %(image_ref)s to "
"%(upload_name)s on the data store "
"%(data_store_name)s",
{'image_ref': image_ref,
'upload_name': 'n/a' if file_path is None else file_path,
'data_store_name': 'n/a' if ds_name is None else ds_name},
instance=instance)