Add more Nova API features for NG Instances
This patch adds more Nova API features for instances. It establishes several new proxy APIs and provides the various JavaScript libraries for accessing those APIs as well. Change-Id: I016be1d0598faf78b1fb02f4d0768efdaf6cb7bf Partially-Implements: blueprint angularize-instances-table
This commit is contained in:
parent
f3f2ea1d62
commit
93b7edd694
@ -13,12 +13,16 @@
|
||||
# limitations under the License.
|
||||
"""API over the nova service.
|
||||
"""
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.utils import http as utils_http
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views import generic
|
||||
|
||||
from horizon import exceptions as hz_exceptions
|
||||
|
||||
from novaclient import exceptions
|
||||
|
||||
from openstack_dashboard import api
|
||||
@ -27,6 +31,24 @@ from openstack_dashboard.api.rest import urls
|
||||
from openstack_dashboard.api.rest import utils as rest_utils
|
||||
from openstack_dashboard.usage import quotas
|
||||
|
||||
import six
|
||||
|
||||
|
||||
@urls.register
|
||||
class Snapshots(generic.View):
|
||||
"""API for nova snapshots.
|
||||
"""
|
||||
url_regex = r'nova/snapshots/$'
|
||||
|
||||
@rest_utils.ajax(data_required=True)
|
||||
def post(self, request):
|
||||
instance_id = request.DATA['instance_id']
|
||||
name = request.DATA['name']
|
||||
result = api.nova.snapshot_create(request,
|
||||
instance_id=instance_id,
|
||||
name=name)
|
||||
return result
|
||||
|
||||
|
||||
@urls.register
|
||||
class Keypairs(generic.View):
|
||||
@ -177,6 +199,146 @@ class Limits(generic.View):
|
||||
return result
|
||||
|
||||
|
||||
@urls.register
|
||||
class ServerActions(generic.View):
|
||||
"""API over all server actions.
|
||||
"""
|
||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/actions/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request, server_id):
|
||||
"""Get a list of server actions.
|
||||
|
||||
The listing result is an object with property "items". Each item is
|
||||
an action taken against the given server.
|
||||
|
||||
Example GET:
|
||||
http://localhost/api/nova/servers/abcd/actions/
|
||||
"""
|
||||
actions = api.nova.instance_action_list(request, server_id)
|
||||
return {'items': [s.to_dict() for s in actions]}
|
||||
|
||||
|
||||
@urls.register
|
||||
class SecurityGroups(generic.View):
|
||||
"""API over all server security groups.
|
||||
"""
|
||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/security-groups/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request, server_id):
|
||||
"""Get a list of server security groups.
|
||||
|
||||
The listing result is an object with property "items". Each item is
|
||||
security group associated with this server.
|
||||
|
||||
Example GET:
|
||||
http://localhost/api/nova/servers/abcd/security-groups/
|
||||
"""
|
||||
groups = api.network.server_security_groups(request, server_id)
|
||||
return {'items': [s.to_dict() for s in groups]}
|
||||
|
||||
|
||||
@urls.register
|
||||
class Volumes(generic.View):
|
||||
"""API over all server volumes.
|
||||
"""
|
||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/volumes/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request, server_id):
|
||||
"""Get a list of server volumes.
|
||||
|
||||
The listing result is an object with property "items". Each item is
|
||||
a volume.
|
||||
|
||||
Example GET:
|
||||
http://localhost/api/nova/servers/abcd/volumes/
|
||||
"""
|
||||
volumes = api.nova.instance_volumes_list(request, server_id)
|
||||
return {'items': [s.to_dict() for s in volumes]}
|
||||
|
||||
|
||||
@urls.register
|
||||
class RemoteConsoleInfo(generic.View):
|
||||
"""API for remote console information.
|
||||
"""
|
||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-info/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def post(self, request, server_id):
|
||||
"""Gets information about an available remote console for the given
|
||||
server.
|
||||
|
||||
Example POST:
|
||||
http://localhost/api/nova/servers/abcd/console-info/
|
||||
"""
|
||||
console_type = request.DATA.get('console_type', 'AUTO')
|
||||
CONSOLES = OrderedDict([('VNC', api.nova.server_vnc_console),
|
||||
('SPICE', api.nova.server_spice_console),
|
||||
('RDP', api.nova.server_rdp_console),
|
||||
('SERIAL', api.nova.server_serial_console)])
|
||||
|
||||
"""Get a tuple of console url and console type."""
|
||||
if console_type == 'AUTO':
|
||||
check_consoles = CONSOLES
|
||||
else:
|
||||
try:
|
||||
check_consoles = {console_type: CONSOLES[console_type]}
|
||||
except KeyError:
|
||||
msg = _('Console type "%s" not supported.') % console_type
|
||||
raise hz_exceptions.NotAvailable(msg)
|
||||
|
||||
# Ugly workaround due novaclient API change from 2.17 to 2.18.
|
||||
try:
|
||||
httpnotimplemented = exceptions.HttpNotImplemented
|
||||
except AttributeError:
|
||||
httpnotimplemented = exceptions.HTTPNotImplemented
|
||||
|
||||
for con_type, api_call in six.iteritems(check_consoles):
|
||||
try:
|
||||
console = api_call(request, server_id)
|
||||
# If not supported, don't log it to avoid lot of errors in case
|
||||
# of AUTO.
|
||||
except httpnotimplemented:
|
||||
continue
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if con_type == 'SERIAL':
|
||||
console_url = console.url
|
||||
else:
|
||||
console_url = "%s&%s(%s)" % (
|
||||
console.url,
|
||||
utils_http.urlencode({'title': _("Console")}),
|
||||
server_id)
|
||||
|
||||
return {"type": con_type, "url": console_url}
|
||||
raise hz_exceptions.NotAvailable(_('No available console found.'))
|
||||
|
||||
|
||||
@urls.register
|
||||
class ConsoleOutput(generic.View):
|
||||
"""API for console output.
|
||||
"""
|
||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-output/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def post(self, request, server_id):
|
||||
"""Get a list of lines of console output.
|
||||
|
||||
The listing result is an object with property "items". Each item is
|
||||
a line of output from the server.
|
||||
|
||||
Example GET:
|
||||
http://localhost/api/nova/servers/abcd/console-output/
|
||||
"""
|
||||
log_length = request.DATA.get('length', 100)
|
||||
console_lines = api.nova.server_console_output(request, server_id,
|
||||
tail_length=log_length)
|
||||
return {"lines": [x for x in console_lines.split('\n')]}
|
||||
|
||||
|
||||
@urls.register
|
||||
class Servers(generic.View):
|
||||
"""API over all servers.
|
||||
@ -186,7 +348,7 @@ class Servers(generic.View):
|
||||
_optional_create = [
|
||||
'block_device_mapping', 'block_device_mapping_v2', 'nics', 'meta',
|
||||
'availability_zone', 'instance_count', 'admin_pass', 'disk_config',
|
||||
'config_drive', 'scheduler_hints'
|
||||
'config_drive'
|
||||
]
|
||||
|
||||
@rest_utils.ajax()
|
||||
@ -267,6 +429,27 @@ class Server(generic.View):
|
||||
"""
|
||||
return api.nova.server_get(request, server_id).to_dict()
|
||||
|
||||
@rest_utils.ajax(data_required=True)
|
||||
def post(self, request, server_id):
|
||||
"""Perform a change to a server
|
||||
"""
|
||||
operation = request.DATA.get('operation', 'none')
|
||||
operations = {
|
||||
'stop': api.nova.server_stop,
|
||||
'start': api.nova.server_start,
|
||||
'pause': api.nova.server_pause,
|
||||
'unpause': api.nova.server_unpause,
|
||||
'suspend': api.nova.server_suspend,
|
||||
'resume': api.nova.server_resume,
|
||||
'hard_reboot': lambda r, s: api.nova.server_reboot(r, s, False),
|
||||
'soft_reboot': lambda r, s: api.nova.server_reboot(r, s, True),
|
||||
}
|
||||
return operations[operation](request, server_id)
|
||||
|
||||
@rest_utils.ajax()
|
||||
def delete(self, request, server_id):
|
||||
api.nova.server_delete(request, server_id)
|
||||
|
||||
|
||||
@urls.register
|
||||
class ServerGroups(generic.View):
|
||||
|
@ -83,11 +83,13 @@
|
||||
// The following retrieves the first argument of the first call to the
|
||||
// error spy. This exposes the inner function that, when invoked,
|
||||
// allows us to inspect the error call and the message given.
|
||||
var innerFunc = promise.error.calls.argsFor(0)[0];
|
||||
expect(innerFunc).toBeDefined();
|
||||
spyOn(toastService, 'add');
|
||||
innerFunc({status: 500});
|
||||
expect(toastService.add).toHaveBeenCalledWith(config.messageType || 'error', config.error);
|
||||
if (config.error) {
|
||||
var innerFunc = promise.error.calls.argsFor(0)[0];
|
||||
expect(innerFunc).toBeDefined();
|
||||
spyOn(toastService, 'add');
|
||||
innerFunc({status: 500});
|
||||
expect(toastService.add).toHaveBeenCalledWith(config.messageType || 'error', config.error);
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -39,6 +39,11 @@
|
||||
function novaAPI(apiService, toastService, $window) {
|
||||
|
||||
var service = {
|
||||
getActionList: getActionList,
|
||||
getConsoleLog: getConsoleLog,
|
||||
getConsoleInfo: getConsoleInfo,
|
||||
getServerVolumes: getServerVolumes,
|
||||
getServerSecurityGroups: getServerSecurityGroups,
|
||||
getKeypairs: getKeypairs,
|
||||
createKeypair: createKeypair,
|
||||
getAvailabilityZones: getAvailabilityZones,
|
||||
@ -47,6 +52,15 @@
|
||||
getServer: getServer,
|
||||
getServers: getServers,
|
||||
getServerGroups: getServerGroups,
|
||||
deleteServer: deleteServer,
|
||||
pauseServer: pauseServer,
|
||||
unpauseServer: unpauseServer,
|
||||
suspendServer: suspendServer,
|
||||
resumeServer: resumeServer,
|
||||
softRebootServer: softRebootServer,
|
||||
hardRebootServer: hardRebootServer,
|
||||
startServer: startServer,
|
||||
stopServer: stopServer,
|
||||
getExtensions: getExtensions,
|
||||
getFlavors: getFlavors,
|
||||
getFlavor: getFlavor,
|
||||
@ -65,7 +79,8 @@
|
||||
getDefaultQuotaSets: getDefaultQuotaSets,
|
||||
setDefaultQuotaSets: setDefaultQuotaSets,
|
||||
getEditableQuotas: getEditableQuotas,
|
||||
updateProjectQuota: updateProjectQuota
|
||||
updateProjectQuota: updateProjectQuota,
|
||||
createServerSnapshot: createServerSnapshot
|
||||
};
|
||||
|
||||
return service;
|
||||
@ -264,6 +279,146 @@
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* @name deleteServer
|
||||
* @description
|
||||
* Delete a single server by ID.
|
||||
*
|
||||
* @param {String} serverId
|
||||
* Server to delete
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function deleteServer(serverId, suppressError) {
|
||||
var promise = apiService.delete('/api/nova/servers/' + serverId);
|
||||
|
||||
return suppressError ? promise : promise.error(function() {
|
||||
var msg = gettext('Unable to delete the server with id: %(id)s');
|
||||
toastService.add('error', interpolate(msg, { id: serverId }, true));
|
||||
});
|
||||
}
|
||||
|
||||
function serverStateOperation(operation, serverId, suppressError, errMsg) {
|
||||
var instruction = {"operation": operation};
|
||||
var promise = apiService.post('/api/nova/servers/' + serverId, instruction);
|
||||
|
||||
return suppressError ? promise : promise.error(function() {
|
||||
toastService.add('error', interpolate(errMsg, { id: serverId }, true));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @name startServer
|
||||
* @description
|
||||
* Start a single server by ID.
|
||||
*
|
||||
* @param {String} serverId
|
||||
* Server to start
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function startServer(serverId, suppressError) {
|
||||
return serverStateOperation('start', serverId, suppressError,
|
||||
gettext('Unable to start the server with id: %(id)s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @name pauseServer
|
||||
* @description
|
||||
* Pause a single server by ID.
|
||||
*
|
||||
* @param {String} serverId
|
||||
* Server to pause
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function pauseServer(serverId, suppressError) {
|
||||
return serverStateOperation('pause', serverId, suppressError,
|
||||
gettext('Unable to pause the server with id: %(id)s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @name unpauseServer
|
||||
* @description
|
||||
* Un-Pause a single server by ID.
|
||||
*
|
||||
* @param {String} serverId
|
||||
* Server to unpause
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function unpauseServer(serverId, suppressError) {
|
||||
return serverStateOperation('unpause', serverId, suppressError,
|
||||
gettext('Unable to unpause the server with id: %(id)s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @name suspendServer
|
||||
* @description
|
||||
* Suspend a single server by ID.
|
||||
*
|
||||
* @param {String} serverId
|
||||
* Server to suspend
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function suspendServer(serverId, suppressError) {
|
||||
return serverStateOperation('suspend', serverId, suppressError,
|
||||
gettext('Unable to suspend the server with id: %(id)s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @name resumeServer
|
||||
* @description
|
||||
* Resumes a single server by ID.
|
||||
*
|
||||
* @param {String} serverId
|
||||
* Server to resume
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function resumeServer(serverId, suppressError) {
|
||||
return serverStateOperation('resume', serverId, suppressError,
|
||||
gettext('Unable to resume the server with id: %(id)s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @name softRebootServer
|
||||
* @description
|
||||
* Soft-reboots a single server by ID.
|
||||
*
|
||||
* @param {String} serverId
|
||||
* Server to reboot
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function softRebootServer(serverId, suppressError) {
|
||||
return serverStateOperation('soft_reboot', serverId, suppressError,
|
||||
gettext('Unable to soft-reboot the server with id: %(id)s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @name hardRebootServer
|
||||
* @description
|
||||
* Hard-reboots a single server by ID.
|
||||
*
|
||||
* @param {String} serverId
|
||||
* Server to reboot
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function hardRebootServer(serverId, suppressError) {
|
||||
return serverStateOperation('hard_reboot', serverId, suppressError,
|
||||
gettext('Unable to hard-reboot the server with id: %(id)s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @name stopServer
|
||||
* @description
|
||||
* Stop a single server by ID.
|
||||
*
|
||||
* @param {String} serverId
|
||||
* Server to stop
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function stopServer(serverId, suppressError) {
|
||||
return serverStateOperation('stop', serverId, suppressError,
|
||||
gettext('Unable to stop the server with id: %(id)s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getExtensions
|
||||
* @param {Object} config - A configuration object
|
||||
@ -636,5 +791,109 @@
|
||||
return getCreateKeypairUrl(keyPairName) + "?regenerate=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* @name createServerSnapshot
|
||||
* @param {Object} newSnapshot - The new server snapshot
|
||||
* @description
|
||||
* Create a server snapshot using the parameters supplied in the
|
||||
* newSnapshot. The required parameters:
|
||||
*
|
||||
* "name", "instance_id"
|
||||
* All strings
|
||||
*
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function createServerSnapshot(newSnapshot) {
|
||||
return apiService.post('/api/nova/snapshots/', newSnapshot)
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to create the server snapshot.'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getActionList
|
||||
* @param {String} ID - The server ID
|
||||
* @description
|
||||
* Retrieves a list of actions performed on the server.
|
||||
*
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function getActionList(instanceId) {
|
||||
return apiService.get('/api/nova/servers/' + instanceId + '/actions/')
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to load the server actions.'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getConsoleLog
|
||||
* @param {String} instanceId - The server ID
|
||||
* @param {Number} length - The number of lines to retrieve (optional)
|
||||
* @description
|
||||
* Retrieves a list of most recent console log lines from the server.
|
||||
*
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function getConsoleLog(instanceId, length) {
|
||||
var config = {};
|
||||
if (length) {
|
||||
config.length = length;
|
||||
}
|
||||
return apiService.post('/api/nova/servers/' + instanceId + '/console-output/', config)
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to load the server console log.'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getConsoleInfo
|
||||
* @param {String} instanceId - The server ID
|
||||
* @param {String} type - The type of console to use (optional)
|
||||
* @description
|
||||
* Retrieves information used to get to a remote console for the given host.
|
||||
*
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function getConsoleInfo(instanceId, type) {
|
||||
var config = {};
|
||||
if (type) {
|
||||
config.console_type = type;
|
||||
}
|
||||
return apiService.post('/api/nova/servers/' + instanceId + '/console-info/', config)
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to load the server console info.'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getServerVolumes
|
||||
* @param {String} instanceId - The server ID
|
||||
* @description
|
||||
* Retrieves information about volumes associated with the server
|
||||
*
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function getServerVolumes(instanceId) {
|
||||
return apiService.get('/api/nova/servers/' + instanceId + '/volumes/')
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to load the server volumes.'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getServerSecurityGroups
|
||||
* @param {String} ID - The server ID
|
||||
* @description
|
||||
* Retrieves information about security groups associated with the server
|
||||
*
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function getServerSecurityGroups(instanceId) {
|
||||
return apiService.get('/api/nova/servers/' + instanceId + '/security-groups/')
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to load the server security groups.'));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}());
|
||||
|
@ -46,6 +46,63 @@
|
||||
"path": "/api/nova/services/",
|
||||
"error": "Unable to retrieve the nova services."
|
||||
},
|
||||
{
|
||||
"func": "getConsoleLog",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/123/console-output/",
|
||||
"data": {
|
||||
"length": 6
|
||||
},
|
||||
"error": "Unable to load the server console log.",
|
||||
"testInput": [123, 6]
|
||||
},
|
||||
{
|
||||
"func": "getActionList",
|
||||
"method": "get",
|
||||
"path": "/api/nova/servers/123/actions/",
|
||||
"error": "Unable to load the server actions.",
|
||||
"testInput": [123]
|
||||
},
|
||||
{
|
||||
"func": "getConsoleLog",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/123/console-output/",
|
||||
"data": {},
|
||||
"error": "Unable to load the server console log.",
|
||||
"testInput": [123]
|
||||
},
|
||||
{
|
||||
"func": "getConsoleInfo",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/123/console-info/",
|
||||
"data": {
|
||||
"console_type": "VNC"
|
||||
},
|
||||
"error": "Unable to load the server console info.",
|
||||
"testInput": [123, "VNC"]
|
||||
},
|
||||
{
|
||||
"func": "getConsoleInfo",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/123/console-info/",
|
||||
"data": {},
|
||||
"error": "Unable to load the server console info.",
|
||||
"testInput": [123]
|
||||
},
|
||||
{
|
||||
"func": "getServerVolumes",
|
||||
"method": "get",
|
||||
"path": "/api/nova/servers/123/volumes/",
|
||||
"error": "Unable to load the server volumes.",
|
||||
"testInput": [123]
|
||||
},
|
||||
{
|
||||
"func": "getServerSecurityGroups",
|
||||
"method": "get",
|
||||
"path": "/api/nova/servers/123/security-groups/",
|
||||
"error": "Unable to load the server security groups.",
|
||||
"testInput": [123]
|
||||
},
|
||||
{
|
||||
"func": "getKeypairs",
|
||||
"method": "get",
|
||||
@ -76,6 +133,98 @@
|
||||
{}
|
||||
]
|
||||
},
|
||||
{
|
||||
"func": "deleteServer",
|
||||
"method": "delete",
|
||||
"path": "/api/nova/servers/12",
|
||||
"error": "Unable to delete the server with id: 12",
|
||||
"testInput": [12]
|
||||
},
|
||||
{
|
||||
"func": "deleteServer",
|
||||
"method": "delete",
|
||||
"path": "/api/nova/servers/12",
|
||||
"testInput": [12, true]
|
||||
},
|
||||
{
|
||||
"func": "createServerSnapshot",
|
||||
"method": "post",
|
||||
"path": "/api/nova/snapshots/",
|
||||
"data": {info: 12},
|
||||
"error": "Unable to create the server snapshot.",
|
||||
"testInput": [{info: 12}]
|
||||
},
|
||||
{
|
||||
"func": "startServer",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/12",
|
||||
"data": { operation: 'start' },
|
||||
"error": "Unable to start the server with id: 12",
|
||||
"testInput": [12]
|
||||
},
|
||||
{
|
||||
"func": "stopServer",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/12",
|
||||
"data": { operation: 'stop' },
|
||||
"error": "Unable to stop the server with id: 12",
|
||||
"testInput": [12]
|
||||
},
|
||||
{
|
||||
"func": "stopServer",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/12",
|
||||
"data": { operation: 'stop' },
|
||||
"testInput": [12, true]
|
||||
},
|
||||
{
|
||||
"func": "pauseServer",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/12",
|
||||
"data": { operation: 'pause' },
|
||||
"error": "Unable to pause the server with id: 12",
|
||||
"testInput": [12]
|
||||
},
|
||||
{
|
||||
"func": "unpauseServer",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/12",
|
||||
"data": { operation: 'unpause' },
|
||||
"error": "Unable to unpause the server with id: 12",
|
||||
"testInput": [12]
|
||||
},
|
||||
{
|
||||
"func": "suspendServer",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/12",
|
||||
"data": { operation: 'suspend' },
|
||||
"error": "Unable to suspend the server with id: 12",
|
||||
"testInput": [12]
|
||||
},
|
||||
{
|
||||
"func": "resumeServer",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/12",
|
||||
"data": { operation: 'resume' },
|
||||
"error": "Unable to resume the server with id: 12",
|
||||
"testInput": [12]
|
||||
},
|
||||
{
|
||||
"func": "softRebootServer",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/12",
|
||||
"data": { operation: 'soft_reboot' },
|
||||
"error": "Unable to soft-reboot the server with id: 12",
|
||||
"testInput": [12]
|
||||
},
|
||||
{
|
||||
"func": "hardRebootServer",
|
||||
"method": "post",
|
||||
"path": "/api/nova/servers/12",
|
||||
"data": { operation: 'hard_reboot' },
|
||||
"error": "Unable to hard-reboot the server with id: 12",
|
||||
"testInput": [12]
|
||||
},
|
||||
{
|
||||
"func": "getAvailabilityZones",
|
||||
"method": "get",
|
||||
@ -329,6 +478,12 @@
|
||||
"error": "Unable to delete the flavor with id: 42",
|
||||
"testInput": [42]
|
||||
},
|
||||
{
|
||||
"func": "deleteFlavor",
|
||||
"method": "delete",
|
||||
"path": "/api/nova/flavors/42/",
|
||||
"testInput": [42, true]
|
||||
},
|
||||
{
|
||||
"func": "getDefaultQuotaSets",
|
||||
"method": "get",
|
||||
|
@ -26,6 +26,150 @@ from novaclient import exceptions
|
||||
|
||||
|
||||
class NovaRestTestCase(test.TestCase):
|
||||
#
|
||||
# Snapshots
|
||||
#
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_snapshots_create(self, nc):
|
||||
body = '{"instance_id": "1234", "name": "foo"}'
|
||||
request = self.mock_rest_request(body=body)
|
||||
nc.snapshot_create.return_value = {'id': 'abcd', 'name': 'foo'}
|
||||
response = nova.Snapshots().post(request)
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.json, {'id': 'abcd', 'name': 'foo'})
|
||||
nc.snapshot_create.assert_called_once_with(request,
|
||||
instance_id='1234',
|
||||
name='foo')
|
||||
|
||||
#
|
||||
# Server Actions
|
||||
#
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_serveractions_list(self, nc):
|
||||
request = self.mock_rest_request()
|
||||
nc.instance_action_list.return_value = [
|
||||
mock.Mock(**{'to_dict.return_value': {'id': '1'}}),
|
||||
mock.Mock(**{'to_dict.return_value': {'id': '2'}}),
|
||||
]
|
||||
response = nova.ServerActions().get(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.json, {'items': [{'id': '1'}, {'id': '2'}]})
|
||||
nc.instance_action_list.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_server_start(self, nc):
|
||||
request = self.mock_rest_request(body='{"operation": "start"}')
|
||||
response = nova.Server().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.server_start.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_server_stop(self, nc):
|
||||
request = self.mock_rest_request(body='{"operation": "stop"}')
|
||||
response = nova.Server().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.server_stop.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_server_pause(self, nc):
|
||||
request = self.mock_rest_request(body='{"operation": "pause"}')
|
||||
response = nova.Server().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.server_pause.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_server_unpause(self, nc):
|
||||
request = self.mock_rest_request(body='{"operation": "unpause"}')
|
||||
response = nova.Server().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.server_unpause.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_server_suspend(self, nc):
|
||||
request = self.mock_rest_request(body='{"operation": "suspend"}')
|
||||
response = nova.Server().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.server_suspend.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_server_resume(self, nc):
|
||||
request = self.mock_rest_request(body='{"operation": "resume"}')
|
||||
response = nova.Server().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.server_resume.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_server_hard_reboot(self, nc):
|
||||
request = self.mock_rest_request(body='{"operation": "hard_reboot"}')
|
||||
response = nova.Server().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.server_reboot.assert_called_once_with(request, 'MegaMan', False)
|
||||
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_server_soft_reboot(self, nc):
|
||||
request = self.mock_rest_request(body='{"operation": "soft_reboot"}')
|
||||
response = nova.Server().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
nc.server_reboot.assert_called_once_with(request, 'MegaMan', True)
|
||||
|
||||
#
|
||||
# Security Groups
|
||||
#
|
||||
@mock.patch.object(nova.api, 'network')
|
||||
def test_securitygroups_list(self, nc):
|
||||
request = self.mock_rest_request()
|
||||
nc.server_security_groups.return_value = [
|
||||
mock.Mock(**{'to_dict.return_value': {'id': '1'}}),
|
||||
mock.Mock(**{'to_dict.return_value': {'id': '2'}}),
|
||||
]
|
||||
response = nova.SecurityGroups().get(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.json, {'items': [{'id': '1'}, {'id': '2'}]})
|
||||
nc.server_security_groups.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
#
|
||||
# Console Output
|
||||
#
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_console_output(self, nc):
|
||||
request = self.mock_rest_request(body='{"length": 50}')
|
||||
nc.server_console_output.return_value = "this\nis\ncool"
|
||||
response = nova.ConsoleOutput().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.json, {'lines': ["this", "is", "cool"]})
|
||||
nc.server_console_output.assert_called_once_with(request,
|
||||
'MegaMan',
|
||||
tail_length=50)
|
||||
|
||||
#
|
||||
# Remote Console Info
|
||||
#
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_console_info(self, nc):
|
||||
request = self.mock_rest_request(body='{"console_type": "SERIAL"}')
|
||||
retval = mock.Mock(**{"url": "http://here.com"})
|
||||
nc.server_serial_console.return_value = retval
|
||||
response = nova.RemoteConsoleInfo().post(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.json,
|
||||
{"type": "SERIAL", "url": "http://here.com"})
|
||||
nc.server_serial_console.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
#
|
||||
# Volumes
|
||||
#
|
||||
@mock.patch.object(nova.api, 'nova')
|
||||
def test_volumes_list(self, nc):
|
||||
request = self.mock_rest_request()
|
||||
nc.instance_volumes_list.return_value = [
|
||||
mock.Mock(**{'to_dict.return_value': {'id': '1'}}),
|
||||
mock.Mock(**{'to_dict.return_value': {'id': '2'}}),
|
||||
]
|
||||
response = nova.Volumes().get(request, 'MegaMan')
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual(response.json, {'items': [{'id': '1'}, {'id': '2'}]})
|
||||
nc.instance_volumes_list.assert_called_once_with(request, 'MegaMan')
|
||||
|
||||
#
|
||||
# Keypairs
|
||||
#
|
||||
|
Loading…
x
Reference in New Issue
Block a user