3
# Common python helper functions used for OpenStack charms.
5
from collections import OrderedDict
12
from charmhelpers.core.hookenv import (
18
from charmhelpers.core.host import (
23
CLOUD_ARCHIVE_URL = "http://ubuntu-cloud.archive.canonical.com/ubuntu"
24
CLOUD_ARCHIVE_KEY_ID = '5EDB1B62EC4926EA'
26
UBUNTU_OPENSTACK_RELEASE = OrderedDict([
27
('oneiric', 'diablo'),
29
('quantal', 'folsom'),
30
('raring', 'grizzly'),
35
OPENSTACK_CODENAMES = OrderedDict([
39
('2013.1', 'grizzly'),
41
('2014.1', 'icehouse'),
58
juju_log("FATAL ERROR: %s" % msg, level='ERROR')
62
def get_os_codename_install_source(src):
63
'''Derive OpenStack release codename from a given installation source.'''
64
ubuntu_rel = lsb_release()['DISTRIB_CODENAME']
68
rel = UBUNTU_OPENSTACK_RELEASE[ubuntu_rel]
70
e = 'Could not derive openstack release for '\
71
'this Ubuntu release: %s' % ubuntu_rel
75
if src.startswith('cloud:'):
76
ca_rel = src.split(':')[1]
77
ca_rel = ca_rel.split('%s-' % ubuntu_rel)[1].split('/')[0]
80
# Best guess match based on deb string provided
81
if src.startswith('deb') or src.startswith('ppa'):
82
for k, v in OPENSTACK_CODENAMES.iteritems():
87
def get_os_version_install_source(src):
88
codename = get_os_codename_install_source(src)
89
return get_os_version_codename(codename)
92
def get_os_codename_version(vers):
93
'''Determine OpenStack codename from version number.'''
95
return OPENSTACK_CODENAMES[vers]
97
e = 'Could not determine OpenStack codename for version %s' % vers
101
def get_os_version_codename(codename):
102
'''Determine OpenStack version number from codename.'''
103
for k, v in OPENSTACK_CODENAMES.iteritems():
106
e = 'Could not derive OpenStack version for '\
107
'codename: %s' % codename
111
def get_os_codename_package(package, fatal=True):
112
'''Derive OpenStack release codename from an installed package.'''
121
# the package is unknown to the current apt cache.
122
e = 'Could not determine version of package with no installation '\
123
'candidate: %s' % package
126
if not pkg.current_ver:
129
# package is known, but no version is currently installed.
130
e = 'Could not determine version of uninstalled package: %s' % package
133
vers = apt.UpstreamVersion(pkg.current_ver.ver_str)
136
if 'swift' in pkg.name:
138
return SWIFT_CODENAMES[vers]
141
return OPENSTACK_CODENAMES[vers]
143
e = 'Could not determine OpenStack codename for version %s' % vers
147
def get_os_version_package(pkg, fatal=True):
148
'''Derive OpenStack version number from an installed package.'''
149
codename = get_os_codename_package(pkg, fatal=fatal)
155
vers_map = SWIFT_CODENAMES
157
vers_map = OPENSTACK_CODENAMES
159
for version, cname in vers_map.iteritems():
160
if cname == codename:
162
#e = "Could not determine OpenStack version for package: %s" % pkg
166
def import_key(keyid):
167
cmd = "apt-key adv --keyserver keyserver.ubuntu.com " \
168
"--recv-keys %s" % keyid
170
subprocess.check_call(cmd.split(' '))
171
except subprocess.CalledProcessError:
172
error_out("Error importing repo key %s" % keyid)
175
def configure_installation_source(rel):
176
'''Configure apt installation source.'''
179
elif rel[:4] == "ppa:":
181
subprocess.check_call(["add-apt-repository", "-y", src])
182
elif rel[:3] == "deb":
183
l = len(rel.split('|'))
185
src, key = rel.split('|')
186
juju_log("Importing PPA key from keyserver for %s" % src)
190
with open('/etc/apt/sources.list.d/juju_deb.list', 'w') as f:
192
elif rel[:6] == 'cloud:':
193
ubuntu_rel = lsb_release()['DISTRIB_CODENAME']
194
rel = rel.split(':')[1]
195
u_rel = rel.split('-')[0]
196
ca_rel = rel.split('-')[1]
198
if u_rel != ubuntu_rel:
199
e = 'Cannot install from Cloud Archive pocket %s on this Ubuntu '\
200
'version (%s)' % (ca_rel, ubuntu_rel)
203
if 'staging' in ca_rel:
204
# staging is just a regular PPA.
205
os_rel = ca_rel.split('/')[0]
206
ppa = 'ppa:ubuntu-cloud-archive/%s-staging' % os_rel
207
cmd = 'add-apt-repository -y %s' % ppa
208
subprocess.check_call(cmd.split(' '))
211
# map charm config options to actual archive pockets.
213
'folsom': 'precise-updates/folsom',
214
'folsom/updates': 'precise-updates/folsom',
215
'folsom/proposed': 'precise-proposed/folsom',
216
'grizzly': 'precise-updates/grizzly',
217
'grizzly/updates': 'precise-updates/grizzly',
218
'grizzly/proposed': 'precise-proposed/grizzly',
219
'havana': 'precise-updates/havana',
220
'havana/updates': 'precise-updates/havana',
221
'havana/proposed': 'precise-proposed/havana',
225
pocket = pockets[ca_rel]
227
e = 'Invalid Cloud Archive release specified: %s' % rel
230
src = "deb %s %s main" % (CLOUD_ARCHIVE_URL, pocket)
231
apt_install('ubuntu-cloud-keyring', fatal=True)
233
with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as f:
236
error_out("Invalid openstack-release specified: %s" % rel)
239
def save_script_rc(script_path="scripts/scriptrc", **env_vars):
241
Write an rc file in the charm-delivered directory containing
242
exported environment variables provided by env_vars. Any charm scripts run
243
outside the juju hook environment can source this scriptrc to obtain
244
updated config information necessary to perform health checks or
247
juju_rc_path = "%s/%s" % (charm_dir(), script_path)
248
if not os.path.exists(os.path.dirname(juju_rc_path)):
249
os.mkdir(os.path.dirname(juju_rc_path))
250
with open(juju_rc_path, 'wb') as rc_script:
253
[rc_script.write('export %s=%s\n' % (u, p))
254
for u, p in env_vars.iteritems() if u != "script_path"]
257
def openstack_upgrade_available(package):
259
Determines if an OpenStack upgrade is available from installation
260
source, based on version of installed package.
262
:param package: str: Name of installed package.
264
:returns: bool: : Returns True if configured installation source offers
265
a newer version of package.
269
src = config('openstack-origin')
270
cur_vers = get_os_version_package(package)
271
available_vers = get_os_version_install_source(src)
273
return apt.version_compare(available_vers, cur_vers) == 1