nova/nova/tests/virt/vmwareapi/test_imagecache.py

236 lines
10 KiB
Python

# 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.
import contextlib
import datetime
import mock
from oslo.config import cfg
from nova.openstack.common import timeutils
from nova import test
from nova.tests.virt.vmwareapi import fake
from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import imagecache
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vmops
CONF = cfg.CONF
class ImageCacheManagerTestCase(test.NoDBTestCase):
def setUp(self):
super(ImageCacheManagerTestCase, self).setUp()
self._session = mock.Mock(name='session')
self._imagecache = imagecache.ImageCacheManager(self._session,
'fake-base-folder')
self._time = datetime.datetime(2012, 11, 22, 12, 00, 00)
self._file_name = 'ts-2012-11-22-12-00-00'
fake.reset()
def tearDown(self):
super(ImageCacheManagerTestCase, self).tearDown()
fake.reset()
def test_timestamp_cleanup(self):
def fake_get_timestamp(ds_browser, ds_path):
self.assertEqual('fake-ds-browser', ds_browser)
self.assertEqual('fake-ds-path', ds_path)
if not self.exists:
return
ts = '%s%s' % (imagecache.TIMESTAMP_PREFIX,
timeutils.strtime(at=self._time,
fmt=imagecache.TIMESTAMP_FORMAT))
return ts
with contextlib.nested(
mock.patch.object(self._imagecache, '_get_timestamp',
fake_get_timestamp),
mock.patch.object(ds_util, 'file_delete')
) as (_get_timestamp, _file_delete):
self.exists = False
self._imagecache.timestamp_cleanup(
'fake-dc-ref', 'fake-ds-browser', 'fake-ds-path')
self.assertEqual(0, _file_delete.call_count)
self.exists = True
self._imagecache.timestamp_cleanup(
'fake-dc-ref', 'fake-ds-browser', 'fake-ds-path')
_file_delete.assert_called_once_with(self._session,
'fake-ds-path/ts-2012-11-22-12-00-00',
'fake-dc-ref')
def test_get_timestamp(self):
def fake_get_sub_folders(session, ds_browser, ds_path):
self.assertEqual('fake-ds-browser', ds_browser)
self.assertEqual('fake-ds-path', ds_path)
if self.exists:
files = set()
files.add(self._file_name)
return files
with contextlib.nested(
mock.patch.object(ds_util, 'get_sub_folders',
fake_get_sub_folders)
):
self.exists = True
ts = self._imagecache._get_timestamp('fake-ds-browser',
'fake-ds-path')
self.assertEqual(self._file_name, ts)
self.exists = False
ts = self._imagecache._get_timestamp('fake-ds-browser',
'fake-ds-path')
self.assertIsNone(ts)
def test_get_timestamp_filename(self):
timeutils.set_time_override(override_time=self._time)
fn = self._imagecache._get_timestamp_filename()
self.assertEqual(self._file_name, fn)
def test_get_datetime_from_filename(self):
t = self._imagecache._get_datetime_from_filename(self._file_name)
self.assertEqual(self._time, t)
def test_get_ds_browser(self):
cache = self._imagecache._ds_browser
ds_browser = mock.Mock()
moref = fake.ManagedObjectReference('datastore-100')
self.assertIsNone(cache.get(moref.value))
mock_get_method = mock.Mock(return_value=ds_browser)
with mock.patch.object(vim_util, 'get_dynamic_property',
mock_get_method):
ret = self._imagecache._get_ds_browser(moref)
mock_get_method.assert_called_once_with(mock.ANY, moref,
'Datastore', 'browser')
self.assertIs(ds_browser, ret)
self.assertIs(ds_browser, cache.get(moref.value))
def test_list_base_images(self):
def fake_get_dynamic_property(vim, mobj, type, property_name):
return 'fake-ds-browser'
def fake_get_sub_folders(session, ds_browser, ds_path):
files = set()
files.add('image-ref-uuid')
return files
with contextlib.nested(
mock.patch.object(vim_util, 'get_dynamic_property',
fake_get_dynamic_property),
mock.patch.object(ds_util, 'get_sub_folders',
fake_get_sub_folders)
) as (_get_dynamic, _get_sub_folders):
fake_ds_ref = fake.ManagedObjectReference('fake-ds-ref')
datastore = {'name': 'ds', 'ref': fake_ds_ref}
ds_path = ds_util.build_datastore_path(datastore['name'],
'base_folder')
images = self._imagecache._list_datastore_images(
ds_path, datastore)
originals = set()
originals.add('image-ref-uuid')
self.assertEqual({'originals': originals,
'unexplained_images': []},
images)
def test_age_cached_images(self):
def fake_get_ds_browser(ds_ref):
return 'fake-ds-browser'
def fake_get_timestamp(ds_browser, path):
self._get_timestamp_called += 1
if path == 'fake-ds-path/fake-image-1':
# No time stamp exists
return
if path == 'fake-ds-path/fake-image-2':
# Timestamp that will be valid => no deletion
return 'ts-2012-11-22-10-00-00'
if path == 'fake-ds-path/fake-image-3':
# Timestamp that will be invalid => deletion
return 'ts-2012-11-20-12-00-00'
self.fail()
def fake_mkdir(session, ts_path, dc_ref):
self.assertEqual(
'fake-ds-path/fake-image-1/ts-2012-11-22-12-00-00',
ts_path)
def fake_file_delete(session, path, dc_ref):
self.assertEqual('fake-ds-path/fake-image-3', path)
def fake_timestamp_cleanup(dc_ref, ds_browser, path):
self.assertEqual('fake-ds-path/fake-image-4', path)
with contextlib.nested(
mock.patch.object(self._imagecache, '_get_ds_browser',
fake_get_ds_browser),
mock.patch.object(self._imagecache, '_get_timestamp',
fake_get_timestamp),
mock.patch.object(ds_util, 'mkdir',
fake_mkdir),
mock.patch.object(ds_util, 'file_delete',
fake_file_delete),
mock.patch.object(self._imagecache, 'timestamp_cleanup',
fake_timestamp_cleanup),
) as (_get_ds_browser, _get_timestamp, _mkdir, _file_delete,
_timestamp_cleanup):
timeutils.set_time_override(override_time=self._time)
datastore = {'name': 'ds', 'ref': 'fake-ds-ref'}
dc_info = vmops.DcInfo(ref='dc_ref', name='name',
vmFolder='vmFolder')
self._get_timestamp_called = 0
self._imagecache.originals = set(['fake-image-1', 'fake-image-2',
'fake-image-3', 'fake-image-4'])
self._imagecache.used_images = set(['fake-image-4'])
self._imagecache._age_cached_images('fake-context',
datastore, dc_info, 'fake-ds-path')
self.assertEqual(3, self._get_timestamp_called)
def test_update(self):
def fake_list_datastore_images(ds_path, datastore):
return {'unexplained_images': [],
'originals': self.images}
def fake_age_cached_images(context, datastore,
dc_info, ds_path):
self.assertEqual('[ds] fake-base-folder', ds_path)
self.assertEqual(self.images,
self._imagecache.used_images)
self.assertEqual(self.images,
self._imagecache.originals)
with contextlib.nested(
mock.patch.object(self._imagecache, '_list_datastore_images',
fake_list_datastore_images),
mock.patch.object(self._imagecache,
'_age_cached_images',
fake_age_cached_images)
) as (_list_base, _age_and_verify):
instances = [{'image_ref': '1',
'host': CONF.host,
'name': 'inst-1',
'uuid': '123',
'vm_state': '',
'task_state': ''},
{'image_ref': '2',
'host': CONF.host,
'name': 'inst-2',
'uuid': '456',
'vm_state': '',
'task_state': ''}]
self.images = set(['1', '2'])
datastore = {'name': 'ds', 'ref': 'fake-ds-ref'}
dc_info = vmops.DcInfo(ref='dc_ref', name='name',
vmFolder='vmFolder')
datastores_info = [(datastore, dc_info)]
self._imagecache.update('context', instances, datastores_info)