~james-page/charms/trusty/swift-proxy/trunk

« back to all changes in this revision

Viewing changes to charmhelpers/contrib/openstack/neutron.py

  • Committer: Ryan Beisner
  • Date: 2016-01-19 12:47:49 UTC
  • mto: This revision was merged to the branch mainline in revision 135.
  • Revision ID: ryan.beisner@canonical.com-20160119124749-5uj102427wonbfmx
Fix typo in mitaka amulet test definition

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2014-2015 Canonical Limited.
2
 
#
3
 
# This file is part of charm-helpers.
4
 
#
5
 
# charm-helpers is free software: you can redistribute it and/or modify
6
 
# it under the terms of the GNU Lesser General Public License version 3 as
7
 
# published by the Free Software Foundation.
8
 
#
9
 
# charm-helpers is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU Lesser General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU Lesser General Public License
15
 
# along with charm-helpers.  If not, see <http://www.gnu.org/licenses/>.
16
 
 
17
 
# Various utilies for dealing with Neutron and the renaming from Quantum.
18
 
 
19
 
import six
20
 
from subprocess import check_output
21
 
 
22
 
from charmhelpers.core.hookenv import (
23
 
    config,
24
 
    log,
25
 
    ERROR,
26
 
)
27
 
 
28
 
from charmhelpers.contrib.openstack.utils import os_release
29
 
 
30
 
 
31
 
def headers_package():
32
 
    """Ensures correct linux-headers for running kernel are installed,
33
 
    for building DKMS package"""
34
 
    kver = check_output(['uname', '-r']).decode('UTF-8').strip()
35
 
    return 'linux-headers-%s' % kver
36
 
 
37
 
QUANTUM_CONF_DIR = '/etc/quantum'
38
 
 
39
 
 
40
 
def kernel_version():
41
 
    """ Retrieve the current major kernel version as a tuple e.g. (3, 13) """
42
 
    kver = check_output(['uname', '-r']).decode('UTF-8').strip()
43
 
    kver = kver.split('.')
44
 
    return (int(kver[0]), int(kver[1]))
45
 
 
46
 
 
47
 
def determine_dkms_package():
48
 
    """ Determine which DKMS package should be used based on kernel version """
49
 
    # NOTE: 3.13 kernels have support for GRE and VXLAN native
50
 
    if kernel_version() >= (3, 13):
51
 
        return []
52
 
    else:
53
 
        return ['openvswitch-datapath-dkms']
54
 
 
55
 
 
56
 
# legacy
57
 
 
58
 
 
59
 
def quantum_plugins():
60
 
    from charmhelpers.contrib.openstack import context
61
 
    return {
62
 
        'ovs': {
63
 
            'config': '/etc/quantum/plugins/openvswitch/'
64
 
                      'ovs_quantum_plugin.ini',
65
 
            'driver': 'quantum.plugins.openvswitch.ovs_quantum_plugin.'
66
 
                      'OVSQuantumPluginV2',
67
 
            'contexts': [
68
 
                context.SharedDBContext(user=config('neutron-database-user'),
69
 
                                        database=config('neutron-database'),
70
 
                                        relation_prefix='neutron',
71
 
                                        ssl_dir=QUANTUM_CONF_DIR)],
72
 
            'services': ['quantum-plugin-openvswitch-agent'],
73
 
            'packages': [[headers_package()] + determine_dkms_package(),
74
 
                         ['quantum-plugin-openvswitch-agent']],
75
 
            'server_packages': ['quantum-server',
76
 
                                'quantum-plugin-openvswitch'],
77
 
            'server_services': ['quantum-server']
78
 
        },
79
 
        'nvp': {
80
 
            'config': '/etc/quantum/plugins/nicira/nvp.ini',
81
 
            'driver': 'quantum.plugins.nicira.nicira_nvp_plugin.'
82
 
                      'QuantumPlugin.NvpPluginV2',
83
 
            'contexts': [
84
 
                context.SharedDBContext(user=config('neutron-database-user'),
85
 
                                        database=config('neutron-database'),
86
 
                                        relation_prefix='neutron',
87
 
                                        ssl_dir=QUANTUM_CONF_DIR)],
88
 
            'services': [],
89
 
            'packages': [],
90
 
            'server_packages': ['quantum-server',
91
 
                                'quantum-plugin-nicira'],
92
 
            'server_services': ['quantum-server']
93
 
        }
94
 
    }
95
 
 
96
 
NEUTRON_CONF_DIR = '/etc/neutron'
97
 
 
98
 
 
99
 
def neutron_plugins():
100
 
    from charmhelpers.contrib.openstack import context
101
 
    release = os_release('nova-common')
102
 
    plugins = {
103
 
        'ovs': {
104
 
            'config': '/etc/neutron/plugins/openvswitch/'
105
 
                      'ovs_neutron_plugin.ini',
106
 
            'driver': 'neutron.plugins.openvswitch.ovs_neutron_plugin.'
107
 
                      'OVSNeutronPluginV2',
108
 
            'contexts': [
109
 
                context.SharedDBContext(user=config('neutron-database-user'),
110
 
                                        database=config('neutron-database'),
111
 
                                        relation_prefix='neutron',
112
 
                                        ssl_dir=NEUTRON_CONF_DIR)],
113
 
            'services': ['neutron-plugin-openvswitch-agent'],
114
 
            'packages': [[headers_package()] + determine_dkms_package(),
115
 
                         ['neutron-plugin-openvswitch-agent']],
116
 
            'server_packages': ['neutron-server',
117
 
                                'neutron-plugin-openvswitch'],
118
 
            'server_services': ['neutron-server']
119
 
        },
120
 
        'nvp': {
121
 
            'config': '/etc/neutron/plugins/nicira/nvp.ini',
122
 
            'driver': 'neutron.plugins.nicira.nicira_nvp_plugin.'
123
 
                      'NeutronPlugin.NvpPluginV2',
124
 
            'contexts': [
125
 
                context.SharedDBContext(user=config('neutron-database-user'),
126
 
                                        database=config('neutron-database'),
127
 
                                        relation_prefix='neutron',
128
 
                                        ssl_dir=NEUTRON_CONF_DIR)],
129
 
            'services': [],
130
 
            'packages': [],
131
 
            'server_packages': ['neutron-server',
132
 
                                'neutron-plugin-nicira'],
133
 
            'server_services': ['neutron-server']
134
 
        },
135
 
        'nsx': {
136
 
            'config': '/etc/neutron/plugins/vmware/nsx.ini',
137
 
            'driver': 'vmware',
138
 
            'contexts': [
139
 
                context.SharedDBContext(user=config('neutron-database-user'),
140
 
                                        database=config('neutron-database'),
141
 
                                        relation_prefix='neutron',
142
 
                                        ssl_dir=NEUTRON_CONF_DIR)],
143
 
            'services': [],
144
 
            'packages': [],
145
 
            'server_packages': ['neutron-server',
146
 
                                'neutron-plugin-vmware'],
147
 
            'server_services': ['neutron-server']
148
 
        },
149
 
        'n1kv': {
150
 
            'config': '/etc/neutron/plugins/cisco/cisco_plugins.ini',
151
 
            'driver': 'neutron.plugins.cisco.network_plugin.PluginV2',
152
 
            'contexts': [
153
 
                context.SharedDBContext(user=config('neutron-database-user'),
154
 
                                        database=config('neutron-database'),
155
 
                                        relation_prefix='neutron',
156
 
                                        ssl_dir=NEUTRON_CONF_DIR)],
157
 
            'services': [],
158
 
            'packages': [[headers_package()] + determine_dkms_package(),
159
 
                         ['neutron-plugin-cisco']],
160
 
            'server_packages': ['neutron-server',
161
 
                                'neutron-plugin-cisco'],
162
 
            'server_services': ['neutron-server']
163
 
        },
164
 
        'Calico': {
165
 
            'config': '/etc/neutron/plugins/ml2/ml2_conf.ini',
166
 
            'driver': 'neutron.plugins.ml2.plugin.Ml2Plugin',
167
 
            'contexts': [
168
 
                context.SharedDBContext(user=config('neutron-database-user'),
169
 
                                        database=config('neutron-database'),
170
 
                                        relation_prefix='neutron',
171
 
                                        ssl_dir=NEUTRON_CONF_DIR)],
172
 
            'services': ['calico-felix',
173
 
                         'bird',
174
 
                         'neutron-dhcp-agent',
175
 
                         'nova-api-metadata',
176
 
                         'etcd'],
177
 
            'packages': [[headers_package()] + determine_dkms_package(),
178
 
                         ['calico-compute',
179
 
                          'bird',
180
 
                          'neutron-dhcp-agent',
181
 
                          'nova-api-metadata',
182
 
                          'etcd']],
183
 
            'server_packages': ['neutron-server', 'calico-control', 'etcd'],
184
 
            'server_services': ['neutron-server', 'etcd']
185
 
        },
186
 
        'vsp': {
187
 
            'config': '/etc/neutron/plugins/nuage/nuage_plugin.ini',
188
 
            'driver': 'neutron.plugins.nuage.plugin.NuagePlugin',
189
 
            'contexts': [
190
 
                context.SharedDBContext(user=config('neutron-database-user'),
191
 
                                        database=config('neutron-database'),
192
 
                                        relation_prefix='neutron',
193
 
                                        ssl_dir=NEUTRON_CONF_DIR)],
194
 
            'services': [],
195
 
            'packages': [],
196
 
            'server_packages': ['neutron-server', 'neutron-plugin-nuage'],
197
 
            'server_services': ['neutron-server']
198
 
        },
199
 
        'plumgrid': {
200
 
            'config': '/etc/neutron/plugins/plumgrid/plumgrid.ini',
201
 
            'driver': 'neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.NeutronPluginPLUMgridV2',
202
 
            'contexts': [
203
 
                context.SharedDBContext(user=config('database-user'),
204
 
                                        database=config('database'),
205
 
                                        ssl_dir=NEUTRON_CONF_DIR)],
206
 
            'services': [],
207
 
            'packages': ['plumgrid-lxc',
208
 
                         'iovisor-dkms'],
209
 
            'server_packages': ['neutron-server',
210
 
                                'neutron-plugin-plumgrid'],
211
 
            'server_services': ['neutron-server']
212
 
        },
213
 
        'midonet': {
214
 
            'config': '/etc/neutron/plugins/midonet/midonet.ini',
215
 
            'driver': 'midonet.neutron.plugin.MidonetPluginV2',
216
 
            'contexts': [
217
 
                context.SharedDBContext(user=config('neutron-database-user'),
218
 
                                        database=config('neutron-database'),
219
 
                                        relation_prefix='neutron',
220
 
                                        ssl_dir=NEUTRON_CONF_DIR)],
221
 
            'services': [],
222
 
            'packages': [[headers_package()] + determine_dkms_package()],
223
 
            'server_packages': ['neutron-server',
224
 
                                'python-neutron-plugin-midonet'],
225
 
            'server_services': ['neutron-server']
226
 
        }
227
 
    }
228
 
    if release >= 'icehouse':
229
 
        # NOTE: patch in ml2 plugin for icehouse onwards
230
 
        plugins['ovs']['config'] = '/etc/neutron/plugins/ml2/ml2_conf.ini'
231
 
        plugins['ovs']['driver'] = 'neutron.plugins.ml2.plugin.Ml2Plugin'
232
 
        plugins['ovs']['server_packages'] = ['neutron-server',
233
 
                                             'neutron-plugin-ml2']
234
 
        # NOTE: patch in vmware renames nvp->nsx for icehouse onwards
235
 
        plugins['nvp'] = plugins['nsx']
236
 
    return plugins
237
 
 
238
 
 
239
 
def neutron_plugin_attribute(plugin, attr, net_manager=None):
240
 
    manager = net_manager or network_manager()
241
 
    if manager == 'quantum':
242
 
        plugins = quantum_plugins()
243
 
    elif manager == 'neutron':
244
 
        plugins = neutron_plugins()
245
 
    else:
246
 
        log("Network manager '%s' does not support plugins." % (manager),
247
 
            level=ERROR)
248
 
        raise Exception
249
 
 
250
 
    try:
251
 
        _plugin = plugins[plugin]
252
 
    except KeyError:
253
 
        log('Unrecognised plugin for %s: %s' % (manager, plugin), level=ERROR)
254
 
        raise Exception
255
 
 
256
 
    try:
257
 
        return _plugin[attr]
258
 
    except KeyError:
259
 
        return None
260
 
 
261
 
 
262
 
def network_manager():
263
 
    '''
264
 
    Deals with the renaming of Quantum to Neutron in H and any situations
265
 
    that require compatability (eg, deploying H with network-manager=quantum,
266
 
    upgrading from G).
267
 
    '''
268
 
    release = os_release('nova-common')
269
 
    manager = config('network-manager').lower()
270
 
 
271
 
    if manager not in ['quantum', 'neutron']:
272
 
        return manager
273
 
 
274
 
    if release in ['essex']:
275
 
        # E does not support neutron
276
 
        log('Neutron networking not supported in Essex.', level=ERROR)
277
 
        raise Exception
278
 
    elif release in ['folsom', 'grizzly']:
279
 
        # neutron is named quantum in F and G
280
 
        return 'quantum'
281
 
    else:
282
 
        # ensure accurate naming for all releases post-H
283
 
        return 'neutron'
284
 
 
285
 
 
286
 
def parse_mappings(mappings, key_rvalue=False):
287
 
    """By default mappings are lvalue keyed.
288
 
 
289
 
    If key_rvalue is True, the mapping will be reversed to allow multiple
290
 
    configs for the same lvalue.
291
 
    """
292
 
    parsed = {}
293
 
    if mappings:
294
 
        mappings = mappings.split()
295
 
        for m in mappings:
296
 
            p = m.partition(':')
297
 
 
298
 
            if key_rvalue:
299
 
                key_index = 2
300
 
                val_index = 0
301
 
                # if there is no rvalue skip to next
302
 
                if not p[1]:
303
 
                    continue
304
 
            else:
305
 
                key_index = 0
306
 
                val_index = 2
307
 
 
308
 
            key = p[key_index].strip()
309
 
            parsed[key] = p[val_index].strip()
310
 
 
311
 
    return parsed
312
 
 
313
 
 
314
 
def parse_bridge_mappings(mappings):
315
 
    """Parse bridge mappings.
316
 
 
317
 
    Mappings must be a space-delimited list of provider:bridge mappings.
318
 
 
319
 
    Returns dict of the form {provider:bridge}.
320
 
    """
321
 
    return parse_mappings(mappings)
322
 
 
323
 
 
324
 
def parse_data_port_mappings(mappings, default_bridge='br-data'):
325
 
    """Parse data port mappings.
326
 
 
327
 
    Mappings must be a space-delimited list of bridge:port.
328
 
 
329
 
    Returns dict of the form {port:bridge} where ports may be mac addresses or
330
 
    interface names.
331
 
    """
332
 
 
333
 
    # NOTE(dosaboy): we use rvalue for key to allow multiple values to be
334
 
    # proposed for <port> since it may be a mac address which will differ
335
 
    # across units this allowing first-known-good to be chosen.
336
 
    _mappings = parse_mappings(mappings, key_rvalue=True)
337
 
    if not _mappings or list(_mappings.values()) == ['']:
338
 
        if not mappings:
339
 
            return {}
340
 
 
341
 
        # For backwards-compatibility we need to support port-only provided in
342
 
        # config.
343
 
        _mappings = {mappings.split()[0]: default_bridge}
344
 
 
345
 
    ports = _mappings.keys()
346
 
    if len(set(ports)) != len(ports):
347
 
        raise Exception("It is not allowed to have the same port configured "
348
 
                        "on more than one bridge")
349
 
 
350
 
    return _mappings
351
 
 
352
 
 
353
 
def parse_vlan_range_mappings(mappings):
354
 
    """Parse vlan range mappings.
355
 
 
356
 
    Mappings must be a space-delimited list of provider:start:end mappings.
357
 
 
358
 
    The start:end range is optional and may be omitted.
359
 
 
360
 
    Returns dict of the form {provider: (start, end)}.
361
 
    """
362
 
    _mappings = parse_mappings(mappings)
363
 
    if not _mappings:
364
 
        return {}
365
 
 
366
 
    mappings = {}
367
 
    for p, r in six.iteritems(_mappings):
368
 
        mappings[p] = tuple(r.split(':'))
369
 
 
370
 
    return mappings