From adfbeb2ec724a97203c8b2120d9874af0cbb7161 Mon Sep 17 00:00:00 2001 From: Billy Olsen Date: Wed, 12 Nov 2014 16:42:57 -0700 Subject: [PATCH] Few changes: - Add support for shared secret for ceilometer's signed messages - Refactor MongoDBContext to be a bit more clean - Specify replicaSet and readPreference parameters in the mongodb url --- hooks/ceilometer_contexts.py | 77 ++++++++++++------------------ hooks/ceilometer_hooks.py | 29 +++++++++-- hooks/ceilometer_utils.py | 28 +++++++++++ templates/icehouse/ceilometer.conf | 2 +- 4 files changed, 85 insertions(+), 51 deletions(-) diff --git a/hooks/ceilometer_contexts.py b/hooks/ceilometer_contexts.py index 20f7178..c8d8bca 100644 --- a/hooks/ceilometer_contexts.py +++ b/hooks/ceilometer_contexts.py @@ -1,5 +1,4 @@ import os -import uuid from charmhelpers.core.hookenv import ( relation_ids, relation_get, @@ -32,66 +31,52 @@ class MongoDBContext(OSContextGenerator): interfaces = ['mongodb'] def __call__(self): - hostnames = [] - port = None + mongo_servers = [] replset = None - # TODO(wolsen) add a check in which will only execute this on a - # supported level of ceilometer code, which would be a specific version - # of the code, not just icehouse. - support = os_release('ceilometer-api') >= 'icehouse' + use_replset = os_release('ceilometer-api') >= 'icehouse' for relid in relation_ids('shared-db'): - for unit in related_units(relid): - replset = relation_get('replset', unit, relid) + rel_units = related_units(relid) + use_replset = use_replset and (len(rel_units) > 1) + + for unit in rel_units: host = relation_get('hostname', unit, relid) - if port is None: - port = relation_get('port', unit, relid) + port = relation_get('port', unit, relid) - # If replica sets aren't used or aren't supported by ceilometer - # then stop looping if there is enough data - if not support or not replset: - if context_complete({'db_host': host, 'db_port': port}): - hostnames.append(host) - break + if not use_replset: + conf = { + "db_host": host, + "db_port": port, + "db_name": CEILOMETER_DB + } + + if context_complete(conf): + return conf else: - hostnames.append('{}:{}'.format(host, port)) - - # If there aren't any hosts, then there's no real configuration - # to fill in here, so bail early - if port is None or port == '': - return {} + if replset is None: + replset = relation_get('replset', unit, relid) + + mongo_servers.append('{}:{}'.format(host, port)) - conf = { - 'db_host': ','.join(hostnames), - 'db_port': port, - 'db_name': CEILOMETER_DB - } + if mongo_servers: + conf = { + 'db_mongo_servers': ','.join(mongo_servers), + 'db_name': CEILOMETER_DB, + 'db_replset': replset + } + return conf - if replset: - conf['db_replset'] = replset + return {} - return conf - - -SHARED_SECRET = "/etc/ceilometer/secret.txt" - - -def get_shared_secret(): - secret = None - if not os.path.exists(SHARED_SECRET): - secret = str(uuid.uuid4()) - with open(SHARED_SECRET, 'w') as secret_file: - secret_file.write(secret) - else: - with open(SHARED_SECRET, 'r') as secret_file: - secret = secret_file.read().strip() - return secret CEILOMETER_PORT = 8777 class CeilometerContext(OSContextGenerator): def __call__(self): + # Lazy-import to avoid a circular dependency in the imports + from ceilometer_utils import get_shared_secret + ctxt = { 'port': CEILOMETER_PORT, 'metering_secret': get_shared_secret() diff --git a/hooks/ceilometer_hooks.py b/hooks/ceilometer_hooks.py index 34d240b..dfbe522 100755 --- a/hooks/ceilometer_hooks.py +++ b/hooks/ceilometer_hooks.py @@ -31,7 +31,9 @@ from ceilometer_utils import ( register_configs, restart_map, get_ceilometer_context, - do_openstack_upgrade + get_shared_secret, + do_openstack_upgrade, + set_shared_secret ) from ceilometer_contexts import CEILOMETER_PORT from charmhelpers.contrib.openstack.ip import ( @@ -43,7 +45,8 @@ from charmhelpers.contrib.network.ip import ( get_netmask_for_address ) from charmhelpers.contrib.hahelpers.cluster import ( - get_hacluster_config + get_hacluster_config, + is_elected_leader ) hooks = Hooks() @@ -109,11 +112,29 @@ def upgrade_charm(): any_changed() -@hooks.hook('cluster-relation-joined', - 'cluster-relation-changed', +@hooks.hook('cluster-relation-joined') +@restart_on_change(restart_map(), stopstart=True) +def cluster_joined(): + vip = get_hacluster_config()['vip'].split()[0] + resource = 'res_ceilometer_{}_vip'.format(get_iface_for_address(vip)) + + # If this node is the elected leader then share our secret with other nodes + if is_elected_leader(resource): + relation_set(shared_secret=get_shared_secret()) + + CONFIGS.write_all() + + +@hooks.hook('cluster-relation-changed', 'cluster-relation-departed') @restart_on_change(restart_map(), stopstart=True) def cluster_changed(): + shared_secret = relation_get('shared_secret') + if shared_secret is None or shared_secret.strip() == '': + log('waiting for shared secret to be provided by leader') + elif not shared_secret == get_shared_secret(): + set_shared_secret(shared_secret) + CONFIGS.write_all() diff --git a/hooks/ceilometer_utils.py b/hooks/ceilometer_utils.py index bcbd366..5aaf066 100644 --- a/hooks/ceilometer_utils.py +++ b/hooks/ceilometer_utils.py @@ -1,4 +1,5 @@ import os +import uuid from collections import OrderedDict @@ -84,6 +85,8 @@ CONFIG_FILES = OrderedDict([ TEMPLATES = 'templates' +SHARED_SECRET = "/etc/ceilometer/secret.txt" + def register_configs(): """ @@ -171,3 +174,28 @@ def get_packages(): >= 'icehouse'): packages = packages + ICEHOUSE_PACKAGES return packages + + +def get_shared_secret(): + """ + Returns the current shared secret for the ceilometer node. If the shared + secret does not exist, this method will generate one. + """ + secret = None + if not os.path.exists(SHARED_SECRET): + secret = str(uuid.uuid4()) + set_shared_secret(secret) + else: + with open(SHARED_SECRET, 'r') as secret_file: + secret = secret_file.read().strip() + return secret + + +def set_shared_secret(secret): + """ + Sets the shared secret which is used to sign ceilometer messages. + + :param secret: the secret to set + """ + with open(SHARED_SECRET, 'w') as secret_file: + secret_file.write(secret) \ No newline at end of file diff --git a/templates/icehouse/ceilometer.conf b/templates/icehouse/ceilometer.conf index 299d20e..07a2b53 100644 --- a/templates/icehouse/ceilometer.conf +++ b/templates/icehouse/ceilometer.conf @@ -18,7 +18,7 @@ os_username = {{ admin_user }} os_password = {{ admin_password }} [database] {% if db_replset: -%} -connection = mongodb://{{ db_host }}/{{ db_name }}?readPreference=primaryPreferred +connection = mongodb://{{ db_mongo_servers }}/{{ db_name }}?readPreference=primaryPreferred&replicaSet={{ db_replset }} mongodb_replica_set = {{ db_replset }} {% else -%} connection = mongodb://{{ db_host }}:{{ db_port }}/{{ db_name }}