~1chb1n/charms/trusty/nova-cloud-controller/15.10-stable-flip-tests-helper-syncs

« back to all changes in this revision

Viewing changes to hooks/nova_cc_hooks.py

Check in start of py redux.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
import sys
 
4
 
 
5
from subprocess import check_call
 
6
from urlparse import urlparse
 
7
 
 
8
from charmhelpers.core.hookenv import (
 
9
    Hooks,
 
10
    UnregisteredHookError,
 
11
    config,
 
12
    log,
 
13
    relation_get,
 
14
    relation_ids,
 
15
    relation_set,
 
16
    open_port,
 
17
    unit_get,
 
18
)
 
19
 
 
20
from charmhelpers.core.host import (
 
21
    apt_install, apt_update, filter_installed_packages, restart_on_change
 
22
)
 
23
 
 
24
from charmhelpers.contrib.openstack.utils import (
 
25
    configure_installation_source,
 
26
    openstack_upgrade_available,
 
27
)
 
28
 
 
29
from nova_cc_utils import (
 
30
    auth_token_config,
 
31
    determine_endpoints,
 
32
    determine_packages,
 
33
    determine_ports,
 
34
    do_openstack_upgrade,
 
35
    keystone_ca_cert_b64,
 
36
    migrate_database,
 
37
    save_script_rc,
 
38
    ssh_compute_add,
 
39
    quantum_plugin,
 
40
    register_configs,
 
41
    restart_map,
 
42
    volume_service,
 
43
    CLUSTER_RES,
 
44
)
 
45
 
 
46
from misc_utils import (
 
47
    quantum_enabled,
 
48
    quantum_attribute,
 
49
)
 
50
 
 
51
from charmhelpers.contrib.hahelpers.cluster import (
 
52
    canonical_url,
 
53
    eligible_leader,
 
54
    get_hacluster_config,
 
55
    is_leader,
 
56
)
 
57
 
 
58
hooks = Hooks()
 
59
CONFIGS = register_configs()
 
60
 
 
61
 
 
62
@hooks.hook()
 
63
def install():
 
64
    configure_installation_source(config('openstack-origin'))
 
65
    apt_update()
 
66
    apt_install(determine_packages(), fatal=True)
 
67
    [open_port(port) for port in determine_ports()]
 
68
 
 
69
 
 
70
@hooks.hook()
 
71
@restart_on_change(restart_map())
 
72
def config_changed():
 
73
    if openstack_upgrade_available('nova-common'):
 
74
        do_openstack_upgrade()
 
75
    save_script_rc()
 
76
    configure_https()
 
77
    # XXX configure quantum networking
 
78
 
 
79
 
 
80
@hooks.hook('amqp-relation-joined')
 
81
@restart_on_change(restart_map())
 
82
def amqp_joined():
 
83
    relation_set(username=config('rabbit-user'), vhost=config('rabbit-vhost'))
 
84
 
 
85
 
 
86
@hooks.hook('amqp-relation-changed')
 
87
@restart_on_change(restart_map())
 
88
def amqp_changed():
 
89
    if 'amqp' not in CONFIGS.complete_contexts():
 
90
        log('amqp relation incomplete. Peer not ready?')
 
91
        return
 
92
    CONFIGS.write('/etc/nova/nova.conf')
 
93
    if quantum_enabled():
 
94
        CONFIGS.write('/etc/quantum/quantum.conf')
 
95
    # XXX Configure quantum networking (after-restart!?)
 
96
 
 
97
 
 
98
@hooks.hook('shared-db-relation-joined')
 
99
def db_joined():
 
100
    relation_set(nova_database=config('database'),
 
101
                 nova_username=config('database-user'),
 
102
                 nova_hostname=unit_get('private-address'))
 
103
    if quantum_enabled():
 
104
        # request a database created for quantum if needed.
 
105
        relation_set(quantum_database=config('database'),
 
106
                     quantum_username=config('database-user'),
 
107
                     quantum_hostname=unit_get('private-address'))
 
108
 
 
109
 
 
110
@hooks.hook('shared-db-relation-changed')
 
111
@restart_on_change(restart_map())
 
112
def db_changed():
 
113
    if 'shared-db' not in CONFIGS.complete_contexts():
 
114
        log('shared-db relation incomplete. Peer not ready?')
 
115
        return
 
116
    CONFIGS.write('/etc/nova/nova.conf')
 
117
 
 
118
    if quantum_enabled():
 
119
        plugin = quantum_plugin()
 
120
        CONFIGS.write(quantum_attribute(plugin, 'config'))
 
121
 
 
122
    if eligible_leader(CLUSTER_RES):
 
123
        migrate_database()
 
124
 
 
125
 
 
126
@hooks.hook('image-service-relation-changed')
 
127
@restart_on_change(restart_map())
 
128
def image_service_changed():
 
129
    if 'image-service' not in CONFIGS.complete_contexts():
 
130
        log('image-service relation incomplete. Peer not ready?')
 
131
        return
 
132
    CONFIGS.write('/etc/nova/nova.conf')
 
133
    # TODO: special case config flag for essex (strip protocol)
 
134
 
 
135
 
 
136
@hooks.hook('identity-service-relation-joined')
 
137
@restart_on_change(restart_map())
 
138
def identity_joined(rid=None):
 
139
    relation_set(rid=rid, **determine_endpoints())
 
140
 
 
141
 
 
142
@hooks.hook('identity-service-relation-changed')
 
143
@restart_on_change(restart_map())
 
144
def identity_changed():
 
145
    if 'identity-service' not in CONFIGS.complete_contexts():
 
146
        log('identity-service relation incomplete. Peer not ready?')
 
147
        return
 
148
    CONFIGS.write('/etc/nova/api-paste.ini')
 
149
    if quantum_enabled():
 
150
        CONFIGS.write('/etc/quantum/api-paste.ini')
 
151
    # XXX configure quantum networking
 
152
 
 
153
 
 
154
@hooks.hook('nova-volume-service-relation-joined',
 
155
            'cinder-volume-service-relation-joined')
 
156
@restart_on_change(restart_map())
 
157
def volume_joined():
 
158
    CONFIGS.write('/etc/nova/nova.conf')
 
159
    # kick identity_joined() to publish possibly new nova-volume endpoint.
 
160
    [identity_joined(rid) for rid in relation_ids('identity-service')]
 
161
 
 
162
 
 
163
def _auth_config():
 
164
    '''Grab all KS auth token config from api-paste.ini, or return empty {}'''
 
165
    ks_auth_host = auth_token_config('auth_host')
 
166
    if not ks_auth_host:
 
167
        # if there is no auth_host set, identity-service changed hooks
 
168
        # have not fired, yet.
 
169
        return {}
 
170
    cfg = {
 
171
        'auth_host': ks_auth_host,
 
172
        'auth_port': auth_token_config('auth_port'),
 
173
        'service_port': auth_token_config('service_port'),
 
174
        'service_username': auth_token_config('admin_user'),
 
175
        'service_password': auth_token_config('admin_password'),
 
176
        'service_tenant_name': auth_token_config('admin_tenant_name'),
 
177
        'auth_uri': auth_token_config('auth_uri'),
 
178
    }
 
179
    return cfg
 
180
 
 
181
 
 
182
@hooks.hook('cloud-compute-relation-joined')
 
183
def compute_joined(rid=None):
 
184
    if not eligible_leader():
 
185
        return
 
186
    rel_settings = {
 
187
        'network_manager': config('network-manager'),
 
188
        'volume_service': volume_service(),
 
189
        # (comment from bash vers) XXX Should point to VIP if clustered, or
 
190
        # this may not even be needed.
 
191
        'ec2_host': unit_get('private-address'),
 
192
    }
 
193
 
 
194
    ks_auth_config = _auth_config()
 
195
 
 
196
    if quantum_enabled():
 
197
        if ks_auth_config:
 
198
            rel_settings.update(ks_auth_config)
 
199
            rel_settings.update({
 
200
                'quantum_plugin': quantum_plugin(),
 
201
                'region': config('region'),
 
202
                'quantum_security_groups': config('quantum_security_groups'),
 
203
            })
 
204
 
 
205
    ks_ca = keystone_ca_cert_b64()
 
206
    if ks_auth_config and ks_ca:
 
207
        rel_settings['ca_cert'] = ks_ca
 
208
    relation_set(rid=rid, **rel_settings)
 
209
 
 
210
 
 
211
@hooks.hook('cloud-compute-relation-joined')
 
212
def compute_changed():
 
213
    migration_auth = relation_get('migration_auth_type')
 
214
    if migration_auth == 'ssh':
 
215
        ssh_compute_add()
 
216
 
 
217
 
 
218
@hooks.hook('quantum-network-servicerelation-joined')
 
219
def quantum_joined(rid=None):
 
220
    if not eligible_leader():
 
221
        return
 
222
 
 
223
    # XXX TODO: Need to add neutron/quantum compat. for pkg naming
 
224
    required_pkg = filter_installed_packages(['quantum-server'])
 
225
    if required_pkg:
 
226
        apt_install(required_pkg)
 
227
 
 
228
    url = canonical_url(CONFIGS) + ':9696'
 
229
 
 
230
    rel_settings = {
 
231
        'quantum_host': urlparse(url).hostname,
 
232
        'quantum_url': url,
 
233
        'quantum_port': 9696,
 
234
        'quantum_plugin': config('quantum-plugin'),
 
235
        'region': config('region')
 
236
    }
 
237
 
 
238
    # inform quantum about local keystone auth config
 
239
    ks_auth_config = _auth_config()
 
240
    rel_settings.update(ks_auth_config)
 
241
 
 
242
    # must pass the keystone CA cert, if it exists.
 
243
    ks_ca = keystone_ca_cert_b64()
 
244
    if ks_auth_config and ks_ca:
 
245
        rel_settings['ca_cert'] = ks_ca
 
246
 
 
247
    relation_set(rid=rid, **rel_settings)
 
248
 
 
249
 
 
250
@hooks.hook('cluster-relation-changed',
 
251
            'cluster-relation-departed')
 
252
@restart_on_change(restart_map())
 
253
def cluster_changed():
 
254
    CONFIGS.write_all()
 
255
 
 
256
 
 
257
@hooks.hook('ha-relation-joined')
 
258
def ha_joined():
 
259
    config = get_hacluster_config()
 
260
    resources = {
 
261
        'res_nova_vip': 'ocf:heartbeat:IPaddr2',
 
262
        'res_nova_haproxy': 'lsb:haproxy',
 
263
    }
 
264
    vip_params = 'params ip="%s" cidr_netmask="%s" nic="%s"' % \
 
265
                 (config['vip'], config['vip_cidr'], config['vip_iface'])
 
266
    resource_params = {
 
267
        'res_nova_vip': vip_params,
 
268
        'res_nova_haproxy': 'op monitor interval="5s"'
 
269
    }
 
270
    init_services = {
 
271
        'res_nova_haproxy': 'haproxy'
 
272
    }
 
273
    clones = {
 
274
        'cl_nova_haproxy': 'res_nova_haproxy'
 
275
    }
 
276
    relation_set(init_services=init_services,
 
277
                 corosync_bindiface=config['ha-bindiface'],
 
278
                 corosync_mcastport=config['ha-mcastport'],
 
279
                 resources=resources,
 
280
                 resource_params=resource_params,
 
281
                 clones=clones)
 
282
 
 
283
 
 
284
@hooks.hook('ha-relation-changed')
 
285
def ha_changed():
 
286
    if not relation_get('clustered'):
 
287
        log('ha_changed: hacluster subordinate not fully clustered.')
 
288
        return
 
289
    if not is_leader(CLUSTER_RES):
 
290
        log('ha_changed: hacluster complete but we are not leader.')
 
291
        return
 
292
    log('Cluster configured, notifying other services and updating '
 
293
        'keystone endpoint configuration')
 
294
    for rid in relation_ids('identity-service'):
 
295
        identity_joined(rid=rid)
 
296
 
 
297
 
 
298
def configure_https():
 
299
    '''
 
300
    Enables SSL API Apache config if appropriate and kicks identity-service
 
301
    with any required api updates.
 
302
    '''
 
303
    # need to write all to ensure changes to the entire request pipeline
 
304
    # propagate (c-api, haprxy, apache)
 
305
    CONFIGS.write_all()
 
306
    if 'https' in CONFIGS.complete_contexts():
 
307
        cmd = ['a2ensite', 'openstack_https_frontend']
 
308
        check_call(cmd)
 
309
    else:
 
310
        cmd = ['a2dissite', 'openstack_https_frontend']
 
311
        check_call(cmd)
 
312
 
 
313
    for rid in relation_ids('identity-service'):
 
314
        identity_joined(rid=rid)
 
315
 
 
316
 
 
317
def main():
 
318
    try:
 
319
        hooks.execute(sys.argv)
 
320
    except UnregisteredHookError as e:
 
321
        log('Unknown hook {} - skipping.'.format(e))
 
322
 
 
323
 
 
324
if __name__ == '__main__':
 
325
    main()