~anton-skriptsov/charms/trusty/cinder-nexentaedge/trunk

« back to all changes in this revision

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

  • Committer: anton.skriptsov at nexenta
  • Date: 2015-11-12 19:21:10 UTC
  • Revision ID: anton.skriptsov@nexenta.com-20151112192110-y49mpvnvf3pp3xk1
initial

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