Support listening to multiple rabbit queues.
This change adds the ability to listen for events across multiple rabbit queues. Nova cells v2 has a message broker per cell and the charms already support having a separate message broker for neutron, in both these topologies ceilometer needs the ability to listen to multiple brokers. To achieve this a new relation 'amqp-listener' has been introduced. The existing 'amqp' relation should be used for the broker that ceilometer listens to and publishes to. 'amqp-listener' should be used for additional brokers that ceilometer just listens on. Update functional tests to satisfy relation with nova-cloud-controller. Change-Id: Ifdade3f7814620f4cd4a1d35a584cbc099bb6d88
This commit is contained in:
parent
173374187e
commit
67b149f89c
10
README.md
10
README.md
|
@ -36,7 +36,7 @@ must be run post deployment in order to update its data store in gnocchi.
|
|||
|
||||
then Keystone and Rabbit relationships need to be established:
|
||||
|
||||
juju add-relation ceilometer rabbitmq
|
||||
juju add-relation ceilometer:amqp rabbitmq
|
||||
juju add-relation ceilometer keystone:identity-service
|
||||
juju add-relation ceilometer keystone:identity-notifications
|
||||
|
||||
|
@ -57,6 +57,14 @@ installed in each nova node, and be related with Ceilometer service:
|
|||
Ceilometer provides an API service that can be used to retrieve
|
||||
Openstack metrics.
|
||||
|
||||
If ceilometer needs to listen to multiple message queues then use the amqp interface
|
||||
to relate ceilometer to the message broker that it should publish to and use the
|
||||
amqp-listener interface for all message brokers ceilometer should monitor.
|
||||
|
||||
juju add-relation ceilometer:amqp rabbitmq-central
|
||||
juju add-relation ceilometer:amqp-listener rabbitmq-neutron
|
||||
juju add-relation ceilometer:amqp-listener rabbitmq-nova-cell2
|
||||
|
||||
HA/Clustering
|
||||
-------------
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ceilometer_hooks.py
|
|
@ -0,0 +1 @@
|
|||
ceilometer_hooks.py
|
|
@ -0,0 +1 @@
|
|||
ceilometer_hooks.py
|
|
@ -130,6 +130,7 @@ def install():
|
|||
disable_package_apache_site()
|
||||
|
||||
|
||||
@hooks.hook("amqp-listener-relation-joined")
|
||||
@hooks.hook("amqp-relation-joined")
|
||||
def amqp_joined():
|
||||
relation_set(username=config('rabbit-user'),
|
||||
|
@ -155,6 +156,8 @@ def metric_service_joined():
|
|||
|
||||
@hooks.hook("amqp-relation-changed",
|
||||
"amqp-relation-departed",
|
||||
"amqp-listener-relation-changed",
|
||||
"amqp-listener-relation-departed",
|
||||
"shared-db-relation-changed",
|
||||
"shared-db-relation-departed",
|
||||
"identity-service-relation-changed",
|
||||
|
|
|
@ -28,6 +28,7 @@ from charmhelpers.contrib.openstack.context import (
|
|||
OSContextGenerator,
|
||||
context_complete,
|
||||
ApacheSSLContext as SSLContext,
|
||||
AMQPContext,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.hahelpers.cluster import (
|
||||
|
@ -186,3 +187,22 @@ class MetricServiceContext(OSContextGenerator):
|
|||
return {'gnocchi_url': gnocchi_url,
|
||||
'archive_policy': config('gnocchi-archive-policy')}
|
||||
return {}
|
||||
|
||||
|
||||
class AMQPListenersContext(OSContextGenerator):
|
||||
interfaces = ['amqp-listener']
|
||||
|
||||
def __init__(self, ssl_dir=None):
|
||||
self.ssl_dir = ssl_dir
|
||||
|
||||
def __call__(self):
|
||||
ctxt = {}
|
||||
messaging_urls = []
|
||||
relids = relation_ids('amqp-listener') + relation_ids('amqp')
|
||||
for relid in relids:
|
||||
amqp_ctxt = AMQPContext(ssl_dir=self.ssl_dir, relation_id=relid)()
|
||||
if amqp_ctxt.get('transport_url'):
|
||||
messaging_urls.append(amqp_ctxt['transport_url'])
|
||||
if messaging_urls:
|
||||
ctxt['messaging_urls'] = messaging_urls
|
||||
return ctxt
|
||||
|
|
|
@ -33,6 +33,7 @@ from ceilometer_contexts import (
|
|||
MetricServiceContext,
|
||||
CEILOMETER_PORT,
|
||||
RemoteSinksContext,
|
||||
AMQPListenersContext,
|
||||
)
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
get_os_codename_package,
|
||||
|
@ -155,7 +156,8 @@ QUEENS_CONFIG_FILES = OrderedDict([
|
|||
context.SyslogContext(),
|
||||
context.MemcacheContext(),
|
||||
MetricServiceContext(),
|
||||
context.WorkerConfigContext()],
|
||||
context.WorkerConfigContext(),
|
||||
AMQPListenersContext(ssl_dir=CEILOMETER_CONF_DIR)],
|
||||
'services': QUEENS_SERVICES
|
||||
}),
|
||||
])
|
||||
|
|
|
@ -32,6 +32,8 @@ requires:
|
|||
interface: mongodb
|
||||
amqp:
|
||||
interface: rabbitmq
|
||||
amqp-listener:
|
||||
interface: rabbitmq
|
||||
identity-service:
|
||||
interface: keystone
|
||||
identity-notifications:
|
||||
|
|
|
@ -23,6 +23,12 @@ transport_url = {{ transport_url }}
|
|||
|
||||
[notification]
|
||||
workers = {{ workers }}
|
||||
{% if messaging_urls -%}
|
||||
{% for item in messaging_urls -%}
|
||||
messaging_urls = {{ item }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
[collector]
|
||||
workers = {{ workers }}
|
||||
|
|
|
@ -67,7 +67,8 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
|
|||
{'name': 'keystone'},
|
||||
{'name': 'glance'}, # to satisfy workload status
|
||||
{'name': 'ceilometer-agent'},
|
||||
{'name': 'nova-compute'}
|
||||
{'name': 'nova-compute'},
|
||||
{'name': 'nova-cloud-controller'},
|
||||
]
|
||||
if self._get_openstack_release() >= self.xenial_pike:
|
||||
other_services.extend([
|
||||
|
@ -99,7 +100,14 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
|
|||
'glance:identity-service': 'keystone:identity-service',
|
||||
'glance:shared-db': 'percona-cluster:shared-db',
|
||||
'glance:amqp': 'rabbitmq-server:amqp',
|
||||
'nova-compute:image-service': 'glance:image-service'
|
||||
'nova-compute:image-service': 'glance:image-service',
|
||||
'nova-cloud-controller:shared-db': 'percona-cluster:shared-db',
|
||||
'nova-cloud-controller:amqp': 'rabbitmq-server:amqp',
|
||||
'nova-cloud-controller:identity-service': 'keystone:'
|
||||
'identity-service',
|
||||
'nova-cloud-controller:cloud-compute': 'nova-compute:'
|
||||
'cloud-compute',
|
||||
'nova-cloud-controller:image-service': 'glance:image-service',
|
||||
}
|
||||
if self._get_openstack_release() >= self.xenial_pike:
|
||||
additional_relations = {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from mock import patch
|
||||
from mock import patch, MagicMock
|
||||
|
||||
import ceilometer_contexts as contexts
|
||||
import ceilometer_utils as utils
|
||||
|
@ -223,3 +223,53 @@ class CeilometerContextsTest(CharmTestCase):
|
|||
self.test_config.set('remote-sink', 'http://foo http://bar')
|
||||
self.assertEqual(contexts.RemoteSinksContext()(),
|
||||
{'remote_sinks': ['http://foo', 'http://bar']})
|
||||
|
||||
@patch.object(contexts, 'AMQPContext')
|
||||
def test_AMQPListenersContext(self, mock_AMQPContext):
|
||||
|
||||
def _context(ssl_dir, relation_id):
|
||||
fake_context1 = MagicMock(
|
||||
return_value={'transport_url': 'rabbit://rab1:1010/os'})
|
||||
fake_context2 = MagicMock(
|
||||
return_value={'other_setting': 'sss'})
|
||||
fake_context3 = MagicMock(
|
||||
return_value={'transport_url': 'rabbit://rab2:1010/os'})
|
||||
rdata = {
|
||||
'amqp-listener:23': fake_context1,
|
||||
'amqp-listener:8': fake_context2,
|
||||
'amqp:2': fake_context3}
|
||||
|
||||
return rdata[relation_id]
|
||||
|
||||
mock_AMQPContext.side_effect = _context
|
||||
|
||||
rids = {
|
||||
'amqp-listener': ['amqp-listener:23', 'amqp-listener:8'],
|
||||
'amqp': ['amqp:2']}
|
||||
self.relation_ids.side_effect = lambda x: rids[x]
|
||||
self.assertEqual(
|
||||
contexts.AMQPListenersContext()(),
|
||||
{'messaging_urls': [
|
||||
'rabbit://rab1:1010/os',
|
||||
'rabbit://rab2:1010/os']})
|
||||
|
||||
@patch.object(contexts, 'AMQPContext')
|
||||
def test_AMQPListenersContext_no_transport_urls(self, mock_AMQPContext):
|
||||
|
||||
def _context(ssl_dir, relation_id):
|
||||
fake_context1 = MagicMock(return_value={})
|
||||
fake_context2 = MagicMock(return_value={})
|
||||
fake_context3 = MagicMock(return_value={})
|
||||
rdata = {
|
||||
'amqp-listener:23': fake_context1,
|
||||
'amqp-listener:8': fake_context2,
|
||||
'amqp:2': fake_context3}
|
||||
return rdata[relation_id]
|
||||
|
||||
mock_AMQPContext.side_effect = _context
|
||||
|
||||
rids = {
|
||||
'amqp-listener': ['amqp-listener:23', 'amqp-listener:8'],
|
||||
'amqp': ['amqp:2']}
|
||||
self.relation_ids.side_effect = lambda x: rids[x]
|
||||
self.assertEqual(contexts.AMQPListenersContext()(), {})
|
||||
|
|
Loading…
Reference in New Issue