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
This commit is contained in:
Billy Olsen
2014-11-12 16:42:57 -07:00
parent b9178d2f15
commit adfbeb2ec7
4 changed files with 85 additions and 51 deletions

View File

@@ -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()

View File

@@ -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()

View File

@@ -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)

View File

@@ -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 }}