From fb755ae05b0b6a7b3701614c8d702e8a24ff380c Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Sun, 24 Jul 2011 00:07:00 -0700 Subject: [PATCH] some cosmetic changes. Prior to merge proposal --- nova/tests/test_vsa.py | 185 +++++++++++++++++++++++++++++++++++++++++ nova/vsa/api.py | 44 ++++++---- 2 files changed, 212 insertions(+), 17 deletions(-) create mode 100644 nova/tests/test_vsa.py diff --git a/nova/tests/test_vsa.py b/nova/tests/test_vsa.py new file mode 100644 index 000000000000..859fe3325415 --- /dev/null +++ b/nova/tests/test_vsa.py @@ -0,0 +1,185 @@ +# 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 stubout +import base64 + +from xml.etree import ElementTree +from xml.etree.ElementTree import Element, SubElement + +from nova import exception +from nova import flags +from nova import vsa +from nova import db +from nova import context +from nova import test +from nova import log as logging +import nova.image.fake + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.tests.vsa') + + +def fake_drive_type_get_by_name(context, name): + drive_type = { + 'id': 1, + 'name': name, + 'type': name.split('_')[0], + 'size_gb': int(name.split('_')[1]), + 'rpm': name.split('_')[2], + 'capabilities': '', + 'visible': True} + return drive_type + + +class VsaTestCase(test.TestCase): + + def setUp(self): + super(VsaTestCase, self).setUp() + self.stubs = stubout.StubOutForTesting() + self.vsa_api = vsa.API() + + self.context_non_admin = context.RequestContext(None, None) + self.context = context.get_admin_context() + + def fake_show_by_name(meh, context, name): + if name == 'wrong_image_name': + LOG.debug(_("Test: Emulate wrong VSA name. Raise")) + raise exception.ImageNotFound + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}} + + self.stubs.Set(nova.image.fake._FakeImageService, 'show_by_name', + fake_show_by_name) + + def tearDown(self): + self.stubs.UnsetAll() + super(VsaTestCase, self).tearDown() + + def test_vsa_create_delete_defaults(self): + param = {'display_name': 'VSA name test'} + vsa_ref = self.vsa_api.create(self.context, **param) + self.assertEqual(vsa_ref['display_name'], param['display_name']) + self.vsa_api.delete(self.context, vsa_ref['id']) + + def test_vsa_create_delete_check_in_db(self): + vsa_list1 = self.vsa_api.get_all(self.context) + vsa_ref = self.vsa_api.create(self.context) + vsa_list2 = self.vsa_api.get_all(self.context) + self.assertEqual(len(vsa_list2), len(vsa_list1) + 1) + + self.vsa_api.delete(self.context, vsa_ref['id']) + vsa_list3 = self.vsa_api.get_all(self.context) + self.assertEqual(len(vsa_list3), len(vsa_list2) - 1) + + def test_vsa_create_delete_high_vc_count(self): + param = {'vc_count': FLAGS.max_vcs_in_vsa + 1} + vsa_ref = self.vsa_api.create(self.context, **param) + self.assertEqual(vsa_ref['vc_count'], FLAGS.max_vcs_in_vsa) + self.vsa_api.delete(self.context, vsa_ref['id']) + + def test_vsa_create_wrong_image_name(self): + param = {'image_name': 'wrong_image_name'} + self.assertRaises(exception.ApiError, + self.vsa_api.create, self.context, **param) + + def test_vsa_create_db_error(self): + + def fake_vsa_create(context, options): + LOG.debug(_("Test: Emulate DB error. Raise")) + raise exception.Error + + self.stubs.Set(nova.db.api, 'vsa_create', fake_vsa_create) + self.assertRaises(exception.ApiError, + self.vsa_api.create, self.context) + + def test_vsa_create_wrong_storage_params(self): + vsa_list1 = self.vsa_api.get_all(self.context) + param = {'storage': [{'stub': 1}]} + self.assertRaises(exception.ApiError, + self.vsa_api.create, self.context, **param) + vsa_list2 = self.vsa_api.get_all(self.context) + self.assertEqual(len(vsa_list2), len(vsa_list1) + 1) + + param = {'storage': [{'drive_name': 'wrong name'}]} + self.assertRaises(exception.ApiError, + self.vsa_api.create, self.context, **param) + + def test_vsa_create_with_storage(self, multi_vol_creation=True): + """Test creation of VSA with BE storage""" + + FLAGS.vsa_multi_vol_creation = multi_vol_creation + + self.stubs.Set(nova.vsa.drive_types, 'get_by_name', + fake_drive_type_get_by_name) + + param = {'storage': [{'drive_name': 'SATA_500_7200', + 'num_drives': 3}]} + vsa_ref = self.vsa_api.create(self.context, **param) + self.assertEqual(vsa_ref['vol_count'], 3) + self.vsa_api.delete(self.context, vsa_ref['id']) + + param = {'storage': [{'drive_name': 'SATA_500_7200', + 'num_drives': 3}], + 'shared': True} + vsa_ref = self.vsa_api.create(self.context, **param) + self.assertEqual(vsa_ref['vol_count'], 15) + self.vsa_api.delete(self.context, vsa_ref['id']) + + def test_vsa_create_with_storage_single_volumes(self): + self.test_vsa_create_with_storage(multi_vol_creation=False) + + def test_vsa_update(self): + vsa_ref = self.vsa_api.create(self.context) + + param = {'vc_count': FLAGS.max_vcs_in_vsa + 1} + vsa_ref = self.vsa_api.update(self.context, vsa_ref['id'], **param) + self.assertEqual(vsa_ref['vc_count'], FLAGS.max_vcs_in_vsa) + + param = {'vc_count': 2} + vsa_ref = self.vsa_api.update(self.context, vsa_ref['id'], **param) + self.assertEqual(vsa_ref['vc_count'], 2) + + self.vsa_api.delete(self.context, vsa_ref['id']) + + def test_vsa_generate_user_data(self): + self.stubs.Set(nova.vsa.drive_types, 'get_by_name', + fake_drive_type_get_by_name) + + FLAGS.vsa_multi_vol_creation = False + param = {'display_name': 'VSA name test', + 'display_description': 'VSA desc test', + 'vc_count': 2, + 'storage': [{'drive_name': 'SATA_500_7200', + 'num_drives': 3}]} + vsa_ref = self.vsa_api.create(self.context, **param) + volumes = db.volume_get_all_assigned_to_vsa(self.context, + vsa_ref['id']) + + user_data = self.vsa_api.generate_user_data(self.context, + vsa_ref, + volumes) + user_data = base64.b64decode(user_data) + + LOG.debug(_("Test: user_data = %s"), user_data) + + elem = ElementTree.fromstring(user_data) + self.assertEqual(elem.findtext('name'), + param['display_name']) + self.assertEqual(elem.findtext('description'), + param['display_description']) + self.assertEqual(elem.findtext('vc_count'), + str(param['vc_count'])) + + self.vsa_api.delete(self.context, vsa_ref['id']) diff --git a/nova/vsa/api.py b/nova/vsa/api.py index b366b658772b..80637cc9e817 100644 --- a/nova/vsa/api.py +++ b/nova/vsa/api.py @@ -74,15 +74,15 @@ class API(base.Base): num_disks = node.get('num_drives', 1) if name is None: - raise exception.ApiError(_("No drive_name param found in %s"), - node) + raise exception.ApiError(_("No drive_name param found in %s") + % node) # find DB record for this disk try: drive_ref = drive_types.get_by_name(context, name) except exception.NotFound: - raise exception.ApiError(_("Invalid drive type name %s"), - name) + raise exception.ApiError(_("Invalid drive type name %s") + % name) # if size field present - override disk size specified in DB size = node.get('size', drive_ref['size_gb']) @@ -149,8 +149,8 @@ class API(base.Base): vc_image = image_service.show_by_name(context, image_name) vc_image_href = vc_image['id'] except exception.ImageNotFound: - raise exception.ApiError(_("Failed to find configured image %s"), - image_name) + raise exception.ApiError(_("Failed to find configured image %s") + % image_name) options = { 'display_name': display_name, @@ -258,34 +258,42 @@ class API(base.Base): """ LOG.info(_("VSA ID %(vsa_id)d: Update VSA call"), locals()) + updatable_fields = ['status', 'vc_count', 'vol_count', + 'display_name', 'display_description'] + changes = {} + for field in updatable_fields: + if field in kwargs: + changes[field] = kwargs[field] + vc_count = kwargs.get('vc_count', None) if vc_count is not None: # VP-TODO: This request may want to update number of VCs # Get number of current VCs and add/delete VCs appropriately vsa = self.get(context, vsa_id) vc_count = int(vc_count) + if vc_count > FLAGS.max_vcs_in_vsa: + LOG.warning(_("Requested number of VCs (%d) is too high."\ + " Setting to default"), vc_count) + vc_count = FLAGS.max_vcs_in_vsa + if vsa['vc_count'] != vc_count: self.update_num_vcs(context, vsa, vc_count) + changes['vc_count'] = vc_count - return self.db.vsa_update(context, vsa_id, kwargs) + return self.db.vsa_update(context, vsa_id, changes) def update_num_vcs(self, context, vsa, vc_count): - if vc_count > FLAGS.max_vcs_in_vsa: - LOG.warning(_("Requested number of VCs (%d) is too high."\ - " Setting to default"), vc_count) - vc_count = FLAGS.max_vcs_in_vsa - vsa_name = vsa['name'] - old_vc_count = vsa['vc_count'] + old_vc_count = int(vsa['vc_count']) if vc_count > old_vc_count: add_cnt = vc_count - old_vc_count - LOG.debug(_("Adding %(add_cnt)d VCs to VSA %(vsa_name)s."), + LOG.debug(_("Adding %(add_cnt)s VCs to VSA %(vsa_name)s."), locals()) # VP-TODO: actual code for adding new VCs elif vc_count < old_vc_count: del_cnt = old_vc_count - vc_count - LOG.debug(_("Deleting %(add_cnt)d VCs from VSA %(vsa_name)s."), + LOG.debug(_("Deleting %(del_cnt)s VCs from VSA %(vsa_name)s."), locals()) # VP-TODO: actual code for deleting extra VCs @@ -372,9 +380,11 @@ class API(base.Base): e_vsa_detail = SubElement(e_vsa, "vc_count") e_vsa_detail.text = str(vsa['vc_count']) e_vsa_detail = SubElement(e_vsa, "auth_user") - e_vsa_detail.text = str(context.user.name) + if context.user is not None: + e_vsa_detail.text = str(context.user.name) e_vsa_detail = SubElement(e_vsa, "auth_access_key") - e_vsa_detail.text = str(context.user.access) + if context.user is not None: + e_vsa_detail.text = str(context.user.access) e_volumes = SubElement(e_vsa, "volumes") for volume in volumes: