~ionutbalutoiu/charms/trusty/neutron-api/next

« back to all changes in this revision

Viewing changes to tests/basic_deployment.py

  • Committer: Ryan Beisner
  • Date: 2015-08-22 03:57:12 UTC
  • mto: This revision was merged to the branch mainline in revision 139.
  • Revision ID: ryan.beisner@canonical.com-20150822035712-cnvtcg46wg642dha
update makefile, amulet test dependencies, test definitions, amulet test

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
2
"""
3
3
Basic neutron-api functional test.
4
 
 
5
 
test_* methods are called in sort order.
6
 
 
7
 
Convention to ensure desired test order:
8
 
    1xx service and endpoint checks
9
 
    2xx relation checks
10
 
    3xx config checks
11
 
    4xx functional checks
12
 
    9xx restarts and other final checks
13
 
 
14
 
Common relation definitions:
15
 
  - [ neutron-api, mysql ]
16
 
  - [ neutron-api, rabbitmq-server ]
17
 
  - [ neutron-api, nova-cloud-controller ]
18
 
  - [ neutron-api, neutron-openvswitch ]
19
 
  - [ neutron-api, keystone ]
20
 
  - [ neutron-api, neutron-gateway ]
21
 
 
22
 
Resultant relations of neutron-api service:
23
 
    relations:
24
 
      amqp:
25
 
      - rabbitmq-server
26
 
      cluster:
27
 
      - neutron-api
28
 
      identity-service:
29
 
      - keystone
30
 
      neutron-api:
31
 
      - nova-cloud-controller
32
 
      neutron-plugin-api:  # not inspected due to
33
 
      - neutron-openvswitch  # bug 1421388
34
 
      shared-db:
35
 
      - mysql
36
4
"""
37
5
 
38
6
import amulet
46
14
 
47
15
from charmhelpers.contrib.openstack.amulet.utils import (
48
16
    OpenStackAmuletUtils,
49
 
    DEBUG, # flake8: noqa
50
 
    ERROR
 
17
    DEBUG,
 
18
    # ERROR
51
19
)
52
20
 
53
21
# Use DEBUG to turn on debug logging
78
46
           """
79
47
        this_service = {'name': 'neutron-api'}
80
48
        other_services = [{'name': 'mysql'},
81
 
                          {'name': 'rabbitmq-server'}, {'name': 'keystone'},
 
49
                          {'name': 'rabbitmq-server'},
 
50
                          {'name': 'keystone'},
82
51
                          {'name': 'neutron-openvswitch'},
83
52
                          {'name': 'nova-cloud-controller'},
84
 
                          {'name': 'quantum-gateway'},
 
53
                          {'name': 'neutron-gateway'},
85
54
                          {'name': 'nova-compute'}]
86
55
        super(NeutronAPIBasicDeployment, self)._add_services(this_service,
87
56
                                                             other_services)
92
61
            'neutron-api:shared-db': 'mysql:shared-db',
93
62
            'neutron-api:amqp': 'rabbitmq-server:amqp',
94
63
            'neutron-api:neutron-api': 'nova-cloud-controller:neutron-api',
95
 
            'neutron-api:neutron-plugin-api': 'quantum-gateway:'
96
 
                                              'neutron-plugin-api',
97
 
            'neutron-api:neutron-plugin-api': 'neutron-openvswitch:'
 
64
            'neutron-api:neutron-plugin-api': 'neutron-gateway:'
98
65
                                              'neutron-plugin-api',
99
66
            'neutron-api:identity-service': 'keystone:identity-service',
100
67
            'keystone:shared-db': 'mysql:shared-db',
101
 
            'nova-compute:neutron-plugin': 'neutron-openvswitch:neutron-plugin',
 
68
            'nova-compute:neutron-plugin': 'neutron-openvswitch:'
 
69
                                           'neutron-plugin',
102
70
            'nova-cloud-controller:shared-db': 'mysql:shared-db',
103
71
        }
 
72
 
 
73
        # NOTE(beisner): relate this separately due to the resulting
 
74
        # duplicate dictionary key if included in the relations dict.
 
75
        relations_more = {
 
76
            'neutron-api:neutron-plugin-api': 'neutron-openvswitch:'
 
77
                                              'neutron-plugin-api',
 
78
        }
104
79
        super(NeutronAPIBasicDeployment, self)._add_relations(relations)
 
80
        super(NeutronAPIBasicDeployment, self)._add_relations(relations_more)
105
81
 
106
82
    def _configure_services(self):
107
83
        """Configure all of the services."""
122
98
                'http_proxy': amulet_http_proxy,
123
99
                'https_proxy': amulet_http_proxy,
124
100
            }
125
 
            neutron_api_config['openstack-origin-git'] = yaml.dump(openstack_origin_git)
 
101
            neutron_api_config['openstack-origin-git'] = yaml.dump(
 
102
                openstack_origin_git)
126
103
        keystone_config = {'admin-password': 'openstack',
127
104
                           'admin-token': 'ubuntutesting'}
128
105
        nova_cc_config = {'network-manager': 'Quantum',
129
106
                          'quantum-security-groups': 'yes'}
130
 
        configs = {'neutron-api': neutron_api_config,
131
 
                   'keystone': keystone_config,
132
 
                   'nova-cloud-controller': nova_cc_config}
 
107
        configs = {
 
108
            'neutron-api': neutron_api_config,
 
109
            'keystone': keystone_config,
 
110
            'nova-cloud-controller': nova_cc_config
 
111
        }
133
112
        super(NeutronAPIBasicDeployment, self)._configure_services(configs)
134
113
 
135
114
    def _initialize_tests(self):
139
118
        self.keystone_sentry = self.d.sentry.unit['keystone/0']
140
119
        self.rabbitmq_sentry = self.d.sentry.unit['rabbitmq-server/0']
141
120
        self.nova_cc_sentry = self.d.sentry.unit['nova-cloud-controller/0']
142
 
        self.quantum_gateway_sentry = self.d.sentry.unit['quantum-gateway/0']
 
121
        self.neutron_sentry = self.d.sentry.unit['neutron-gateway/0']
143
122
        self.neutron_api_sentry = self.d.sentry.unit['neutron-api/0']
 
123
        self.neutron_ovs_sentry = self.d.sentry.unit['neutron-openvswitch/0']
144
124
        self.nova_compute_sentry = self.d.sentry.unit['nova-compute/0']
145
125
        u.log.debug('openstack release val: {}'.format(
146
126
            self._get_openstack_release()))
149
129
        # Let things settle a bit before moving forward
150
130
        time.sleep(30)
151
131
 
152
 
 
153
132
    def test_100_services(self):
154
133
        """Verify the expected services are running on the corresponding
155
134
           service units."""
156
135
        u.log.debug('Checking status of system services...')
157
 
        # Fails vivid-kilo, bug 1454754
158
 
        neutron_api_services = ['status neutron-server']
159
 
        neutron_services = ['status neutron-dhcp-agent',
160
 
                            'status neutron-lbaas-agent',
161
 
                            'status neutron-metadata-agent',
162
 
                            'status neutron-plugin-openvswitch-agent',
163
 
                            'status neutron-ovs-cleanup']
 
136
        neutron_api_services = ['neutron-server']
 
137
        neutron_services = ['neutron-dhcp-agent',
 
138
                            'neutron-lbaas-agent',
 
139
                            'neutron-metadata-agent',
 
140
                            'neutron-plugin-openvswitch-agent',
 
141
                            'neutron-ovs-cleanup']
164
142
 
165
143
        if self._get_openstack_release() <= self.trusty_juno:
166
 
            neutron_services.append('status neutron-vpn-agent')
 
144
            neutron_services.append('neutron-vpn-agent')
167
145
 
168
146
        if self._get_openstack_release() < self.trusty_kilo:
169
147
            # Juno or earlier
170
 
            neutron_services.append('status neutron-metering-agent')
171
 
 
172
 
        nova_cc_services = ['status nova-api-ec2',
173
 
                            'status nova-api-os-compute',
174
 
                            'status nova-objectstore',
175
 
                            'status nova-cert',
176
 
                            'status nova-scheduler',
177
 
                            'status nova-conductor']
178
 
 
179
 
        commands = {
180
 
            self.mysql_sentry: ['status mysql'],
181
 
            self.keystone_sentry: ['status keystone'],
 
148
            neutron_services.append('neutron-metering-agent')
 
149
 
 
150
        nova_cc_services = ['nova-api-ec2',
 
151
                            'nova-api-os-compute',
 
152
                            'nova-objectstore',
 
153
                            'nova-cert',
 
154
                            'nova-scheduler',
 
155
                            'nova-conductor']
 
156
 
 
157
        services = {
 
158
            self.mysql_sentry: ['mysql'],
 
159
            self.keystone_sentry: ['keystone'],
182
160
            self.nova_cc_sentry: nova_cc_services,
183
 
            self.quantum_gateway_sentry: neutron_services,
 
161
            self.neutron_sentry: neutron_services,
184
162
            self.neutron_api_sentry: neutron_api_services,
185
163
        }
186
164
 
187
 
        ret = u.validate_services(commands)
 
165
        ret = u.validate_services_by_name(services)
188
166
        if ret:
189
167
            amulet.raise_status(amulet.FAIL, msg=ret)
190
168
 
191
169
    def test_200_neutron_api_shared_db_relation(self):
192
170
        """Verify the neutron-api to mysql shared-db relation data"""
193
 
        u.log.debug('Checking neutron-api:mysql relation data...')
 
171
        u.log.debug('Checking neutron-api:mysql db relation data...')
194
172
        unit = self.neutron_api_sentry
195
173
        relation = ['shared-db', 'mysql:shared-db']
196
174
        expected = {
207
185
 
208
186
    def test_201_shared_db_neutron_api_relation(self):
209
187
        """Verify the mysql to neutron-api shared-db relation data"""
210
 
        u.log.debug('Checking mysql:neutron-api relation data...')
 
188
        u.log.debug('Checking mysql:neutron-api db relation data...')
211
189
        unit = self.mysql_sentry
212
190
        relation = ['shared-db', 'neutron-api:shared-db']
213
191
        expected = {
214
192
            'db_host': u.valid_ip,
215
193
            'private-address': u.valid_ip,
 
194
            'password': u.not_null
216
195
        }
217
196
 
218
197
        if self._get_openstack_release() == self.precise_icehouse:
223
202
            expected['allowed_units'] = 'neutron-api/0'
224
203
 
225
204
        ret = u.validate_relation_data(unit, relation, expected)
226
 
        rel_data = unit.relation('shared-db', 'neutron-api:shared-db')
227
 
        if ret or 'password' not in rel_data:
 
205
        if ret:
228
206
            message = u.relation_error('mysql shared-db', ret)
229
207
            amulet.raise_status(amulet.FAIL, msg=message)
230
208
 
249
227
        u.log.debug('Checking amqp:neutron-api relation data...')
250
228
        unit = self.rabbitmq_sentry
251
229
        relation = ['amqp', 'neutron-api:amqp']
252
 
        rel_data = unit.relation('amqp', 'neutron-api:amqp')
253
230
        expected = {
254
231
            'hostname': u.valid_ip,
255
232
            'private-address': u.valid_ip,
 
233
            'password': u.not_null
256
234
        }
257
235
 
258
236
        ret = u.validate_relation_data(unit, relation, expected)
259
 
        if ret or not 'password' in rel_data:
 
237
        if ret:
260
238
            message = u.relation_error('rabbitmq amqp', ret)
261
239
            amulet.raise_status(amulet.FAIL, msg=message)
262
240
 
263
 
    def test_204_neutron_api_identity_relation(self):
 
241
    def test_204_neutron_api_keystone_identity_relation(self):
264
242
        """Verify the neutron-api to keystone identity-service relation data"""
265
 
        u.log.debug('Checking neutron-api:keystone relation data...')
 
243
        u.log.debug('Checking neutron-api:keystone id relation data...')
266
244
        unit = self.neutron_api_sentry
267
245
        relation = ['identity-service', 'keystone:identity-service']
268
246
        api_ip = unit.relation('identity-service',
269
247
                               'keystone:identity-service')['private-address']
270
 
        api_endpoint = "http://%s:9696" % (api_ip)
 
248
        api_endpoint = 'http://{}:9696'.format(api_ip)
271
249
        expected = {
272
250
            'private-address': u.valid_ip,
273
251
            'quantum_region': 'RegionOne',
284
262
 
285
263
    def test_205_keystone_neutron_api_identity_relation(self):
286
264
        """Verify the keystone to neutron-api identity-service relation data"""
287
 
        u.log.debug('Checking keystone:neutron-api relation data...')
 
265
        u.log.debug('Checking keystone:neutron-api id relation data...')
288
266
        unit = self.keystone_sentry
289
267
        relation = ['identity-service', 'neutron-api:identity-service']
290
 
        id_relation = unit.relation('identity-service',
291
 
                                    'neutron-api:identity-service')
292
 
        id_ip = id_relation['private-address']
 
268
        rel_ks_id = unit.relation('identity-service',
 
269
                                  'neutron-api:identity-service')
 
270
        id_ip = rel_ks_id['private-address']
293
271
        expected = {
294
272
            'admin_token': 'ubuntutesting',
295
273
            'auth_host': id_ip,
303
281
            message = u.relation_error('neutron-api identity-service', ret)
304
282
            amulet.raise_status(amulet.FAIL, msg=message)
305
283
 
306
 
    def test_206_neutron_api_plugin_relation(self):
 
284
    def test_206_neutron_api_neutron_ovs_plugin_api_relation(self):
307
285
        """Verify neutron-api to neutron-openvswitch neutron-plugin-api"""
308
 
        u.log.debug('Checking neutron-api:neutron-ovs relation data...')
 
286
        u.log.debug('Checking neutron-api:neutron-ovs plugin-api '
 
287
                    'relation data...')
309
288
        unit = self.neutron_api_sentry
310
289
        relation = ['neutron-plugin-api',
311
290
                    'neutron-openvswitch:neutron-plugin-api']
 
291
#
 
292
        u.log.debug(unit.relation(relation[0], relation[1]))
 
293
        expected = {
 
294
            'auth_host': u.valid_ip,
 
295
            'auth_port': '35357',
 
296
            'auth_protocol': 'http',
 
297
            'enable-dvr': 'False',
 
298
            'enable-l3ha': 'False',
 
299
            'l2-population': 'True',
 
300
            'neutron-security-groups': 'False',
 
301
            'overlay-network-type': 'gre',
 
302
            'private-address': u.valid_ip,
 
303
            'region': 'RegionOne',
 
304
            'service_host': u.valid_ip,
 
305
            'service_password': u.not_null,
 
306
            'service_port': '5000',
 
307
            'service_protocol': 'http',
 
308
            'service_tenant': 'services',
 
309
            'service_username': 'quantum',
 
310
        }
 
311
        ret = u.validate_relation_data(unit, relation, expected)
 
312
        if ret:
 
313
            message = u.relation_error(
 
314
                'neutron-api neutron-ovs neutronplugin-api', ret)
 
315
            amulet.raise_status(amulet.FAIL, msg=message)
 
316
 
 
317
    def test_207_neutron_ovs_neutron_api_plugin_api_relation(self):
 
318
        """Verify neutron-openvswitch to neutron-api neutron-plugin-api"""
 
319
        u.log.debug('Checking neutron-ovs:neutron-api plugin-api '
 
320
                    'relation data...')
 
321
        unit = self.neutron_ovs_sentry
 
322
        relation = ['neutron-plugin-api',
 
323
                    'neutron-api:neutron-plugin-api']
312
324
        expected = {
313
325
            'private-address': u.valid_ip,
314
326
        }
317
329
            message = u.relation_error('neutron-api neutron-plugin-api', ret)
318
330
            amulet.raise_status(amulet.FAIL, msg=message)
319
331
 
320
 
    def test_207_neutron_api_novacc_relation(self):
 
332
    def test_208_neutron_api_novacc_relation(self):
321
333
        """Verify the neutron-api to nova-cloud-controller relation data"""
322
334
        u.log.debug('Checking neutron-api:novacc relation data...')
323
335
        unit = self.neutron_api_sentry
324
336
        relation = ['neutron-api', 'nova-cloud-controller:neutron-api']
325
337
        api_ip = unit.relation('identity-service',
326
338
                               'keystone:identity-service')['private-address']
327
 
        api_endpoint = "http://%s:9696" % (api_ip)
 
339
        api_endpoint = 'http://{}:9696'.format(api_ip)
328
340
        expected = {
329
341
            'private-address': api_ip,
330
342
            'neutron-plugin': 'ovs',
336
348
            message = u.relation_error('neutron-api neutron-api', ret)
337
349
            amulet.raise_status(amulet.FAIL, msg=message)
338
350
 
339
 
    def test_208_novacc_neutron_api_relation(self):
 
351
    def test_209_novacc_neutron_api_relation(self):
340
352
        """Verify the nova-cloud-controller to neutron-api relation data"""
341
353
        u.log.debug('Checking novacc:neutron-api relation data...')
342
354
        unit = self.nova_cc_sentry
343
355
        relation = ['neutron-api', 'neutron-api:neutron-api']
344
356
        cc_ip = unit.relation('neutron-api',
345
357
                              'neutron-api:neutron-api')['private-address']
346
 
        cc_endpoint = "http://%s:8774/v2" % (cc_ip)
 
358
        cc_endpoint = 'http://{}:8774/v2'.format(cc_ip)
347
359
        expected = {
348
360
            'private-address': cc_ip,
349
361
            'nova_url': cc_endpoint,
353
365
            message = u.relation_error('nova-cc neutron-api', ret)
354
366
            amulet.raise_status(amulet.FAIL, msg=message)
355
367
 
356
 
    # XXX Test missing to examine the relation data neutron-openvswitch is
357
 
    #     receiving. Current;y this data cannot be interegated due to
358
 
    #     Bug#1421388
359
 
 
360
 
    def test_900_restart_on_config_change(self):
361
 
        """Verify that the specified services are restarted when the config
362
 
           is changed.
363
 
 
364
 
           Note(coreycb): The method name with the _z_ is a little odd
365
 
           but it forces the test to run last.  It just makes things
366
 
           easier because restarting services requires re-authorization.
367
 
           """
368
 
        u.log.debug('Checking novacc neutron-api relation data...')
369
 
        conf = '/etc/neutron/neutron.conf'
370
 
        services = ['neutron-server']
371
 
        u.log.debug('Making config change on neutron-api service...')
372
 
        self.d.configure('neutron-api', {'use-syslog': 'True'})
373
 
        stime = 60
374
 
        for s in services:
375
 
            u.log.debug("Checking that service restarted: {}".format(s))
376
 
            if not u.service_restarted(self.neutron_api_sentry, s, conf,
377
 
                                       pgrep_full=True, sleep_time=stime):
378
 
                self.d.configure('neutron-api', {'use-syslog': 'False'})
379
 
                msg = "service {} didn't restart after config change".format(s)
380
 
                amulet.raise_status(amulet.FAIL, msg=msg)
381
 
            stime = 0
382
 
        self.d.configure('neutron-api', {'use-syslog': 'False'})
383
 
 
384
368
    def test_300_neutron_config(self):
385
369
        """Verify the data in the neutron config file."""
386
370
        u.log.debug('Checking neutron.conf config file data...')
389
373
                                                   'neutron-api:neutron-api')
390
374
        rabbitmq_relation = self.rabbitmq_sentry.relation('amqp',
391
375
                                                          'neutron-api:amqp')
392
 
        ks_rel = self.keystone_sentry.relation('identity-service',
393
 
                                               'neutron-api:identity-service')
 
376
        rel_napi_ks = self.keystone_sentry.relation(
 
377
            'identity-service', 'neutron-api:identity-service')
394
378
 
395
 
        nova_auth_url = '%s://%s:%s/v2.0' % (ks_rel['auth_protocol'],
396
 
                                             ks_rel['auth_host'],
397
 
                                             ks_rel['auth_port'])
398
 
        db_relation = self.mysql_sentry.relation('shared-db',
 
379
        nova_auth_url = '{}://{}:{}/v2.0'.format(rel_napi_ks['auth_protocol'],
 
380
                                                 rel_napi_ks['auth_host'],
 
381
                                                 rel_napi_ks['auth_port'])
 
382
        rel_napi_my = self.mysql_sentry.relation('shared-db',
399
383
                                                 'neutron-api:shared-db')
400
 
        db_conn = 'mysql://neutron:%s@%s/neutron' % (db_relation['password'],
401
 
                                                     db_relation['db_host'])
 
384
        db_conn = 'mysql://neutron:{}@{}/neutron'.format(
 
385
            rel_napi_my['password'], rel_napi_my['db_host'])
 
386
 
402
387
        conf = '/etc/neutron/neutron.conf'
403
388
        expected = {
404
389
            'DEFAULT': {
405
390
                'verbose': 'False',
 
391
# True on Kilo!?:
406
392
                'debug': 'False',
407
393
                'bind_port': '9686',
408
394
                'nova_url': cc_relation['nova_url'],
409
395
                'nova_region_name': 'RegionOne',
410
 
                'nova_admin_username': ks_rel['service_username'],
411
 
                'nova_admin_tenant_id': ks_rel['service_tenant_id'],
412
 
                'nova_admin_password': ks_rel['service_password'],
 
396
                'nova_admin_username': rel_napi_ks['service_username'],
 
397
                'nova_admin_tenant_id': rel_napi_ks['service_tenant_id'],
 
398
                'nova_admin_password': rel_napi_ks['service_password'],
413
399
                'nova_admin_auth_url': nova_auth_url,
414
400
            },
415
401
            'keystone_authtoken': {
416
402
                'signing_dir': '/var/cache/neutron',
417
403
                'admin_tenant_name': 'services',
418
404
                'admin_user': 'quantum',
419
 
                'admin_password': ks_rel['service_password'],
 
405
                'admin_password': rel_napi_ks['service_password'],
420
406
            },
421
407
            'database': {
422
408
                'connection': db_conn,
425
411
 
426
412
        if self._get_openstack_release() >= self.trusty_kilo:
427
413
            # Kilo or later
428
 
            expected.update(
429
 
                {
430
 
                    'oslo_messaging_rabbit': {
431
 
                        'rabbit_userid': 'neutron',
432
 
                        'rabbit_virtual_host': 'openstack',
433
 
                        'rabbit_password': rabbitmq_relation['password'],
434
 
                        'rabbit_host': rabbitmq_relation['hostname']
435
 
                    }
436
 
                }
437
 
            )
 
414
            expected['oslo_messaging_rabbit'] = {
 
415
                'rabbit_userid': 'neutron',
 
416
                'rabbit_virtual_host': 'openstack',
 
417
                'rabbit_password': rabbitmq_relation['password'],
 
418
                'rabbit_host': rabbitmq_relation['hostname']
 
419
            }
438
420
        else:
439
421
            # Juno or earlier
440
 
            expected['DEFAULT'].update(
441
 
                {
442
 
                    'rabbit_userid': 'neutron',
443
 
                    'rabbit_virtual_host': 'openstack',
444
 
                    'rabbit_password': rabbitmq_relation['password'],
445
 
                    'rabbit_host': rabbitmq_relation['hostname']
446
 
                }
447
 
            )
448
 
            expected['keystone_authtoken'].update(
449
 
                {
450
 
                    'service_protocol': ks_rel['service_protocol'],
451
 
                    'service_host': ks_rel['service_host'],
452
 
                    'service_port': ks_rel['service_port'],
453
 
                    'auth_host': ks_rel['auth_host'],
454
 
                    'auth_port': ks_rel['auth_port'],
455
 
                    'auth_protocol':  ks_rel['auth_protocol']
456
 
                }
457
 
            )
 
422
            expected['DEFAULT'].update({
 
423
                'rabbit_userid': 'neutron',
 
424
                'rabbit_virtual_host': 'openstack',
 
425
                'rabbit_password': rabbitmq_relation['password'],
 
426
                'rabbit_host': rabbitmq_relation['hostname']
 
427
            })
 
428
            expected['keystone_authtoken'].update({
 
429
                'service_protocol': rel_napi_ks['service_protocol'],
 
430
                'service_host': rel_napi_ks['service_host'],
 
431
                'service_port': rel_napi_ks['service_port'],
 
432
                'auth_host': rel_napi_ks['auth_host'],
 
433
                'auth_port': rel_napi_ks['auth_port'],
 
434
                'auth_protocol':  rel_napi_ks['auth_protocol']
 
435
            })
458
436
 
459
437
        for section, pairs in expected.iteritems():
460
438
            ret = u.validate_config_data(unit, conf, section, pairs)
495
473
 
496
474
        if self._get_openstack_release() >= self.trusty_kilo:
497
475
            # Kilo or later
498
 
            expected['ml2'].update(
499
 
                {
500
 
                    'mechanism_drivers': 'openvswitch,l2population'
501
 
                }
502
 
            )
 
476
            expected['ml2'].update({
 
477
                'mechanism_drivers': 'openvswitch,l2population'
 
478
            })
503
479
        else:
504
480
            # Juno or earlier
505
 
            expected['ml2'].update(
506
 
                {
507
 
                    'mechanism_drivers': 'openvswitch,hyperv,l2population'
508
 
                }
509
 
            )
 
481
            expected['ml2'].update({
 
482
                'mechanism_drivers': 'openvswitch,hyperv,l2population'
 
483
            })
510
484
 
511
485
        for section, pairs in expected.iteritems():
512
486
            ret = u.validate_config_data(unit, conf, section, pairs)
513
487
            if ret:
514
488
                message = "ml2 config error: {}".format(ret)
515
489
                amulet.raise_status(amulet.FAIL, msg=message)
 
490
 
 
491
    def test_900_restart_on_config_change(self):
 
492
        """Verify that the specified services are restarted when the
 
493
        config is changed."""
 
494
 
 
495
        sentry = self.neutron_api_sentry
 
496
        juju_service = 'neutron-api'
 
497
 
 
498
        # Expected default and alternate values
 
499
        set_default = {'debug': 'False'}
 
500
        set_alternate = {'debug': 'True'}
 
501
 
 
502
        # Services which are expected to restart upon config change,
 
503
        # and corresponding config files affected by the change
 
504
        services = {'neutron-server': '/etc/neutron/neutron.conf'}
 
505
 
 
506
        # Make config change, check for service restarts
 
507
        u.log.debug('Making config change on {}...'.format(juju_service))
 
508
        mtime = u.get_sentry_time(sentry)
 
509
        self.d.configure(juju_service, set_alternate)
 
510
 
 
511
        sleep_time = 60
 
512
        for s, conf_file in services.iteritems():
 
513
            u.log.debug("Checking that service restarted: {}".format(s))
 
514
            if not u.validate_service_config_changed(sentry, mtime, s,
 
515
                                                     conf_file,
 
516
                                                     sleep_time=sleep_time):
 
517
                self.d.configure(juju_service, set_default)
 
518
                msg = "service {} didn't restart after config change".format(s)
 
519
                amulet.raise_status(amulet.FAIL, msg=msg)
 
520
            sleep_time = 0
 
521
 
 
522
        self.d.configure(juju_service, set_default)