Merge James' lib/ refactoring.
This commit is contained in:
commit
e46b7adb79
17
.project
Normal file
17
.project
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>rabbitmq-server</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.python.pydev.PyDevBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.python.pydev.pythonNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
8
.pydevproject
Normal file
8
.pydevproject
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||||
|
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
|
||||||
|
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||||
|
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||||
|
<path>/rabbitmq-server/hooks</path>
|
||||||
|
</pydev_pathproperty>
|
||||||
|
</pydev_project>
|
@ -1 +1 @@
|
|||||||
rabbitmq-server-relations.py
|
rabbitmq_server_relations.py
|
@ -1 +1 @@
|
|||||||
rabbitmq-server-relations.py
|
rabbitmq_server_relations.py
|
@ -1 +1 @@
|
|||||||
rabbitmq-server-relations.py
|
rabbitmq_server_relations.py
|
@ -1 +1 @@
|
|||||||
rabbitmq-server-relations.py
|
rabbitmq_server_relations.py
|
@ -1 +1 @@
|
|||||||
rabbitmq-server-relations.py
|
rabbitmq_server_relations.py
|
@ -1 +1 @@
|
|||||||
rabbitmq-server-relations.py
|
rabbitmq_server_relations.py
|
@ -1 +1 @@
|
|||||||
rabbitmq-server-relations.py
|
rabbitmq_server_relations.py
|
@ -1 +1 @@
|
|||||||
rabbitmq-server-relations.py
|
rabbitmq_server_relations.py
|
@ -1,10 +1,18 @@
|
|||||||
import utils
|
#
|
||||||
|
# Copyright 2012 Canonical Ltd.
|
||||||
|
#
|
||||||
|
# This file is sourced from lp:openstack-charm-helpers
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# James Page <james.page@ubuntu.com>
|
||||||
|
# Adam Gandelman <adamg@ubuntu.com>
|
||||||
|
#
|
||||||
|
|
||||||
import commands
|
import commands
|
||||||
import re
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import lib.utils as utils
|
||||||
|
|
||||||
KEYRING = '/etc/ceph/ceph.client.%s.keyring'
|
KEYRING = '/etc/ceph/ceph.client.%s.keyring'
|
||||||
KEYFILE = '/etc/ceph/ceph.client.%s.key'
|
KEYFILE = '/etc/ceph/ceph.client.%s.key'
|
||||||
@ -15,6 +23,7 @@ CEPH_CONF = """[global]
|
|||||||
mon host = %(mon_hosts)s
|
mon host = %(mon_hosts)s
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def execute(cmd):
|
def execute(cmd):
|
||||||
subprocess.check_call(cmd)
|
subprocess.check_call(cmd)
|
||||||
|
|
||||||
@ -55,6 +64,7 @@ def pool_exists(service, name):
|
|||||||
(rc, out) = commands.getstatusoutput("rados --id %s lspools" % service)
|
(rc, out) = commands.getstatusoutput("rados --id %s lspools" % service)
|
||||||
return name in out
|
return name in out
|
||||||
|
|
||||||
|
|
||||||
def create_pool(service, name):
|
def create_pool(service, name):
|
||||||
cmd = [
|
cmd = [
|
||||||
'rados',
|
'rados',
|
||||||
@ -69,9 +79,11 @@ def create_pool(service, name):
|
|||||||
def keyfile_path(service):
|
def keyfile_path(service):
|
||||||
return KEYFILE % service
|
return KEYFILE % service
|
||||||
|
|
||||||
|
|
||||||
def keyring_path(service):
|
def keyring_path(service):
|
||||||
return KEYRING % service
|
return KEYRING % service
|
||||||
|
|
||||||
|
|
||||||
def create_keyring(service, key):
|
def create_keyring(service, key):
|
||||||
keyring = keyring_path(service)
|
keyring = keyring_path(service)
|
||||||
if os.path.exists(keyring):
|
if os.path.exists(keyring):
|
||||||
@ -122,6 +134,7 @@ def image_mapped(image_name):
|
|||||||
(rc, out) = commands.getstatusoutput('rbd showmapped')
|
(rc, out) = commands.getstatusoutput('rbd showmapped')
|
||||||
return image_name in out
|
return image_name in out
|
||||||
|
|
||||||
|
|
||||||
def map_block_storage(service, pool, image):
|
def map_block_storage(service, pool, image):
|
||||||
cmd = [
|
cmd = [
|
||||||
'rbd',
|
'rbd',
|
||||||
@ -138,6 +151,7 @@ def map_block_storage(service, pool, image):
|
|||||||
def filesystem_mounted(fs):
|
def filesystem_mounted(fs):
|
||||||
return subprocess.call(['grep', '-wqs', fs, '/proc/mounts']) == 0
|
return subprocess.call(['grep', '-wqs', fs, '/proc/mounts']) == 0
|
||||||
|
|
||||||
|
|
||||||
def make_filesystem(blk_device, fstype='ext4'):
|
def make_filesystem(blk_device, fstype='ext4'):
|
||||||
utils.juju_log('INFO',
|
utils.juju_log('INFO',
|
||||||
'ceph: Formatting block device %s as filesystem %s.' %\
|
'ceph: Formatting block device %s as filesystem %s.' %\
|
||||||
@ -173,9 +187,10 @@ def place_data_on_ceph(service, blk_device, data_src_dst, fstype='ext4'):
|
|||||||
cmd = ['chown', '-R', '%s:%s' % (uid, gid), data_src_dst]
|
cmd = ['chown', '-R', '%s:%s' % (uid, gid), data_src_dst]
|
||||||
execute(cmd)
|
execute(cmd)
|
||||||
|
|
||||||
|
|
||||||
# TODO: re-use
|
# TODO: re-use
|
||||||
def modprobe_kernel_module(module):
|
def modprobe_kernel_module(module):
|
||||||
utils.juju_log('INFO','Loading kernel module')
|
utils.juju_log('INFO', 'Loading kernel module')
|
||||||
cmd = ['modprobe', module]
|
cmd = ['modprobe', module]
|
||||||
execute(cmd)
|
execute(cmd)
|
||||||
cmd = 'echo %s >> /etc/modules' % module
|
cmd = 'echo %s >> /etc/modules' % module
|
||||||
@ -191,6 +206,7 @@ def copy_files(src, dst, symlinks=False, ignore=None):
|
|||||||
else:
|
else:
|
||||||
shutil.copy2(s, d)
|
shutil.copy2(s, d)
|
||||||
|
|
||||||
|
|
||||||
def ensure_ceph_storage(service, pool, rbd_img, sizemb, mount_point,
|
def ensure_ceph_storage(service, pool, rbd_img, sizemb, mount_point,
|
||||||
blk_device, fstype, system_services=[]):
|
blk_device, fstype, system_services=[]):
|
||||||
"""
|
"""
|
130
hooks/lib/cluster_utils.py
Normal file
130
hooks/lib/cluster_utils.py
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2012 Canonical Ltd.
|
||||||
|
#
|
||||||
|
# This file is sourced from lp:openstack-charm-helpers
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# James Page <james.page@ubuntu.com>
|
||||||
|
# Adam Gandelman <adamg@ubuntu.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
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)
|
283
hooks/lib/utils.py
Normal file
283
hooks/lib/utils.py
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2012 Canonical Ltd.
|
||||||
|
#
|
||||||
|
# This file is sourced from lp:openstack-charm-helpers
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# James Page <james.page@ubuntu.com>
|
||||||
|
# Paul Collins <paul.collins@canonical.com>
|
||||||
|
# Adam Gandelman <adamg@ubuntu.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
import json
|
||||||
|
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'
|
||||||
|
|
||||||
|
try:
|
||||||
|
import jinja2
|
||||||
|
except ImportError:
|
||||||
|
install('python-jinja2')
|
||||||
|
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 = jinja2.Environment(
|
||||||
|
loader=jinja2.FileSystemLoader(template_dir)
|
||||||
|
)
|
||||||
|
template = templates.get_template(template_name)
|
||||||
|
return template.render(context)
|
||||||
|
|
||||||
|
CLOUD_ARCHIVE = \
|
||||||
|
""" # Ubuntu Cloud Archive
|
||||||
|
deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
|
||||||
|
"""
|
||||||
|
|
||||||
|
CLOUD_ARCHIVE_POCKETS = {
|
||||||
|
'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'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def configure_source():
|
||||||
|
source = str(config_get('openstack-origin'))
|
||||||
|
if not source:
|
||||||
|
return
|
||||||
|
if source.startswith('ppa:'):
|
||||||
|
cmd = [
|
||||||
|
'add-apt-repository',
|
||||||
|
source
|
||||||
|
]
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
if source.startswith('cloud:'):
|
||||||
|
install('ubuntu-cloud-keyring')
|
||||||
|
pocket = source.split(':')[1]
|
||||||
|
with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as apt:
|
||||||
|
apt.write(CLOUD_ARCHIVE.format(CLOUD_ARCHIVE_POCKETS[pocket]))
|
||||||
|
if source.startswith('deb'):
|
||||||
|
l = len(source.split('|'))
|
||||||
|
if l == 2:
|
||||||
|
(apt_line, key) = source.split('|')
|
||||||
|
cmd = [
|
||||||
|
'apt-key',
|
||||||
|
'adv', '--keyserver keyserver.ubuntu.com',
|
||||||
|
'--recv-keys', key
|
||||||
|
]
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
elif l == 1:
|
||||||
|
apt_line = source
|
||||||
|
|
||||||
|
with open('/etc/apt/sources.list.d/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 juju_log(severity, message):
|
||||||
|
cmd = [
|
||||||
|
'juju-log',
|
||||||
|
'--log-level', severity,
|
||||||
|
message
|
||||||
|
]
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def relation_ids(relation):
|
||||||
|
cmd = [
|
||||||
|
'relation-ids',
|
||||||
|
relation
|
||||||
|
]
|
||||||
|
result = str(subprocess.check_output(cmd)).split()
|
||||||
|
if result == "":
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def relation_list(rid):
|
||||||
|
cmd = [
|
||||||
|
'relation-list',
|
||||||
|
'-r', rid,
|
||||||
|
]
|
||||||
|
result = str(subprocess.check_output(cmd)).split()
|
||||||
|
if result == "":
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
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':
|
||||||
|
if v:
|
||||||
|
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',
|
||||||
|
'--format',
|
||||||
|
'json',
|
||||||
|
]
|
||||||
|
out = subprocess.check_output(cmd).strip() # IGNORE:E1103
|
||||||
|
cfg = json.loads(out)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return cfg[attribute]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_unit_hostname():
|
||||||
|
return socket.gethostname()
|
||||||
|
|
||||||
|
|
||||||
|
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
|
@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import utils
|
import lib.utils as utils
|
||||||
import apt_pkg as apt
|
import apt_pkg as apt
|
||||||
|
|
||||||
PACKAGES = ['pwgen', 'rabbitmq-server']
|
PACKAGES = ['pwgen', 'rabbitmq-server']
|
||||||
@ -9,6 +9,7 @@ PACKAGES = ['pwgen', 'rabbitmq-server']
|
|||||||
RABBITMQ_CTL = '/usr/sbin/rabbitmqctl'
|
RABBITMQ_CTL = '/usr/sbin/rabbitmqctl'
|
||||||
COOKIE_PATH = '/var/lib/rabbitmq/.erlang.cookie'
|
COOKIE_PATH = '/var/lib/rabbitmq/.erlang.cookie'
|
||||||
|
|
||||||
|
|
||||||
def vhost_exists(vhost):
|
def vhost_exists(vhost):
|
||||||
cmd = [RABBITMQ_CTL, 'list_vhosts']
|
cmd = [RABBITMQ_CTL, 'list_vhosts']
|
||||||
out = subprocess.check_output(cmd)
|
out = subprocess.check_output(cmd)
|
||||||
|
@ -7,19 +7,22 @@ import subprocess
|
|||||||
|
|
||||||
|
|
||||||
import rabbit_utils as rabbit
|
import rabbit_utils as rabbit
|
||||||
import utils
|
import lib.utils as utils
|
||||||
import lib.ceph as ceph
|
import lib.cluster_utils as cluster
|
||||||
|
import lib.ceph_utils as ceph
|
||||||
|
|
||||||
SERVICE_NAME = os.getenv('JUJU_UNIT_NAME').split('/')[0]
|
SERVICE_NAME = os.getenv('JUJU_UNIT_NAME').split('/')[0]
|
||||||
POOL_NAME = SERVICE_NAME
|
POOL_NAME = SERVICE_NAME
|
||||||
RABBIT_DIR='/var/lib/rabbitmq'
|
RABBIT_DIR = '/var/lib/rabbitmq'
|
||||||
|
|
||||||
|
|
||||||
def install():
|
def install():
|
||||||
utils.install(*rabbit.PACKAGES)
|
utils.install(*rabbit.PACKAGES)
|
||||||
utils.expose(5672)
|
utils.expose(5672)
|
||||||
|
|
||||||
|
|
||||||
def amqp_changed(relation_id=None, remote_unit=None):
|
def amqp_changed(relation_id=None, remote_unit=None):
|
||||||
if not utils.eligible_leader('res_rabbitmq_vip'):
|
if not cluster.eligible_leader('res_rabbitmq_vip'):
|
||||||
msg = 'amqp_changed(): Deferring amqp_changed to eligible_leader.'
|
msg = 'amqp_changed(): Deferring amqp_changed to eligible_leader.'
|
||||||
utils.juju_log('INFO', msg)
|
utils.juju_log('INFO', msg)
|
||||||
return
|
return
|
||||||
@ -47,7 +50,7 @@ def amqp_changed(relation_id=None, remote_unit=None):
|
|||||||
relation_settings = {
|
relation_settings = {
|
||||||
'password': password
|
'password': password
|
||||||
}
|
}
|
||||||
if utils.is_clustered():
|
if cluster.is_clustered():
|
||||||
relation_settings['clustered'] = 'true'
|
relation_settings['clustered'] = 'true'
|
||||||
relation_settings['vip'] = utils.config_get('vip')
|
relation_settings['vip'] = utils.config_get('vip')
|
||||||
if relation_id:
|
if relation_id:
|
||||||
@ -107,7 +110,6 @@ def cluster_changed():
|
|||||||
|
|
||||||
|
|
||||||
def ha_joined():
|
def ha_joined():
|
||||||
config = {}
|
|
||||||
corosync_bindiface = utils.config_get('ha-bindiface')
|
corosync_bindiface = utils.config_get('ha-bindiface')
|
||||||
corosync_mcastport = utils.config_get('ha-mcastport')
|
corosync_mcastport = utils.config_get('ha-mcastport')
|
||||||
vip = utils.config_get('vip')
|
vip = utils.config_get('vip')
|
||||||
@ -121,14 +123,13 @@ def ha_joined():
|
|||||||
'configure hacluster.')
|
'configure hacluster.')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not utils.is_relation_made('ceph', 'auth'):
|
||||||
if not utils.is_relation_made('ceph'):
|
|
||||||
utils.juju_log('INFO',
|
utils.juju_log('INFO',
|
||||||
'ha_joined: No ceph relation yet, deferring.')
|
'ha_joined: No ceph relation yet, deferring.')
|
||||||
return
|
return
|
||||||
|
|
||||||
# rabbit node-name need to match on all nodes.
|
# rabbit node-name need to match on all nodes.
|
||||||
utils.juju_log('INFO','Stopping rabbitmq-server.')
|
utils.juju_log('INFO', 'Stopping rabbitmq-server.')
|
||||||
utils.stop('rabbitmq-server')
|
utils.stop('rabbitmq-server')
|
||||||
|
|
||||||
rabbit.set_node_name('%s@localhost' % SERVICE_NAME)
|
rabbit.set_node_name('%s@localhost' % SERVICE_NAME)
|
||||||
@ -138,25 +139,27 @@ def ha_joined():
|
|||||||
relation_settings['corosync_mcastport'] = corosync_mcastport
|
relation_settings['corosync_mcastport'] = corosync_mcastport
|
||||||
|
|
||||||
relation_settings['resources'] = {
|
relation_settings['resources'] = {
|
||||||
'res_rabbitmq_rbd':'ocf:ceph:rbd',
|
'res_rabbitmq_rbd': 'ocf:ceph:rbd',
|
||||||
'res_rabbitmq_fs':'ocf:heartbeat:Filesystem',
|
'res_rabbitmq_fs': 'ocf:heartbeat:Filesystem',
|
||||||
'res_rabbitmq_vip':'ocf:heartbeat:IPaddr2',
|
'res_rabbitmq_vip': 'ocf:heartbeat:IPaddr2',
|
||||||
'res_rabbitmq-server':'lsb:rabbitmq-server',
|
'res_rabbitmq-server': 'lsb:rabbitmq-server',
|
||||||
}
|
}
|
||||||
|
|
||||||
relation_settings['resource_params'] = {
|
relation_settings['resource_params'] = {
|
||||||
'res_rabbitmq_rbd': 'params name="%s" pool="%s" user="%s" secret="%s"' %\
|
'res_rabbitmq_rbd': 'params name="%s" pool="%s" user="%s" '
|
||||||
(rbd_name, POOL_NAME, SERVICE_NAME, ceph.keyfile_path(SERVICE_NAME)),
|
'secret="%s"' % \
|
||||||
|
(rbd_name, POOL_NAME,
|
||||||
|
SERVICE_NAME, ceph.keyfile_path(SERVICE_NAME)),
|
||||||
'res_rabbitmq_fs': 'params device="/dev/rbd/%s/%s" directory="%s" '\
|
'res_rabbitmq_fs': 'params device="/dev/rbd/%s/%s" directory="%s" '\
|
||||||
'fstype="ext4" op start start-delay="10s"' %\
|
'fstype="ext4" op start start-delay="10s"' %\
|
||||||
(POOL_NAME, rbd_name, RABBIT_DIR),
|
(POOL_NAME, rbd_name, RABBIT_DIR),
|
||||||
'res_rabbitmq_vip':'params ip="%s" cidr_netmask="%s" nic="%s"' %\
|
'res_rabbitmq_vip': 'params ip="%s" cidr_netmask="%s" nic="%s"' %\
|
||||||
(vip, vip_cidr, vip_iface),
|
(vip, vip_cidr, vip_iface),
|
||||||
'res_rabbitmqd':'op start start-delay="5s" op monitor interval="5s"',
|
'res_rabbitmqd': 'op start start-delay="5s" op monitor interval="5s"',
|
||||||
}
|
}
|
||||||
|
|
||||||
relation_settings['groups'] = {
|
relation_settings['groups'] = {
|
||||||
'grp_rabbitmq':'res_rabbitmq_rbd res_rabbitmq_fs res_rabbitmq_vip '\
|
'grp_rabbitmq': 'res_rabbitmq_rbd res_rabbitmq_fs res_rabbitmq_vip '\
|
||||||
'res_rabbitmq-server',
|
'res_rabbitmq-server',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,14 +168,12 @@ def ha_joined():
|
|||||||
|
|
||||||
|
|
||||||
def ha_changed():
|
def ha_changed():
|
||||||
if not utils.is_clustered():
|
if not cluster.is_clustered():
|
||||||
return
|
return
|
||||||
vip = utils.config_get('vip')
|
vip = utils.config_get('vip')
|
||||||
utils.juju_log('INFO', 'ha_changed(): We are now HA clustered. '\
|
utils.juju_log('INFO', 'ha_changed(): We are now HA clustered. '
|
||||||
'Advertising our VIP (%s) to all AMQP clients.' %\
|
'Advertising our VIP (%s) to all AMQP clients.' %\
|
||||||
vip)
|
vip)
|
||||||
relation_settings = {'vip': vip, 'clustered': 'true'}
|
|
||||||
|
|
||||||
# need to re-authenticate all clients since node-name changed.
|
# need to re-authenticate all clients since node-name changed.
|
||||||
for rid in utils.relation_ids('amqp'):
|
for rid in utils.relation_ids('amqp'):
|
||||||
for unit in utils.relation_list(rid):
|
for unit in utils.relation_list(rid):
|
||||||
@ -195,7 +196,7 @@ def ceph_changed():
|
|||||||
|
|
||||||
ceph.configure(service=SERVICE_NAME, key=key, auth=auth)
|
ceph.configure(service=SERVICE_NAME, key=key, auth=auth)
|
||||||
|
|
||||||
if utils.eligible_leader('res_rabbitmq_vip'):
|
if cluster.eligible_leader('res_rabbitmq_vip'):
|
||||||
rbd_img = utils.config_get('rbd-name')
|
rbd_img = utils.config_get('rbd-name')
|
||||||
rbd_size = utils.config_get('rbd-size')
|
rbd_size = utils.config_get('rbd-size')
|
||||||
sizemb = int(rbd_size.split('G')[0]) * 1024
|
sizemb = int(rbd_size.split('G')[0]) * 1024
|
||||||
@ -208,7 +209,7 @@ def ceph_changed():
|
|||||||
else:
|
else:
|
||||||
utils.juju_log('INFO',
|
utils.juju_log('INFO',
|
||||||
'This is not the peer leader. Not configuring RBD.')
|
'This is not the peer leader. Not configuring RBD.')
|
||||||
utils.juju_log('INFO','Stopping rabbitmq-server.')
|
utils.juju_log('INFO', 'Stopping rabbitmq-server.')
|
||||||
utils.stop('rabbitmq-server')
|
utils.stop('rabbitmq-server')
|
||||||
|
|
||||||
# If 'ha' relation has been made before the 'ceph' relation
|
# If 'ha' relation has been made before the 'ceph' relation
|
||||||
@ -230,8 +231,9 @@ def upgrade_charm():
|
|||||||
if f.endswith('.passwd'):
|
if f.endswith('.passwd'):
|
||||||
s = os.path.join('/var/lib/juju', f)
|
s = os.path.join('/var/lib/juju', f)
|
||||||
d = os.path.join('/var/lib/rabbitmq', f)
|
d = os.path.join('/var/lib/rabbitmq', f)
|
||||||
m = 'upgrade_charm: Migrating stored passwd from %s to %s.' % (s, d)
|
utils.juju_log('INFO',
|
||||||
utils.juju_log('INFO', m)
|
'upgrade_charm: Migrating stored passwd'
|
||||||
|
' from %s to %s.' % (s, d))
|
||||||
shutil.move(s, d)
|
shutil.move(s, d)
|
||||||
|
|
||||||
hooks = {
|
hooks = {
|
@ -1 +1 @@
|
|||||||
rabbitmq-server-relations.py
|
rabbitmq_server_relations.py
|
457
hooks/utils.py
457
hooks/utils.py
@ -1,457 +0,0 @@
|
|||||||
|
|
||||||
#
|
|
||||||
# Copyright 2012 Canonical Ltd.
|
|
||||||
#
|
|
||||||
# Authors:
|
|
||||||
# James Page <james.page@ubuntu.com>
|
|
||||||
# Paul Collins <paul.collins@canonical.com>
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import fcntl
|
|
||||||
import struct
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
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 can_install():
|
|
||||||
try:
|
|
||||||
fd = os.open("/var/lib/dpkg/lock", os.O_RDWR|os.O_CREAT|os.O_NOFOLLOW, 0640)
|
|
||||||
fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
||||||
except IOError, message:
|
|
||||||
os.close(fd)
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
fcntl.lockf(fd, fcntl.LOCK_UN)
|
|
||||||
os.close(fd)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def install(*pkgs):
|
|
||||||
cmd = [
|
|
||||||
'apt-get',
|
|
||||||
'-y',
|
|
||||||
'install'
|
|
||||||
]
|
|
||||||
for pkg in pkgs:
|
|
||||||
cmd.append(pkg)
|
|
||||||
while not can_install():
|
|
||||||
juju_log('INFO',
|
|
||||||
"dpkg is busy, can't install %s yet, waiting..." % pkgs)
|
|
||||||
time.sleep(1)
|
|
||||||
subprocess.check_call(cmd)
|
|
||||||
|
|
||||||
TEMPLATES_DIR = 'templates'
|
|
||||||
|
|
||||||
try:
|
|
||||||
import jinja2
|
|
||||||
except ImportError:
|
|
||||||
install('python-jinja2')
|
|
||||||
import jinja2
|
|
||||||
|
|
||||||
try:
|
|
||||||
from netaddr import IPNetwork
|
|
||||||
except ImportError:
|
|
||||||
install('python-netaddr')
|
|
||||||
from netaddr import IPNetwork
|
|
||||||
|
|
||||||
try:
|
|
||||||
import dns.resolver
|
|
||||||
except ImportError:
|
|
||||||
install('python-dnspython')
|
|
||||||
import dns.resolver
|
|
||||||
|
|
||||||
|
|
||||||
def render_template(template_name, context, template_dir=TEMPLATES_DIR):
|
|
||||||
templates = jinja2.Environment(
|
|
||||||
loader=jinja2.FileSystemLoader(template_dir)
|
|
||||||
)
|
|
||||||
template = templates.get_template(template_name)
|
|
||||||
return template.render(context)
|
|
||||||
|
|
||||||
|
|
||||||
CLOUD_ARCHIVE = \
|
|
||||||
""" # Ubuntu Cloud Archive
|
|
||||||
deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
|
|
||||||
"""
|
|
||||||
|
|
||||||
CLOUD_ARCHIVE_POCKETS = {
|
|
||||||
'precise-folsom': 'precise-updates/folsom',
|
|
||||||
'precise-folsom/updates': 'precise-updates/folsom',
|
|
||||||
'precise-folsom/proposed': 'precise-proposed/folsom',
|
|
||||||
'precise-grizzly': 'precise-updates/grizzly',
|
|
||||||
'precise-grizzly/updates': 'precise-updates/grizzly',
|
|
||||||
'precise-grizzly/proposed': 'precise-proposed/grizzly'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def execute(cmd, die=False, echo=False):
|
|
||||||
""" Executes a command
|
|
||||||
|
|
||||||
if die=True, script will exit(1) if command does not return 0
|
|
||||||
if echo=True, output of command will be printed to stdout
|
|
||||||
|
|
||||||
returns a tuple: (stdout, stderr, return code)
|
|
||||||
"""
|
|
||||||
p = subprocess.Popen(cmd.split(" "),
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
stdout=""
|
|
||||||
stderr=""
|
|
||||||
|
|
||||||
def print_line(l):
|
|
||||||
if echo:
|
|
||||||
print l.strip('\n')
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
for l in iter(p.stdout.readline, ''):
|
|
||||||
print_line(l)
|
|
||||||
stdout += l
|
|
||||||
for l in iter(p.stderr.readline, ''):
|
|
||||||
print_line(l)
|
|
||||||
stderr += l
|
|
||||||
|
|
||||||
p.communicate()
|
|
||||||
rc = p.returncode
|
|
||||||
|
|
||||||
if die and rc != 0:
|
|
||||||
error_out("ERROR: command %s return non-zero.\n" % cmd)
|
|
||||||
return (stdout, stderr, rc)
|
|
||||||
|
|
||||||
|
|
||||||
def configure_source():
|
|
||||||
source = str(config_get('openstack-origin'))
|
|
||||||
if not source:
|
|
||||||
return
|
|
||||||
if source.startswith('ppa:'):
|
|
||||||
cmd = [
|
|
||||||
'add-apt-repository',
|
|
||||||
source
|
|
||||||
]
|
|
||||||
subprocess.check_call(cmd)
|
|
||||||
if source.startswith('cloud:'):
|
|
||||||
install('ubuntu-cloud-keyring')
|
|
||||||
pocket = source.split(':')[1]
|
|
||||||
with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as apt:
|
|
||||||
apt.write(CLOUD_ARCHIVE.format(CLOUD_ARCHIVE_POCKETS[pocket]))
|
|
||||||
if source.startswith('deb'):
|
|
||||||
l = len(source.split('|'))
|
|
||||||
if l == 2:
|
|
||||||
(apt_line, key) = source.split('|')
|
|
||||||
cmd = [
|
|
||||||
'apt-key',
|
|
||||||
'adv', '--keyserver keyserver.ubuntu.com',
|
|
||||||
'--recv-keys', key
|
|
||||||
]
|
|
||||||
subprocess.check_call(cmd)
|
|
||||||
elif l == 1:
|
|
||||||
apt_line = source
|
|
||||||
|
|
||||||
with open('/etc/apt/sources.list.d/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 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_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 += ' -r %s' % relation_id
|
|
||||||
if remote_unit:
|
|
||||||
remote_unit_orig = os.getenv('JUJU_REMOTE_UNIT', None)
|
|
||||||
os.environ['JUJU_REMOTE_UNIT'] = remote_unit
|
|
||||||
j = execute(cmd, die=True)[0]
|
|
||||||
if remote_unit and remote_unit_orig:
|
|
||||||
os.environ['JUJU_REMOTE_UNIT'] = remote_unit_orig
|
|
||||||
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':
|
|
||||||
cmd.append('-r')
|
|
||||||
cmd.append(v)
|
|
||||||
else:
|
|
||||||
args.append('{}={}'.format(k, v))
|
|
||||||
cmd += args
|
|
||||||
subprocess.check_call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def unit_get(attribute):
|
|
||||||
cmd = [
|
|
||||||
'unit-get',
|
|
||||||
attribute
|
|
||||||
]
|
|
||||||
value = subprocess.check_output(cmd).strip() # IGNORE:E1103
|
|
||||||
if value == "":
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def config_get(attribute):
|
|
||||||
cmd = [
|
|
||||||
'config-get',
|
|
||||||
attribute
|
|
||||||
]
|
|
||||||
value = subprocess.check_output(cmd).strip() # IGNORE:E1103
|
|
||||||
if value == "":
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def get_unit_hostname():
|
|
||||||
return socket.gethostname()
|
|
||||||
|
|
||||||
|
|
||||||
def get_unit_name():
|
|
||||||
return os.environ.get('JUJU_UNIT_NAME').replace('/','-')
|
|
||||||
|
|
||||||
|
|
||||||
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:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
answers = dns.resolver.query(hostname, 'A')
|
|
||||||
if answers:
|
|
||||||
return answers[0].address
|
|
||||||
except dns.resolver.NXDOMAIN:
|
|
||||||
pass
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def restart(*services):
|
|
||||||
for service in services:
|
|
||||||
subprocess.check_call(['service', service, 'restart'])
|
|
||||||
|
|
||||||
|
|
||||||
def stop(*services):
|
|
||||||
for service in services:
|
|
||||||
subprocess.check_call(['service', service, 'stop'])
|
|
||||||
|
|
||||||
|
|
||||||
def start(*services):
|
|
||||||
for service in services:
|
|
||||||
subprocess.check_call(['service', service, 'start'])
|
|
||||||
|
|
||||||
|
|
||||||
def running(service):
|
|
||||||
# TODO: ensure compat. /w sysv init scripts.
|
|
||||||
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 disable_upstart_services(*services):
|
|
||||||
for service in services:
|
|
||||||
with open("/etc/init/{}.override".format(service), "w") as override:
|
|
||||||
override.write("manual")
|
|
||||||
|
|
||||||
|
|
||||||
def enable_upstart_services(*services):
|
|
||||||
for service in services:
|
|
||||||
path = '/etc/init/{}.override'.format(service)
|
|
||||||
if os.path.exists(path):
|
|
||||||
os.remove(path)
|
|
||||||
|
|
||||||
|
|
||||||
def disable_lsb_services(*services):
|
|
||||||
for service in services:
|
|
||||||
subprocess.check_call(['update-rc.d', '-f', service, 'remove'])
|
|
||||||
|
|
||||||
|
|
||||||
def enable_lsb_services(*services):
|
|
||||||
for service in services:
|
|
||||||
subprocess.check_call(['update-rc.d', '-f', service, 'defaults'])
|
|
||||||
|
|
||||||
|
|
||||||
def get_iface_ipaddr(iface):
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
return socket.inet_ntoa(fcntl.ioctl(
|
|
||||||
s.fileno(),
|
|
||||||
0x8919, # SIOCGIFADDR
|
|
||||||
struct.pack('256s', iface[:15])
|
|
||||||
)[20:24])
|
|
||||||
|
|
||||||
|
|
||||||
def get_iface_netmask(iface):
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
return socket.inet_ntoa(fcntl.ioctl(
|
|
||||||
s.fileno(),
|
|
||||||
0x891b, # SIOCGIFNETMASK
|
|
||||||
struct.pack('256s', iface[:15])
|
|
||||||
)[20:24])
|
|
||||||
|
|
||||||
|
|
||||||
def get_netmask_cidr(netmask):
|
|
||||||
netmask = netmask.split('.')
|
|
||||||
binary_str = ''
|
|
||||||
for octet in netmask:
|
|
||||||
binary_str += bin(int(octet))[2:].zfill(8)
|
|
||||||
return str(len(binary_str.rstrip('0')))
|
|
||||||
|
|
||||||
|
|
||||||
def get_network_address(iface):
|
|
||||||
if iface:
|
|
||||||
network = "{}/{}".format(get_iface_ipaddr(iface),
|
|
||||||
get_netmask_cidr(get_iface_netmask(iface)))
|
|
||||||
ip = IPNetwork(network)
|
|
||||||
return str(ip.network)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
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(res):
|
|
||||||
status = execute('crm resource show %s' % res, echo=True)[0].strip()
|
|
||||||
hostname = execute('hostname', echo=True)[0].strip()
|
|
||||||
if 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(res):
|
|
||||||
if is_clustered():
|
|
||||||
if not is_leader(res):
|
|
||||||
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 is_relation_made(relation=None):
|
|
||||||
relation_data = []
|
|
||||||
for r_id in (relation_ids(relation) or []):
|
|
||||||
for unit in (relation_list(r_id) or []):
|
|
||||||
relation_data.append(relation_get_dict(relation_id=r_id,
|
|
||||||
remote_unit=unit))
|
|
||||||
if not relation_data:
|
|
||||||
return False
|
|
||||||
return True
|
|
Loading…
Reference in New Issue
Block a user