Switch to using openstack context templating
This commit is contained in:
parent
ff58b0ebed
commit
3d154836aa
|
@ -1,6 +1,7 @@
|
||||||
branch: lp:~openstack-charmers/charm-helpers/to_upstream
|
branch: lp:charm-helpers
|
||||||
destination: hooks/charmhelpers
|
destination: hooks/charmhelpers
|
||||||
include:
|
include:
|
||||||
- core
|
- core
|
||||||
- fetch
|
- fetch
|
||||||
- contrib.openstack
|
- contrib.openstack
|
||||||
|
- contrib.hahelpers
|
||||||
|
|
|
@ -26,3 +26,11 @@ options:
|
||||||
default: RegionOne
|
default: RegionOne
|
||||||
type: string
|
type: string
|
||||||
description: OpenStack Region
|
description: OpenStack Region
|
||||||
|
rabbit-user:
|
||||||
|
default: ceilometer
|
||||||
|
type: string
|
||||||
|
description: Username to request access on rabbitmq-server.
|
||||||
|
rabbit-vhost:
|
||||||
|
default: openstack
|
||||||
|
type: string
|
||||||
|
description: RabbitMQ virtual host to request access on rabbitmq-server.
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import os
|
||||||
|
import uuid
|
||||||
|
from charmhelpers.core.hookenv import (
|
||||||
|
relation_ids,
|
||||||
|
relation_get,
|
||||||
|
related_units,
|
||||||
|
config
|
||||||
|
)
|
||||||
|
|
||||||
|
from charmhelpers.contrib.openstack.context import (
|
||||||
|
OSContextGenerator,
|
||||||
|
context_complete
|
||||||
|
)
|
||||||
|
|
||||||
|
CEILOMETER_DB = 'ceilometer'
|
||||||
|
|
||||||
|
|
||||||
|
class LoggingConfigContext(OSContextGenerator):
|
||||||
|
def __call__(self):
|
||||||
|
return {'debug': config('debug'), 'verbose': config('verbose')}
|
||||||
|
|
||||||
|
|
||||||
|
class MongoDBContext(OSContextGenerator):
|
||||||
|
interfaces = ['mongodb']
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
for relid in relation_ids('shared-db'):
|
||||||
|
for unit in related_units(relid):
|
||||||
|
conf = {
|
||||||
|
"db_host": relation_get('hostname', unit, relid),
|
||||||
|
"db_port": relation_get('port', unit, relid),
|
||||||
|
"db_name": CEILOMETER_DB
|
||||||
|
}
|
||||||
|
if context_complete(conf):
|
||||||
|
return conf
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
ctxt = {
|
||||||
|
'port': CEILOMETER_PORT,
|
||||||
|
'metering_secret': get_shared_secret()
|
||||||
|
}
|
||||||
|
return ctxt
|
|
@ -1,8 +1,6 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
#import lib.utils as utils
|
|
||||||
from charmhelpers.fetch import (
|
from charmhelpers.fetch import (
|
||||||
apt_install, filter_installed_packages,
|
apt_install, filter_installed_packages,
|
||||||
apt_update
|
apt_update
|
||||||
|
@ -10,35 +8,31 @@ from charmhelpers.fetch import (
|
||||||
from charmhelpers.core.hookenv import (
|
from charmhelpers.core.hookenv import (
|
||||||
open_port,
|
open_port,
|
||||||
relation_set,
|
relation_set,
|
||||||
relation_get,
|
|
||||||
relation_ids,
|
relation_ids,
|
||||||
related_units,
|
|
||||||
config,
|
config,
|
||||||
unit_get,
|
unit_get,
|
||||||
Hooks, UnregisteredHookError,
|
Hooks, UnregisteredHookError,
|
||||||
log
|
log
|
||||||
)
|
)
|
||||||
from charmhelpers.core.host import (
|
from charmhelpers.core.host import (
|
||||||
service_restart,
|
restart_on_change
|
||||||
)
|
)
|
||||||
from charmhelpers.contrib.openstack.utils import (
|
from charmhelpers.contrib.openstack.utils import (
|
||||||
configure_installation_source
|
configure_installation_source
|
||||||
)
|
)
|
||||||
from ceilometer_utils import (
|
from ceilometer_utils import (
|
||||||
CEILOMETER_PACKAGES,
|
CEILOMETER_PACKAGES,
|
||||||
CEILOMETER_PORT,
|
|
||||||
RABBIT_USER,
|
|
||||||
RABBIT_VHOST,
|
|
||||||
CEILOMETER_DB,
|
CEILOMETER_DB,
|
||||||
CEILOMETER_SERVICES,
|
|
||||||
CEILOMETER_SERVICE,
|
CEILOMETER_SERVICE,
|
||||||
CEILOMETER_ROLE,
|
CEILOMETER_ROLE,
|
||||||
CEILOMETER_CONF,
|
register_configs,
|
||||||
get_shared_secret,
|
restart_map,
|
||||||
render_template
|
get_ceilometer_context
|
||||||
)
|
)
|
||||||
|
from ceilometer_contexts import CEILOMETER_PORT
|
||||||
|
|
||||||
hooks = Hooks()
|
hooks = Hooks()
|
||||||
|
CONFIGS = register_configs()
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook()
|
@hooks.hook()
|
||||||
|
@ -52,8 +46,8 @@ def install():
|
||||||
|
|
||||||
@hooks.hook("amqp-relation-joined")
|
@hooks.hook("amqp-relation-joined")
|
||||||
def amqp_joined():
|
def amqp_joined():
|
||||||
relation_set(username=RABBIT_USER,
|
relation_set(username=config('rabbit-user'),
|
||||||
vhost=RABBIT_VHOST)
|
vhost=config('rabbit-vhost'))
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook("shared-db-relation-joined")
|
@hooks.hook("shared-db-relation-joined")
|
||||||
|
@ -64,18 +58,17 @@ def db_joined():
|
||||||
@hooks.hook("amqp-relation-changed",
|
@hooks.hook("amqp-relation-changed",
|
||||||
"shared-db-relation-changed",
|
"shared-db-relation-changed",
|
||||||
"identity-service-relation-changed")
|
"identity-service-relation-changed")
|
||||||
def all_changed():
|
@restart_on_change(restart_map())
|
||||||
if render_ceilometer_conf():
|
def any_changed():
|
||||||
for svc in CEILOMETER_SERVICES:
|
CONFIGS.write_all()
|
||||||
service_restart(svc)
|
ceilometer_joined()
|
||||||
ceilometer_joined()
|
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook('config-changed',
|
@hooks.hook('config-changed',
|
||||||
'upgrade-charm')
|
'upgrade-charm')
|
||||||
def config_changed():
|
def config_changed():
|
||||||
install()
|
install()
|
||||||
all_changed()
|
any_changed()
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook("identity-service-relation-joined")
|
@hooks.hook("identity-service-relation-joined")
|
||||||
|
@ -83,107 +76,18 @@ def keystone_joined():
|
||||||
url = "http://{}:{}".format(unit_get("private-address"),
|
url = "http://{}:{}".format(unit_get("private-address"),
|
||||||
CEILOMETER_PORT)
|
CEILOMETER_PORT)
|
||||||
region = config("region")
|
region = config("region")
|
||||||
|
|
||||||
relation_set(service=CEILOMETER_SERVICE,
|
relation_set(service=CEILOMETER_SERVICE,
|
||||||
public_url=url, admin_url=url, internal_url=url,
|
public_url=url, admin_url=url, internal_url=url,
|
||||||
requested_roles=CEILOMETER_ROLE,
|
requested_roles=CEILOMETER_ROLE,
|
||||||
region=region)
|
region=region)
|
||||||
|
|
||||||
|
|
||||||
def get_rabbit_conf():
|
|
||||||
for relid in relation_ids('amqp'):
|
|
||||||
for unit in related_units(relid):
|
|
||||||
conf = {
|
|
||||||
"rabbit_host": relation_get('private-address',
|
|
||||||
unit, relid),
|
|
||||||
"rabbit_virtual_host": RABBIT_VHOST,
|
|
||||||
"rabbit_userid": RABBIT_USER,
|
|
||||||
"rabbit_password": relation_get('password',
|
|
||||||
unit, relid)
|
|
||||||
}
|
|
||||||
if relation_get('clustered',
|
|
||||||
unit, relid):
|
|
||||||
conf["rabbit_host"] = relation_get('vip', unit, relid)
|
|
||||||
if None not in conf.itervalues():
|
|
||||||
return conf
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_db_conf():
|
|
||||||
for relid in relation_ids('shared-db'):
|
|
||||||
for unit in related_units(relid):
|
|
||||||
conf = {
|
|
||||||
"db_host": relation_get('hostname', unit, relid),
|
|
||||||
"db_port": relation_get('port', unit, relid),
|
|
||||||
"db_name": CEILOMETER_DB
|
|
||||||
}
|
|
||||||
if None not in conf.itervalues():
|
|
||||||
return conf
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_keystone_conf():
|
|
||||||
for relid in relation_ids('identity-service'):
|
|
||||||
for unit in related_units(relid):
|
|
||||||
keystone_username = relation_get('service_username',
|
|
||||||
unit, relid)
|
|
||||||
keystone_port = relation_get('service_port',
|
|
||||||
unit, relid)
|
|
||||||
keystone_host = relation_get('service_host',
|
|
||||||
unit, relid)
|
|
||||||
keystone_password = relation_get('service_password',
|
|
||||||
unit, relid)
|
|
||||||
keystone_tenant = relation_get('service_tenant',
|
|
||||||
unit, relid)
|
|
||||||
|
|
||||||
conf = {
|
|
||||||
"keystone_os_username": keystone_username,
|
|
||||||
"keystone_os_password": keystone_password,
|
|
||||||
"keystone_os_tenant": keystone_tenant,
|
|
||||||
"keystone_host": keystone_host,
|
|
||||||
"keystone_port": keystone_port
|
|
||||||
}
|
|
||||||
if None not in conf.itervalues():
|
|
||||||
return conf
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def render_ceilometer_conf():
|
|
||||||
context = get_rabbit_conf()
|
|
||||||
contextdb = get_db_conf()
|
|
||||||
contextkeystone = get_keystone_conf()
|
|
||||||
|
|
||||||
if (context and contextdb and contextkeystone and
|
|
||||||
os.path.exists(CEILOMETER_CONF)):
|
|
||||||
# merge contexts
|
|
||||||
context.update(contextkeystone)
|
|
||||||
context.update(contextdb)
|
|
||||||
context['metering_secret'] = get_shared_secret()
|
|
||||||
context['service_port'] = CEILOMETER_PORT
|
|
||||||
context['debug'] = config('debug')
|
|
||||||
context['verbose'] = config('verbose')
|
|
||||||
|
|
||||||
with open(CEILOMETER_CONF, "w") as conf:
|
|
||||||
conf.write(render_template(os.path.basename(CEILOMETER_CONF),
|
|
||||||
context))
|
|
||||||
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook("ceilometer-service-relation-joined")
|
@hooks.hook("ceilometer-service-relation-joined")
|
||||||
def ceilometer_joined():
|
def ceilometer_joined():
|
||||||
# set all relationships for ceilometer service
|
# Pass local context data onto related agent services
|
||||||
context = get_rabbit_conf()
|
context = get_ceilometer_context()
|
||||||
contextdb = get_db_conf()
|
for relid in relation_ids('ceilometer-service'):
|
||||||
contextkeystone = get_keystone_conf()
|
relation_set(relid, context)
|
||||||
if context and contextdb and contextkeystone:
|
|
||||||
context.update(contextdb)
|
|
||||||
context.update(contextkeystone)
|
|
||||||
context["metering_secret"] = get_shared_secret()
|
|
||||||
# set all that info into ceilometer-service relationship
|
|
||||||
for relid in relation_ids('ceilometer-service'):
|
|
||||||
relation_set(relid, context)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,61 +1,97 @@
|
||||||
import os
|
from charmhelpers.contrib.openstack import (
|
||||||
import uuid
|
templating,
|
||||||
from charmhelpers.fetch import apt_install as install
|
context,
|
||||||
|
)
|
||||||
|
from ceilometer_contexts import (
|
||||||
|
LoggingConfigContext,
|
||||||
|
MongoDBContext,
|
||||||
|
CeilometerContext
|
||||||
|
)
|
||||||
|
from charmhelpers.contrib.openstack.utils import (
|
||||||
|
get_os_codename_package
|
||||||
|
)
|
||||||
|
|
||||||
RABBIT_USER = "ceilometer"
|
|
||||||
RABBIT_VHOST = "openstack"
|
|
||||||
CEILOMETER_CONF = "/etc/ceilometer/ceilometer.conf"
|
CEILOMETER_CONF = "/etc/ceilometer/ceilometer.conf"
|
||||||
|
|
||||||
SHARED_SECRET = "/etc/ceilometer/secret.txt"
|
|
||||||
CEILOMETER_SERVICES = [
|
CEILOMETER_SERVICES = [
|
||||||
'ceilometer-agent-central', 'ceilometer-collector',
|
'ceilometer-agent-central',
|
||||||
|
'ceilometer-collector',
|
||||||
'ceilometer-api'
|
'ceilometer-api'
|
||||||
]
|
]
|
||||||
|
|
||||||
CEILOMETER_DB = "ceilometer"
|
CEILOMETER_DB = "ceilometer"
|
||||||
CEILOMETER_SERVICE = "ceilometer"
|
CEILOMETER_SERVICE = "ceilometer"
|
||||||
CEILOMETER_COMPUTE_SERVICES = ['ceilometer-agent-compute']
|
|
||||||
CEILOMETER_PACKAGES = [
|
CEILOMETER_PACKAGES = [
|
||||||
'python-ceilometer', 'ceilometer-common',
|
'ceilometer-agent-central',
|
||||||
'ceilometer-agent-central', 'ceilometer-collector', 'ceilometer-api'
|
'ceilometer-collector',
|
||||||
|
'ceilometer-api'
|
||||||
]
|
]
|
||||||
CEILOMETER_AGENT_PACKAGES = [
|
|
||||||
'python-ceilometer', 'ceilometer-common',
|
|
||||||
'ceilometer-agent-compute'
|
|
||||||
]
|
|
||||||
CEILOMETER_PORT = 8777
|
|
||||||
CEILOMETER_ROLE = "ResellerAdmin"
|
CEILOMETER_ROLE = "ResellerAdmin"
|
||||||
|
|
||||||
NOVA_CONF = "/etc/nova/nova.conf"
|
#NOVA_CONF = "/etc/nova/nova.conf"
|
||||||
NOVA_SETTINGS = [
|
#NOVA_SETTINGS = [
|
||||||
('DEFAULT', 'instance_usage_audit', 'True'),
|
# ('DEFAULT', 'instance_usage_audit', 'True'),
|
||||||
('DEFAULT', 'instance_usage_audit_period', 'hour'),
|
# ('DEFAULT', 'instance_usage_audit_period', 'hour'),
|
||||||
('DEFAULT', 'notification_driver', 'ceilometer.compute.nova_notifier')
|
# ('DEFAULT', 'notification_driver', 'ceilometer.compute.nova_notifier')
|
||||||
]
|
#]
|
||||||
|
|
||||||
|
CONFIG_FILES = {
|
||||||
|
CEILOMETER_CONF: {
|
||||||
|
'hook_contexts': [context.IdentityServiceContext(),
|
||||||
|
context.AMQPContext(),
|
||||||
|
LoggingConfigContext(),
|
||||||
|
MongoDBContext(),
|
||||||
|
CeilometerContext()],
|
||||||
|
'services': CEILOMETER_SERVICES
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEMPLATES = 'templates'
|
||||||
|
|
||||||
|
|
||||||
def get_shared_secret():
|
def register_configs():
|
||||||
secret = None
|
"""
|
||||||
if not os.path.exists(SHARED_SECRET):
|
Register config files with their respective contexts.
|
||||||
secret = str(uuid.uuid4())
|
Regstration of some configs may not be required depending on
|
||||||
with open(SHARED_SECRET, 'w') as secret_file:
|
existing of certain relations.
|
||||||
secret_file.write(secret)
|
"""
|
||||||
else:
|
# if called without anything installed (eg during install hook)
|
||||||
with open(SHARED_SECRET, 'r') as secret_file:
|
# just default to earliest supported release. configs dont get touched
|
||||||
secret = secret_file.read().strip()
|
# till post-install, anyway.
|
||||||
return secret
|
release = get_os_codename_package('ceilometer-common', fatal=False) \
|
||||||
|
or 'grizzly'
|
||||||
|
configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
|
||||||
|
openstack_release=release)
|
||||||
|
|
||||||
|
for conf in CONFIG_FILES:
|
||||||
|
configs.register(conf, CONFIG_FILES[conf]['hook_contexts'])
|
||||||
|
|
||||||
|
return configs
|
||||||
|
|
||||||
|
|
||||||
TEMPLATES_DIR = 'templates'
|
def restart_map():
|
||||||
|
'''
|
||||||
|
Determine the correct resource map to be passed to
|
||||||
|
charmhelpers.core.restart_on_change() based on the services configured.
|
||||||
|
|
||||||
try:
|
:returns: dict: A dictionary mapping config file to lists of services
|
||||||
import jinja2
|
that should be restarted when file changes.
|
||||||
except ImportError:
|
'''
|
||||||
install(['python-jinja2'])
|
_map = {}
|
||||||
import jinja2
|
for f, ctxt in CONFIG_FILES.iteritems():
|
||||||
|
svcs = []
|
||||||
|
for svc in ctxt['services']:
|
||||||
|
svcs.append(svc)
|
||||||
|
if svcs:
|
||||||
|
_map[f] = svcs
|
||||||
|
return _map
|
||||||
|
|
||||||
|
|
||||||
def render_template(template_name, context, template_dir=TEMPLATES_DIR):
|
def get_ceilometer_context():
|
||||||
templates = \
|
''' Retrieve a map of all current relation data for agent configuration '''
|
||||||
jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir))
|
ctxt = {}
|
||||||
template = templates.get_template(template_name)
|
for context in CONFIG_FILES[CEILOMETER_CONF]['hook_contexts']:
|
||||||
return template.render(context)
|
ctxt.update(context())
|
||||||
|
return ctxt
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
#
|
||||||
|
# Copyright 2012 Canonical Ltd.
|
||||||
|
#
|
||||||
|
# This file is sourced from lp:openstack-charm-helpers
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# James Page <james.page@ubuntu.com>
|
||||||
|
# Adam Gandelman <adamg@ubuntu.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from charmhelpers.core.hookenv import (
|
||||||
|
config as config_get,
|
||||||
|
relation_get,
|
||||||
|
relation_ids,
|
||||||
|
related_units as relation_list,
|
||||||
|
log,
|
||||||
|
INFO,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_cert():
|
||||||
|
cert = config_get('ssl_cert')
|
||||||
|
key = config_get('ssl_key')
|
||||||
|
if not (cert and key):
|
||||||
|
log("Inspecting identity-service relations for SSL certificate.",
|
||||||
|
level=INFO)
|
||||||
|
cert = key = None
|
||||||
|
for r_id in relation_ids('identity-service'):
|
||||||
|
for unit in relation_list(r_id):
|
||||||
|
if not cert:
|
||||||
|
cert = relation_get('ssl_cert',
|
||||||
|
rid=r_id, unit=unit)
|
||||||
|
if not key:
|
||||||
|
key = relation_get('ssl_key',
|
||||||
|
rid=r_id, unit=unit)
|
||||||
|
return (cert, key)
|
||||||
|
|
||||||
|
|
||||||
|
def get_ca_cert():
|
||||||
|
ca_cert = None
|
||||||
|
log("Inspecting identity-service relations for CA SSL certificate.",
|
||||||
|
level=INFO)
|
||||||
|
for r_id in relation_ids('identity-service'):
|
||||||
|
for unit in relation_list(r_id):
|
||||||
|
if not ca_cert:
|
||||||
|
ca_cert = relation_get('ca_cert',
|
||||||
|
rid=r_id, unit=unit)
|
||||||
|
return ca_cert
|
||||||
|
|
||||||
|
|
||||||
|
def install_ca_cert(ca_cert):
|
||||||
|
if ca_cert:
|
||||||
|
with open('/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt',
|
||||||
|
'w') as crt:
|
||||||
|
crt.write(ca_cert)
|
||||||
|
subprocess.check_call(['update-ca-certificates', '--fresh'])
|
|
@ -0,0 +1,183 @@
|
||||||
|
#
|
||||||
|
# Copyright 2012 Canonical Ltd.
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# James Page <james.page@ubuntu.com>
|
||||||
|
# Adam Gandelman <adamg@ubuntu.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
from socket import gethostname as get_unit_hostname
|
||||||
|
|
||||||
|
from charmhelpers.core.hookenv import (
|
||||||
|
log,
|
||||||
|
relation_ids,
|
||||||
|
related_units as relation_list,
|
||||||
|
relation_get,
|
||||||
|
config as config_get,
|
||||||
|
INFO,
|
||||||
|
ERROR,
|
||||||
|
unit_get,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class HAIncompleteConfig(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def is_clustered():
|
||||||
|
for r_id in (relation_ids('ha') or []):
|
||||||
|
for unit in (relation_list(r_id) or []):
|
||||||
|
clustered = relation_get('clustered',
|
||||||
|
rid=r_id,
|
||||||
|
unit=unit)
|
||||||
|
if clustered:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_leader(resource):
|
||||||
|
cmd = [
|
||||||
|
"crm", "resource",
|
||||||
|
"show", resource
|
||||||
|
]
|
||||||
|
try:
|
||||||
|
status = subprocess.check_output(cmd)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if get_unit_hostname() in status:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def peer_units():
|
||||||
|
peers = []
|
||||||
|
for r_id in (relation_ids('cluster') or []):
|
||||||
|
for unit in (relation_list(r_id) or []):
|
||||||
|
peers.append(unit)
|
||||||
|
return peers
|
||||||
|
|
||||||
|
|
||||||
|
def oldest_peer(peers):
|
||||||
|
local_unit_no = int(os.getenv('JUJU_UNIT_NAME').split('/')[1])
|
||||||
|
for peer in peers:
|
||||||
|
remote_unit_no = int(peer.split('/')[1])
|
||||||
|
if remote_unit_no < local_unit_no:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def eligible_leader(resource):
|
||||||
|
if is_clustered():
|
||||||
|
if not is_leader(resource):
|
||||||
|
log('Deferring action to CRM leader.', level=INFO)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
peers = peer_units()
|
||||||
|
if peers and not oldest_peer(peers):
|
||||||
|
log('Deferring action to oldest service unit.', level=INFO)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def https():
|
||||||
|
'''
|
||||||
|
Determines whether enough data has been provided in configuration
|
||||||
|
or relation data to configure HTTPS
|
||||||
|
.
|
||||||
|
returns: boolean
|
||||||
|
'''
|
||||||
|
if config_get('use-https') == "yes":
|
||||||
|
return True
|
||||||
|
if config_get('ssl_cert') and config_get('ssl_key'):
|
||||||
|
return True
|
||||||
|
for r_id in relation_ids('identity-service'):
|
||||||
|
for unit in relation_list(r_id):
|
||||||
|
rel_state = [
|
||||||
|
relation_get('https_keystone', rid=r_id, unit=unit),
|
||||||
|
relation_get('ssl_cert', rid=r_id, unit=unit),
|
||||||
|
relation_get('ssl_key', rid=r_id, unit=unit),
|
||||||
|
relation_get('ca_cert', rid=r_id, unit=unit),
|
||||||
|
]
|
||||||
|
# NOTE: works around (LP: #1203241)
|
||||||
|
if (None not in rel_state) and ('' not in rel_state):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def determine_api_port(public_port):
|
||||||
|
'''
|
||||||
|
Determine correct API server listening port based on
|
||||||
|
existence of HTTPS reverse proxy and/or haproxy.
|
||||||
|
|
||||||
|
public_port: int: standard public port for given service
|
||||||
|
|
||||||
|
returns: int: the correct listening port for the API service
|
||||||
|
'''
|
||||||
|
i = 0
|
||||||
|
if len(peer_units()) > 0 or is_clustered():
|
||||||
|
i += 1
|
||||||
|
if https():
|
||||||
|
i += 1
|
||||||
|
return public_port - (i * 10)
|
||||||
|
|
||||||
|
|
||||||
|
def determine_haproxy_port(public_port):
|
||||||
|
'''
|
||||||
|
Description: Determine correct proxy listening port based on public IP +
|
||||||
|
existence of HTTPS reverse proxy.
|
||||||
|
|
||||||
|
public_port: int: standard public port for given service
|
||||||
|
|
||||||
|
returns: int: the correct listening port for the HAProxy service
|
||||||
|
'''
|
||||||
|
i = 0
|
||||||
|
if https():
|
||||||
|
i += 1
|
||||||
|
return public_port - (i * 10)
|
||||||
|
|
||||||
|
|
||||||
|
def get_hacluster_config():
|
||||||
|
'''
|
||||||
|
Obtains all relevant configuration from charm configuration required
|
||||||
|
for initiating a relation to hacluster:
|
||||||
|
|
||||||
|
ha-bindiface, ha-mcastport, vip, vip_iface, vip_cidr
|
||||||
|
|
||||||
|
returns: dict: A dict containing settings keyed by setting name.
|
||||||
|
raises: HAIncompleteConfig if settings are missing.
|
||||||
|
'''
|
||||||
|
settings = ['ha-bindiface', 'ha-mcastport', 'vip', 'vip_iface', 'vip_cidr']
|
||||||
|
conf = {}
|
||||||
|
for setting in settings:
|
||||||
|
conf[setting] = config_get(setting)
|
||||||
|
missing = []
|
||||||
|
[missing.append(s) for s, v in conf.iteritems() if v is None]
|
||||||
|
if missing:
|
||||||
|
log('Insufficient config data to configure hacluster.', level=ERROR)
|
||||||
|
raise HAIncompleteConfig
|
||||||
|
return conf
|
||||||
|
|
||||||
|
|
||||||
|
def canonical_url(configs, vip_setting='vip'):
|
||||||
|
'''
|
||||||
|
Returns the correct HTTP URL to this host given the state of HTTPS
|
||||||
|
configuration and hacluster.
|
||||||
|
|
||||||
|
:configs : OSTemplateRenderer: A config tempating object to inspect for
|
||||||
|
a complete https context.
|
||||||
|
:vip_setting: str: Setting in charm config that specifies
|
||||||
|
VIP address.
|
||||||
|
'''
|
||||||
|
scheme = 'http'
|
||||||
|
if 'https' in configs.complete_contexts():
|
||||||
|
scheme = 'https'
|
||||||
|
if is_clustered():
|
||||||
|
addr = config_get(vip_setting)
|
||||||
|
else:
|
||||||
|
addr = unit_get('private-address')
|
||||||
|
return '%s://%s' % (scheme, addr)
|
|
@ -1,3 +1,4 @@
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
|
@ -21,6 +22,7 @@ from charmhelpers.core.hookenv import (
|
||||||
related_units,
|
related_units,
|
||||||
unit_get,
|
unit_get,
|
||||||
unit_private_ip,
|
unit_private_ip,
|
||||||
|
ERROR,
|
||||||
WARNING,
|
WARNING,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -431,3 +433,90 @@ class OSConfigFlagContext(OSContextGenerator):
|
||||||
flags[k.strip()] = v
|
flags[k.strip()] = v
|
||||||
ctxt = {'user_config_flags': flags}
|
ctxt = {'user_config_flags': flags}
|
||||||
return ctxt
|
return ctxt
|
||||||
|
|
||||||
|
|
||||||
|
class SubordinateConfigContext(OSContextGenerator):
|
||||||
|
"""
|
||||||
|
Responsible for inspecting relations to subordinates that
|
||||||
|
may be exporting required config via a json blob.
|
||||||
|
|
||||||
|
The subordinate interface allows subordinates to export their
|
||||||
|
configuration requirements to the principle for multiple config
|
||||||
|
files and multiple serivces. Ie, a subordinate that has interfaces
|
||||||
|
to both glance and nova may export to following yaml blob as json:
|
||||||
|
|
||||||
|
glance:
|
||||||
|
/etc/glance/glance-api.conf:
|
||||||
|
sections:
|
||||||
|
DEFAULT:
|
||||||
|
- [key1, value1]
|
||||||
|
/etc/glance/glance-registry.conf:
|
||||||
|
MYSECTION:
|
||||||
|
- [key2, value2]
|
||||||
|
nova:
|
||||||
|
/etc/nova/nova.conf:
|
||||||
|
sections:
|
||||||
|
DEFAULT:
|
||||||
|
- [key3, value3]
|
||||||
|
|
||||||
|
|
||||||
|
It is then up to the principle charms to subscribe this context to
|
||||||
|
the service+config file it is interestd in. Configuration data will
|
||||||
|
be available in the template context, in glance's case, as:
|
||||||
|
ctxt = {
|
||||||
|
... other context ...
|
||||||
|
'subordinate_config': {
|
||||||
|
'DEFAULT': {
|
||||||
|
'key1': 'value1',
|
||||||
|
},
|
||||||
|
'MYSECTION': {
|
||||||
|
'key2': 'value2',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, service, config_file, interface):
|
||||||
|
"""
|
||||||
|
:param service : Service name key to query in any subordinate
|
||||||
|
data found
|
||||||
|
:param config_file : Service's config file to query sections
|
||||||
|
:param interface : Subordinate interface to inspect
|
||||||
|
"""
|
||||||
|
self.service = service
|
||||||
|
self.config_file = config_file
|
||||||
|
self.interface = interface
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
ctxt = {}
|
||||||
|
for rid in relation_ids(self.interface):
|
||||||
|
for unit in related_units(rid):
|
||||||
|
sub_config = relation_get('subordinate_configuration',
|
||||||
|
rid=rid, unit=unit)
|
||||||
|
if sub_config and sub_config != '':
|
||||||
|
try:
|
||||||
|
sub_config = json.loads(sub_config)
|
||||||
|
except:
|
||||||
|
log('Could not parse JSON from subordinate_config '
|
||||||
|
'setting from %s' % rid, level=ERROR)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if self.service not in sub_config:
|
||||||
|
log('Found subordinate_config on %s but it contained'
|
||||||
|
'nothing for %s service' % (rid, self.service))
|
||||||
|
continue
|
||||||
|
|
||||||
|
sub_config = sub_config[self.service]
|
||||||
|
if self.config_file not in sub_config:
|
||||||
|
log('Found subordinate_config on %s but it contained'
|
||||||
|
'nothing for %s' % (rid, self.config_file))
|
||||||
|
continue
|
||||||
|
|
||||||
|
sub_config = sub_config[self.config_file]
|
||||||
|
for k, v in sub_config.iteritems():
|
||||||
|
ctxt[k] = v
|
||||||
|
|
||||||
|
if not ctxt:
|
||||||
|
ctxt['sections'] = {}
|
||||||
|
|
||||||
|
return ctxt
|
||||||
|
|
|
@ -85,7 +85,7 @@ def neutron_plugin_attribute(plugin, attr, net_manager=None):
|
||||||
_plugin = plugins[plugin]
|
_plugin = plugins[plugin]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
log('Unrecognised plugin for %s: %s' % (manager, plugin), level=ERROR)
|
log('Unrecognised plugin for %s: %s' % (manager, plugin), level=ERROR)
|
||||||
raise
|
raise Exception
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return _plugin[attr]
|
return _plugin[attr]
|
||||||
|
@ -108,7 +108,7 @@ def network_manager():
|
||||||
if release in ['essex']:
|
if release in ['essex']:
|
||||||
# E does not support neutron
|
# E does not support neutron
|
||||||
log('Neutron networking not supported in Essex.', level=ERROR)
|
log('Neutron networking not supported in Essex.', level=ERROR)
|
||||||
raise
|
raise Exception
|
||||||
elif release in ['folsom', 'grizzly']:
|
elif release in ['folsom', 'grizzly']:
|
||||||
# neutron is named quantum in F and G
|
# neutron is named quantum in F and G
|
||||||
return 'quantum'
|
return 'quantum'
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
[DEFAULT]
|
|
||||||
debug = {{ debug }}
|
|
||||||
verbose = {{ verbose }}
|
|
||||||
metering_secret = {{ metering_secret }}
|
|
||||||
control_exchange = ceilometer
|
|
||||||
metering_api_port = {{ service_port }}
|
|
||||||
rabbit_host = {{ rabbit_host }}
|
|
||||||
rabbit_port = 5672
|
|
||||||
rabbit_userid = {{ rabbit_userid }}
|
|
||||||
rabbit_password = {{ rabbit_password }}
|
|
||||||
rabbit_virtual_host = {{ rabbit_virtual_host }}
|
|
||||||
database_connection = mongodb://{{ db_host }}:{{ db_port }}/{{ db_name }}
|
|
||||||
os_auth_url = http://{{ keystone_host }}:{{ keystone_port }}/v2.0
|
|
||||||
os_tenant_name = {{ keystone_os_tenant }}
|
|
||||||
os_username = {{ keystone_os_username }}
|
|
||||||
os_password = {{ keystone_os_password }}
|
|
||||||
logdir = /var/log/ceilometer
|
|
||||||
|
|
||||||
[keystone_authtoken]
|
|
||||||
auth_host = {{ keystone_host }}
|
|
||||||
auth_port = {{ keystone_port }}
|
|
||||||
auth_protocol = http
|
|
||||||
admin_tenant_name = {{ keystone_os_tenant }}
|
|
||||||
admin_user = {{ keystone_os_username }}
|
|
||||||
admin_password = {{ keystone_os_password }}
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
# grizzly
|
||||||
|
###############################################################################
|
||||||
|
# [ WARNING ]
|
||||||
|
# ceilometer configuration file maintained by Juju
|
||||||
|
# local changes may be overwritten.
|
||||||
|
###############################################################################
|
||||||
|
[DEFAULT]
|
||||||
|
debug = {{ debug }}
|
||||||
|
verbose = {{ verbose }}
|
||||||
|
|
||||||
|
metering_secret = {{ metering_secret }}
|
||||||
|
metering_api_port = {{ port }}
|
||||||
|
|
||||||
|
rabbit_host = {{ rabbitmq_host }}
|
||||||
|
rabbit_userid = {{ rabbitmq_user }}
|
||||||
|
rabbit_password = {{ rabbitmq_password }}
|
||||||
|
rabbit_virtual_host = {{ rabbitmq_virtual_host }}
|
||||||
|
|
||||||
|
database_connection = mongodb://{{ db_host }}:{{ db_port }}/{{ db_name }}
|
||||||
|
|
||||||
|
os_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
|
||||||
|
os_tenant_name = {{ admin_tenant_name }}
|
||||||
|
os_username = {{ admin_user }}
|
||||||
|
os_password = {{ admin_password }}
|
||||||
|
|
||||||
|
logdir = /var/log/ceilometer
|
||||||
|
|
||||||
|
[keystone_authtoken]
|
||||||
|
auth_host = {{ auth_host }}
|
||||||
|
auth_port = {{ auth_port }}
|
||||||
|
auth_protocol = {{ auth_protocol }}
|
||||||
|
admin_tenant_name = {{ admin_tenant_name }}
|
||||||
|
admin_user = {{ admin_user }}
|
||||||
|
admin_password = {{ admin_password }}
|
|
@ -0,0 +1,38 @@
|
||||||
|
# havana
|
||||||
|
###############################################################################
|
||||||
|
# [ WARNING ]
|
||||||
|
# ceilometer configuration file maintained by Juju
|
||||||
|
# local changes may be overwritten.
|
||||||
|
###############################################################################
|
||||||
|
[DEFAULT]
|
||||||
|
debug = {{ debug }}
|
||||||
|
verbose = {{ verbose }}
|
||||||
|
|
||||||
|
rabbit_host = {{ rabbitmq_host }}
|
||||||
|
rabbit_userid = {{ rabbitmq_user }}
|
||||||
|
rabbit_password = {{ rabbitmq_password }}
|
||||||
|
rabbit_virtual_host = {{ rabbitmq_virtual_host }}
|
||||||
|
|
||||||
|
[api]
|
||||||
|
port = {{ port }}
|
||||||
|
|
||||||
|
[service_credentials]
|
||||||
|
os_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
|
||||||
|
os_tenant_name = {{ admin_tenant_name }}
|
||||||
|
os_username = {{ admin_user }}
|
||||||
|
os_password = {{ admin_password }}
|
||||||
|
|
||||||
|
[database]
|
||||||
|
connection = mongodb://{{ db_host }}:{{ db_port }}/{{ db_name }}
|
||||||
|
|
||||||
|
[publisher_rpc]
|
||||||
|
metering_secret = {{ metering_secret }}
|
||||||
|
|
||||||
|
[keystone_authtoken]
|
||||||
|
auth_host = {{ auth_host }}
|
||||||
|
auth_port = {{ auth_port }}
|
||||||
|
auth_protocol = {{ auth_protocol }}
|
||||||
|
admin_tenant_name = {{ admin_tenant_name }}
|
||||||
|
admin_user = {{ admin_user }}
|
||||||
|
admin_password = {{ admin_password }}
|
||||||
|
|
Loading…
Reference in New Issue