From d679930416efd9d85a57423bd8775cdf59afb8b9 Mon Sep 17 00:00:00 2001 From: Adam Gandelman Date: Wed, 23 Jan 2013 13:56:44 -0800 Subject: [PATCH] Python rewrite. --- hooks/amqp-relation-changed | 2 +- hooks/amqp-relation-joined | 1 - hooks/cluster-relation-changed | 2 +- hooks/cluster-relation-joined | 2 +- hooks/config-changed | 70 ---------- hooks/ha-relation-changed | 2 +- hooks/ha-relation-joined | 2 +- hooks/install | 2 +- hooks/rabbit_utils.py | 97 ++++++++++++++ hooks/rabbitmq-common | 82 ------------ hooks/rabbitmq-relations | 198 ----------------------------- hooks/rabbitmq-server-relations.py | 142 +++++++++++++++++++++ hooks/start | 1 - hooks/stop | 1 - hooks/utils.py | 147 +++++++++++++++++++++ revision | 2 +- 16 files changed, 393 insertions(+), 360 deletions(-) delete mode 120000 hooks/amqp-relation-joined delete mode 100755 hooks/config-changed create mode 100644 hooks/rabbit_utils.py delete mode 100755 hooks/rabbitmq-common delete mode 100755 hooks/rabbitmq-relations create mode 100755 hooks/rabbitmq-server-relations.py delete mode 120000 hooks/start delete mode 120000 hooks/stop create mode 100644 hooks/utils.py diff --git a/hooks/amqp-relation-changed b/hooks/amqp-relation-changed index 564b83a1..46ff2b7a 120000 --- a/hooks/amqp-relation-changed +++ b/hooks/amqp-relation-changed @@ -1 +1 @@ -rabbitmq-relations \ No newline at end of file +rabbitmq-server-relations.py \ No newline at end of file diff --git a/hooks/amqp-relation-joined b/hooks/amqp-relation-joined deleted file mode 120000 index 564b83a1..00000000 --- a/hooks/amqp-relation-joined +++ /dev/null @@ -1 +0,0 @@ -rabbitmq-relations \ No newline at end of file diff --git a/hooks/cluster-relation-changed b/hooks/cluster-relation-changed index 564b83a1..46ff2b7a 120000 --- a/hooks/cluster-relation-changed +++ b/hooks/cluster-relation-changed @@ -1 +1 @@ -rabbitmq-relations \ No newline at end of file +rabbitmq-server-relations.py \ No newline at end of file diff --git a/hooks/cluster-relation-joined b/hooks/cluster-relation-joined index 564b83a1..46ff2b7a 120000 --- a/hooks/cluster-relation-joined +++ b/hooks/cluster-relation-joined @@ -1 +1 @@ -rabbitmq-relations \ No newline at end of file +rabbitmq-server-relations.py \ No newline at end of file diff --git a/hooks/config-changed b/hooks/config-changed deleted file mode 100755 index 32ca812c..00000000 --- a/hooks/config-changed +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash -set -eu - -juju-log "rabbitmq-server: Firing config hook" - -export HOME=/root # (HOME is not set on first run) -RABBIT_PLUGINS=/usr/lib/rabbitmq/lib/rabbitmq_server-*/sbin/rabbitmq-plugins -if [ "`config-get management_plugin`" == "True" ]; then - $RABBIT_PLUGINS enable rabbitmq_management - open-port 55672/tcp -else - $RABBIT_PLUGINS disable rabbitmq_management - close-port 55672/tcp -fi - -ssl_enabled=`config-get ssl_enabled` - -cd /etc/rabbitmq - -new_config=`mktemp /etc/rabbitmq/.rabbitmq.config.XXXXXX` -chgrp rabbitmq "$new_config" -chmod g+r "$new_config" -exec 3> "$new_config" - -cat >&3 < "$ssl_key_file" - config-get ssl_cert > "$ssl_cert_file" - chgrp rabbitmq "$ssl_key_file" "$ssl_cert_file" - if [ ! -s "$ssl_key_file" ]; then - juju-log "ssl_key not set - can't configure SSL" - exit 0 - fi - if [ ! -s "$ssl_cert_file" ]; then - juju-log "ssl_cert not set - can't configure SSL" - exit 0 - fi - cat >&3 <&3 <&- - -if [ -f rabbitmq.config ]; then - mv rabbitmq.config{,.bak} -fi - -mv "$new_config" rabbitmq.config - -/etc/init.d/rabbitmq-server restart diff --git a/hooks/ha-relation-changed b/hooks/ha-relation-changed index 564b83a1..46ff2b7a 120000 --- a/hooks/ha-relation-changed +++ b/hooks/ha-relation-changed @@ -1 +1 @@ -rabbitmq-relations \ No newline at end of file +rabbitmq-server-relations.py \ No newline at end of file diff --git a/hooks/ha-relation-joined b/hooks/ha-relation-joined index 564b83a1..46ff2b7a 120000 --- a/hooks/ha-relation-joined +++ b/hooks/ha-relation-joined @@ -1 +1 @@ -rabbitmq-relations \ No newline at end of file +rabbitmq-server-relations.py \ No newline at end of file diff --git a/hooks/install b/hooks/install index 564b83a1..46ff2b7a 120000 --- a/hooks/install +++ b/hooks/install @@ -1 +1 @@ -rabbitmq-relations \ No newline at end of file +rabbitmq-server-relations.py \ No newline at end of file diff --git a/hooks/rabbit_utils.py b/hooks/rabbit_utils.py new file mode 100644 index 00000000..575fbbb3 --- /dev/null +++ b/hooks/rabbit_utils.py @@ -0,0 +1,97 @@ +import re +import subprocess +import utils +import apt_pkg as apt + +PACKAGES = ['pwgen', 'rabbitmq-server'] + +RABBITMQ_CTL = '/usr/sbin/rabbitmqctl' +COOKIE_PATH = '/var/lib/rabbitmq/.erlang.cookie' + +def vhost_exists(vhost): + cmd = [RABBITMQ_CTL, 'list_vhosts'] + out = subprocess.check_output(cmd) + for line in out.split('\n')[1:]: + if line == vhost: + utils.juju_log('INFO', 'vhost (%s) already exists.' % vhost) + return True + return False + + +def create_vhost(vhost): + if vhost_exists(vhost): + return + cmd = [RABBITMQ_CTL, 'add_vhost', vhost] + subprocess.check_call(cmd) + utils.juju_log('INFO', 'Created new vhost (%s).' % vhost) + + +def user_exists(user): + cmd = [RABBITMQ_CTL, 'list_users'] + out = subprocess.check_output(cmd) + for line in out.split('\n')[1:]: + _user = line.split('\t')[0] + if _user == user: + admin = line.split('\t')[1] + return True, (admin == '[administrator]') + return False, False + + +def create_user(user, password, admin=False): + exists, is_admin = user_exists(user) + + if not exists: + cmd = [RABBITMQ_CTL, 'add_user', user, password] + subprocess.check_call(cmd) + utils.juju_log('INFO', 'Created new user (%s).' % user) + + if admin == is_admin: + return + + if admin: + cmd = [RABBITMQ_CTL, 'set_user_tags', user, 'administrator'] + utils.juju_log('INFO', 'Granting user (%s) admin access.') + else: + cmd = [RABBITMQ_CTL, 'set_user_tags', user] + utils.juju_log('INFO', 'Revoking user (%s) admin access.') + + +def grant_permissions(user, vhost): + cmd = [RABBITMQ_CTL, 'set_permissions', '-p', + vhost, user, '.*', '.*', '.*'] + subprocess.check_call(cmd) + + +def service(action): + cmd = ['service', 'rabbitmq-server', action] + subprocess.check_call(cmd) + + +def rabbit_version(): + apt.init() + cache = apt.Cache() + pkg = cache['rabbitmq-server'] + if pkg.current_ver: + return apt.upstream_version(pkg.current_ver.ver_str) + else: + return None + + +def cluster_with(host): + utils.juju_log('INFO', 'Clustering with remote rabbit host (%s).' % host) + vers = rabbit_version() + if vers >= '3.0.1-1': + cluster_cmd = 'join_cluster' + else: + cluster_cmd = 'cluster' + out = subprocess.check_output([RABBITMQ_CTL, 'cluster_status']) + for line in out.split('\n'): + if re.search(host, line): + utils.juju_log('INFO', 'Host already clustered with %s.' % host) + return + cmd = [RABBITMQ_CTL, 'stop_app'] + subprocess.check_call(cmd) + cmd = [RABBITMQ_CTL, cluster_cmd, 'rabbit@%s' % host] + subprocess.check_call(cmd) + cmd = [RABBITMQ_CTL, 'start_app'] + subprocess.check_call(cmd) diff --git a/hooks/rabbitmq-common b/hooks/rabbitmq-common deleted file mode 100755 index 49d07ce6..00000000 --- a/hooks/rabbitmq-common +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash -# -# rabbitmq-common - common formula shell functions and config variables -# -# Copyright (C) 2011 Canonical Ltd. -# Author: Adam Gandelman -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -set -e - -RABBIT_CTL='rabbitmqctl' - -ERLANG_COOKIE="/var/lib/rabbitmq/.erlang.cookie" - -function user_exists { - $RABBIT_CTL list_users | grep -wq "^$1" -} - -function user_is_admin { - $RABBIT_CTL list_users | grep -w "^$1" | grep -q "administrator" -} - -function vhost_exists { - $RABBIT_CTL list_vhosts | grep "^$1\$" >/dev/null -} - -function create_vhost { - juju-log "Creating vhost: $1" - $RABBIT_CTL add_vhost "$1" -} - -function user_create { - local user="$1" - local passwd="$2" - local vhost="$3" - local admin="$4" - juju-log "rabbitmq: Creating user $1 (vhost: $3" - $RABBIT_CTL add_user "$user" "$passwd" || return 1 - - # grant the user all permissions on the default vhost / - # TODO: investigate sane permissions - juju-log "rabbitmq: Granting permission to $1 on vhost /" - $RABBIT_CTL set_permissions -p "$vhost" "$user" ".*" ".*" ".*" - - if [[ "$admin" == "admin" ]] ; then - user_is_admin "$user" && return 0 - juju-log "rabbitmq: Granting user $user admin access" - $RABBIT_CTL set_user_tags "$user" administrator || return 1 - fi -} - -function rabbit_version { - echo "$(dpkg -l | grep rabbitmq-server | awk '{ print $3 }')" -} - -########################################################################## -# Description: Query HA interface to determine is cluster is configured -# Returns: 0 if configured, 1 if not configured -########################################################################## -is_clustered() { - for r_id in `relation-ids ha`; do - for unit in `relation-list -r $r_id`; do - clustered=`relation-get -r $r_id clustered $unit` - if [ -n "$clustered" ]; then - return 0 - fi - done - done - return 1 -} diff --git a/hooks/rabbitmq-relations b/hooks/rabbitmq-relations deleted file mode 100755 index 858e4761..00000000 --- a/hooks/rabbitmq-relations +++ /dev/null @@ -1,198 +0,0 @@ -#!/bin/bash -# -# rabbitmq-relations - relations to be used by formula, referenced -# via symlink -# -# Copyright (C) 2011 Canonical Ltd. -# Author: Adam Gandelman -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -set -e - -CHARM_DIR=$(dirname $0) -ARG0=${0##*/} - -if [[ -e $CHARM_DIR/rabbitmq-common ]] ; then - . $CHARM_DIR/rabbitmq-common -else - juju-log "rabbitmq-server: ERROR Could not load $CHARM_DIR/rabbitmq-common" - exit 1 -fi - -juju-log "rabbitmq-server: Firing hook $ARG0." - -function install_hook() { - [[ ! `which pwgen` ]] && apt-get -y install pwgen - DEBIAN_FRONTEND=noninteractive apt-get -qqy \ - install --no-install-recommends rabbitmq-server - rc=$? - service rabbitmq-server stop - open-port 5672/tcp -} - -function amqp_changed() { - # Connecting clients should request a username and vhost. - # In reponse, we generate a password for new users, - # grant the user access on the default vhost "/", - # and tell it where to reach us. - - # Skip managing rabbit queue config unless we are the - # lowest numbered unit in the service cluster. - local local_unit_id=$(echo $JUJU_UNIT_NAME | cut -d/ -f2) - local remote_unit_id="" - for relid in $(relation-ids cluster) ; do - for unit in $(relation-list -r "$relid") ; do - remote_unit_id="$(echo $unit | cut -d/ -f2)" - if [[ "$local_unit_id" -gt "$remote_unit_id" ]]; then - juju-log "amqp_changed(): Deferring amqp_changed to leader." - exit 0 - fi - done - done - - local rabbit_user=`relation-get username` - local vhost=`relation-get vhost` - if [[ -z "$rabbit_user" ]] || [[ -z "$vhost" ]] ; then - juju-log "rabbitmq-server: rabbit_user||vhost not yet received from peer." - exit 0 - fi - local passwd_file="/var/lib/juju/$rabbit_user.passwd" - local password="" - if [[ -e $passwd_file ]] ; then - password=$(cat $passwd_file) - else - password=$(pwgen 10 1) - echo $password >$passwd_file - chmod 0400 $passwd_file - fi - if ! vhost_exists "$vhost" ; then - juju-log "rabbitmq-server: Creating vhost $vhost" - create_vhost "$vhost" - fi - if ! user_exists "$rabbit_user" ; then - juju-log "rabbitmq-server: Creating user $rabbit_user" - user_create "$rabbit_user" "$password" "$vhost" admin || exit 1 - else - juju-log "rabbitmq-server: user $rabbit_user already exists." - fi - local remote_host="$(relation-get private-address)" - juju-log "rabbitmq-server: Returning credentials for $rabbit_user@$remote_host" - relation-set password="$password" - - if is_clustered ; then - relation-set clustered="true" vip="$(config-get vip)" - fi -} - -function cluster_joined { - local remote_unit_id=$(echo $JUJU_REMOTE_UNIT | cut -d/ -f2) - local local_unit_id=$(echo $JUJU_UNIT_NAME | cut -d/ -f2) - [[ $local_unit_id -gt $remote_unit_id ]] && echo "Relation greater" && exit 0 - if [[ ! -e $ERLANG_COOKIE ]] ; then - juju-log "rabbitmq-server: ERROR Could not find cookie at $ERLANG_COOKIE" - exit 1 - fi - relation-set cookie="$(cat $ERLANG_COOKIE)" host="$(hostname)" -} - -function cluster_changed { - local remote_unit_id=$(echo $JUJU_REMOTE_UNIT | cut -d/ -f2) - local local_unit_id=$(echo $JUJU_UNIT_NAME | cut -d/ -f2) - - [[ $local_unit_id -lt $remote_unit_id ]] && echo "Relation lesser" && exit 0 - - local remote_host=$(relation-get host) - local cookie_value=$(relation-get cookie) - - [[ -z "$remote_host" ]] || [[ -z "$cookie_value" ]] && \ - juju-log "rabbimtq-server: remote_host||cookie_value not yet set." && - exit 0 - - # Sync the erlang cookie to that of remote host. - service rabbitmq-server stop - echo -n "$cookie_value" > $ERLANG_COOKIE - service rabbitmq-server start - - # Configure clustering. - # rabbitmq apparently does not like FQDNs. - local short_host=$(echo $remote_host | sed -e 's/\./ /g' | awk '{ print $1 }') - local cur_vers=$(rabbit_version) - local cluster_cmd="cluster" - if dpkg --compare-versions "$cur_vers" ge "3.0.1-1" ; then - cluster_cmd="join_cluster" - fi - if ! rabbitmqctl cluster_status | grep -q "rabbit@$short_host" ; then - juju-log "Clustering with new rabbitmq peer @ $short_host." - rabbitmqctl stop_app - rabbitmqctl $cluster_cmd rabbit@$short_host - rabbitmqctl start_app - else - juju-log "Already clustered with rabbitmq peer @ $short_host." - fi -} - -function ha_joined() { - local corosync_bindiface=`config-get ha-bindiface` - local corosync_mcastport=`config-get ha-mcastport` - local vip=`config-get vip` - local vip_iface=`config-get vip_iface` - local vip_cidr=`config-get vip_cidr` - if [ -n "$vip" ] && [ -n "$vip_iface" ] && \ - [ -n "$vip_cidr" ] && [ -n "$corosync_bindiface" ] && \ - [ -n "$corosync_mcastport" ]; then - # TODO: This feels horrible but the data required by the hacluster - # charm is quite complex and is python ast parsed. - resources="{ -'res_rabbitmq_vip':'ocf:heartbeat:IPaddr2' -}" - resource_params="{ -'res_rabbitmq_vip': 'params ip=\"$vip\" cidr_netmask=\"$vip_cidr\" nic=\"$vip_iface\"' -}" - relation-set corosync_bindiface=$corosync_bindiface \ - corosync_mcastport=$corosync_mcastport \ - resources="$resources" resource_params="$resource_params" - else - juju-log "Insufficient configuration data to configure hacluster" - exit 1 - fi -} - -function ha_changed() { - # we may now be clustered, advertise our vip to clients if so. - if is_clustered ; then - local vip="$(config-get vip)" - juju-log "$CHARM - ha_changed(): We are now HA clustered. "\ - "Advertising our VIP ($vip) to all AMQP clients." - for rid in $(relation-ids amqp) ; do - relation-set -r $rid clustered="true" vip="$vip" - done - fi -} - -case $ARG0 in - "install") install_hook ;; - "start") service rabbitmq-server status || service rabbitmq-server start ;; - "stop") service rabbitmq-server status && service rabbitmq-server stop ;; - "amqp-relation-joined") exit 0 ;; - "amqp-relation-changed") amqp_changed ;; - "cluster-relation-joined") cluster_joined ;; - "cluster-relation-changed") cluster_changed ;; - "ha-relation-joined") ha_joined ;; - "ha-relation-changed") ha_changed ;; -esac - -rc=$? -juju-log "rabbitmq-server: Hook $ARG0 complete. Exiting $rc" -exit $rc diff --git a/hooks/rabbitmq-server-relations.py b/hooks/rabbitmq-server-relations.py new file mode 100755 index 00000000..647bdaea --- /dev/null +++ b/hooks/rabbitmq-server-relations.py @@ -0,0 +1,142 @@ +#!/usr/bin/python + +import rabbit_utils as rabbit +import utils + +import os +import sys +import subprocess + +def install(): + utils.install(*rabbit.PACKAGES) + utils.expose(5672) + +def amqp_changed(): + l_unit_no=os.getenv('JUJU_UNIT_NAME').split('/')[1] + r_unit_no=None + for rid in utils.relation_ids('cluster'): + for unit in utils.relation_list(rid): + r_unit_no = unit.split('/')[1] + if l_unit_no > r_unit_no: + msg = 'amqp_changed(): Deferring amqp_changed to leader.' + utils.juju_log('INFO', msg) + return + + rabbit_user=utils.relation_get('username') + vhost=utils.relation_get('vhost') + if None in [rabbit_user, vhost]: + utils.juju_log('INFO', 'amqp_changed(): Relation not ready.') + return + + password_file = '/var/lib/juju/%s.passwd' % rabbit_user + if os.path.exists(password_file): + password = open(password_file).read().strip() + else: + cmd = ['pwgen', '64', '1'] + password = subprocess.check_output(cmd).strip() + with open(password_file, 'wb') as out: + out.write(password) + + rabbit.create_vhost(vhost) + rabbit.create_user(rabbit_user, password) + rabbit.grant_permissions(rabbit_user, vhost) + + relation_settings = { + 'password': password + } + if utils.is_clustered(): + relation_settings['clustered'] = 'true' + relation_settings['vip'] = utils.config_get('vip') + utils.relation_set(**relation_settings) + + +def cluster_joined(): + l_unit_no = os.getenv('JUJU_UNIT_NAME').split('/')[1] + r_unit_no = os.getenv('JUJU_REMOTE_UNIT').split('/')[1] + if l_unit_no > r_unit_no: + utils.juju_log('INFO', 'cluster_joined: Relation greater.') + return + rabbit.COOKIE_PATH = '/var/lib/rabbitmq/.erlang.cookie' + if not os.path.isfile(rabbit.COOKIE_PATH): + utils.juju_log('ERROR', 'erlang cookie missing from %s' %\ + rabbit.COOKIE_PATH) + cookie = open(rabbit.COOKIE_PATH, 'r').read().strip() + local_hostname = subprocess.check_output(['hostname']).strip() + utils.relation_set(cookie=cookie, host=local_hostname) + + +def cluster_changed(): + l_unit_no = os.getenv('JUJU_UNIT_NAME').split('/')[1] + r_unit_no = os.getenv('JUJU_REMOTE_UNIT').split('/')[1] + if l_unit_no < r_unit_no: + utils.juju_log('INFO', 'cluster_joined: Relation lesser.') + return + + remote_host = utils.relation_get('host') + cookie = utils.relation_get('cookie') + if None in [remote_host, cookie]: + utils.juju_log('INFO', + 'cluster_joined: remote_host|cookie not yet set.') + return + + if open(rabbit.COOKIE_PATH, 'r').read().strip() == cookie: + utils.juju_log('INFO', 'Cookie already synchronized with peer.') + return + + utils.juju_log('INFO', 'Synchronizing erlang cookie from peer.') + rabbit.service('stop') + with open(rabbit.COOKIE_PATH, 'wb') as out: + out.write(cookie) + rabbit.service('start') + rabbit.cluster_with(remote_host) + + +def ha_joined(): + config = {} + corosync_bindiface = utils.config_get('ha-bindiface') + corosync_mcastport = utils.config_get('ha-mcastport') + vip = utils.config_get('vip') + vip_iface = utils.config_get('vip_iface') + vip_cidr = utils.config_get('vip_cidr') + if None in [corosync_bindiface, corosync_mcastport, vip, vip_iface, + vip_cidr]: + utils.juju_log('ERROR', 'Insufficient configuration data to '\ + 'configure hacluster.') + sys.exit(1) + + relation_settings = {} + relation_settings['corosync_bindiface'] = corosync_bindiface + relation_settings['corosync_mcastport'] = corosync_mcastport + relation_settings['resources'] = { + 'res_rabbitmq_vip': 'ocf:heartbeat:IPaddr2' + } + relation_settings['resource_params'] = { + 'res_rabbitmq_vip': ('params ip="%s" cider_netmask="%s" nic="%s"' %\ + (vip, vip_cidr, vip_iface)) + } + utils.relation_set(**relation_settings) + + +def ha_changed(): + if not utils.is_clustered: + return + vip = utils.config_get('vip') + utils.juju_log('INFO', 'ha_changed(): We are now HA clustered. '\ + 'Advertising our VIP (%s) to all AMQP clients.' %\ + vip) + relation_settings = {'vip': vip, 'clustered': 'true'} + for rid in utils.relation_ids('amqp'): + relation_settings['rid'] = rid + utils.relation_set(**relation_settings) + + +hooks = { + 'install': install, + 'amqp-relation-changed': amqp_changed, + 'cluster-relation-joined': cluster_joined, + 'cluster-relation-changed': cluster_changed, + 'ha-relation-joined': ha_joined, + 'ha-relation-changed': ha_changed, +} + +utils.do_hooks(hooks) diff --git a/hooks/start b/hooks/start deleted file mode 120000 index 564b83a1..00000000 --- a/hooks/start +++ /dev/null @@ -1 +0,0 @@ -rabbitmq-relations \ No newline at end of file diff --git a/hooks/stop b/hooks/stop deleted file mode 120000 index 564b83a1..00000000 --- a/hooks/stop +++ /dev/null @@ -1 +0,0 @@ -rabbitmq-relations \ No newline at end of file diff --git a/hooks/utils.py b/hooks/utils.py new file mode 100644 index 00000000..d0a998bc --- /dev/null +++ b/hooks/utils.py @@ -0,0 +1,147 @@ + +# +# Copyright 2012 Canonical Ltd. +# +# Authors: +# James Page +# Paul Collins +# + +import os +import subprocess +import socket +import sys + + +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' + + +def expose(port, protocol='TCP'): + cmd = [ + 'open-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 is_clustered(): + for r_id in (relation_ids('ha') or []): + for unit in (relation_list(r_id) or []): + relation_data = \ + relation_get_dict(relation_id=r_id, + remote_unit=unit) + if 'clustered' in relation_data: + return True + return False + + +def is_leader(): + status = execute('crm resource show res_ks_vip', echo=True)[0].strip() + hostname = execute('hostname', echo=True)[0].strip() + if hostname in status: + return True + else: + return False diff --git a/revision b/revision index 04f9fe46..abdfb053 100644 --- a/revision +++ b/revision @@ -1 +1 @@ -59 +60