diff --git a/.pydevproject b/.pydevproject
index 7be6617b..984673a8 100644
--- a/.pydevproject
+++ b/.pydevproject
@@ -4,6 +4,5 @@
Default
/rabbitmq-server/hooks
-/rabbitmq-server/lib
diff --git a/Makefile b/Makefile
index d7aea1a5..5026b768 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
PYTHON := /usr/bin/env python
lint:
- @flake8 --exclude lib/charmhelpers hooks
+ @flake8 --exclude hooks/charmhelpers hooks
@charm proof
sync:
diff --git a/charm-helpers.yaml b/charm-helpers.yaml
index 1f1fbc1e..647a564e 100644
--- a/charm-helpers.yaml
+++ b/charm-helpers.yaml
@@ -1,4 +1,4 @@
-destination: lib/charmhelpers
+destination: hooks/charmhelpers
branch: lp:~openstack-charmers/charm-helpers/ssl-everywhere
include:
- fetch
@@ -7,3 +7,4 @@ include:
- contrib.openstack
- contrib.storage
- contrib.ssl
+ - contrib.hahelpers.cluster
diff --git a/lib/charmhelpers/__init__.py b/hooks/charmhelpers/__init__.py
similarity index 100%
rename from lib/charmhelpers/__init__.py
rename to hooks/charmhelpers/__init__.py
diff --git a/lib/charmhelpers/contrib/__init__.py b/hooks/charmhelpers/contrib/__init__.py
similarity index 100%
rename from lib/charmhelpers/contrib/__init__.py
rename to hooks/charmhelpers/contrib/__init__.py
diff --git a/lib/charmhelpers/contrib/charmsupport/__init__.py b/hooks/charmhelpers/contrib/charmsupport/__init__.py
similarity index 100%
rename from lib/charmhelpers/contrib/charmsupport/__init__.py
rename to hooks/charmhelpers/contrib/charmsupport/__init__.py
diff --git a/lib/charmhelpers/contrib/charmsupport/nrpe.py b/hooks/charmhelpers/contrib/charmsupport/nrpe.py
similarity index 100%
rename from lib/charmhelpers/contrib/charmsupport/nrpe.py
rename to hooks/charmhelpers/contrib/charmsupport/nrpe.py
diff --git a/lib/charmhelpers/contrib/charmsupport/volumes.py b/hooks/charmhelpers/contrib/charmsupport/volumes.py
similarity index 100%
rename from lib/charmhelpers/contrib/charmsupport/volumes.py
rename to hooks/charmhelpers/contrib/charmsupport/volumes.py
diff --git a/lib/charmhelpers/contrib/openstack/__init__.py b/hooks/charmhelpers/contrib/hahelpers/__init__.py
similarity index 100%
rename from lib/charmhelpers/contrib/openstack/__init__.py
rename to hooks/charmhelpers/contrib/hahelpers/__init__.py
diff --git a/hooks/charmhelpers/contrib/hahelpers/cluster.py b/hooks/charmhelpers/contrib/hahelpers/cluster.py
new file mode 100644
index 00000000..bf832f7d
--- /dev/null
+++ b/hooks/charmhelpers/contrib/hahelpers/cluster.py
@@ -0,0 +1,183 @@
+#
+# Copyright 2012 Canonical Ltd.
+#
+# Authors:
+# James Page
+# Adam Gandelman
+#
+
+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_apache_port(public_port):
+ '''
+ Description: Determine correct apache listening port based on public IP +
+ state of the cluster.
+
+ public_port: int: standard public port for given service
+
+ returns: int: the correct listening port for the HAProxy service
+ '''
+ i = 0
+ if len(peer_units()) > 0 or is_clustered():
+ 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)
diff --git a/lib/charmhelpers/contrib/storage/__init__.py b/hooks/charmhelpers/contrib/openstack/__init__.py
similarity index 100%
rename from lib/charmhelpers/contrib/storage/__init__.py
rename to hooks/charmhelpers/contrib/openstack/__init__.py
diff --git a/lib/charmhelpers/contrib/openstack/alternatives.py b/hooks/charmhelpers/contrib/openstack/alternatives.py
similarity index 100%
rename from lib/charmhelpers/contrib/openstack/alternatives.py
rename to hooks/charmhelpers/contrib/openstack/alternatives.py
diff --git a/lib/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py
similarity index 100%
rename from lib/charmhelpers/contrib/openstack/context.py
rename to hooks/charmhelpers/contrib/openstack/context.py
diff --git a/lib/charmhelpers/contrib/openstack/neutron.py b/hooks/charmhelpers/contrib/openstack/neutron.py
similarity index 100%
rename from lib/charmhelpers/contrib/openstack/neutron.py
rename to hooks/charmhelpers/contrib/openstack/neutron.py
diff --git a/lib/charmhelpers/contrib/openstack/templates/__init__.py b/hooks/charmhelpers/contrib/openstack/templates/__init__.py
similarity index 100%
rename from lib/charmhelpers/contrib/openstack/templates/__init__.py
rename to hooks/charmhelpers/contrib/openstack/templates/__init__.py
diff --git a/lib/charmhelpers/contrib/openstack/templating.py b/hooks/charmhelpers/contrib/openstack/templating.py
similarity index 100%
rename from lib/charmhelpers/contrib/openstack/templating.py
rename to hooks/charmhelpers/contrib/openstack/templating.py
diff --git a/lib/charmhelpers/contrib/openstack/utils.py b/hooks/charmhelpers/contrib/openstack/utils.py
similarity index 100%
rename from lib/charmhelpers/contrib/openstack/utils.py
rename to hooks/charmhelpers/contrib/openstack/utils.py
diff --git a/lib/charmhelpers/contrib/ssl/__init__.py b/hooks/charmhelpers/contrib/ssl/__init__.py
similarity index 100%
rename from lib/charmhelpers/contrib/ssl/__init__.py
rename to hooks/charmhelpers/contrib/ssl/__init__.py
diff --git a/lib/charmhelpers/contrib/ssl/service.py b/hooks/charmhelpers/contrib/ssl/service.py
similarity index 100%
rename from lib/charmhelpers/contrib/ssl/service.py
rename to hooks/charmhelpers/contrib/ssl/service.py
diff --git a/lib/charmhelpers/contrib/storage/linux/__init__.py b/hooks/charmhelpers/contrib/storage/__init__.py
similarity index 100%
rename from lib/charmhelpers/contrib/storage/linux/__init__.py
rename to hooks/charmhelpers/contrib/storage/__init__.py
diff --git a/lib/charmhelpers/core/__init__.py b/hooks/charmhelpers/contrib/storage/linux/__init__.py
similarity index 100%
rename from lib/charmhelpers/core/__init__.py
rename to hooks/charmhelpers/contrib/storage/linux/__init__.py
diff --git a/lib/charmhelpers/contrib/storage/linux/ceph.py b/hooks/charmhelpers/contrib/storage/linux/ceph.py
similarity index 100%
rename from lib/charmhelpers/contrib/storage/linux/ceph.py
rename to hooks/charmhelpers/contrib/storage/linux/ceph.py
diff --git a/lib/charmhelpers/contrib/storage/linux/loopback.py b/hooks/charmhelpers/contrib/storage/linux/loopback.py
similarity index 100%
rename from lib/charmhelpers/contrib/storage/linux/loopback.py
rename to hooks/charmhelpers/contrib/storage/linux/loopback.py
diff --git a/lib/charmhelpers/contrib/storage/linux/lvm.py b/hooks/charmhelpers/contrib/storage/linux/lvm.py
similarity index 100%
rename from lib/charmhelpers/contrib/storage/linux/lvm.py
rename to hooks/charmhelpers/contrib/storage/linux/lvm.py
diff --git a/lib/charmhelpers/contrib/storage/linux/utils.py b/hooks/charmhelpers/contrib/storage/linux/utils.py
similarity index 100%
rename from lib/charmhelpers/contrib/storage/linux/utils.py
rename to hooks/charmhelpers/contrib/storage/linux/utils.py
diff --git a/hooks/charmhelpers/core/__init__.py b/hooks/charmhelpers/core/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/lib/charmhelpers/core/hookenv.py b/hooks/charmhelpers/core/hookenv.py
similarity index 100%
rename from lib/charmhelpers/core/hookenv.py
rename to hooks/charmhelpers/core/hookenv.py
diff --git a/lib/charmhelpers/core/host.py b/hooks/charmhelpers/core/host.py
similarity index 100%
rename from lib/charmhelpers/core/host.py
rename to hooks/charmhelpers/core/host.py
diff --git a/lib/charmhelpers/fetch/__init__.py b/hooks/charmhelpers/fetch/__init__.py
similarity index 100%
rename from lib/charmhelpers/fetch/__init__.py
rename to hooks/charmhelpers/fetch/__init__.py
diff --git a/lib/charmhelpers/fetch/archiveurl.py b/hooks/charmhelpers/fetch/archiveurl.py
similarity index 100%
rename from lib/charmhelpers/fetch/archiveurl.py
rename to hooks/charmhelpers/fetch/archiveurl.py
diff --git a/lib/charmhelpers/fetch/bzrurl.py b/hooks/charmhelpers/fetch/bzrurl.py
similarity index 100%
rename from lib/charmhelpers/fetch/bzrurl.py
rename to hooks/charmhelpers/fetch/bzrurl.py
diff --git a/hooks/lib/ceph_utils.py b/hooks/lib/ceph_utils.py
deleted file mode 100644
index 150af5ab..00000000
--- a/hooks/lib/ceph_utils.py
+++ /dev/null
@@ -1,320 +0,0 @@
-#
-# Copyright 2012 Canonical Ltd.
-#
-# This file is sourced from lp:openstack-charm-helpers
-#
-# Authors:
-# James Page
-# Adam Gandelman
-#
-
-import commands
-import json
-import subprocess
-import os
-import shutil
-import time
-import lib.utils as utils
-
-KEYRING = '/etc/ceph/ceph.client.%s.keyring'
-KEYFILE = '/etc/ceph/ceph.client.%s.key'
-
-CEPH_CONF = """[global]
- auth supported = %(auth)s
- keyring = %(keyring)s
- mon host = %(mon_hosts)s
- log to syslog = %(use_syslog)s
- err to syslog = %(use_syslog)s
- clog to syslog = %(use_syslog)s
-"""
-
-
-def execute(cmd):
- subprocess.check_call(cmd)
-
-
-def execute_shell(cmd):
- subprocess.check_call(cmd, shell=True)
-
-
-def install():
- ceph_dir = "/etc/ceph"
- if not os.path.isdir(ceph_dir):
- os.mkdir(ceph_dir)
- utils.install('ceph-common')
-
-
-def rbd_exists(service, pool, rbd_img):
- (rc, out) = commands.getstatusoutput('rbd list --id %s --pool %s' %
- (service, pool))
- return rbd_img in out
-
-
-def create_rbd_image(service, pool, image, sizemb):
- cmd = [
- 'rbd',
- 'create',
- image,
- '--size',
- str(sizemb),
- '--id',
- service,
- '--pool',
- pool]
- execute(cmd)
-
-
-def pool_exists(service, name):
- (rc, out) = commands.getstatusoutput("rados --id %s lspools" % service)
- return name in out
-
-
-def ceph_version():
- ''' Retrieve the local version of ceph '''
- if os.path.exists('/usr/bin/ceph'):
- cmd = ['ceph', '-v']
- output = subprocess.check_output(cmd)
- output = output.split()
- if len(output) > 3:
- return output[2]
- else:
- return None
- else:
- return None
-
-
-def get_osds(service):
- '''
- Return a list of all Ceph Object Storage Daemons
- currently in the cluster
- '''
- version = ceph_version()
- if version and version >= '0.56':
- cmd = ['ceph', '--id', service, 'osd', 'ls', '--format=json']
- return json.loads(subprocess.check_output(cmd))
- else:
- return None
-
-
-def create_pool(service, name, replicas=2):
- ''' Create a new RADOS pool '''
- if pool_exists(service, name):
- utils.juju_log('WARNING',
- "Ceph pool {} already exists, "
- "skipping creation".format(name))
- return
-
- osds = get_osds(service)
- if osds:
- pgnum = (len(osds) * 100 / replicas)
- else:
- # NOTE(james-page): Default to 200 for older ceph versions
- # which don't support OSD query from cli
- pgnum = 200
-
- cmd = [
- 'ceph', '--id', service,
- 'osd', 'pool', 'create',
- name, str(pgnum)
- ]
- subprocess.check_call(cmd)
- cmd = [
- 'ceph', '--id', service,
- 'osd', 'pool', 'set', name,
- 'size', str(replicas)
- ]
- subprocess.check_call(cmd)
-
-
-def keyfile_path(service):
- return KEYFILE % service
-
-
-def keyring_path(service):
- return KEYRING % service
-
-
-def create_keyring(service, key):
- keyring = keyring_path(service)
- if os.path.exists(keyring):
- utils.juju_log('INFO', 'ceph: Keyring exists at %s.' % keyring)
- cmd = [
- 'ceph-authtool',
- keyring,
- '--create-keyring',
- '--name=client.%s' % service,
- '--add-key=%s' % key]
- execute(cmd)
- utils.juju_log('INFO', 'ceph: Created new ring at %s.' % keyring)
-
-
-def create_key_file(service, key):
- # create a file containing the key
- keyfile = keyfile_path(service)
- if os.path.exists(keyfile):
- utils.juju_log('INFO', 'ceph: Keyfile exists at %s.' % keyfile)
- fd = open(keyfile, 'w')
- fd.write(key)
- fd.close()
- utils.juju_log('INFO', 'ceph: Created new keyfile at %s.' % keyfile)
-
-
-def get_ceph_nodes():
- hosts = []
- for r_id in utils.relation_ids('ceph'):
- for unit in utils.relation_list(r_id):
- ceph_public_addr = utils.relation_get(
- 'ceph_public_addr', unit=unit, rid=r_id) or \
- utils.relation_get('private-address', unit=unit, rid=r_id)
- hosts.append(ceph_public_addr)
- return hosts
-
-
-def configure(service, key, auth, use_syslog):
- create_keyring(service, key)
- create_key_file(service, key)
- hosts = get_ceph_nodes()
- mon_hosts = ",".join(map(str, hosts))
- keyring = keyring_path(service)
- with open('/etc/ceph/ceph.conf', 'w') as ceph_conf:
- ceph_conf.write(CEPH_CONF % locals())
- modprobe_kernel_module('rbd')
-
-
-def image_mapped(image_name):
- (rc, out) = commands.getstatusoutput('rbd showmapped')
- return image_name in out
-
-
-def map_block_storage(service, pool, image):
- cmd = [
- 'rbd',
- 'map',
- '%s/%s' % (pool, image),
- '--user',
- service,
- '--secret',
- keyfile_path(service)]
- execute(cmd)
-
-
-def filesystem_mounted(fs):
- return subprocess.call(['grep', '-wqs', fs, '/proc/mounts']) == 0
-
-
-def make_filesystem(blk_device, fstype='ext4'):
- count = 0
- e_noent = os.errno.ENOENT
- while not os.path.exists(blk_device):
- if count >= 10:
- utils.juju_log('ERROR',
- 'ceph: gave up waiting on block device %s' %
- blk_device)
- raise IOError(e_noent, os.strerror(e_noent), blk_device)
- utils.juju_log('INFO',
- 'ceph: waiting for block device %s to appear' %
- blk_device)
- count += 1
- time.sleep(1)
- else:
- utils.juju_log('INFO',
- 'ceph: Formatting block device %s as filesystem %s.' %
- (blk_device, fstype))
- execute(['mkfs', '-t', fstype, blk_device])
-
-
-def place_data_on_ceph(service, blk_device, data_src_dst, fstype='ext4'):
- # mount block device into /mnt
- cmd = ['mount', '-t', fstype, blk_device, '/mnt']
- execute(cmd)
-
- # copy data to /mnt
- try:
- copy_files(data_src_dst, '/mnt')
- except:
- pass
-
- # umount block device
- cmd = ['umount', '/mnt']
- execute(cmd)
-
- _dir = os.stat(data_src_dst)
- uid = _dir.st_uid
- gid = _dir.st_gid
-
- # re-mount where the data should originally be
- cmd = ['mount', '-t', fstype, blk_device, data_src_dst]
- execute(cmd)
-
- # ensure original ownership of new mount.
- cmd = ['chown', '-R', '%s:%s' % (uid, gid), data_src_dst]
- execute(cmd)
-
-
-# TODO: re-use
-def modprobe_kernel_module(module):
- utils.juju_log('INFO', 'Loading kernel module')
- cmd = ['modprobe', module]
- execute(cmd)
- cmd = 'echo %s >> /etc/modules' % module
- execute_shell(cmd)
-
-
-def copy_files(src, dst, symlinks=False, ignore=None):
- for item in os.listdir(src):
- s = os.path.join(src, item)
- d = os.path.join(dst, item)
- if os.path.isdir(s):
- shutil.copytree(s, d, symlinks, ignore)
- else:
- shutil.copy2(s, d)
-
-
-def ensure_ceph_storage(service, pool, rbd_img, sizemb, mount_point,
- blk_device, fstype, system_services=[],
- rbd_pool_replicas=2):
- """
- To be called from the current cluster leader.
- Ensures given pool and RBD image exists, is mapped to a block device,
- and the device is formatted and mounted at the given mount_point.
-
- If formatting a device for the first time, data existing at mount_point
- will be migrated to the RBD device before being remounted.
-
- All services listed in system_services will be stopped prior to data
- migration and restarted when complete.
- """
- # Ensure pool, RBD image, RBD mappings are in place.
- if not pool_exists(service, pool):
- utils.juju_log('INFO', 'ceph: Creating new pool %s.' % pool)
- create_pool(service, pool, replicas=rbd_pool_replicas)
-
- if not rbd_exists(service, pool, rbd_img):
- utils.juju_log('INFO', 'ceph: Creating RBD image (%s).' % rbd_img)
- create_rbd_image(service, pool, rbd_img, sizemb)
-
- if not image_mapped(rbd_img):
- utils.juju_log('INFO', 'ceph: Mapping RBD Image as a Block Device.')
- map_block_storage(service, pool, rbd_img)
-
- # make file system
- # TODO: What happens if for whatever reason this is run again and
- # the data is already in the rbd device and/or is mounted??
- # When it is mounted already, it will fail to make the fs
- # XXX: This is really sketchy! Need to at least add an fstab entry
- # otherwise this hook will blow away existing data if its executed
- # after a reboot.
- if not filesystem_mounted(mount_point):
- make_filesystem(blk_device, fstype)
-
- for svc in system_services:
- if utils.running(svc):
- utils.juju_log('INFO',
- 'Stopping services %s prior to migrating '
- 'data' % svc)
- utils.stop(svc)
-
- place_data_on_ceph(service, blk_device, mount_point, fstype)
-
- for svc in system_services:
- utils.start(svc)
diff --git a/hooks/lib/cluster_utils.py b/hooks/lib/cluster_utils.py
deleted file mode 100644
index 534acb3b..00000000
--- a/hooks/lib/cluster_utils.py
+++ /dev/null
@@ -1,128 +0,0 @@
-#
-# Copyright 2012 Canonical Ltd.
-#
-# This file is sourced from lp:openstack-charm-helpers
-#
-# Authors:
-# James Page
-# Adam Gandelman
-#
-
-from lib.utils import (
- juju_log,
- relation_ids,
- relation_list,
- relation_get,
- get_unit_hostname,
- config_get)
-import subprocess
-import os
-
-
-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 = os.getenv('JUJU_UNIT_NAME').split('/')[1]
- for peer in peers:
- remote_unit_no = 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):
- juju_log('INFO', 'Deferring action to CRM leader.')
- return False
- else:
- peers = peer_units()
- if peers and not oldest_peer(peers):
- juju_log('INFO', 'Deferring action to oldest service unit.')
- 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):
- if (relation_get('https_keystone', rid=r_id, unit=unit) and
- relation_get('ssl_cert', rid=r_id, unit=unit) and
- relation_get('ssl_key', rid=r_id, unit=unit) and
- relation_get('ca_cert', rid=r_id, unit=unit)):
- 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)
diff --git a/hooks/lib/openstack_common.py b/hooks/lib/openstack_common.py
deleted file mode 100644
index b897e5ec..00000000
--- a/hooks/lib/openstack_common.py
+++ /dev/null
@@ -1,230 +0,0 @@
-#!/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.
- """
- charm_dir = os.getenv('CHARM_DIR')
- juju_rc_path = "%s/%s" % (charm_dir, 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/lib/unison.py b/hooks/lib/unison.py
deleted file mode 100755
index 44657194..00000000
--- a/hooks/lib/unison.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/usr/bin/python
-#
-# Easy file synchronization among peer units using ssh + unison.
-#
-# From *both* peer relation -joined and -changed, add a call to
-# ssh_authorized_peers() describing the peer relation and the desired
-# user + group. After all peer relations have settled, all hosts should
-# be able to connect to on another via key auth'd ssh as the specified user.
-#
-# Other hooks are then free to synchronize files and directories using
-# sync_to_peers().
-#
-# For a peer relation named 'cluster', for example:
-#
-# cluster-relation-joined:
-# ...
-# ssh_authorized_peers(peer_interface='cluster',
-# user='juju_ssh', group='juju_ssh',
-# ensure_user=True)
-# ...
-#
-# cluster-relation-changed:
-# ...
-# ssh_authorized_peers(peer_interface='cluster',
-# user='juju_ssh', group='juju_ssh',
-# ensure_user=True)
-# ...
-#
-# Hooks are now free to sync files as easily as:
-#
-# files = ['/etc/fstab', '/etc/apt.conf.d/']
-# sync_to_peers(peer_interface='cluster',
-# user='juju_ssh, paths=[files])
-#
-# It is assumed the charm itself has setup permissions on each unit
-# such that 'juju_ssh' has read + write permissions. Also assumed
-# that the calling charm takes care of leader delegation.
-#
-# TODO: Currently depends on the utils.py shipped with the keystone charm.
-# Either copy required functionality to this library or depend on
-# something more generic.
-
-import os
-import sys
-import lib.utils as utils
-import subprocess
-import grp
-import pwd
-
-
-def get_homedir(user):
- try:
- user = pwd.getpwnam(user)
- return user.pw_dir
- except KeyError:
- utils.juju_log('INFO',
- 'Could not get homedir for user %s: user exists?')
- sys.exit(1)
-
-
-def get_keypair(user):
- home_dir = get_homedir(user)
- ssh_dir = os.path.join(home_dir, '.ssh')
- if not os.path.isdir(ssh_dir):
- os.mkdir(ssh_dir)
-
- priv_key = os.path.join(ssh_dir, 'id_rsa')
- if not os.path.isfile(priv_key):
- utils.juju_log('INFO', 'Generating new ssh key for user %s.' % user)
- cmd = ['ssh-keygen', '-q', '-N', '', '-t', 'rsa', '-b', '2048',
- '-f', priv_key]
- subprocess.check_call(cmd)
-
- pub_key = '%s.pub' % priv_key
- if not os.path.isfile(pub_key):
- utils.juju_log('INFO', 'Generatring missing ssh public key @ %s.' %
- pub_key)
- cmd = ['ssh-keygen', '-y', '-f', priv_key]
- p = subprocess.check_output(cmd).strip()
- with open(pub_key, 'wb') as out:
- out.write(p)
- subprocess.check_call(['chown', '-R', user, ssh_dir])
- return (open(priv_key, 'r').read().strip(),
- open(pub_key, 'r').read().strip())
-
-
-def write_authorized_keys(user, keys):
- home_dir = get_homedir(user)
- ssh_dir = os.path.join(home_dir, '.ssh')
- auth_keys = os.path.join(ssh_dir, 'authorized_keys')
- utils.juju_log('INFO', 'Syncing authorized_keys @ %s.' % auth_keys)
- with open(auth_keys, 'wb') as out:
- for k in keys:
- out.write('%s\n' % k)
-
-
-def write_known_hosts(user, hosts):
- home_dir = get_homedir(user)
- ssh_dir = os.path.join(home_dir, '.ssh')
- known_hosts = os.path.join(ssh_dir, 'known_hosts')
- khosts = []
- for host in hosts:
- cmd = ['ssh-keyscan', '-H', '-t', 'rsa', host]
- remote_key = subprocess.check_output(cmd).strip()
- khosts.append(remote_key)
- utils.juju_log('INFO', 'Syncing known_hosts @ %s.' % known_hosts)
- with open(known_hosts, 'wb') as out:
- for host in khosts:
- out.write('%s\n' % host)
-
-
-def ensure_user(user, group=None):
- # need to ensure a bash shell'd user exists.
- try:
- pwd.getpwnam(user)
- except KeyError:
- utils.juju_log('INFO', 'Creating new user %s.%s.' % (user, group))
- cmd = ['adduser', '--system', '--shell', '/bin/bash', user]
- if group:
- try:
- grp.getgrnam(group)
- except KeyError:
- subprocess.check_call(['addgroup', group])
- cmd += ['--ingroup', group]
- subprocess.check_call(cmd)
-
-
-def ssh_authorized_peers(peer_interface, user, group=None,
- ensure_local_user=False):
- """
- Main setup function, should be called from both peer -changed and -joined
- hooks with the same parameters.
- """
- if ensure_local_user:
- ensure_user(user, group)
- priv_key, pub_key = get_keypair(user)
- hook = os.path.basename(sys.argv[0])
- if hook == '%s-relation-joined' % peer_interface:
- utils.relation_set(ssh_pub_key=pub_key)
- print 'joined'
- elif hook == '%s-relation-changed' % peer_interface:
- hosts = []
- keys = []
- for r_id in utils.relation_ids(peer_interface):
- for unit in utils.relation_list(r_id):
- settings = utils.relation_get_dict(relation_id=r_id,
- remote_unit=unit)
- if 'ssh_pub_key' in settings:
- keys.append(settings['ssh_pub_key'])
- hosts.append(settings['private-address'])
- else:
- utils.juju_log('INFO',
- 'ssh_authorized_peers(): ssh_pub_key '
- 'missing for unit %s, skipping.' % unit)
- write_authorized_keys(user, keys)
- write_known_hosts(user, hosts)
- authed_hosts = ':'.join(hosts)
- utils.relation_set(ssh_authorized_hosts=authed_hosts)
-
-
-def _run_as_user(user):
- try:
- user = pwd.getpwnam(user)
- except KeyError:
- utils.juju_log('INFO', 'Invalid user: %s' % user)
- sys.exit(1)
- uid, gid = user.pw_uid, user.pw_gid
- os.environ['HOME'] = user.pw_dir
-
- def _inner():
- os.setgid(gid)
- os.setuid(uid)
- return _inner
-
-
-def run_as_user(user, cmd):
- return subprocess.check_output(cmd, preexec_fn=_run_as_user(user), cwd='/')
-
-
-def sync_to_peers(peer_interface, user, paths=[], verbose=False):
- base_cmd = ['unison', '-auto', '-batch=true', '-confirmbigdel=false',
- '-fastcheck=true', '-group=false', '-owner=false',
- '-prefer=newer', '-times=true']
- if not verbose:
- base_cmd.append('-silent')
-
- hosts = []
- for r_id in (utils.relation_ids(peer_interface) or []):
- for unit in utils.relation_list(r_id):
- settings = utils.relation_get_dict(relation_id=r_id,
- remote_unit=unit)
- try:
- authed_hosts = settings['ssh_authorized_hosts'].split(':')
- except KeyError:
- print 'unison sync_to_peers: peer has not authorized *any* '\
- 'hosts yet.'
- return
-
- unit_hostname = utils.unit_get('private-address')
- add_host = None
- for authed_host in authed_hosts:
- if unit_hostname == authed_host:
- add_host = settings['private-address']
- if add_host:
- hosts.append(settings['private-address'])
- else:
- print ('unison sync_to_peers: peer (%s) has not authorized '
- '*this* host yet, skipping.' %
- settings['private-address'])
-
- for path in paths:
- # removing trailing slash from directory paths, unison
- # doesn't like these.
- if path.endswith('/'):
- path = path[:(len(path) - 1)]
- for host in hosts:
- try:
- cmd = base_cmd + [path, 'ssh://%s@%s/%s' % (user, host, path)]
- utils.juju_log('INFO', 'Syncing local path %s to %s@%s:%s' %
- (path, user, host, path))
- run_as_user(user, cmd)
- except:
- # it may fail for permissions on some files
- pass
diff --git a/hooks/lib/utils.py b/hooks/lib/utils.py
index 1798c783..23f4e984 100644
--- a/hooks/lib/utils.py
+++ b/hooks/lib/utils.py
@@ -9,50 +9,26 @@
# Adam Gandelman
#
-import json
import grp
import os
import pwd
-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)
+from charmhelpers.fetch import (
+ apt_install
+)
+from charmhelpers.core.hookenv import (
+ local_unit,
+ remote_unit,
+ log
+)
TEMPLATES_DIR = 'templates'
try:
import jinja2
except ImportError:
- install('python-jinja2')
+ apt_install('python-jinja2', fatal=True)
import jinja2
-try:
- import dns.resolver
-except ImportError:
- install('python-dnspython')
- import dns.resolver
-
def render_template(template_name, context, template_dir=TEMPLATES_DIR):
templates = \
@@ -60,326 +36,45 @@ def render_template(template_name, context, template_dir=TEMPLATES_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 = {
- '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',
- 'havana': 'precise-updates/havana',
- 'havana/updates': 'precise-updates/havana',
- 'havana/proposed': 'precise-proposed/havana',
- 'icehouse': 'precise-updates/icehouse',
- 'icehouse/updates': 'precise-updates/icehouse',
- 'icehouse/proposed': 'precise-proposed/icehouse',
- }
-
-
-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:'):
- # CA values should be formatted as cloud:ubuntu-openstack/pocket, eg:
- # cloud:precise-folsom/updates or cloud:precise-folsom/proposed
- install('ubuntu-cloud-keyring')
- pocket = source.split(':')[1]
- pocket = pocket.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/quantum.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 open_port(port, protocol='TCP'):
- expose(port, protocol)
-
-
-def close_port(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)
-
-
-cache = {}
-
-
-def cached(func):
- def wrapper(*args, **kwargs):
- global cache
- key = str((func, args, kwargs))
- try:
- return cache[key]
- except KeyError:
- res = func(*args, **kwargs)
- cache[key] = res
- return res
- return wrapper
-
-
-@cached
-def relation_ids(relation):
- cmd = [
- 'relation-ids',
- relation]
- result = str(subprocess.check_output(cmd)).split()
- if result == "":
- return None
- else:
- return result
-
-
-@cached
-def relation_list(rid):
- cmd = [
- 'relation-list',
- '-r', rid]
- result = str(subprocess.check_output(cmd)).split()
- if result == "":
- return None
- else:
- return result
-
-
-@cached
-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
-
-
-@cached
-def relation_get_dict(relation_id=None, remote_unit=None):
- """Obtain all relation data as dict by way of JSON"""
- cmd = [
- 'relation-get', '--format=json']
- if relation_id:
- cmd.append('-r')
- cmd.append(relation_id)
- if remote_unit:
- cmd.append('-')
- cmd.append(remote_unit)
- j = subprocess.check_output(cmd)
- d = json.loads(j)
- settings = {}
- # convert unicode to strings
- for k, v in d.iteritems():
- settings[str(k)] = str(v)
- return settings
-
-
-def relation_set(**kwargs):
- cmd = [
- 'relation-set']
- args = []
- for k, v in kwargs.items():
- if k == 'rid':
- if v:
- cmd.append('-r')
- cmd.append(v)
- else:
- args.append('{}={}'.format(k, v))
- cmd += args
- subprocess.check_call(cmd)
-
-
-@cached
-def unit_get(attribute):
- cmd = [
- 'unit-get',
- attribute]
- value = subprocess.check_output(cmd).strip() # IGNORE:E1103
- if value == "":
- return None
- else:
- return value
-
-
-@cached
-def config_get(scope=None):
- """Juju charm configuration"""
- config_cmd_line = ['config-get']
- if scope is not None:
- config_cmd_line.append(scope)
- config_cmd_line.append('--format=json')
- try:
- return json.loads(subprocess.check_output(config_cmd_line))
- except ValueError:
- return None
-
-
-@cached
-def get_unit_hostname():
- return socket.gethostname()
-
-
-@cached
-def get_host_ip(hostname=unit_get('private-address')):
- try:
- # Test to see if already an IPv4 address
- socket.inet_aton(hostname)
- return hostname
- except socket.error:
- answers = dns.resolver.query(hostname, 'A')
- if answers:
- return answers[0].address
- return None
-
-
-def _svc_control(service, action):
- subprocess.check_call(['service', service, action])
-
-
-def restart(*services):
- for service in services:
- _svc_control(service, 'restart')
-
-
-def stop(*services):
- for service in services:
- _svc_control(service, 'stop')
-
-
-def start(*services):
- for service in services:
- _svc_control(service, 'start')
-
-
-def reload(*services):
- for service in services:
- try:
- _svc_control(service, 'reload')
- except subprocess.CalledProcessError:
- # Reload failed - either service does not support reload
- # or it was not running - restart will fixup most things
- _svc_control(service, 'restart')
-
-
-def running(service):
- try:
- output = subprocess.check_output(['service', service, 'status'])
- except subprocess.CalledProcessError:
- return False
- else:
- if ("start/running" in output or
- "is running" in output):
- return True
- else:
- return False
-
-
-def is_relation_made(relation, key='private-address'):
- for r_id in (relation_ids(relation) or []):
- for unit in (relation_list(r_id) or []):
- if relation_get(key, rid=r_id, unit=unit):
- return True
- return False
-
-
-def get_homedir(user):
- try:
- user = pwd.getpwnam(user)
- return user.pw_dir
- except KeyError:
- log('Could not get homedir for user %s: user exists?', ERROR)
- raise Exception
-
def is_newer():
- l_unit_no = os.getenv('JUJU_UNIT_NAME').split('/')[1]
- r_unit_no = os.getenv('JUJU_REMOTE_UNIT').split('/')[1]
+ l_unit_no = local_unit().split('/')[1]
+ r_unit_no = remote_unit().split('/')[1]
return (l_unit_no > r_unit_no)
def chown(path, owner='root', group='root', recursive=False):
"""Changes owner of given path, recursively if needed"""
if os.path.exists(path):
- juju_log('INFO', 'Changing ownership of path %s to %s:%s' %
- (path, owner, group))
+ log('Changing ownership of path %s to %s:%s' %
+ (path, owner, group))
uid = pwd.getpwnam(owner).pw_uid
gid = grp.getgrnam(group).gr_gid
if recursive:
- for root, dirs, files in os.walk(path):
- for dir in dirs:
- os.chown(os.path.join(root, dir), uid, gid)
- for file in files:
- os.chown(os.path.join(root, file), uid, gid)
+ for root, dirs, files in os.walk(path):
+ for d in dirs:
+ os.chown(os.path.join(root, d), uid, gid)
+ for f in files:
+ os.chown(os.path.join(root, f), uid, gid)
else:
os.chown(path, uid, gid)
else:
- juju_log('ERROR', '%s path does not exist' % path)
+ log('%s path does not exist' % path)
def chmod(path, perms, recursive=False):
"""Changes perms of given path, recursively if needed"""
if os.path.exists(path):
- juju_log('INFO', 'Changing perms of path %s ' % path)
+ log('Changing perms of path %s ' % path)
if recursive:
- for root, dirs, files in os.walk(path):
- for dir in dirs:
- os.chmod(os.path.join(root, dir), perms)
- for file in files:
- os.chmod(os.path.join(root, file), perms)
+ for root, dirs, files in os.walk(path):
+ for d in dirs:
+ os.chmod(os.path.join(root, d), perms)
+ for f in files:
+ os.chmod(os.path.join(root, f), perms)
else:
os.chmod(path, perms)
else:
- juju_log('ERROR', '%s path does not exist' % path)
+ log('ERROR', '%s path does not exist' % path)
diff --git a/hooks/rabbit_utils.py b/hooks/rabbit_utils.py
index 673c7d8d..02c567f5 100644
--- a/hooks/rabbit_utils.py
+++ b/hooks/rabbit_utils.py
@@ -1,22 +1,28 @@
import os
+import pwd
+import grp
import re
import sys
import subprocess
import glob
-import lib.utils as utils
+from lib.utils import render_template
import apt_pkg as apt
-import _pythonpath
-_ = _pythonpath
-
from charmhelpers.contrib.openstack.utils import (
get_hostname,
- error_out
)
-from charmhelpers.core.hookenv import config, relation_ids, relation_get, relation_set, local_unit
+from charmhelpers.core.hookenv import (
+ config,
+ relation_ids,
+ relation_get,
+ relation_set,
+ related_units,
+ local_unit,
+ log, ERROR
+)
-PACKAGES = ['pwgen', 'rabbitmq-server', 'python-amqplib']
+PACKAGES = ['rabbitmq-server', 'python-amqplib']
RABBITMQ_CTL = '/usr/sbin/rabbitmqctl'
COOKIE_PATH = '/var/lib/rabbitmq/.erlang.cookie'
@@ -32,7 +38,7 @@ def vhost_exists(vhost):
out = subprocess.check_output(cmd)
for line in out.split('\n')[1:]:
if line == vhost:
- utils.juju_log('INFO', 'vhost (%s) already exists.' % vhost)
+ log('vhost (%s) already exists.' % vhost)
return True
return False
except:
@@ -45,7 +51,7 @@ def create_vhost(vhost):
return
cmd = [RABBITMQ_CTL, 'add_vhost', vhost]
subprocess.check_call(cmd)
- utils.juju_log('INFO', 'Created new vhost (%s).' % vhost)
+ log('Created new vhost (%s).' % vhost)
def user_exists(user):
@@ -65,17 +71,17 @@ def create_user(user, password, admin=False):
if not exists:
cmd = [RABBITMQ_CTL, 'add_user', user, password]
subprocess.check_call(cmd)
- utils.juju_log('INFO', 'Created new user (%s).' % user)
+ log('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.')
+ log('Granting user (%s) admin access.')
else:
cmd = [RABBITMQ_CTL, 'set_user_tags', user]
- utils.juju_log('INFO', 'Revoking user (%s) admin access.')
+ log('Revoking user (%s) admin access.')
def grant_permissions(user, vhost):
@@ -102,13 +108,13 @@ def compare_version(base_version):
def cluster_with():
- utils.juju_log('INFO', 'Clustering with new node')
+ log('Clustering with new node')
if compare_version('3.0.1') >= 0:
cluster_cmd = 'join_cluster'
else:
cluster_cmd = 'cluster'
out = subprocess.check_output([RABBITMQ_CTL, 'cluster_status'])
- utils.juju_log('INFO', 'cluster status is %s' % str(out))
+ log('cluster status is %s' % str(out))
# check if node is already clustered
total_nodes = 1
@@ -120,32 +126,29 @@ def cluster_with():
total_nodes = len(running_nodes)
if total_nodes > 1:
- utils.juju_log('INFO', 'Node is already clustered, skipping')
+ log('Node is already clustered, skipping')
return False
# check all peers and try to cluster with them
available_nodes = []
- for r_id in (utils.relation_ids('cluster') or []):
- for unit in (utils.relation_list(r_id) or []):
- address = utils.relation_get('private-address',
- rid=r_id, unit=unit)
+ for r_id in relation_ids('cluster'):
+ for unit in related_units(r_id):
+ address = relation_get('private-address',
+ rid=r_id, unit=unit)
if address is not None:
node = get_hostname(address, fqdn=False)
available_nodes.append(node)
if len(available_nodes) == 0:
- utils.juju_log('INFO', 'No nodes available to cluster with')
+ log('No nodes available to cluster with')
return False
# iterate over all the nodes, join to the first available
num_tries = 0
for node in available_nodes:
- utils.juju_log('INFO',
- 'Clustering with remote'
- ' rabbit host (%s).' % node)
+ log('Clustering with remote rabbit host (%s).' % node)
if node in running_nodes:
- utils.juju_log('INFO',
- 'Host already clustered with %s.' % node)
+ log('Host already clustered with %s.' % node)
return False
try:
@@ -155,19 +158,18 @@ def cluster_with():
subprocess.check_call(cmd)
cmd = [RABBITMQ_CTL, 'start_app']
subprocess.check_call(cmd)
- utils.juju_log('INFO', 'Host clustered with %s.' % node)
+ log('Host clustered with %s.' % node)
if compare_version('3.0.1') >= 0:
cmd = [RABBITMQ_CTL, 'set_policy', 'HA',
'^(?!amq\.).*', '{"ha-mode": "all"}']
subprocess.check_call(cmd)
return True
except:
- utils.juju_log('INFO', 'Failed to cluster with %s.' % node)
+ log('Failed to cluster with %s.' % node)
# continue to the next node
num_tries += 1
if num_tries > config('max-cluster-tries'):
- utils.juju_log('ERROR',
- 'Max tries number exhausted, exiting')
+ log('Max tries number exhausted, exiting', level=ERROR)
raise
return False
@@ -181,11 +183,11 @@ def break_cluster():
subprocess.check_call(cmd)
cmd = [RABBITMQ_CTL, 'start_app']
subprocess.check_call(cmd)
- utils.juju_log('INFO', 'Cluster successfully broken.')
+ log('Cluster successfully broken.')
except:
# error, no nodes available for clustering
- utils.juju_log('ERROR', 'Error breaking rabbit cluster')
- sys.exit(1)
+ log('Error breaking rabbit cluster', level=ERROR)
+ raise
def set_node_name(name):
@@ -193,7 +195,7 @@ def set_node_name(name):
# rabbitmq.conf.d is not present on all releases, so use or create
# rabbitmq-env.conf instead.
if not os.path.isfile(ENV_CONF):
- utils.juju_log('INFO', '%s does not exist, creating.' % ENV_CONF)
+ log('%s does not exist, creating.' % ENV_CONF)
with open(ENV_CONF, 'wb') as out:
out.write('RABBITMQ_NODENAME=%s\n' % name)
return
@@ -207,8 +209,8 @@ def set_node_name(name):
out.append(line)
if not f:
out.append('RABBITMQ_NODENAME=%s\n' % name)
- utils.juju_log('INFO', 'Updating %s, RABBITMQ_NODENAME=%s' %
- (ENV_CONF, name))
+ log('Updating %s, RABBITMQ_NODENAME=%s' %
+ (ENV_CONF, name))
with open(ENV_CONF, 'wb') as conf:
conf.write(''.join(out))
@@ -257,7 +259,7 @@ def enable_ssl(ssl_key, ssl_cert, ssl_port,
continue
with open(path, 'w') as fh:
fh.write(contents)
- os.chmod(path, 0640)
+ os.chmod(path, 0o640)
os.chown(path, uid, gid)
data = {
@@ -272,7 +274,7 @@ def enable_ssl(ssl_key, ssl_cert, ssl_port,
data["ssl_ca_file"] = ssl_ca_file
with open(RABBITMQ_CONF, 'w') as rmq_conf:
- rmq_conf.write(utils.render_template(
+ rmq_conf.write(render_template(
os.path.basename(RABBITMQ_CONF), data))
@@ -307,7 +309,7 @@ def execute(cmd, die=False, echo=False):
rc = p.returncode
if die and rc != 0:
- utils.juju_log('INFO', "ERROR: command %s return non-zero.\n" % cmd)
+ log("command %s return non-zero." % cmd, level=ERROR)
return (stdout, stderr, rc)
@@ -315,13 +317,19 @@ def get_clustered_attribute(attribute_name):
cluster_rels = relation_ids('cluster')
if len(cluster_rels) > 0:
cluster_rid = cluster_rels[0]
- password = relation_get(attribute=attribute_name, rid=cluster_rid, unit=local_unit())
+ password = relation_get(
+ attribute=attribute_name,
+ rid=cluster_rid,
+ unit=local_unit())
return password
else:
return None
+
def set_clustered_attribute(attribute_name, value):
cluster_rels = relation_ids('cluster')
if len(cluster_rels) > 0:
cluster_rid = cluster_rels[0]
- relation_set(relation_id=cluster_rid, relation_settings={attribute_name: value})
+ relation_set(
+ relation_id=cluster_rid,
+ relation_settings={attribute_name: value})
diff --git a/hooks/rabbitmq_server_relations.py b/hooks/rabbitmq_server_relations.py
index 008e2763..d6caca9e 100755
--- a/hooks/rabbitmq_server_relations.py
+++ b/hooks/rabbitmq_server_relations.py
@@ -6,24 +6,45 @@ import sys
import subprocess
import glob
-
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
+from lib.utils import (
+ chown, chmod,
+ is_newer,
+)
+from charmhelpers.contrib.hahelpers.cluster import (
+ is_clustered,
+ eligible_leader
+)
-import _pythonpath
-_ = _pythonpath
+import charmhelpers.contrib.storage.linux.ceph as ceph
+from charmhelpers.contrib.openstack.utils import save_script_rc
from charmhelpers.fetch import (
add_source,
- apt_update)
-from charmhelpers.core import hookenv
-from charmhelpers.core.host import rsync, mkdir, pwgen
+ apt_update,
+ apt_install)
+
+from charmhelpers.core.hookenv import (
+ open_port, close_port,
+ log, ERROR,
+ relation_get,
+ relation_set,
+ relation_ids,
+ related_units,
+ local_unit,
+ config,
+ unit_get,
+ is_relation_made,
+ Hooks, UnregisteredHookError
+)
+from charmhelpers.core.host import (
+ rsync, pwgen,
+ service_stop, service_restart
+)
from charmhelpers.contrib.charmsupport.nrpe import NRPE
from charmhelpers.contrib.ssl.service import ServiceCA
+hooks = Hooks()
SERVICE_NAME = os.getenv('JUJU_UNIT_NAME').split('/')[0]
POOL_NAME = SERVICE_NAME
@@ -31,14 +52,15 @@ RABBIT_DIR = '/var/lib/rabbitmq'
NAGIOS_PLUGINS = '/usr/local/lib/nagios/plugins'
+@hooks.hook('install')
def install():
pre_install_hooks()
- add_source(utils.config_get('source'), utils.config_get('key'))
+ add_source(config('source'), config('key'))
apt_update(fatal=True)
- utils.install(*rabbit.PACKAGES)
- utils.expose(5672)
- utils.chown(RABBIT_DIR, rabbit.RABBIT_USER, rabbit.RABBIT_USER)
- utils.chmod(RABBIT_DIR, 0775)
+ apt_install(rabbit.PACKAGES, fatal=True)
+ open_port(5672)
+ chown(RABBIT_DIR, rabbit.RABBIT_USER, rabbit.RABBIT_USER)
+ chmod(RABBIT_DIR, 0o775)
def configure_amqp(username, vhost):
@@ -56,21 +78,22 @@ def configure_amqp(username, vhost):
return password
+
+@hooks.hook('amqp-relation-changed')
def amqp_changed(relation_id=None, remote_unit=None):
- if not cluster.eligible_leader('res_rabbitmq_vip'):
- utils.juju_log('INFO',
- 'amqp_changed(): Deferring amqp_changed'
- ' to eligible_leader.')
+ if not eligible_leader('res_rabbitmq_vip'):
+ log('amqp_changed(): Deferring amqp_changed'
+ ' to eligible_leader.')
return
relation_settings = {}
- settings = hookenv.relation_get(rid=relation_id, unit=remote_unit)
+ settings = relation_get(rid=relation_id, unit=remote_unit)
singleset = set(['username', 'vhost'])
if singleset.issubset(settings):
if None in [settings['username'], settings['vhost']]:
- utils.juju_log('INFO', 'amqp_changed(): Relation not ready.')
+ log('amqp_changed(): Relation not ready.')
return
relation_settings['password'] = configure_amqp(
@@ -88,133 +111,132 @@ def amqp_changed(relation_id=None, remote_unit=None):
if singleset.issubset(queues[amqp]):
relation_settings[
'_'.join([amqp, 'password'])] = configure_amqp(
- queues[amqp]['username'],
- queues[amqp]['vhost'])
+ queues[amqp]['username'],
+ queues[amqp]['vhost'])
- relation_settings['hostname'] = utils.unit_get('private-address')
+ relation_settings['hostname'] = unit_get('private-address')
configure_client_ssl(relation_settings)
- if cluster.is_clustered():
+ if is_clustered():
relation_settings['clustered'] = 'true'
- if utils.is_relation_made('ha'):
+ if is_relation_made('ha'):
# active/passive settings
- relation_settings['vip'] = utils.config_get('vip')
- relation_settings['ha-vip-only'] = utils.config_get('ha-vip-only')
+ relation_settings['vip'] = config('vip')
+ relation_settings['ha-vip-only'] = config('ha-vip-only')
if relation_id:
relation_settings['rid'] = relation_id
# set if need HA queues or not
relation_settings['ha_queues'] = (rabbit.compare_version('3.0.1') >= 0)
- utils.relation_set(**relation_settings)
+ relation_set(relation_settings=relation_settings)
+@hooks.hook('cluster-relation-joined')
def cluster_joined():
- if utils.is_relation_made('ha') and \
- utils.config_get('ha-vip-only') is False:
- utils.juju_log('INFO',
- 'hacluster relation is present, skipping native '
- 'rabbitmq cluster config.')
+ if is_relation_made('ha') and \
+ config('ha-vip-only') is False:
+ log('hacluster relation is present, skipping native '
+ 'rabbitmq cluster config.')
return
- if utils.is_newer():
- utils.juju_log('INFO', 'cluster_joined: Relation greater.')
+ if is_newer():
+ log('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)
+ log('erlang cookie missing from %s' % rabbit.COOKIE_PATH,
+ level=ERROR)
return
cookie = open(rabbit.COOKIE_PATH, 'r').read().strip()
rabbit.set_clustered_attribute('cookie', cookie)
+@hooks.hook('cluster-relation-changed')
def cluster_changed():
# sync passwords
- rdata = hookenv.relation_get()
+ rdata = relation_get()
echo_data = {}
for attribute, value in rdata.iteritems():
if '.passwd' in attribute or attribute == 'cookie':
echo_data[attribute] = value
if len(echo_data) > 0:
- hookenv.relation_set(relation_settings=echo_data)
+ relation_set(relation_settings=echo_data)
if 'cookie' not in echo_data:
- utils.juju_log('INFO',
- 'cluster_joined: cookie not yet set.')
+ log('cluster_joined: cookie not yet set.')
return
# sync cookie
cookie = echo_data['cookie']
if open(rabbit.COOKIE_PATH, 'r').read().strip() == cookie:
- utils.juju_log('INFO', 'Cookie already synchronized with peer.')
+ log('Cookie already synchronized with peer.')
else:
- utils.juju_log('INFO', 'Synchronizing erlang cookie from peer.')
+ log('Synchronizing erlang cookie from peer.')
rabbit.service('stop')
with open(rabbit.COOKIE_PATH, 'wb') as out:
out.write(cookie)
rabbit.service('start')
- if utils.is_relation_made('ha') and \
- utils.config_get('ha-vip-only') is False:
- utils.juju_log('INFO',
- 'hacluster relation is present, skipping native '
- 'rabbitmq cluster config.')
+ if is_relation_made('ha') and \
+ config('ha-vip-only') is False:
+ log('hacluster relation is present, skipping native '
+ 'rabbitmq cluster config.')
return
# cluster with node
- if utils.is_newer():
+ if is_newer():
if rabbit.cluster_with():
# resync nrpe user after clustering
update_nrpe_checks()
+@hooks.hook('cluster-relation-departed')
def cluster_departed():
- if utils.is_relation_made('ha') and \
- utils.config_get('ha-vip-only') is False:
- utils.juju_log('INFO',
- 'hacluster relation is present, skipping native '
- 'rabbitmq cluster config.')
+ if is_relation_made('ha') and \
+ config('ha-vip-only') is False:
+ log('hacluster relation is present, skipping native '
+ 'rabbitmq cluster config.')
return
- if not utils.is_newer():
- utils.juju_log('INFO', 'cluster_joined: Relation lesser.')
+ if not is_newer():
+ log('cluster_joined: Relation lesser.')
return
rabbit.break_cluster()
+@hooks.hook('ha-relation-joined')
def ha_joined():
- 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')
- rbd_name = utils.config_get('rbd-name')
- vip_only = utils.config_get('ha-vip-only')
+ corosync_bindiface = config('ha-bindiface')
+ corosync_mcastport = config('ha-mcastport')
+ vip = config('vip')
+ vip_iface = config('vip_iface')
+ vip_cidr = config('vip_cidr')
+ rbd_name = config('rbd-name')
+ vip_only = config('ha-vip-only')
if None in [corosync_bindiface, corosync_mcastport, vip, vip_iface,
vip_cidr, rbd_name] and vip_only is False:
- utils.juju_log('ERROR', 'Insufficient configuration data to '
- 'configure hacluster.')
+ log('Insufficient configuration data to configure hacluster.',
+ level=ERROR)
sys.exit(1)
elif None in [corosync_bindiface, corosync_mcastport, vip, vip_iface,
vip_cidr] and vip_only is True:
- utils.juju_log('ERROR', 'Insufficient configuration data to '
- 'configure VIP-only hacluster.')
+ log('Insufficient configuration data to configure VIP-only hacluster.',
+ level=ERROR)
sys.exit(1)
- if not utils.is_relation_made('ceph', 'auth') and vip_only is False:
- utils.juju_log('INFO',
- 'ha_joined: No ceph relation yet, deferring.')
+ if not is_relation_made('ceph', 'auth') and vip_only is False:
+ log('ha_joined: No ceph relation yet, deferring.')
return
name = '%s@localhost' % SERVICE_NAME
if rabbit.get_node_name() != name and vip_only is False:
- utils.juju_log('INFO', 'Stopping rabbitmq-server.')
- utils.stop('rabbitmq-server')
+ log('Stopping rabbitmq-server.')
+ service_stop('rabbitmq-server')
rabbit.set_node_name('%s@localhost' % SERVICE_NAME)
else:
- utils.juju_log('INFO', 'Node name already set to %s.' % name)
+ log('Node name already set to %s.' % name)
relation_settings = {}
relation_settings['corosync_bindiface'] = corosync_bindiface
@@ -240,7 +262,8 @@ def ha_joined():
'res_rabbitmq_rbd': 'params name="%s" pool="%s" user="%s" '
'secret="%s"' %
(rbd_name, POOL_NAME,
- SERVICE_NAME, ceph.keyfile_path(SERVICE_NAME)),
+ SERVICE_NAME, ceph._keyfile_path(
+ SERVICE_NAME)),
'res_rabbitmq_fs': 'params device="/dev/rbd/%s/%s" directory="%s" '
'fstype="ext4" op start start-delay="10s"' %
(POOL_NAME, rbd_name, RABBIT_DIR),
@@ -251,58 +274,63 @@ def ha_joined():
}
relation_settings['groups'] = {
- 'grp_rabbitmq': 'res_rabbitmq_rbd res_rabbitmq_fs res_rabbitmq_vip '
- 'res_rabbitmq-server',
+ 'grp_rabbitmq':
+ 'res_rabbitmq_rbd res_rabbitmq_fs res_rabbitmq_vip '
+ 'res_rabbitmq-server',
}
- for rel_id in utils.relation_ids('ha'):
- utils.relation_set(rid=rel_id, **relation_settings)
+ for rel_id in relation_ids('ha'):
+ relation_set(relation_id=rel_id, relation_settings=relation_settings)
env_vars = {
'OPENSTACK_PORT_EPMD': 4369,
- 'OPENSTACK_PORT_MCASTPORT': utils.config_get('ha-mcastport'),
+ 'OPENSTACK_PORT_MCASTPORT': config('ha-mcastport'),
}
- openstack.save_script_rc(**env_vars)
+ save_script_rc(**env_vars)
+@hooks.hook('ha-relation-changed')
def ha_changed():
- if not cluster.is_clustered():
+ if not is_clustered():
return
- vip = utils.config_get('vip')
- utils.juju_log('INFO', 'ha_changed(): We are now HA clustered. '
+ vip = config('vip')
+ log('ha_changed(): We are now HA clustered. '
'Advertising our VIP (%s) to all AMQP clients.' %
vip)
# need to re-authenticate all clients since node-name changed.
- for rid in utils.relation_ids('amqp'):
- for unit in utils.relation_list(rid):
+ for rid in relation_ids('amqp'):
+ for unit in related_units(rid):
amqp_changed(relation_id=rid, remote_unit=unit)
+@hooks.hook('ceph-relation-joined')
def ceph_joined():
- utils.juju_log('INFO', 'Start Ceph Relation Joined')
- utils.configure_source()
+ log('Start Ceph Relation Joined')
+ #NOTE fixup
+ #utils.configure_source()
ceph.install()
- utils.juju_log('INFO', 'Finish Ceph Relation Joined')
+ log('Finish Ceph Relation Joined')
+@hooks.hook('ceph-relation-changed')
def ceph_changed():
- utils.juju_log('INFO', 'Start Ceph Relation Changed')
- auth = utils.relation_get('auth')
- key = utils.relation_get('key')
- use_syslog = str(utils.config_get('use-syslog')).lower()
+ log('Start Ceph Relation Changed')
+ auth = relation_get('auth')
+ key = relation_get('key')
+ use_syslog = str(config('use-syslog')).lower()
if None in [auth, key]:
- utils.juju_log('INFO', 'Missing key or auth in relation')
+ log('Missing key or auth in relation')
sys.exit(0)
ceph.configure(service=SERVICE_NAME, key=key, auth=auth,
use_syslog=use_syslog)
- if cluster.eligible_leader('res_rabbitmq_vip'):
- rbd_img = utils.config_get('rbd-name')
- rbd_size = utils.config_get('rbd-size')
+ if eligible_leader('res_rabbitmq_vip'):
+ rbd_img = config('rbd-name')
+ rbd_size = config('rbd-size')
sizemb = int(rbd_size.split('G')[0]) * 1024
blk_device = '/dev/rbd/%s/%s' % (POOL_NAME, rbd_img)
- rbd_pool_rep_count = utils.config_get('ceph-osd-replication-count')
+ rbd_pool_rep_count = config('ceph-osd-replication-count')
ceph.ensure_ceph_storage(service=SERVICE_NAME, pool=POOL_NAME,
rbd_img=rbd_img, sizemb=sizemb,
fstype='ext4', mount_point=RABBIT_DIR,
@@ -310,22 +338,22 @@ def ceph_changed():
system_services=['rabbitmq-server'],
rbd_pool_replicas=rbd_pool_rep_count)
else:
- utils.juju_log('INFO',
- 'This is not the peer leader. Not configuring RBD.')
- utils.juju_log('INFO', 'Stopping rabbitmq-server.')
- utils.stop('rabbitmq-server')
+ log('This is not the peer leader. Not configuring RBD.')
+ log('Stopping rabbitmq-server.')
+ service_stop('rabbitmq-server')
# If 'ha' relation has been made before the 'ceph' relation
# it is important to make sure the ha-relation data is being
# sent.
- if utils.is_relation_made('ha'):
- utils.juju_log('INFO', '*ha* relation exists. Triggering ha_joined()')
+ if is_relation_made('ha'):
+ log('*ha* relation exists. Triggering ha_joined()')
ha_joined()
else:
- utils.juju_log('INFO', '*ha* relation does not exist.')
- utils.juju_log('INFO', 'Finish Ceph Relation Changed')
+ log('*ha* relation does not exist.')
+ log('Finish Ceph Relation Changed')
+@hooks.hook('nrpe-external-master-relation-changed')
def update_nrpe_checks():
if os.path.isdir(NAGIOS_PLUGINS):
rsync(os.path.join(os.getenv('CHARM_DIR'), 'scripts',
@@ -333,12 +361,12 @@ def update_nrpe_checks():
os.path.join(NAGIOS_PLUGINS, 'check_rabbitmq.py'))
# create unique user and vhost for each unit
- current_unit = hookenv.local_unit().replace('/', '-')
+ current_unit = local_unit().replace('/', '-')
user = 'nagios-%s' % current_unit
vhost = 'nagios-%s' % current_unit
password = rabbit.get_clustered_attribute('%s.passwd' % user)
if not password:
- utils.juju_log('INFO', 'Setting password for nagios unit: %s' % user)
+ log('Setting password for nagios unit: %s' % user)
password = pwgen(length=64)
rabbit.set_clustered_attribute('%s.passwd' % user, password)
@@ -356,9 +384,10 @@ def update_nrpe_checks():
nrpe_compat.write()
+@hooks.hook('upgrade-charm')
def upgrade_charm():
pre_install_hooks()
- add_source(utils.config_get('source'), utils.config_get('key'))
+ add_source(config('source'), config('key'))
apt_update(fatal=True)
# Ensure older passwd files in /var/lib/juju are moved to
@@ -378,9 +407,8 @@ def upgrade_charm():
if stored_password:
rabbit.set_clustered_attribute(username, stored_password)
- utils.juju_log('INFO',
- 'upgrade_charm: Migrating stored passwd'
- ' from %s to %s.' % (s, d))
+ log('upgrade_charm: Migrating stored passwd'
+ ' from %s to %s.' % (s, d))
shutil.move(s, d)
# explicitly update buggy file name naigos.passwd
@@ -399,18 +427,18 @@ def configure_client_ssl(relation_data):
ssl_mode, external_ca = _get_ssl_mode()
if ssl_mode == 'off':
return
- relation_data['ssl_port'] = utils.config_get('ssl_port')
+ relation_data['ssl_port'] = config('ssl_port')
if external_ca:
- if utils.config_get('ssl_ca'):
+ if config('ssl_ca'):
relation_data['ssl_ca'] = base64.b64encode(
- utils.config_get('ssl_ca'))
+ config('ssl_ca'))
return
ca = ServiceCA.get_ca()
relation_data['ssl_ca'] = base64.b64encode(ca.get_ca_bundle())
def _get_ssl_mode():
- config = utils.config_get()
+ config = config()
ssl_mode = config.get('ssl')
external_ca = False
# Legacy config boolean option
@@ -419,8 +447,8 @@ def _get_ssl_mode():
ssl_mode = 'off'
elif ssl_mode == 'off' and ssl_on:
ssl_mode = 'on'
- ssl_key = utils.config_get('ssl_key')
- ssl_cert = utils.config_get('ssl_cert')
+ ssl_key = config('ssl_key')
+ ssl_cert = config('ssl_cert')
if all((ssl_key, ssl_cert)):
external_ca = True
return ssl_mode, external_ca
@@ -441,16 +469,14 @@ def _convert_from_base64(v):
def reconfigure_client_ssl(ssl_enabled=False):
ssl_config_keys = set(('ssl_key', 'ssl_cert', 'ssl_ca'))
- for rid in hookenv.relation_ids('amqp'):
- rdata = hookenv.relation_get(
- rid=rid, unit=os.environ['JUJU_UNIT_NAME'])
+ for rid in relation_ids('amqp'):
+ rdata = relation_get(rid=rid, unit=os.environ['JUJU_UNIT_NAME'])
if not ssl_enabled and ssl_config_keys.intersection(rdata):
# No clean way to remove entirely, but blank them.
- utils.relation_set(
- rid=rid, ssl_key='', ssl_cert='', ssl_ca='')
+ relation_set(relation_id=rid, ssl_key='', ssl_cert='', ssl_ca='')
elif ssl_enabled and not ssl_config_keys.intersection(rdata):
configure_client_ssl(rdata)
- utils.relation_set(rid=rid, **rdata)
+ relation_set(relation_id=rid, **rdata)
def configure_rabbit_ssl():
@@ -465,20 +491,19 @@ def configure_rabbit_ssl():
if ssl_mode == 'off':
if os.path.exists(rabbit.RABBITMQ_CONF):
os.remove(rabbit.RABBITMQ_CONF)
- utils.close_port(utils.config_get('ssl_port'))
+ close_port(config('ssl_port'))
reconfigure_client_ssl()
return
- ssl_key = _convert_from_base64(utils.config_get('ssl_key'))
- ssl_cert = _convert_from_base64(utils.config_get('ssl_cert'))
- ssl_ca = _convert_from_base64(utils.config_get('ssl_ca'))
- ssl_port = utils.config_get('ssl_port')
+ ssl_key = _convert_from_base64(config('ssl_key'))
+ ssl_cert = _convert_from_base64(config('ssl_cert'))
+ ssl_ca = _convert_from_base64(config('ssl_ca'))
+ ssl_port = config('ssl_port')
# If external managed certs then we need all the fields.
if (ssl_mode in ('on', 'only') and any((ssl_key, ssl_cert)) and
not all((ssl_key, ssl_cert))):
- utils.juju_log(
- 'ERROR',
- 'If ssl_key or ssl_cert are specified both are required.')
+ log('If ssl_key or ssl_cert are specified both are required.',
+ level=ERROR)
sys.exit(1)
if not external_ca:
@@ -488,22 +513,23 @@ def configure_rabbit_ssl():
ssl_key, ssl_cert, ssl_port, ssl_ca,
ssl_only=(ssl_mode == "only"), ssl_client=False)
reconfigure_client_ssl(True)
- utils.open_port(ssl_port)
+ open_port(ssl_port)
+@hooks.hook('config-changed')
def config_changed():
- if utils.config_get('management_plugin') is True:
+ if config('management_plugin') is True:
rabbit.enable_plugin(MAN_PLUGIN)
- utils.open_port(55672)
+ open_port(55672)
else:
rabbit.disable_plugin(MAN_PLUGIN)
- utils.close_port(55672)
+ close_port(55672)
configure_rabbit_ssl()
- if cluster.eligible_leader('res_rabbitmq_vip') or \
- utils.config_get('ha-vip-only') is True:
- utils.restart('rabbitmq-server')
+ if eligible_leader('res_rabbitmq_vip') or \
+ config('ha-vip-only') is True:
+ service_restart('rabbitmq-server')
update_nrpe_checks()
@@ -513,19 +539,9 @@ def pre_install_hooks():
if os.path.isfile(f) and os.access(f, os.X_OK):
subprocess.check_call(['sh', '-c', f])
-hooks = {
- 'install': install,
- 'amqp-relation-changed': amqp_changed,
- 'cluster-relation-joined': cluster_joined,
- 'cluster-relation-changed': cluster_changed,
- 'cluster-relation-departed': cluster_departed,
- 'ha-relation-joined': ha_joined,
- 'ha-relation-changed': ha_changed,
- 'ceph-relation-joined': ceph_joined,
- 'ceph-relation-changed': ceph_changed,
- 'upgrade-charm': upgrade_charm,
- 'config-changed': config_changed,
- 'nrpe-external-master-relation-changed': update_nrpe_checks
-}
-utils.do_hooks(hooks)
+if __name__ == '__main__':
+ try:
+ hooks.execute(sys.argv)
+ except UnregisteredHookError as e:
+ log('Unknown hook {} - skipping.'.format(e))
diff --git a/lib/charmhelpers-0.1.2.egg-info b/lib/charmhelpers-0.1.2.egg-info
deleted file mode 100644
index 6d99dbe2..00000000
--- a/lib/charmhelpers-0.1.2.egg-info
+++ /dev/null
@@ -1,18 +0,0 @@
-Metadata-Version: 1.0
-Name: charmhelpers
-Version: 0.1.2
-Summary: UNKNOWN
-Home-page: https://code.launchpad.net/charm-helpers
-Author: Ubuntu Developers
-Author-email: ubuntu-devel-discuss@lists.ubuntu.com
-License: Affero GNU Public License v3
-Description: ============
- CharmHelpers
- ============
-
- CharmHelpers provides an opinionated set of tools for building Juju
- charms that work together. In addition to basic tasks like interact-
- ing with the charm environment and the machine it runs on, it also
- helps keep you build hooks and establish relations effortlessly.
-
-Platform: UNKNOWN