From 1347022cc97b1f916f2316b8fc14e543a5057dd7 Mon Sep 17 00:00:00 2001 From: Maxim Kulkin Date: Thu, 31 Oct 2013 16:38:35 +0400 Subject: [PATCH] Added RabbitMQ info descovery --- rubick/discovery.py | 24 ++++++++++- rubick/model.py | 18 +++++++- rubick/schema.py | 65 +++++++++++++++++++++++++---- rubick/schemas/__init__.py | 1 + rubick/schemas/rabbitmq/__init__.py | 1 + rubick/schemas/rabbitmq/v3_0_0.py | 27 ++++++++++++ rubick/test_type_validators.py | 46 +++++++++++++++++++- 7 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 rubick/schemas/rabbitmq/__init__.py create mode 100644 rubick/schemas/rabbitmq/v3_0_0.py diff --git a/rubick/discovery.py b/rubick/discovery.py index e9cffe8..e458ae3 100644 --- a/rubick/discovery.py +++ b/rubick/discovery.py @@ -624,7 +624,9 @@ class OpenstackDiscovery(object): def _collect_rabbitmq_data(self, client): process = self._find_process(client, 'beam.smp') if not process: - return None + process = self._find_process(client, 'beam') + if not process: + return None if ' '.join(process).find('rabbit') == -1: return None @@ -632,6 +634,24 @@ class OpenstackDiscovery(object): rabbitmq = RabbitMqComponent() rabbitmq.version = 'unknown' + env_file = '/etc/rabbitmq/rabbitmq-env.conf' + env_vars = {} + result = client.run(['bash', '-c', 'source %s && printenv' % env_file]) + if result.return_code == 0: + lines = result.output.split("\n") + env_vars = dict((k, v) for k, v in lines.split('=', 1)) + + rabbitmq_env_vars = \ + dict((key.replace('RABBITMQ_', ''), value) + for key, value in env_vars if key.startswith('RABBITMQ_')) + + for key, value in rabbitmq_env_vars: + rabbitmq.config.set_env(key, value) + + for i, s in enumerate(process): + if s == '-rabbit' and i + 2 <= len(process): + rabbitmq.config.set_cli(process[i + 1], process[i + 2]) + return rabbitmq def _collect_neutron_server_data(self, client): @@ -673,4 +693,4 @@ class OpenstackDiscovery(object): swift_proxy_server.config_files.append( self._collect_file(client, config_path)) - return swift_proxy_server \ No newline at end of file + return swift_proxy_server diff --git a/rubick/model.py b/rubick/model.py index 0b44ced..f6eb544 100644 --- a/rubick/model.py +++ b/rubick/model.py @@ -1,7 +1,7 @@ from itertools import groupby import logging -from rubick.common import Mark, Issue, MarkedIssue +from rubick.common import Mark, Issue, MarkedIssue, Version from rubick.config_formats import IniConfigParser from rubick.config_model import Configuration from rubick.schema import ConfigSchemaRegistry, TypeValidatorRegistry @@ -346,6 +346,22 @@ class MysqlComponent(Service): class RabbitMqComponent(Service): name = 'rabbitmq' + @property + @memoized + def config(self): + config = Configuration() + schema = ConfigSchemaRegistry.get_schema('rabbitmq', Version(1000000)) + if schema: + for parameter in schema.parameters: + if not parameter.default: + continue + + config.set_default(parameter.name, parameter.default) + else: + print("RabbitMQ schema not found") + + return config + class GlanceApiComponent(OpenstackComponent): component = 'glance' diff --git a/rubick/schema.py b/rubick/schema.py index 4a1d080..c0b382e 100644 --- a/rubick/schema.py +++ b/rubick/schema.py @@ -1,4 +1,5 @@ from contextlib import contextmanager +import re from rubick.common import Issue, MarkedIssue, Mark, Version, find, index from rubick.exceptions import RubickException @@ -443,8 +444,7 @@ def validate_port(s, min=1, max=65535): return validate_integer(s, min=min, max=max) -@type_validator('string_list') -def validate_list(s, element_type='string'): +def validate_list(s, element_type): element_type_validator = TypeValidatorRegistry.get_validator(element_type) if not element_type_validator: return SchemaIssue('Invalid element type "%s"' % element_type) @@ -456,16 +456,29 @@ def validate_list(s, element_type='string'): return result values = s.split(',') - for value in values: - validated_value = element_type_validator.validate(value.strip()) - if isinstance(validated_value, Issue): - # TODO: provide better position reporting - return validated_value + while len(values) > 0: + value = values.pop(0) + while True: + validated_value = element_type_validator.validate(value.strip()) + if not isinstance(validated_value, Issue): + break + + if len(values) == 0: + # TODO: provide better position reporting + return validated_value + + value += ',' + values.pop() + result.append(validated_value) return result +@type_validator('string_list') +def validate_string_list(s): + return validate_list(s, element_type='string') + + @type_validator('string_dict') def validate_dict(s, element_type='string'): element_type_validator = TypeValidatorRegistry.get_validator(element_type) @@ -501,3 +514,41 @@ def validate_dict(s, element_type='string'): return validated_value result[key] = validated_value return result + + +@type_validator('rabbitmq_bind') +def validate_rabbitmq_bind(s): + m = re.match('\d+', s) + if m: + port = validate_port(s) + if isinstance(port, Issue): + return port + + return ('0.0.0.0', port) + + m = re.match('{\s*\"(.+)\"\s*,\s*(\d+)\s*}', s) + if m: + host = validate_host_address(m.group(1)) + port = validate_port(m.group(2)) + + if isinstance(host, Issue): + return host + + if isinstance(port, Issue): + return port + + return (host, port) + + return SchemaIssue("Unrecognized bind format") + + +def validate_rabbitmq_list(s, element_type): + if not (s.startswith('[') and s.endswith(']')): + return SchemaIssue('List should be surrounded by [ and ]') + + return validate_list(s[1:-1], element_type=element_type) + + +@type_validator('rabbitmq_bind_list') +def validate_rabbitmq_bind_list(s): + return validate_rabbitmq_list(s, element_type='rabbitmq_bind') diff --git a/rubick/schemas/__init__.py b/rubick/schemas/__init__.py index 9ded00d..013c485 100644 --- a/rubick/schemas/__init__.py +++ b/rubick/schemas/__init__.py @@ -4,3 +4,4 @@ import rubick.schemas.keystone import rubick.schemas.neutron import rubick.schemas.nova import rubick.schemas.swift +import rubick.schemas.rabbitmq diff --git a/rubick/schemas/rabbitmq/__init__.py b/rubick/schemas/rabbitmq/__init__.py new file mode 100644 index 0000000..6ee69af --- /dev/null +++ b/rubick/schemas/rabbitmq/__init__.py @@ -0,0 +1 @@ +import rubick.schemas.rabbitmq.v3_0_0 diff --git a/rubick/schemas/rabbitmq/v3_0_0.py b/rubick/schemas/rabbitmq/v3_0_0.py new file mode 100644 index 0000000..f882f7b --- /dev/null +++ b/rubick/schemas/rabbitmq/v3_0_0.py @@ -0,0 +1,27 @@ +from rubick.schema import ConfigSchemaRegistry + +rabbitmq = ConfigSchemaRegistry.register_schema(project='rabbitmq') + +with rabbitmq.version('3.0.0', checkpoint=True) as cfg: + cfg.param( + 'tcp_listeners', type='rabbitmq_bind_list', default=[5672], + description="List of ports on which to listen for AMQP connections (without SSL)") + + cfg.param( + 'ssl_listeners', type='rabbitmq_bind_list', default=[], + description="List of ports on which to listen for AMQP connections (SSL)") + + cfg.param('ssl_options', type='string_list', default=[]) + + cfg.param('vm_memory_high_watermark', type='float', default=0.4) + + cfg.param('vm_memory_high_watermark_paging_ratio', + type='float', default=0.5) + + cfg.param('disk_free_limit', type='integer', default='50000000') + cfg.param('log_levels', type='string_list', default=['{connection, info}']) + cfg.param('frame_max', type='integer', default=131072) + cfg.param('heartbeat', type='integer', default=600) + cfg.param('default_vhost', type='string', default='/') + cfg.param('default_user', type='string', default='guest') + cfg.param('default_pass', type='string', default='guest') diff --git a/rubick/test_type_validators.py b/rubick/test_type_validators.py index 3b3203b..21a9a72 100644 --- a/rubick/test_type_validators.py +++ b/rubick/test_type_validators.py @@ -5,7 +5,6 @@ import unittest class TypeValidatorTestHelper(object): - def setUp(self): super(TypeValidatorTestHelper, self).setUp() self.validator = TypeValidatorRegistry.get_validator(self.type_name) @@ -14,7 +13,8 @@ class TypeValidatorTestHelper(object): self.assertNotIsInstance(self.validator.validate(value), Issue) def assertInvalid(self, value): - self.assertIsInstance(self.validator.validate(value), Issue) + self.assertIsInstance( + self.validator.validate(value), Issue) class StringTypeValidatorTests(TypeValidatorTestHelper, unittest.TestCase): @@ -277,5 +277,47 @@ class StringDictTypeValidatorTests(TypeValidatorTestHelper, unittest.TestCase): self.assertEqual(2, len(v)) +class RabbitmqBindValidatorTest(TypeValidatorTestHelper, unittest.TestCase): + type_name = 'rabbitmq_bind' + + def test_empty_value_is_an_error(self): + self.assertInvalid('') + + def test_integer(self): + v = self.validator.validate('123') + + self.assertEqual(('0.0.0.0', 123), v) + + def test_integer_outside_port_range(self): + self.assertInvalid('65536') + + def test_host_port(self): + v = self.validator.validate('{"127.0.0.1",8080}') + + self.assertEqual(('127.0.0.1', 8080), v) + + +class RabbitmqListValidatorTest(TypeValidatorTestHelper, unittest.TestCase): + type_name = 'rabbitmq_bind_list' + + def test_empty(self): + self.assertInvalid('') + + def test_empty_list(self): + v = self.validator.validate('[]') + + self.assertEqual([], v) + + def test_single_entry(self): + v = self.validator.validate('[123]') + + self.assertEqual([('0.0.0.0', 123)], v) + + def test_multiple_entries(self): + v = self.validator.validate('[1080,{"localhost",8080}]') + + self.assertEqual([('0.0.0.0', 1080), ('localhost', 8080)], v) + + if __name__ == '__main__': unittest.main()