summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Dague <sean@dague.net>2016-08-11 15:20:53 -0400
committerMatt Riedemann <mriedem@us.ibm.com>2016-08-12 16:00:56 -0400
commitf839cf1625714c2e159631c56560d9d92eb9964f (patch)
tree8e9e21285283a12a4cdaef2fcb1dda08aeaf9863
parentfe1fd3321bce29f283e010db90423ddcd7d4f7fd (diff)
downloadpython-novaclient-f839cf1625714c2e159631c56560d9d92eb9964f.tar.gz
Look up image names directly in glance
This does a lookup directly to the image service for name => id mapping of images. This is required to move on to supporting the 2.36 microversion since that microversion makes the compute image API proxy return a 404, so before the client can support that microversion it has to first drop it's usage of the proxy API. Because of the way the FakeHTTPClient was stubbing the image API proxy and the tests are not passing uuids for image IDs, there is a lot of cleaning up of the tests to make this work with a fake glance v2 API backend. The tests were basically false though since you can't do 'nova image-show 1', but because the stubs mask that it's just been a mountain of lies that has to be cleaned up here. As a side effect of fixing a bunch of the tests, this also makes debugging assert_called less terrible with a better error message. Co-Authored-By: Matt Riedemann <mriedem@us.ibm.com> Related to blueprint deprecate-api-proxies Change-Id: Iaff3999eafb7d746e5c6032f07ce0756f7b5e868
-rw-r--r--novaclient/base.py18
-rw-r--r--novaclient/tests/unit/fakes.py10
-rw-r--r--novaclient/tests/unit/v2/fakes.py65
-rw-r--r--novaclient/tests/unit/v2/test_shell.py289
-rw-r--r--novaclient/v2/client.py1
-rw-r--r--novaclient/v2/images.py43
-rw-r--r--novaclient/v2/shell.py16
-rw-r--r--releasenotes/notes/no-glance-proxy-5c13001a4b13e8ce.yaml10
8 files changed, 278 insertions, 174 deletions
diff --git a/novaclient/base.py b/novaclient/base.py
index 14485e5e..6e9fdcdf 100644
--- a/novaclient/base.py
+++ b/novaclient/base.py
@@ -267,6 +267,18 @@ class Manager(HookableMixin):
return ListWithMeta(items, resp)
@contextlib.contextmanager
+ def alternate_service_type(self, default, allowed_types=()):
+ original_service_type = self.api.client.service_type
+ if original_service_type in allowed_types:
+ yield
+ else:
+ self.api.client.service_type = default
+ try:
+ yield
+ finally:
+ self.api.client.service_type = original_service_type
+
+ @contextlib.contextmanager
def completion_cache(self, cache_type, obj_class, mode):
"""The completion cache for bash autocompletion.
@@ -332,7 +344,11 @@ class Manager(HookableMixin):
def _get(self, url, response_key):
resp, body = self.api.client.get(url)
- return self.resource_class(self, body[response_key], loaded=True,
+ if response_key is not None:
+ content = body[response_key]
+ else:
+ content = body
+ return self.resource_class(self, content, loaded=True,
resp=resp)
def _create(self, url, body, response_key, return_raw=False, **kwargs):
diff --git a/novaclient/tests/unit/fakes.py b/novaclient/tests/unit/fakes.py
index c6964865..e89370bc 100644
--- a/novaclient/tests/unit/fakes.py
+++ b/novaclient/tests/unit/fakes.py
@@ -78,13 +78,19 @@ class FakeClient(object):
}, pos=4)
"""
expected = (method, url)
- called = self.client.callstack[pos][0:2]
assert self.client.callstack, \
"Expected %s %s but no calls were made." % expected
+ called = self.client.callstack[pos][0:2]
+
assert expected == called, \
- 'Expected %s %s; got %s %s' % (expected + called)
+ ('\nExpected: %(expected)s'
+ '\nActual: %(called)s'
+ '\nCall position: %(pos)s'
+ '\nCalls:\n%(calls)s' %
+ {'expected': expected, 'called': called, 'pos': pos,
+ 'calls': '\n'.join(str(c) for c in self.client.callstack)})
if body is not None:
if self.client.callstack[pos][2] != body:
diff --git a/novaclient/tests/unit/v2/fakes.py b/novaclient/tests/unit/v2/fakes.py
index b4b671ff..59e5e858 100644
--- a/novaclient/tests/unit/v2/fakes.py
+++ b/novaclient/tests/unit/v2/fakes.py
@@ -45,6 +45,8 @@ CALLBACK_RE = re.compile(r"^get_http:__nova_api:8774_v\d(_\d)?$")
# fake image uuids
FAKE_IMAGE_UUID_1 = 'c99d7632-bd66-4be9-aed5-3dd14b223a76'
FAKE_IMAGE_UUID_2 = 'f27f479a-ddda-419a-9bbc-d6b56b210161'
+FAKE_IMAGE_UUID_SNAPSHOT = '555cae93-fb41-4145-9c52-f5b923538a26'
+FAKE_IMAGE_UUID_SNAP_DEL = '55bb23af-97a4-4068-bdf8-f10c62880ddf'
# fake request id
FAKE_REQUEST_ID = fakes.FAKE_REQUEST_ID
@@ -128,6 +130,12 @@ class FakeHTTPClient(base_client.HTTPClient):
# more like we'd expect when making REST calls.
raise exceptions.NotFound('404')
+ # Handle fake glance v2 requests
+ v2_image = False
+ if callback.startswith('get_v2_images'):
+ v2_image = True
+ callback = callback.replace('get_v2_', 'get_')
+
if not hasattr(self, callback):
raise AssertionError('Called unknown API method: %s %s, '
'expected fakes method name: %s' %
@@ -137,6 +145,12 @@ class FakeHTTPClient(base_client.HTTPClient):
self.callstack.append((method, url, kwargs.get('body')))
status, headers, body = getattr(self, callback)(**kwargs)
+
+ # If we're dealing with a glance v2 image response, the response
+ # isn't wrapped like the compute images API proxy is, so handle that.
+ if body and v2_image and 'image' in body:
+ body = body['image']
+
r = utils.TestResponse({
"status_code": status,
"text": body,
@@ -417,7 +431,7 @@ class FakeHTTPClient(base_client.HTTPClient):
"id": 5678,
"name": "sample-server2",
"image": {
- "id": 2,
+ "id": FAKE_IMAGE_UUID_1,
"name": "sample image",
},
"flavor": {
@@ -742,9 +756,11 @@ class FakeHTTPClient(base_client.HTTPClient):
_body = {'adminPass': 'RescuePassword'}
elif action == 'createImage':
assert set(body[action].keys()) == set(['name', 'metadata'])
- _headers = dict(location="http://blah/images/456")
+ _headers = dict(location="http://blah/images/%s" %
+ FAKE_IMAGE_UUID_SNAPSHOT)
if body[action]['name'] == 'mysnapshot_deleted':
- _headers = dict(location="http://blah/images/457")
+ _headers = dict(location="http://blah/images/%s" %
+ FAKE_IMAGE_UUID_SNAP_DEL)
elif action == 'os-getConsoleOutput':
assert list(body[action]) == ['length']
return (202, {}, {'output': 'foo'})
@@ -1079,8 +1095,6 @@ class FakeHTTPClient(base_client.HTTPClient):
#
def get_images(self, **kw):
return (200, {}, {'images': [
- {'id': 1, 'name': 'CentOS 5.2'},
- {'id': 2, 'name': 'My Server Backup'},
{'id': FAKE_IMAGE_UUID_1, 'name': 'CentOS 5.2'},
{'id': FAKE_IMAGE_UUID_2, 'name': 'My Server Backup'}
]})
@@ -1088,18 +1102,7 @@ class FakeHTTPClient(base_client.HTTPClient):
def get_images_detail(self, **kw):
return (200, {}, {'images': [
{
- 'id': 1,
- 'name': 'CentOS 5.2',
- "updated": "2010-10-10T12:00:00Z",
- "created": "2010-08-10T12:00:00Z",
- "status": "ACTIVE",
- "metadata": {
- "test_key": "test_value",
- },
- "links": {},
- },
- {
- "id": 2,
+ "id": FAKE_IMAGE_UUID_SNAPSHOT,
"name": "My Server Backup",
"serverId": 1234,
"updated": "2010-10-10T12:00:00Z",
@@ -1109,7 +1112,7 @@ class FakeHTTPClient(base_client.HTTPClient):
"links": {},
},
{
- "id": 3,
+ "id": FAKE_IMAGE_UUID_SNAP_DEL,
"name": "My Server Backup Deleted",
"serverId": 1234,
"updated": "2010-10-10T12:00:00Z",
@@ -1141,38 +1144,31 @@ class FakeHTTPClient(base_client.HTTPClient):
}
]})
- def get_images_1(self, **kw):
+ def get_images_555cae93_fb41_4145_9c52_f5b923538a26(self, **kw):
return (200, {}, {'image': self.get_images_detail()[2]['images'][0]})
- def get_images_2(self, **kw):
- return (200, {}, {'image': self.get_images_detail()[2]['images'][1]})
-
- def get_images_456(self, **kw):
+ def get_images_55bb23af_97a4_4068_bdf8_f10c62880ddf(self, **kw):
return (200, {}, {'image': self.get_images_detail()[2]['images'][1]})
- def get_images_457(self, **kw):
- return (200, {}, {'image': self.get_images_detail()[2]['images'][2]})
-
def get_images_c99d7632_bd66_4be9_aed5_3dd14b223a76(self, **kw):
- return (200, {}, {'image': self.get_images_detail()[2]['images'][3]})
+ return (200, {}, {'image': self.get_images_detail()[2]['images'][2]})
def get_images_f27f479a_ddda_419a_9bbc_d6b56b210161(self, **kw):
- return (200, {}, {'image': self.get_images_detail()[2]['images'][4]})
+ return (200, {}, {'image': self.get_images_detail()[2]['images'][3]})
def get_images_3e861307_73a6_4d1f_8d68_f68b03223032(self):
raise exceptions.NotFound('404')
- def post_images_1_metadata(self, body, **kw):
+ def post_images_c99d7632_bd66_4be9_aed5_3dd14b223a76_metadata(
+ self, body, **kw):
assert list(body) == ['metadata']
fakes.assert_has_keys(body['metadata'],
required=['test_key'])
+ get_image = self.get_images_c99d7632_bd66_4be9_aed5_3dd14b223a76
return (
200,
{},
- {'metadata': self.get_images_1()[2]['image']['metadata']})
-
- def delete_images_1(self, **kw):
- return (204, {}, None)
+ {'metadata': get_image()[2]['image']['metadata']})
def delete_images_c99d7632_bd66_4be9_aed5_3dd14b223a76(self, **kw):
return (204, {}, None)
@@ -1180,7 +1176,8 @@ class FakeHTTPClient(base_client.HTTPClient):
def delete_images_f27f479a_ddda_419a_9bbc_d6b56b210161(self, **kw):
return (204, {}, None)
- def delete_images_1_metadata_test_key(self, **kw):
+ def delete_images_c99d7632_bd66_4be9_aed5_3dd14b223a76_metadata_test_key(
+ self, **kw):
return (204, {}, None)
#
diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py
index cac85853..90469ea1 100644
--- a/novaclient/tests/unit/v2/test_shell.py
+++ b/novaclient/tests/unit/v2/test_shell.py
@@ -131,13 +131,14 @@ class ShellTest(utils.TestCase):
"md5hash": "add6bb58e139be103324d04d82d8f546"}})
def test_boot(self):
- self.run_command('boot --flavor 1 --image 1 some-server')
+ self.run_command('boot --flavor 1 --image %s '
+ 'some-server' % FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
}},
@@ -151,20 +152,21 @@ class ShellTest(utils.TestCase):
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
}},
)
def test_boot_key(self):
- self.run_command('boot --flavor 1 --image 1 --key-name 1 some-server')
+ self.run_command('boot --flavor 1 --image %s --key-name 1 some-server'
+ % FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'key_name': '1',
'min_count': 1,
'max_count': 1,
@@ -177,13 +179,14 @@ class ShellTest(utils.TestCase):
data = testfile_fd.read().encode('utf-8')
expected_file_data = base64.b64encode(data).decode('utf-8')
self.run_command(
- 'boot --flavor 1 --image 1 --user-data %s some-server' % testfile)
+ 'boot --flavor 1 --image %s --user-data %s some-server' %
+ (FAKE_UUID_1, testfile))
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'user_data': expected_file_data
@@ -192,14 +195,14 @@ class ShellTest(utils.TestCase):
def test_boot_avzone(self):
self.run_command(
- 'boot --flavor 1 --image 1 --availability-zone avzone '
- 'some-server')
+ 'boot --flavor 1 --image %s --availability-zone avzone '
+ 'some-server' % FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'availability_zone': 'avzone',
'min_count': 1,
'max_count': 1
@@ -208,8 +211,8 @@ class ShellTest(utils.TestCase):
def test_boot_secgroup(self):
self.run_command(
- 'boot --flavor 1 --image 1 --security-groups secgroup1,'
- 'secgroup2 some-server')
+ 'boot --flavor 1 --image %s --security-groups secgroup1,'
+ 'secgroup2 some-server' % FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{'server': {
@@ -217,7 +220,7 @@ class ShellTest(utils.TestCase):
{'name': 'secgroup2'}],
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
}},
@@ -225,13 +228,14 @@ class ShellTest(utils.TestCase):
def test_boot_config_drive(self):
self.run_command(
- 'boot --flavor 1 --image 1 --config-drive 1 some-server')
+ 'boot --flavor 1 --image %s --config-drive 1 some-server' %
+ FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'config_drive': True
@@ -240,14 +244,14 @@ class ShellTest(utils.TestCase):
def test_boot_access_ip(self):
self.run_command(
- 'boot --flavor 1 --image 1 --access-ip-v4 10.10.10.10 '
- '--access-ip-v6 ::1 some-server')
+ 'boot --flavor 1 --image %s --access-ip-v4 10.10.10.10 '
+ '--access-ip-v6 ::1 some-server' % FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'accessIPv4': '10.10.10.10',
'accessIPv6': '::1',
'max_count': 1,
@@ -257,13 +261,14 @@ class ShellTest(utils.TestCase):
def test_boot_config_drive_custom(self):
self.run_command(
- 'boot --flavor 1 --image 1 --config-drive /dev/hda some-server')
+ 'boot --flavor 1 --image %s --config-drive /dev/hda some-server' %
+ FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'config_drive': '/dev/hda'
@@ -273,8 +278,8 @@ class ShellTest(utils.TestCase):
def test_boot_invalid_user_data(self):
invalid_file = os.path.join(os.path.dirname(__file__),
'no_such_file')
- cmd = ('boot some-server --flavor 1 --image 1'
- ' --user-data %s' % invalid_file)
+ cmd = ('boot some-server --flavor 1 --image %s'
+ ' --user-data %s' % (FAKE_UUID_1, invalid_file))
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_no_image_no_bdms(self):
@@ -282,7 +287,7 @@ class ShellTest(utils.TestCase):
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_no_flavor(self):
- cmd = 'boot --image 1 some-server'
+ cmd = 'boot --image %s some-server' % FAKE_UUID_1
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_no_image_bdms(self):
@@ -309,9 +314,9 @@ class ShellTest(utils.TestCase):
def test_boot_image_bdms_v2(self):
self.run_command(
- 'boot --flavor 1 --image 1 --block-device id=fake-id,'
+ 'boot --flavor 1 --image %s --block-device id=fake-id,'
'source=volume,dest=volume,device=vda,size=1,format=ext4,'
- 'type=disk,shutdown=preserve some-server'
+ 'type=disk,shutdown=preserve some-server' % FAKE_UUID_1
)
self.assert_called_anytime(
'POST', '/os-volumes_boot',
@@ -320,7 +325,7 @@ class ShellTest(utils.TestCase):
'name': 'some-server',
'block_device_mapping_v2': [
{
- 'uuid': 1,
+ 'uuid': FAKE_UUID_1,
'source_type': 'image',
'destination_type': 'local',
'boot_index': 0,
@@ -337,7 +342,7 @@ class ShellTest(utils.TestCase):
'delete_on_termination': False,
},
],
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
}},
@@ -345,9 +350,9 @@ class ShellTest(utils.TestCase):
def test_boot_image_bdms_v2_with_tag(self):
self.run_command(
- 'boot --flavor 1 --image 1 --block-device id=fake-id,'
+ 'boot --flavor 1 --image %s --block-device id=fake-id,'
'source=volume,dest=volume,device=vda,size=1,format=ext4,'
- 'type=disk,shutdown=preserve,tag=foo some-server',
+ 'type=disk,shutdown=preserve,tag=foo some-server' % FAKE_UUID_1,
api_version='2.32'
)
self.assert_called_anytime(
@@ -357,7 +362,7 @@ class ShellTest(utils.TestCase):
'name': 'some-server',
'block_device_mapping_v2': [
{
- 'uuid': 1,
+ 'uuid': FAKE_UUID_1,
'source_type': 'image',
'destination_type': 'local',
'boot_index': 0,
@@ -375,7 +380,7 @@ class ShellTest(utils.TestCase):
'tag': 'foo',
},
],
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
}},
@@ -504,20 +509,20 @@ class ShellTest(utils.TestCase):
def test_boot_bdms_v2_invalid_shutdown_value(self):
self.assertRaises(exceptions.CommandError, self.run_command,
- ('boot --flavor 1 --image 1 --block-device '
+ ('boot --flavor 1 --image %s --block-device '
'id=fake-id,source=volume,dest=volume,device=vda,'
'size=1,format=ext4,type=disk,shutdown=foobar '
- 'some-server'))
+ 'some-server' % FAKE_UUID_1))
def test_boot_metadata(self):
- self.run_command('boot --image 1 --flavor 1 --meta foo=bar=pants'
- ' --meta spam=eggs some-server ')
+ self.run_command('boot --image %s --flavor 1 --meta foo=bar=pants'
+ ' --meta spam=eggs some-server ' % FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'metadata': {'foo': 'bar=pants', 'spam': 'eggs'},
'min_count': 1,
'max_count': 1,
@@ -525,15 +530,16 @@ class ShellTest(utils.TestCase):
)
def test_boot_hints(self):
- self.run_command('boot --image 1 --flavor 1 '
- '--hint a=b0=c0 --hint a=b1=c1 some-server ')
+ self.run_command('boot --image %s --flavor 1 '
+ '--hint a=b0=c0 --hint a=b1=c1 some-server ' %
+ FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
},
@@ -542,8 +548,9 @@ class ShellTest(utils.TestCase):
)
def test_boot_nics(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id=a=c,v4-fixed-ip=10.0.0.1 some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id=a=c,v4-fixed-ip=10.0.0.1 some-server' %
+ FAKE_UUID_1)
self.run_command(cmd)
self.assert_called_anytime(
'POST', '/servers',
@@ -551,7 +558,7 @@ class ShellTest(utils.TestCase):
'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'networks': [
@@ -562,8 +569,9 @@ class ShellTest(utils.TestCase):
)
def test_boot_nics_with_tag(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id=a=c,v4-fixed-ip=10.0.0.1,tag=foo some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id=a=c,v4-fixed-ip=10.0.0.1,tag=foo some-server' %
+ FAKE_UUID_1)
self.run_command(cmd, api_version='2.32')
self.assert_called_anytime(
'POST', '/servers',
@@ -571,7 +579,7 @@ class ShellTest(utils.TestCase):
'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'networks': [
@@ -583,23 +591,24 @@ class ShellTest(utils.TestCase):
def test_boot_invalid_nics_pre_v2_32(self):
# This is a negative test to make sure we fail with the correct message
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id=1,port-id=2 some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id=1,port-id=2 some-server' % FAKE_UUID_1)
ex = self.assertRaises(exceptions.CommandError, self.run_command,
cmd, api_version='2.1')
self.assertNotIn('tag=tag', six.text_type(ex))
def test_boot_invalid_nics_v2_32(self):
# This is a negative test to make sure we fail with the correct message
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id=1,port-id=2 some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id=1,port-id=2 some-server' % FAKE_UUID_1)
ex = self.assertRaises(exceptions.CommandError, self.run_command,
cmd, api_version='2.32')
self.assertIn('tag=tag', six.text_type(ex))
def test_boot_nics_ipv6(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id=a=c,v6-fixed-ip=2001:db9:0:1::10 some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id=a=c,v6-fixed-ip=2001:db9:0:1::10 some-server' %
+ FAKE_UUID_1)
self.run_command(cmd)
self.assert_called_anytime(
'POST', '/servers',
@@ -607,7 +616,7 @@ class ShellTest(utils.TestCase):
'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'networks': [
@@ -618,44 +627,48 @@ class ShellTest(utils.TestCase):
)
def test_boot_nics_both_ipv4_and_ipv6(self):
- cmd = ('boot --image 1 --flavor 1 '
+ cmd = ('boot --image %s --flavor 1 '
'--nic net-id=a=c,v4-fixed-ip=10.0.0.1,'
- 'v6-fixed-ip=2001:db9:0:1::10 some-server')
+ 'v6-fixed-ip=2001:db9:0:1::10 some-server' % FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_nics_no_value(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id some-server' % FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_nics_random_key(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id=a=c,v4-fixed-ip=10.0.0.1,foo=bar some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id=a=c,v4-fixed-ip=10.0.0.1,foo=bar some-server' %
+ FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_nics_no_netid_or_portid(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic v4-fixed-ip=10.0.0.1 some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic v4-fixed-ip=10.0.0.1 some-server' % FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_nics_netid_and_portid(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic port-id=some=port,net-id=some=net some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic port-id=some=port,net-id=some=net some-server' %
+ FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_nics_invalid_ipv4(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id=a=c,v4-fixed-ip=2001:db9:0:1::10 some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id=a=c,v4-fixed-ip=2001:db9:0:1::10 some-server' %
+ FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_nics_invalid_ipv6(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id=a=c,v6-fixed-ip=10.0.0.1 some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id=a=c,v6-fixed-ip=10.0.0.1 some-server' %
+ FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_nics_net_id_twice(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-id=net-id1,net-id=net-id2 some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-id=net-id1,net-id=net-id2 some-server' % FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
@mock.patch(
@@ -664,8 +677,8 @@ class ShellTest(utils.TestCase):
mock_networks_list.return_value = (200, {}, {
'networks': [{"label": "some-net", 'id': '1'}]})
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-name=some-net some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-name=some-net some-server' % FAKE_UUID_1)
self.run_command(cmd)
self.assert_called_anytime(
'POST', '/servers',
@@ -673,7 +686,7 @@ class ShellTest(utils.TestCase):
'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'networks': [
@@ -684,8 +697,8 @@ class ShellTest(utils.TestCase):
)
def test_boot_nics_net_name_not_found(self):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-name=some-net some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-name=some-net some-server' % FAKE_UUID_1)
self.assertRaises(exceptions.ResourceNotFound, self.run_command, cmd)
@mock.patch(
@@ -695,20 +708,22 @@ class ShellTest(utils.TestCase):
'networks': [{"label": "some-net", 'id': '1'},
{"label": "some-net", 'id': '2'}]})
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-name=some-net some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-name=some-net some-server' % FAKE_UUID_1)
self.assertRaises(exceptions.NoUniqueMatch, self.run_command, cmd)
@mock.patch('novaclient.v2.shell._find_network_id', return_value='net-id')
def test_boot_nics_net_name_and_net_id(self, mock_find_network_id):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-name=some-net,net-id=some-id some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-name=some-net,net-id=some-id some-server' %
+ FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
@mock.patch('novaclient.v2.shell._find_network_id', return_value='net-id')
def test_boot_nics_net_name_and_port_id(self, mock_find_network_id):
- cmd = ('boot --image 1 --flavor 1 '
- '--nic net-name=some-net,port-id=some-id some-server')
+ cmd = ('boot --image %s --flavor 1 '
+ '--nic net-name=some-net,port-id=some-id some-server' %
+ FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_files(self):
@@ -717,16 +732,16 @@ class ShellTest(utils.TestCase):
data = testfile_fd.read()
expected = base64.b64encode(data.encode('utf-8')).decode('utf-8')
- cmd = ('boot some-server --flavor 1 --image 1'
+ cmd = ('boot some-server --flavor 1 --image %s'
' --file /tmp/foo=%s --file /tmp/bar=%s')
- self.run_command(cmd % (testfile, testfile))
+ self.run_command(cmd % (FAKE_UUID_1, testfile, testfile))
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'personality': [
@@ -739,92 +754,96 @@ class ShellTest(utils.TestCase):
def test_boot_invalid_files(self):
invalid_file = os.path.join(os.path.dirname(__file__),
'asdfasdfasdfasdf')
- cmd = ('boot some-server --flavor 1 --image 1'
- ' --file /foo=%s' % invalid_file)
+ cmd = ('boot some-server --flavor 1 --image %s'
+ ' --file /foo=%s' % (FAKE_UUID_1, invalid_file))
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_max_min_count(self):
- self.run_command('boot --image 1 --flavor 1 --min-count 1'
- ' --max-count 3 server')
+ self.run_command('boot --image %s --flavor 1 --min-count 1'
+ ' --max-count 3 server' % FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 3,
}
})
def test_boot_invalid_min_count(self):
- cmd = 'boot --image 1 --flavor 1 --min-count 0 server'
+ cmd = 'boot --image %s --flavor 1 --min-count 0 server' % FAKE_UUID_1
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_min_max_count(self):
- self.run_command('boot --image 1 --flavor 1 --max-count 3 server')
+ self.run_command('boot --image %s --flavor 1 --max-count 3 server' %
+ FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 3,
}
})
- self.run_command('boot --image 1 --flavor 1 --min-count 3 server')
+ self.run_command('boot --image %s --flavor 1 --min-count 3 server' %
+ FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 3,
'max_count': 3,
}
})
- self.run_command('boot --image 1 --flavor 1 '
- '--min-count 3 --max-count 3 server')
+ self.run_command('boot --image %s --flavor 1 '
+ '--min-count 3 --max-count 3 server' % FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 3,
'max_count': 3,
}
})
- self.run_command('boot --image 1 --flavor 1 '
- '--min-count 3 --max-count 5 server')
+ self.run_command('boot --image %s --flavor 1 '
+ '--min-count 3 --max-count 5 server' % FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 3,
'max_count': 5,
}
})
- cmd = 'boot --image 1 --flavor 1 --min-count 3 --max-count 1 serv'
+ cmd = ('boot --image %s --flavor 1 --min-count 3 --max-count 1 serv' %
+ FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
@mock.patch('novaclient.v2.shell._poll_for_status')
def test_boot_with_poll(self, poll_method):
- self.run_command('boot --flavor 1 --image 1 some-server --poll')
+ self.run_command('boot --flavor 1 --image %s some-server --poll' %
+ FAKE_UUID_1)
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
- 'imageRef': '1',
+ 'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
}},
@@ -836,13 +855,14 @@ class ShellTest(utils.TestCase):
def test_boot_with_poll_to_check_VM_state_error(self):
self.assertRaises(exceptions.ResourceInErrorState, self.run_command,
- 'boot --flavor 1 --image 1 some-bad-server --poll')
+ 'boot --flavor 1 --image %s some-bad-server --poll' %
+ FAKE_UUID_1)
def test_boot_named_flavor(self):
self.run_command(["boot", "--image", FAKE_UUID_1,
"--flavor", "512 MB Server",
"--max-count", "3", "server"])
- self.assert_called('GET', '/images/' + FAKE_UUID_1, pos=0)
+ self.assert_called('GET', '/v2/images/' + FAKE_UUID_1, pos=0)
self.assert_called('GET', '/flavors/512 MB Server', pos=1)
self.assert_called('GET', '/flavors?is_public=None', pos=2)
self.assert_called('GET', '/flavors/2', pos=3)
@@ -859,7 +879,8 @@ class ShellTest(utils.TestCase):
}, pos=4)
def test_boot_invalid_ephemeral_data_format(self):
- cmd = 'boot --flavor 1 --image 1 --ephemeral 1 some-server'
+ cmd = ('boot --flavor 1 --image %s --ephemeral 1 some-server' %
+ FAKE_UUID_1)
self.assertRaises(argparse.ArgumentTypeError, self.run_command, cmd)
def test_flavor_list(self):
@@ -949,19 +970,22 @@ class ShellTest(utils.TestCase):
{'removeTenantAccess': {'tenant': 'proj2'}})
def test_image_show(self):
- _, err = self.run_command('image-show 1')
+ _, err = self.run_command('image-show %s' % FAKE_UUID_1)
self.assertIn('Command image-show is deprecated', err)
- self.assert_called('GET', '/images/1')
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_1)
def test_image_meta_set(self):
- _, err = self.run_command('image-meta 1 set test_key=test_value')
+ _, err = self.run_command('image-meta %s set test_key=test_value' %
+ FAKE_UUID_1)
self.assertIn('Command image-meta is deprecated', err)
- self.assert_called('POST', '/images/1/metadata',
+ self.assert_called('POST', '/images/%s/metadata' % FAKE_UUID_1,
{'metadata': {'test_key': 'test_value'}})
def test_image_meta_del(self):
- self.run_command('image-meta 1 delete test_key=test_value')
- self.assert_called('DELETE', '/images/1/metadata/test_key')
+ self.run_command('image-meta %s delete test_key=test_value' %
+ FAKE_UUID_1)
+ self.assert_called('DELETE', '/images/%s/metadata/test_key' %
+ FAKE_UUID_1)
@mock.patch('sys.stdout', six.StringIO())
@mock.patch('sys.stderr', six.StringIO())
@@ -1009,7 +1033,8 @@ class ShellTest(utils.TestCase):
)
self.assertEqual(1, poll_method.call_count)
poll_method.assert_has_calls(
- [mock.call(self.shell.cs.images.get, '456', 'snapshotting',
+ [mock.call(self.shell.cs.glance.find_image,
+ fakes.FAKE_IMAGE_UUID_SNAPSHOT, 'snapshotting',
['active'])])
def test_create_image_with_poll_to_check_image_state_deleted(self):
@@ -1018,15 +1043,15 @@ class ShellTest(utils.TestCase):
'image-create sample-server mysnapshot_deleted --poll')
def test_image_delete(self):
- _, err = self.run_command('image-delete 1')
+ _, err = self.run_command('image-delete %s' % FAKE_UUID_1)
self.assertIn('Command image-delete is deprecated', err)
- self.assert_called('DELETE', '/images/1')
+ self.assert_called('DELETE', '/images/%s' % FAKE_UUID_1)
def test_image_delete_multiple(self):
self.run_command('image-delete %s %s' % (FAKE_UUID_1, FAKE_UUID_2))
- self.assert_called('GET', '/images/' + FAKE_UUID_1, pos=0)
+ self.assert_called('GET', '/v2/images/' + FAKE_UUID_1, pos=0)
self.assert_called('DELETE', '/images/' + FAKE_UUID_1, pos=1)
- self.assert_called('GET', '/images/' + FAKE_UUID_2, pos=2)
+ self.assert_called('GET', '/v2/images/' + FAKE_UUID_2, pos=2)
self.assert_called('DELETE', '/images/' + FAKE_UUID_2, pos=3)
def test_list(self):
@@ -1042,8 +1067,8 @@ class ShellTest(utils.TestCase):
self.assert_called('GET', '/servers/detail?deleted=True')
def test_list_with_images(self):
- self.run_command('list --image 1')
- self.assert_called('GET', '/servers/detail?image=1')
+ self.run_command('list --image %s' % FAKE_UUID_1)
+ self.assert_called('GET', '/servers/detail?image=%s' % FAKE_UUID_1)
def test_list_with_flavors(self):
self.run_command('list --flavor 1')
@@ -1180,11 +1205,11 @@ class ShellTest(utils.TestCase):
output, _ = self.run_command('rebuild sample-server %s' % FAKE_UUID_1)
self.assert_called('GET', '/servers?name=sample-server', pos=0)
self.assert_called('GET', '/servers/1234', pos=1)
- self.assert_called('GET', '/images/%s' % FAKE_UUID_1, pos=2)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_1, pos=2)
self.assert_called('POST', '/servers/1234/action',
{'rebuild': {'imageRef': FAKE_UUID_1}}, pos=3)
self.assert_called('GET', '/flavors/1', pos=4)
- self.assert_called('GET', '/images/%s' % FAKE_UUID_2, pos=5)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_2, pos=5)
self.assertIn('adminPass', output)
def test_rebuild_password(self):
@@ -1193,12 +1218,12 @@ class ShellTest(utils.TestCase):
% FAKE_UUID_1)
self.assert_called('GET', '/servers?name=sample-server', pos=0)
self.assert_called('GET', '/servers/1234', pos=1)
- self.assert_called('GET', '/images/%s' % FAKE_UUID_1, pos=2)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_1, pos=2)
self.assert_called('POST', '/servers/1234/action',
{'rebuild': {'imageRef': FAKE_UUID_1,
'adminPass': 'asdf'}}, pos=3)
self.assert_called('GET', '/flavors/1', pos=4)
- self.assert_called('GET', '/images/%s' % FAKE_UUID_2, pos=5)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_2, pos=5)
self.assertIn('adminPass', output)
def test_rebuild_preserve_ephemeral(self):
@@ -1206,25 +1231,25 @@ class ShellTest(utils.TestCase):
% FAKE_UUID_1)
self.assert_called('GET', '/servers?name=sample-server', pos=0)
self.assert_called('GET', '/servers/1234', pos=1)
- self.assert_called('GET', '/images/%s' % FAKE_UUID_1, pos=2)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_1, pos=2)
self.assert_called('POST', '/servers/1234/action',
{'rebuild': {'imageRef': FAKE_UUID_1,
'preserve_ephemeral': True}}, pos=3)
self.assert_called('GET', '/flavors/1', pos=4)
- self.assert_called('GET', '/images/%s' % FAKE_UUID_2, pos=5)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_2, pos=5)
def test_rebuild_name_meta(self):
self.run_command('rebuild sample-server %s --name asdf --meta '
'foo=bar' % FAKE_UUID_1)
self.assert_called('GET', '/servers?name=sample-server', pos=0)
self.assert_called('GET', '/servers/1234', pos=1)
- self.assert_called('GET', '/images/%s' % FAKE_UUID_1, pos=2)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_1, pos=2)
self.assert_called('POST', '/servers/1234/action',
{'rebuild': {'imageRef': FAKE_UUID_1,
'name': 'asdf',
'metadata': {'foo': 'bar'}}}, pos=3)
self.assert_called('GET', '/flavors/1', pos=4)
- self.assert_called('GET', '/images/%s' % FAKE_UUID_2, pos=5)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_2, pos=5)
def test_start(self):
self.run_command('start sample-server')
@@ -1282,9 +1307,9 @@ class ShellTest(utils.TestCase):
{'rescue': {'adminPass': 'asdf'}})
def test_rescue_image(self):
- self.run_command('rescue sample-server --image 1')
+ self.run_command('rescue sample-server --image %s' % FAKE_UUID_1)
self.assert_called('POST', '/servers/1234/action',
- {'rescue': {'rescue_image_ref': 1}})
+ {'rescue': {'rescue_image_ref': FAKE_UUID_1}})
def test_unrescue(self):
self.run_command('unrescue sample-server')
@@ -1356,7 +1381,7 @@ class ShellTest(utils.TestCase):
self.assert_called('GET', '/servers?name=1234', pos=1)
self.assert_called('GET', '/servers/1234', pos=2)
self.assert_called('GET', '/flavors/1', pos=3)
- self.assert_called('GET', '/images/%s' % FAKE_UUID_2, pos=4)
+ self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_2, pos=4)
def test_show_no_image(self):
self.run_command('show 9012')
@@ -1369,13 +1394,13 @@ class ShellTest(utils.TestCase):
def test_show_unavailable_image_and_flavor(self):
output, _ = self.run_command('show 9013')
- self.assert_called('GET', '/servers/9013', pos=-8)
+ self.assert_called('GET', '/servers/9013', pos=-6)
self.assert_called('GET',
'/flavors/80645cf4-6ad3-410a-bbc8-6f3e1e291f51',
- pos=-7)
+ pos=-5)
self.assert_called('GET',
- '/images/3e861307-73a6-4d1f-8d68-f68b03223032',
- pos=-3)
+ '/v2/images/3e861307-73a6-4d1f-8d68-f68b03223032',
+ pos=-1)
self.assertIn('Image not found', output)
self.assertIn('Flavor not found', output)
diff --git a/novaclient/v2/client.py b/novaclient/v2/client.py
index f5dee15d..044653f5 100644
--- a/novaclient/v2/client.py
+++ b/novaclient/v2/client.py
@@ -131,6 +131,7 @@ class Client(object):
self.flavors = flavors.FlavorManager(self)
self.flavor_access = flavor_access.FlavorAccessManager(self)
self.images = images.ImageManager(self)
+ self.glance = images.GlanceManager(self)
self.limits = limits.LimitsManager(self)
self.servers = servers.ServerManager(self)
self.versions = versions.VersionManager(self)
diff --git a/novaclient/v2/images.py b/novaclient/v2/images.py
index dbbc60ce..d00abba1 100644
--- a/novaclient/v2/images.py
+++ b/novaclient/v2/images.py
@@ -18,9 +18,12 @@ DEPRECATED: Image interface.
import warnings
+from oslo_utils import uuidutils
from six.moves.urllib import parse
from novaclient import base
+from novaclient import exceptions
+from novaclient.i18n import _
class Image(base.Resource):
@@ -42,6 +45,46 @@ class Image(base.Resource):
return self.manager.delete(self)
+class GlanceManager(base.Manager):
+ """Use glance directly from service catalog.
+
+ This is used to do name to id lookups for images. Do not use it
+ for anything else besides that. You have been warned.
+
+ """
+
+ resource_class = Image
+
+ def find_image(self, name_or_id):
+ """Find an image by name or id (user provided input)."""
+
+ with self.alternate_service_type(
+ 'image', allowed_types=('image',)):
+ # glance catalog entries are the unversioned endpoint, so
+ # we need to jam a version bit in here.
+ if uuidutils.is_uuid_like(name_or_id):
+ # if it's a uuid, then just go collect the info and be
+ # done with it.
+ return self._get('/v2/images/%s' % name_or_id, None)
+ else:
+ matches = self._list('/v2/images?name=%s' % name_or_id,
+ "images")
+ num_matches = len(matches)
+ if num_matches == 0:
+ msg = "No %s matching %s." % (
+ self.resource_class.__name__, name_or_id)
+ raise exceptions.NotFound(404, msg)
+ elif num_matches > 1:
+ msg = (_("Multiple %(class)s matches found for "
+ "'%(name)s', use an ID to be more specific.") %
+ {'class': self.resource_class.__name__.lower(),
+ 'name': name_or_id})
+ raise exceptions.NoUniqueMatch(msg)
+ else:
+ matches[0].append_request_ids(matches.request_ids)
+ return matches[0]
+
+
class ImageManager(base.ManagerWithFind):
"""
DEPRECATED: Manage :class:`Image` resources.
diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py
index f0f81367..f3a4fcb2 100644
--- a/novaclient/v2/shell.py
+++ b/novaclient/v2/shell.py
@@ -1274,7 +1274,7 @@ def _print_image(image):
info = image._info.copy()
# ignore links, we don't need to present those
- info.pop('links')
+ info.pop('links', None)
# try to replace a server entity to just an id
server = info.pop('server', None)
@@ -1322,7 +1322,10 @@ def do_image_delete(cs, args):
emit_image_deprecation_warning('image-delete')
for image in args.image:
try:
- _find_image(cs, image).delete()
+ # _find_image is using the GlanceManager which doesn't implement
+ # the delete() method so use the ImagesManager for that.
+ image = _find_image(cs, image)
+ cs.images.delete(image)
except Exception as e:
print(_("Delete for image %(image)s failed: %(e)s") %
{'image': image, 'e': e})
@@ -2080,7 +2083,7 @@ def do_image_create(cs, args):
image_uuid = cs.servers.create_image(server, args.name, meta)
if args.poll:
- _poll_for_status(cs.images.get, image_uuid, 'snapshotting',
+ _poll_for_status(cs.glance.find_image, image_uuid, 'snapshotting',
['active'])
# NOTE(sirp): A race-condition exists between when the image finishes
@@ -2099,7 +2102,7 @@ def do_image_create(cs, args):
show_progress=False, silent=True)
if args.show:
- _print_image(cs.images.get(image_uuid))
+ _print_image(_find_image(cs, image_uuid))
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
@@ -2253,7 +2256,10 @@ def _find_server(cs, server, raise_if_notfound=True, **find_args):
def _find_image(cs, image):
"""Get an image by name or ID."""
- return utils.find_resource(cs.images, image)
+ try:
+ return cs.glance.find_image(image)
+ except (exceptions.NotFound, exceptions.NoUniqueMatch) as e:
+ raise exceptions.CommandError(six.text_type(e))
def _find_flavor(cs, flavor):
diff --git a/releasenotes/notes/no-glance-proxy-5c13001a4b13e8ce.yaml b/releasenotes/notes/no-glance-proxy-5c13001a4b13e8ce.yaml
new file mode 100644
index 00000000..01b65bb7
--- /dev/null
+++ b/releasenotes/notes/no-glance-proxy-5c13001a4b13e8ce.yaml
@@ -0,0 +1,10 @@
+---
+upgrade:
+ - |
+ The 2.36 microversion deprecated the image proxy API. As such, CLI calls
+ now directly call the image service to get image details, for example,
+ as a convenience to boot a server with an image name rather than the image
+ id. To do this the following is assumed:
+
+ #. There is an **image** entry in the service catalog.
+ #. The image v2 API is available.