~gnuoy/charms/trusty/neutron-openvswitch/workloadstatus

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/openstack/context.py

[hopem,r=gnuoy] Sync charm-helpers to get fix for LP: #1497517

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# You should have received a copy of the GNU Lesser General Public License
15
15
# along with charm-helpers.  If not, see <http://www.gnu.org/licenses/>.
16
16
 
 
17
import glob
17
18
import json
18
19
import os
19
20
import re
194
195
class OSContextGenerator(object):
195
196
    """Base class for all context generators."""
196
197
    interfaces = []
 
198
    related = False
 
199
    complete = False
 
200
    missing_data = []
197
201
 
198
202
    def __call__(self):
199
203
        raise NotImplementedError
200
204
 
 
205
    def context_complete(self, ctxt):
 
206
        """Check for missing data for the required context data.
 
207
        Set self.missing_data if it exists and return False.
 
208
        Set self.complete if no missing data and return True.
 
209
        """
 
210
        # Fresh start
 
211
        self.complete = False
 
212
        self.missing_data = []
 
213
        for k, v in six.iteritems(ctxt):
 
214
            if v is None or v == '':
 
215
                if k not in self.missing_data:
 
216
                    self.missing_data.append(k)
 
217
 
 
218
        if self.missing_data:
 
219
            self.complete = False
 
220
            log('Missing required data: %s' % ' '.join(self.missing_data), level=INFO)
 
221
        else:
 
222
            self.complete = True
 
223
        return self.complete
 
224
 
 
225
    def get_related(self):
 
226
        """Check if any of the context interfaces have relation ids.
 
227
        Set self.related and return True if one of the interfaces
 
228
        has relation ids.
 
229
        """
 
230
        # Fresh start
 
231
        self.related = False
 
232
        try:
 
233
            for interface in self.interfaces:
 
234
                if relation_ids(interface):
 
235
                    self.related = True
 
236
            return self.related
 
237
        except AttributeError as e:
 
238
            log("{} {}"
 
239
                "".format(self, e), 'INFO')
 
240
            return self.related
 
241
 
201
242
 
202
243
class SharedDBContext(OSContextGenerator):
203
244
    interfaces = ['shared-db']
213
254
        self.database = database
214
255
        self.user = user
215
256
        self.ssl_dir = ssl_dir
 
257
        self.rel_name = self.interfaces[0]
216
258
 
217
259
    def __call__(self):
218
260
        self.database = self.database or config('database')
246
288
            password_setting = self.relation_prefix + '_password'
247
289
 
248
290
        for rid in relation_ids(self.interfaces[0]):
 
291
            self.related = True
249
292
            for unit in related_units(rid):
250
293
                rdata = relation_get(rid=rid, unit=unit)
251
294
                host = rdata.get('db_host')
257
300
                    'database_password': rdata.get(password_setting),
258
301
                    'database_type': 'mysql'
259
302
                }
260
 
                if context_complete(ctxt):
 
303
                if self.context_complete(ctxt):
261
304
                    db_ssl(rdata, ctxt, self.ssl_dir)
262
305
                    return ctxt
263
306
        return {}
278
321
 
279
322
        ctxt = {}
280
323
        for rid in relation_ids(self.interfaces[0]):
 
324
            self.related = True
281
325
            for unit in related_units(rid):
282
326
                rel_host = relation_get('host', rid=rid, unit=unit)
283
327
                rel_user = relation_get('user', rid=rid, unit=unit)
287
331
                        'database_user': rel_user,
288
332
                        'database_password': rel_passwd,
289
333
                        'database_type': 'postgresql'}
290
 
                if context_complete(ctxt):
 
334
                if self.context_complete(ctxt):
291
335
                    return ctxt
292
336
 
293
337
        return {}
348
392
            ctxt['signing_dir'] = cachedir
349
393
 
350
394
        for rid in relation_ids(self.rel_name):
 
395
            self.related = True
351
396
            for unit in related_units(rid):
352
397
                rdata = relation_get(rid=rid, unit=unit)
353
398
                serv_host = rdata.get('service_host')
366
411
                             'service_protocol': svc_protocol,
367
412
                             'auth_protocol': auth_protocol})
368
413
 
369
 
                if context_complete(ctxt):
 
414
                if self.context_complete(ctxt):
370
415
                    # NOTE(jamespage) this is required for >= icehouse
371
416
                    # so a missing value just indicates keystone needs
372
417
                    # upgrading
405
450
        ctxt = {}
406
451
        for rid in relation_ids(self.rel_name):
407
452
            ha_vip_only = False
 
453
            self.related = True
408
454
            for unit in related_units(rid):
409
455
                if relation_get('clustered', rid=rid, unit=unit):
410
456
                    ctxt['clustered'] = True
437
483
                ha_vip_only = relation_get('ha-vip-only',
438
484
                                           rid=rid, unit=unit) is not None
439
485
 
440
 
                if context_complete(ctxt):
 
486
                if self.context_complete(ctxt):
441
487
                    if 'rabbit_ssl_ca' in ctxt:
442
488
                        if not self.ssl_dir:
443
489
                            log("Charm not setup for ssl support but ssl ca "
469
515
            ctxt['oslo_messaging_flags'] = config_flags_parser(
470
516
                oslo_messaging_flags)
471
517
 
472
 
        if not context_complete(ctxt):
 
518
        if not self.complete:
473
519
            return {}
474
520
 
475
521
        return ctxt
485
531
 
486
532
        log('Generating template context for ceph', level=DEBUG)
487
533
        mon_hosts = []
488
 
        auth = None
489
 
        key = None
490
 
        use_syslog = str(config('use-syslog')).lower()
 
534
        ctxt = {
 
535
            'use_syslog': str(config('use-syslog')).lower()
 
536
        }
491
537
        for rid in relation_ids('ceph'):
492
538
            for unit in related_units(rid):
493
 
                auth = relation_get('auth', rid=rid, unit=unit)
494
 
                key = relation_get('key', rid=rid, unit=unit)
 
539
                if not ctxt.get('auth'):
 
540
                    ctxt['auth'] = relation_get('auth', rid=rid, unit=unit)
 
541
                if not ctxt.get('key'):
 
542
                    ctxt['key'] = relation_get('key', rid=rid, unit=unit)
495
543
                ceph_pub_addr = relation_get('ceph-public-address', rid=rid,
496
544
                                             unit=unit)
497
545
                unit_priv_addr = relation_get('private-address', rid=rid,
500
548
                ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr
501
549
                mon_hosts.append(ceph_addr)
502
550
 
503
 
        ctxt = {'mon_hosts': ' '.join(sorted(mon_hosts)),
504
 
                'auth': auth,
505
 
                'key': key,
506
 
                'use_syslog': use_syslog}
 
551
        ctxt['mon_hosts'] = ' '.join(sorted(mon_hosts))
507
552
 
508
553
        if not os.path.isdir('/etc/ceph'):
509
554
            os.mkdir('/etc/ceph')
510
555
 
511
 
        if not context_complete(ctxt):
 
556
        if not self.context_complete(ctxt):
512
557
            return {}
513
558
 
514
559
        ensure_packages(['ceph-common'])
1334
1379
            ports = mappings.values()
1335
1380
            napi_settings = NeutronAPIContext()()
1336
1381
            mtu = napi_settings.get('network_device_mtu')
 
1382
            all_ports = set()
 
1383
            # If any of ports is a vlan device, its underlying device must have
 
1384
            # mtu applied first.
 
1385
            for port in ports:
 
1386
                for lport in glob.glob("/sys/class/net/%s/lower_*" % port):
 
1387
                    lport = os.path.basename(lport)
 
1388
                    all_ports.add(lport.split('_')[1])
 
1389
 
 
1390
            all_ports = list(all_ports)
 
1391
            all_ports.extend(ports)
1337
1392
            if mtu:
1338
 
                ctxt["devs"] = '\\n'.join(ports)
 
1393
                ctxt["devs"] = '\\n'.join(all_ports)
1339
1394
                ctxt['mtu'] = mtu
1340
1395
 
1341
1396
        return ctxt
1367
1422
                    'auth_protocol':
1368
1423
                    rdata.get('auth_protocol') or 'http',
1369
1424
                }
1370
 
                if context_complete(ctxt):
 
1425
                if self.context_complete(ctxt):
1371
1426
                    return ctxt
1372
1427
        return {}