From f027dbca2904e44329aeea97ca82dc67cc01bbf0 Mon Sep 17 00:00:00 2001 From: Jerry Seutter Date: Mon, 1 Apr 2013 13:47:19 -0600 Subject: [PATCH] Added health check scripts to rabbitmq charm. --- hooks/lib/openstack_common.py | 230 ++++++++++++++++++ hooks/rabbitmq_server_relations.py | 10 + scripts/add_to_cluster | 2 + scripts/health_checks.d/service_ports_live | 13 + .../health_checks.d/service_rabbitmq_running | 13 + scripts/remove_from_cluster | 2 + 6 files changed, 270 insertions(+) create mode 100644 hooks/lib/openstack_common.py create mode 100755 scripts/add_to_cluster create mode 100755 scripts/health_checks.d/service_ports_live create mode 100755 scripts/health_checks.d/service_rabbitmq_running create mode 100755 scripts/remove_from_cluster diff --git a/hooks/lib/openstack_common.py b/hooks/lib/openstack_common.py new file mode 100644 index 00000000..d44390c1 --- /dev/null +++ b/hooks/lib/openstack_common.py @@ -0,0 +1,230 @@ +#!/usr/bin/python + +# 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' + +ubuntu_openstack_release = { + 'oneiric': 'diablo', + 'precise': 'essex', + 'quantal': 'folsom', + 'raring': 'grizzly', +} + + +openstack_codenames = { + '2011.2': 'diablo', + '2012.1': 'essex', + '2012.2': 'folsom', + '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', +} + + +def juju_log(msg): + subprocess.check_call(['juju-log', msg]) + + +def error_out(msg): + juju_log("FATAL ERROR: %s" % msg) + exit(1) + + +def lsb_release(): + '''Return /etc/lsb-release in a dict''' + lsb = open('/etc/lsb-release', 'r') + d = {} + for l in lsb: + k, v = l.split('=') + d[k.strip()] = v.strip() + return d + + +def get_os_codename_install_source(src): + '''Derive OpenStack release codename from a given installation source.''' + ubuntu_rel = lsb_release()['DISTRIB_CODENAME'] + + rel = '' + if src == 'distro': + try: + rel = ubuntu_openstack_release[ubuntu_rel] + except KeyError: + e = 'Code not derive openstack release for '\ + 'this Ubuntu release: %s' % rel + error_out(e) + return rel + + if src.startswith('cloud:'): + ca_rel = src.split(':')[1] + ca_rel = ca_rel.split('%s-' % ubuntu_rel)[1].split('/')[0] + return ca_rel + + # Best guess match based on deb string provided + if src.startswith('deb') or src.startswith('ppa'): + for k, v in openstack_codenames.iteritems(): + if v in src: + return v + + +def get_os_codename_version(vers): + '''Determine OpenStack codename from version number.''' + try: + return openstack_codenames[vers] + except KeyError: + e = 'Could not determine OpenStack codename for version %s' % vers + error_out(e) + + +def get_os_version_codename(codename): + '''Determine OpenStack version number from codename.''' + for k, v in openstack_codenames.iteritems(): + if v == codename: + return k + e = 'Code not derive OpenStack version for '\ + 'codename: %s' % codename + error_out(e) + + +def get_os_codename_package(pkg): + '''Derive OpenStack release codename from an installed package.''' + apt.init() + cache = apt.Cache() + try: + pkg = cache[pkg] + except: + e = 'Could not determine version of installed package: %s' % pkg + error_out(e) + + vers = apt.UpstreamVersion(pkg.current_ver.ver_str) + + try: + 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(keyid): + cmd = "apt-key adv --keyserver keyserver.ubuntu.com " \ + "--recv-keys %s" % keyid + try: + subprocess.check_call(cmd.split(' ')) + except subprocess.CalledProcessError: + error_out("Error importing repo key %s" % keyid) + + if rel == 'distro': + return + elif rel[:4] == "ppa:": + src = rel + subprocess.check_call(["add-apt-repository", "-y", src]) + elif rel[:3] == "deb": + l = len(rel.split('|')) + if l == 2: + src, key = rel.split('|') + juju_log("Importing PPA key from keyserver for %s" % src) + _import_key(key) + elif l == 1: + src = rel + else: + error_out("Invalid openstack-release: %s" % rel) + + with open('/etc/apt/sources.list.d/juju_deb.list', 'w') as f: + f.write(src) + elif rel[:6] == 'cloud:': + ubuntu_rel = lsb_release()['DISTRIB_CODENAME'] + rel = rel.split(':')[1] + u_rel = rel.split('-')[0] + ca_rel = rel.split('-')[1] + + if u_rel != ubuntu_rel: + e = 'Cannot install from Cloud Archive pocket %s on this Ubuntu '\ + 'version (%s)' % (ca_rel, ubuntu_rel) + error_out(e) + + if 'staging' in ca_rel: + # staging is just a regular PPA. + 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 + + # map charm config options to actual archive pockets. + pockets = { + 'folsom': 'precise-updates/folsom', + 'folsom/updates': 'precise-updates/folsom', + 'folsom/proposed': 'precise-proposed/folsom', + 'grizzly': 'precise-updates/grizzly', + 'grizzly/updates': 'precise-updates/grizzly', + 'grizzly/proposed': 'precise-proposed/grizzly' + } + + try: + pocket = pockets[ca_rel] + except KeyError: + e = 'Invalid Cloud Archive release specified: %s' % rel + error_out(e) + + src = "deb %s %s main" % (CLOUD_ARCHIVE_URL, pocket) + _import_key(CLOUD_ARCHIVE_KEY_ID) + + with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as f: + 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/rabbitmq_server_relations.py b/hooks/rabbitmq_server_relations.py index 0a197e64..bf4f5cc6 100755 --- a/hooks/rabbitmq_server_relations.py +++ b/hooks/rabbitmq_server_relations.py @@ -10,6 +10,8 @@ import rabbit_utils as rabbit import lib.utils as utils import lib.cluster_utils as cluster import lib.ceph_utils as ceph +import lib.openstack_common as openstack + SERVICE_NAME = os.getenv('JUJU_UNIT_NAME').split('/')[0] POOL_NAME = SERVICE_NAME @@ -166,6 +168,14 @@ def ha_joined(): for rel_id in utils.relation_ids('ha'): utils.relation_set(rid=rel_id, **relation_settings) + env_vars = { + 'OPENSTACK_SERVICE_RABBIT': 'rabbitmq-server', + 'OPENSTACK_PORT_EPMD': 4369, + 'OPENSTACK_PORT_MCASTPORT': utils.config_get('ha-mcastport') + 'OPENSTACK_PORT_SSL': utils.config_get('ssl_port'), + } + openstack.save_script_rc(**env_vars) + def ha_changed(): if not cluster.is_clustered(): diff --git a/scripts/add_to_cluster b/scripts/add_to_cluster new file mode 100755 index 00000000..e50ab019 --- /dev/null +++ b/scripts/add_to_cluster @@ -0,0 +1,2 @@ +#!/bin/bash +crm node online diff --git a/scripts/health_checks.d/service_ports_live b/scripts/health_checks.d/service_ports_live new file mode 100755 index 00000000..5ad0be0f --- /dev/null +++ b/scripts/health_checks.d/service_ports_live @@ -0,0 +1,13 @@ +#!/bin/bash +# Validate that service ports are active +HEALTH_DIR=`dirname $0` +SCRIPTS_DIR=`dirname $HEALTH_DIR` +. $SCRIPTS_DIR/scriptrc +set -e + +# Grab any OPENSTACK_PORT* environment variables +openstack_ports=`env| awk -F '=' '(/OPENSTACK_PORT/){print $2}'` +for port in $openstack_ports +do + netstat -ln | grep -q ":$port " +done diff --git a/scripts/health_checks.d/service_rabbitmq_running b/scripts/health_checks.d/service_rabbitmq_running new file mode 100755 index 00000000..9aec8237 --- /dev/null +++ b/scripts/health_checks.d/service_rabbitmq_running @@ -0,0 +1,13 @@ +#!/bin/bash +# Validate that service is running +HEALTH_DIR=`dirname $0` +SCRIPTS_DIR=`dirname $HEALTH_DIR` +. $SCRIPTS_DIR/scriptrc +set -e + +# Grab any OPENSTACK_SERVICE* environment variables +openstack_service_names=`env| awk -F '=' '(/OPENSTACK_SERVICE/){print $2}'` +for service_name in $openstack_service_names +do + service $service_name status +done diff --git a/scripts/remove_from_cluster b/scripts/remove_from_cluster new file mode 100755 index 00000000..4fb2aa16 --- /dev/null +++ b/scripts/remove_from_cluster @@ -0,0 +1,2 @@ +#!/bin/bash +crm node standby