From c8b47d80ed9697559c6dfafa9ecd684d6f9b7980 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Thu, 2 Aug 2012 17:32:07 +1200 Subject: [PATCH] Port existing rpc calls to use the new RPC client API. Patch 2/2, this implements github heat issue 181. test_api_v1 was modified to handle the extra rpc arguments. metadata_register_address hasn't been included in EngineAPI, and it possibly doesn't deserve to. This means that bin/heat-metadata has the only remaining raw rpc call. --- heat/api/v1/stacks.py | 89 +++++++++++--------------- heat/common/config.py | 15 +++-- heat/metadata/api/v1/metadata.py | 43 ++++++------- heat/tests/test_api_v1.py | 104 +++++++++++++++++++------------ 4 files changed, 130 insertions(+), 121 deletions(-) diff --git a/heat/api/v1/stacks.py b/heat/api/v1/stacks.py index 73ba343e00..e21ed55a05 100644 --- a/heat/api/v1/stacks.py +++ b/heat/api/v1/stacks.py @@ -29,6 +29,7 @@ from heat.common import wsgi from heat.common import config from heat.common import context from heat import utils +from heat.engine import rpcapi as engine_rpcapi import heat.engine.api as engine_api from heat.openstack.common import rpc @@ -47,6 +48,7 @@ class StackController(object): def __init__(self, options): self.options = options + self.engine_rpcapi = engine_rpcapi.EngineAPI() def _stackid_addprefix(self, resp): """ @@ -168,10 +170,9 @@ class StackController(object): try: # Note show_stack returns details for all stacks when called with # no stack_name, we only use a subset of the result here though - stack_list = rpc.call(con, 'engine', - {'method': 'show_stack', - 'args': {'stack_name': None, - 'params': parms}}) + stack_list = self.engine_rpcapi.show_stack(con, + stack_name=None, + params=parms) except rpc_common.RemoteError as ex: return self._remote_error(ex) @@ -243,10 +244,9 @@ class StackController(object): stack_name = req.params['StackName'] try: - stack_list = rpc.call(con, 'engine', - {'method': 'show_stack', - 'args': {'stack_name': stack_name, - 'params': parms}}) + stack_list = self.engine_rpcapi.show_stack(con, + stack_name=stack_name, + params=parms) except rpc_common.RemoteError as ex: return self._remote_error(ex) @@ -318,8 +318,8 @@ class StackController(object): # This should not happen, so return HeatInternalFailureError return exception.HeatInternalFailureError(detail=msg) - engine_action = {self.CREATE_STACK: "create_stack", - self.UPDATE_STACK: "update_stack"} + engine_action = {self.CREATE_STACK: self.engine_rpcapi.create_stack, + self.UPDATE_STACK: self.engine_rpcapi.update_stack} con = req.context @@ -346,12 +346,11 @@ class StackController(object): return exception.HeatInvalidParameterValueError(detail=msg) try: - res = rpc.call(con, 'engine', - {'method': engine_action[action], - 'args': {'stack_name': req.params['StackName'], - 'template': stack, - 'params': stack_parms, - 'args': create_args}}) + res = engine_action[action](con, + stack_name=req.params['StackName'], + template=stack, + params=stack_parms, + args=create_args) except rpc_common.RemoteError as ex: return self._remote_error(ex) @@ -368,10 +367,9 @@ class StackController(object): logger.info('get_template') try: - templ = rpc.call(con, 'engine', - {'method': 'get_template', - 'args': {'stack_name': req.params['StackName'], - 'params': parms}}) + templ = self.engine_rpcapi.get_template(con, + stack_name=req.params['StackName'], + params=parms) except rpc_common.RemoteError as ex: return self._remote_error(ex) @@ -415,10 +413,9 @@ class StackController(object): logger.info('validate_template') try: - return rpc.call(con, 'engine', - {'method': 'validate_template', - 'args': {'template': stack, - 'params': parms}}) + return self.engine_rpcapi.validate_template(con, + template=stack, + params=parms) except rpc_common.RemoteError as ex: return self._remote_error(ex) @@ -431,10 +428,10 @@ class StackController(object): parms = dict(req.params) try: - res = rpc.call(con, 'engine', - {'method': 'delete_stack', - 'args': {'stack_name': req.params['StackName'], - 'params': parms}}) + res = self.engine_rpcapi.delete_stack(con, + stack_name=req.params['StackName'], + params=parms, + cast=False) except rpc_common.RemoteError as ex: return self._remote_error(ex) @@ -475,10 +472,9 @@ class StackController(object): stack_name = req.params.get('StackName', None) try: - event_res = rpc.call(con, 'engine', - {'method': 'list_events', - 'args': {'stack_name': stack_name, - 'params': parms}}) + event_res = self.engine_rpcapi.list_events(con, + stack_name=stack_name, + params=parms) except rpc_common.RemoteError as ex: return self._remote_error(ex) @@ -517,15 +513,11 @@ class StackController(object): return self._stackid_addprefix(result) con = req.context - args = { - 'stack_name': req.params.get('StackName'), - 'resource_name': req.params.get('LogicalResourceId'), - } try: - resource_details = rpc.call(con, 'engine', - {'method': 'describe_stack_resource', - 'args': args}) + resource_details = self.engine_rpcapi.describe_stack_resource(con, + stack_name=req.params.get('StackName'), + resource_name=req.params.get('LogicalResourceId')) except rpc_common.RemoteError as ex: return self._remote_error(ex) @@ -579,16 +571,11 @@ class StackController(object): msg = 'Use `StackName` or `PhysicalResourceId` but not both' return exception.HeatInvalidParameterCombinationError(detail=msg) - args = { - 'stack_name': stack_name, - 'physical_resource_id': physical_resource_id, - 'logical_resource_id': req.params.get('LogicalResourceId'), - } - try: - resources = rpc.call(con, 'engine', - {'method': 'describe_stack_resources', - 'args': args}) + resources = self.engine_rpcapi.describe_stack_resources(con, + stack_name=stack_name, + physical_resource_id=physical_resource_id, + logical_resource_id=req.params.get('LogicalResourceId')) except rpc_common.RemoteError as ex: return self._remote_error(ex) @@ -621,10 +608,8 @@ class StackController(object): con = req.context try: - resources = rpc.call(con, 'engine', { - 'method': 'list_stack_resources', - 'args': {'stack_name': req.params.get('StackName')} - }) + resources = self.engine_rpcapi.list_stack_resources(con, + stack_name=req.params.get('StackName')) except rpc_common.RemoteError as ex: return self._remote_error(ex) diff --git a/heat/common/config.py b/heat/common/config.py index ed9c9a52fc..f782e44450 100644 --- a/heat/common/config.py +++ b/heat/common/config.py @@ -91,13 +91,15 @@ cfg.IntOpt('sql_idle_timeout', help='timeout before idle sql connections are reaped'), ] engine_opts = [ -cfg.StrOpt('host', - default=socket.gethostname(), - help='Name of this node. This can be an opaque identifier. ' - 'It is not necessarily a hostname, FQDN, or IP address.'), cfg.StrOpt('instance_driver', default='heat.engine.nova', - help='Driver to use for controlling instances'), + help='Driver to use for controlling instances') +] +rpc_opts = [ +cfg.StrOpt('host', + default=socket.gethostname(), + help='Name of the engine node. This can be an opaque identifier.' + 'It is not necessarily a hostname, FQDN, or IP address.'), cfg.StrOpt('engine_topic', default='engine', help='the topic engine nodes listen on') @@ -107,16 +109,19 @@ cfg.StrOpt('engine_topic', def register_metadata_opts(): cfg.CONF.register_opts(service_opts) cfg.CONF.register_opts(bind_opts) + cfg.CONF.register_opts(rpc_opts) def register_api_opts(): cfg.CONF.register_opts(bind_opts) + cfg.CONF.register_opts(rpc_opts) def register_engine_opts(): cfg.CONF.register_opts(engine_opts) cfg.CONF.register_opts(db_opts) cfg.CONF.register_opts(service_opts) + cfg.CONF.register_opts(rpc_opts) def setup_logging(): diff --git a/heat/metadata/api/v1/metadata.py b/heat/metadata/api/v1/metadata.py index 5677eb6e7f..68c0effb1c 100644 --- a/heat/metadata/api/v1/metadata.py +++ b/heat/metadata/api/v1/metadata.py @@ -19,6 +19,7 @@ from webob.exc import Response from heat.common import wsgi from heat.common import context +from heat.engine import rpcapi as engine_rpcapi from heat.openstack.common import rpc @@ -39,6 +40,7 @@ def json_error(http_status, message): class MetadataController: def __init__(self, options): self.options = options + self.engine_rpcapi = engine_rpcapi.EngineAPI() def entry_point(self, req): return { @@ -48,15 +50,13 @@ class MetadataController: def list_stacks(self, req): con = context.get_admin_context() - resp = rpc.call(con, 'engine', - {'method': 'metadata_list_stacks'}) + resp = self.engine_rpcapi.metadata_list_stacks(con) return resp def list_resources(self, req, stack_name): con = context.get_admin_context() - resources = rpc.call(con, 'engine', - {'method': 'metadata_list_resources', - 'args': {'stack_name': stack_name}}) + resources = self.engine_rpcapi.metadata_list_resources(con, + stack_name=stack_name) if resources: return resources else: @@ -65,11 +65,9 @@ class MetadataController: def get_resource(self, req, stack_name, resource_name): con = context.get_admin_context() - [error, metadata] = rpc.call(con, 'engine', - {'method': 'metadata_get_resource', - 'args': {'stack_name': stack_name, - 'resource_name': resource_name} - }) + [error, metadata] = self.engine_rpcapi.metadata_get_resource(con, + stack_name=stack_name, + resource_name=resource_name) if error: if error == 'stack': return json_error(404, @@ -81,11 +79,10 @@ class MetadataController: def update_metadata(self, req, body, stack_id, resource_name): con = context.get_admin_context() - [error, metadata] = rpc.call(con, 'engine', - {'method': 'metadata_update', - 'args': {'stack_id': stack_id, - 'resource_name': resource_name, - 'metadata': body}}) + [error, metadata] = self.engine_rpcapi.metadata_update(con, + stack_id=stack_id, + resource_name=resource_name, + metadata=body) if error: if error == 'stack': return json_error(404, @@ -100,28 +97,24 @@ class MetadataController: def create_event(self, req, body=None): con = context.get_admin_context() - [error, event] = rpc.call(con, 'engine', - {'method': 'event_create', - 'args': {'event': body}}) + [error, event] = self.engine_rpcapi.event_create(con, event=body) if error: return json_error(400, error) return json_response(201, event) def create_watch_data(self, req, body, watch_name): con = context.get_admin_context() - [error, watch_data] = rpc.call(con, 'engine', - {'method': 'create_watch_data', - 'args': {'watch_name': watch_name, - 'stats_data': body}}) + [error, watch_data] = self.engine_rpcapi.create_watch_data(con, + watch_name=watch_name, + stats_data=body) if error: return json_error(400, error) return json_response(201, watch_data) def list_watch_data(self, req, watch_name): con = context.get_admin_context() - data = rpc.call(con, 'engine', - {'method': 'list_watch_data', - 'args': {'watch_name': watch_name}}) + data = self.engine_rpcapi.list_watch_data(con, + watch_name=watch_name) if data: return data else: diff --git a/heat/tests/test_api_v1.py b/heat/tests/test_api_v1.py index 6dfcd0b8c9..bf9bff480c 100644 --- a/heat/tests/test_api_v1.py +++ b/heat/tests/test_api_v1.py @@ -25,8 +25,10 @@ import httplib import json import urlparse +from heat.common import config from heat.common import context from heat.engine import auth +from heat.openstack.common import cfg from heat.openstack.common import rpc import heat.openstack.common.rpc.common as rpc_common from heat.common.wsgi import Request @@ -145,9 +147,10 @@ class StackControllerTest(unittest.TestCase): u'stack_name': u'wordpress', u'stack_status': u'CREATE_COMPLETE'}]} self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'show_stack', + rpc.call(dummy_req.context, self.topic, {'method': 'show_stack', 'args': {'stack_name': None, - 'params': dict(dummy_req.params)}} + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None ).AndReturn(engine_resp) # Stub socket.gethostname so it returns "ahostname" @@ -175,9 +178,10 @@ class StackControllerTest(unittest.TestCase): # Insert an engine RPC error and ensure we map correctly to the # heat exception type self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'show_stack', + rpc.call(dummy_req.context, self.topic, {'method': 'show_stack', 'args': {'stack_name': None, - 'params': dict(dummy_req.params)}} + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("AttributeError")) self.m.ReplayAll() @@ -193,9 +197,10 @@ class StackControllerTest(unittest.TestCase): # Insert an engine RPC error and ensure we map correctly to the # heat exception type self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'show_stack', + rpc.call(dummy_req.context, self.topic, {'method': 'show_stack', 'args': {'stack_name': None, - 'params': dict(dummy_req.params)}} + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("Exception")) self.m.ReplayAll() @@ -206,7 +211,7 @@ class StackControllerTest(unittest.TestCase): def test_describe(self): # Format a dummy GET request to pass into the WSGI handler - stack_name = "wordpress" + stack_name = u"wordpress" params = {'Action': 'DescribeStacks', 'StackName': stack_name} dummy_req = self._dummy_GET_request(params) @@ -238,9 +243,10 @@ class StackControllerTest(unittest.TestCase): u'capabilities':[]}]} self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'show_stack', 'args': - {'stack_name': stack_name, - 'params': dict(dummy_req.params)}}).AndReturn(engine_resp) + rpc.call(dummy_req.context, self.topic, {'method': 'show_stack', + 'args': {'stack_name': stack_name, + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None).AndReturn(engine_resp) # Stub socket.gethostname so it returns "ahostname" self.m.StubOutWithMock(socket, 'gethostname') @@ -292,9 +298,10 @@ class StackControllerTest(unittest.TestCase): # Insert an engine RPC error and ensure we map correctly to the # heat exception type self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'show_stack', 'args': - {'stack_name': stack_name, - 'params': dict(dummy_req.params)}} + rpc.call(dummy_req.context, self.topic, {'method': 'show_stack', + 'args': {'stack_name': stack_name, + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("AttributeError")) self.m.ReplayAll() @@ -330,12 +337,13 @@ class StackControllerTest(unittest.TestCase): engine_resp = {u'StackName': u'wordpress', u'StackId': 1} self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'create_stack', + rpc.call(dummy_req.context, self.topic, {'method': 'create_stack', 'args': {'stack_name': stack_name, 'template': template, 'params': engine_parms, - 'args': engine_args}}).AndReturn(engine_resp) + 'args': engine_args}, + 'version': self.api_version}, None).AndReturn(engine_resp) # Stub socket.gethostname so it returns "ahostname" self.m.StubOutWithMock(socket, 'gethostname') @@ -389,12 +397,13 @@ class StackControllerTest(unittest.TestCase): # heat exception type self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'create_stack', + rpc.call(dummy_req.context, self.topic, {'method': 'create_stack', 'args': {'stack_name': stack_name, 'template': template, 'params': engine_parms, - 'args': engine_args}} + 'args': engine_args}, + 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("AttributeError")) self.m.ReplayAll() @@ -420,12 +429,13 @@ class StackControllerTest(unittest.TestCase): engine_resp = {u'StackName': u'wordpress', u'StackId': 1} self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'update_stack', + rpc.call(dummy_req.context, self.topic, {'method': 'update_stack', 'args': {'stack_name': stack_name, 'template': template, 'params': engine_parms, - 'args': engine_args}}).AndReturn(engine_resp) + 'args': engine_args}, + 'version': self.api_version}, None).AndReturn(engine_resp) # Stub socket.gethostname so it returns "ahostname" self.m.StubOutWithMock(socket, 'gethostname') @@ -456,10 +466,11 @@ class StackControllerTest(unittest.TestCase): engine_resp = template self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'get_template', + rpc.call(dummy_req.context, self.topic, {'method': 'get_template', 'args': {'stack_name': stack_name, - 'params': dict(dummy_req.params)}}).AndReturn(engine_resp) + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None).AndReturn(engine_resp) self.m.ReplayAll() @@ -479,10 +490,11 @@ class StackControllerTest(unittest.TestCase): # Insert an engine RPC error and ensure we map correctly to the # heat exception type self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'get_template', + rpc.call(dummy_req.context, self.topic, {'method': 'get_template', 'args': {'stack_name': stack_name, - 'params': dict(dummy_req.params)}} + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("AttributeError")) self.m.ReplayAll() @@ -502,10 +514,11 @@ class StackControllerTest(unittest.TestCase): engine_resp = None self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'get_template', + rpc.call(dummy_req.context, self.topic, {'method': 'get_template', 'args': {'stack_name': stack_name, - 'params': dict(dummy_req.params)}}).AndReturn(engine_resp) + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None).AndReturn(engine_resp) self.m.ReplayAll() @@ -543,10 +556,11 @@ class StackControllerTest(unittest.TestCase): engine_resp = None self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'delete_stack', + rpc.call(dummy_req.context, self.topic, {'method': 'delete_stack', 'args': {'stack_name': stack_name, - 'params': dict(dummy_req.params)}}).AndReturn(engine_resp) + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None).AndReturn(engine_resp) self.m.ReplayAll() @@ -564,10 +578,11 @@ class StackControllerTest(unittest.TestCase): # Insert an engine RPC error and ensure we map correctly to the # heat exception type self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'delete_stack', + rpc.call(dummy_req.context, self.topic, {'method': 'delete_stack', 'args': {'stack_name': stack_name, - 'params': dict(dummy_req.params)}} + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("AttributeError")) self.m.ReplayAll() @@ -596,10 +611,11 @@ class StackControllerTest(unittest.TestCase): u'resource_type': u'AWS::EC2::Instance'}]} self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'list_events', + rpc.call(dummy_req.context, self.topic, {'method': 'list_events', 'args': {'stack_name': stack_name, - 'params': dict(dummy_req.params)}}).AndReturn(engine_resp) + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None).AndReturn(engine_resp) # Stub socket.gethostname so it returns "ahostname" self.m.StubOutWithMock(socket, 'gethostname') @@ -633,10 +649,11 @@ class StackControllerTest(unittest.TestCase): # Insert an engine RPC error and ensure we map correctly to the # heat exception type self.m.StubOutWithMock(rpc, 'call') - rpc.call(dummy_req.context, 'engine', {'method': 'list_events', + rpc.call(dummy_req.context, self.topic, {'method': 'list_events', 'args': {'stack_name': stack_name, - 'params': dict(dummy_req.params)}} + 'params': dict(dummy_req.params)}, + 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("Exception")) self.m.ReplayAll() @@ -671,9 +688,10 @@ class StackControllerTest(unittest.TestCase): 'stack_name': dummy_req.params.get('StackName'), 'resource_name': dummy_req.params.get('LogicalResourceId'), } - rpc.call(dummy_req.context, 'engine', + rpc.call(dummy_req.context, self.topic, {'method': 'describe_stack_resource', - 'args': args}).AndReturn(engine_resp) + 'args': args, + 'version': self.api_version}, None).AndReturn(engine_resp) # Stub socket.gethostname so it returns "ahostname" self.m.StubOutWithMock(socket, 'gethostname') @@ -727,9 +745,10 @@ class StackControllerTest(unittest.TestCase): 'physical_resource_id': None, 'logical_resource_id': dummy_req.params.get('LogicalResourceId'), } - rpc.call(dummy_req.context, 'engine', + rpc.call(dummy_req.context, self.topic, {'method': 'describe_stack_resources', - 'args': args}).AndReturn(engine_resp) + 'args': args, + 'version': self.api_version}, None).AndReturn(engine_resp) # Stub socket.gethostname so it returns "ahostname" self.m.StubOutWithMock(socket, 'gethostname') @@ -792,9 +811,10 @@ class StackControllerTest(unittest.TestCase): args = { 'stack_name': dummy_req.params.get('StackName'), } - rpc.call(dummy_req.context, 'engine', + rpc.call(dummy_req.context, self.topic, {'method': 'list_stack_resources', - 'args': args}).AndReturn(engine_resp) + 'args': args, + 'version': self.api_version}, None).AndReturn(engine_resp) self.m.ReplayAll() @@ -816,6 +836,12 @@ class StackControllerTest(unittest.TestCase): self.maxDiff = None self.m = mox.Mox() + config.register_engine_opts() + cfg.CONF.set_default('engine_topic', 'engine') + cfg.CONF.set_default('host', 'host') + self.topic = '%s.%s' % (cfg.CONF.engine_topic, cfg.CONF.host) + self.api_version = '1.0' + # Create WSGI controller instance class DummyConfig(): bind_port = 8000