Allow image and flavor by name for create_server

We do a bunch of work everywhere else in shade to be friendly - but for
some reason we only accept object or id for image and flavor. Fix it.

In the unit tests, pass in a dict with an id value to avoid the need to
mock the glance client, since that's not really what we're testing in
any of those tests ... but add a test that does not do that to verify
that the glance and nova clients are used to look at image/flavor lists.

Change-Id: I1760a7464e43e19a475f6d277148a3c7e54ac468
This commit is contained in:
Monty Taylor 2016-08-14 10:00:56 -05:00
parent 79d87718d9
commit 4e7772632a
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
3 changed files with 47 additions and 15 deletions

View File

@ -0,0 +1,9 @@
---
features:
- The image and flavor parameters for create_server
now accept name in addition to id and dict. If given
as a name or id, shade will do a get_image or a
get_flavor to find the matching image or flavor.
If you have an id already and are not using any caching
and the extra lookup is annoying, passing the id in
as "dict(id='my-id')" will avoid the lookup.

View File

@ -4194,8 +4194,8 @@ class OpenStackCloud(object):
"""Create a virtual server instance.
:param name: Something to name the server.
:param image: Image dict or id to boot with.
:param flavor: Flavor dict or id to boot onto.
:param image: Image dict, name or id to boot with.
:param flavor: Flavor dict, name or id to boot onto.
:param auto_ip: Whether to take actions to find a routable IP for
the server. (defaults to True)
:param ips: List of IPs to attach to the server (defaults to None)
@ -4300,7 +4300,15 @@ class OpenStackCloud(object):
if default_network:
kwargs['nics'] = [{'net-id': default_network['id']}]
kwargs['image'] = image
if image:
if isinstance(image, dict):
kwargs['image'] = image
else:
kwargs['image'] = self.get_image(image)
if flavor and isinstance(flavor, dict):
kwargs['flavor'] = flavor
else:
kwargs['flavor'] = self.get_flavor(flavor, get_extra=False)
kwargs = self._get_boot_from_volume_kwargs(
image=image, boot_from_volume=boot_from_volume,
@ -4310,7 +4318,7 @@ class OpenStackCloud(object):
with _utils.shade_exceptions("Error in creating instance"):
server = self.manager.submitTask(_tasks.ServerCreate(
name=name, flavor=flavor, **kwargs))
name=name, **kwargs))
admin_pass = server.get('adminPass') or kwargs.get('admin_pass')
if not wait:
# This is a direct get task call to skip the list_servers

View File

@ -99,7 +99,8 @@ class TestCreateServer(base.TestCase):
self.assertRaises(
OpenStackCloudException,
self.cloud.create_server,
'server-name', 'image-id', 'flavor-id', wait=True)
'server-name', dict(id='image-id'),
dict(id='flavor-id'), wait=True)
def test_create_server_with_timeout(self):
"""
@ -117,7 +118,8 @@ class TestCreateServer(base.TestCase):
self.assertRaises(
OpenStackCloudTimeout,
self.cloud.create_server,
'server-name', 'image-id', 'flavor-id',
'server-name',
dict(id='image-id'), dict(id='flavor-id'),
wait=True, timeout=0.01)
def test_create_server_no_wait(self):
@ -142,8 +144,9 @@ class TestCreateServer(base.TestCase):
cloud_name=self.cloud.name,
region_name=self.cloud.region_name),
self.cloud.create_server(
name='server-name', image='image=id',
flavor='flavor-id'))
name='server-name',
image=dict(id='image=id'),
flavor=dict(id='flavor-id')))
def test_create_server_with_admin_pass_no_wait(self):
"""
@ -168,8 +171,8 @@ class TestCreateServer(base.TestCase):
cloud_name=self.cloud.name,
region_name=self.cloud.region_name),
self.cloud.create_server(
name='server-name', image='image=id',
flavor='flavor-id', admin_pass='ooBootheiX0edoh'))
name='server-name', image=dict(id='image=id'),
flavor=dict(id='flavor-id'), admin_pass='ooBootheiX0edoh'))
@patch.object(OpenStackCloud, "wait_for_server")
@patch.object(OpenStackCloud, "nova_client")
@ -188,8 +191,9 @@ class TestCreateServer(base.TestCase):
meta.obj_to_dict(fake_server), None, None)
server = self.cloud.create_server(
name='server-name', image='image-id',
flavor='flavor-id', admin_pass='ooBootheiX0edoh', wait=True)
name='server-name', image=dict(id='image-id'),
flavor=dict(id='flavor-id'),
admin_pass='ooBootheiX0edoh', wait=True)
# Assert that we did wait
self.assertTrue(mock_wait.called)
@ -245,7 +249,8 @@ class TestCreateServer(base.TestCase):
mock_nova.servers.create.return_value = fake_server
self.cloud.create_server(
'server-name', 'image-id', 'flavor-id', wait=True),
'server-name',
dict(id='image-id'), dict(id='flavor-id'), wait=True),
mock_wait.assert_called_once_with(
fake_server, auto_ip=True, ips=None,
@ -291,7 +296,8 @@ class TestCreateServer(base.TestCase):
attempt to get the network for the server.
"""
self.cloud.create_server(
'server-name', 'image-id', 'flavor-id', network='network-name')
'server-name',
dict(id='image-id'), dict(id='flavor-id'), network='network-name')
mock_get_network.assert_called_once_with(name_or_id='network-name')
@patch('shade.OpenStackCloud.nova_client')
@ -304,6 +310,15 @@ class TestCreateServer(base.TestCase):
it's treated the same as if 'nics' were not included.
"""
self.cloud.create_server(
'server-name', 'image-id', 'flavor-id',
'server-name', dict(id='image-id'), dict(id='flavor-id'),
network='network-name', nics=[])
mock_get_network.assert_called_once_with(name_or_id='network-name')
@patch('shade.OpenStackCloud.glance_client')
@patch('shade.OpenStackCloud.nova_client')
def test_create_server_get_flavor_image(
self, mock_nova, mock_glance):
self.cloud.create_server(
'server-name', 'image-id', 'flavor-id')
mock_nova.flavors.list.assert_called_once()
mock_glance.images.list.assert_called_once()