From e66a379d5a4b256b65bab24ee093f07d0f765691 Mon Sep 17 00:00:00 2001 From: James Page Date: Sun, 31 Mar 2013 12:19:54 +0100 Subject: [PATCH] General tidy, sort out hooks, use openstack helpers --- config.yaml | 2 +- hooks/ceilometer_utils.py | 4 +- hooks/hooks.py | 51 +++----- hooks/lib/__init__.py | 2 - hooks/lib/openstack_common.py | 110 ++++++++++------ hooks/utils.py | 239 ---------------------------------- templates/ceilometer.conf | 1 + 7 files changed, 99 insertions(+), 310 deletions(-) delete mode 100644 hooks/utils.py diff --git a/config.yaml b/config.yaml index 4e90fab..27dda18 100644 --- a/config.yaml +++ b/config.yaml @@ -8,7 +8,7 @@ options: type: string description: "Enable verbose logging" openstack-origin: - default: cloud:precise-folsom + default: cloud:precise-grizzly type: string description: | Repository from which to install. May be one of the following: diff --git a/hooks/ceilometer_utils.py b/hooks/ceilometer_utils.py index cb228b3..e7e9637 100644 --- a/hooks/ceilometer_utils.py +++ b/hooks/ceilometer_utils.py @@ -1,6 +1,8 @@ import os import uuid import ConfigParser +import sys +from lib.utils import juju_log RABBIT_USER = "ceilometer" RABBIT_VHOST = "ceilometer" @@ -56,6 +58,6 @@ def modify_config_file(nova_conf, values): config.write(f) f.close() - except IOError as e: + except IOError: juju_log('ERROR', 'Error updating nova config file') sys.exit(1) diff --git a/hooks/hooks.py b/hooks/hooks.py index 97a670e..4ea4c30 100755 --- a/hooks/hooks.py +++ b/hooks/hooks.py @@ -1,18 +1,14 @@ #!/usr/bin/python -import sys -import time import os -import utils +import lib.utils as utils import ceilometer_utils def install(): utils.configure_source() utils.install(*ceilometer_utils.CEILOMETER_PACKAGES) - - port = ceilometer_utils.CEILOMETER_PORT - utils.expose(port) + utils.expose(ceilometer_utils.CEILOMETER_PORT) def amqp_joined(): @@ -23,7 +19,7 @@ def amqp_joined(): def amqp_changed(): if render_ceilometer_conf(): utils.restart(*ceilometer_utils.CEILOMETER_SERVICES) - ceilometer_changed() + ceilometer_joined() def db_joined(): @@ -33,7 +29,7 @@ def db_joined(): def db_changed(): if render_ceilometer_conf(): utils.restart(*ceilometer_utils.CEILOMETER_SERVICES) - ceilometer_changed() + ceilometer_joined() def keystone_joined(): @@ -48,7 +44,7 @@ def keystone_joined(): def keystone_changed(): if render_ceilometer_conf(): utils.restart(*ceilometer_utils.CEILOMETER_SERVICES) - ceilometer_changed() + ceilometer_joined() def get_rabbit_conf(): @@ -62,6 +58,10 @@ def get_rabbit_conf(): "rabbit_password": utils.relation_get('password', unit, relid) } + if utils.relation_get('clustered', + unit, relid): + conf["rabbit_host"] = utils.relation_get('vip', + unit, relid) if None not in conf.itervalues(): return conf return None @@ -84,12 +84,15 @@ def get_keystone_conf(): for relid in utils.relation_ids('identity-service'): for unit in utils.relation_list(relid): keystone_username = utils.relation_get('service_username', - unit, relid) - keystone_port = utils.relation_get('service_port', unit, relid) - keystone_host = utils.relation_get('service_host', unit, relid) + unit, relid) + keystone_port = utils.relation_get('service_port', + unit, relid) + keystone_host = utils.relation_get('service_host', + unit, relid) keystone_password = utils.relation_get('service_password', - unit, relid) - keystone_tenant = utils.relation_get('service_tenant', unit, relid) + unit, relid) + keystone_tenant = utils.relation_get('service_tenant', + unit, relid) conf = { "keystone_os_username": keystone_username, @@ -125,29 +128,19 @@ def render_ceilometer_conf(): def ceilometer_joined(): - # update metering secret - metering_secret = ceilometer_utils.get_shared_secret() - for relid in utils.relation_ids('ceilometer-service'): - utils.relation_set(metering_secret=metering_secret, rid=relid) - - -def ceilometer_changed(): # set all relationships for ceilometer service context = get_rabbit_conf() contextdb = get_db_conf() contextkeystone = get_keystone_conf() - if context and contextdb and contextkeystone: context.update(contextdb) context.update(contextkeystone) context["metering_secret"] = ceilometer_utils.get_shared_secret() - # set all that info into ceilometer-service relationship for relid in utils.relation_ids('ceilometer-service'): - for unit in utils.relation_list(relid): - context["rid"] = relid - utils.relation_set(**context) - + context["rid"] = relid + utils.relation_set(**context) + utils.do_hooks({ "install": install, @@ -157,7 +150,5 @@ utils.do_hooks({ "shared-db-relation-changed": db_changed, "identity-service-relation-joined": keystone_joined, "identity-service-relation-changed": keystone_changed, - "ceilometer-service-relation-joined": ceilometer_joined, - "ceilometer-service-relation-changed": ceilometer_changed + "ceilometer-service-relation-joined": ceilometer_joined }) -sys.exit(0) diff --git a/hooks/lib/__init__.py b/hooks/lib/__init__.py index 139597f..e69de29 100644 --- a/hooks/lib/__init__.py +++ b/hooks/lib/__init__.py @@ -1,2 +0,0 @@ - - diff --git a/hooks/lib/openstack_common.py b/hooks/lib/openstack_common.py index dd9678e..d44390c 100644 --- a/hooks/lib/openstack_common.py +++ b/hooks/lib/openstack_common.py @@ -2,7 +2,9 @@ # Common python helper functions used for OpenStack charms. +import apt_pkg as apt import subprocess +import os CLOUD_ARCHIVE_URL = "http://ubuntu-cloud.archive.canonical.com/ubuntu" CLOUD_ARCHIVE_KEY_ID = '5EDB1B62EC4926EA' @@ -11,7 +13,7 @@ ubuntu_openstack_release = { 'oneiric': 'diablo', 'precise': 'essex', 'quantal': 'folsom', - 'raring': 'grizzly' + 'raring': 'grizzly', } @@ -19,7 +21,18 @@ openstack_codenames = { '2011.2': 'diablo', '2012.1': 'essex', '2012.2': 'folsom', - '2012.3': 'grizzly' + '2013.1': 'grizzly', + '2013.2': 'havana', +} + +# The ugly duckling +swift_codenames = { + '1.4.3': 'diablo', + '1.4.8': 'essex', + '1.7.4': 'folsom', + '1.7.6': 'grizzly', + '1.7.7': 'grizzly', + '1.8.0': 'grizzly', } @@ -62,7 +75,7 @@ def get_os_codename_install_source(src): return ca_rel # Best guess match based on deb string provided - if src.startswith('deb'): + if src.startswith('deb') or src.startswith('ppa'): for k, v in openstack_codenames.iteritems(): if v in src: return v @@ -89,52 +102,54 @@ def get_os_version_codename(codename): def get_os_codename_package(pkg): '''Derive OpenStack release codename from an installed package.''' - cmd = ['dpkg', '-l', pkg] - + apt.init() + cache = apt.Cache() try: - output = subprocess.check_output(cmd) - except subprocess.CalledProcessError: - e = 'Could not derive OpenStack version from package that is not '\ - 'installed; %s' % pkg - error_out(e) - - def _clean(line): - line = line.split(' ') - clean = [] - for c in line: - if c != '': - clean.append(c) - return clean - - vers = None - for l in output.split('\n'): - if l.startswith('ii'): - l = _clean(l) - if l[1] == pkg: - vers = l[2] - - if not vers: + pkg = cache[pkg] + except: e = 'Could not determine version of installed package: %s' % pkg error_out(e) - vers = vers[:6] + vers = apt.UpstreamVersion(pkg.current_ver.ver_str) + try: - return openstack_codenames[vers] + if 'swift' in pkg.name: + vers = vers[:5] + return swift_codenames[vers] + else: + vers = vers[:6] + return openstack_codenames[vers] except KeyError: e = 'Could not determine OpenStack codename for version %s' % vers error_out(e) +def get_os_version_package(pkg): + '''Derive OpenStack version number from an installed package.''' + codename = get_os_codename_package(pkg) + + if 'swift' in pkg: + vers_map = swift_codenames + else: + vers_map = openstack_codenames + + for version, cname in vers_map.iteritems(): + if cname == codename: + return version + e = "Could not determine OpenStack version for package: %s" % pkg + error_out(e) + + def configure_installation_source(rel): '''Configure apt installation source.''' - def _import_key(id): + def _import_key(keyid): cmd = "apt-key adv --keyserver keyserver.ubuntu.com " \ - "--recv-keys %s" % id + "--recv-keys %s" % keyid try: subprocess.check_call(cmd.split(' ')) - except: - error_out("Error importing repo key %s" % id) + except subprocess.CalledProcessError: + error_out("Error importing repo key %s" % keyid) if rel == 'distro': return @@ -165,10 +180,11 @@ def configure_installation_source(rel): 'version (%s)' % (ca_rel, ubuntu_rel) error_out(e) - if ca_rel == 'folsom/staging': + if 'staging' in ca_rel: # staging is just a regular PPA. - cmd = 'add-apt-repository -y ppa:ubuntu-cloud-archive/'\ - 'folsom-staging' + os_rel = ca_rel.split('/')[0] + ppa = 'ppa:ubuntu-cloud-archive/%s-staging' % os_rel + cmd = 'add-apt-repository -y %s' % ppa subprocess.check_call(cmd.split(' ')) return @@ -176,7 +192,10 @@ def configure_installation_source(rel): pockets = { 'folsom': 'precise-updates/folsom', 'folsom/updates': 'precise-updates/folsom', - 'folsom/proposed': 'precise-proposed/folsom' + 'folsom/proposed': 'precise-proposed/folsom', + 'grizzly': 'precise-updates/grizzly', + 'grizzly/updates': 'precise-updates/grizzly', + 'grizzly/proposed': 'precise-proposed/grizzly' } try: @@ -192,3 +211,20 @@ def configure_installation_source(rel): f.write(src) else: error_out("Invalid openstack-release specified: %s" % rel) + + +def save_script_rc(script_path="scripts/scriptrc", **env_vars): + """ + Write an rc file in the charm-delivered directory containing + exported environment variables provided by env_vars. Any charm scripts run + outside the juju hook environment can source this scriptrc to obtain + updated config information necessary to perform health checks or + service changes. + """ + unit_name = os.getenv('JUJU_UNIT_NAME').replace('/', '-') + juju_rc_path = "/var/lib/juju/units/%s/charm/%s" % (unit_name, script_path) + with open(juju_rc_path, 'wb') as rc_script: + rc_script.write( + "#!/bin/bash\n") + [rc_script.write('export %s=%s\n' % (u, p)) + for u, p in env_vars.iteritems() if u != "script_path"] diff --git a/hooks/utils.py b/hooks/utils.py deleted file mode 100644 index def7c77..0000000 --- a/hooks/utils.py +++ /dev/null @@ -1,239 +0,0 @@ -# -# Copyright 2012 Canonical Ltd. -# -# Authors: -# James Page -# Paul Collins -# - -import os -import subprocess -import socket -import sys -import apt_pkg as apt -import re -import ceilometer_utils - - -def do_hooks(hooks): - hook = os.path.basename(sys.argv[0]) - - try: - hook_func = hooks[hook] - except KeyError: - juju_log('INFO', - "This charm doesn't know how to handle '{}'.".format(hook)) - else: - hook_func() - - -def install(*pkgs): - cmd = [ - 'apt-get', - '-y', - 'install' - ] - for pkg in pkgs: - cmd.append(pkg) - subprocess.check_call(cmd) - -TEMPLATES_DIR = 'templates' - -try: - import jinja2 -except ImportError: - install('python-jinja2') - import jinja2 - - -def render_template(template_name, context, template_dir=TEMPLATES_DIR): - templates = jinja2.Environment( - loader=jinja2.FileSystemLoader(template_dir) - ) - template = templates.get_template(template_name) - return template.render(context) - -CLOUD_ARCHIVE = \ - """ # Ubuntu Cloud Archive - deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main - """ - -CLOUD_ARCHIVE_POCKETS = { - 'precise-folsom': 'precise-updates/folsom', - 'precise-folsom/updates': 'precise-updates/folsom', - 'precise-folsom/proposed': 'precise-proposed/folsom', - 'precise-grizzly': 'precise-updates/grizzly', - 'precise-grizzly/updates': 'precise-updates/grizzly', - 'precise-grizzly/proposed': 'precise-proposed/grizzly' -} - - -def configure_source(): - source = str(config_get('openstack-origin')) - if not source: - return - if source.startswith('ppa:'): - cmd = [ - 'add-apt-repository', - source - ] - subprocess.check_call(cmd) - if source.startswith('cloud:'): - install('ubuntu-cloud-keyring') - pocket = source.split(':')[1] - with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as apt: - apt.write(CLOUD_ARCHIVE.format(CLOUD_ARCHIVE_POCKETS[pocket])) - if source.startswith('deb'): - l = len(source.split('|')) - if l == 2: - (apt_line, key) = source.split('|') - cmd = [ - 'apt-key', - 'adv', '--keyserver keyserver.ubuntu.com', - '--recv-keys', key - ] - subprocess.check_call(cmd) - elif l == 1: - apt_line = source - - with open('/etc/apt/sources.list.d/ceilometer.list', 'w') as apt: - apt.write(apt_line + "\n") - cmd = [ - 'apt-get', - 'update' - ] - subprocess.check_call(cmd) - -# Protocols -TCP = 'TCP' -UDP = 'UDP' - - -def expose(port, protocol='TCP'): - cmd = [ - 'open-port', - '{}/{}'.format(port, protocol) - ] - subprocess.check_call(cmd) - - -def unexpose(port, protocol='TCP'): - cmd = [ - 'close-port', - '{}/{}'.format(port, protocol) - ] - subprocess.check_call(cmd) - - -def juju_log(severity, message): - cmd = [ - 'juju-log', - '--log-level', severity, - message - ] - subprocess.check_call(cmd) - - -def relation_ids(relation): - cmd = [ - 'relation-ids', - relation - ] - return subprocess.check_output(cmd).split() # IGNORE:E1103 - - -def relation_list(rid): - cmd = [ - 'relation-list', - '-r', rid, - ] - return subprocess.check_output(cmd).split() # IGNORE:E1103 - - -def relation_get(attribute, unit=None, rid=None): - cmd = [ - 'relation-get', - ] - if rid: - cmd.append('-r') - cmd.append(rid) - cmd.append(attribute) - if unit: - cmd.append(unit) - value = subprocess.check_output(cmd).strip() # IGNORE:E1103 - if value == "": - return None - else: - return value - - -def relation_set(**kwargs): - cmd = [ - 'relation-set' - ] - args = [] - for k, v in kwargs.items(): - if k == 'rid': - cmd.append('-r') - cmd.append(v) - else: - args.append('{}={}'.format(k, v)) - cmd += args - subprocess.check_call(cmd) - - -def unit_get(attribute): - cmd = [ - 'unit-get', - attribute - ] - value = subprocess.check_output(cmd).strip() # IGNORE:E1103 - if value == "": - return None - else: - return value - - -def config_get(attribute): - cmd = [ - 'config-get', - attribute - ] - value = subprocess.check_output(cmd).strip() # IGNORE:E1103 - if value == "": - return None - else: - return value - - -def get_unit_hostname(): - return socket.gethostname() - - -def _service_ctl(service, action): - subprocess.check_call(['service', service, action]) - - -def restart(*services): - for service in services: - _service_ctl(service, 'restart') - - -def stop(*services): - for service in services: - _service_ctl(service, 'stop') - - -def start(*services): - for service in services: - _service_ctl(service, 'start') - - -def get_os_version(package=None): - apt.init() - cache = apt.Cache() - pkg = cache[package or 'quantum-common'] - if pkg.current_ver: - return apt.upstream_version(pkg.current_ver.ver_str) - else: - return None diff --git a/templates/ceilometer.conf b/templates/ceilometer.conf index 522c69c..77be102 100644 --- a/templates/ceilometer.conf +++ b/templates/ceilometer.conf @@ -23,3 +23,4 @@ auth_protocol = http admin_tenant_name = {{ keystone_os_tenant }} admin_user = {{ keystone_os_username }} admin_password = {{ keystone_os_password }} +