3
Basic 3-node rabbitmq-server native cluster + nrpe functional tests
5
Cinder is present to exercise and inspect amqp relation functionality.
7
Each individual test is idempotent, in that it creates/deletes
8
a rmq test user, enables or disables ssl as needed.
10
Test order is not required, however tests are numbered to keep
11
relevant tests grouped together in run order.
17
from charmhelpers.contrib.openstack.amulet.deployment import (
18
OpenStackAmuletDeployment
21
from charmhelpers.contrib.openstack.amulet.utils import (
27
# Use DEBUG to turn on debug logging
28
u = OpenStackAmuletUtils(DEBUG)
31
class RmqBasicDeployment(OpenStackAmuletDeployment):
32
"""Amulet tests on a basic rabbitmq cluster deployment. Verify
33
relations, service status, users and endpoint service catalog."""
35
def __init__(self, series=None, openstack=None, source=None, stable=False):
36
"""Deploy the entire test environment."""
37
super(RmqBasicDeployment, self).__init__(series, openstack, source,
41
self._configure_services()
43
self._initialize_tests()
45
def _add_services(self):
48
Add the services that we're testing, where rmq is local,
49
and the rest of the service are from lp branches that are
50
compatible with the local charm (e.g. stable or next).
53
'name': 'rabbitmq-server',
56
other_services = [{'name': 'cinder'},
59
super(RmqBasicDeployment, self)._add_services(this_service,
62
def _add_relations(self):
63
"""Add relations for the services."""
64
relations = {'cinder:amqp': 'rabbitmq-server:amqp',
65
'nrpe:nrpe-external-master':
66
'rabbitmq-server:nrpe-external-master'}
68
super(RmqBasicDeployment, self)._add_relations(relations)
70
def _configure_services(self):
71
"""Configure all of the services."""
73
'min-cluster-size': '3',
74
'max-cluster-tries': '6',
76
'management_plugin': 'False',
77
'stats_cron_schedule': '*/1 * * * *'
80
configs = {'rabbitmq-server': rmq_config,
81
'cinder': cinder_config}
82
super(RmqBasicDeployment, self)._configure_services(configs)
84
def _initialize_tests(self):
85
"""Perform final initialization before tests get run."""
86
# Access the sentries for inspecting service units
87
self.rmq0_sentry = self.d.sentry.unit['rabbitmq-server/0']
88
self.rmq1_sentry = self.d.sentry.unit['rabbitmq-server/1']
89
self.rmq2_sentry = self.d.sentry.unit['rabbitmq-server/2']
90
self.cinder_sentry = self.d.sentry.unit['cinder/0']
91
self.nrpe_sentry = self.d.sentry.unit['nrpe/0']
92
u.log.debug('openstack release val: {}'.format(
93
self._get_openstack_release()))
94
u.log.debug('openstack release str: {}'.format(
95
self._get_openstack_release_string()))
97
# Let things settle a bit before moving forward
100
def _get_rmq_sentry_units(self):
101
"""Local helper specific to this 3-node rmq series of tests."""
102
return [self.rmq0_sentry,
106
def _test_rmq_amqp_messages_all_units(self, sentry_units,
107
ssl=False, port=None):
108
"""Reusable test to send amqp messages to every listed rmq unit
109
and check every listed rmq unit for messages.
111
:param sentry_units: list of sentry units
112
:returns: None if successful. Raise on error.
115
# Add test user if it does not already exist
116
u.add_rmq_test_user(sentry_units)
120
u.configure_rmq_ssl_on(sentry_units, self.d, port=port)
122
u.configure_rmq_ssl_off(sentry_units, self.d)
124
# Publish and get amqp messages in all possible unit combinations.
125
# Qty of checks == (qty of units) ^ 2
127
host_names = u.get_unit_hostnames(sentry_units)
129
for dest_unit in sentry_units:
130
dest_unit_name = dest_unit.info['unit_name']
131
dest_unit_host = dest_unit.info['public-address']
132
dest_unit_host_name = host_names[dest_unit_name]
134
for check_unit in sentry_units:
135
check_unit_name = check_unit.info['unit_name']
136
check_unit_host = check_unit.info['public-address']
137
check_unit_host_name = host_names[check_unit_name]
139
amqp_msg_stamp = u.get_uuid_epoch_stamp()
140
amqp_msg = ('Message {}@{} {}'.format(amqp_msg_counter,
142
amqp_msg_stamp)).upper()
143
# Publish amqp message
144
u.log.debug('Publish message to: {} '
145
'({} {})'.format(dest_unit_host,
147
dest_unit_host_name))
149
u.publish_amqp_message_by_unit(dest_unit,
153
# Wait a bit before checking for message
157
u.log.debug('Get message from: {} '
158
'({} {})'.format(check_unit_host,
160
check_unit_host_name))
162
amqp_msg_rcvd = u.get_amqp_message_by_unit(check_unit,
166
# Validate amqp message content
167
if amqp_msg == amqp_msg_rcvd:
168
u.log.debug('Message {} received '
169
'OK.'.format(amqp_msg_counter))
171
u.log.error('Expected: {}'.format(amqp_msg))
172
u.log.error('Actual: {}'.format(amqp_msg_rcvd))
173
msg = 'Message {} mismatch.'.format(amqp_msg_counter)
174
amulet.raise_status(amulet.FAIL, msg)
176
amqp_msg_counter += 1
178
# Delete the test user
179
u.delete_rmq_test_user(sentry_units)
181
def test_100_rmq_processes(self):
182
"""Verify that the expected service processes are running
183
on each rabbitmq-server unit."""
185
# Beam and epmd sometimes briefly have more than one PID,
186
# True checks for at least 1.
192
# Units with process names and PID quantities expected
193
expected_processes = {
194
self.rmq0_sentry: rmq_processes,
195
self.rmq1_sentry: rmq_processes,
196
self.rmq2_sentry: rmq_processes
199
actual_pids = u.get_unit_process_ids(expected_processes)
200
ret = u.validate_unit_process_ids(expected_processes, actual_pids)
202
amulet.raise_status(amulet.FAIL, msg=ret)
206
def test_102_services(self):
207
"""Verify that the expected services are running on the
208
corresponding service units."""
210
self.rmq0_sentry: ['rabbitmq-server'],
211
self.rmq1_sentry: ['rabbitmq-server'],
212
self.rmq2_sentry: ['rabbitmq-server'],
213
self.cinder_sentry: ['cinder-api',
217
ret = u.validate_services_by_name(services)
219
amulet.raise_status(amulet.FAIL, msg=ret)
223
def test_200_rmq_cinder_amqp_relation(self):
224
"""Verify the rabbitmq-server:cinder amqp relation data"""
225
u.log.debug('Checking rmq:cinder amqp relation data...')
226
unit = self.rmq0_sentry
227
relation = ['amqp', 'cinder:amqp']
229
'private-address': u.valid_ip,
230
'password': u.not_null,
231
'hostname': u.valid_ip
233
ret = u.validate_relation_data(unit, relation, expected)
235
msg = u.relation_error('amqp cinder', ret)
236
amulet.raise_status(amulet.FAIL, msg=msg)
240
def test_201_cinder_rmq_amqp_relation(self):
241
"""Verify the cinder:rabbitmq-server amqp relation data"""
242
u.log.debug('Checking cinder:rmq amqp relation data...')
243
unit = self.cinder_sentry
244
relation = ['amqp', 'rabbitmq-server:amqp']
246
'private-address': u.valid_ip,
247
'vhost': 'openstack',
248
'username': u.not_null
250
ret = u.validate_relation_data(unit, relation, expected)
252
msg = u.relation_error('cinder amqp', ret)
253
amulet.raise_status(amulet.FAIL, msg=msg)
257
def test_202_rmq_nrpe_ext_master_relation(self):
258
"""Verify rabbitmq-server:nrpe nrpe-external-master relation data"""
259
u.log.debug('Checking rmq:nrpe external master relation data...')
260
unit = self.rmq0_sentry
261
relation = ['nrpe-external-master',
262
'nrpe:nrpe-external-master']
264
mon_sub = ('monitors:\n remote:\n nrpe:\n rabbitmq: '
265
'{command: check_rabbitmq}\n rabbitmq_queue: '
266
'{command: check_rabbitmq_queue}\n')
269
'private-address': u.valid_ip,
273
ret = u.validate_relation_data(unit, relation, expected)
275
msg = u.relation_error('amqp nrpe', ret)
276
amulet.raise_status(amulet.FAIL, msg=msg)
280
def test_203_nrpe_rmq_ext_master_relation(self):
281
"""Verify nrpe:rabbitmq-server nrpe-external-master relation data"""
282
u.log.debug('Checking nrpe:rmq external master relation data...')
283
unit = self.nrpe_sentry
284
relation = ['nrpe-external-master',
285
'rabbitmq-server:nrpe-external-master']
288
'private-address': u.valid_ip
291
ret = u.validate_relation_data(unit, relation, expected)
293
msg = u.relation_error('nrpe amqp', ret)
294
amulet.raise_status(amulet.FAIL, msg=msg)
298
def test_300_rmq_config(self):
299
"""Verify the data in the rabbitmq conf file."""
300
conf = '/etc/rabbitmq/rabbitmq-env.conf'
301
sentry_units = self._get_rmq_sentry_units()
302
for unit in sentry_units:
303
host_name = unit.file_contents('/etc/hostname').strip()
304
u.log.debug('Checking rabbitmq config file data on '
305
'{} ({})...'.format(unit.info['unit_name'],
308
'RABBITMQ_NODENAME': 'rabbit@{}'.format(host_name)
311
file_contents = unit.file_contents(conf)
312
u.validate_sectionless_conf(file_contents, expected)
316
def test_400_rmq_cluster_running_nodes(self):
317
"""Verify that cluster status from each rmq juju unit shows
318
every cluster node as a running member in that cluster."""
319
u.log.debug('Checking that all units are in cluster_status '
322
sentry_units = self._get_rmq_sentry_units()
324
ret = u.validate_rmq_cluster_running_nodes(sentry_units)
326
amulet.raise_status(amulet.FAIL, msg=ret)
330
def test_402_rmq_connect_with_ssl_off(self):
331
"""Verify successful non-ssl amqp connection to all units when
332
charm config option for ssl is set False."""
333
u.log.debug('Confirming that non-ssl connection succeeds when '
334
'ssl config is off...')
335
sentry_units = self._get_rmq_sentry_units()
336
u.add_rmq_test_user(sentry_units)
337
u.configure_rmq_ssl_off(sentry_units, self.d)
339
# Check amqp connection for all units, expect connections to succeed
340
for unit in sentry_units:
341
connection = u.connect_amqp_by_unit(unit, ssl=False, fatal=False)
344
u.delete_rmq_test_user(sentry_units)
347
def test_404_rmq_ssl_connect_with_ssl_off(self):
348
"""Verify unsuccessful ssl amqp connection to all units when
349
charm config option for ssl is set False."""
350
u.log.debug('Confirming that ssl connection fails when ssl '
352
sentry_units = self._get_rmq_sentry_units()
353
u.add_rmq_test_user(sentry_units)
354
u.configure_rmq_ssl_off(sentry_units, self.d)
356
# Check ssl amqp connection for all units, expect connections to fail
357
for unit in sentry_units:
358
connection = u.connect_amqp_by_unit(unit, ssl=True,
359
port=5971, fatal=False)
362
msg = 'SSL connection unexpectedly succeeded with ssl=off'
363
amulet.raise_status(amulet.FAIL, msg)
365
u.delete_rmq_test_user(sentry_units)
366
u.log.info('OK - Confirmed that ssl connection attempt fails '
367
'when ssl config is off.')
369
def test_406_rmq_amqp_messages_all_units_ssl_off(self):
370
"""Send amqp messages to every rmq unit and check every rmq unit
371
for messages. Standard amqp tcp port, no ssl."""
372
u.log.debug('Checking amqp message publish/get on all units '
375
sentry_units = self._get_rmq_sentry_units()
376
self._test_rmq_amqp_messages_all_units(sentry_units, ssl=False)
379
def test_408_rmq_amqp_messages_all_units_ssl_on(self):
380
"""Send amqp messages with ssl enabled, to every rmq unit and
381
check every rmq unit for messages. Standard ssl tcp port."""
382
u.log.debug('Checking amqp message publish/get on all units '
385
sentry_units = self._get_rmq_sentry_units()
386
self._test_rmq_amqp_messages_all_units(sentry_units,
390
def test_410_rmq_amqp_messages_all_units_ssl_alt_port(self):
391
"""Send amqp messages with ssl on, to every rmq unit and check
392
every rmq unit for messages. Custom ssl tcp port."""
393
u.log.debug('Checking amqp message publish/get on all units '
396
sentry_units = self._get_rmq_sentry_units()
397
self._test_rmq_amqp_messages_all_units(sentry_units,
401
def test_412_rmq_management_plugin(self):
402
"""Enable and check management plugin."""
403
u.log.debug('Checking tcp socket connect to management plugin '
404
'port on all rmq units...')
406
sentry_units = self._get_rmq_sentry_units()
409
# Enable management plugin
410
u.log.debug('Enabling management_plugin charm config option...')
411
config = {'management_plugin': 'True'}
412
self.d.configure('rabbitmq-server', config)
414
# Check tcp connect to management plugin port
417
ret = u.port_knock_units(sentry_units, mgmt_port)
418
while ret and tries < (max_wait / 12):
420
u.log.debug('Attempt {}: {}'.format(tries, ret))
421
ret = u.port_knock_units(sentry_units, mgmt_port)
425
amulet.raise_status(amulet.FAIL, ret)
427
u.log.debug('Connect to all units (OK)\n')
429
# Disable management plugin
430
u.log.debug('Disabling management_plugin charm config option...')
431
config = {'management_plugin': 'False'}
432
self.d.configure('rabbitmq-server', config)
434
# Negative check - tcp connect to management plugin port
435
u.log.info('Expect tcp connect fail since charm config '
436
'option is disabled.')
438
ret = u.port_knock_units(sentry_units, mgmt_port, expect_success=False)
439
while ret and tries < (max_wait / 12):
441
u.log.debug('Attempt {}: {}'.format(tries, ret))
442
ret = u.port_knock_units(sentry_units, mgmt_port,
443
expect_success=False)
447
amulet.raise_status(amulet.FAIL, ret)
449
u.log.info('Confirm mgmt port closed on all units (OK)\n')
451
def test_414_rmq_nrpe_monitors(self):
452
"""Check rabbimq-server nrpe monitor basic functionality."""
453
sentry_units = self._get_rmq_sentry_units()
454
host_names = u.get_unit_hostnames(sentry_units)
456
# check_rabbitmq monitor
457
u.log.debug('Checking nrpe check_rabbitmq on units...')
458
cmds = ['egrep -oh /usr/local.* /etc/nagios/nrpe.d/'
459
'check_rabbitmq.cfg']
460
ret = u.check_commands_on_units(cmds, sentry_units)
462
amulet.raise_status(amulet.FAIL, msg=ret)
464
u.log.debug('Sleeping 70s for 1m cron job to run...')
467
# check_rabbitmq_queue monitor
468
u.log.debug('Checking nrpe check_rabbitmq_queue on units...')
469
cmds = ['egrep -oh /usr/local.* /etc/nagios/nrpe.d/'
470
'check_rabbitmq_queue.cfg']
471
ret = u.check_commands_on_units(cmds, sentry_units)
473
amulet.raise_status(amulet.FAIL, msg=ret)
475
# check dat file existence
476
u.log.debug('Checking nrpe dat file existence on units...')
477
for sentry_unit in sentry_units:
478
unit_name = sentry_unit.info['unit_name']
479
unit_host_name = host_names[unit_name]
482
'stat /var/lib/rabbitmq/data/{}_general_stats.dat'.format(
484
'stat /var/lib/rabbitmq/data/{}_queue_stats.dat'.format(
488
ret = u.check_commands_on_units(cmds, [sentry_unit])
490
amulet.raise_status(amulet.FAIL, msg=ret)