Use only strings in paste.deploy.loadapp global_conf
1. encode the flags as json 2. pass node_id, bus_id rather than DseNode instance. Create DseNode in harness not eventlet_server. Rationale: global_conf not meant to take non-strings. Somehow got away with it in python2, but fails in python3. When dict (and DseNode) passed through global_conf, paste.deploy.loadapp adds them to configparser defaults, causing errors when configparser calls string methods on them. File "/usr/lib/python3.4/configparser.py", line 390, in _interpolate_some p = rest.find("%") AttributeError: Error in file congress/tests/etc/api-paste.ini: 'dict' object has no attribute 'find' Change-Id: I549b9281e72512bb804a7d6f07bf6482e9485ae4
This commit is contained in:
parent
40b3b3473b
commit
7c6d7c5ad2
|
@ -29,6 +29,7 @@ import sys
|
|||
import eventlet
|
||||
import eventlet.wsgi
|
||||
import greenlet
|
||||
import json
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import service
|
||||
|
@ -99,34 +100,30 @@ class APIServer(service.ServiceBase):
|
|||
self.keepalive = keepalive
|
||||
self.keepidle = keepidle
|
||||
self.socket = None
|
||||
self.node = None
|
||||
self.bus_id = bus_id
|
||||
# store API, policy-engine, datasource flags; for use in start()
|
||||
self.flags = kwargs
|
||||
|
||||
# TODO(masa): To support Active-Active HA with DseNode on any
|
||||
# driver of oslo.messaging, make sure to use same partition_id
|
||||
# among multi DseNodes sharing same message topic namespace.
|
||||
self.node = dse_node.DseNode(cfg.CONF, self.name, [],
|
||||
partition_id=bus_id)
|
||||
|
||||
def start(self, key=None, backlog=128):
|
||||
"""Run a WSGI server with the given application."""
|
||||
if self.node is not None:
|
||||
self.node.start()
|
||||
|
||||
if self.socket is None:
|
||||
self.listen(key=key, backlog=backlog)
|
||||
|
||||
try:
|
||||
kwargs = {'global_conf':
|
||||
{'node': [self.node],
|
||||
'flags': self.flags}}
|
||||
{'node_id': self.name,
|
||||
'bus_id': self.bus_id,
|
||||
'flags': json.dumps(self.flags)}}
|
||||
self.application = deploy.loadapp('config:%s' % self.app_conf,
|
||||
name='congress', **kwargs)
|
||||
except Exception:
|
||||
LOG.exception('Failed to Start %s server', self.node.node_id)
|
||||
LOG.exception('Failed to Start %s server', self.name)
|
||||
raise exception.CongressException(
|
||||
'Failed to Start initializing %s server' % self.node.node_id)
|
||||
'Failed to Start initializing %s server' % self.name)
|
||||
|
||||
self.greenthread = self.pool.spawn(self._run,
|
||||
self.application,
|
||||
|
@ -198,8 +195,8 @@ class APIServer(service.ServiceBase):
|
|||
|
||||
def stop(self):
|
||||
self.kill()
|
||||
if self.node is not None:
|
||||
self.node.stop()
|
||||
# We're not able to stop the DseNode in this case. Is there a need to
|
||||
# stop the ApiServer without also exiting the process?
|
||||
|
||||
def reset(self):
|
||||
LOG.info("reset() not implemented yet")
|
||||
|
|
|
@ -39,6 +39,7 @@ from congress.api import status_model
|
|||
from congress.api.system import driver_model
|
||||
from congress.api import table_model
|
||||
from congress.db import datasources as db_datasources
|
||||
from congress.dse2 import dse_node
|
||||
from congress import exception
|
||||
from congress.policy_engines import agnostic
|
||||
|
||||
|
@ -47,18 +48,31 @@ LOG = logging.getLogger(__name__)
|
|||
ENGINE_SERVICE_NAME = 'engine'
|
||||
|
||||
|
||||
def create2(node, policy_engine=True, datasources=True, api=True):
|
||||
def create2(node_id=None, bus_id=None, existing_node=None,
|
||||
policy_engine=True, datasources=True, api=True):
|
||||
"""Get Congress up.
|
||||
|
||||
Creates a DseNode if one is not provided and adds policy_engine,
|
||||
datasources, api to that node.
|
||||
|
||||
:param node is a DseNode
|
||||
:param node_id is node_id of DseNode to be created
|
||||
:param bus_id is partition_id of DseNode to be created
|
||||
:param existing_node is a DseNode (optional; in lieu of previous 2 params)
|
||||
:param policy_engine controls whether policy_engine is included
|
||||
:param datasources controls whether datasources are included
|
||||
:param api controls whether API is included
|
||||
:returns DseNode
|
||||
"""
|
||||
# create DseNode if existing_node not given
|
||||
if existing_node is None:
|
||||
assert (not (node_id is None or bus_id is None)),\
|
||||
'params node_id and bus_id required.'
|
||||
node = dse_node.DseNode(cfg.CONF, node_id, [], partition_id=bus_id)
|
||||
else:
|
||||
assert (node_id is None and bus_id is None),\
|
||||
'params node_id and bus_id must be None when existing_node given.'
|
||||
node = existing_node
|
||||
|
||||
# create services as required
|
||||
services = {}
|
||||
if api:
|
||||
|
|
|
@ -103,7 +103,7 @@ def create_api_server(conf_path, node_id, host, port, workers, policy_engine,
|
|||
def create_nonapi_server(node_id, policy_engine, datasources, workers):
|
||||
congress_server = eventlet_server.Server(
|
||||
node_id, bus_id=cfg.CONF.dse.bus_id)
|
||||
harness.create2(node=congress_server.node, api=False,
|
||||
harness.create2(existing_node=congress_server.node, api=False,
|
||||
policy_engine=policy_engine,
|
||||
datasources=datasources)
|
||||
return node_id, ServerWrapper(congress_server, workers)
|
||||
|
|
|
@ -15,6 +15,7 @@ from __future__ import division
|
|||
from __future__ import absolute_import
|
||||
|
||||
import functools
|
||||
import json
|
||||
import sys
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
@ -41,9 +42,11 @@ def fail_gracefully(f):
|
|||
@fail_gracefully
|
||||
def congress_app_factory(global_conf, **local_conf):
|
||||
# global_conf only accepts an iteratable value as its dict value
|
||||
flags_dict = json.loads(global_conf['flags'])
|
||||
services = harness.create2(
|
||||
node=global_conf['node'][0], # value must be iterables
|
||||
policy_engine=global_conf['flags']['policy_engine'],
|
||||
api=global_conf['flags']['api'],
|
||||
datasources=global_conf['flags']['datasources'])
|
||||
node_id=global_conf['node_id'],
|
||||
bus_id=global_conf['bus_id'],
|
||||
policy_engine=flags_dict['policy_engine'],
|
||||
api=flags_dict['api'],
|
||||
datasources=flags_dict['datasources'])
|
||||
return application.ApiApplication(services['api_service'])
|
||||
|
|
|
@ -46,7 +46,8 @@ def setup_config(with_fake_datasource=True, node_id='testnode',
|
|||
cfg.CONF.set_override('datasources', True)
|
||||
|
||||
with mock.patch.object(periodics, 'PeriodicWorker', autospec=True):
|
||||
services = harness.create2(node=node, policy_engine=policy, api=api,
|
||||
services = harness.create2(
|
||||
existing_node=node, policy_engine=policy, api=api,
|
||||
datasources=datasources)
|
||||
|
||||
data = None
|
||||
|
|
|
@ -198,7 +198,7 @@ class TestDsePerformance(testbase.SqlTestCase):
|
|||
[('congress.tests.datasources.performance_datasource_driver'
|
||||
'.PerformanceTestDriver')])
|
||||
self.cage = helper.make_dsenode_new_partition("perf")
|
||||
harness.create2(self.cage)
|
||||
harness.create2(existing_node=self.cage)
|
||||
self.api = {'policy': self.cage.service_object('api-policy'),
|
||||
'rule': self.cage.service_object('api-rule'),
|
||||
'table': self.cage.service_object('api-table'),
|
||||
|
|
Loading…
Reference in New Issue