diff --git a/openstack_dashboard/api/rest/nova.py b/openstack_dashboard/api/rest/nova.py
index 5d2db901b8..2227abcc48 100644
--- a/openstack_dashboard/api/rest/nova.py
+++ b/openstack_dashboard/api/rest/nova.py
@@ -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):
diff --git a/openstack_dashboard/static/app/core/openstack-service-api/common-test.mock.js b/openstack_dashboard/static/app/core/openstack-service-api/common-test.mock.js
index ae4f95e9fd..85e6ed74c0 100644
--- a/openstack_dashboard/static/app/core/openstack-service-api/common-test.mock.js
+++ b/openstack_dashboard/static/app/core/openstack-service-api/common-test.mock.js
@@ -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);
+    }
   }
 
 })();
diff --git a/openstack_dashboard/static/app/core/openstack-service-api/nova.service.js b/openstack_dashboard/static/app/core/openstack-service-api/nova.service.js
index 059ff860f9..30a66e49f3 100644
--- a/openstack_dashboard/static/app/core/openstack-service-api/nova.service.js
+++ b/openstack_dashboard/static/app/core/openstack-service-api/nova.service.js
@@ -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.'));
+        });
+    }
+
   }
 }());
diff --git a/openstack_dashboard/static/app/core/openstack-service-api/nova.service.spec.js b/openstack_dashboard/static/app/core/openstack-service-api/nova.service.spec.js
index 512e0e3545..967d2f7855 100644
--- a/openstack_dashboard/static/app/core/openstack-service-api/nova.service.spec.js
+++ b/openstack_dashboard/static/app/core/openstack-service-api/nova.service.spec.js
@@ -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",
diff --git a/openstack_dashboard/test/api_tests/nova_rest_tests.py b/openstack_dashboard/test/api_tests/nova_rest_tests.py
index dd32098e37..b779834659 100644
--- a/openstack_dashboard/test/api_tests/nova_rest_tests.py
+++ b/openstack_dashboard/test/api_tests/nova_rest_tests.py
@@ -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
     #