~ubuntu-branches/ubuntu/oneiric/nova/oneiric-updates

« back to all changes in this revision

Viewing changes to .pc/fqdn-in-local-hostname-of-ec2-metadata.patch/nova/network/manager.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Adam Gandelman, Chuck Short, Scott Moser
  • Date: 2011-09-27 14:56:59 UTC
  • Revision ID: package-import@ubuntu.com-20110927145659-rz5u0ldy09hvwzlg
Tags: 2011.3-0ubuntu3
[Adam Gandelman]
* debian/nova-common.postinst: Create 'nova' group, add user to it
  (LP: #856530)
* debian/nova.conf, debian/nova-compute.upstart.in: Move reference of
  nova-compute.conf from nova.conf to nova-compute's argv. (LP: #839796)

[Chuck Short]
* debian/patches/backport-recreate-gateway-using-dhcp.patch:
  Makes sure to recreate gateway for moved ip. (LP: #859587)
* debian/control: Update Vcs info.

[ Scott Moser ]
* debian/patches/fqdn-in-local-hostname-of-ec2-metadata.patch
  Make the 'local-hostname' in the EC2 Metadata service contain
  the domainname also. (LP: #854614)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
3
# Copyright 2010 United States Government as represented by the
 
4
# Administrator of the National Aeronautics and Space Administration.
 
5
# All Rights Reserved.
 
6
#
 
7
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 
8
#    not use this file except in compliance with the License. You may obtain
 
9
#    a copy of the License at
 
10
#
 
11
#         http://www.apache.org/licenses/LICENSE-2.0
 
12
#
 
13
#    Unless required by applicable law or agreed to in writing, software
 
14
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
15
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
16
#    License for the specific language governing permissions and limitations
 
17
#    under the License.
 
18
 
 
19
"""Network Hosts are responsible for allocating ips and setting up network.
 
20
 
 
21
There are multiple backend drivers that handle specific types of networking
 
22
topologies.  All of the network commands are issued to a subclass of
 
23
:class:`NetworkManager`.
 
24
 
 
25
**Related Flags**
 
26
 
 
27
:network_driver:  Driver to use for network creation
 
28
:flat_network_bridge:  Bridge device for simple network instances
 
29
:flat_interface:  FlatDhcp will bridge into this interface if set
 
30
:flat_network_dns:  Dns for simple network
 
31
:vlan_start:  First VLAN for private networks
 
32
:vpn_ip:  Public IP for the cloudpipe VPN servers
 
33
:vpn_start:  First Vpn port for private networks
 
34
:cnt_vpn_clients:  Number of addresses reserved for vpn clients
 
35
:network_size:  Number of addresses in each private subnet
 
36
:floating_range:  Floating IP address block
 
37
:fixed_range:  Fixed IP address block
 
38
:date_dhcp_on_disassociate:  Whether to update dhcp when fixed_ip
 
39
                             is disassociated
 
40
:fixed_ip_disassociate_timeout:  Seconds after which a deallocated ip
 
41
                                 is disassociated
 
42
:create_unique_mac_address_attempts:  Number of times to attempt creating
 
43
                                      a unique mac address
 
44
 
 
45
"""
 
46
 
 
47
import datetime
 
48
import itertools
 
49
import math
 
50
import netaddr
 
51
import socket
 
52
from eventlet import greenpool
 
53
 
 
54
from nova import context
 
55
from nova import db
 
56
from nova import exception
 
57
from nova import flags
 
58
from nova import ipv6
 
59
from nova import log as logging
 
60
from nova import manager
 
61
from nova import quota
 
62
from nova import utils
 
63
from nova import rpc
 
64
from nova.network import api as network_api
 
65
from nova.compute import api as compute_api
 
66
import random
 
67
 
 
68
 
 
69
LOG = logging.getLogger("nova.network.manager")
 
70
 
 
71
 
 
72
FLAGS = flags.FLAGS
 
73
flags.DEFINE_string('flat_network_bridge', None,
 
74
                    'Bridge for simple network instances')
 
75
flags.DEFINE_string('flat_network_dns', '8.8.4.4',
 
76
                    'Dns for simple network')
 
77
flags.DEFINE_bool('flat_injected', False,
 
78
                  'Whether to attempt to inject network setup into guest')
 
79
flags.DEFINE_string('flat_interface', None,
 
80
                    'FlatDhcp will bridge into this interface if set')
 
81
flags.DEFINE_integer('vlan_start', 100, 'First VLAN for private networks')
 
82
flags.DEFINE_string('vlan_interface', None,
 
83
                    'vlans will bridge into this interface if set')
 
84
flags.DEFINE_integer('num_networks', 1, 'Number of networks to support')
 
85
flags.DEFINE_string('vpn_ip', '$my_ip',
 
86
                    'Public IP for the cloudpipe VPN servers')
 
87
flags.DEFINE_integer('vpn_start', 1000, 'First Vpn port for private networks')
 
88
flags.DEFINE_bool('multi_host', False,
 
89
                  'Default value for multi_host in networks')
 
90
flags.DEFINE_integer('network_size', 256,
 
91
                        'Number of addresses in each private subnet')
 
92
flags.DEFINE_string('floating_range', '4.4.4.0/24',
 
93
                    'Floating IP address block')
 
94
flags.DEFINE_string('fixed_range', '10.0.0.0/8', 'Fixed IP address block')
 
95
flags.DEFINE_string('fixed_range_v6', 'fd00::/48', 'Fixed IPv6 address block')
 
96
flags.DEFINE_string('gateway_v6', None, 'Default IPv6 gateway')
 
97
flags.DEFINE_integer('cnt_vpn_clients', 0,
 
98
                     'Number of addresses reserved for vpn clients')
 
99
flags.DEFINE_string('network_driver', 'nova.network.linux_net',
 
100
                    'Driver to use for network creation')
 
101
flags.DEFINE_bool('update_dhcp_on_disassociate', False,
 
102
                  'Whether to update dhcp when fixed_ip is disassociated')
 
103
flags.DEFINE_integer('fixed_ip_disassociate_timeout', 600,
 
104
                     'Seconds after which a deallocated ip is disassociated')
 
105
flags.DEFINE_integer('create_unique_mac_address_attempts', 5,
 
106
                     'Number of attempts to create unique mac address')
 
107
flags.DEFINE_bool('auto_assign_floating_ip', False,
 
108
                  'Autoassigning floating ip to VM')
 
109
flags.DEFINE_string('network_host', socket.gethostname(),
 
110
                    'Network host to use for ip allocation in flat modes')
 
111
flags.DEFINE_bool('fake_call', False,
 
112
                  'If True, skip using the queue and make local calls')
 
113
flags.DEFINE_bool('force_dhcp_release', False,
 
114
                  'If True, send a dhcp release on instance termination')
 
115
 
 
116
 
 
117
class AddressAlreadyAllocated(exception.Error):
 
118
    """Address was already allocated."""
 
119
    pass
 
120
 
 
121
 
 
122
class RPCAllocateFixedIP(object):
 
123
    """Mixin class originally for FlatDCHP and VLAN network managers.
 
124
 
 
125
    used since they share code to RPC.call allocate_fixed_ip on the
 
126
    correct network host to configure dnsmasq
 
127
    """
 
128
    def _allocate_fixed_ips(self, context, instance_id, host, networks,
 
129
                            **kwargs):
 
130
        """Calls allocate_fixed_ip once for each network."""
 
131
        green_pool = greenpool.GreenPool()
 
132
 
 
133
        vpn = kwargs.get('vpn')
 
134
        requested_networks = kwargs.get('requested_networks')
 
135
 
 
136
        for network in networks:
 
137
            address = None
 
138
            if requested_networks is not None:
 
139
                for address in (fixed_ip for (uuid, fixed_ip) in \
 
140
                              requested_networks if network['uuid'] == uuid):
 
141
                    break
 
142
 
 
143
            # NOTE(vish): if we are not multi_host pass to the network host
 
144
            if not network['multi_host']:
 
145
                host = network['host']
 
146
            # NOTE(vish): if there is no network host, set one
 
147
            if host == None:
 
148
                host = rpc.call(context, FLAGS.network_topic,
 
149
                                {'method': 'set_network_host',
 
150
                                 'args': {'network_ref': network}})
 
151
            if host != self.host:
 
152
                # need to call allocate_fixed_ip to correct network host
 
153
                topic = self.db.queue_get_for(context,
 
154
                                              FLAGS.network_topic,
 
155
                                              host)
 
156
                args = {}
 
157
                args['instance_id'] = instance_id
 
158
                args['network_id'] = network['id']
 
159
                args['address'] = address
 
160
                args['vpn'] = vpn
 
161
 
 
162
                green_pool.spawn_n(rpc.call, context, topic,
 
163
                                   {'method': '_rpc_allocate_fixed_ip',
 
164
                                    'args': args})
 
165
            else:
 
166
                # i am the correct host, run here
 
167
                self.allocate_fixed_ip(context, instance_id, network,
 
168
                                       vpn=vpn, address=address)
 
169
 
 
170
        # wait for all of the allocates (if any) to finish
 
171
        green_pool.waitall()
 
172
 
 
173
    def _rpc_allocate_fixed_ip(self, context, instance_id, network_id,
 
174
                               **kwargs):
 
175
        """Sits in between _allocate_fixed_ips and allocate_fixed_ip to
 
176
        perform network lookup on the far side of rpc.
 
177
        """
 
178
        network = self.db.network_get(context, network_id)
 
179
        self.allocate_fixed_ip(context, instance_id, network, **kwargs)
 
180
 
 
181
 
 
182
class FloatingIP(object):
 
183
    """Mixin class for adding floating IP functionality to a manager."""
 
184
    def init_host_floating_ips(self):
 
185
        """Configures floating ips owned by host."""
 
186
 
 
187
        admin_context = context.get_admin_context()
 
188
        try:
 
189
            floating_ips = self.db.floating_ip_get_all_by_host(admin_context,
 
190
                                                               self.host)
 
191
        except exception.NotFound:
 
192
            return
 
193
 
 
194
        for floating_ip in floating_ips:
 
195
            if floating_ip.get('fixed_ip', None):
 
196
                fixed_address = floating_ip['fixed_ip']['address']
 
197
                # NOTE(vish): The False here is because we ignore the case
 
198
                #             that the ip is already bound.
 
199
                self.driver.bind_floating_ip(floating_ip['address'], False)
 
200
                self.driver.ensure_floating_forward(floating_ip['address'],
 
201
                                                    fixed_address)
 
202
 
 
203
    def allocate_for_instance(self, context, **kwargs):
 
204
        """Handles allocating the floating IP resources for an instance.
 
205
 
 
206
        calls super class allocate_for_instance() as well
 
207
 
 
208
        rpc.called by network_api
 
209
        """
 
210
        instance_id = kwargs.get('instance_id')
 
211
        project_id = kwargs.get('project_id')
 
212
        requested_networks = kwargs.get('requested_networks')
 
213
        LOG.debug(_("floating IP allocation for instance |%s|"), instance_id,
 
214
                                                               context=context)
 
215
        # call the next inherited class's allocate_for_instance()
 
216
        # which is currently the NetworkManager version
 
217
        # do this first so fixed ip is already allocated
 
218
        ips = super(FloatingIP, self).allocate_for_instance(context, **kwargs)
 
219
        if FLAGS.auto_assign_floating_ip:
 
220
            # allocate a floating ip (public_ip is just the address string)
 
221
            public_ip = self.allocate_floating_ip(context, project_id)
 
222
            # set auto_assigned column to true for the floating ip
 
223
            self.db.floating_ip_set_auto_assigned(context, public_ip)
 
224
            # get the floating ip object from public_ip string
 
225
            floating_ip = self.db.floating_ip_get_by_address(context,
 
226
                                                             public_ip)
 
227
 
 
228
            # get the first fixed_ip belonging to the instance
 
229
            fixed_ips = self.db.fixed_ip_get_by_instance(context, instance_id)
 
230
            fixed_ip = fixed_ips[0] if fixed_ips else None
 
231
 
 
232
            # call to correct network host to associate the floating ip
 
233
            self.network_api.associate_floating_ip(context,
 
234
                                              floating_ip,
 
235
                                              fixed_ip,
 
236
                                              affect_auto_assigned=True)
 
237
        return ips
 
238
 
 
239
    def deallocate_for_instance(self, context, **kwargs):
 
240
        """Handles deallocating floating IP resources for an instance.
 
241
 
 
242
        calls super class deallocate_for_instance() as well.
 
243
 
 
244
        rpc.called by network_api
 
245
        """
 
246
        instance_id = kwargs.get('instance_id')
 
247
        LOG.debug(_("floating IP deallocation for instance |%s|"), instance_id,
 
248
                                                               context=context)
 
249
 
 
250
        fixed_ips = self.db.fixed_ip_get_by_instance(context, instance_id)
 
251
        # add to kwargs so we can pass to super to save a db lookup there
 
252
        kwargs['fixed_ips'] = fixed_ips
 
253
        for fixed_ip in fixed_ips:
 
254
            # disassociate floating ips related to fixed_ip
 
255
            for floating_ip in fixed_ip.floating_ips:
 
256
                address = floating_ip['address']
 
257
                self.network_api.disassociate_floating_ip(context, address)
 
258
                # deallocate if auto_assigned
 
259
                if floating_ip['auto_assigned']:
 
260
                    self.network_api.release_floating_ip(context,
 
261
                                                         address,
 
262
                                                         True)
 
263
 
 
264
        # call the next inherited class's deallocate_for_instance()
 
265
        # which is currently the NetworkManager version
 
266
        # call this after so floating IPs are handled first
 
267
        super(FloatingIP, self).deallocate_for_instance(context, **kwargs)
 
268
 
 
269
    def allocate_floating_ip(self, context, project_id):
 
270
        """Gets an floating ip from the pool."""
 
271
        # NOTE(tr3buchet): all networks hosts in zone now use the same pool
 
272
        LOG.debug("QUOTA: %s" % quota.allowed_floating_ips(context, 1))
 
273
        if quota.allowed_floating_ips(context, 1) < 1:
 
274
            LOG.warn(_('Quota exceeded for %s, tried to allocate '
 
275
                       'address'),
 
276
                     context.project_id)
 
277
            raise quota.QuotaError(_('Address quota exceeded. You cannot '
 
278
                                     'allocate any more addresses'))
 
279
        # TODO(vish): add floating ips through manage command
 
280
        return self.db.floating_ip_allocate_address(context,
 
281
                                                    project_id)
 
282
 
 
283
    def associate_floating_ip(self, context, floating_address, fixed_address):
 
284
        """Associates an floating ip to a fixed ip."""
 
285
        floating_ip = self.db.floating_ip_get_by_address(context,
 
286
                                                         floating_address)
 
287
        if floating_ip['fixed_ip']:
 
288
            raise exception.FloatingIpAlreadyInUse(
 
289
                            address=floating_ip['address'],
 
290
                            fixed_ip=floating_ip['fixed_ip']['address'])
 
291
 
 
292
        self.db.floating_ip_fixed_ip_associate(context,
 
293
                                               floating_address,
 
294
                                               fixed_address,
 
295
                                               self.host)
 
296
        self.driver.bind_floating_ip(floating_address)
 
297
        self.driver.ensure_floating_forward(floating_address, fixed_address)
 
298
 
 
299
    def disassociate_floating_ip(self, context, floating_address):
 
300
        """Disassociates a floating ip."""
 
301
        fixed_address = self.db.floating_ip_disassociate(context,
 
302
                                                         floating_address)
 
303
        self.driver.unbind_floating_ip(floating_address)
 
304
        self.driver.remove_floating_forward(floating_address, fixed_address)
 
305
 
 
306
    def deallocate_floating_ip(self, context, floating_address):
 
307
        """Returns an floating ip to the pool."""
 
308
        self.db.floating_ip_deallocate(context, floating_address)
 
309
 
 
310
 
 
311
class NetworkManager(manager.SchedulerDependentManager):
 
312
    """Implements common network manager functionality.
 
313
 
 
314
    This class must be subclassed to support specific topologies.
 
315
 
 
316
    host management:
 
317
        hosts configure themselves for networks they are assigned to in the
 
318
        table upon startup. If there are networks in the table which do not
 
319
        have hosts, those will be filled in and have hosts configured
 
320
        as the hosts pick them up one at time during their periodic task.
 
321
        The one at a time part is to flatten the layout to help scale
 
322
    """
 
323
 
 
324
    # If True, this manager requires VIF to create a bridge.
 
325
    SHOULD_CREATE_BRIDGE = False
 
326
 
 
327
    # If True, this manager requires VIF to create VLAN tag.
 
328
    SHOULD_CREATE_VLAN = False
 
329
 
 
330
    timeout_fixed_ips = True
 
331
 
 
332
    def __init__(self, network_driver=None, *args, **kwargs):
 
333
        if not network_driver:
 
334
            network_driver = FLAGS.network_driver
 
335
        self.driver = utils.import_object(network_driver)
 
336
        self.network_api = network_api.API()
 
337
        self.compute_api = compute_api.API()
 
338
        super(NetworkManager, self).__init__(service_name='network',
 
339
                                                *args, **kwargs)
 
340
 
 
341
    @utils.synchronized('get_dhcp')
 
342
    def _get_dhcp_ip(self, context, network_ref, host=None):
 
343
        """Get the proper dhcp address to listen on."""
 
344
        # NOTE(vish): this is for compatibility
 
345
        if not network_ref['multi_host']:
 
346
            return network_ref['gateway']
 
347
 
 
348
        if not host:
 
349
            host = self.host
 
350
        network_id = network_ref['id']
 
351
        try:
 
352
            fip = self.db.fixed_ip_get_by_network_host(context,
 
353
                                                       network_id,
 
354
                                                       host)
 
355
            return fip['address']
 
356
        except exception.FixedIpNotFoundForNetworkHost:
 
357
            elevated = context.elevated()
 
358
            return self.db.fixed_ip_associate_pool(elevated,
 
359
                                                   network_id,
 
360
                                                   host=host)
 
361
 
 
362
    def init_host(self):
 
363
        """Do any initialization that needs to be run if this is a
 
364
        standalone service.
 
365
        """
 
366
        # NOTE(vish): Set up networks for which this host already has
 
367
        #             an ip address.
 
368
        ctxt = context.get_admin_context()
 
369
        for network in self.db.network_get_all_by_host(ctxt, self.host):
 
370
            self._setup_network(ctxt, network)
 
371
 
 
372
    def periodic_tasks(self, context=None):
 
373
        """Tasks to be run at a periodic interval."""
 
374
        super(NetworkManager, self).periodic_tasks(context)
 
375
        if self.timeout_fixed_ips:
 
376
            now = utils.utcnow()
 
377
            timeout = FLAGS.fixed_ip_disassociate_timeout
 
378
            time = now - datetime.timedelta(seconds=timeout)
 
379
            num = self.db.fixed_ip_disassociate_all_by_timeout(context,
 
380
                                                               self.host,
 
381
                                                               time)
 
382
            if num:
 
383
                LOG.debug(_('Dissassociated %s stale fixed ip(s)'), num)
 
384
 
 
385
    def set_network_host(self, context, network_ref):
 
386
        """Safely sets the host of the network."""
 
387
        LOG.debug(_('setting network host'), context=context)
 
388
        host = self.db.network_set_host(context,
 
389
                                        network_ref['id'],
 
390
                                        self.host)
 
391
        return host
 
392
 
 
393
    def _do_trigger_security_group_members_refresh_for_instance(self,
 
394
                                                                instance_id):
 
395
        admin_context = context.get_admin_context()
 
396
        instance_ref = self.db.instance_get(admin_context, instance_id)
 
397
        groups = instance_ref['security_groups']
 
398
        group_ids = [group['id'] for group in groups]
 
399
        self.compute_api.trigger_security_group_members_refresh(admin_context,
 
400
                                                                    group_ids)
 
401
 
 
402
    def _get_networks_for_instance(self, context, instance_id, project_id,
 
403
                                   requested_networks=None):
 
404
        """Determine & return which networks an instance should connect to."""
 
405
        # TODO(tr3buchet) maybe this needs to be updated in the future if
 
406
        #                 there is a better way to determine which networks
 
407
        #                 a non-vlan instance should connect to
 
408
        if requested_networks is not None and len(requested_networks) != 0:
 
409
            network_uuids = [uuid for (uuid, fixed_ip) in requested_networks]
 
410
            networks = self.db.network_get_all_by_uuids(context,
 
411
                                                    network_uuids)
 
412
        else:
 
413
            try:
 
414
                networks = self.db.network_get_all(context)
 
415
            except exception.NoNetworksFound:
 
416
                return []
 
417
        # return only networks which are not vlan networks
 
418
        return [network for network in networks if
 
419
                not network['vlan']]
 
420
 
 
421
    def allocate_for_instance(self, context, **kwargs):
 
422
        """Handles allocating the various network resources for an instance.
 
423
 
 
424
        rpc.called by network_api
 
425
        """
 
426
        instance_id = kwargs.pop('instance_id')
 
427
        host = kwargs.pop('host')
 
428
        project_id = kwargs.pop('project_id')
 
429
        type_id = kwargs.pop('instance_type_id')
 
430
        requested_networks = kwargs.get('requested_networks')
 
431
        vpn = kwargs.pop('vpn')
 
432
        admin_context = context.elevated()
 
433
        LOG.debug(_("network allocations for instance %s"), instance_id,
 
434
                                                            context=context)
 
435
        networks = self._get_networks_for_instance(admin_context,
 
436
                                        instance_id, project_id,
 
437
                                        requested_networks=requested_networks)
 
438
        self._allocate_mac_addresses(context, instance_id, networks)
 
439
        self._allocate_fixed_ips(admin_context, instance_id,
 
440
                                 host, networks, vpn=vpn,
 
441
                                 requested_networks=requested_networks)
 
442
        return self.get_instance_nw_info(context, instance_id, type_id, host)
 
443
 
 
444
    def deallocate_for_instance(self, context, **kwargs):
 
445
        """Handles deallocating various network resources for an instance.
 
446
 
 
447
        rpc.called by network_api
 
448
        kwargs can contain fixed_ips to circumvent another db lookup
 
449
        """
 
450
        instance_id = kwargs.pop('instance_id')
 
451
        try:
 
452
            fixed_ips = kwargs.get('fixed_ips') or \
 
453
                  self.db.fixed_ip_get_by_instance(context, instance_id)
 
454
        except exception.FixedIpNotFoundForInstance:
 
455
            fixed_ips = []
 
456
        LOG.debug(_("network deallocation for instance |%s|"), instance_id,
 
457
                                                               context=context)
 
458
        # deallocate fixed ips
 
459
        for fixed_ip in fixed_ips:
 
460
            self.deallocate_fixed_ip(context, fixed_ip['address'], **kwargs)
 
461
 
 
462
        # deallocate vifs (mac addresses)
 
463
        self.db.virtual_interface_delete_by_instance(context, instance_id)
 
464
 
 
465
    def get_instance_nw_info(self, context, instance_id,
 
466
                             instance_type_id, host):
 
467
        """Creates network info list for instance.
 
468
 
 
469
        called by allocate_for_instance and netowrk_api
 
470
        context needs to be elevated
 
471
        :returns: network info list [(network,info),(network,info)...]
 
472
        where network = dict containing pertinent data from a network db object
 
473
        and info = dict containing pertinent networking data
 
474
        """
 
475
        # TODO(tr3buchet) should handle floating IPs as well?
 
476
        try:
 
477
            fixed_ips = self.db.fixed_ip_get_by_instance(context, instance_id)
 
478
        except exception.FixedIpNotFoundForInstance:
 
479
            LOG.warn(_('No fixed IPs for instance %s'), instance_id)
 
480
            fixed_ips = []
 
481
 
 
482
        vifs = self.db.virtual_interface_get_by_instance(context, instance_id)
 
483
        flavor = self.db.instance_type_get(context, instance_type_id)
 
484
        network_info = []
 
485
        # a vif has an address, instance_id, and network_id
 
486
        # it is also joined to the instance and network given by those IDs
 
487
        for vif in vifs:
 
488
            network = vif['network']
 
489
 
 
490
            if network is None:
 
491
                continue
 
492
 
 
493
            # determine which of the instance's IPs belong to this network
 
494
            network_IPs = [fixed_ip['address'] for fixed_ip in fixed_ips if
 
495
                           fixed_ip['network_id'] == network['id']]
 
496
 
 
497
            # TODO(tr3buchet) eventually "enabled" should be determined
 
498
            def ip_dict(ip):
 
499
                return {
 
500
                    'ip': ip,
 
501
                    'netmask': network['netmask'],
 
502
                    'enabled': '1'}
 
503
 
 
504
            def ip6_dict():
 
505
                return {
 
506
                    'ip': ipv6.to_global(network['cidr_v6'],
 
507
                                         vif['address'],
 
508
                                         network['project_id']),
 
509
                    'netmask': network['netmask_v6'],
 
510
                    'enabled': '1'}
 
511
            network_dict = {
 
512
                'bridge': network['bridge'],
 
513
                'id': network['id'],
 
514
                'cidr': network['cidr'],
 
515
                'cidr_v6': network['cidr_v6'],
 
516
                'injected': network['injected'],
 
517
                'vlan': network['vlan'],
 
518
                'bridge_interface': network['bridge_interface'],
 
519
                'multi_host': network['multi_host']}
 
520
            if network['multi_host']:
 
521
                dhcp_server = self._get_dhcp_ip(context, network, host)
 
522
            else:
 
523
                dhcp_server = self._get_dhcp_ip(context,
 
524
                                                network,
 
525
                                                network['host'])
 
526
            info = {
 
527
                'label': network['label'],
 
528
                'gateway': network['gateway'],
 
529
                'dhcp_server': dhcp_server,
 
530
                'broadcast': network['broadcast'],
 
531
                'mac': vif['address'],
 
532
                'vif_uuid': vif['uuid'],
 
533
                'rxtx_cap': flavor['rxtx_cap'],
 
534
                'dns': [],
 
535
                'ips': [ip_dict(ip) for ip in network_IPs],
 
536
                'should_create_bridge': self.SHOULD_CREATE_BRIDGE,
 
537
                'should_create_vlan': self.SHOULD_CREATE_VLAN}
 
538
 
 
539
            if network['cidr_v6']:
 
540
                info['ip6s'] = [ip6_dict()]
 
541
            # TODO(tr3buchet): handle ip6 routes here as well
 
542
            if network['gateway_v6']:
 
543
                info['gateway6'] = network['gateway_v6']
 
544
            if network['dns1']:
 
545
                info['dns'].append(network['dns1'])
 
546
            if network['dns2']:
 
547
                info['dns'].append(network['dns2'])
 
548
 
 
549
            network_info.append((network_dict, info))
 
550
        return network_info
 
551
 
 
552
    def _allocate_mac_addresses(self, context, instance_id, networks):
 
553
        """Generates mac addresses and creates vif rows in db for them."""
 
554
        for network in networks:
 
555
            self.add_virtual_interface(context, instance_id, network['id'])
 
556
 
 
557
    def add_virtual_interface(self, context, instance_id, network_id):
 
558
        vif = {'address': self.generate_mac_address(),
 
559
                   'instance_id': instance_id,
 
560
                   'network_id': network_id,
 
561
                   'uuid': str(utils.gen_uuid())}
 
562
        # try FLAG times to create a vif record with a unique mac_address
 
563
        for _ in xrange(FLAGS.create_unique_mac_address_attempts):
 
564
            try:
 
565
                return self.db.virtual_interface_create(context, vif)
 
566
            except exception.VirtualInterfaceCreateException:
 
567
                vif['address'] = self.generate_mac_address()
 
568
        else:
 
569
            self.db.virtual_interface_delete_by_instance(context,
 
570
                                                             instance_id)
 
571
            raise exception.VirtualInterfaceMacAddressException()
 
572
 
 
573
    def generate_mac_address(self):
 
574
        """Generate an Ethernet MAC address."""
 
575
        mac = [0x02, 0x16, 0x3e,
 
576
               random.randint(0x00, 0x7f),
 
577
               random.randint(0x00, 0xff),
 
578
               random.randint(0x00, 0xff)]
 
579
        return ':'.join(map(lambda x: "%02x" % x, mac))
 
580
 
 
581
    def add_fixed_ip_to_instance(self, context, instance_id, host, network_id):
 
582
        """Adds a fixed ip to an instance from specified network."""
 
583
        networks = [self.db.network_get(context, network_id)]
 
584
        self._allocate_fixed_ips(context, instance_id, host, networks)
 
585
 
 
586
    def remove_fixed_ip_from_instance(self, context, instance_id, address):
 
587
        """Removes a fixed ip from an instance from specified network."""
 
588
        fixed_ips = self.db.fixed_ip_get_by_instance(context, instance_id)
 
589
        for fixed_ip in fixed_ips:
 
590
            if fixed_ip['address'] == address:
 
591
                self.deallocate_fixed_ip(context, address)
 
592
                return
 
593
        raise exception.FixedIpNotFoundForSpecificInstance(
 
594
                                    instance_id=instance_id, ip=address)
 
595
 
 
596
    def allocate_fixed_ip(self, context, instance_id, network, **kwargs):
 
597
        """Gets a fixed ip from the pool."""
 
598
        # TODO(vish): when this is called by compute, we can associate compute
 
599
        #             with a network, or a cluster of computes with a network
 
600
        #             and use that network here with a method like
 
601
        #             network_get_by_compute_host
 
602
        address = None
 
603
        if network['cidr']:
 
604
            address = kwargs.get('address', None)
 
605
            if address:
 
606
                address = self.db.fixed_ip_associate(context,
 
607
                                                     address, instance_id,
 
608
                                                     network['id'])
 
609
            else:
 
610
                address = self.db.fixed_ip_associate_pool(context.elevated(),
 
611
                                                          network['id'],
 
612
                                                          instance_id)
 
613
            self._do_trigger_security_group_members_refresh_for_instance(
 
614
                                                                   instance_id)
 
615
            get_vif = self.db.virtual_interface_get_by_instance_and_network
 
616
            vif = get_vif(context, instance_id, network['id'])
 
617
            values = {'allocated': True,
 
618
                      'virtual_interface_id': vif['id']}
 
619
            self.db.fixed_ip_update(context, address, values)
 
620
 
 
621
        self._setup_network(context, network)
 
622
        return address
 
623
 
 
624
    def deallocate_fixed_ip(self, context, address, **kwargs):
 
625
        """Returns a fixed ip to the pool."""
 
626
        self.db.fixed_ip_update(context, address,
 
627
                                {'allocated': False,
 
628
                                 'virtual_interface_id': None})
 
629
        fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address)
 
630
        instance_ref = fixed_ip_ref['instance']
 
631
        instance_id = instance_ref['id']
 
632
        self._do_trigger_security_group_members_refresh_for_instance(
 
633
                                                                   instance_id)
 
634
        if FLAGS.force_dhcp_release:
 
635
            dev = self.driver.get_dev(fixed_ip_ref['network'])
 
636
            vif = self.db.virtual_interface_get_by_instance_and_network(
 
637
                    context, instance_ref['id'], fixed_ip_ref['network']['id'])
 
638
            self.driver.release_dhcp(dev, address, vif['address'])
 
639
 
 
640
    def lease_fixed_ip(self, context, address):
 
641
        """Called by dhcp-bridge when ip is leased."""
 
642
        LOG.debug(_('Leased IP |%(address)s|'), locals(), context=context)
 
643
        fixed_ip = self.db.fixed_ip_get_by_address(context, address)
 
644
        instance = fixed_ip['instance']
 
645
        if not instance:
 
646
            raise exception.Error(_('IP %s leased that is not associated') %
 
647
                                  address)
 
648
        now = utils.utcnow()
 
649
        self.db.fixed_ip_update(context,
 
650
                                fixed_ip['address'],
 
651
                                {'leased': True,
 
652
                                 'updated_at': now})
 
653
        if not fixed_ip['allocated']:
 
654
            LOG.warn(_('IP |%s| leased that isn\'t allocated'), address,
 
655
                     context=context)
 
656
 
 
657
    def release_fixed_ip(self, context, address):
 
658
        """Called by dhcp-bridge when ip is released."""
 
659
        LOG.debug(_('Released IP |%(address)s|'), locals(), context=context)
 
660
        fixed_ip = self.db.fixed_ip_get_by_address(context, address)
 
661
        instance = fixed_ip['instance']
 
662
        if not instance:
 
663
            raise exception.Error(_('IP %s released that is not associated') %
 
664
                                  address)
 
665
        if not fixed_ip['leased']:
 
666
            LOG.warn(_('IP %s released that was not leased'), address,
 
667
                     context=context)
 
668
        self.db.fixed_ip_update(context,
 
669
                                fixed_ip['address'],
 
670
                                {'leased': False})
 
671
        if not fixed_ip['allocated']:
 
672
            self.db.fixed_ip_disassociate(context, address)
 
673
            # NOTE(vish): dhcp server isn't updated until next setup, this
 
674
            #             means there will stale entries in the conf file
 
675
            #             the code below will update the file if necessary
 
676
            if FLAGS.update_dhcp_on_disassociate:
 
677
                network_ref = self.db.fixed_ip_get_network(context, address)
 
678
                self._setup_network(context, network_ref)
 
679
 
 
680
    def create_networks(self, context, label, cidr, multi_host, num_networks,
 
681
                        network_size, cidr_v6, gateway_v6, bridge,
 
682
                        bridge_interface, dns1=None, dns2=None, **kwargs):
 
683
        """Create networks based on parameters."""
 
684
        # NOTE(jkoelker): these are dummy values to make sure iter works
 
685
        fixed_net_v4 = netaddr.IPNetwork('0/32')
 
686
        fixed_net_v6 = netaddr.IPNetwork('::0/128')
 
687
        subnets_v4 = []
 
688
        subnets_v6 = []
 
689
 
 
690
        subnet_bits = int(math.ceil(math.log(network_size, 2)))
 
691
 
 
692
        if cidr_v6:
 
693
            fixed_net_v6 = netaddr.IPNetwork(cidr_v6)
 
694
            prefixlen_v6 = 128 - subnet_bits
 
695
            subnets_v6 = fixed_net_v6.subnet(prefixlen_v6, count=num_networks)
 
696
 
 
697
        if cidr:
 
698
            fixed_net_v4 = netaddr.IPNetwork(cidr)
 
699
            prefixlen_v4 = 32 - subnet_bits
 
700
            subnets_v4 = list(fixed_net_v4.subnet(prefixlen_v4,
 
701
                                                  count=num_networks))
 
702
 
 
703
            # NOTE(jkoelker): This replaces the _validate_cidrs call and
 
704
            #                 prevents looping multiple times
 
705
            try:
 
706
                nets = self.db.network_get_all(context)
 
707
            except exception.NoNetworksFound:
 
708
                nets = []
 
709
            used_subnets = [netaddr.IPNetwork(net['cidr']) for net in nets]
 
710
 
 
711
            def find_next(subnet):
 
712
                next_subnet = subnet.next()
 
713
                while next_subnet in subnets_v4:
 
714
                    next_subnet = next_subnet.next()
 
715
                if next_subnet in fixed_net_v4:
 
716
                    return next_subnet
 
717
 
 
718
            for subnet in list(subnets_v4):
 
719
                if subnet in used_subnets:
 
720
                    next_subnet = find_next(subnet)
 
721
                    if next_subnet:
 
722
                        subnets_v4.remove(subnet)
 
723
                        subnets_v4.append(next_subnet)
 
724
                        subnet = next_subnet
 
725
                    else:
 
726
                        raise ValueError(_('cidr already in use'))
 
727
                for used_subnet in used_subnets:
 
728
                    if subnet in used_subnet:
 
729
                        msg = _('requested cidr (%(cidr)s) conflicts with '
 
730
                                'existing supernet (%(super)s)')
 
731
                        raise ValueError(msg % {'cidr': subnet,
 
732
                                                'super': used_subnet})
 
733
                    if used_subnet in subnet:
 
734
                        next_subnet = find_next(subnet)
 
735
                        if next_subnet:
 
736
                            subnets_v4.remove(subnet)
 
737
                            subnets_v4.append(next_subnet)
 
738
                            subnet = next_subnet
 
739
                        else:
 
740
                            msg = _('requested cidr (%(cidr)s) conflicts '
 
741
                                    'with existing smaller cidr '
 
742
                                    '(%(smaller)s)')
 
743
                            raise ValueError(msg % {'cidr': subnet,
 
744
                                                    'smaller': used_subnet})
 
745
 
 
746
        networks = []
 
747
        subnets = itertools.izip_longest(subnets_v4, subnets_v6)
 
748
        for index, (subnet_v4, subnet_v6) in enumerate(subnets):
 
749
            net = {}
 
750
            net['bridge'] = bridge
 
751
            net['bridge_interface'] = bridge_interface
 
752
            net['multi_host'] = multi_host
 
753
 
 
754
            net['dns1'] = dns1
 
755
            net['dns2'] = dns2
 
756
 
 
757
            if num_networks > 1:
 
758
                net['label'] = '%s_%d' % (label, index)
 
759
            else:
 
760
                net['label'] = label
 
761
 
 
762
            if cidr and subnet_v4:
 
763
                net['cidr'] = str(subnet_v4)
 
764
                net['netmask'] = str(subnet_v4.netmask)
 
765
                net['gateway'] = str(subnet_v4[1])
 
766
                net['broadcast'] = str(subnet_v4.broadcast)
 
767
                net['dhcp_start'] = str(subnet_v4[2])
 
768
 
 
769
            if cidr_v6 and subnet_v6:
 
770
                net['cidr_v6'] = str(subnet_v6)
 
771
                if gateway_v6:
 
772
                    # use a pre-defined gateway if one is provided
 
773
                    net['gateway_v6'] = str(gateway_v6)
 
774
                else:
 
775
                    net['gateway_v6'] = str(subnet_v6[1])
 
776
 
 
777
                net['netmask_v6'] = str(subnet_v6._prefixlen)
 
778
 
 
779
            if kwargs.get('vpn', False):
 
780
                # this bit here is for vlan-manager
 
781
                del net['dns1']
 
782
                del net['dns2']
 
783
                vlan = kwargs['vlan_start'] + index
 
784
                net['vpn_private_address'] = str(subnet_v4[2])
 
785
                net['dhcp_start'] = str(subnet_v4[3])
 
786
                net['vlan'] = vlan
 
787
                net['bridge'] = 'br%s' % vlan
 
788
 
 
789
                # NOTE(vish): This makes ports unique accross the cloud, a more
 
790
                #             robust solution would be to make them uniq per ip
 
791
                net['vpn_public_port'] = kwargs['vpn_start'] + index
 
792
 
 
793
            # None if network with cidr or cidr_v6 already exists
 
794
            network = self.db.network_create_safe(context, net)
 
795
 
 
796
            if not network:
 
797
                raise ValueError(_('Network already exists!'))
 
798
            else:
 
799
                networks.append(network)
 
800
 
 
801
            if network and cidr and subnet_v4:
 
802
                self._create_fixed_ips(context, network['id'])
 
803
        return networks
 
804
 
 
805
    def delete_network(self, context, fixed_range, require_disassociated=True):
 
806
 
 
807
        network = db.network_get_by_cidr(context, fixed_range)
 
808
 
 
809
        if require_disassociated and network.project_id is not None:
 
810
            raise ValueError(_('Network must be disassociated from project %s'
 
811
                               ' before delete' % network.project_id))
 
812
        db.network_delete_safe(context, network.id)
 
813
 
 
814
    @property
 
815
    def _bottom_reserved_ips(self):  # pylint: disable=R0201
 
816
        """Number of reserved ips at the bottom of the range."""
 
817
        return 2  # network, gateway
 
818
 
 
819
    @property
 
820
    def _top_reserved_ips(self):  # pylint: disable=R0201
 
821
        """Number of reserved ips at the top of the range."""
 
822
        return 1  # broadcast
 
823
 
 
824
    def _create_fixed_ips(self, context, network_id):
 
825
        """Create all fixed ips for network."""
 
826
        network = self.db.network_get(context, network_id)
 
827
        # NOTE(vish): Should these be properties of the network as opposed
 
828
        #             to properties of the manager class?
 
829
        bottom_reserved = self._bottom_reserved_ips
 
830
        top_reserved = self._top_reserved_ips
 
831
        project_net = netaddr.IPNetwork(network['cidr'])
 
832
        num_ips = len(project_net)
 
833
        for index in range(num_ips):
 
834
            address = str(project_net[index])
 
835
            if index < bottom_reserved or num_ips - index < top_reserved:
 
836
                reserved = True
 
837
            else:
 
838
                reserved = False
 
839
            self.db.fixed_ip_create(context, {'network_id': network_id,
 
840
                                              'address': address,
 
841
                                              'reserved': reserved})
 
842
 
 
843
    def _allocate_fixed_ips(self, context, instance_id, host, networks,
 
844
                            **kwargs):
 
845
        """Calls allocate_fixed_ip once for each network."""
 
846
        raise NotImplementedError()
 
847
 
 
848
    def _setup_network(self, context, network_ref):
 
849
        """Sets up network on this host."""
 
850
        raise NotImplementedError()
 
851
 
 
852
    def validate_networks(self, context, networks):
 
853
        """check if the networks exists and host
 
854
        is set to each network.
 
855
        """
 
856
        if networks is None or len(networks) == 0:
 
857
            return
 
858
 
 
859
        network_uuids = [uuid for (uuid, fixed_ip) in networks]
 
860
 
 
861
        self._get_networks_by_uuids(context, network_uuids)
 
862
 
 
863
        for network_uuid, address in networks:
 
864
            # check if the fixed IP address is valid and
 
865
            # it actually belongs to the network
 
866
            if address is not None:
 
867
                if not utils.is_valid_ipv4(address):
 
868
                    raise exception.FixedIpInvalid(address=address)
 
869
 
 
870
                fixed_ip_ref = self.db.fixed_ip_get_by_address(context,
 
871
                                                               address)
 
872
                if fixed_ip_ref['network']['uuid'] != network_uuid:
 
873
                    raise exception.FixedIpNotFoundForNetwork(address=address,
 
874
                                            network_uuid=network_uuid)
 
875
                if fixed_ip_ref['instance'] is not None:
 
876
                    raise exception.FixedIpAlreadyInUse(address=address)
 
877
 
 
878
    def _get_networks_by_uuids(self, context, network_uuids):
 
879
        return self.db.network_get_all_by_uuids(context, network_uuids)
 
880
 
 
881
 
 
882
class FlatManager(NetworkManager):
 
883
    """Basic network where no vlans are used.
 
884
 
 
885
    FlatManager does not do any bridge or vlan creation.  The user is
 
886
    responsible for setting up whatever bridges are specified when creating
 
887
    networks through nova-manage. This bridge needs to be created on all
 
888
    compute hosts.
 
889
 
 
890
    The idea is to create a single network for the host with a command like:
 
891
    nova-manage network create 192.168.0.0/24 1 256. Creating multiple
 
892
    networks for for one manager is currently not supported, but could be
 
893
    added by modifying allocate_fixed_ip and get_network to get the a network
 
894
    with new logic instead of network_get_by_bridge. Arbitrary lists of
 
895
    addresses in a single network can be accomplished with manual db editing.
 
896
 
 
897
    If flat_injected is True, the compute host will attempt to inject network
 
898
    config into the guest.  It attempts to modify /etc/network/interfaces and
 
899
    currently only works on debian based systems. To support a wider range of
 
900
    OSes, some other method may need to be devised to let the guest know which
 
901
    ip it should be using so that it can configure itself. Perhaps an attached
 
902
    disk or serial device with configuration info.
 
903
 
 
904
    Metadata forwarding must be handled by the gateway, and since nova does
 
905
    not do any setup in this mode, it must be done manually.  Requests to
 
906
    169.254.169.254 port 80 will need to be forwarded to the api server.
 
907
 
 
908
    """
 
909
 
 
910
    timeout_fixed_ips = False
 
911
 
 
912
    def _allocate_fixed_ips(self, context, instance_id, host, networks,
 
913
                            **kwargs):
 
914
        """Calls allocate_fixed_ip once for each network."""
 
915
        requested_networks = kwargs.get('requested_networks')
 
916
        for network in networks:
 
917
            address = None
 
918
            if requested_networks is not None:
 
919
                for address in (fixed_ip for (uuid, fixed_ip) in \
 
920
                              requested_networks if network['uuid'] == uuid):
 
921
                    break
 
922
 
 
923
            self.allocate_fixed_ip(context, instance_id,
 
924
                                   network, address=address)
 
925
 
 
926
    def deallocate_fixed_ip(self, context, address, **kwargs):
 
927
        """Returns a fixed ip to the pool."""
 
928
        super(FlatManager, self).deallocate_fixed_ip(context, address,
 
929
                                                     **kwargs)
 
930
        self.db.fixed_ip_disassociate(context, address)
 
931
 
 
932
    def _setup_network(self, context, network_ref):
 
933
        """Setup Network on this host."""
 
934
        net = {}
 
935
        net['injected'] = FLAGS.flat_injected
 
936
        self.db.network_update(context, network_ref['id'], net)
 
937
 
 
938
 
 
939
class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager):
 
940
    """Flat networking with dhcp.
 
941
 
 
942
    FlatDHCPManager will start up one dhcp server to give out addresses.
 
943
    It never injects network settings into the guest. It also manages bridges.
 
944
    Otherwise it behaves like FlatManager.
 
945
 
 
946
    """
 
947
 
 
948
    SHOULD_CREATE_BRIDGE = True
 
949
 
 
950
    def init_host(self):
 
951
        """Do any initialization that needs to be run if this is a
 
952
        standalone service.
 
953
        """
 
954
        self.driver.init_host()
 
955
        self.driver.ensure_metadata_ip()
 
956
 
 
957
        super(FlatDHCPManager, self).init_host()
 
958
        self.init_host_floating_ips()
 
959
 
 
960
        self.driver.metadata_forward()
 
961
 
 
962
    def _setup_network(self, context, network_ref):
 
963
        """Sets up network on this host."""
 
964
        network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref)
 
965
 
 
966
        mac_address = self.generate_mac_address()
 
967
        dev = self.driver.plug(network_ref, mac_address)
 
968
        self.driver.initialize_gateway_device(dev, network_ref)
 
969
 
 
970
        if not FLAGS.fake_network:
 
971
            self.driver.update_dhcp(context, dev, network_ref)
 
972
            if(FLAGS.use_ipv6):
 
973
                self.driver.update_ra(context, dev, network_ref)
 
974
                gateway = utils.get_my_linklocal(dev)
 
975
                self.db.network_update(context, network_ref['id'],
 
976
                                       {'gateway_v6': gateway})
 
977
 
 
978
 
 
979
class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
 
980
    """Vlan network with dhcp.
 
981
 
 
982
    VlanManager is the most complicated.  It will create a host-managed
 
983
    vlan for each project.  Each project gets its own subnet.  The networks
 
984
    and associated subnets are created with nova-manage using a command like:
 
985
    nova-manage network create 10.0.0.0/8 3 16.  This will create 3 networks
 
986
    of 16 addresses from the beginning of the 10.0.0.0 range.
 
987
 
 
988
    A dhcp server is run for each subnet, so each project will have its own.
 
989
    For this mode to be useful, each project will need a vpn to access the
 
990
    instances in its subnet.
 
991
 
 
992
    """
 
993
 
 
994
    SHOULD_CREATE_BRIDGE = True
 
995
    SHOULD_CREATE_VLAN = True
 
996
 
 
997
    def init_host(self):
 
998
        """Do any initialization that needs to be run if this is a
 
999
        standalone service.
 
1000
        """
 
1001
 
 
1002
        self.driver.init_host()
 
1003
        self.driver.ensure_metadata_ip()
 
1004
 
 
1005
        NetworkManager.init_host(self)
 
1006
        self.init_host_floating_ips()
 
1007
 
 
1008
        self.driver.metadata_forward()
 
1009
 
 
1010
    def allocate_fixed_ip(self, context, instance_id, network, **kwargs):
 
1011
        """Gets a fixed ip from the pool."""
 
1012
        if kwargs.get('vpn', None):
 
1013
            address = network['vpn_private_address']
 
1014
            self.db.fixed_ip_associate(context,
 
1015
                                       address,
 
1016
                                       instance_id,
 
1017
                                       reserved=True)
 
1018
        else:
 
1019
            address = kwargs.get('address', None)
 
1020
            if address:
 
1021
                address = self.db.fixed_ip_associate(context, address,
 
1022
                                                     instance_id,
 
1023
                                                     network['id'])
 
1024
            else:
 
1025
                address = self.db.fixed_ip_associate_pool(context,
 
1026
                                                          network['id'],
 
1027
                                                          instance_id)
 
1028
            self._do_trigger_security_group_members_refresh_for_instance(
 
1029
                                                                   instance_id)
 
1030
        vif = self.db.virtual_interface_get_by_instance_and_network(context,
 
1031
                                                                 instance_id,
 
1032
                                                                 network['id'])
 
1033
        values = {'allocated': True,
 
1034
                  'virtual_interface_id': vif['id']}
 
1035
        self.db.fixed_ip_update(context, address, values)
 
1036
        self._setup_network(context, network)
 
1037
        return address
 
1038
 
 
1039
    def add_network_to_project(self, context, project_id):
 
1040
        """Force adds another network to a project."""
 
1041
        self.db.network_associate(context, project_id, force=True)
 
1042
 
 
1043
    def _get_networks_for_instance(self, context, instance_id, project_id,
 
1044
                                   requested_networks=None):
 
1045
        """Determine which networks an instance should connect to."""
 
1046
        # get networks associated with project
 
1047
        if requested_networks is not None and len(requested_networks) != 0:
 
1048
            network_uuids = [uuid for (uuid, fixed_ip) in requested_networks]
 
1049
            networks = self.db.network_get_all_by_uuids(context,
 
1050
                                                    network_uuids,
 
1051
                                                    project_id)
 
1052
        else:
 
1053
            networks = self.db.project_get_networks(context, project_id)
 
1054
        return networks
 
1055
 
 
1056
    def create_networks(self, context, **kwargs):
 
1057
        """Create networks based on parameters."""
 
1058
        # Check that num_networks + vlan_start is not > 4094, fixes lp708025
 
1059
        if kwargs['num_networks'] + kwargs['vlan_start'] > 4094:
 
1060
            raise ValueError(_('The sum between the number of networks and'
 
1061
                               ' the vlan start cannot be greater'
 
1062
                               ' than 4094'))
 
1063
 
 
1064
        # check that num networks and network size fits in fixed_net
 
1065
        fixed_net = netaddr.IPNetwork(kwargs['cidr'])
 
1066
        if len(fixed_net) < kwargs['num_networks'] * kwargs['network_size']:
 
1067
            raise ValueError(_('The network range is not big enough to fit '
 
1068
                  '%(num_networks)s. Network size is %(network_size)s') %
 
1069
                  kwargs)
 
1070
 
 
1071
        NetworkManager.create_networks(self, context, vpn=True, **kwargs)
 
1072
 
 
1073
    def _setup_network(self, context, network_ref):
 
1074
        """Sets up network on this host."""
 
1075
        if not network_ref['vpn_public_address']:
 
1076
            net = {}
 
1077
            address = FLAGS.vpn_ip
 
1078
            net['vpn_public_address'] = address
 
1079
            network_ref = db.network_update(context, network_ref['id'], net)
 
1080
        else:
 
1081
            address = network_ref['vpn_public_address']
 
1082
        network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref)
 
1083
 
 
1084
        mac_address = self.generate_mac_address()
 
1085
        dev = self.driver.plug(network_ref, mac_address)
 
1086
        self.driver.initialize_gateway_device(dev, network_ref)
 
1087
 
 
1088
        # NOTE(vish): only ensure this forward if the address hasn't been set
 
1089
        #             manually.
 
1090
        if address == FLAGS.vpn_ip and hasattr(self.driver,
 
1091
                                               "ensure_vpn_forward"):
 
1092
            self.driver.ensure_vpn_forward(FLAGS.vpn_ip,
 
1093
                                            network_ref['vpn_public_port'],
 
1094
                                            network_ref['vpn_private_address'])
 
1095
        if not FLAGS.fake_network:
 
1096
            self.driver.update_dhcp(context, dev, network_ref)
 
1097
            if(FLAGS.use_ipv6):
 
1098
                self.driver.update_ra(context, dev, network_ref)
 
1099
                gateway = utils.get_my_linklocal(dev)
 
1100
                self.db.network_update(context, network_ref['id'],
 
1101
                                       {'gateway_v6': gateway})
 
1102
 
 
1103
    def _get_networks_by_uuids(self, context, network_uuids):
 
1104
        return self.db.network_get_all_by_uuids(context, network_uuids,
 
1105
                                                     context.project_id)
 
1106
 
 
1107
    @property
 
1108
    def _bottom_reserved_ips(self):
 
1109
        """Number of reserved ips at the bottom of the range."""
 
1110
        return super(VlanManager, self)._bottom_reserved_ips + 1  # vpn server
 
1111
 
 
1112
    @property
 
1113
    def _top_reserved_ips(self):
 
1114
        """Number of reserved ips at the top of the range."""
 
1115
        parent_reserved = super(VlanManager, self)._top_reserved_ips
 
1116
        return parent_reserved + FLAGS.cnt_vpn_clients