Nova Flavor Server Extensions Rest APIs - Angular
This provide flavor APIs for launch instance work. This provides extension APIs for launch instance work. This provides single server get for instance details work. This provide single flavor get for instance details work. Partially Implements: blueprint launch-instance-redesign Partially Implements: blueprint instance-details-redesign Change-Id: Ia1fd36ec31de21c60801f4d47716ef69aad7525f Co-Authored-By: Richard Jones <r1chardj0n3s@gmail.com>
This commit is contained in:
parent
243d2a5a44
commit
b915760a56
@ -144,6 +144,108 @@ limitations under the License.
|
||||
horizon.alert('error', gettext('Unable to create the server.'));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @name hz.api.novaAPI.getServer
|
||||
* @description
|
||||
* Get a single server by ID
|
||||
* @param {string} id
|
||||
* Specifies the id of the server to request.
|
||||
*/
|
||||
this.getServer = function(id) {
|
||||
return apiService.get('/api/nova/servers/' + id)
|
||||
.error(function () {
|
||||
horizon.alert('error', gettext('Unable to retrieve server.'));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @name hz.api.novaAPI.getExtensions
|
||||
* @description
|
||||
* Returns a list of enabled extensions.
|
||||
*
|
||||
* The listing result is an object with property "items". Each item is
|
||||
* an extension.
|
||||
* @example
|
||||
* The following is an example response:
|
||||
*
|
||||
* {
|
||||
* "items": [
|
||||
* {
|
||||
* "alias": "NMN",
|
||||
* "description": "Multiple network support.",
|
||||
* "links": [],
|
||||
* "name": "Multinic",
|
||||
* "namespace": "http://docs.openstack.org/compute/ext/multinic/api/v1.1",
|
||||
* "updated": "2011-06-09T00:00:00Z"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
this.getExtensions = function() {
|
||||
return apiService.get('/api/nova/extensions/')
|
||||
.error(function () {
|
||||
horizon.alert('error', gettext('Unable to retrieve extensions.'));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @name hz.api.novaAPI.getFlavors
|
||||
* @description
|
||||
* Returns a list of flavors.
|
||||
*
|
||||
* The listing result is an object with property "items". Each item is
|
||||
* a flavor.
|
||||
*
|
||||
* @param {boolean} isPublic (optional)
|
||||
* True if public flavors should be returned. If not specified, the API
|
||||
* will return public flavors by default for Admins and only project
|
||||
* flavors for non-admins.
|
||||
* @param {boolean} getExtras (optional)
|
||||
* Also retrieve the extra specs. This is expensive (one extra underlying
|
||||
* call per flavor).
|
||||
*/
|
||||
this.getFlavors = function(isPublic, getExtras) {
|
||||
var config = {'params': {}};
|
||||
if (isPublic) { config.params.is_public = 'true'; }
|
||||
if (getExtras) { config.params.get_extras = 'true'; }
|
||||
return apiService.get('/api/nova/flavors/', config)
|
||||
.error(function () {
|
||||
horizon.alert('error', gettext('Unable to retrieve flavors.'));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @name hz.api.novaAPI.getFlavor
|
||||
* @description
|
||||
* Get a single flavor by ID.
|
||||
* @param {string} id
|
||||
* Specifies the id of the flavor to request.
|
||||
* @param {boolean} getExtras (optional)
|
||||
* Also retrieve the extra specs for the flavor.
|
||||
*/
|
||||
this.getFlavor = function(id, getExtras) {
|
||||
var config = {'params': {}};
|
||||
if (getExtras) { config.params.get_extras = 'true'; }
|
||||
return apiService.get('/api/nova/flavors/' + id, config)
|
||||
.error(function () {
|
||||
horizon.alert('error', gettext('Unable to retrieve flavor.'));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @name hz.api.novaAPI.getFlavorExtraSpecs
|
||||
* @description
|
||||
* Get a single flavor's extra specs by ID.
|
||||
* @param {string} id
|
||||
* Specifies the id of the flavor to request the extra specs.
|
||||
*/
|
||||
this.getFlavorExtraSpecs = function(id) {
|
||||
return apiService.get('/api/nova/flavors/' + id + '/extra-specs')
|
||||
.error(function () {
|
||||
horizon.alert('error', gettext('Unable to retrieve flavor extra specs.'));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('hz.api')
|
||||
|
@ -117,6 +117,12 @@ class APIResourceWrapper(object):
|
||||
for attr in self._attrs
|
||||
if hasattr(self, attr)))
|
||||
|
||||
def to_dict(self):
|
||||
obj = {}
|
||||
for key in self._attrs:
|
||||
obj[key] = getattr(self._apiresource, key, None)
|
||||
return obj
|
||||
|
||||
|
||||
class APIDictWrapper(object):
|
||||
"""Simple wrapper for api dictionaries
|
||||
|
@ -486,14 +486,21 @@ def flavor_delete(request, flavor_id):
|
||||
novaclient(request).flavors.delete(flavor_id)
|
||||
|
||||
|
||||
def flavor_get(request, flavor_id):
|
||||
return novaclient(request).flavors.get(flavor_id)
|
||||
def flavor_get(request, flavor_id, get_extras=False):
|
||||
flavor = novaclient(request).flavors.get(flavor_id)
|
||||
if get_extras:
|
||||
flavor.extras = flavor_get_extras(request, flavor.id, True, flavor)
|
||||
return flavor
|
||||
|
||||
|
||||
@memoized
|
||||
def flavor_list(request, is_public=True):
|
||||
def flavor_list(request, is_public=True, get_extras=False):
|
||||
"""Get the list of available instance sizes (flavors)."""
|
||||
return novaclient(request).flavors.list(is_public=is_public)
|
||||
flavors = novaclient(request).flavors.list(is_public=is_public)
|
||||
if get_extras:
|
||||
for flavor in flavors:
|
||||
flavor.extras = flavor_get_extras(request, flavor.id, True, flavor)
|
||||
return flavors
|
||||
|
||||
|
||||
@memoized
|
||||
@ -514,9 +521,10 @@ def remove_tenant_from_flavor(request, flavor, tenant):
|
||||
flavor=flavor, tenant=tenant)
|
||||
|
||||
|
||||
def flavor_get_extras(request, flavor_id, raw=False):
|
||||
def flavor_get_extras(request, flavor_id, raw=False, flavor=None):
|
||||
"""Get flavor extra specs."""
|
||||
flavor = novaclient(request).flavors.get(flavor_id)
|
||||
if flavor is None:
|
||||
flavor = novaclient(request).flavors.get(flavor_id)
|
||||
extras = flavor.get_keys()
|
||||
if raw:
|
||||
return extras
|
||||
|
@ -173,3 +173,115 @@ class Servers(generic.View):
|
||||
'/api/nova/servers/%s' % urllib.quote(new.id),
|
||||
new.to_dict()
|
||||
)
|
||||
|
||||
|
||||
@urls.register
|
||||
class Server(generic.View):
|
||||
"""API for retrieving a single server
|
||||
"""
|
||||
url_regex = r'nova/servers/(?P<server_id>.+|default)$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request, server_id):
|
||||
"""Get a specific server
|
||||
|
||||
http://localhost/api/nova/servers/1
|
||||
"""
|
||||
return api.nova.server_get(request, server_id).to_dict()
|
||||
|
||||
|
||||
@urls.register
|
||||
class Extensions(generic.View):
|
||||
"""API for nova extensions.
|
||||
"""
|
||||
url_regex = r'nova/extensions/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request):
|
||||
"""Get a list of extensions.
|
||||
|
||||
The listing result is an object with property "items". Each item is
|
||||
an image.
|
||||
|
||||
Example GET:
|
||||
http://localhost/api/nova/extensions
|
||||
"""
|
||||
result = api.nova.list_extensions(request)
|
||||
return {'items': [e.to_dict() for e in result]}
|
||||
|
||||
|
||||
@urls.register
|
||||
class Flavors(generic.View):
|
||||
"""API for nova flavors.
|
||||
"""
|
||||
url_regex = r'nova/flavors/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request):
|
||||
"""Get a list of flavors.
|
||||
|
||||
The listing result is an object with property "items". Each item is
|
||||
an flavor. By default this will return the flavors for the user's
|
||||
current project. If the user is admin, public flavors will also be
|
||||
returned.
|
||||
|
||||
:param is_public: For a regular user, set to True to see all public
|
||||
flavors. For an admin user, set to False to not see public flavors.
|
||||
:param get_extras: Also retrieve the extra specs.
|
||||
|
||||
Example GET:
|
||||
http://localhost/api/nova/flavors?is_public=true
|
||||
"""
|
||||
is_public = request.GET.get('is_public')
|
||||
is_public = (is_public and is_public.lower() == 'true')
|
||||
get_extras = request.GET.get('get_extras')
|
||||
get_extras = bool(get_extras and get_extras.lower() == 'true')
|
||||
flavors = api.nova.flavor_list(request, is_public=is_public,
|
||||
get_extras=get_extras)
|
||||
result = {'items': []}
|
||||
for flavor in flavors:
|
||||
d = flavor.to_dict()
|
||||
if get_extras:
|
||||
d['extras'] = flavor.extras
|
||||
result['items'].append(d)
|
||||
return result
|
||||
|
||||
|
||||
@urls.register
|
||||
class Flavor(generic.View):
|
||||
"""API for retrieving a single flavor
|
||||
"""
|
||||
url_regex = r'nova/flavors/(?P<flavor_id>.+)/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request, flavor_id):
|
||||
"""Get a specific flavor
|
||||
|
||||
:param get_extras: Also retrieve the extra specs.
|
||||
|
||||
Example GET:
|
||||
http://localhost/api/nova/flavors/1
|
||||
"""
|
||||
get_extras = request.GET.get('get_extras')
|
||||
get_extras = bool(get_extras and get_extras.lower() == 'true')
|
||||
flavor = api.nova.flavor_get(request, flavor_id, get_extras=get_extras)
|
||||
result = flavor.to_dict()
|
||||
if get_extras:
|
||||
result['extras'] = flavor.extras
|
||||
return result
|
||||
|
||||
|
||||
@urls.register
|
||||
class FlavorExtraSpecs(generic.View):
|
||||
"""API for managing flavor extra specs
|
||||
"""
|
||||
url_regex = r'nova/flavors/(?P<flavor_id>.+)/extra-specs$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request, flavor_id):
|
||||
"""Get a specific flavor's extra specs
|
||||
|
||||
Example GET:
|
||||
http://localhost/api/nova/flavors/1/extra-specs
|
||||
"""
|
||||
return api.nova.flavor_get_extras(request, flavor_id, raw=True)
|
||||
|
@ -142,3 +142,131 @@ class NovaRestTestCase(test.TestCase):
|
||||
request, 'Ni!', 'image123', 'flavor123', 'sekrit', 'base64 yes',
|
||||
[{'name': 'root'}]
|
||||
)
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_server_get_single(self, nc):
|
||||
request = self.mock_rest_request()
|
||||
nc.server_get.return_value.to_dict.return_value = {'name': '1'}
|
||||
|
||||
response = nova.Server().get(request, "1")
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.server_get.assert_called_once_with(request, "1")
|
||||
|
||||
#
|
||||
# Extensions
|
||||
#
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def _test_extension_list(self, nc):
|
||||
request = self.mock_rest_request()
|
||||
nc.list_extensions.return_value = [
|
||||
mock.Mock(**{'to_dict.return_value': {'name': 'foo'}}),
|
||||
mock.Mock(**{'to_dict.return_value': {'name': 'bar'}}),
|
||||
]
|
||||
response = nova.Extensions().get(request)
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.content,
|
||||
'{"items": [{"name": "foo"}, {"name": "bar"}]}')
|
||||
nc.list_extensions.assert_called_once_with(request)
|
||||
|
||||
#
|
||||
# Flavors
|
||||
#
|
||||
def test_get_extras_no(self):
|
||||
self._test_flavor_get_single(get_extras=False)
|
||||
|
||||
def test_get_extras_yes(self):
|
||||
self._test_flavor_get_single(get_extras=True)
|
||||
|
||||
def test_get_extras_default(self):
|
||||
self._test_flavor_get_single(get_extras=None)
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def _test_flavor_get_single(self, nc, get_extras):
|
||||
if get_extras:
|
||||
request = self.mock_rest_request(GET={'get_extras': 'tRuE'})
|
||||
elif get_extras is None:
|
||||
request = self.mock_rest_request()
|
||||
get_extras = False
|
||||
else:
|
||||
request = self.mock_rest_request(GET={'get_extras': 'fAlsE'})
|
||||
nc.flavor_get.return_value.to_dict.return_value = {'name': '1'}
|
||||
|
||||
response = nova.Flavor().get(request, "1")
|
||||
self.assertStatusCode(response, 200)
|
||||
if get_extras:
|
||||
self.assertEqual(response.content, '{"extras": {}, "name": "1"}')
|
||||
else:
|
||||
self.assertEqual(response.content, '{"name": "1"}')
|
||||
nc.flavor_get.assert_called_once_with(request, "1",
|
||||
get_extras=get_extras)
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def _test_flavor_list_public(self, nc, is_public=None):
|
||||
if is_public:
|
||||
request = self.mock_rest_request(GET={'is_public': 'tRuE'})
|
||||
elif is_public is None:
|
||||
request = self.mock_rest_request(GET={})
|
||||
else:
|
||||
request = self.mock_rest_request(GET={'is_public': 'fAlsE'})
|
||||
nc.flavor_list.return_value = [
|
||||
mock.Mock(**{'to_dict.return_value': {'id': '1'}}),
|
||||
mock.Mock(**{'to_dict.return_value': {'id': '2'}}),
|
||||
]
|
||||
response = nova.Flavors().get(request)
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.content,
|
||||
'{"items": [{"id": "1"}, {"id": "2"}]}')
|
||||
nc.flavor_list.assert_called_once_with(request, is_public=is_public,
|
||||
get_extras=False)
|
||||
|
||||
def test_flavor_list_private(self):
|
||||
self._test_flavor_list_public(is_public=False)
|
||||
|
||||
def test_flavor_list_public(self):
|
||||
self._test_flavor_list_public(is_public=True)
|
||||
|
||||
def test_flavor_list_public_none(self):
|
||||
self._test_flavor_list_public(is_public=None)
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def _test_flavor_list_extras(self, nc, get_extras=None):
|
||||
if get_extras:
|
||||
request = self.mock_rest_request(GET={'get_extras': 'tRuE'})
|
||||
elif get_extras is None:
|
||||
request = self.mock_rest_request(GET={})
|
||||
get_extras = False
|
||||
else:
|
||||
request = self.mock_rest_request(GET={'get_extras': 'fAlsE'})
|
||||
nc.flavor_list.return_value = [
|
||||
mock.Mock(**{'extras': {}, 'to_dict.return_value': {'id': '1'}}),
|
||||
mock.Mock(**{'extras': {}, 'to_dict.return_value': {'id': '2'}}),
|
||||
]
|
||||
response = nova.Flavors().get(request)
|
||||
self.assertStatusCode(response, 200)
|
||||
if get_extras:
|
||||
self.assertEqual(response.content,
|
||||
'{"items": [{"extras": {}, "id": "1"}, '
|
||||
'{"extras": {}, "id": "2"}]}')
|
||||
else:
|
||||
self.assertEqual(response.content,
|
||||
'{"items": [{"id": "1"}, {"id": "2"}]}')
|
||||
nc.flavor_list.assert_called_once_with(request, is_public=None,
|
||||
get_extras=get_extras)
|
||||
|
||||
def test_flavor_list_extras_no(self):
|
||||
self._test_flavor_list_extras(get_extras=False)
|
||||
|
||||
def test_flavor_list_extras_yes(self):
|
||||
self._test_flavor_list_extras(get_extras=True)
|
||||
|
||||
def test_flavor_list_extras_absent(self):
|
||||
self._test_flavor_list_extras(get_extras=None)
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_flavor_extra_specs(self, nc):
|
||||
request = self.mock_rest_request()
|
||||
nc.flavor_get_extras.return_value.to_dict.return_value = {'foo': '1'}
|
||||
|
||||
response = nova.FlavorExtraSpecs().get(request, "1")
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.flavor_get_extras.assert_called_once_with(request, "1", raw=True)
|
||||
|
Loading…
Reference in New Issue
Block a user