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
|
||||||
import eventlet.wsgi
|
import eventlet.wsgi
|
||||||
import greenlet
|
import greenlet
|
||||||
|
import json
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_service import service
|
from oslo_service import service
|
||||||
|
@ -99,34 +100,30 @@ class APIServer(service.ServiceBase):
|
||||||
self.keepalive = keepalive
|
self.keepalive = keepalive
|
||||||
self.keepidle = keepidle
|
self.keepidle = keepidle
|
||||||
self.socket = None
|
self.socket = None
|
||||||
self.node = None
|
self.bus_id = bus_id
|
||||||
# store API, policy-engine, datasource flags; for use in start()
|
# store API, policy-engine, datasource flags; for use in start()
|
||||||
self.flags = kwargs
|
self.flags = kwargs
|
||||||
|
|
||||||
# TODO(masa): To support Active-Active HA with DseNode on any
|
# TODO(masa): To support Active-Active HA with DseNode on any
|
||||||
# driver of oslo.messaging, make sure to use same partition_id
|
# driver of oslo.messaging, make sure to use same partition_id
|
||||||
# among multi DseNodes sharing same message topic namespace.
|
# 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):
|
def start(self, key=None, backlog=128):
|
||||||
"""Run a WSGI server with the given application."""
|
"""Run a WSGI server with the given application."""
|
||||||
if self.node is not None:
|
|
||||||
self.node.start()
|
|
||||||
|
|
||||||
if self.socket is None:
|
if self.socket is None:
|
||||||
self.listen(key=key, backlog=backlog)
|
self.listen(key=key, backlog=backlog)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
kwargs = {'global_conf':
|
kwargs = {'global_conf':
|
||||||
{'node': [self.node],
|
{'node_id': self.name,
|
||||||
'flags': self.flags}}
|
'bus_id': self.bus_id,
|
||||||
|
'flags': json.dumps(self.flags)}}
|
||||||
self.application = deploy.loadapp('config:%s' % self.app_conf,
|
self.application = deploy.loadapp('config:%s' % self.app_conf,
|
||||||
name='congress', **kwargs)
|
name='congress', **kwargs)
|
||||||
except Exception:
|
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(
|
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.greenthread = self.pool.spawn(self._run,
|
||||||
self.application,
|
self.application,
|
||||||
|
@ -198,8 +195,8 @@ class APIServer(service.ServiceBase):
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.kill()
|
self.kill()
|
||||||
if self.node is not None:
|
# We're not able to stop the DseNode in this case. Is there a need to
|
||||||
self.node.stop()
|
# stop the ApiServer without also exiting the process?
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
LOG.info("reset() not implemented yet")
|
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.system import driver_model
|
||||||
from congress.api import table_model
|
from congress.api import table_model
|
||||||
from congress.db import datasources as db_datasources
|
from congress.db import datasources as db_datasources
|
||||||
|
from congress.dse2 import dse_node
|
||||||
from congress import exception
|
from congress import exception
|
||||||
from congress.policy_engines import agnostic
|
from congress.policy_engines import agnostic
|
||||||
|
|
||||||
|
@ -47,18 +48,31 @@ LOG = logging.getLogger(__name__)
|
||||||
ENGINE_SERVICE_NAME = 'engine'
|
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.
|
"""Get Congress up.
|
||||||
|
|
||||||
Creates a DseNode if one is not provided and adds policy_engine,
|
Creates a DseNode if one is not provided and adds policy_engine,
|
||||||
datasources, api to that node.
|
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 policy_engine controls whether policy_engine is included
|
||||||
:param datasources controls whether datasources are included
|
:param datasources controls whether datasources are included
|
||||||
:param api controls whether API is included
|
:param api controls whether API is included
|
||||||
:returns DseNode
|
: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
|
# create services as required
|
||||||
services = {}
|
services = {}
|
||||||
if api:
|
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):
|
def create_nonapi_server(node_id, policy_engine, datasources, workers):
|
||||||
congress_server = eventlet_server.Server(
|
congress_server = eventlet_server.Server(
|
||||||
node_id, bus_id=cfg.CONF.dse.bus_id)
|
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,
|
policy_engine=policy_engine,
|
||||||
datasources=datasources)
|
datasources=datasources)
|
||||||
return node_id, ServerWrapper(congress_server, workers)
|
return node_id, ServerWrapper(congress_server, workers)
|
||||||
|
|
|
@ -15,6 +15,7 @@ from __future__ import division
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
@ -41,9 +42,11 @@ def fail_gracefully(f):
|
||||||
@fail_gracefully
|
@fail_gracefully
|
||||||
def congress_app_factory(global_conf, **local_conf):
|
def congress_app_factory(global_conf, **local_conf):
|
||||||
# global_conf only accepts an iteratable value as its dict value
|
# global_conf only accepts an iteratable value as its dict value
|
||||||
|
flags_dict = json.loads(global_conf['flags'])
|
||||||
services = harness.create2(
|
services = harness.create2(
|
||||||
node=global_conf['node'][0], # value must be iterables
|
node_id=global_conf['node_id'],
|
||||||
policy_engine=global_conf['flags']['policy_engine'],
|
bus_id=global_conf['bus_id'],
|
||||||
api=global_conf['flags']['api'],
|
policy_engine=flags_dict['policy_engine'],
|
||||||
datasources=global_conf['flags']['datasources'])
|
api=flags_dict['api'],
|
||||||
|
datasources=flags_dict['datasources'])
|
||||||
return application.ApiApplication(services['api_service'])
|
return application.ApiApplication(services['api_service'])
|
||||||
|
|
|
@ -46,8 +46,9 @@ def setup_config(with_fake_datasource=True, node_id='testnode',
|
||||||
cfg.CONF.set_override('datasources', True)
|
cfg.CONF.set_override('datasources', True)
|
||||||
|
|
||||||
with mock.patch.object(periodics, 'PeriodicWorker', autospec=True):
|
with mock.patch.object(periodics, 'PeriodicWorker', autospec=True):
|
||||||
services = harness.create2(node=node, policy_engine=policy, api=api,
|
services = harness.create2(
|
||||||
datasources=datasources)
|
existing_node=node, policy_engine=policy, api=api,
|
||||||
|
datasources=datasources)
|
||||||
|
|
||||||
data = None
|
data = None
|
||||||
if with_fake_datasource:
|
if with_fake_datasource:
|
||||||
|
|
|
@ -198,7 +198,7 @@ class TestDsePerformance(testbase.SqlTestCase):
|
||||||
[('congress.tests.datasources.performance_datasource_driver'
|
[('congress.tests.datasources.performance_datasource_driver'
|
||||||
'.PerformanceTestDriver')])
|
'.PerformanceTestDriver')])
|
||||||
self.cage = helper.make_dsenode_new_partition("perf")
|
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'),
|
self.api = {'policy': self.cage.service_object('api-policy'),
|
||||||
'rule': self.cage.service_object('api-rule'),
|
'rule': self.cage.service_object('api-rule'),
|
||||||
'table': self.cage.service_object('api-table'),
|
'table': self.cage.service_object('api-table'),
|
||||||
|
|
Loading…
Reference in New Issue