~openstack-charmers-archive/charms/precise/swift-storage/trunk

« back to all changes in this revision

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

  • Committer: Liam Young
  • Date: 2015-04-16 10:28:51 UTC
  • Revision ID: liam.young@canonical.com-20150416102851-9wk4lwq6cvlve6ls
[gnuoy,trivial] Pre-release charmhelper sync

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import json
18
18
import os
 
19
import re
19
20
import time
20
21
from base64 import b64decode
21
22
from subprocess import check_call
46
47
)
47
48
 
48
49
from charmhelpers.core.sysctl import create as sysctl_create
 
50
from charmhelpers.core.strutils import bool_from_string
49
51
 
50
52
from charmhelpers.core.host import (
 
53
    list_nics,
 
54
    get_nic_hwaddr,
51
55
    mkdir,
52
56
    write_file,
53
57
)
64
68
)
65
69
from charmhelpers.contrib.openstack.neutron import (
66
70
    neutron_plugin_attribute,
 
71
    parse_data_port_mappings,
 
72
)
 
73
from charmhelpers.contrib.openstack.ip import (
 
74
    resolve_address,
 
75
    INTERNAL,
67
76
)
68
77
from charmhelpers.contrib.network.ip import (
69
78
    get_address_in_network,
 
79
    get_ipv4_addr,
70
80
    get_ipv6_addr,
71
81
    get_netmask_for_address,
72
82
    format_ipv6_addr,
73
83
    is_address_in_network,
 
84
    is_bridge_member,
74
85
)
75
86
from charmhelpers.contrib.openstack.utils import get_host_ip
76
 
 
77
87
CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
78
88
ADDRESS_TYPES = ['admin', 'internal', 'public']
79
89
 
310
320
 
311
321
 
312
322
class IdentityServiceContext(OSContextGenerator):
313
 
    interfaces = ['identity-service']
314
323
 
315
 
    def __init__(self, service=None, service_user=None):
 
324
    def __init__(self, service=None, service_user=None, rel_name='identity-service'):
316
325
        self.service = service
317
326
        self.service_user = service_user
 
327
        self.rel_name = rel_name
 
328
        self.interfaces = [self.rel_name]
318
329
 
319
330
    def __call__(self):
320
 
        log('Generating template context for identity-service', level=DEBUG)
 
331
        log('Generating template context for ' + self.rel_name, level=DEBUG)
321
332
        ctxt = {}
322
333
 
323
334
        if self.service and self.service_user:
331
342
 
332
343
            ctxt['signing_dir'] = cachedir
333
344
 
334
 
        for rid in relation_ids('identity-service'):
 
345
        for rid in relation_ids(self.rel_name):
335
346
            for unit in related_units(rid):
336
347
                rdata = relation_get(rid=rid, unit=unit)
337
348
                serv_host = rdata.get('service_host')
727
738
                'endpoints': [],
728
739
                'ext_ports': []}
729
740
 
730
 
        for cn in self.canonical_names():
 
741
        cns = self.canonical_names()
 
742
        if cns:
 
743
            for cn in cns:
 
744
                self.configure_cert(cn)
 
745
        else:
 
746
            # Expect cert/key provided in config (currently assumed that ca
 
747
            # uses ip for cn)
 
748
            cn = resolve_address(endpoint_type=INTERNAL)
731
749
            self.configure_cert(cn)
732
750
 
733
751
        addresses = self.get_network_addresses()
790
808
 
791
809
        return ovs_ctxt
792
810
 
 
811
    def nuage_ctxt(self):
 
812
        driver = neutron_plugin_attribute(self.plugin, 'driver',
 
813
                                          self.network_manager)
 
814
        config = neutron_plugin_attribute(self.plugin, 'config',
 
815
                                          self.network_manager)
 
816
        nuage_ctxt = {'core_plugin': driver,
 
817
                      'neutron_plugin': 'vsp',
 
818
                      'neutron_security_groups': self.neutron_security_groups,
 
819
                      'local_ip': unit_private_ip(),
 
820
                      'config': config}
 
821
 
 
822
        return nuage_ctxt
 
823
 
793
824
    def nvp_ctxt(self):
794
825
        driver = neutron_plugin_attribute(self.plugin, 'driver',
795
826
                                          self.network_manager)
873
904
            ctxt.update(self.n1kv_ctxt())
874
905
        elif self.plugin == 'Calico':
875
906
            ctxt.update(self.calico_ctxt())
 
907
        elif self.plugin == 'vsp':
 
908
            ctxt.update(self.nuage_ctxt())
876
909
 
877
910
        alchemy_flags = config('neutron-alchemy-flags')
878
911
        if alchemy_flags:
883
916
        return ctxt
884
917
 
885
918
 
 
919
class NeutronPortContext(OSContextGenerator):
 
920
    NIC_PREFIXES = ['eth', 'bond']
 
921
 
 
922
    def resolve_ports(self, ports):
 
923
        """Resolve NICs not yet bound to bridge(s)
 
924
 
 
925
        If hwaddress provided then returns resolved hwaddress otherwise NIC.
 
926
        """
 
927
        if not ports:
 
928
            return None
 
929
 
 
930
        hwaddr_to_nic = {}
 
931
        hwaddr_to_ip = {}
 
932
        for nic in list_nics(self.NIC_PREFIXES):
 
933
            hwaddr = get_nic_hwaddr(nic)
 
934
            hwaddr_to_nic[hwaddr] = nic
 
935
            addresses = get_ipv4_addr(nic, fatal=False)
 
936
            addresses += get_ipv6_addr(iface=nic, fatal=False)
 
937
            hwaddr_to_ip[hwaddr] = addresses
 
938
 
 
939
        resolved = []
 
940
        mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I)
 
941
        for entry in ports:
 
942
            if re.match(mac_regex, entry):
 
943
                # NIC is in known NICs and does NOT hace an IP address
 
944
                if entry in hwaddr_to_nic and not hwaddr_to_ip[entry]:
 
945
                    # If the nic is part of a bridge then don't use it
 
946
                    if is_bridge_member(hwaddr_to_nic[entry]):
 
947
                        continue
 
948
 
 
949
                    # Entry is a MAC address for a valid interface that doesn't
 
950
                    # have an IP address assigned yet.
 
951
                    resolved.append(hwaddr_to_nic[entry])
 
952
            else:
 
953
                # If the passed entry is not a MAC address, assume it's a valid
 
954
                # interface, and that the user put it there on purpose (we can
 
955
                # trust it to be the real external network).
 
956
                resolved.append(entry)
 
957
 
 
958
        return resolved
 
959
 
 
960
 
886
961
class OSConfigFlagContext(OSContextGenerator):
887
962
    """Provides support for user-defined config flags.
888
963
 
1104
1179
            sysctl_create(sysctl_dict,
1105
1180
                          '/etc/sysctl.d/50-{0}.conf'.format(charm_name()))
1106
1181
        return {'sysctl': sysctl_dict}
 
1182
 
 
1183
 
 
1184
class NeutronAPIContext(OSContextGenerator):
 
1185
    '''
 
1186
    Inspects current neutron-plugin-api relation for neutron settings. Return
 
1187
    defaults if it is not present.
 
1188
    '''
 
1189
    interfaces = ['neutron-plugin-api']
 
1190
 
 
1191
    def __call__(self):
 
1192
        self.neutron_defaults = {
 
1193
            'l2_population': {
 
1194
                'rel_key': 'l2-population',
 
1195
                'default': False,
 
1196
            },
 
1197
            'overlay_network_type': {
 
1198
                'rel_key': 'overlay-network-type',
 
1199
                'default': 'gre',
 
1200
            },
 
1201
            'neutron_security_groups': {
 
1202
                'rel_key': 'neutron-security-groups',
 
1203
                'default': False,
 
1204
            },
 
1205
            'network_device_mtu': {
 
1206
                'rel_key': 'network-device-mtu',
 
1207
                'default': None,
 
1208
            },
 
1209
            'enable_dvr': {
 
1210
                'rel_key': 'enable-dvr',
 
1211
                'default': False,
 
1212
            },
 
1213
            'enable_l3ha': {
 
1214
                'rel_key': 'enable-l3ha',
 
1215
                'default': False,
 
1216
            },
 
1217
        }
 
1218
        ctxt = self.get_neutron_options({})
 
1219
        for rid in relation_ids('neutron-plugin-api'):
 
1220
            for unit in related_units(rid):
 
1221
                rdata = relation_get(rid=rid, unit=unit)
 
1222
                if 'l2-population' in rdata:
 
1223
                    ctxt.update(self.get_neutron_options(rdata))
 
1224
 
 
1225
        return ctxt
 
1226
 
 
1227
    def get_neutron_options(self, rdata):
 
1228
        settings = {}
 
1229
        for nkey in self.neutron_defaults.keys():
 
1230
            defv = self.neutron_defaults[nkey]['default']
 
1231
            rkey = self.neutron_defaults[nkey]['rel_key']
 
1232
            if rkey in rdata.keys():
 
1233
                if type(defv) is bool:
 
1234
                    settings[nkey] = bool_from_string(rdata[rkey])
 
1235
                else:
 
1236
                    settings[nkey] = rdata[rkey]
 
1237
            else:
 
1238
                settings[nkey] = defv
 
1239
        return settings
 
1240
 
 
1241
 
 
1242
class ExternalPortContext(NeutronPortContext):
 
1243
 
 
1244
    def __call__(self):
 
1245
        ctxt = {}
 
1246
        ports = config('ext-port')
 
1247
        if ports:
 
1248
            ports = [p.strip() for p in ports.split()]
 
1249
            ports = self.resolve_ports(ports)
 
1250
            if ports:
 
1251
                ctxt = {"ext_port": ports[0]}
 
1252
                napi_settings = NeutronAPIContext()()
 
1253
                mtu = napi_settings.get('network_device_mtu')
 
1254
                if mtu:
 
1255
                    ctxt['ext_port_mtu'] = mtu
 
1256
 
 
1257
        return ctxt
 
1258
 
 
1259
 
 
1260
class DataPortContext(NeutronPortContext):
 
1261
 
 
1262
    def __call__(self):
 
1263
        ports = config('data-port')
 
1264
        if ports:
 
1265
            portmap = parse_data_port_mappings(ports)
 
1266
            ports = portmap.values()
 
1267
            resolved = self.resolve_ports(ports)
 
1268
            normalized = {get_nic_hwaddr(port): port for port in resolved
 
1269
                          if port not in ports}
 
1270
            normalized.update({port: port for port in resolved
 
1271
                               if port in ports})
 
1272
            if resolved:
 
1273
                return {bridge: normalized[port] for bridge, port in
 
1274
                        six.iteritems(portmap) if port in normalized.keys()}
 
1275
 
 
1276
        return None
 
1277
 
 
1278
 
 
1279
class PhyNICMTUContext(DataPortContext):
 
1280
 
 
1281
    def __call__(self):
 
1282
        ctxt = {}
 
1283
        mappings = super(PhyNICMTUContext, self).__call__()
 
1284
        if mappings and mappings.values():
 
1285
            ports = mappings.values()
 
1286
            napi_settings = NeutronAPIContext()()
 
1287
            mtu = napi_settings.get('network_device_mtu')
 
1288
            if mtu:
 
1289
                ctxt["devs"] = '\\n'.join(ports)
 
1290
                ctxt['mtu'] = mtu
 
1291
 
 
1292
        return ctxt
 
1293
 
 
1294
 
 
1295
class NetworkServiceContext(OSContextGenerator):
 
1296
 
 
1297
    def __init__(self, rel_name='quantum-network-service'):
 
1298
        self.rel_name = rel_name
 
1299
        self.interfaces = [rel_name]
 
1300
 
 
1301
    def __call__(self):
 
1302
        for rid in relation_ids(self.rel_name):
 
1303
            for unit in related_units(rid):
 
1304
                rdata = relation_get(rid=rid, unit=unit)
 
1305
                ctxt = {
 
1306
                    'keystone_host': rdata.get('keystone_host'),
 
1307
                    'service_port': rdata.get('service_port'),
 
1308
                    'auth_port': rdata.get('auth_port'),
 
1309
                    'service_tenant': rdata.get('service_tenant'),
 
1310
                    'service_username': rdata.get('service_username'),
 
1311
                    'service_password': rdata.get('service_password'),
 
1312
                    'quantum_host': rdata.get('quantum_host'),
 
1313
                    'quantum_port': rdata.get('quantum_port'),
 
1314
                    'quantum_url': rdata.get('quantum_url'),
 
1315
                    'region': rdata.get('region'),
 
1316
                    'service_protocol':
 
1317
                    rdata.get('service_protocol') or 'http',
 
1318
                    'auth_protocol':
 
1319
                    rdata.get('auth_protocol') or 'http',
 
1320
                }
 
1321
                if context_complete(ctxt):
 
1322
                    return ctxt
 
1323
        return {}