~james-page/charms/trusty/neutron-openvswitch/lp1531102

« back to all changes in this revision

Viewing changes to hooks/neutron_ovs_context.py

Deploy from source

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import os
 
2
import uuid
1
3
from charmhelpers.core.hookenv import (
 
4
    config,
 
5
    relation_get,
2
6
    relation_ids,
3
7
    related_units,
4
 
    relation_get,
5
 
    config,
6
8
    unit_get,
7
9
)
8
 
from charmhelpers.core.strutils import bool_from_string
 
10
from charmhelpers.contrib.openstack.ip import resolve_address
9
11
from charmhelpers.contrib.openstack import context
10
 
from charmhelpers.core.host import (
11
 
    service_running,
12
 
    service_start,
13
 
    service_restart,
14
 
)
15
 
from charmhelpers.contrib.network.ovs import add_bridge, add_bridge_port
16
12
from charmhelpers.contrib.openstack.utils import get_host_ip
17
13
from charmhelpers.contrib.network.ip import get_address_in_network
 
14
from charmhelpers.contrib.openstack.context import (
 
15
    OSContextGenerator,
 
16
    NeutronAPIContext,
 
17
)
18
18
from charmhelpers.contrib.openstack.neutron import (
19
 
    parse_bridge_mappings,
20
 
    parse_data_port_mappings,
21
19
    parse_vlan_range_mappings,
22
20
)
23
 
from charmhelpers.core.host import (
24
 
    get_nic_hwaddr,
25
 
)
26
 
OVS_BRIDGE = 'br-int'
27
 
 
28
 
 
29
 
def _neutron_api_settings():
30
 
    '''
31
 
    Inspects current neutron-plugin relation
32
 
    '''
33
 
    neutron_settings = {
34
 
        'neutron_security_groups': False,
35
 
        'l2_population': True,
36
 
        'overlay_network_type': 'gre',
37
 
    }
38
 
 
39
 
    for rid in relation_ids('neutron-plugin-api'):
40
 
        for unit in related_units(rid):
41
 
            rdata = relation_get(rid=rid, unit=unit)
42
 
            if 'l2-population' in rdata:
43
 
                neutron_settings.update({
44
 
                    'l2_population': bool_from_string(rdata['l2-population']),
45
 
                    'overlay_network_type': rdata['overlay-network-type'],
46
 
                    'neutron_security_groups':
47
 
                        bool_from_string(rdata['neutron-security-groups'])
48
 
                })
49
 
 
50
 
            # Override with configuration if set to true
51
 
            if config('disable-security-groups'):
52
 
                neutron_settings['neutron_security_groups'] = False
53
 
 
54
 
            net_dev_mtu = rdata.get('network-device-mtu')
55
 
            if net_dev_mtu:
56
 
                neutron_settings['network_device_mtu'] = net_dev_mtu
57
 
 
58
 
    return neutron_settings
59
 
 
60
 
 
61
 
class DataPortContext(context.NeutronPortContext):
62
 
 
63
 
    def __call__(self):
64
 
        ports = config('data-port')
65
 
        if ports:
66
 
            portmap = parse_data_port_mappings(ports)
67
 
            ports = portmap.values()
68
 
            resolved = self.resolve_ports(ports)
69
 
            normalized = {get_nic_hwaddr(port): port for port in resolved
70
 
                          if port not in ports}
71
 
            normalized.update({port: port for port in resolved
72
 
                               if port in ports})
73
 
            if resolved:
74
 
                return {bridge: normalized[port] for bridge, port in
75
 
                        portmap.iteritems() if port in normalized.keys()}
76
 
 
77
 
        return None
78
21
 
79
22
 
80
23
class OVSPluginContext(context.NeutronContext):
90
33
 
91
34
    @property
92
35
    def neutron_security_groups(self):
93
 
        neutron_api_settings = _neutron_api_settings()
 
36
        if config('disable-security-groups'):
 
37
            return False
 
38
        neutron_api_settings = NeutronAPIContext()()
94
39
        return neutron_api_settings['neutron_security_groups']
95
40
 
96
 
    def _ensure_bridge(self):
97
 
        if not service_running('openvswitch-switch'):
98
 
            service_start('openvswitch-switch')
99
 
 
100
 
        add_bridge(OVS_BRIDGE)
101
 
 
102
 
        portmaps = DataPortContext()()
103
 
        bridgemaps = parse_bridge_mappings(config('bridge-mappings'))
104
 
        for provider, br in bridgemaps.iteritems():
105
 
            add_bridge(br)
106
 
 
107
 
            if not portmaps or br not in portmaps:
108
 
                continue
109
 
 
110
 
            add_bridge_port(br, portmaps[br], promisc=True)
111
 
 
112
 
        service_restart('os-charm-phy-nic-mtu')
113
 
 
114
41
    def ovs_ctxt(self):
115
42
        # In addition to generating config context, ensure the OVS service
116
43
        # is running and the OVS bridge exists. Also need to ensure
119
46
        if not ovs_ctxt:
120
47
            return {}
121
48
 
122
 
        self._ensure_bridge()
123
 
 
124
49
        conf = config()
125
50
        ovs_ctxt['local_ip'] = \
126
51
            get_address_in_network(config('os-data-network'),
127
52
                                   get_host_ip(unit_get('private-address')))
128
 
        neutron_api_settings = _neutron_api_settings()
 
53
        neutron_api_settings = NeutronAPIContext()()
129
54
        ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups
130
55
        ovs_ctxt['l2_population'] = neutron_api_settings['l2_population']
 
56
        ovs_ctxt['distributed_routing'] = neutron_api_settings['enable_dvr']
131
57
        ovs_ctxt['overlay_network_type'] = \
132
58
            neutron_api_settings['overlay_network_type']
133
59
        # TODO: We need to sort out the syslog and debug/verbose options as a
157
83
        return ovs_ctxt
158
84
 
159
85
 
160
 
class PhyNICMTUContext(DataPortContext):
161
 
    """Context used to apply settings to neutron data-port devices"""
 
86
class L3AgentContext(OSContextGenerator):
162
87
 
163
88
    def __call__(self):
 
89
        neutron_api_settings = NeutronAPIContext()()
164
90
        ctxt = {}
165
 
        mappings = super(PhyNICMTUContext, self).__call__()
166
 
        if mappings and mappings.values():
167
 
            ports = mappings.values()
168
 
            neutron_api_settings = _neutron_api_settings()
169
 
            mtu = neutron_api_settings.get('network_device_mtu')
170
 
            if mtu:
171
 
                ctxt['devs'] = '\\n'.join(ports)
172
 
                ctxt['mtu'] = mtu
173
 
 
 
91
        if neutron_api_settings['enable_dvr']:
 
92
            ctxt['agent_mode'] = 'dvr'
 
93
        else:
 
94
            ctxt['agent_mode'] = 'legacy'
 
95
        return ctxt
 
96
 
 
97
 
 
98
SHARED_SECRET = "/etc/neutron/secret.txt"
 
99
 
 
100
 
 
101
def get_shared_secret():
 
102
    secret = None
 
103
    if not os.path.exists(SHARED_SECRET):
 
104
        secret = str(uuid.uuid4())
 
105
        with open(SHARED_SECRET, 'w') as secret_file:
 
106
            secret_file.write(secret)
 
107
    else:
 
108
        with open(SHARED_SECRET, 'r') as secret_file:
 
109
            secret = secret_file.read().strip()
 
110
    return secret
 
111
 
 
112
 
 
113
class DVRSharedSecretContext(OSContextGenerator):
 
114
 
 
115
    def __call__(self):
 
116
        if NeutronAPIContext()()['enable_dvr']:
 
117
            ctxt = {
 
118
                'shared_secret': get_shared_secret(),
 
119
                'local_ip': resolve_address(),
 
120
            }
 
121
        else:
 
122
            ctxt = {}
 
123
        return ctxt
 
124
 
 
125
 
 
126
class APIIdentityServiceContext(context.IdentityServiceContext):
 
127
 
 
128
    def __init__(self):
 
129
        super(APIIdentityServiceContext,
 
130
              self).__init__(rel_name='neutron-plugin-api')
 
131
 
 
132
    def __call__(self):
 
133
        ctxt = super(APIIdentityServiceContext, self).__call__()
 
134
        if not ctxt:
 
135
            return
 
136
        for rid in relation_ids('neutron-plugin-api'):
 
137
            for unit in related_units(rid):
 
138
                rdata = relation_get(rid=rid, unit=unit)
 
139
                ctxt['region'] = rdata.get('region')
 
140
                if ctxt['region']:
 
141
                    return ctxt
174
142
        return ctxt