2012-12-12 09:18:54 -08:00
|
|
|
#!/usr/bin/python
|
|
|
|
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import shutil
|
|
|
|
import uuid
|
2013-09-27 13:02:37 +01:00
|
|
|
import subprocess
|
|
|
|
|
|
|
|
import charmhelpers.contrib.openstack.utils as openstack
|
|
|
|
import charmhelpers.contrib.hahelpers.cluster as cluster
|
|
|
|
from swift_utils import (
|
|
|
|
register_configs,
|
|
|
|
restart_map,
|
|
|
|
determine_packages,
|
|
|
|
ensure_swift_dir,
|
2014-01-20 12:05:14 +00:00
|
|
|
SWIFT_RINGS, get_www_dir,
|
2013-09-27 13:02:37 +01:00
|
|
|
initialize_ring,
|
|
|
|
swift_user,
|
|
|
|
SWIFT_HA_RES,
|
|
|
|
balance_ring,
|
|
|
|
SWIFT_CONF_DIR,
|
|
|
|
get_zone,
|
|
|
|
exists_in_ring,
|
|
|
|
add_to_ring,
|
|
|
|
should_balance,
|
2013-09-27 13:16:22 +01:00
|
|
|
do_openstack_upgrade,
|
|
|
|
write_rc_script
|
2013-09-27 13:02:37 +01:00
|
|
|
)
|
|
|
|
from swift_context import get_swift_hash
|
|
|
|
|
|
|
|
from charmhelpers.core.hookenv import (
|
|
|
|
config,
|
|
|
|
unit_get,
|
|
|
|
relation_set,
|
|
|
|
relation_ids,
|
|
|
|
relation_get,
|
|
|
|
log, ERROR,
|
|
|
|
Hooks, UnregisteredHookError,
|
|
|
|
open_port
|
|
|
|
)
|
|
|
|
from charmhelpers.core.host import (
|
|
|
|
service_restart,
|
|
|
|
restart_on_change
|
|
|
|
)
|
|
|
|
from charmhelpers.fetch import (
|
|
|
|
apt_install,
|
|
|
|
apt_update
|
|
|
|
)
|
2013-09-27 17:11:20 +01:00
|
|
|
from charmhelpers.payload.execd import execd_preinstall
|
2014-06-27 11:56:24 +01:00
|
|
|
from charmhelpers.contrib.network.ip import get_address_in_network
|
2012-12-12 09:18:54 -08:00
|
|
|
|
2013-02-27 16:07:46 +00:00
|
|
|
extra_pkgs = [
|
|
|
|
"haproxy",
|
|
|
|
"python-jinja2"
|
2013-09-27 13:02:37 +01:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
hooks = Hooks()
|
2013-02-27 16:07:46 +00:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
CONFIGS = register_configs()
|
2013-03-12 11:17:32 +00:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
|
|
|
|
@hooks.hook('install')
|
2012-12-12 09:18:54 -08:00
|
|
|
def install():
|
2013-09-27 17:11:20 +01:00
|
|
|
execd_preinstall()
|
2013-09-27 13:02:37 +01:00
|
|
|
src = config('openstack-origin')
|
2012-12-12 09:18:54 -08:00
|
|
|
if src != 'distro':
|
|
|
|
openstack.configure_installation_source(src)
|
2013-09-27 13:02:37 +01:00
|
|
|
apt_update(fatal=True)
|
2012-12-12 09:18:54 -08:00
|
|
|
rel = openstack.get_os_codename_install_source(src)
|
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
pkgs = determine_packages(rel)
|
|
|
|
apt_install(pkgs, fatal=True)
|
|
|
|
apt_install(extra_pkgs, fatal=True)
|
2012-12-12 09:18:54 -08:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
ensure_swift_dir()
|
2012-12-12 09:18:54 -08:00
|
|
|
# initialize new storage rings.
|
2013-09-27 13:02:37 +01:00
|
|
|
for ring in SWIFT_RINGS.iteritems():
|
|
|
|
initialize_ring(ring[1],
|
|
|
|
config('partition-power'),
|
|
|
|
config('replicas'),
|
|
|
|
config('min-hours'))
|
2012-12-12 09:18:54 -08:00
|
|
|
|
|
|
|
# configure a directory on webserver for distributing rings.
|
2014-01-20 12:05:14 +00:00
|
|
|
www_dir = get_www_dir()
|
|
|
|
if not os.path.isdir(www_dir):
|
2014-04-10 17:52:10 +01:00
|
|
|
os.mkdir(www_dir, 0o755)
|
2013-09-27 13:02:37 +01:00
|
|
|
uid, gid = swift_user()
|
2014-01-20 12:05:14 +00:00
|
|
|
os.chown(www_dir, uid, gid)
|
2012-12-12 09:18:54 -08:00
|
|
|
|
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
@hooks.hook('identity-service-relation-joined')
|
2012-12-12 09:18:54 -08:00
|
|
|
def keystone_joined(relid=None):
|
2013-09-27 13:02:37 +01:00
|
|
|
if not cluster.eligible_leader(SWIFT_HA_RES):
|
2013-02-27 21:25:38 +00:00
|
|
|
return
|
2013-03-12 11:17:32 +00:00
|
|
|
if cluster.is_clustered():
|
2014-06-27 11:56:24 +01:00
|
|
|
public_ip, internal_ip, admin_ip = config('vip')
|
2013-02-27 16:07:46 +00:00
|
|
|
else:
|
2014-06-27 11:56:24 +01:00
|
|
|
public_ip = get_address_in_network(config('os-public-network'),
|
|
|
|
unit_get('public-address'))
|
|
|
|
internal_ip = get_address_in_network(config('os-internal-network'),
|
|
|
|
unit_get('private-address'))
|
2014-06-27 12:01:56 +01:00
|
|
|
admin_ip = get_address_in_network(config('os-admin-network'),
|
2014-06-27 11:56:24 +01:00
|
|
|
unit_get('private-address'))
|
2013-09-27 13:02:37 +01:00
|
|
|
port = config('bind-port')
|
2013-03-12 11:17:32 +00:00
|
|
|
if cluster.https():
|
2012-12-12 09:18:54 -08:00
|
|
|
proto = 'https'
|
|
|
|
else:
|
|
|
|
proto = 'http'
|
2014-06-27 11:56:24 +01:00
|
|
|
admin_url = '%s://%s:%s' % (proto, admin_ip, port)
|
|
|
|
internal_url = '%s://%s:%s/v1/AUTH_$(tenant_id)s' % (proto, internal_ip,
|
|
|
|
port)
|
|
|
|
public_url = '%s://%s:%s/v1/AUTH_$(tenant_id)s' % (proto, public_ip,
|
|
|
|
port)
|
2013-09-27 13:02:37 +01:00
|
|
|
relation_set(service='swift',
|
|
|
|
region=config('region'),
|
2014-06-27 11:56:24 +01:00
|
|
|
public_url=public_url,
|
|
|
|
internal_url=internal_url,
|
2013-09-27 13:02:37 +01:00
|
|
|
admin_url=admin_url,
|
|
|
|
requested_roles=config('operator-roles'),
|
|
|
|
relation_id=relid)
|
2012-12-12 09:18:54 -08:00
|
|
|
|
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
@hooks.hook('identity-service-relation-changed')
|
|
|
|
@restart_on_change(restart_map())
|
2012-12-12 09:18:54 -08:00
|
|
|
def keystone_changed():
|
2013-09-27 13:02:37 +01:00
|
|
|
configure_https()
|
2012-12-12 09:18:54 -08:00
|
|
|
|
|
|
|
|
|
|
|
def balance_rings():
|
|
|
|
'''handle doing ring balancing and distribution.'''
|
|
|
|
new_ring = False
|
2013-09-27 13:02:37 +01:00
|
|
|
for ring in SWIFT_RINGS.itervalues():
|
|
|
|
if balance_ring(ring):
|
|
|
|
log('Balanced ring %s' % ring)
|
2012-12-12 09:18:54 -08:00
|
|
|
new_ring = True
|
|
|
|
if not new_ring:
|
|
|
|
return
|
|
|
|
|
2014-01-20 12:05:14 +00:00
|
|
|
www_dir = get_www_dir()
|
2013-09-27 13:02:37 +01:00
|
|
|
for ring in SWIFT_RINGS.keys():
|
2012-12-12 09:18:54 -08:00
|
|
|
f = '%s.ring.gz' % ring
|
2013-09-27 13:02:37 +01:00
|
|
|
shutil.copyfile(os.path.join(SWIFT_CONF_DIR, f),
|
2014-01-20 12:05:14 +00:00
|
|
|
os.path.join(www_dir, f))
|
2012-12-12 09:18:54 -08:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
if cluster.eligible_leader(SWIFT_HA_RES):
|
2013-02-27 16:18:34 +00:00
|
|
|
msg = 'Broadcasting notification to all storage nodes that new '\
|
|
|
|
'ring is ready for consumption.'
|
2013-09-27 13:02:37 +01:00
|
|
|
log(msg)
|
2014-01-22 17:10:47 +00:00
|
|
|
path = os.path.basename(www_dir)
|
2013-02-27 16:18:34 +00:00
|
|
|
trigger = uuid.uuid4()
|
2013-04-05 16:49:46 -04:00
|
|
|
|
|
|
|
if cluster.is_clustered():
|
2013-09-27 13:02:37 +01:00
|
|
|
hostname = config('vip')
|
2013-04-05 16:49:46 -04:00
|
|
|
else:
|
2013-09-27 13:02:37 +01:00
|
|
|
hostname = unit_get('private-address')
|
2013-04-05 16:49:46 -04:00
|
|
|
|
|
|
|
rings_url = 'http://%s/%s' % (hostname, path)
|
2013-02-27 16:18:34 +00:00
|
|
|
# notify storage nodes that there is a new ring to fetch.
|
2013-09-27 13:02:37 +01:00
|
|
|
for relid in relation_ids('swift-storage'):
|
|
|
|
relation_set(relation_id=relid, swift_hash=get_swift_hash(),
|
|
|
|
rings_url=rings_url, trigger=trigger)
|
2013-02-27 16:07:46 +00:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
service_restart('swift-proxy')
|
2012-12-12 09:18:54 -08:00
|
|
|
|
2013-03-12 11:17:32 +00:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
@hooks.hook('swift-storage-relation-changed')
|
|
|
|
@restart_on_change(restart_map())
|
2012-12-18 11:59:19 -08:00
|
|
|
def storage_changed():
|
2013-09-27 13:02:37 +01:00
|
|
|
zone = get_zone(config('zone-assignment'))
|
2012-12-12 09:18:54 -08:00
|
|
|
node_settings = {
|
2013-09-27 13:02:37 +01:00
|
|
|
'ip': openstack.get_host_ip(relation_get('private-address')),
|
2012-12-14 15:07:01 -08:00
|
|
|
'zone': zone,
|
2013-09-27 13:02:37 +01:00
|
|
|
'account_port': relation_get('account_port'),
|
|
|
|
'object_port': relation_get('object_port'),
|
|
|
|
'container_port': relation_get('container_port'),
|
2012-12-12 09:18:54 -08:00
|
|
|
}
|
|
|
|
if None in node_settings.itervalues():
|
2013-09-27 13:02:37 +01:00
|
|
|
log('storage_changed: Relation not ready.')
|
2012-12-12 09:18:54 -08:00
|
|
|
return None
|
|
|
|
|
|
|
|
for k in ['zone', 'account_port', 'object_port', 'container_port']:
|
|
|
|
node_settings[k] = int(node_settings[k])
|
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
CONFIGS.write_all()
|
2012-12-12 09:18:54 -08:00
|
|
|
|
|
|
|
# allow for multiple devs per unit, passed along as a : separated list
|
2013-09-27 13:02:37 +01:00
|
|
|
devs = relation_get('device').split(':')
|
2012-12-12 09:18:54 -08:00
|
|
|
for dev in devs:
|
|
|
|
node_settings['device'] = dev
|
2013-09-27 13:02:37 +01:00
|
|
|
for ring in SWIFT_RINGS.itervalues():
|
|
|
|
if not exists_in_ring(ring, node_settings):
|
|
|
|
add_to_ring(ring, node_settings)
|
2012-12-12 09:18:54 -08:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
if should_balance([r for r in SWIFT_RINGS.itervalues()]):
|
2012-12-12 09:18:54 -08:00
|
|
|
balance_rings()
|
|
|
|
|
2013-03-12 11:17:32 +00:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
@hooks.hook('swift-storage-relation-broken')
|
|
|
|
@restart_on_change(restart_map())
|
2012-12-18 11:59:19 -08:00
|
|
|
def storage_broken():
|
2013-09-27 13:02:37 +01:00
|
|
|
CONFIGS.write_all()
|
2012-12-12 09:18:54 -08:00
|
|
|
|
2013-03-12 11:17:32 +00:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
@hooks.hook('config-changed')
|
|
|
|
@restart_on_change(restart_map())
|
2012-12-12 09:18:54 -08:00
|
|
|
def config_changed():
|
2013-09-27 13:02:37 +01:00
|
|
|
configure_https()
|
|
|
|
open_port(config('bind-port'))
|
2013-05-22 14:30:39 -07:00
|
|
|
# Determine whether or not we should do an upgrade, based on the
|
|
|
|
# the version offered in keyston-release.
|
2014-03-06 13:45:35 +00:00
|
|
|
if (openstack.openstack_upgrade_available('python-swift')):
|
|
|
|
do_openstack_upgrade(CONFIGS)
|
2014-06-27 11:56:24 +01:00
|
|
|
for r_id in relation_ids('identity-service'):
|
2014-06-27 12:00:03 +01:00
|
|
|
keystone_joined(relid=r_id)
|
2013-02-27 16:07:46 +00:00
|
|
|
|
2013-02-27 16:18:34 +00:00
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
@hooks.hook('cluster-relation-changed',
|
|
|
|
'cluster-relation-joined')
|
|
|
|
@restart_on_change(restart_map())
|
2013-02-27 16:07:46 +00:00
|
|
|
def cluster_changed():
|
2013-09-27 13:02:37 +01:00
|
|
|
CONFIGS.write_all()
|
2013-02-27 16:07:46 +00:00
|
|
|
|
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
@hooks.hook('ha-relation-changed')
|
2013-02-27 16:07:46 +00:00
|
|
|
def ha_relation_changed():
|
2013-09-27 13:02:37 +01:00
|
|
|
clustered = relation_get('clustered')
|
|
|
|
if clustered and cluster.is_leader(SWIFT_HA_RES):
|
|
|
|
log('Cluster configured, notifying other services and'
|
|
|
|
'updating keystone endpoint configuration')
|
2013-02-27 16:07:46 +00:00
|
|
|
# Tell all related services to start using
|
2013-03-01 23:20:05 +00:00
|
|
|
# the VIP instead
|
2013-09-27 13:02:37 +01:00
|
|
|
for r_id in relation_ids('identity-service'):
|
2013-02-27 16:07:46 +00:00
|
|
|
keystone_joined(relid=r_id)
|
|
|
|
|
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
@hooks.hook('ha-relation-joined')
|
2013-02-27 16:07:46 +00:00
|
|
|
def ha_relation_joined():
|
|
|
|
# Obtain the config values necessary for the cluster config. These
|
|
|
|
# include multicast port and interface to bind to.
|
2013-09-27 13:02:37 +01:00
|
|
|
corosync_bindiface = config('ha-bindiface')
|
|
|
|
corosync_mcastport = config('ha-mcastport')
|
|
|
|
vip = config('vip')
|
|
|
|
vip_cidr = config('vip_cidr')
|
|
|
|
vip_iface = config('vip_iface')
|
2013-02-27 16:07:46 +00:00
|
|
|
if not vip:
|
2013-09-27 13:02:37 +01:00
|
|
|
log('Unable to configure hacluster as vip not provided',
|
|
|
|
level=ERROR)
|
2013-02-27 16:07:46 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
# Obtain resources
|
|
|
|
resources = {
|
2013-09-27 13:02:37 +01:00
|
|
|
'res_swift_vip': 'ocf:heartbeat:IPaddr2',
|
|
|
|
'res_swift_haproxy': 'lsb:haproxy'
|
|
|
|
}
|
2013-02-27 16:07:46 +00:00
|
|
|
resource_params = {
|
2013-09-27 13:02:37 +01:00
|
|
|
'res_swift_vip': 'params ip="%s" cidr_netmask="%s" nic="%s"' %
|
|
|
|
(vip, vip_cidr, vip_iface),
|
|
|
|
'res_swift_haproxy': 'op monitor interval="5s"'
|
|
|
|
}
|
2013-02-27 16:07:46 +00:00
|
|
|
init_services = {
|
2013-09-27 13:02:37 +01:00
|
|
|
'res_swift_haproxy': 'haproxy'
|
|
|
|
}
|
2013-02-27 16:07:46 +00:00
|
|
|
clones = {
|
2013-09-27 13:02:37 +01:00
|
|
|
'cl_swift_haproxy': 'res_swift_haproxy'
|
|
|
|
}
|
|
|
|
|
|
|
|
relation_set(init_services=init_services,
|
|
|
|
corosync_bindiface=corosync_bindiface,
|
|
|
|
corosync_mcastport=corosync_mcastport,
|
|
|
|
resources=resources,
|
|
|
|
resource_params=resource_params,
|
|
|
|
clones=clones)
|
|
|
|
|
|
|
|
|
|
|
|
def configure_https():
|
|
|
|
'''
|
|
|
|
Enables SSL API Apache config if appropriate and kicks identity-service
|
|
|
|
with any required api updates.
|
|
|
|
'''
|
|
|
|
# need to write all to ensure changes to the entire request pipeline
|
|
|
|
# propagate (c-api, haprxy, apache)
|
|
|
|
CONFIGS.write_all()
|
|
|
|
if 'https' in CONFIGS.complete_contexts():
|
|
|
|
cmd = ['a2ensite', 'openstack_https_frontend']
|
|
|
|
subprocess.check_call(cmd)
|
|
|
|
else:
|
|
|
|
cmd = ['a2dissite', 'openstack_https_frontend']
|
|
|
|
subprocess.check_call(cmd)
|
|
|
|
|
2013-09-27 13:16:22 +01:00
|
|
|
# Apache 2.4 required enablement of configuration
|
|
|
|
if os.path.exists('/usr/sbin/a2enconf'):
|
|
|
|
subprocess.check_call(['a2enconf', 'swift-rings'])
|
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
for rid in relation_ids('identity-service'):
|
|
|
|
keystone_joined(relid=rid)
|
|
|
|
|
2013-09-27 13:16:22 +01:00
|
|
|
write_rc_script()
|
|
|
|
|
2013-09-27 13:02:37 +01:00
|
|
|
|
|
|
|
def main():
|
|
|
|
try:
|
|
|
|
hooks.execute(sys.argv)
|
|
|
|
except UnregisteredHookError as e:
|
|
|
|
log('Unknown hook {} - skipping.'.format(e))
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|