General tidy, sort out hooks, use openstack helpers

This commit is contained in:
James Page 2013-03-31 12:19:54 +01:00
parent 59feb3673a
commit e66a379d5a
7 changed files with 99 additions and 310 deletions

View File

@ -8,7 +8,7 @@ options:
type: string
description: "Enable verbose logging"
openstack-origin:
default: cloud:precise-folsom
default: cloud:precise-grizzly
type: string
description: |
Repository from which to install. May be one of the following:

View File

@ -1,6 +1,8 @@
import os
import uuid
import ConfigParser
import sys
from lib.utils import juju_log
RABBIT_USER = "ceilometer"
RABBIT_VHOST = "ceilometer"
@ -56,6 +58,6 @@ def modify_config_file(nova_conf, values):
config.write(f)
f.close()
except IOError as e:
except IOError:
juju_log('ERROR', 'Error updating nova config file')
sys.exit(1)

View File

@ -1,18 +1,14 @@
#!/usr/bin/python
import sys
import time
import os
import utils
import lib.utils as utils
import ceilometer_utils
def install():
utils.configure_source()
utils.install(*ceilometer_utils.CEILOMETER_PACKAGES)
port = ceilometer_utils.CEILOMETER_PORT
utils.expose(port)
utils.expose(ceilometer_utils.CEILOMETER_PORT)
def amqp_joined():
@ -23,7 +19,7 @@ def amqp_joined():
def amqp_changed():
if render_ceilometer_conf():
utils.restart(*ceilometer_utils.CEILOMETER_SERVICES)
ceilometer_changed()
ceilometer_joined()
def db_joined():
@ -33,7 +29,7 @@ def db_joined():
def db_changed():
if render_ceilometer_conf():
utils.restart(*ceilometer_utils.CEILOMETER_SERVICES)
ceilometer_changed()
ceilometer_joined()
def keystone_joined():
@ -48,7 +44,7 @@ def keystone_joined():
def keystone_changed():
if render_ceilometer_conf():
utils.restart(*ceilometer_utils.CEILOMETER_SERVICES)
ceilometer_changed()
ceilometer_joined()
def get_rabbit_conf():
@ -62,6 +58,10 @@ def get_rabbit_conf():
"rabbit_password": utils.relation_get('password',
unit, relid)
}
if utils.relation_get('clustered',
unit, relid):
conf["rabbit_host"] = utils.relation_get('vip',
unit, relid)
if None not in conf.itervalues():
return conf
return None
@ -84,12 +84,15 @@ def get_keystone_conf():
for relid in utils.relation_ids('identity-service'):
for unit in utils.relation_list(relid):
keystone_username = utils.relation_get('service_username',
unit, relid)
keystone_port = utils.relation_get('service_port', unit, relid)
keystone_host = utils.relation_get('service_host', unit, relid)
unit, relid)
keystone_port = utils.relation_get('service_port',
unit, relid)
keystone_host = utils.relation_get('service_host',
unit, relid)
keystone_password = utils.relation_get('service_password',
unit, relid)
keystone_tenant = utils.relation_get('service_tenant', unit, relid)
unit, relid)
keystone_tenant = utils.relation_get('service_tenant',
unit, relid)
conf = {
"keystone_os_username": keystone_username,
@ -125,29 +128,19 @@ def render_ceilometer_conf():
def ceilometer_joined():
# update metering secret
metering_secret = ceilometer_utils.get_shared_secret()
for relid in utils.relation_ids('ceilometer-service'):
utils.relation_set(metering_secret=metering_secret, rid=relid)
def ceilometer_changed():
# set all relationships for ceilometer service
context = get_rabbit_conf()
contextdb = get_db_conf()
contextkeystone = get_keystone_conf()
if context and contextdb and contextkeystone:
context.update(contextdb)
context.update(contextkeystone)
context["metering_secret"] = ceilometer_utils.get_shared_secret()
# set all that info into ceilometer-service relationship
for relid in utils.relation_ids('ceilometer-service'):
for unit in utils.relation_list(relid):
context["rid"] = relid
utils.relation_set(**context)
context["rid"] = relid
utils.relation_set(**context)
utils.do_hooks({
"install": install,
@ -157,7 +150,5 @@ utils.do_hooks({
"shared-db-relation-changed": db_changed,
"identity-service-relation-joined": keystone_joined,
"identity-service-relation-changed": keystone_changed,
"ceilometer-service-relation-joined": ceilometer_joined,
"ceilometer-service-relation-changed": ceilometer_changed
"ceilometer-service-relation-joined": ceilometer_joined
})
sys.exit(0)

View File

@ -1,2 +0,0 @@

View File

@ -2,7 +2,9 @@
# Common python helper functions used for OpenStack charms.
import apt_pkg as apt
import subprocess
import os
CLOUD_ARCHIVE_URL = "http://ubuntu-cloud.archive.canonical.com/ubuntu"
CLOUD_ARCHIVE_KEY_ID = '5EDB1B62EC4926EA'
@ -11,7 +13,7 @@ ubuntu_openstack_release = {
'oneiric': 'diablo',
'precise': 'essex',
'quantal': 'folsom',
'raring': 'grizzly'
'raring': 'grizzly',
}
@ -19,7 +21,18 @@ openstack_codenames = {
'2011.2': 'diablo',
'2012.1': 'essex',
'2012.2': 'folsom',
'2012.3': 'grizzly'
'2013.1': 'grizzly',
'2013.2': 'havana',
}
# The ugly duckling
swift_codenames = {
'1.4.3': 'diablo',
'1.4.8': 'essex',
'1.7.4': 'folsom',
'1.7.6': 'grizzly',
'1.7.7': 'grizzly',
'1.8.0': 'grizzly',
}
@ -62,7 +75,7 @@ def get_os_codename_install_source(src):
return ca_rel
# Best guess match based on deb string provided
if src.startswith('deb'):
if src.startswith('deb') or src.startswith('ppa'):
for k, v in openstack_codenames.iteritems():
if v in src:
return v
@ -89,52 +102,54 @@ def get_os_version_codename(codename):
def get_os_codename_package(pkg):
'''Derive OpenStack release codename from an installed package.'''
cmd = ['dpkg', '-l', pkg]
apt.init()
cache = apt.Cache()
try:
output = subprocess.check_output(cmd)
except subprocess.CalledProcessError:
e = 'Could not derive OpenStack version from package that is not '\
'installed; %s' % pkg
error_out(e)
def _clean(line):
line = line.split(' ')
clean = []
for c in line:
if c != '':
clean.append(c)
return clean
vers = None
for l in output.split('\n'):
if l.startswith('ii'):
l = _clean(l)
if l[1] == pkg:
vers = l[2]
if not vers:
pkg = cache[pkg]
except:
e = 'Could not determine version of installed package: %s' % pkg
error_out(e)
vers = vers[:6]
vers = apt.UpstreamVersion(pkg.current_ver.ver_str)
try:
return openstack_codenames[vers]
if 'swift' in pkg.name:
vers = vers[:5]
return swift_codenames[vers]
else:
vers = vers[:6]
return openstack_codenames[vers]
except KeyError:
e = 'Could not determine OpenStack codename for version %s' % vers
error_out(e)
def get_os_version_package(pkg):
'''Derive OpenStack version number from an installed package.'''
codename = get_os_codename_package(pkg)
if 'swift' in pkg:
vers_map = swift_codenames
else:
vers_map = openstack_codenames
for version, cname in vers_map.iteritems():
if cname == codename:
return version
e = "Could not determine OpenStack version for package: %s" % pkg
error_out(e)
def configure_installation_source(rel):
'''Configure apt installation source.'''
def _import_key(id):
def _import_key(keyid):
cmd = "apt-key adv --keyserver keyserver.ubuntu.com " \
"--recv-keys %s" % id
"--recv-keys %s" % keyid
try:
subprocess.check_call(cmd.split(' '))
except:
error_out("Error importing repo key %s" % id)
except subprocess.CalledProcessError:
error_out("Error importing repo key %s" % keyid)
if rel == 'distro':
return
@ -165,10 +180,11 @@ def configure_installation_source(rel):
'version (%s)' % (ca_rel, ubuntu_rel)
error_out(e)
if ca_rel == 'folsom/staging':
if 'staging' in ca_rel:
# staging is just a regular PPA.
cmd = 'add-apt-repository -y ppa:ubuntu-cloud-archive/'\
'folsom-staging'
os_rel = ca_rel.split('/')[0]
ppa = 'ppa:ubuntu-cloud-archive/%s-staging' % os_rel
cmd = 'add-apt-repository -y %s' % ppa
subprocess.check_call(cmd.split(' '))
return
@ -176,7 +192,10 @@ def configure_installation_source(rel):
pockets = {
'folsom': 'precise-updates/folsom',
'folsom/updates': 'precise-updates/folsom',
'folsom/proposed': 'precise-proposed/folsom'
'folsom/proposed': 'precise-proposed/folsom',
'grizzly': 'precise-updates/grizzly',
'grizzly/updates': 'precise-updates/grizzly',
'grizzly/proposed': 'precise-proposed/grizzly'
}
try:
@ -192,3 +211,20 @@ def configure_installation_source(rel):
f.write(src)
else:
error_out("Invalid openstack-release specified: %s" % rel)
def save_script_rc(script_path="scripts/scriptrc", **env_vars):
"""
Write an rc file in the charm-delivered directory containing
exported environment variables provided by env_vars. Any charm scripts run
outside the juju hook environment can source this scriptrc to obtain
updated config information necessary to perform health checks or
service changes.
"""
unit_name = os.getenv('JUJU_UNIT_NAME').replace('/', '-')
juju_rc_path = "/var/lib/juju/units/%s/charm/%s" % (unit_name, script_path)
with open(juju_rc_path, 'wb') as rc_script:
rc_script.write(
"#!/bin/bash\n")
[rc_script.write('export %s=%s\n' % (u, p))
for u, p in env_vars.iteritems() if u != "script_path"]

View File

@ -1,239 +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 apt_pkg as apt
import re
import ceilometer_utils
def do_hooks(hooks):
hook = os.path.basename(sys.argv[0])
try:
hook_func = hooks[hook]
except KeyError:
juju_log('INFO',
"This charm doesn't know how to handle '{}'.".format(hook))
else:
hook_func()
def install(*pkgs):
cmd = [
'apt-get',
'-y',
'install'
]
for pkg in pkgs:
cmd.append(pkg)
subprocess.check_call(cmd)
TEMPLATES_DIR = 'templates'
try:
import jinja2
except ImportError:
install('python-jinja2')
import jinja2
def render_template(template_name, context, template_dir=TEMPLATES_DIR):
templates = jinja2.Environment(
loader=jinja2.FileSystemLoader(template_dir)
)
template = templates.get_template(template_name)
return template.render(context)
CLOUD_ARCHIVE = \
""" # Ubuntu Cloud Archive
deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
"""
CLOUD_ARCHIVE_POCKETS = {
'precise-folsom': 'precise-updates/folsom',
'precise-folsom/updates': 'precise-updates/folsom',
'precise-folsom/proposed': 'precise-proposed/folsom',
'precise-grizzly': 'precise-updates/grizzly',
'precise-grizzly/updates': 'precise-updates/grizzly',
'precise-grizzly/proposed': 'precise-proposed/grizzly'
}
def configure_source():
source = str(config_get('openstack-origin'))
if not source:
return
if source.startswith('ppa:'):
cmd = [
'add-apt-repository',
source
]
subprocess.check_call(cmd)
if source.startswith('cloud:'):
install('ubuntu-cloud-keyring')
pocket = source.split(':')[1]
with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as apt:
apt.write(CLOUD_ARCHIVE.format(CLOUD_ARCHIVE_POCKETS[pocket]))
if source.startswith('deb'):
l = len(source.split('|'))
if l == 2:
(apt_line, key) = source.split('|')
cmd = [
'apt-key',
'adv', '--keyserver keyserver.ubuntu.com',
'--recv-keys', key
]
subprocess.check_call(cmd)
elif l == 1:
apt_line = source
with open('/etc/apt/sources.list.d/ceilometer.list', 'w') as apt:
apt.write(apt_line + "\n")
cmd = [
'apt-get',
'update'
]
subprocess.check_call(cmd)
# Protocols
TCP = 'TCP'
UDP = 'UDP'
def expose(port, protocol='TCP'):
cmd = [
'open-port',
'{}/{}'.format(port, protocol)
]
subprocess.check_call(cmd)
def unexpose(port, protocol='TCP'):
cmd = [
'close-port',
'{}/{}'.format(port, protocol)
]
subprocess.check_call(cmd)
def juju_log(severity, message):
cmd = [
'juju-log',
'--log-level', severity,
message
]
subprocess.check_call(cmd)
def relation_ids(relation):
cmd = [
'relation-ids',
relation
]
return subprocess.check_output(cmd).split() # IGNORE:E1103
def relation_list(rid):
cmd = [
'relation-list',
'-r', rid,
]
return subprocess.check_output(cmd).split() # IGNORE:E1103
def relation_get(attribute, unit=None, rid=None):
cmd = [
'relation-get',
]
if rid:
cmd.append('-r')
cmd.append(rid)
cmd.append(attribute)
if unit:
cmd.append(unit)
value = subprocess.check_output(cmd).strip() # IGNORE:E1103
if value == "":
return None
else:
return value
def relation_set(**kwargs):
cmd = [
'relation-set'
]
args = []
for k, v in kwargs.items():
if k == 'rid':
cmd.append('-r')
cmd.append(v)
else:
args.append('{}={}'.format(k, v))
cmd += args
subprocess.check_call(cmd)
def unit_get(attribute):
cmd = [
'unit-get',
attribute
]
value = subprocess.check_output(cmd).strip() # IGNORE:E1103
if value == "":
return None
else:
return value
def config_get(attribute):
cmd = [
'config-get',
attribute
]
value = subprocess.check_output(cmd).strip() # IGNORE:E1103
if value == "":
return None
else:
return value
def get_unit_hostname():
return socket.gethostname()
def _service_ctl(service, action):
subprocess.check_call(['service', service, action])
def restart(*services):
for service in services:
_service_ctl(service, 'restart')
def stop(*services):
for service in services:
_service_ctl(service, 'stop')
def start(*services):
for service in services:
_service_ctl(service, 'start')
def get_os_version(package=None):
apt.init()
cache = apt.Cache()
pkg = cache[package or 'quantum-common']
if pkg.current_ver:
return apt.upstream_version(pkg.current_ver.ver_str)
else:
return None

View File

@ -23,3 +23,4 @@ auth_protocol = http
admin_tenant_name = {{ keystone_os_tenant }}
admin_user = {{ keystone_os_username }}
admin_password = {{ keystone_os_password }}