summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvladimir.p <vladimir@zadarastorage.com>2011-07-24 00:07:00 -0700
committervladimir.p <vladimir@zadarastorage.com>2011-07-24 00:07:00 -0700
commitfb755ae05b0b6a7b3701614c8d702e8a24ff380c (patch)
treecee1e7f0d110085aa578cf065610707dc179ebd5
parent10006a77176f5ffc6e9acd94fe44e6e6695a6716 (diff)
downloadnova-fb755ae05b0b6a7b3701614c8d702e8a24ff380c.tar.gz
nova-fb755ae05b0b6a7b3701614c8d702e8a24ff380c.tar.xz
nova-fb755ae05b0b6a7b3701614c8d702e8a24ff380c.zip
some cosmetic changes. Prior to merge proposal
-rw-r--r--nova/tests/test_vsa.py185
-rw-r--r--nova/vsa/api.py44
2 files changed, 212 insertions, 17 deletions
diff --git a/nova/tests/test_vsa.py b/nova/tests/test_vsa.py
new file mode 100644
index 000000000..859fe3325
--- /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 b366b6587..80637cc9e 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: