[BugFix] Change parameters for legacy bdm

`_parse_block_device_mapping` method was design to support both
bdm v1 and v2. The implementation is based on the fact that API side
ignores unknown/incorrect parameters, so `_parse_block_device_mapping` compose
equal parameter for bdm v1 and bdm v2. Since Nova V2.1 contains schema checks,
such implementation stoped working.
Despite the fact that novaclient.v2.servers contains separate logic for bdm v2,
we can make `_parse_block_device_mapping` works only with legacy bdm and
in future patches make it works for both bdm v1 and bdm v2.

Change-Id: I37c00ac77b1a3b500221d779533532e9f43e5277
Closes-Bug: #1491737
This commit is contained in:
Andrey Kurilin 2015-09-09 01:04:45 +03:00
parent e612205ab8
commit 5153dcda80
5 changed files with 75 additions and 23 deletions

View File

@ -274,6 +274,9 @@ class BootingManagerWithFind(ManagerWithFind):
"""Like a `ManagerWithFind`, but has the ability to boot servers."""
def _parse_block_device_mapping(self, block_device_mapping):
"""Parses legacy block device mapping."""
# FIXME(andreykurilin): make it work with block device mapping v2
bdm = []
for device_name, mapping in six.iteritems(block_device_mapping):
@ -285,15 +288,9 @@ class BootingManagerWithFind(ManagerWithFind):
mapping_parts = mapping.split(':')
source_id = mapping_parts[0]
bdm_dict['uuid'] = source_id
bdm_dict['boot_index'] = 0
if len(mapping_parts) == 1:
bdm_dict['volume_id'] = source_id
bdm_dict['source_type'] = 'volume'
elif len(mapping_parts) > 1:
if len(mapping_parts) > 1:
source_type = mapping_parts[1]
bdm_dict['source_type'] = source_type
if source_type.startswith('snap'):
bdm_dict['snapshot_id'] = source_id
else:

View File

@ -193,6 +193,28 @@ class ClientTestBase(testtools.TestCase):
self.fail("Volume %s did not reach status %s after %d s"
% (volume.id, status, timeout))
def wait_for_resource_delete(self, resource, manager,
timeout=60, poll_interval=1):
"""Wait until getting the resource raises NotFound exception.
:param resource: Resource object.
:param manager: Manager object with get method.
:param timeout: timeout in seconds
:param poll_interval: poll interval in seconds
"""
start_time = time.time()
while time.time() - start_time < timeout:
try:
manager.get(resource)
except Exception as e:
if getattr(e, "http_status", None) == 404:
break
else:
raise
time.sleep(poll_interval)
else:
self.fail("The resource '%s' still exists." % resource.id)
def name_generate(self, prefix='Entity'):
"""Generate randomized name for some entity.
@ -200,3 +222,24 @@ class ClientTestBase(testtools.TestCase):
"""
name = "%s-%s" % (prefix, six.text_type(uuid.uuid4()))
return name
def _get_value_from_the_table(self, table, key):
"""Parses table to get desired value.
EXAMPLE of the table:
# +-------------+----------------------------------+
# | Property | Value |
# +-------------+----------------------------------+
# | description | |
# | enabled | True |
# | id | 582df899eabc47018c96713c2f7196ba |
# | name | admin |
# +-------------+----------------------------------+
"""
lines = table.split("\n")
for line in lines:
if "|" in line:
l_property, l_value = line.split("|")[1:3]
if l_property.strip() == key:
return l_value.strip()
raise ValueError("Property '%s' is missing from the table." % key)

View File

@ -25,19 +25,10 @@ class TestQuotasNovaClient(base.ClientTestBase):
'server_groups', 'server_group_members']
def test_quotas_update(self):
# `nova quota-update` requires tenant-id. EXAMPLE of keystone output:
# +-------------+----------------------------------+
# | Property | Value |
# +-------------+----------------------------------+
# | description | |
# | enabled | True |
# | id | 582df899eabc47018c96713c2f7196ba |
# | name | admin |
# +-------------+----------------------------------+
# `nova quota-update` requires tenant-id.
tenant_info = self.cli_clients.keystone(
"tenant-get", params=self.cli_clients.tenant_name).split("\n")
tenant_id = [l.rsplit("|", 2)[-2].strip()
for l in tenant_info if "id" in l][0]
"tenant-get", params=self.cli_clients.tenant_name)
tenant_id = self._get_value_from_the_table(tenant_info, "id")
self.addCleanup(self.client.quotas.delete, tenant_id)

View File

@ -16,6 +16,30 @@ from novaclient.tests.functional import base
from novaclient.v2 import shell
class TestServersBootNovaClient(base.ClientTestBase):
"""Servers boot functional tests.
"""
def test_boot_server_with_legacy_bdm(self):
volume_size = 1
volume_name = str(uuid.uuid4())
volume = self.client.volumes.create(size=volume_size,
display_name=volume_name,
imageRef=self.image.id)
self.wait_for_volume_status(volume, "available")
server_info = self.nova("boot", params=(
"%(name)s --flavor %(flavor)s --poll "
"--block-device-mapping vda=%(volume_id)s:::1" % {
"name": str(uuid.uuid4()), "flavor":
self.flavor.id,
"volume_id": volume.id}))
server_id = self._get_value_from_the_table(server_info, "id")
self.client.servers.delete(server_id)
self.wait_for_resource_delete(server_id, self.client.servers)
class TestServersListNovaClient(base.ClientTestBase):
"""Servers list functional tests.
"""

View File

@ -274,10 +274,7 @@ class ShellTest(utils.TestCase):
{
'volume_id': 'blah',
'delete_on_termination': '0',
'device_name': 'vda',
'uuid': 'blah',
'boot_index': 0,
'source_type': ''
'device_name': 'vda'
}
],
'imageRef': '',