Files
gantt/nova/tests/test_quantum.py
2012-02-20 09:05:02 +00:00

536 lines
22 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011,2012 Nicira, Inc.
# 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.db.sqlalchemy import models
from nova.db.sqlalchemy.session import get_session
from nova import exception
from nova import flags
from nova import log as logging
from nova.network.quantum import client as quantum_client
from nova.network.quantum import fake_client
from nova.network.quantum import manager as quantum_manager
from nova.network.quantum import quantum_connection
from nova.network.quantum import melange_connection
from nova.network.quantum import melange_ipam_lib
from nova import test
from nova import utils
LOG = logging.getLogger(__name__)
FLAGS = flags.FLAGS
networks = [{'label': 'project1-net1',
'injected': False,
'multi_host': False,
'cidr': '100.168.0.0/24',
'cidr_v6': '100:1db8::/64',
'gateway_v6': '100:1db8::1',
'netmask_v6': '64',
'netmask': '255.255.255.0',
'bridge': None,
'bridge_interface': None,
'gateway': '100.168.0.1',
'broadcast': '100.168.0.255',
'dns1': '8.8.8.8',
'vlan': None,
'host': None,
'vpn_public_address': None,
'project_id': 'fake_project1',
'priority': 1},
{'label': 'project2-net1',
'injected': False,
'multi_host': False,
'cidr': '101.168.1.0/24',
'cidr_v6': '101:1db9::/64',
'gateway_v6': '101:1db9::1',
'netmask_v6': '64',
'netmask': '255.255.255.0',
'bridge': None,
'bridge_interface': None,
'gateway': '101.168.1.1',
'broadcast': '101.168.1.255',
'dns1': '8.8.8.8',
'vlan': None,
'host': None,
'project_id': 'fake_project2',
'priority': 1},
{'label': "public",
'injected': False,
'multi_host': False,
'cidr': '102.0.0.0/24',
'cidr_v6': '102:1dba::/64',
'gateway_v6': '102:1dba::1',
'netmask_v6': '64',
'netmask': '255.255.255.0',
'bridge': None,
'bridge_interface': None,
'gateway': '102.0.0.1',
'broadcast': '102.0.0.255',
'dns1': '8.8.8.8',
'vlan': None,
'host': None,
'project_id': None,
'priority': 0},
{'label': "project2-net2",
'injected': False,
'multi_host': False,
'cidr': '103.0.0.0/24',
'cidr_v6': '103:1dbb::/64',
'gateway_v6': '103:1dbb::1',
'netmask_v6': '64',
'netmask': '255.255.255.0',
'bridge': None,
'bridge_interface': None,
'gateway': '103.0.0.1',
'broadcast': '103.0.0.255',
'dns1': '8.8.8.8',
'vlan': None,
'host': None,
'project_id': "fake_project2",
'priority': 2}]
class QuantumConnectionTestCase(test.TestCase):
def test_connection(self):
fc = fake_client.FakeClient(LOG)
qc = quantum_connection.QuantumClientConnection(client=fc)
t = "tenant1"
net1_name = "net1"
net1_uuid = qc.create_network(t, net1_name)
self.assertEquals(net1_name, qc.get_network_name(t, net1_uuid))
self.assertTrue(qc.network_exists(t, net1_uuid))
self.assertFalse(qc.network_exists(t, "fake-uuid"))
self.assertFalse(qc.network_exists("fake-tenant", net1_uuid))
nets = qc.get_networks(t)['networks']
self.assertEquals(len(nets), 1)
self.assertEquals(nets[0]['id'], net1_uuid)
num_ports = 10
for i in range(0, num_ports):
qc.create_and_attach_port(t, net1_uuid,
'iface' + str(i), state='ACTIVE')
self.assertEquals(len(qc.get_attached_ports(t, net1_uuid)), num_ports)
for i in range(0, num_ports):
port_uuid = qc.get_port_by_attachment(t, net1_uuid,
'iface' + str(i))
self.assertTrue(port_uuid)
qc.detach_and_delete_port(t, net1_uuid, port_uuid)
self.assertEquals(len(qc.get_attached_ports(t, net1_uuid)), 0)
# test port not found
qc.create_and_attach_port(t, net1_uuid, 'foo', state='ACTIVE')
port_uuid = qc.get_port_by_attachment(t, net1_uuid, 'foo')
qc.detach_and_delete_port(t, net1_uuid, port_uuid)
self.assertRaises(quantum_client.QuantumNotFoundException,
qc.detach_and_delete_port, t,
net1_uuid, port_uuid)
qc.delete_network(t, net1_uuid)
self.assertFalse(qc.network_exists(t, net1_uuid))
self.assertEquals(len(qc.get_networks(t)['networks']), 0)
self.assertRaises(quantum_client.QuantumNotFoundException,
qc.get_network_name, t, net1_uuid)
# this is a base class to be used by other QuantumManager Test classes
class QuantumNovaTestCase(test.TestCase):
def setUp(self):
super(QuantumNovaTestCase, self).setUp()
self.flags(quantum_use_dhcp=True)
self.flags(l3_lib="nova.network.l3.LinuxNetL3")
linuxdrv = "nova.network.linux_net.LinuxOVSInterfaceDriver"
self.flags(linuxnet_interface_driver=linuxdrv)
fc = fake_client.FakeClient(LOG)
qc = quantum_connection.QuantumClientConnection(client=fc)
self.net_man = quantum_manager.QuantumManager(
ipam_lib="nova.network.quantum.nova_ipam_lib",
q_conn=qc)
def func(arg1, arg2):
pass
def func2(arg1, arg2, arg3):
pass
def func1(arg1):
pass
self.net_man.driver.update_dhcp_hostfile_with_text = func
self.net_man.driver.restart_dhcp = func2
self.net_man.driver.kill_dhcp = func1
# Tests seem to create some networks by default, which
# we don't want. So we delete them.
ctx = context.RequestContext('user1', 'fake_project1').elevated()
for n in db.network_get_all(ctx):
db.network_delete_safe(ctx, n['id'])
# Other unit tests (e.g., test_compute.py) have a nasty
# habit of of creating fixed IPs and not cleaning up, which
# can confuse these tests, so we remove all existing fixed
# ips before starting.
session = get_session()
result = session.query(models.FixedIp).all()
with session.begin():
for fip_ref in result:
session.delete(fip_ref)
self.net_man.init_host()
def _create_network(self, n):
ctx = context.RequestContext('user1', n['project_id'])
nwks = self.net_man.create_networks(
ctx,
label=n['label'], cidr=n['cidr'],
multi_host=n['multi_host'],
num_networks=1, network_size=256,
cidr_v6=n['cidr_v6'],
gateway=n['gateway'],
gateway_v6=n['gateway_v6'], bridge=None,
bridge_interface=None, dns1=n['dns1'],
project_id=n['project_id'],
priority=n['priority'])
n['uuid'] = nwks[0]['uuid']
class QuantumDeallocationTestCase(QuantumNovaTestCase):
def test_deallocate_port(self):
quantum = self.mox.CreateMock(quantum_connection\
.QuantumClientConnection)
quantum.get_port_by_attachment('q_tenant_id', 'net_id',
'interface_id').AndReturn('port_id')
quantum.detach_and_delete_port('q_tenant_id', 'net_id', 'port_id')
self.net_man.q_conn = quantum
self.mox.ReplayAll()
self.net_man.deallocate_port('interface_id', 'net_id', 'q_tenant_id',
'instance_id')
def test_deallocate_ip_address(self):
ipam = self.mox.CreateMock(melange_ipam_lib.QuantumMelangeIPAMLib)
ipam.get_tenant_id_by_net_id('context', 'net_id', {'uuid': 1},
'project_id').AndReturn('ipam_tenant_id')
self.net_man.ipam = ipam
self.mox.ReplayAll()
self.net_man.deallocate_ip_address('context', 'net_id', 'project_id',
{'uuid': 1}, 'instance_id')
class QuantumManagerTestCase(QuantumNovaTestCase):
def test_create_and_delete_nets(self):
self._create_nets()
self._delete_nets()
def _create_nets(self):
for n in networks:
self._create_network(n)
def _delete_nets(self):
for n in networks:
ctx = context.RequestContext('user1', n['project_id'])
self.net_man.delete_network(ctx, None, n['uuid'])
self.assertRaises(exception.NoNetworksFound,
db.network_get_all, ctx.elevated())
def _validate_nw_info(self, nw_info, expected_net_labels):
self.assertEquals(len(nw_info), len(expected_net_labels))
ctx = context.RequestContext('user1', 'foo').elevated()
all_net_map = {}
for n in db.network_get_all(ctx):
all_net_map[n['label']] = n
for i in range(0, len(nw_info)):
vif = nw_info[i]
net = all_net_map[expected_net_labels[i]]
# simple test assumes that each starting prefix is unique
expected_v4_cidr_start = net['cidr'].split(".")[0].lower()
expected_v6_cidr_start = net['cidr_v6'].split(":")[0].lower()
for subnet in vif['network']['subnets']:
addr = subnet['ips'][0]['address']
if subnet['version'] == 4:
address_start = addr.split(".")[0].lower()
self.assertTrue(expected_v4_cidr_start, address_start)
else:
address_start = addr.split(":")[0].lower()
self.assertTrue(expected_v6_cidr_start, address_start)
# confirm that there is a DHCP device on corresponding net
for l in expected_net_labels:
n = all_net_map[l]
tenant_id = (n['project_id'] or
FLAGS.quantum_default_tenant_id)
ports = self.net_man.q_conn.get_attached_ports(
tenant_id, n['uuid'])
self.assertEquals(len(ports), 2) # gw + instance VIF
# make sure we aren't allowed to delete network with
# active port
self.assertRaises(Exception, self.net_man.delete_network,
ctx, None, n['uuid'])
def _check_vifs(self, expect_num_vifs):
ctx = context.RequestContext('user1', "").elevated()
self.assertEqual(len(db.virtual_interface_get_all(ctx)),
expect_num_vifs)
def _allocate_and_deallocate_instance(self, project_id, requested_networks,
expected_labels):
ctx = context.RequestContext('user1', project_id)
self._check_vifs(0)
instance_ref = db.instance_create(ctx,
{"project_id": project_id})
nw_info = self.net_man.allocate_for_instance(ctx.elevated(),
instance_id=instance_ref['id'], host="",
rxtx_factor=3,
project_id=project_id,
requested_networks=requested_networks)
self._check_vifs(len(nw_info))
self._validate_nw_info(nw_info, expected_labels)
nw_info = self.net_man.get_instance_nw_info(ctx, instance_ref['id'],
instance_ref['uuid'],
instance_ref['instance_type_id'], "",
project_id=project_id)
self._check_vifs(len(nw_info))
self._validate_nw_info(nw_info, expected_labels)
port_net_pairs = []
for vif in nw_info:
nid = vif['network']['id']
pid = self.net_man.q_conn.get_port_by_attachment(
project_id, nid, vif['id'])
if pid is None:
pid = self.net_man.q_conn.get_port_by_attachment(
FLAGS.quantum_default_tenant_id,
nid, vif['id'])
self.assertTrue(pid is not None)
port_net_pairs.append((pid, nid))
self.net_man.deallocate_for_instance(ctx,
instance_id=instance_ref['id'],
project_id=project_id)
for pid, nid in port_net_pairs:
self.assertRaises(quantum_client.QuantumNotFoundException,
self.net_man.q_conn.detach_and_delete_port,
project_id, nid, pid)
self.assertRaises(quantum_client.QuantumNotFoundException,
self.net_man.q_conn.detach_and_delete_port,
FLAGS.quantum_default_tenant_id, nid, pid)
self._check_vifs(0)
def test_allocate_and_deallocate_instance_static(self):
self._create_nets()
self._allocate_and_deallocate_instance("fake_project1", None,
['public', 'project1-net1'])
self._delete_nets()
def test_allocate_and_deallocate_instance_dynamic(self):
self._create_nets()
project_id = "fake_project2"
ctx = context.RequestContext('user1', project_id)
all_valid_networks = self.net_man.ipam.get_project_and_global_net_ids(
ctx, project_id)
requested_networks = [(n[0], None) for n in all_valid_networks]
self.net_man.validate_networks(ctx, requested_networks)
label_map = {}
for n in db.network_get_all(ctx.elevated()):
label_map[n['uuid']] = n['label']
expected_labels = [label_map[uid] for uid, _i in requested_networks]
self._allocate_and_deallocate_instance(project_id, requested_networks,
expected_labels)
self._delete_nets()
def test_validate_bad_network(self):
ctx = context.RequestContext('user1', 'fake_project1')
self.assertRaises(exception.NetworkNotFound,
self.net_man.validate_networks, ctx, [("", None)])
def test_create_net_external_uuid(self):
"""Tests use case where network can be created directly via
Quantum API, then the UUID is passed in via nova-manage"""
project_id = "foo_project"
ctx = context.RequestContext('user1', project_id)
net_id = self.net_man.q_conn.create_network(project_id, 'net1')
self.net_man.create_networks(
ctx,
label='achtungbaby',
cidr="9.9.9.0/24",
multi_host=False,
num_networks=1,
network_size=256,
cidr_v6=None,
gateway="9.9.9.1",
gateway_v6=None,
bridge=None,
bridge_interface=None,
dns1="8.8.8.8",
project_id=project_id,
priority=9,
uuid=net_id)
net = db.network_get_by_uuid(ctx.elevated(), net_id)
self.assertTrue(net is not None)
self.assertEquals(net['uuid'], net_id)
class QuantumNovaMACGenerationTestCase(QuantumNovaTestCase):
def test_local_mac_address_creation(self):
self.flags(use_melange_mac_generation=False)
fake_mac = "ab:cd:ef:ab:cd:ef"
self.stubs.Set(utils, "generate_mac_address",
lambda: fake_mac)
project_id = "fake_project1"
ctx = context.RequestContext('user1', project_id)
self._create_network(networks[0])
all_valid_networks = self.net_man.ipam.get_project_and_global_net_ids(
ctx, project_id)
requested_networks = [(n[0], None) for n in all_valid_networks]
instance_ref = db.api.instance_create(ctx,
{"project_id": project_id})
nw_info = self.net_man.allocate_for_instance(ctx,
instance_id=instance_ref['id'], host="",
rxtx_factor=3,
project_id=project_id,
requested_networks=requested_networks)
self.assertEqual(nw_info[0]['address'], fake_mac)
def test_melange_mac_address_creation(self):
self.flags(use_melange_mac_generation=True)
fake_mac = "ab:cd:ef:ab:cd:ef"
self.stubs.Set(melange_connection.MelangeConnection, "create_vif",
lambda w, x, y, z: fake_mac)
project_id = "fake_project1"
ctx = context.RequestContext('user1', project_id)
self._create_network(networks[0])
all_valid_networks = self.net_man.ipam.get_project_and_global_net_ids(
ctx, project_id)
requested_networks = [(n[0], None) for n in all_valid_networks]
instance_ref = db.api.instance_create(ctx,
{"project_id": project_id})
nw_info = self.net_man.allocate_for_instance(ctx,
instance_id=instance_ref['id'], host="",
rxtx_factor=3,
project_id=project_id,
requested_networks=requested_networks)
self.assertEqual(nw_info[0]['address'], fake_mac)
class QuantumNovaPortSecurityTestCase(QuantumNovaTestCase):
def test_port_securty(self):
self.flags(use_melange_mac_generation=True)
self.flags(quantum_use_port_security=True)
fake_mac = "ab:cd:ef:ab:cd:ef"
self.stubs.Set(melange_connection.MelangeConnection, "create_vif",
lambda w, x, y, z: fake_mac)
project_id = "fake_project1"
ctx = context.RequestContext('user1', project_id)
self._create_network(networks[0])
all_valid_networks = self.net_man.ipam.get_project_and_global_net_ids(
ctx, project_id)
requested_networks = [(n[0], None) for n in all_valid_networks]
instance_ref = db.api.instance_create(ctx,
{"project_id": project_id})
oldfunc = self.net_man.q_conn.create_and_attach_port
# Make sure we get the appropriate mac set in allowed_address_pairs
# if port security is enabled.
def _instrumented_create_and_attach_port(tenant_id, net_id,
interface_id, **kwargs):
self.assertTrue('allowed_address_pairs' in kwargs.keys())
pairs = kwargs['allowed_address_pairs']
self.assertTrue(pairs[0]['mac_address'] == fake_mac)
self.net_man.q_conn.create_and_attach_port = oldfunc
return oldfunc(tenant_id, net_id, interface_id, **kwargs)
_port_attach = _instrumented_create_and_attach_port
self.net_man.q_conn.create_and_attach_port = _port_attach
nw_info = self.net_man.allocate_for_instance(ctx,
instance_id=instance_ref['id'], host="",
rxtx_factor=3,
project_id=project_id,
requested_networks=requested_networks)
self.assertEqual(nw_info[0]['address'], fake_mac)
def test_port_securty_negative(self):
self.flags(use_melange_mac_generation=True)
self.flags(quantum_use_port_security=False)
fake_mac = "ab:cd:ef:ab:cd:ef"
self.stubs.Set(melange_connection.MelangeConnection, "create_vif",
lambda w, x, y, z: fake_mac)
project_id = "fake_project1"
ctx = context.RequestContext('user1', project_id)
self._create_network(networks[0])
all_valid_networks = self.net_man.ipam.get_project_and_global_net_ids(
ctx, project_id)
requested_networks = [(n[0], None) for n in all_valid_networks]
instance_ref = db.api.instance_create(ctx,
{"project_id": project_id})
oldfunc = self.net_man.q_conn.create_and_attach_port
# Make sure no pairs are passed in if port security is turned off
def _instrumented_create_and_attach_port(tenant_id, net_id,
interface_id, **kwargs):
self.assertTrue('allowed_address_pairs' in kwargs.keys())
pairs = kwargs['allowed_address_pairs']
self.assertTrue(len(pairs) == 0)
self.net_man.q_conn.create_and_attach_port = oldfunc
return oldfunc(tenant_id, net_id, interface_id, **kwargs)
_port_attach = _instrumented_create_and_attach_port
self.net_man.q_conn.create_and_attach_port = _port_attach
nw_info = self.net_man.allocate_for_instance(ctx,
instance_id=instance_ref['id'], host="",
rxtx_factor=3,
project_id=project_id,
requested_networks=requested_networks)
self.assertEqual(nw_info[0]['address'], fake_mac)