Last active
November 25, 2015 05:05
-
-
Save misterdorm/5e9513bb1211b49e551c to your computer and use it in GitHub Desktop.
Support for server groups in nova cells v1: Note this patch will probably not apply cleanly to stock nova, as it's rebased from a few other cells-related patches we also run. But it should be fairly trivial to rebase onto whatever flavor of nova you have.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/nova/api/openstack/compute/contrib/server_groups.py b/nova/api/openstack/compute/contrib/server_groups.py | |
index 553f946..b9854c1 100644 | |
--- a/nova/api/openstack/compute/contrib/server_groups.py | |
+++ b/nova/api/openstack/compute/contrib/server_groups.py | |
@@ -27,6 +27,7 @@ from nova.i18n import _ | |
from nova.i18n import _LE | |
from nova import objects | |
from nova import utils | |
+from nova import compute | |
LOG = logging.getLogger(__name__) | |
@@ -47,6 +48,7 @@ class ServerGroupController(wsgi.Controller): | |
def __init__(self, ext_mgr): | |
self.ext_mgr = ext_mgr | |
+ self.api = compute.ServerGroupAPI() | |
def _format_server_group(self, context, group): | |
# the id field has its value as the uuid of the server group | |
@@ -158,11 +160,11 @@ class ServerGroupController(wsgi.Controller): | |
"server group")) | |
try: | |
- sg.destroy() | |
- except nova.exception.InstanceGroupNotFound as e: | |
+ self.api.delete(context, id) | |
+ except: | |
if quotas: | |
quotas.rollback() | |
- raise webob.exc.HTTPNotFound(explanation=e.format_message()) | |
+ raise | |
if quotas: | |
quotas.commit() | |
@@ -202,23 +204,17 @@ class ServerGroupController(wsgi.Controller): | |
msg = _("Quota exceeded, too many server groups.") | |
raise exc.HTTPForbidden(explanation=msg) | |
- vals = body['server_group'] | |
- sg = objects.InstanceGroup(context) | |
- sg.project_id = context.project_id | |
- sg.user_id = context.user_id | |
try: | |
- sg.name = vals.get('name') | |
- sg.policies = vals.get('policies') | |
- sg.create() | |
- except ValueError as e: | |
+ sg = self.api.create(context, body['server_group']) | |
+ except: | |
if quotas: | |
quotas.rollback() | |
- raise exc.HTTPBadRequest(explanation=e) | |
+ raise | |
if quotas: | |
quotas.commit() | |
- return {'server_group': self._format_server_group(context, sg)} | |
+ return sg | |
class Server_groups(extensions.ExtensionDescriptor): | |
diff --git a/nova/api/openstack/compute/plugins/v3/server_groups.py b/nova/api/openstack/compute/plugins/v3/server_groups.py | |
index 6f3782e..aef43d3 100644 | |
--- a/nova/api/openstack/compute/plugins/v3/server_groups.py | |
+++ b/nova/api/openstack/compute/plugins/v3/server_groups.py | |
@@ -24,6 +24,7 @@ from nova.api.openstack.compute.schemas.v3 import server_groups as schema | |
from nova.api.openstack import extensions | |
from nova.api.openstack import wsgi | |
from nova.api import validation | |
+from nova import compute | |
import nova.exception | |
from nova.i18n import _ | |
from nova.i18n import _LE | |
@@ -46,6 +47,9 @@ def _authorize_context(req): | |
class ServerGroupController(wsgi.Controller): | |
"""The Server group API controller for the OpenStack API.""" | |
+ def __init__(self): | |
+ self.api = compute.ServerGroupAPI() | |
+ | |
def _format_server_group(self, context, group): | |
# the id field has its value as the uuid of the server group | |
# There is no 'uuid' key in server_group seen by clients. | |
@@ -101,7 +105,7 @@ class ServerGroupController(wsgi.Controller): | |
"server group")) | |
try: | |
- sg.destroy() | |
+ self.api.delete(context, id) | |
except nova.exception.InstanceGroupNotFound as e: | |
if quotas: | |
quotas.rollback() | |
@@ -139,21 +143,15 @@ class ServerGroupController(wsgi.Controller): | |
msg = _("Quota exceeded, too many server groups.") | |
raise exc.HTTPForbidden(explanation=msg) | |
- vals = body['server_group'] | |
- sg = objects.InstanceGroup(context) | |
- sg.project_id = context.project_id | |
- sg.user_id = context.user_id | |
try: | |
- sg.name = vals.get('name') | |
- sg.policies = vals.get('policies') | |
- sg.create() | |
- except ValueError as e: | |
+ sg = self.api.create(context, body['server_group']) | |
+ except: | |
quotas.rollback() | |
- raise exc.HTTPBadRequest(explanation=e) | |
+ raise | |
quotas.commit() | |
- return {'server_group': self._format_server_group(context, sg)} | |
+ return sg | |
class ServerGroups(extensions.V3APIExtensionBase): | |
diff --git a/nova/cells/manager.py b/nova/cells/manager.py | |
index 438bb7c..a5fa07b 100644 | |
--- a/nova/cells/manager.py | |
+++ b/nova/cells/manager.py | |
@@ -80,7 +80,7 @@ class CellsManager(manager.Manager): | |
Scheduling requests get passed to the scheduler class. | |
""" | |
- target = oslo_messaging.Target(version='1.36') | |
+ target = oslo_messaging.Target(version='1.36.1') | |
def __init__(self, *args, **kwargs): | |
LOG.warning(_LW('The cells feature of Nova is considered experimental ' | |
@@ -653,6 +653,19 @@ class CellsManager(manager.Manager): | |
ctxt, cell_name, aggregate_id, host_name) | |
return self._response_to_aggregate(response) | |
+ def create_server_group(self, ctxt, server_group_id, | |
+ server_group, policy): | |
+ response = self.msg_runner.create_server_group( | |
+ ctxt, server_group_id, server_group, policy) | |
+ | |
+ def delete_server_group(self, ctxt, server_group_id): | |
+ response = self.msg_runner.delete_server_group( | |
+ ctxt, server_group_id) | |
+ | |
+ def server_group_add_members(self, ctxt, server_group_id, instance_uuid): | |
+ response = self.msg_runner.server_group_add_members( | |
+ ctxt, server_group_id, instance_uuid) | |
+ | |
def flavor_create(self, ctxt, cell_name, values): | |
response = self.msg_runner.flavor_create(ctxt, | |
cell_name, values) | |
diff --git a/nova/cells/messaging.py b/nova/cells/messaging.py | |
index 505223a..7a71f97 100644 | |
--- a/nova/cells/messaging.py | |
+++ b/nova/cells/messaging.py | |
@@ -618,6 +618,7 @@ class _BaseMessageMethods(base.Base): | |
self.compute_rpcapi = compute_rpcapi.ComputeAPI() | |
self.consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI() | |
self.host_api = compute.HostAPI() | |
+ self.server_group_api = compute.api.ServerGroupAPI() | |
def task_log_get_all(self, message, task_name, period_beginning, | |
period_ending, host, state): | |
@@ -1288,6 +1289,22 @@ class _BroadcastMessageMethods(_BaseMessageMethods): | |
response = self.aggregate_api.get_aggregate_list(message.ctxt) | |
return jsonutils.to_primitive(response) | |
+ def create_server_group(self, message, server_group_id, | |
+ server_group, policy): | |
+ server_group_dict = { 'uuid': server_group_id, | |
+ 'name': server_group, | |
+ 'policies': policy } | |
+ response = self.server_group_api.create(message.ctxt, server_group_dict) | |
+ return jsonutils.to_primitive(response) | |
+ | |
+ def delete_server_group(self, message, server_group_id): | |
+ response = self.server_group_api.delete(message.ctxt, server_group_id) | |
+ return jsonutils.to_primitive(response) | |
+ | |
+ def server_group_add_members(self, message, server_group_id, instance_uuid): | |
+ response = self.server_group_api.add_members(message.ctxt, server_group_id, | |
+ instance_uuid) | |
+ return jsonutils.to_primitive(response) | |
_CELL_MESSAGE_TYPE_TO_MESSAGE_CLS = {'targeted': _TargetedMessage, | |
'broadcast': _BroadcastMessage, | |
@@ -1941,6 +1958,28 @@ class MessageRunner(object): | |
cell_name, need_response=True) | |
return message.process() | |
+ def create_server_group(self, ctxt, server_group_id, | |
+ server_group, policy): | |
+ method_kwargs = dict(server_group_id=server_group_id, | |
+ server_group=server_group, | |
+ policy=policy) | |
+ message = _BroadcastMessage(self, ctxt, 'create_server_group', | |
+ method_kwargs, 'down', run_locally=False, need_response=True) | |
+ return message.process() | |
+ | |
+ def delete_server_group(self, ctxt, server_group_id): | |
+ method_kwargs = dict(server_group_id=server_group_id) | |
+ message = _BroadcastMessage(self, ctxt, 'delete_server_group', | |
+ method_kwargs, 'down', run_locally=False, need_response=True) | |
+ return message.process() | |
+ | |
+ def server_group_add_members(self, ctxt, server_group_id, instance_uuid): | |
+ method_kwargs = dict(server_group_id=server_group_id, | |
+ instance_uuid=instance_uuid) | |
+ message = _BroadcastMessage(self, ctxt, 'server_group_add_members', | |
+ method_kwargs, 'down', run_locally=False, need_response=True) | |
+ return message.process() | |
+ | |
def flavor_create(self, ctxt, cell_name, values): | |
message = _TargetedMessage(self, ctxt, 'flavor_create', | |
dict(values=values), | |
diff --git a/nova/cells/rpcapi.py b/nova/cells/rpcapi.py | |
index 2c1f717..615b23e 100644 | |
--- a/nova/cells/rpcapi.py | |
+++ b/nova/cells/rpcapi.py | |
@@ -757,3 +757,22 @@ class CellsAPI(object): | |
cell_name=cell_name, | |
aggregate_id=aggregate_id, | |
host_name=host_name) | |
+ | |
+ def create_server_group(self, ctxt, server_group_id, | |
+ server_group, policy): | |
+ cctxt = self.client.prepare(version='1.36.1') | |
+ return cctxt.cast(ctxt, 'create_server_group', | |
+ server_group_id=server_group_id, | |
+ server_group=server_group, | |
+ policy=policy) | |
+ | |
+ def delete_server_group(self, ctxt, server_group_id): | |
+ cctxt = self.client.prepare(version='1.36.1') | |
+ return cctxt.cast(ctxt, 'delete_server_group', | |
+ server_group_id=server_group_id) | |
+ | |
+ def server_group_add_members(self, ctxt, server_group_id, instance_uuid): | |
+ cctxt = self.client.prepare(version='1.36.1') | |
+ return cctxt.cast(ctxt, 'server_group_add_members', | |
+ server_group_id=server_group_id, | |
+ instance_uuid=instance_uuid) | |
diff --git a/nova/compute/__init__.py b/nova/compute/__init__.py | |
index d8a65ec..451149f 100644 | |
--- a/nova/compute/__init__.py | |
+++ b/nova/compute/__init__.py | |
@@ -58,6 +58,16 @@ def AggregateAPI(*args, **kwargs): | |
class_name = compute_api_class.__module__ + ".AggregateAPI" | |
return importutils.import_object(class_name, *args, **kwargs) | |
+def ServerGroupAPI(*args, **kwargs): | |
+ """ | |
+ Returns the 'ServerGroupAPI' class from the same module as the configured | |
+ compute api | |
+ """ | |
+ compute_api_class_name = _get_compute_api_class_name() | |
+ compute_api_class = importutils.import_class(compute_api_class_name) | |
+ class_name = compute_api_class.__module__ + ".ServerGroupAPI" | |
+ return importutils.import_object(class_name, *args, **kwargs) | |
+ | |
def InstanceActionAPI(*args, **kwargs): | |
"""Returns the 'InstanceActionAPI' class from the same module as the | |
diff --git a/nova/compute/api.py b/nova/compute/api.py | |
index ab0f60f..c15858d 100644 | |
--- a/nova/compute/api.py | |
+++ b/nova/compute/api.py | |
@@ -76,6 +76,7 @@ from nova import servicegroup | |
from nova import utils | |
from nova.virt import hardware | |
from nova import volume | |
+from nova import compute | |
LOG = logging.getLogger(__name__) | |
@@ -283,6 +284,7 @@ class API(base.Base): | |
self.compute_rpcapi = compute_rpcapi.ComputeAPI() | |
self._compute_task_api = None | |
self.servicegroup_api = servicegroup.API() | |
+ self.servergroup_api = compute.ServerGroupAPI() | |
self.notifier = rpc.get_notifier('compute', CONF.host) | |
if CONF.ephemeral_storage_encryption.enabled: | |
self.key_manager = keymgr.API() | |
@@ -938,7 +940,7 @@ class API(base.Base): | |
"group") | |
raise exception.QuotaError(msg) | |
- objects.InstanceGroup.add_members(context, | |
+ self.servergroup_api.add_members(context, | |
instance_group.uuid, | |
[instance.uuid]) | |
@@ -3731,6 +3733,70 @@ class AggregateAPI(base.Base): | |
return aggregate | |
+class ServerGroupAPI(base.Base): | |
+ """The Server group API controller for the OpenStack API.""" | |
+ | |
+ def __init__(self, **kwargs): | |
+ self.compute_rpcapi = compute_rpcapi.ComputeAPI() | |
+ super(ServerGroupAPI, self).__init__(**kwargs) | |
+ | |
+ def _format_server_group(self, context, group): | |
+ # the id field has its value as the uuid of the server group | |
+ # There is no 'uuid' key in server_group seen by clients. | |
+ # In addition, clients see policies as a ["policy-name"] list; | |
+ # and they see members as a ["server-id"] list. | |
+ server_group = {} | |
+ server_group['id'] = group.uuid | |
+ server_group['name'] = group.name | |
+ server_group['policies'] = group.policies or [] | |
+ # NOTE(danms): This has been exposed to the user, but never used. | |
+ # Since we can't remove it, just make sure it's always empty. | |
+ server_group['metadata'] = {} | |
+ members = [] | |
+ if group.members: | |
+ # Display the instances that are not deleted. | |
+ filters = {'uuid': group.members, 'deleted': False} | |
+ instances = objects.InstanceList.get_by_filters( | |
+ context, filters=filters) | |
+ members = [instance.uuid for instance in instances] | |
+ server_group['members'] = members | |
+ return server_group | |
+ | |
+ def delete(self, context, id): | |
+ """Delete an server group.""" | |
+ try: | |
+ sg = objects.InstanceGroup.get_by_uuid(context, id) | |
+ except nova.exception.InstanceGroupNotFound as e: | |
+ raise exc.HTTPNotFound(explanation=e.format_message()) | |
+ | |
+ try: | |
+ sg.destroy() | |
+ except nova.exception.InstanceGroupNotFound as e: | |
+ raise exc.HTTPNotFound(explanation=e.format_message()) | |
+ | |
+ return True | |
+ | |
+ def create(self, context, server_group): | |
+ """Creates a new server group.""" | |
+ sg = objects.InstanceGroup(context) | |
+ sg.project_id = context.project_id | |
+ sg.user_id = context.user_id | |
+ try: | |
+ sg.name = server_group.get('name') | |
+ sg.policies = server_group.get('policies') | |
+ if 'uuid' in server_group: | |
+ sg.uuid = server_group.get('uuid') | |
+ sg.create() | |
+ | |
+ except ValueError as e: | |
+ raise exc.HTTPBadRequest(explanation=e) | |
+ | |
+ return {'server_group': self._format_server_group(context, sg)} | |
+ | |
+ def add_members(self, context, server_group_id, instance_uuid): | |
+ objects.InstanceGroup.get_by_uuid(context, server_group_id).add_members(context, server_group_id, instance_uuid) | |
+ | |
+ | |
class KeypairAPI(base.Base): | |
"""Subset of the Compute Manager API for managing key pairs.""" | |
diff --git a/nova/compute/cells_api.py b/nova/compute/cells_api.py | |
index 6a5f237..faec92a 100644 | |
--- a/nova/compute/cells_api.py | |
+++ b/nova/compute/cells_api.py | |
@@ -682,3 +682,50 @@ class AggregateAPI(compute_api.AggregateAPI): | |
def remove_host_from_aggregate(self, context, aggregate_id, host_name): | |
return self._call_rpc_api( | |
context, 'remove_host_from_aggregate', aggregate_id, host_name) | |
+ | |
+ | |
+class ServerGroupAPI(compute_api.ServerGroupAPI): | |
+ """Sub-set of the Compute Manager API for managing server groups.""" | |
+ | |
+ def __init__(self, **kwargs): | |
+ super(ServerGroupAPI, self).__init__(**kwargs) | |
+ self.cells_rpcapi = cells_rpcapi.CellsAPI() | |
+ | |
+ def _call_rpc_api(self, context, method_name, | |
+ *args, **kwargs): | |
+ method = getattr(self.cells_rpcapi, method_name) | |
+ return method(context, *args, **kwargs) | |
+ | |
+ def delete(self, context, id): | |
+ """Delete an server group.""" | |
+ | |
+ """Delete the server group in all compute cells""" | |
+ cells_rc = self._call_rpc_api( | |
+ context, 'delete_server_group', id) | |
+ | |
+ """Finally delete the server group in the API cell""" | |
+ return super(ServerGroupAPI, self).delete(context, id) | |
+ | |
+ def create(self, context, server_group): | |
+ """Creates a new server group.""" | |
+ | |
+ """Create the server group in the API cell""" | |
+ localsg = super(ServerGroupAPI, self).create(context, server_group) | |
+ | |
+ """Create server group in all compute cells.""" | |
+ cells_rc = self._call_rpc_api( | |
+ context, 'create_server_group', localsg.get('server_group').get('id'), | |
+ server_group.get('name'), | |
+ server_group.get('policies')) | |
+ | |
+ return localsg | |
+ | |
+ def add_members(self, context, server_group_id, instance_uuid): | |
+ """Updates server group membership.""" | |
+ | |
+ """Update membership in all compute cells.""" | |
+ cells_rc = self._call_rpc_api( | |
+ context, 'server_group_add_members', server_group_id, instance_uuid) | |
+ | |
+ """Update membership in the API cell.""" | |
+ super(ServerGroupAPI, self).add_members(context, server_group_id, instance_uuid) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment