~niedbalski/charms/trusty/swift-proxy/fix-lp-1308557

« back to all changes in this revision

Viewing changes to hooks/swift_hooks.py

  • Committer: James Page
  • Date: 2013-06-03 16:50:28 UTC
  • mfrom: (35.1.18 swift-proxy)
  • Revision ID: james.page@canonical.com-20130603165028-f9ya6llay65w3t9e
* Python rewrite

* Support for manually assigned storage zones

* Support for high availability via hacluster subordinate.

* Adds Grizzly compatibility.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
import os
 
4
import sys
 
5
import shutil
 
6
import uuid
 
7
from subprocess import check_call
 
8
 
 
9
import lib.openstack_common as openstack
 
10
import lib.utils as utils
 
11
import lib.cluster_utils as cluster
 
12
import swift_utils as swift
 
13
 
 
14
extra_pkgs = [
 
15
    "haproxy",
 
16
    "python-jinja2"
 
17
    ]
 
18
 
 
19
 
 
20
def install():
 
21
    src = utils.config_get('openstack-origin')
 
22
    if src != 'distro':
 
23
        openstack.configure_installation_source(src)
 
24
    check_call(['apt-get', 'update'])
 
25
    rel = openstack.get_os_codename_install_source(src)
 
26
 
 
27
    pkgs = swift.determine_packages(rel)
 
28
    utils.install(*pkgs)
 
29
    utils.install(*extra_pkgs)
 
30
 
 
31
    swift.ensure_swift_dir()
 
32
 
 
33
    # initialize swift configs.
 
34
    # swift.conf hash
 
35
    ctxt = {
 
36
        'swift_hash': swift.get_swift_hash()
 
37
    }
 
38
    with open(swift.SWIFT_CONF, 'w') as conf:
 
39
        conf.write(swift.render_config(swift.SWIFT_CONF, ctxt))
 
40
 
 
41
    # swift-proxy.conf
 
42
    swift.write_proxy_config()
 
43
 
 
44
    # memcached.conf
 
45
    ctxt = {'proxy_ip': utils.get_host_ip()}
 
46
    with open(swift.MEMCACHED_CONF, 'w') as conf:
 
47
        conf.write(swift.render_config(swift.MEMCACHED_CONF, ctxt))
 
48
    check_call(['service', 'memcached', 'restart'])
 
49
 
 
50
    # initialize new storage rings.
 
51
    for ring in swift.SWIFT_RINGS.iteritems():
 
52
        swift.initialize_ring(ring[1],
 
53
                              utils.config_get('partition-power'),
 
54
                              utils.config_get('replicas'),
 
55
                              utils.config_get('min-hours'))
 
56
 
 
57
    # configure a directory on webserver for distributing rings.
 
58
    if not os.path.isdir(swift.WWW_DIR):
 
59
        os.mkdir(swift.WWW_DIR, 0755)
 
60
    uid, gid = swift.swift_user()
 
61
    os.chown(swift.WWW_DIR, uid, gid)
 
62
    swift.write_apache_config()
 
63
    swift.configure_https()
 
64
 
 
65
 
 
66
def keystone_joined(relid=None):
 
67
    if not cluster.eligible_leader(swift.SWIFT_HA_RES):
 
68
        return
 
69
    if cluster.is_clustered():
 
70
        hostname = utils.config_get('vip')
 
71
    else:
 
72
        hostname = utils.unit_get('private-address')
 
73
    port = utils.config_get('bind-port')
 
74
    if cluster.https():
 
75
        proto = 'https'
 
76
    else:
 
77
        proto = 'http'
 
78
    admin_url = '%s://%s:%s' % (proto, hostname, port)
 
79
    internal_url = public_url = '%s/v1/AUTH_$(tenant_id)s' % admin_url
 
80
    utils.relation_set(service='swift',
 
81
                       region=utils.config_get('region'),
 
82
                       public_url=public_url, internal_url=internal_url,
 
83
                       admin_url=admin_url,
 
84
                       requested_roles=utils.config_get('operator-roles'),
 
85
                       rid=relid)
 
86
 
 
87
 
 
88
def keystone_changed():
 
89
    swift.write_proxy_config()
 
90
    swift.configure_https()
 
91
    # Re-fire keystone hooks to ripple back the HTTPS service entry
 
92
    for relid in utils.relation_ids('identity-service'):
 
93
        keystone_joined(relid=relid)
 
94
 
 
95
 
 
96
def balance_rings():
 
97
    '''handle doing ring balancing and distribution.'''
 
98
    new_ring = False
 
99
    for ring in swift.SWIFT_RINGS.itervalues():
 
100
        if swift.balance_ring(ring):
 
101
            utils.juju_log('INFO', 'Balanced ring %s' % ring)
 
102
            new_ring = True
 
103
    if not new_ring:
 
104
        return
 
105
 
 
106
    for ring in swift.SWIFT_RINGS.keys():
 
107
        f = '%s.ring.gz' % ring
 
108
        shutil.copyfile(os.path.join(swift.SWIFT_CONF_DIR, f),
 
109
                        os.path.join(swift.WWW_DIR, f))
 
110
 
 
111
    if cluster.eligible_leader(swift.SWIFT_HA_RES):
 
112
        msg = 'Broadcasting notification to all storage nodes that new '\
 
113
              'ring is ready for consumption.'
 
114
        utils.juju_log('INFO', msg)
 
115
        path = swift.WWW_DIR.split('/var/www/')[1]
 
116
        trigger = uuid.uuid4()
 
117
        swift_hash = swift.get_swift_hash()
 
118
 
 
119
        if cluster.is_clustered():
 
120
            hostname = utils.config_get('vip')
 
121
        else:
 
122
            hostname = utils.unit_get('private-address')
 
123
 
 
124
        rings_url = 'http://%s/%s' % (hostname, path)
 
125
        # notify storage nodes that there is a new ring to fetch.
 
126
        for relid in utils.relation_ids('swift-storage'):
 
127
            utils.relation_set(rid=relid, swift_hash=swift_hash,
 
128
                               rings_url=rings_url, trigger=trigger)
 
129
 
 
130
    swift.proxy_control('restart')
 
131
 
 
132
 
 
133
def storage_changed():
 
134
    zone = swift.get_zone(utils.config_get('zone-assignment'))
 
135
    node_settings = {
 
136
        'ip': utils.get_host_ip(utils.relation_get('private-address')),
 
137
        'zone': zone,
 
138
        'account_port': utils.relation_get('account_port'),
 
139
        'object_port': utils.relation_get('object_port'),
 
140
        'container_port': utils.relation_get('container_port'),
 
141
    }
 
142
    if None in node_settings.itervalues():
 
143
        utils.juju_log('INFO', 'storage_changed: Relation not ready.')
 
144
        return None
 
145
 
 
146
    for k in ['zone', 'account_port', 'object_port', 'container_port']:
 
147
        node_settings[k] = int(node_settings[k])
 
148
 
 
149
    # Grant new node access to rings via apache.
 
150
    swift.write_apache_config()
 
151
 
 
152
    # allow for multiple devs per unit, passed along as a : separated list
 
153
    devs = utils.relation_get('device').split(':')
 
154
    for dev in devs:
 
155
        node_settings['device'] = dev
 
156
        for ring in swift.SWIFT_RINGS.itervalues():
 
157
            if not swift.exists_in_ring(ring, node_settings):
 
158
                swift.add_to_ring(ring, node_settings)
 
159
 
 
160
    if swift.should_balance([r for r in swift.SWIFT_RINGS.itervalues()]):
 
161
        balance_rings()
 
162
 
 
163
 
 
164
def storage_broken():
 
165
    swift.write_apache_config()
 
166
 
 
167
 
 
168
def config_changed():
 
169
    # Determine whether or not we should do an upgrade, based on the
 
170
    # the version offered in keyston-release.
 
171
    src = utils.config_get('openstack-origin')
 
172
    available = openstack.get_os_codename_install_source(src)
 
173
    installed = openstack.get_os_codename_package('python-swift')
 
174
    if (available and
 
175
        openstack.get_os_version_codename(available) > \
 
176
        openstack.get_os_version_codename(installed)):
 
177
        pkgs = swift.determine_packages(available)
 
178
        swift.do_openstack_upgrade(src, pkgs)
 
179
 
 
180
    relids = utils.relation_ids('identity-service')
 
181
    if relids:
 
182
        for relid in relids:
 
183
            keystone_joined(relid)
 
184
    swift.write_proxy_config()
 
185
    swift.configure_https()
 
186
 
 
187
 
 
188
def cluster_changed():
 
189
    swift.configure_haproxy()
 
190
 
 
191
 
 
192
def ha_relation_changed():
 
193
    clustered = utils.relation_get('clustered')
 
194
    if clustered and cluster.is_leader(swift.SWIFT_HA_RES):
 
195
        utils.juju_log('INFO',
 
196
                       'Cluster configured, notifying other services and'
 
197
                       'updating keystone endpoint configuration')
 
198
        # Tell all related services to start using
 
199
        # the VIP instead
 
200
        for r_id in utils.relation_ids('identity-service'):
 
201
            keystone_joined(relid=r_id)
 
202
 
 
203
 
 
204
def ha_relation_joined():
 
205
    # Obtain the config values necessary for the cluster config. These
 
206
    # include multicast port and interface to bind to.
 
207
    corosync_bindiface = utils.config_get('ha-bindiface')
 
208
    corosync_mcastport = utils.config_get('ha-mcastport')
 
209
    vip = utils.config_get('vip')
 
210
    vip_cidr = utils.config_get('vip_cidr')
 
211
    vip_iface = utils.config_get('vip_iface')
 
212
    if not vip:
 
213
        utils.juju_log('ERROR',
 
214
                       'Unable to configure hacluster as vip not provided')
 
215
        sys.exit(1)
 
216
 
 
217
    # Obtain resources
 
218
    resources = {
 
219
            'res_swift_vip': 'ocf:heartbeat:IPaddr2',
 
220
            'res_swift_haproxy': 'lsb:haproxy'
 
221
        }
 
222
    resource_params = {
 
223
            'res_swift_vip': 'params ip="%s" cidr_netmask="%s" nic="%s"' % \
 
224
                              (vip, vip_cidr, vip_iface),
 
225
            'res_swift_haproxy': 'op monitor interval="5s"'
 
226
        }
 
227
    init_services = {
 
228
            'res_swift_haproxy': 'haproxy'
 
229
        }
 
230
    clones = {
 
231
            'cl_swift_haproxy': 'res_swift_haproxy'
 
232
        }
 
233
 
 
234
    utils.relation_set(init_services=init_services,
 
235
                       corosync_bindiface=corosync_bindiface,
 
236
                       corosync_mcastport=corosync_mcastport,
 
237
                       resources=resources,
 
238
                       resource_params=resource_params,
 
239
                       clones=clones)
 
240
 
 
241
 
 
242
hooks = {
 
243
    'install': install,
 
244
    'config-changed': config_changed,
 
245
    'identity-service-relation-joined': keystone_joined,
 
246
    'identity-service-relation-changed': keystone_changed,
 
247
    'swift-storage-relation-changed': storage_changed,
 
248
    'swift-storage-relation-broken': storage_broken,
 
249
    "cluster-relation-joined": cluster_changed,
 
250
    "cluster-relation-changed": cluster_changed,
 
251
    "ha-relation-joined": ha_relation_joined,
 
252
    "ha-relation-changed": ha_relation_changed
 
253
}
 
254
 
 
255
utils.do_hooks(hooks)
 
256
 
 
257
sys.exit(0)