~corey.bryant/charms/trusty/quantum-gateway/amulet-updates

« back to all changes in this revision

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

  • Committer: Corey Bryant
  • Date: 2014-10-07 21:03:47 UTC
  • Revision ID: corey.bryant@canonical.com-20141007210347-ltczd6bjm0b0yj18
Sync charm-helpers.

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
    check_call
9
9
)
10
10
 
11
 
 
12
11
from charmhelpers.fetch import (
13
12
    apt_install,
14
13
    filter_installed_packages,
28
27
    INFO
29
28
)
30
29
 
 
30
from charmhelpers.core.host import (
 
31
    mkdir,
 
32
    write_file
 
33
)
 
34
 
31
35
from charmhelpers.contrib.hahelpers.cluster import (
32
36
    determine_apache_port,
33
37
    determine_api_port,
38
42
from charmhelpers.contrib.hahelpers.apache import (
39
43
    get_cert,
40
44
    get_ca_cert,
 
45
    install_ca_cert,
41
46
)
42
47
 
43
48
from charmhelpers.contrib.openstack.neutron import (
47
52
from charmhelpers.contrib.network.ip import (
48
53
    get_address_in_network,
49
54
    get_ipv6_addr,
 
55
    get_netmask_for_address,
 
56
    format_ipv6_addr,
 
57
    is_address_in_network
50
58
)
51
59
 
 
60
from charmhelpers.contrib.openstack.utils import get_host_ip
 
61
 
52
62
CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
53
63
 
54
64
 
168
178
        for rid in relation_ids('shared-db'):
169
179
            for unit in related_units(rid):
170
180
                rdata = relation_get(rid=rid, unit=unit)
 
181
                host = rdata.get('db_host')
 
182
                host = format_ipv6_addr(host) or host
171
183
                ctxt = {
172
 
                    'database_host': rdata.get('db_host'),
 
184
                    'database_host': host,
173
185
                    'database': self.database,
174
186
                    'database_user': self.user,
175
187
                    'database_password': rdata.get(password_setting),
245
257
        for rid in relation_ids('identity-service'):
246
258
            for unit in related_units(rid):
247
259
                rdata = relation_get(rid=rid, unit=unit)
 
260
                serv_host = rdata.get('service_host')
 
261
                serv_host = format_ipv6_addr(serv_host) or serv_host
 
262
                auth_host = rdata.get('auth_host')
 
263
                auth_host = format_ipv6_addr(auth_host) or auth_host
 
264
 
248
265
                ctxt = {
249
266
                    'service_port': rdata.get('service_port'),
250
 
                    'service_host': rdata.get('service_host'),
251
 
                    'auth_host': rdata.get('auth_host'),
 
267
                    'service_host': serv_host,
 
268
                    'auth_host': auth_host,
252
269
                    'auth_port': rdata.get('auth_port'),
253
270
                    'admin_tenant_name': rdata.get('service_tenant'),
254
271
                    'admin_user': rdata.get('service_username'),
297
314
            for unit in related_units(rid):
298
315
                if relation_get('clustered', rid=rid, unit=unit):
299
316
                    ctxt['clustered'] = True
300
 
                    ctxt['rabbitmq_host'] = relation_get('vip', rid=rid,
301
 
                                                         unit=unit)
 
317
                    vip = relation_get('vip', rid=rid, unit=unit)
 
318
                    vip = format_ipv6_addr(vip) or vip
 
319
                    ctxt['rabbitmq_host'] = vip
302
320
                else:
303
 
                    ctxt['rabbitmq_host'] = relation_get('private-address',
304
 
                                                         rid=rid, unit=unit)
 
321
                    host = relation_get('private-address', rid=rid, unit=unit)
 
322
                    host = format_ipv6_addr(host) or host
 
323
                    ctxt['rabbitmq_host'] = host
305
324
                ctxt.update({
306
325
                    'rabbitmq_user': username,
307
326
                    'rabbitmq_password': relation_get('password', rid=rid,
340
359
                    and len(related_units(rid)) > 1:
341
360
                rabbitmq_hosts = []
342
361
                for unit in related_units(rid):
343
 
                    rabbitmq_hosts.append(relation_get('private-address',
344
 
                                                       rid=rid, unit=unit))
 
362
                    host = relation_get('private-address', rid=rid, unit=unit)
 
363
                    host = format_ipv6_addr(host) or host
 
364
                    rabbitmq_hosts.append(host)
345
365
                ctxt['rabbitmq_hosts'] = ','.join(rabbitmq_hosts)
346
366
        if not context_complete(ctxt):
347
367
            return {}
370
390
                ceph_addr = \
371
391
                    relation_get('ceph-public-address', rid=rid, unit=unit) or \
372
392
                    relation_get('private-address', rid=rid, unit=unit)
 
393
                ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr
373
394
                mon_hosts.append(ceph_addr)
374
395
 
375
396
        ctxt = {
390
411
        return ctxt
391
412
 
392
413
 
 
414
ADDRESS_TYPES = ['admin', 'internal', 'public']
 
415
 
 
416
 
393
417
class HAProxyContext(OSContextGenerator):
394
418
    interfaces = ['cluster']
395
419
 
402
426
        if not relation_ids('cluster'):
403
427
            return {}
404
428
 
 
429
        l_unit = local_unit().replace('/', '-')
 
430
 
 
431
        if config('prefer-ipv6'):
 
432
            addr = get_ipv6_addr(exc_list=[config('vip')])[0]
 
433
        else:
 
434
            addr = get_host_ip(unit_get('private-address'))
 
435
 
405
436
        cluster_hosts = {}
406
 
        l_unit = local_unit().replace('/', '-')
407
 
        if config('prefer-ipv6'):
408
 
            addr = get_ipv6_addr()
409
 
        else:
410
 
            addr = unit_get('private-address')
411
 
        cluster_hosts[l_unit] = get_address_in_network(config('os-internal-network'),
412
 
                                                       addr)
413
 
 
414
 
        for rid in relation_ids('cluster'):
415
 
            for unit in related_units(rid):
416
 
                _unit = unit.replace('/', '-')
417
 
                addr = relation_get('private-address', rid=rid, unit=unit)
418
 
                cluster_hosts[_unit] = addr
 
437
 
 
438
        # NOTE(jamespage): build out map of configured network endpoints
 
439
        # and associated backends
 
440
        for addr_type in ADDRESS_TYPES:
 
441
            laddr = get_address_in_network(
 
442
                config('os-{}-network'.format(addr_type)))
 
443
            if laddr:
 
444
                cluster_hosts[laddr] = {}
 
445
                cluster_hosts[laddr]['network'] = "{}/{}".format(
 
446
                    laddr,
 
447
                    get_netmask_for_address(laddr)
 
448
                )
 
449
                cluster_hosts[laddr]['backends'] = {}
 
450
                cluster_hosts[laddr]['backends'][l_unit] = laddr
 
451
                for rid in relation_ids('cluster'):
 
452
                    for unit in related_units(rid):
 
453
                        _unit = unit.replace('/', '-')
 
454
                        _laddr = relation_get('{}-address'.format(addr_type),
 
455
                                              rid=rid, unit=unit)
 
456
                        if _laddr:
 
457
                            cluster_hosts[laddr]['backends'][_unit] = _laddr
 
458
 
 
459
        # NOTE(jamespage) no split configurations found, just use
 
460
        # private addresses
 
461
        if not cluster_hosts:
 
462
            cluster_hosts[addr] = {}
 
463
            cluster_hosts[addr]['network'] = "{}/{}".format(
 
464
                addr,
 
465
                get_netmask_for_address(addr)
 
466
            )
 
467
            cluster_hosts[addr]['backends'] = {}
 
468
            cluster_hosts[addr]['backends'][l_unit] = addr
 
469
            for rid in relation_ids('cluster'):
 
470
                for unit in related_units(rid):
 
471
                    _unit = unit.replace('/', '-')
 
472
                    _laddr = relation_get('private-address',
 
473
                                          rid=rid, unit=unit)
 
474
                    if _laddr:
 
475
                        cluster_hosts[addr]['backends'][_unit] = _laddr
419
476
 
420
477
        ctxt = {
421
 
            'units': cluster_hosts,
 
478
            'frontends': cluster_hosts,
422
479
        }
423
480
 
424
481
        if config('haproxy-server-timeout'):
425
 
            ctxt['haproxy-server-timeout'] = config('haproxy-server-timeout')
 
482
            ctxt['haproxy_server_timeout'] = config('haproxy-server-timeout')
426
483
        if config('haproxy-client-timeout'):
427
 
            ctxt['haproxy-client-timeout'] = config('haproxy-client-timeout')
 
484
            ctxt['haproxy_client_timeout'] = config('haproxy-client-timeout')
428
485
 
429
486
        if config('prefer-ipv6'):
430
487
            ctxt['local_host'] = 'ip6-localhost'
435
492
            ctxt['haproxy_host'] = '0.0.0.0'
436
493
            ctxt['stat_port'] = ':8888'
437
494
 
438
 
        if len(cluster_hosts.keys()) > 1:
439
 
            # Enable haproxy when we have enough peers.
440
 
            log('Ensuring haproxy enabled in /etc/default/haproxy.')
441
 
            with open('/etc/default/haproxy', 'w') as out:
442
 
                out.write('ENABLED=1\n')
443
 
            return ctxt
 
495
        for frontend in cluster_hosts:
 
496
            if len(cluster_hosts[frontend]['backends']) > 1:
 
497
                # Enable haproxy when we have enough peers.
 
498
                log('Ensuring haproxy enabled in /etc/default/haproxy.')
 
499
                with open('/etc/default/haproxy', 'w') as out:
 
500
                    out.write('ENABLED=1\n')
 
501
                return ctxt
444
502
        log('HAProxy context is incomplete, this unit has no peers.')
445
503
        return {}
446
504
 
495
553
        cmd = ['a2enmod', 'ssl', 'proxy', 'proxy_http']
496
554
        check_call(cmd)
497
555
 
498
 
    def configure_cert(self):
499
 
        if not os.path.isdir('/etc/apache2/ssl'):
500
 
            os.mkdir('/etc/apache2/ssl')
 
556
    def configure_cert(self, cn=None):
501
557
        ssl_dir = os.path.join('/etc/apache2/ssl/', self.service_namespace)
502
 
        if not os.path.isdir(ssl_dir):
503
 
            os.mkdir(ssl_dir)
504
 
        cert, key = get_cert()
505
 
        with open(os.path.join(ssl_dir, 'cert'), 'w') as cert_out:
506
 
            cert_out.write(b64decode(cert))
507
 
        with open(os.path.join(ssl_dir, 'key'), 'w') as key_out:
508
 
            key_out.write(b64decode(key))
 
558
        mkdir(path=ssl_dir)
 
559
        cert, key = get_cert(cn)
 
560
        if cn:
 
561
            cert_filename = 'cert_{}'.format(cn)
 
562
            key_filename = 'key_{}'.format(cn)
 
563
        else:
 
564
            cert_filename = 'cert'
 
565
            key_filename = 'key'
 
566
        write_file(path=os.path.join(ssl_dir, cert_filename),
 
567
                   content=b64decode(cert))
 
568
        write_file(path=os.path.join(ssl_dir, key_filename),
 
569
                   content=b64decode(key))
 
570
 
 
571
    def configure_ca(self):
509
572
        ca_cert = get_ca_cert()
510
573
        if ca_cert:
511
 
            with open(CA_CERT_PATH, 'w') as ca_out:
512
 
                ca_out.write(b64decode(ca_cert))
513
 
            check_call(['update-ca-certificates'])
 
574
            install_ca_cert(b64decode(ca_cert))
 
575
 
 
576
    def canonical_names(self):
 
577
        '''Figure out which canonical names clients will access this service'''
 
578
        cns = []
 
579
        for r_id in relation_ids('identity-service'):
 
580
            for unit in related_units(r_id):
 
581
                rdata = relation_get(rid=r_id, unit=unit)
 
582
                for k in rdata:
 
583
                    if k.startswith('ssl_key_'):
 
584
                        cns.append(k.lstrip('ssl_key_'))
 
585
        return list(set(cns))
514
586
 
515
587
    def __call__(self):
516
588
        if isinstance(self.external_ports, basestring):
518
590
        if (not self.external_ports or not https()):
519
591
            return {}
520
592
 
521
 
        self.configure_cert()
 
593
        self.configure_ca()
522
594
        self.enable_modules()
523
595
 
524
596
        ctxt = {
525
597
            'namespace': self.service_namespace,
526
 
            'private_address': unit_get('private-address'),
527
 
            'endpoints': []
 
598
            'endpoints': [],
 
599
            'ext_ports': []
528
600
        }
529
 
        if is_clustered():
530
 
            ctxt['private_address'] = config('vip')
531
 
        for api_port in self.external_ports:
532
 
            ext_port = determine_apache_port(api_port)
533
 
            int_port = determine_api_port(api_port)
534
 
            portmap = (int(ext_port), int(int_port))
535
 
            ctxt['endpoints'].append(portmap)
 
601
 
 
602
        for cn in self.canonical_names():
 
603
            self.configure_cert(cn)
 
604
 
 
605
        addresses = []
 
606
        vips = []
 
607
        if config('vip'):
 
608
            vips = config('vip').split()
 
609
 
 
610
        for network_type in ['os-internal-network',
 
611
                             'os-admin-network',
 
612
                             'os-public-network']:
 
613
            address = get_address_in_network(config(network_type),
 
614
                                             unit_get('private-address'))
 
615
            if len(vips) > 0 and is_clustered():
 
616
                for vip in vips:
 
617
                    if is_address_in_network(config(network_type),
 
618
                                             vip):
 
619
                        addresses.append((address, vip))
 
620
                        break
 
621
            elif is_clustered():
 
622
                addresses.append((address, config('vip')))
 
623
            else:
 
624
                addresses.append((address, address))
 
625
 
 
626
        for address, endpoint in set(addresses):
 
627
            for api_port in self.external_ports:
 
628
                ext_port = determine_apache_port(api_port)
 
629
                int_port = determine_api_port(api_port)
 
630
                portmap = (address, endpoint, int(ext_port), int(int_port))
 
631
                ctxt['endpoints'].append(portmap)
 
632
                ctxt['ext_ports'].append(int(ext_port))
 
633
        ctxt['ext_ports'] = list(set(ctxt['ext_ports']))
536
634
        return ctxt
537
635
 
538
636
 
662
760
 
663
761
class OSConfigFlagContext(OSContextGenerator):
664
762
 
665
 
        """
666
 
        Responsible for adding user-defined config-flags in charm config to a
667
 
        template context.
668
 
 
669
 
        NOTE: the value of config-flags may be a comma-separated list of
670
 
              key=value pairs and some Openstack config files support
671
 
              comma-separated lists as values.
672
 
        """
673
 
 
674
 
        def __call__(self):
675
 
            config_flags = config('config-flags')
676
 
            if not config_flags:
677
 
                return {}
678
 
 
679
 
            flags = config_flags_parser(config_flags)
680
 
            return {'user_config_flags': flags}
 
763
    """
 
764
    Responsible for adding user-defined config-flags in charm config to a
 
765
    template context.
 
766
 
 
767
    NOTE: the value of config-flags may be a comma-separated list of
 
768
          key=value pairs and some Openstack config files support
 
769
          comma-separated lists as values.
 
770
    """
 
771
 
 
772
    def __call__(self):
 
773
        config_flags = config('config-flags')
 
774
        if not config_flags:
 
775
            return {}
 
776
 
 
777
        flags = config_flags_parser(config_flags)
 
778
        return {'user_config_flags': flags}
681
779
 
682
780
 
683
781
class SubordinateConfigContext(OSContextGenerator):
792
890
            'use_syslog': config('use-syslog')
793
891
        }
794
892
        return ctxt
 
893
 
 
894
 
 
895
class BindHostContext(OSContextGenerator):
 
896
 
 
897
    def __call__(self):
 
898
        if config('prefer-ipv6'):
 
899
            return {
 
900
                'bind_host': '::'
 
901
            }
 
902
        else:
 
903
            return {
 
904
                'bind_host': '0.0.0.0'
 
905
            }
 
906
 
 
907
 
 
908
class WorkerConfigContext(OSContextGenerator):
 
909
 
 
910
    @property
 
911
    def num_cpus(self):
 
912
        try:
 
913
            from psutil import NUM_CPUS
 
914
        except ImportError:
 
915
            apt_install('python-psutil', fatal=True)
 
916
            from psutil import NUM_CPUS
 
917
        return NUM_CPUS
 
918
 
 
919
    def __call__(self):
 
920
        multiplier = config('worker-multiplier') or 1
 
921
        ctxt = {
 
922
            "workers": self.num_cpus * multiplier
 
923
        }
 
924
        return ctxt