~niedbalski/charms/trusty/rabbitmq-server/fqdn-maas-1.5

« back to all changes in this revision

Viewing changes to hooks/rabbitmq_server_relations.py

  • Committer: Adam Gandelman
  • Date: 2013-06-24 22:25:45 UTC
  • mfrom: (37.3.10 rabbitmq-server)
  • Revision ID: adamg@canonical.com-20130624222545-5p7dt00wfm5600fn
Merge HA work + Python rewrite.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
import os
 
4
import shutil
 
5
import sys
 
6
import subprocess
 
7
import glob
 
8
 
 
9
 
 
10
import rabbit_utils as rabbit
 
11
import lib.utils as utils
 
12
import lib.cluster_utils as cluster
 
13
import lib.ceph_utils as ceph
 
14
import lib.openstack_common as openstack
 
15
 
 
16
 
 
17
SERVICE_NAME = os.getenv('JUJU_UNIT_NAME').split('/')[0]
 
18
POOL_NAME = SERVICE_NAME
 
19
RABBIT_DIR = '/var/lib/rabbitmq'
 
20
 
 
21
 
 
22
def install():
 
23
    pre_install_hooks()
 
24
    utils.install(*rabbit.PACKAGES)
 
25
    utils.expose(5672)
 
26
 
 
27
 
 
28
def amqp_changed(relation_id=None, remote_unit=None):
 
29
    if not cluster.eligible_leader('res_rabbitmq_vip'):
 
30
        msg = 'amqp_changed(): Deferring amqp_changed to eligible_leader.'
 
31
        utils.juju_log('INFO', msg)
 
32
        return
 
33
 
 
34
    rabbit_user = utils.relation_get('username', rid=relation_id,
 
35
                                     unit=remote_unit)
 
36
    vhost = utils.relation_get('vhost', rid=relation_id, unit=remote_unit)
 
37
    if None in [rabbit_user, vhost]:
 
38
        utils.juju_log('INFO', 'amqp_changed(): Relation not ready.')
 
39
        return
 
40
 
 
41
    password_file = os.path.join(RABBIT_DIR, '%s.passwd' % rabbit_user)
 
42
    if os.path.exists(password_file):
 
43
        password = open(password_file).read().strip()
 
44
    else:
 
45
        cmd = ['pwgen', '64', '1']
 
46
        password = subprocess.check_output(cmd).strip()
 
47
        with open(password_file, 'wb') as out:
 
48
            out.write(password)
 
49
 
 
50
    rabbit.create_vhost(vhost)
 
51
    rabbit.create_user(rabbit_user, password)
 
52
    rabbit.grant_permissions(rabbit_user, vhost)
 
53
    rabbit_hostname = utils.unit_get('private-address')
 
54
 
 
55
    relation_settings = {
 
56
        'password': password,
 
57
        'hostname': rabbit_hostname
 
58
    }
 
59
    if cluster.is_clustered():
 
60
        relation_settings['clustered'] = 'true'
 
61
        relation_settings['vip'] = utils.config_get('vip')
 
62
    if relation_id:
 
63
        relation_settings['rid'] = relation_id
 
64
    utils.relation_set(**relation_settings)
 
65
 
 
66
 
 
67
def cluster_joined():
 
68
    if utils.is_relation_made('ha'):
 
69
        utils.juju_log('INFO',
 
70
                       'hacluster relation is present, skipping native '\
 
71
                       'rabbitmq cluster config.')
 
72
        return
 
73
    l_unit_no = os.getenv('JUJU_UNIT_NAME').split('/')[1]
 
74
    r_unit_no = os.getenv('JUJU_REMOTE_UNIT').split('/')[1]
 
75
    if l_unit_no > r_unit_no:
 
76
        utils.juju_log('INFO', 'cluster_joined: Relation greater.')
 
77
        return
 
78
    rabbit.COOKIE_PATH = '/var/lib/rabbitmq/.erlang.cookie'
 
79
    if not os.path.isfile(rabbit.COOKIE_PATH):
 
80
        utils.juju_log('ERROR', 'erlang cookie missing from %s' %\
 
81
                       rabbit.COOKIE_PATH)
 
82
    cookie = open(rabbit.COOKIE_PATH, 'r').read().strip()
 
83
    local_hostname = subprocess.check_output(['hostname']).strip()
 
84
    utils.relation_set(cookie=cookie, host=local_hostname)
 
85
 
 
86
 
 
87
def cluster_changed():
 
88
    if utils.is_relation_made('ha'):
 
89
        utils.juju_log('INFO',
 
90
                       'hacluster relation is present, skipping native '\
 
91
                       'rabbitmq cluster config.')
 
92
        return
 
93
    l_unit_no = os.getenv('JUJU_UNIT_NAME').split('/')[1]
 
94
    r_unit_no = os.getenv('JUJU_REMOTE_UNIT').split('/')[1]
 
95
    if l_unit_no < r_unit_no:
 
96
        utils.juju_log('INFO', 'cluster_joined: Relation lesser.')
 
97
        return
 
98
 
 
99
    remote_host = utils.relation_get('host')
 
100
    cookie = utils.relation_get('cookie')
 
101
    if None in [remote_host, cookie]:
 
102
        utils.juju_log('INFO',
 
103
                       'cluster_joined: remote_host|cookie not yet set.')
 
104
        return
 
105
 
 
106
    if open(rabbit.COOKIE_PATH, 'r').read().strip() == cookie:
 
107
        utils.juju_log('INFO', 'Cookie already synchronized with peer.')
 
108
        return
 
109
 
 
110
    utils.juju_log('INFO', 'Synchronizing erlang cookie from peer.')
 
111
    rabbit.service('stop')
 
112
    with open(rabbit.COOKIE_PATH, 'wb') as out:
 
113
        out.write(cookie)
 
114
    rabbit.service('start')
 
115
    rabbit.cluster_with(remote_host)
 
116
 
 
117
 
 
118
def ha_joined():
 
119
    corosync_bindiface = utils.config_get('ha-bindiface')
 
120
    corosync_mcastport = utils.config_get('ha-mcastport')
 
121
    vip = utils.config_get('vip')
 
122
    vip_iface = utils.config_get('vip_iface')
 
123
    vip_cidr = utils.config_get('vip_cidr')
 
124
    rbd_name = utils.config_get('rbd-name')
 
125
 
 
126
    if None in [corosync_bindiface, corosync_mcastport, vip, vip_iface,
 
127
                vip_cidr, rbd_name]:
 
128
        utils.juju_log('ERROR', 'Insufficient configuration data to '\
 
129
                       'configure hacluster.')
 
130
        sys.exit(1)
 
131
 
 
132
    if not utils.is_relation_made('ceph', 'auth'):
 
133
        utils.juju_log('INFO',
 
134
                       'ha_joined: No ceph relation yet, deferring.')
 
135
        return
 
136
 
 
137
    name = '%s@localhost' % SERVICE_NAME
 
138
    if rabbit.get_node_name() != name:
 
139
        utils.juju_log('INFO', 'Stopping rabbitmq-server.')
 
140
        utils.stop('rabbitmq-server')
 
141
        rabbit.set_node_name('%s@localhost' % SERVICE_NAME)
 
142
    else:
 
143
        utils.juju_log('INFO', 'Node name already set to %s.' % name)
 
144
 
 
145
    relation_settings = {}
 
146
    relation_settings['corosync_bindiface'] = corosync_bindiface
 
147
    relation_settings['corosync_mcastport'] = corosync_mcastport
 
148
 
 
149
    relation_settings['resources'] = {
 
150
        'res_rabbitmq_rbd': 'ocf:ceph:rbd',
 
151
        'res_rabbitmq_fs': 'ocf:heartbeat:Filesystem',
 
152
        'res_rabbitmq_vip': 'ocf:heartbeat:IPaddr2',
 
153
        'res_rabbitmq-server': 'lsb:rabbitmq-server',
 
154
    }
 
155
 
 
156
    relation_settings['resource_params'] = {
 
157
        'res_rabbitmq_rbd': 'params name="%s" pool="%s" user="%s" '
 
158
                            'secret="%s"' % \
 
159
                            (rbd_name, POOL_NAME,
 
160
                             SERVICE_NAME, ceph.keyfile_path(SERVICE_NAME)),
 
161
        'res_rabbitmq_fs': 'params device="/dev/rbd/%s/%s" directory="%s" '\
 
162
                           'fstype="ext4" op start start-delay="10s"' %\
 
163
                           (POOL_NAME, rbd_name, RABBIT_DIR),
 
164
        'res_rabbitmq_vip': 'params ip="%s" cidr_netmask="%s" nic="%s"' %\
 
165
                            (vip, vip_cidr, vip_iface),
 
166
        'res_rabbitmq-server': 'op start start-delay="5s" op monitor interval="5s"',
 
167
    }
 
168
 
 
169
    relation_settings['groups'] = {
 
170
        'grp_rabbitmq': 'res_rabbitmq_rbd res_rabbitmq_fs res_rabbitmq_vip '\
 
171
                        'res_rabbitmq-server',
 
172
    }
 
173
 
 
174
    for rel_id in utils.relation_ids('ha'):
 
175
        utils.relation_set(rid=rel_id, **relation_settings)
 
176
 
 
177
    env_vars = {
 
178
        'OPENSTACK_PORT_EPMD': 4369,
 
179
        'OPENSTACK_PORT_MCASTPORT': utils.config_get('ha-mcastport'),
 
180
    }
 
181
    openstack.save_script_rc(**env_vars)
 
182
 
 
183
 
 
184
def ha_changed():
 
185
    if not cluster.is_clustered():
 
186
        return
 
187
    vip = utils.config_get('vip')
 
188
    utils.juju_log('INFO', 'ha_changed(): We are now HA clustered. '
 
189
                   'Advertising our VIP (%s) to all AMQP clients.' %\
 
190
                   vip)
 
191
    # need to re-authenticate all clients since node-name changed.
 
192
    for rid in utils.relation_ids('amqp'):
 
193
        for unit in utils.relation_list(rid):
 
194
            amqp_changed(relation_id=rid, remote_unit=unit)
 
195
 
 
196
 
 
197
def ceph_joined():
 
198
    utils.juju_log('INFO', 'Start Ceph Relation Joined')
 
199
    ceph.install()
 
200
    utils.juju_log('INFO', 'Finish Ceph Relation Joined')
 
201
 
 
202
 
 
203
def ceph_changed():
 
204
    utils.juju_log('INFO', 'Start Ceph Relation Changed')
 
205
    auth = utils.relation_get('auth')
 
206
    key = utils.relation_get('key')
 
207
    if None in [auth, key]:
 
208
        utils.juju_log('INFO', 'Missing key or auth in relation')
 
209
        sys.exit(0)
 
210
 
 
211
    ceph.configure(service=SERVICE_NAME, key=key, auth=auth)
 
212
 
 
213
    if cluster.eligible_leader('res_rabbitmq_vip'):
 
214
        rbd_img = utils.config_get('rbd-name')
 
215
        rbd_size = utils.config_get('rbd-size')
 
216
        sizemb = int(rbd_size.split('G')[0]) * 1024
 
217
        blk_device = '/dev/rbd/%s/%s' % (POOL_NAME, rbd_img)
 
218
        ceph.ensure_ceph_storage(service=SERVICE_NAME, pool=POOL_NAME,
 
219
                                 rbd_img=rbd_img, sizemb=sizemb,
 
220
                                 fstype='ext4', mount_point=RABBIT_DIR,
 
221
                                 blk_device=blk_device,
 
222
                                 system_services=['rabbitmq-server'])
 
223
    else:
 
224
        utils.juju_log('INFO',
 
225
                       'This is not the peer leader. Not configuring RBD.')
 
226
        utils.juju_log('INFO', 'Stopping rabbitmq-server.')
 
227
        utils.stop('rabbitmq-server')
 
228
 
 
229
    # If 'ha' relation has been made before the 'ceph' relation
 
230
    # it is important to make sure the ha-relation data is being
 
231
    # sent.
 
232
    if utils.is_relation_made('ha'):
 
233
        utils.juju_log('INFO', '*ha* relation exists. Triggering ha_joined()')
 
234
        ha_joined()
 
235
    else:
 
236
        utils.juju_log('INFO', '*ha* relation does not exist.')
 
237
    utils.juju_log('INFO', 'Finish Ceph Relation Changed')
 
238
 
 
239
 
 
240
def upgrade_charm():
 
241
    pre_install_hooks()
 
242
    # Ensure older passwd files in /var/lib/juju are moved to
 
243
    # /var/lib/rabbitmq which will end up replicated if clustered.
 
244
    for f in [f for f in os.listdir('/var/lib/juju')
 
245
              if os.path.isfile(os.path.join('/var/lib/juju', f))]:
 
246
        if f.endswith('.passwd'):
 
247
            s = os.path.join('/var/lib/juju', f)
 
248
            d = os.path.join('/var/lib/rabbitmq', f)
 
249
            utils.juju_log('INFO',
 
250
                           'upgrade_charm: Migrating stored passwd'
 
251
                           ' from %s to %s.' % (s, d))
 
252
            shutil.move(s, d)
 
253
 
 
254
MAN_PLUGIN = 'rabbitmq_management'
 
255
 
 
256
def config_changed():
 
257
    if utils.config_get('management_plugin') == True:
 
258
        rabbit.enable_plugin(MAN_PLUGIN)
 
259
        utils.open_port(55672)
 
260
    else:
 
261
        rabbit.disable_plugin(MAN_PLUGIN)
 
262
        utils.close_port(55672)
 
263
    
 
264
    if utils.config_get('ssl_enabled') == True:
 
265
        ssl_key = utils.config_get('ssl_key')
 
266
        ssl_cert = utils.config_get('ssl_cert')
 
267
        ssl_port = utils.config_get('ssl_port')
 
268
        if None in [ ssl_key, ssl_cert, ssl_port ]:
 
269
            utils.juju_log('ERROR',
 
270
                           'Please provide ssl_key, ssl_cert and ssl_port'
 
271
                           ' config when enabling SSL support')
 
272
            sys.exit(1)
 
273
        else:
 
274
            rabbit.enable_ssl(ssl_key, ssl_cert, ssl_port)
 
275
            utils.open_port(ssl_port)
 
276
    else:
 
277
        if os.path.exists(rabbit.RABBITMQ_CONF):
 
278
            os.remove(rabbit.RABBITMQ_CONF)
 
279
        utils.close_port(utils.config_get('ssl_port'))
 
280
    
 
281
    utils.restart('rabbitmq-server')
 
282
 
 
283
 
 
284
def pre_install_hooks():
 
285
    for f in glob.glob('exec.d/*/charm-pre-install'):
 
286
        if os.path.isfile(f) and os.access(f, os.X_OK):
 
287
            subprocess.check_call(['sh', '-c', f])
 
288
 
 
289
hooks = {
 
290
    'install': install,
 
291
    'amqp-relation-changed': amqp_changed,
 
292
    'cluster-relation-joined': cluster_joined,
 
293
    'cluster-relation-changed': cluster_changed,
 
294
    'ha-relation-joined': ha_joined,
 
295
    'ha-relation-changed': ha_changed,
 
296
    'ceph-relation-joined': ceph_joined,
 
297
    'ceph-relation-changed': ceph_changed,
 
298
    'upgrade-charm': upgrade_charm,
 
299
    'config-changed': config_changed
 
300
}
 
301
 
 
302
utils.do_hooks(hooks)