pulled in koelkers test changes

This commit is contained in:
Trey Morris
2011-06-29 16:39:05 -05:00
12 changed files with 251 additions and 224 deletions
-4
View File
@@ -1,4 +0,0 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 2a2fe6198f4be4a4d6f289b09d16d74a
tags: fbb0d17656682115ca4d033fb2f83ba1
+39
View File
@@ -0,0 +1,39 @@
MultiNic
========
What is it
----------
Multinic allows an instance to have more than one vif connected to it. Each vif is representative of a separate network with its own IP block.
Managers
--------
Each of the network managers are designed to run independently of the compute manager. They expose a common API for the compute manager to call to determine and configure the network(s) for an instance. Direct calls to either the network api or especially the DB should be avoided by the virt layers.
On startup a manager looks in the networks table for networks it is assigned and configures itself to support that network. Using the periodic task, they will claim new networks that have no host set. Only one network per network-host will be claimed at a time. This allows for psuedo-loadbalancing if there are multiple network-hosts running.
Flat Manager
------------
.. image:: /images/multinic_flat.png
The Flat manager is most similar to a traditional switched network environment. It assumes that the IP routing, DNS, DHCP (possibly) and bridge creation is handled by something else. That is it makes no attempt to configure any of this. It does keep track of a range of IPs for the instances that are connected to the network to be allocated.
Each instance will get a fixed IP from each network's pool. The guest operating system may be configured to gather this information through an agent or by the hypervisor injecting the files, or it may ignore it completely and come up with only a layer 2 connection.
Flat manager requires at least one nova-network process running that will listen to the API queue and respond to queries. It does not need to sit on any of the networks but it does keep track of the IPs it hands out to instances.
FlatDHCP Manager
----------------
.. image:: /images/multinic_dhcp.png
FlatDHCP manager builds on the the Flat manager adding dnsmask (DNS and DHCP) and radvd (Router Advertisement) servers on the bridge for that network. The services run on the host that is assigned to that nework. The FlatDHCP manager will create its bridge as specified when the network was created on the network-host when the network host starts up or when a new network gets allocated to that host. Compute nodes will also create the bridges as necessary and connect instance VIFs to them.
VLAN Manager
------------
.. image:: /images/multinic_vlan.png
The VLAN manager sets up forwarding to/from a cloudpipe instance in addition to providing dnsmask (DNS and DHCP) and radvd (Router Advertisement) services for each network. The manager will create its bridge as specified when the network was created on the network-host when the network host starts up or when a new network gets allocated to that host. Compute nodes will also create the bridges as necessary and conenct instance VIFs to them.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

@@ -58,8 +58,7 @@ provider_fw_rules = Table('provider_fw_rules', meta,
Column('to_port', Integer()),
Column('cidr',
String(length=255, convert_unicode=False, assert_unicode=None,
unicode_error=None, _warn_on_bytestring=False))
)
unicode_error=None, _warn_on_bytestring=False)))
def upgrade(migrate_engine):
-67
View File
@@ -1,67 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Utility methods
"""
import os
from nova import context
from nova import db
from nova import flags
from nova import log as logging
from nova import utils
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.network')
def binpath(script):
"""Returns the absolute path to a script in bin"""
return os.path.abspath(os.path.join(__file__, "../../../../bin", script))
def lease_ip(private_ip):
"""Run add command on dhcpbridge"""
network_ref = db.fixed_ip_get_network(context.get_admin_context(),
private_ip)
instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
private_ip)
cmd = (binpath('nova-dhcpbridge'), 'add',
instance_ref['mac_address'],
private_ip, 'fake')
env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
'TESTING': '1',
'FLAGFILE': FLAGS.dhcpbridge_flagfile}
(out, err) = utils.execute(*cmd, addl_env=env)
LOG.debug("ISSUE_IP: %s, %s ", out, err)
def release_ip(private_ip):
"""Run del command on dhcpbridge"""
network_ref = db.fixed_ip_get_network(context.get_admin_context(),
private_ip)
instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
private_ip)
cmd = (binpath('nova-dhcpbridge'), 'del',
instance_ref['mac_address'],
private_ip, 'fake')
env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
'TESTING': '1',
'FLAGFILE': FLAGS.dhcpbridge_flagfile}
(out, err) = utils.execute(*cmd, addl_env=env)
LOG.debug("RELEASE_IP: %s, %s ", out, err)
-144
View File
@@ -1,144 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Rackspace
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from nova import context
from nova import db
from nova import flags
from nova import log as logging
from nova import test
from nova import utils
from nova.auth import manager
from nova.tests.db import fakes as db_fakes
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.network')
class NetworkTestCase(test.TestCase):
def setUp(self):
super(NetworkTestCase, self).setUp()
self.flags(connection_type='fake',
fake_call=True,
fake_network=True,
network_manager=self.network_manager)
self.manager = manager.AuthManager()
self.user = self.manager.create_user('netuser',
'netuser',
'netuser')
self.projects = []
self.network = utils.import_object(FLAGS.network_manager)
db_fakes.stub_out_db_network_api(self.stubs)
self.network.db = db
self.network.network_api.db = db
self.context = context.RequestContext(project='fake', user=self.user)
def tearDown(self):
super(NetworkTestCase, self).tearDown()
self.manager.delete_user(self.user.id)
reload(db)
class TestFuncs(object):
def _compare_fields(self, dict1, dict2, fields):
for field in fields:
self.assertEqual(dict1[field], dict2[field])
def test_set_network_hosts(self):
self.network.set_network_hosts(self.context)
def test_set_network_host(self):
host = self.network.host
self.assertEqual(self.network.set_network_host(self.context, 0),
host)
def test_allocate_for_instance(self):
instance_id = 0
project_id = self.context.project_id
type_id = 0
self.network.set_network_hosts(self.context)
nw = self.network.allocate_for_instance(self.context,
instance_id=instance_id,
project_id=project_id,
instance_type_id=type_id)
static_info = [({'bridge': 'fa0', 'id': 0},
{'broadcast': '192.168.0.255',
'dns': ['192.168.0.1'],
'gateway': '192.168.0.1',
'gateway6': 'dead:beef::1',
'ip6s': [{'enabled': '1',
'ip': 'dead:beef::dcad:beff:feef:0',
'netmask': '64'}],
'ips': [{'enabled': '1',
'ip': '192.168.0.100',
'netmask': '255.255.255.0'}],
'label': 'fake',
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
self._compare_fields(nw[0][0], static_info[0][0], ('bridge',))
self._compare_fields(nw[0][1], static_info[0][1], ('ips',
'broadcast',
'gateway',
'ip6s'))
def test_deallocate_for_instance(self):
instance_id = 0
network_id = 0
self.network.set_network_hosts(self.context)
self.network.add_fixed_ip_to_instance(self.context,
instance_id=instance_id,
network_id=network_id)
ips = db.fixed_ip_get_by_instance(self.context, instance_id)
for ip in ips:
self.assertTrue(ip['allocated'])
self.network.deallocate_for_instance(self.context,
instance_id=instance_id)
ips = db.fixed_ip_get_by_instance(self.context, instance_id)
for ip in ips:
self.assertFalse(ip['allocated'])
def test_lease_release_fixed_ip(self):
instance_id = 0
project_id = self.context.project_id
type_id = 0
self.network.set_network_hosts(self.context)
nw = self.network.allocate_for_instance(self.context,
instance_id=instance_id,
project_id=project_id,
instance_type_id=type_id)
self.assertTrue(nw)
self.assertTrue(nw[0])
network_id = nw[0][0]['id']
ips = db.fixed_ip_get_by_instance(self.context, instance_id)
vif = db.virtual_interface_get_by_instance_and_network(self.context,
instance_id,
network_id)
self.assertTrue(ips)
address = ips[0]['address']
db.fixed_ip_associate(self.context, address, instance_id)
db.fixed_ip_update(self.context, address,
{'virtual_interface_id': vif['id']})
self.network.lease_fixed_ip(self.context, address)
ip = db.fixed_ip_get_by_address(self.context, address)
self.assertTrue(ip['leased'])
self.network.release_fixed_ip(self.context, address)
ip = db.fixed_ip_get_by_address(self.context, address)
self.assertFalse(ip['leased'])
+211 -7
View File
@@ -15,22 +15,226 @@
# License for the specific language governing permissions and limitations
# under the License.
from nova import db
from nova import flags
from nova import log as logging
from nova.tests.network import base
from nova import test
from nova.network import manager as network_manager
import mox
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.network')
class FlatNetworkTestCase(base.NetworkTestCase, base.TestFuncs):
network_manager = 'nova.network.manager.FlatManager'
HOST = "testhost"
class FlatDHCPNetworkTestCase(base.NetworkTestCase, base.TestFuncs):
network_manager = 'nova.network.manager.FlatDHCPManager'
class FakeModel(dict):
"""Represent a model from the db"""
def __init__(self, *args, **kwargs):
self.update(kwargs)
def __getattr__(self, name):
return self[name]
class VlanNetworkTestCase(base.NetworkTestCase, base.TestFuncs):
network_manager = 'nova.network.manager.VlanManager'
networks = [{'id': 0,
'label': 'test0',
'injected': False,
'cidr': '192.168.0.0/24',
'cidr_v6': '2001:db8::/64',
'gateway_v6': '2001:db8::1',
'netmask_v6': '64',
'netmask': '255.255.255.0',
'bridge': 'fa0',
'bridge_interface': 'fake_fa0',
'gateway': '192.168.0.1',
'broadcast': '192.168.0.255',
'dns': '192.168.0.1',
'vlan': None,
'host': None,
'project_id': 'fake_project',
'vpn_public_address': '192.168.0.2'},
{'id': 1,
'label': 'test1',
'injected': False,
'cidr': '192.168.1.0/24',
'cidr_v6': '2001:db9::/64',
'gateway_v6': '2001:db9::1',
'netmask_v6': '64',
'netmask': '255.255.255.0',
'bridge': 'fa1',
'bridge_interface': 'fake_fa1',
'gateway': '192.168.1.1',
'broadcast': '192.168.1.255',
'dns': '192.168.0.1',
'vlan': None,
'host': None,
'project_id': 'fake_project',
'vpn_public_address': '192.168.1.2'}]
fixed_ips = [{'id': 0,
'network_id': 0,
'address': '192.168.0.100',
'instance_id': 0,
'allocated': False,
'virtual_interface_id': 0,
'floating_ips': []},
{'id': 0,
'network_id': 1,
'address': '192.168.1.100',
'instance_id': 0,
'allocated': False,
'virtual_interface_id': 0,
'floating_ips': []}]
flavor = {'id': 0,
'rxtx_cap': 3}
floating_ip_fields = {'id': 0,
'address': '192.168.10.100',
'fixed_ip_id': 0,
'project_id': None,
'auto_assigned': False}
vifs = [{'id': 0,
'address': 'DE:AD:BE:EF:00:00',
'network_id': 0,
'network': FakeModel(**networks[0]),
'instance_id': 0},
{'id': 1,
'address': 'DE:AD:BE:EF:00:01',
'network_id': 1,
'network': FakeModel(**networks[1]),
'instance_id': 0}]
class FlatNetworkTestCase(test.TestCase):
def setUp(self):
super(FlatNetworkTestCase, self).setUp()
self.network = network_manager.FlatManager(host=HOST)
self.network.db = db
def test_set_network_hosts(self):
self.mox.StubOutWithMock(db, 'network_get_all')
self.mox.StubOutWithMock(db, 'network_set_host')
self.mox.StubOutWithMock(db, 'network_update')
db.network_get_all(mox.IgnoreArg()).AndReturn([networks[0]])
db.network_set_host(mox.IgnoreArg(),
networks[0]['id'],
mox.IgnoreArg()).AndReturn(HOST)
db.network_update(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg())
self.mox.ReplayAll()
self.network.set_network_hosts(None)
def test_get_instance_nw_info(self):
self.mox.StubOutWithMock(db, 'fixed_ip_get_by_instance')
self.mox.StubOutWithMock(db, 'virtual_interface_get_by_instance')
self.mox.StubOutWithMock(db, 'instance_type_get_by_id')
db.fixed_ip_get_by_instance(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(fixed_ips)
db.virtual_interface_get_by_instance(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(vifs)
db.instance_type_get_by_id(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(flavor)
self.mox.ReplayAll()
nw_info = self.network.get_instance_nw_info(None, 0, 0)
self.assertTrue(nw_info)
for i, nw in enumerate(nw_info):
i8 = i + 8
check = {'bridge': 'fa%s' % i,
'cidr': '192.168.%s.0/24' % i,
'cidr_v6': '2001:db%s::/64' % i8,
'id': i,
'injected': 'DONTCARE'}
self.assertDictMatch(nw[0], check)
check = {'broadcast': '192.168.%s.255' % i,
'dns': 'DONTCARE',
'gateway': '192.168.%s.1' % i,
'gateway6': '2001:db%s::1' % i8,
'ip6s': 'DONTCARE',
'ips': 'DONTCARE',
'label': 'test%s' % i,
'mac': 'DE:AD:BE:EF:00:0%s' % i,
'rxtx_cap': 'DONTCARE'}
self.assertDictMatch(nw[1], check)
check = [{'enabled': 'DONTCARE',
'ip': '2001:db%s::dcad:beff:feef:%s' % (i8, i),
'netmask': '64'}]
self.assertDictListMatch(nw[1]['ip6s'], check)
check = [{'enabled': '1',
'ip': '192.168.%s.100' % i,
'netmask': '255.255.255.0'}]
self.assertDictListMatch(nw[1]['ips'], check)
class VlanNetworkTestCase(test.TestCase):
def setUp(self):
super(VlanNetworkTestCase, self).setUp()
self.network = network_manager.VlanManager(host=HOST)
self.network.db = db
def test_vpn_allocate_fixed_ip(self):
self.mox.StubOutWithMock(db, 'fixed_ip_associate')
self.mox.StubOutWithMock(db, 'fixed_ip_update')
self.mox.StubOutWithMock(db,
'virtual_interface_get_by_instance_and_network')
db.fixed_ip_associate(mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn('192.168.0.1')
db.fixed_ip_update(mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg())
db.virtual_interface_get_by_instance_and_network(mox.IgnoreArg(),
mox.IgnoreArg(), mox.IgnoreArg()).AndReturn({'id': 0})
self.mox.ReplayAll()
network = dict(networks[0])
network['vpn_private_address'] = '192.168.0.2'
self.network.allocate_fixed_ip(None, 0, network, vpn=True)
def test_allocate_fixed_ip(self):
self.mox.StubOutWithMock(db, 'fixed_ip_associate_pool')
self.mox.StubOutWithMock(db, 'fixed_ip_update')
self.mox.StubOutWithMock(db,
'virtual_interface_get_by_instance_and_network')
db.fixed_ip_associate_pool(mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn('192.168.0.1')
db.fixed_ip_update(mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg())
db.virtual_interface_get_by_instance_and_network(mox.IgnoreArg(),
mox.IgnoreArg(), mox.IgnoreArg()).AndReturn({'id': 0})
self.mox.ReplayAll()
network = dict(networks[0])
network['vpn_private_address'] = '192.168.0.2'
self.network.allocate_fixed_ip(None, 0, network)
def test_create_networks_too_big(self):
self.assertRaises(ValueError, self.network.create_networks, None,
num_networks=4094, vlan_start=1)
def test_create_networks_too_many(self):
self.assertRaises(ValueError, self.network.create_networks, None,
num_networks=100, vlan_start=1,
cidr='192.168.0.1/24', network_size=100)