~felipe-alfaro-gmail/charms/xenial/neutron-api/trunk

« back to all changes in this revision

Viewing changes to hooks/etcd-proxy-relation-broken

  • Committer: Felipe Alfaro Solana
  • Date: 2017-04-05 19:45:40 UTC
  • Revision ID: felipe.alfaro@gmail.com-20170405194540-85i0nhnp98ipob0y
Neutron API charm.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
#
 
3
# Copyright 2016 Canonical Ltd
 
4
#
 
5
# Licensed under the Apache License, Version 2.0 (the "License");
 
6
# you may not use this file except in compliance with the License.
 
7
# You may obtain a copy of the License at
 
8
#
 
9
#  http://www.apache.org/licenses/LICENSE-2.0
 
10
#
 
11
# Unless required by applicable law or agreed to in writing, software
 
12
# distributed under the License is distributed on an "AS IS" BASIS,
 
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
# See the License for the specific language governing permissions and
 
15
# limitations under the License.
 
16
 
 
17
import sys
 
18
import uuid
 
19
from subprocess import (
 
20
    check_call,
 
21
)
 
22
 
 
23
from charmhelpers.core.hookenv import (
 
24
    Hooks,
 
25
    UnregisteredHookError,
 
26
    config,
 
27
    is_relation_made,
 
28
    local_unit,
 
29
    log,
 
30
    ERROR,
 
31
    relation_get,
 
32
    relation_ids,
 
33
    relation_set,
 
34
    status_set,
 
35
    open_port,
 
36
    unit_get,
 
37
    network_get_primary_address,
 
38
)
 
39
 
 
40
from charmhelpers.core.host import (
 
41
    mkdir,
 
42
    service_reload,
 
43
    service_restart,
 
44
)
 
45
 
 
46
from charmhelpers.fetch import (
 
47
    apt_install,
 
48
    add_source,
 
49
    apt_update,
 
50
    filter_installed_packages,
 
51
)
 
52
 
 
53
from charmhelpers.contrib.openstack.utils import (
 
54
    config_value_changed,
 
55
    configure_installation_source,
 
56
    git_install_requested,
 
57
    openstack_upgrade_available,
 
58
    os_requires_version,
 
59
    os_release,
 
60
    sync_db_with_multi_ipv6_addresses,
 
61
    is_unit_paused_set,
 
62
    pausable_restart_on_change as restart_on_change,
 
63
)
 
64
 
 
65
from neutron_api_utils import (
 
66
    additional_install_locations,
 
67
    API_PASTE_INI,
 
68
    api_port,
 
69
    assess_status,
 
70
    CLUSTER_RES,
 
71
    determine_packages,
 
72
    determine_ports,
 
73
    do_openstack_upgrade,
 
74
    dvr_router_present,
 
75
    force_etcd_restart,
 
76
    get_topics,
 
77
    git_install,
 
78
    is_api_ready,
 
79
    l3ha_router_present,
 
80
    migrate_neutron_database,
 
81
    NEUTRON_CONF,
 
82
    neutron_ready,
 
83
    register_configs,
 
84
    restart_map,
 
85
    services,
 
86
    setup_ipv6,
 
87
)
 
88
from neutron_api_context import (
 
89
    get_dvr,
 
90
    get_l3ha,
 
91
    get_l2population,
 
92
    get_overlay_network_type,
 
93
    IdentityServiceContext,
 
94
    EtcdContext,
 
95
)
 
96
 
 
97
from charmhelpers.contrib.hahelpers.cluster import (
 
98
    get_hacluster_config,
 
99
    is_elected_leader,
 
100
)
 
101
 
 
102
from charmhelpers.contrib.openstack.ha.utils import (
 
103
    update_dns_ha_resource_params,
 
104
)
 
105
 
 
106
from charmhelpers.payload.execd import execd_preinstall
 
107
 
 
108
from charmhelpers.contrib.openstack.ip import (
 
109
    canonical_url,
 
110
    PUBLIC, INTERNAL, ADMIN
 
111
)
 
112
 
 
113
from charmhelpers.contrib.openstack.neutron import (
 
114
    neutron_plugin_attribute,
 
115
)
 
116
 
 
117
from charmhelpers.contrib.network.ip import (
 
118
    get_iface_for_address,
 
119
    get_netmask_for_address,
 
120
    get_address_in_network,
 
121
    get_ipv6_addr,
 
122
    is_ipv6
 
123
)
 
124
 
 
125
from charmhelpers.contrib.openstack.context import ADDRESS_TYPES
 
126
 
 
127
from charmhelpers.contrib.charmsupport import nrpe
 
128
from charmhelpers.contrib.hardening.harden import harden
 
129
 
 
130
hooks = Hooks()
 
131
CONFIGS = register_configs()
 
132
 
 
133
 
 
134
def conditional_neutron_migration():
 
135
    if os_release('neutron-server') <= 'icehouse':
 
136
        log('Not running neutron database migration as migrations are handled '
 
137
            'by the neutron-server process.')
 
138
        return
 
139
    if is_elected_leader(CLUSTER_RES):
 
140
        allowed_units = relation_get('allowed_units')
 
141
        if allowed_units and local_unit() in allowed_units.split():
 
142
            migrate_neutron_database()
 
143
            if not is_unit_paused_set():
 
144
                service_restart('neutron-server')
 
145
        else:
 
146
            log('Not running neutron database migration, either no'
 
147
                ' allowed_units or this unit is not present')
 
148
            return
 
149
    else:
 
150
        log('Not running neutron database migration, not leader')
 
151
 
 
152
 
 
153
def configure_https():
 
154
    '''
 
155
    Enables SSL API Apache config if appropriate and kicks identity-service
 
156
    with any required api updates.
 
157
    '''
 
158
    # need to write all to ensure changes to the entire request pipeline
 
159
    # propagate (c-api, haprxy, apache)
 
160
    CONFIGS.write_all()
 
161
    if 'https' in CONFIGS.complete_contexts():
 
162
        cmd = ['a2ensite', 'openstack_https_frontend']
 
163
        check_call(cmd)
 
164
    else:
 
165
        cmd = ['a2dissite', 'openstack_https_frontend']
 
166
        check_call(cmd)
 
167
 
 
168
    # TODO: improve this by checking if local CN certs are available
 
169
    # first then checking reload status (see LP #1433114).
 
170
    if not is_unit_paused_set():
 
171
        service_reload('apache2', restart_on_failure=True)
 
172
 
 
173
    for rid in relation_ids('identity-service'):
 
174
        identity_joined(rid=rid)
 
175
 
 
176
 
 
177
@hooks.hook('install.real')
 
178
@hooks.hook()
 
179
@harden()
 
180
def install():
 
181
    status_set('maintenance', 'Executing pre-install')
 
182
    execd_preinstall()
 
183
    openstack_origin = config('openstack-origin')
 
184
    configure_installation_source(openstack_origin)
 
185
    neutron_plugin = config('neutron-plugin')
 
186
    additional_install_locations(neutron_plugin, openstack_origin)
 
187
 
 
188
    add_source(config('extra-source'), config('extra-key'))
 
189
    status_set('maintenance', 'Installing apt packages')
 
190
    apt_update(fatal=True)
 
191
    packages = determine_packages(openstack_origin)
 
192
    apt_install(packages, fatal=True)
 
193
 
 
194
    status_set('maintenance', 'Git install')
 
195
    git_install(config('openstack-origin-git'))
 
196
 
 
197
    [open_port(port) for port in determine_ports()]
 
198
 
 
199
    if neutron_plugin == 'midonet':
 
200
        mkdir('/etc/neutron/plugins/midonet', owner='neutron', group='neutron',
 
201
              perms=0o755, force=False)
 
202
 
 
203
 
 
204
@hooks.hook('vsd-rest-api-relation-joined')
 
205
@restart_on_change(restart_map(), stopstart=True)
 
206
def relation_set_nuage_cms_name(rid=None):
 
207
    if os_release('neutron-server') >= 'kilo':
 
208
        if config('vsd-cms-name') is None:
 
209
            e = "Neutron Api hook failed as vsd-cms-name" \
 
210
                " is not specified"
 
211
            status_set('blocked', e)
 
212
        else:
 
213
            relation_data = {
 
214
                'vsd-cms-name': '{}'.format(config('vsd-cms-name'))
 
215
            }
 
216
            relation_set(relation_id=rid, **relation_data)
 
217
 
 
218
 
 
219
@hooks.hook('vsd-rest-api-relation-changed')
 
220
@restart_on_change(restart_map(), stopstart=True)
 
221
def vsd_changed(relation_id=None, remote_unit=None):
 
222
    if config('neutron-plugin') == 'vsp':
 
223
        vsd_ip_address = relation_get('vsd-ip-address')
 
224
        if not vsd_ip_address:
 
225
            return
 
226
        vsd_address = '{}:8443'.format(vsd_ip_address)
 
227
        if os_release('neutron-server') >= 'kilo':
 
228
            vsd_cms_id = relation_get('nuage-cms-id')
 
229
            log("nuage-vsd-api-relation-changed : cms_id:{}"
 
230
                .format(vsd_cms_id))
 
231
        nuage_config_file = neutron_plugin_attribute(config('neutron-plugin'),
 
232
                                                     'config', 'neutron')
 
233
        log('vsd-rest-api-relation-changed: ip address:{}'.format(vsd_address))
 
234
        log('vsd-rest-api-relation-changed:{}'.format(nuage_config_file))
 
235
 
 
236
        CONFIGS.write(nuage_config_file)
 
237
 
 
238
 
 
239
@hooks.hook('upgrade-charm')
 
240
@hooks.hook('config-changed')
 
241
@restart_on_change(restart_map(), stopstart=True)
 
242
@harden()
 
243
def config_changed():
 
244
    # If neutron is ready to be queried then check for incompatability between
 
245
    # existing neutron objects and charm settings
 
246
    if neutron_ready():
 
247
        if l3ha_router_present() and not get_l3ha():
 
248
            e = ('Cannot disable Router HA while ha enabled routers exist.'
 
249
                 ' Please remove any ha routers')
 
250
            status_set('blocked', e)
 
251
            raise Exception(e)
 
252
        if dvr_router_present() and not get_dvr():
 
253
            e = ('Cannot disable dvr while dvr enabled routers exist. Please'
 
254
                 ' remove any distributed routers')
 
255
            log(e, level=ERROR)
 
256
            status_set('blocked', e)
 
257
            raise Exception(e)
 
258
    if config('prefer-ipv6'):
 
259
        status_set('maintenance', 'configuring ipv6')
 
260
        setup_ipv6()
 
261
        sync_db_with_multi_ipv6_addresses(config('database'),
 
262
                                          config('database-user'))
 
263
 
 
264
    global CONFIGS
 
265
    if git_install_requested():
 
266
        if config_value_changed('openstack-origin-git'):
 
267
            status_set('maintenance', 'Running Git install')
 
268
            git_install(config('openstack-origin-git'))
 
269
    elif not config('action-managed-upgrade'):
 
270
        if openstack_upgrade_available('neutron-common'):
 
271
            status_set('maintenance', 'Running openstack upgrade')
 
272
            do_openstack_upgrade(CONFIGS)
 
273
 
 
274
    additional_install_locations(
 
275
        config('neutron-plugin'),
 
276
        config('openstack-origin')
 
277
    )
 
278
    status_set('maintenance', 'Installing apt packages')
 
279
    apt_install(filter_installed_packages(
 
280
                determine_packages(config('openstack-origin'))),
 
281
                fatal=True)
 
282
    configure_https()
 
283
    update_nrpe_config()
 
284
    CONFIGS.write_all()
 
285
    for r_id in relation_ids('neutron-api'):
 
286
        neutron_api_relation_joined(rid=r_id)
 
287
    for r_id in relation_ids('neutron-plugin-api'):
 
288
        neutron_plugin_api_relation_joined(rid=r_id)
 
289
    for r_id in relation_ids('amqp'):
 
290
        amqp_joined(relation_id=r_id)
 
291
    for r_id in relation_ids('identity-service'):
 
292
        identity_joined(rid=r_id)
 
293
    for rid in relation_ids('zeromq-configuration'):
 
294
        zeromq_configuration_relation_joined(rid)
 
295
    [cluster_joined(rid) for rid in relation_ids('cluster')]
 
296
 
 
297
 
 
298
@hooks.hook('amqp-relation-joined')
 
299
def amqp_joined(relation_id=None):
 
300
    relation_set(relation_id=relation_id,
 
301
                 username=config('rabbit-user'), vhost=config('rabbit-vhost'))
 
302
 
 
303
 
 
304
@hooks.hook('amqp-relation-changed')
 
305
@hooks.hook('amqp-relation-departed')
 
306
@restart_on_change(restart_map())
 
307
def amqp_changed():
 
308
    if 'amqp' not in CONFIGS.complete_contexts():
 
309
        log('amqp relation incomplete. Peer not ready?')
 
310
        return
 
311
    CONFIGS.write(NEUTRON_CONF)
 
312
 
 
313
    for r_id in relation_ids('neutron-plugin-api-subordinate'):
 
314
        neutron_plugin_api_subordinate_relation_joined(relid=r_id)
 
315
 
 
316
 
 
317
@hooks.hook('shared-db-relation-joined')
 
318
def db_joined():
 
319
    if is_relation_made('pgsql-db'):
 
320
        # error, postgresql is used
 
321
        e = ('Attempting to associate a mysql database when there is already '
 
322
             'associated a postgresql one')
 
323
        log(e, level=ERROR)
 
324
        raise Exception(e)
 
325
 
 
326
    if config('prefer-ipv6'):
 
327
        sync_db_with_multi_ipv6_addresses(config('database'),
 
328
                                          config('database-user'))
 
329
    else:
 
330
        host = None
 
331
        try:
 
332
            # NOTE: try to use network spaces
 
333
            host = network_get_primary_address('shared-db')
 
334
        except NotImplementedError:
 
335
            # NOTE: fallback to private-address
 
336
            host = unit_get('private-address')
 
337
 
 
338
        relation_set(database=config('database'),
 
339
                     username=config('database-user'),
 
340
                     hostname=host)
 
341
 
 
342
 
 
343
@hooks.hook('pgsql-db-relation-joined')
 
344
def pgsql_neutron_db_joined():
 
345
    if is_relation_made('shared-db'):
 
346
        # raise error
 
347
        e = ('Attempting to associate a postgresql database'
 
348
             ' when there is already associated a mysql one')
 
349
        log(e, level=ERROR)
 
350
        raise Exception(e)
 
351
 
 
352
    relation_set(database=config('database'))
 
353
 
 
354
 
 
355
@hooks.hook('shared-db-relation-changed')
 
356
@restart_on_change(restart_map())
 
357
def db_changed():
 
358
    if 'shared-db' not in CONFIGS.complete_contexts():
 
359
        log('shared-db relation incomplete. Peer not ready?')
 
360
        return
 
361
    CONFIGS.write_all()
 
362
    conditional_neutron_migration()
 
363
 
 
364
    for r_id in relation_ids('neutron-plugin-api-subordinate'):
 
365
        neutron_plugin_api_subordinate_relation_joined(relid=r_id)
 
366
 
 
367
 
 
368
@hooks.hook('pgsql-db-relation-changed')
 
369
@restart_on_change(restart_map())
 
370
def postgresql_neutron_db_changed():
 
371
    CONFIGS.write(NEUTRON_CONF)
 
372
    conditional_neutron_migration()
 
373
 
 
374
    for r_id in relation_ids('neutron-plugin-api-subordinate'):
 
375
        neutron_plugin_api_subordinate_relation_joined(relid=r_id)
 
376
 
 
377
 
 
378
@hooks.hook('amqp-relation-broken',
 
379
            'identity-service-relation-broken',
 
380
            'shared-db-relation-broken',
 
381
            'pgsql-db-relation-broken')
 
382
def relation_broken():
 
383
    CONFIGS.write_all()
 
384
 
 
385
 
 
386
@hooks.hook('identity-service-relation-joined')
 
387
def identity_joined(rid=None, relation_trigger=False):
 
388
    public_url = '{}:{}'.format(canonical_url(CONFIGS, PUBLIC),
 
389
                                api_port('neutron-server'))
 
390
    admin_url = '{}:{}'.format(canonical_url(CONFIGS, ADMIN),
 
391
                               api_port('neutron-server'))
 
392
    internal_url = '{}:{}'.format(canonical_url(CONFIGS, INTERNAL),
 
393
                                  api_port('neutron-server')
 
394
                                  )
 
395
    rel_settings = {
 
396
        'neutron_service': 'neutron',
 
397
        'neutron_region': config('region'),
 
398
        'neutron_public_url': public_url,
 
399
        'neutron_admin_url': admin_url,
 
400
        'neutron_internal_url': internal_url,
 
401
        'quantum_service': None,
 
402
        'quantum_region': None,
 
403
        'quantum_public_url': None,
 
404
        'quantum_admin_url': None,
 
405
        'quantum_internal_url': None,
 
406
    }
 
407
    if relation_trigger:
 
408
        rel_settings['relation_trigger'] = str(uuid.uuid4())
 
409
    relation_set(relation_id=rid, relation_settings=rel_settings)
 
410
 
 
411
 
 
412
@hooks.hook('identity-service-relation-changed')
 
413
@restart_on_change(restart_map())
 
414
def identity_changed():
 
415
    if 'identity-service' not in CONFIGS.complete_contexts():
 
416
        log('identity-service relation incomplete. Peer not ready?')
 
417
        return
 
418
    CONFIGS.write(NEUTRON_CONF)
 
419
    for r_id in relation_ids('neutron-api'):
 
420
        neutron_api_relation_joined(rid=r_id)
 
421
    for r_id in relation_ids('neutron-plugin-api'):
 
422
        neutron_plugin_api_relation_joined(rid=r_id)
 
423
    for r_id in relation_ids('neutron-plugin-api-subordinate'):
 
424
        neutron_plugin_api_subordinate_relation_joined(relid=r_id)
 
425
    configure_https()
 
426
 
 
427
 
 
428
@hooks.hook('neutron-api-relation-joined')
 
429
def neutron_api_relation_joined(rid=None):
 
430
    base_url = canonical_url(CONFIGS, INTERNAL)
 
431
    neutron_url = '%s:%s' % (base_url, api_port('neutron-server'))
 
432
    relation_data = {
 
433
        'enable-sriov': config('enable-sriov'),
 
434
        'neutron-url': neutron_url,
 
435
        'neutron-plugin': config('neutron-plugin'),
 
436
    }
 
437
    if config('neutron-security-groups'):
 
438
        relation_data['neutron-security-groups'] = "yes"
 
439
    else:
 
440
        relation_data['neutron-security-groups'] = "no"
 
441
 
 
442
    if is_api_ready(CONFIGS):
 
443
        relation_data['neutron-api-ready'] = "yes"
 
444
    else:
 
445
        relation_data['neutron-api-ready'] = "no"
 
446
 
 
447
    relation_set(relation_id=rid, **relation_data)
 
448
    # Nova-cc may have grabbed the neutron endpoint so kick identity-service
 
449
    # relation to register that its here
 
450
    for r_id in relation_ids('identity-service'):
 
451
        identity_joined(rid=r_id, relation_trigger=True)
 
452
 
 
453
 
 
454
@hooks.hook('neutron-api-relation-changed')
 
455
@restart_on_change(restart_map())
 
456
def neutron_api_relation_changed():
 
457
    CONFIGS.write(NEUTRON_CONF)
 
458
 
 
459
 
 
460
@hooks.hook('neutron-plugin-api-relation-joined')
 
461
def neutron_plugin_api_relation_joined(rid=None):
 
462
    if config('neutron-plugin') == 'nsx':
 
463
        relation_data = {
 
464
            'nsx-username': config('nsx-username'),
 
465
            'nsx-password': config('nsx-password'),
 
466
            'nsx-cluster-name': config('nsx-cluster-name'),
 
467
            'nsx-tz-uuid': config('nsx-tz-uuid'),
 
468
            'nsx-l3-uuid': config('nsx-l3-uuid'),
 
469
            'nsx-controllers': config('nsx-controllers'),
 
470
        }
 
471
    else:
 
472
        relation_data = {
 
473
            'neutron-security-groups': config('neutron-security-groups'),
 
474
            'l2-population': get_l2population(),
 
475
            'enable-dvr': get_dvr(),
 
476
            'enable-l3ha': get_l3ha(),
 
477
            'overlay-network-type': get_overlay_network_type(),
 
478
            'addr': unit_get('private-address'),
 
479
        }
 
480
 
 
481
        # Provide this value to relations since it needs to be set in multiple
 
482
        # places e.g. neutron.conf, nova.conf
 
483
        net_dev_mtu = config('network-device-mtu')
 
484
        if net_dev_mtu:
 
485
            relation_data['network-device-mtu'] = net_dev_mtu
 
486
 
 
487
    identity_ctxt = IdentityServiceContext()()
 
488
    if not identity_ctxt:
 
489
        identity_ctxt = {}
 
490
 
 
491
    relation_data.update({
 
492
        'auth_host': identity_ctxt.get('auth_host'),
 
493
        'auth_port': identity_ctxt.get('auth_port'),
 
494
        'auth_protocol': identity_ctxt.get('auth_protocol'),
 
495
        'service_protocol': identity_ctxt.get('service_protocol'),
 
496
        'service_host': identity_ctxt.get('service_host'),
 
497
        'service_port': identity_ctxt.get('service_port'),
 
498
        'service_tenant': identity_ctxt.get('admin_tenant_name'),
 
499
        'service_username': identity_ctxt.get('admin_user'),
 
500
        'service_password': identity_ctxt.get('admin_password'),
 
501
        'region': config('region'),
 
502
    })
 
503
 
 
504
    if is_api_ready(CONFIGS):
 
505
        relation_data['neutron-api-ready'] = "yes"
 
506
    else:
 
507
        relation_data['neutron-api-ready'] = "no"
 
508
 
 
509
    relation_set(relation_id=rid, **relation_data)
 
510
 
 
511
 
 
512
@hooks.hook('cluster-relation-joined')
 
513
def cluster_joined(relation_id=None):
 
514
    for addr_type in ADDRESS_TYPES:
 
515
        address = get_address_in_network(
 
516
            config('os-{}-network'.format(addr_type))
 
517
        )
 
518
        if address:
 
519
            relation_set(
 
520
                relation_id=relation_id,
 
521
                relation_settings={'{}-address'.format(addr_type): address}
 
522
            )
 
523
    if config('prefer-ipv6'):
 
524
        private_addr = get_ipv6_addr(exc_list=[config('vip')])[0]
 
525
        relation_set(relation_id=relation_id,
 
526
                     relation_settings={'private-address': private_addr})
 
527
 
 
528
 
 
529
@hooks.hook('cluster-relation-changed',
 
530
            'cluster-relation-departed')
 
531
@restart_on_change(restart_map(), stopstart=True)
 
532
def cluster_changed():
 
533
    CONFIGS.write_all()
 
534
 
 
535
 
 
536
@hooks.hook('ha-relation-joined')
 
537
def ha_joined(relation_id=None):
 
538
    cluster_config = get_hacluster_config()
 
539
    resources = {
 
540
        'res_neutron_haproxy': 'lsb:haproxy',
 
541
    }
 
542
    resource_params = {
 
543
        'res_neutron_haproxy': 'op monitor interval="5s"'
 
544
    }
 
545
    if config('dns-ha'):
 
546
        update_dns_ha_resource_params(relation_id=relation_id,
 
547
                                      resources=resources,
 
548
                                      resource_params=resource_params)
 
549
    else:
 
550
        vip_group = []
 
551
        for vip in cluster_config['vip'].split():
 
552
            if is_ipv6(vip):
 
553
                res_neutron_vip = 'ocf:heartbeat:IPv6addr'
 
554
                vip_params = 'ipv6addr'
 
555
            else:
 
556
                res_neutron_vip = 'ocf:heartbeat:IPaddr2'
 
557
                vip_params = 'ip'
 
558
 
 
559
            iface = (get_iface_for_address(vip) or
 
560
                     config('vip_iface'))
 
561
            netmask = (get_netmask_for_address(vip) or
 
562
                       config('vip_cidr'))
 
563
 
 
564
            if iface is not None:
 
565
                vip_key = 'res_neutron_{}_vip'.format(iface)
 
566
                resources[vip_key] = res_neutron_vip
 
567
                resource_params[vip_key] = (
 
568
                    'params {ip}="{vip}" cidr_netmask="{netmask}" '
 
569
                    'nic="{iface}"'.format(ip=vip_params,
 
570
                                           vip=vip,
 
571
                                           iface=iface,
 
572
                                           netmask=netmask)
 
573
                )
 
574
                vip_group.append(vip_key)
 
575
 
 
576
        if len(vip_group) >= 1:
 
577
            relation_set(groups={'grp_neutron_vips': ' '.join(vip_group)})
 
578
 
 
579
    init_services = {
 
580
        'res_neutron_haproxy': 'haproxy'
 
581
    }
 
582
    clones = {
 
583
        'cl_nova_haproxy': 'res_neutron_haproxy'
 
584
    }
 
585
    relation_set(relation_id=relation_id,
 
586
                 init_services=init_services,
 
587
                 corosync_bindiface=cluster_config['ha-bindiface'],
 
588
                 corosync_mcastport=cluster_config['ha-mcastport'],
 
589
                 resources=resources,
 
590
                 resource_params=resource_params,
 
591
                 clones=clones)
 
592
 
 
593
 
 
594
@hooks.hook('ha-relation-changed')
 
595
def ha_changed():
 
596
    clustered = relation_get('clustered')
 
597
    if not clustered or clustered in [None, 'None', '']:
 
598
        log('ha_changed: hacluster subordinate'
 
599
            ' not fully clustered: %s' % clustered)
 
600
        return
 
601
    log('Cluster configured, notifying other services and updating '
 
602
        'keystone endpoint configuration')
 
603
    for rid in relation_ids('identity-service'):
 
604
        identity_joined(rid=rid)
 
605
    for rid in relation_ids('neutron-api'):
 
606
        neutron_api_relation_joined(rid=rid)
 
607
 
 
608
 
 
609
@hooks.hook('zeromq-configuration-relation-joined')
 
610
@os_requires_version('kilo', 'neutron-server')
 
611
def zeromq_configuration_relation_joined(relid=None):
 
612
    relation_set(relation_id=relid,
 
613
                 topics=" ".join(get_topics()),
 
614
                 users="neutron")
 
615
 
 
616
 
 
617
@hooks.hook('neutron-plugin-api-subordinate-relation-joined',
 
618
            'neutron-plugin-api-subordinate-relation-changed')
 
619
@restart_on_change(restart_map(), stopstart=True)
 
620
def neutron_plugin_api_subordinate_relation_joined(relid=None):
 
621
    '''
 
622
    -changed handles relation data set by a subordinate.
 
623
    '''
 
624
    relation_data = {'neutron-api-ready': 'no'}
 
625
    if is_api_ready(CONFIGS):
 
626
        relation_data['neutron-api-ready'] = "yes"
 
627
    relation_set(relation_id=relid, **relation_data)
 
628
 
 
629
    # there is no race condition with the neutron service restart
 
630
    # as juju propagates the changes done in relation_set only after
 
631
    # the hook exists
 
632
    CONFIGS.write(API_PASTE_INI)
 
633
 
 
634
 
 
635
@hooks.hook('zeromq-configuration-relation-changed',
 
636
            'neutron-plugin-api-subordinate-relation-changed')
 
637
@restart_on_change(restart_map(), stopstart=True)
 
638
def zeromq_configuration_relation_changed():
 
639
    CONFIGS.write_all()
 
640
 
 
641
 
 
642
@hooks.hook('nrpe-external-master-relation-joined',
 
643
            'nrpe-external-master-relation-changed')
 
644
def update_nrpe_config():
 
645
    # python-dbus is used by check_upstart_job
 
646
    apt_install('python-dbus')
 
647
    hostname = nrpe.get_nagios_hostname()
 
648
    current_unit = nrpe.get_nagios_unit_name()
 
649
    nrpe_setup = nrpe.NRPE(hostname=hostname)
 
650
    nrpe.copy_nrpe_checks()
 
651
    nrpe.add_init_service_checks(nrpe_setup, services(), current_unit)
 
652
 
 
653
    nrpe.add_haproxy_checks(nrpe_setup, current_unit)
 
654
    nrpe_setup.write()
 
655
 
 
656
 
 
657
@hooks.hook('etcd-proxy-relation-joined')
 
658
@hooks.hook('etcd-proxy-relation-changed')
 
659
def etcd_proxy_force_restart(relation_id=None):
 
660
    # note(cory.benfield): Mostly etcd does not require active management,
 
661
    # but occasionally it does require a full config nuking. This does not
 
662
    # play well with the standard neutron-api config management, so we
 
663
    # treat etcd like the special snowflake it insists on being.
 
664
    CONFIGS.register('/etc/init/etcd.conf', [EtcdContext()])
 
665
    CONFIGS.write('/etc/init/etcd.conf')
 
666
    CONFIGS.register('/etc/default/etcd', [EtcdContext()])
 
667
    CONFIGS.write('/etc/default/etcd')
 
668
 
 
669
    if 'etcd-proxy' in CONFIGS.complete_contexts():
 
670
        force_etcd_restart()
 
671
 
 
672
 
 
673
@hooks.hook('midonet-relation-joined')
 
674
@hooks.hook('midonet-relation-changed')
 
675
@hooks.hook('midonet-relation-departed')
 
676
@restart_on_change(restart_map())
 
677
def midonet_changed():
 
678
    CONFIGS.write_all()
 
679
 
 
680
 
 
681
@hooks.hook('update-status')
 
682
@harden()
 
683
@harden()
 
684
def update_status():
 
685
    log('Updating status.')
 
686
 
 
687
 
 
688
def main():
 
689
    try:
 
690
        hooks.execute(sys.argv)
 
691
    except UnregisteredHookError as e:
 
692
        log('Unknown hook {} - skipping.'.format(e))
 
693
    assess_status(CONFIGS)
 
694
 
 
695
 
 
696
if __name__ == '__main__':
 
697
    main()