diff options
| author | masumotok <masumotok@nttdata.co.jp> | 2012-01-26 04:38:41 -0800 |
|---|---|---|
| committer | masumotok <masumotok@nttdata.co.jp> | 2012-01-26 04:38:41 -0800 |
| commit | 09ccc2f9315eb0441d5f7793326614cc25814089 (patch) | |
| tree | 5b8d0036919b9f35474b3802b54261077113883d /nova/api | |
| parent | 6142230ccf2555650dbb902a5c342a342e9b2582 (diff) | |
Adding live migration server actions
Change-Id: I5e1f5dddaf45d1c6eae8666647425bff748b639e
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/openstack/compute/contrib/admin_actions.py | 37 | ||||
| -rw-r--r-- | nova/api/openstack/compute/contrib/hosts.py | 76 |
2 files changed, 113 insertions, 0 deletions
diff --git a/nova/api/openstack/compute/contrib/admin_actions.py b/nova/api/openstack/compute/contrib/admin_actions.py index cbd54117d..f68126fb2 100644 --- a/nova/api/openstack/compute/contrib/admin_actions.py +++ b/nova/api/openstack/compute/contrib/admin_actions.py @@ -272,6 +272,43 @@ class AdminActionsController(wsgi.Controller): resp.headers['Location'] = image_ref return resp + @wsgi.action('os-migrateLive') + @exception.novaclient_converter + @scheduler_api.redirect_handler + def _migrate_live(self, req, id, body): + """Permit admins to (live) migrate a server to a new host""" + context = req.environ["nova.context"] + # Expected to use AuthMiddleware. + # Otherwise, non-admin user can use live migration + if not context.is_admin: + msg = _("Live migration is admin only functionality") + raise exc.HTTPForbidden(explanation=msg) + + try: + block_migration = body["os-migrateLive"]["block_migration"] + disk_over_commit = body["os-migrateLive"]["disk_over_commit"] + host = body["os-migrateLive"]["host"] + except (TypeError, KeyError): + msg = _("host and block_migration must be specified.") + raise exc.HTTPBadRequest(explanation=msg) + + try: + instance = self.compute_api.get(context, id) + result = scheduler_api.live_migration(context, + block_migration, + disk_over_commit, + instance["id"], + host, + topic=FLAGS.compute_topic) + except Exception, e: + msg = _("Live migration of instance %(id)s to host %(host)s" + " failed") % locals() + LOG.exception(msg) + # Return messages from scheduler + raise exc.HTTPBadRequest(explanation=msg) + + return webob.Response(status_int=202) + class Admin_actions(extensions.ExtensionDescriptor): """Enable admin-only server actions diff --git a/nova/api/openstack/compute/contrib/hosts.py b/nova/api/openstack/compute/contrib/hosts.py index b522e6a98..53f1a064a 100644 --- a/nova/api/openstack/compute/contrib/hosts.py +++ b/nova/api/openstack/compute/contrib/hosts.py @@ -23,6 +23,7 @@ from nova.api.openstack import wsgi from nova.api.openstack import xmlutil from nova.api.openstack import extensions from nova import compute +from nova import db from nova import exception from nova import flags from nova import log as logging @@ -82,6 +83,15 @@ class HostDeserializer(wsgi.XMLDeserializer): return dict(body=updates) +class HostShowTemplate(xmlutil.TemplateBuilder): + def construct(self): + root = xmlutil.TemplateElement('host', selector='host') + root.set('resource') + root.set('usage') + + return xmlutil.MasterTemplate(root, 1) + + def _list_hosts(req, service=None): """Returns a summary list of hosts, optionally filtering by service type. @@ -176,6 +186,72 @@ class HostController(object): def reboot(self, req, id): return self._host_power_action(req, host=id, action="reboot") + @wsgi.serializers(xml=HostShowTemplate) + def show(self, req, id): + """Shows the physical/usage resource given by hosts. + + :param context: security context + :param host: hostname + :returns: + {'host': {'resource':D1, 'usage':{proj_id1:D2,..}}} + + 'resource' shows "available" and "in-use" vcpus, memory and disk. + 'usage' shows "in-use" vcpus, memory and disk per project. + + D1: {'vcpus': 16, 'memory_mb': 2048, 'local_gb': 2048, + 'vcpus_used': 12, 'memory_mb_used': 10240, + 'local_gb_used': 64} + D2: {'vcpus': 1, 'memory_mb': 2048, 'local_gb': 20} + """ + host = id + context = req.environ['nova.context'] + # Expected to use AuthMiddleware. + # Otherwise, non-admin user can use describe-resource + if not context.is_admin: + msg = _("Describe-resource is admin only functionality") + raise webob.exc.HTTPForbidden(explanation=msg) + + # Getting compute node info and related instances info + try: + compute_ref = db.service_get_all_compute_by_host(context, host) + compute_ref = compute_ref[0] + except exception.ComputeHostNotFound: + raise webob.exc.HTTPNotFound(explanation=_("Host not found")) + instance_refs = db.instance_get_all_by_host(context, + compute_ref['host']) + + # Getting total available/used resource + compute_ref = compute_ref['compute_node'][0] + resource = {'vcpus': compute_ref['vcpus'], + 'memory_mb': compute_ref['memory_mb'], + 'local_gb': compute_ref['local_gb'], + 'vcpus_used': compute_ref['vcpus_used'], + 'memory_mb_used': compute_ref['memory_mb_used'], + 'local_gb_used': compute_ref['local_gb_used']} + usage = dict() + if not instance_refs: + return {'host': + {'resource': resource, 'usage': usage}} + + # Getting usage resource per project + project_ids = [i['project_id'] for i in instance_refs] + project_ids = list(set(project_ids)) + for project_id in project_ids: + vcpus = [i['vcpus'] for i in instance_refs + if i['project_id'] == project_id] + + mem = [i['memory_mb'] for i in instance_refs + if i['project_id'] == project_id] + + disk = [i['root_gb'] + i['ephemeral_gb'] for i in instance_refs + if i['project_id'] == project_id] + + usage[project_id] = {'vcpus': reduce(lambda x, y: x + y, vcpus), + 'memory_mb': reduce(lambda x, y: x + y, mem), + 'local_gb': reduce(lambda x, y: x + y, disk)} + + return {'host': {'resource': resource, 'usage': usage}} + class Hosts(extensions.ExtensionDescriptor): """Admin-only host administration""" |
