vmware-nsx/vmware_nsx/tests/unit/common_plugin/common_v3.py

500 lines
19 KiB
Python

# Copyright 2018 VMware, 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.
import contextlib
import decorator
from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
import netaddr
from neutron_lib import constants
from webob import exc
class FixExternalNetBaseTest(object):
"""Base class providing utilities for handling tests which require updating
a network to be external, which is not supported for the NSX-v3 and NSX-P
plugins.
"""
def setUp(self, *args, **kwargs):
self.original_subnet = self.subnet
self.original_create_subnet = self._create_subnet
self.original_network = self.network
self.subnet_calls = []
super(FixExternalNetBaseTest, self).setUp(*args, **kwargs)
def _set_net_external(self, net_id):
# This action is not supported by the V3 plugin
pass
def _create_external_network(self):
data = {'network': {'name': 'net1',
'router:external': 'True',
'tenant_id': 'tenant_one',
'provider:physical_network': 'stam'}}
network_req = self.new_create_request('networks', data)
network = self.deserialize(self.fmt,
network_req.get_response(self.api))
return network
def external_subnet(self, network=None, **kwargs):
# External subnet ,ust have dhcp disabled
kwargs['enable_dhcp'] = False
if network:
return self.original_subnet(network=network, **kwargs)
ext_net = self._create_external_network()
return self.original_subnet(network=ext_net, **kwargs)
def create_external_subnet(self, *args, **kwargs):
kwargs['enable_dhcp'] = False
return super(FixExternalNetBaseTest, self)._create_subnet(
*args, **kwargs)
def no_dhcp_subnet(self, *args, **kwargs):
if 'enable_dhcp' in kwargs:
return self.original_subnet(*args, **kwargs)
return self.original_subnet(*args, enable_dhcp=False, **kwargs)
def external_subnet_by_list(self, *args, **kwargs):
if len(self.subnet_calls) > 0:
result = self.subnet_calls[0](*args, **kwargs)
del self.subnet_calls[0]
else:
# back to normal
self.subnet = self.original_subnet
result = self.subnet(*args, **kwargs)
return result
@contextlib.contextmanager
def floatingip_with_assoc(self, port_id=None, fmt=None, fixed_ip=None,
public_cidr='11.0.0.0/24', set_context=False,
tenant_id=None, **kwargs):
# Override super implementation to avoid changing the network to
# external after creation
with self._create_l3_ext_network() as ext_net,\
self.subnet(network=ext_net, cidr=public_cidr,
set_context=set_context,
tenant_id=tenant_id,
enable_dhcp=False) as public_sub:
private_port = None
if port_id:
private_port = self._show('ports', port_id)
with test_plugin.optional_ctx(
private_port, self.port,
set_context=set_context,
tenant_id=tenant_id) as private_port:
with self.router(set_context=set_context,
tenant_id=tenant_id) as r:
sid = private_port['port']['fixed_ips'][0]['subnet_id']
private_sub = {'subnet': {'id': sid}}
floatingip = None
self._add_external_gateway_to_router(
r['router']['id'],
public_sub['subnet']['network_id'])
self._router_interface_action(
'add', r['router']['id'],
private_sub['subnet']['id'], None)
floatingip = self._make_floatingip(
fmt or self.fmt,
public_sub['subnet']['network_id'],
port_id=private_port['port']['id'],
fixed_ip=fixed_ip,
tenant_id=tenant_id,
set_context=set_context,
**kwargs)
yield floatingip
if floatingip:
self._delete('floatingips',
floatingip['floatingip']['id'])
@contextlib.contextmanager
def floatingip_no_assoc(self, private_sub, fmt=None,
set_context=False, flavor_id=None, **kwargs):
# override super code to create an external subnet in advanced
with self.external_subnet(cidr='12.0.0.0/24') as public_sub:
with self.floatingip_no_assoc_with_public_sub(
private_sub, fmt, set_context, public_sub,
flavor_id, **kwargs) as (f, r):
# Yield only the floating ip object
yield f
# Override subnet/network creation in some tests to create external
# networks immediately instead of updating it post creation, which the
# v3 plugin does not support
@decorator.decorator
def with_external_subnet(f, *args, **kwargs):
obj = args[0]
obj.subnet = obj.external_subnet
result = f(*args, **kwargs)
obj.subnet = obj.original_subnet
return result
@decorator.decorator
def with_disable_dhcp(f, *args, **kwargs):
obj = args[0]
obj.force_disable_dhcp = True
result = f(*args, **kwargs)
obj.force_disable_dhcp = False
return result
@decorator.decorator
def with_disable_dhcp_once(f, *args, **kwargs):
obj = args[0]
obj.force_disable_dhcp = True
obj.force_disable_dhcp_once = True
result = f(*args, **kwargs)
obj.force_disable_dhcp = False
obj.force_disable_dhcp_once = False
return result
def init_subnet_calls(self, n):
self.subnet_calls = []
for i in range(0, n - 1):
self.subnet_calls.append(self.subnet)
self.subnet_calls.append(self.external_subnet)
def call_with_subnet_calls(self, f, *args, **kwargs):
self.subnet = self.external_subnet_by_list
result = f(*args, **kwargs)
self.subnet = self.original_subnet
return result
@decorator.decorator
def with_external_subnet_once(f, *args, **kwargs):
obj = args[0]
init_subnet_calls(obj, 1)
return call_with_subnet_calls(obj, f, *args, **kwargs)
@decorator.decorator
def with_external_subnet_second_time(f, *args, **kwargs):
obj = args[0]
init_subnet_calls(obj, 2)
return call_with_subnet_calls(obj, f, *args, **kwargs)
@decorator.decorator
def with_external_subnet_third_time(f, *args, **kwargs):
obj = args[0]
init_subnet_calls(obj, 3)
return call_with_subnet_calls(obj, f, *args, **kwargs)
@decorator.decorator
def with_external_network(f, *args, **kwargs):
obj = args[0]
obj.network = obj.external_network
obj.subnet = obj.external_subnet
obj._create_subnet = obj.create_external_subnet
result = f(*args, **kwargs)
obj._create_subnet = obj.original_create_subnet
obj.subnet = obj.original_subnet
obj.network = obj.original_network
return result
# Override subnet creation in some tests to create a subnet with dhcp
# disabled
@decorator.decorator
def with_no_dhcp_subnet(f, *args, **kwargs):
obj = args[0]
obj.subnet = obj.no_dhcp_subnet
result = f(*args, **kwargs)
obj.subnet = obj.original_subnet
return result
# TODO(annak): remove this when DHCPv6 is supported
@decorator.decorator
def with_force_slaac(f, *args, **kwargs):
obj = args[0]
obj.force_slaac = True
result = f(*args, **kwargs)
obj.force_slaac = False
return result
class NsxV3SubnetMixin(object):
def setUp(self, *args, **kwargs):
super(NsxV3SubnetMixin, self).setUp(*args, **kwargs)
self.force_slaac = False
self.force_disable_dhcp = False
self.force_disable_dhcp_once = False
def _test_create_subnet(self, network=None, expected=None, **kwargs):
# Until DHCPv6 is supported, switch all test to slaac-only
if (self.force_slaac and
'ipv6_ra_mode' in kwargs and 'ipv6_address_mode' in kwargs):
kwargs['ipv6_ra_mode'] = constants.IPV6_SLAAC
kwargs['ipv6_address_mode'] = constants.IPV6_SLAAC
return super(NsxV3SubnetMixin,
self)._test_create_subnet(network, expected, **kwargs)
def _create_subnet(self, fmt, net_id, cidr,
expected_res_status=None, **kwargs):
if self.force_disable_dhcp:
kwargs['enable_dhcp'] = False
if self.force_disable_dhcp_once:
self.force_disable_dhcp = False
return super(NsxV3SubnetMixin, self)._create_subnet(
fmt, net_id, cidr, expected_res_status, **kwargs)
class NsxV3TestSubnets(NsxV3SubnetMixin,
test_plugin.TestSubnetsV2):
@with_disable_dhcp
def test_list_subnets_filtering_by_project_id(self):
super(NsxV3TestSubnets,
self).test_list_subnets_filtering_by_project_id()
@with_disable_dhcp
def test_list_subnets_filtering_by_cidr_used_on_create(self):
super(NsxV3TestSubnets,
self).test_list_subnets_filtering_by_cidr_used_on_create()
@with_disable_dhcp
def test_list_subnets(self):
super(NsxV3TestSubnets, self).test_list_subnets()
@with_disable_dhcp
def test_list_subnets_with_parameter(self):
super(NsxV3TestSubnets, self).test_list_subnets_with_parameter()
def test_create_subnet_ipv6_pd_gw_values(self):
self.skipTest('Test not suited to the plugin DHCP code')
def test_create_subnet_ipv6_slaac_with_port_not_found(self):
self.skipTest('Test not suited to the plugin DHCP code')
def test_bulk_create_subnet_ipv6_auto_addr_with_port_on_network(self):
self.skipTest('No Multiple v6 subnets support yet')
def test_create_subnet_dhcpv6_stateless_with_ip_already_allocated(self):
self.skipTest('Test not suited to the plugin DHCP code')
def test_create_subnet_ipv6_slaac_with_dhcp_port_on_network(self):
self.skipTest('Test not suited to the plugin DHCP code')
def test_create_subnet_dhcpv6_stateless_with_port_on_network(self):
self.skipTest('Test not suited to the plugin DHCP code')
def test_delete_subnet_port_exists_owned_by_network(self):
self.skipTest('Test not suited to the plugin DHCP code')
def test_create_subnets_bulk_native_ipv6(self):
self.skipTest('Multiple IPv6 subnets on one network is not supported')
@with_disable_dhcp
def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self):
super(NsxV3TestSubnets,
self).test_update_subnet_inconsistent_ipv6_hostroute_dst_v4()
@with_disable_dhcp
def test_create_two_subnets(self):
super(NsxV3TestSubnets, self).test_create_two_subnets()
@with_disable_dhcp
def test_create_subnets_bulk_emulated(self):
super(NsxV3TestSubnets, self).test_create_subnets_bulk_emulated()
@with_disable_dhcp
def test_create_subnets_bulk_native(self):
super(NsxV3TestSubnets, self).test_create_subnets_bulk_native()
@with_disable_dhcp
def test_get_subnets_count(self):
super(NsxV3TestSubnets, self).test_get_subnets_count()
@with_disable_dhcp
def test_get_subnets_count_filter_by_project_id(self):
super(NsxV3TestSubnets,
self).test_get_subnets_count_filter_by_project_id()
@with_disable_dhcp
def test_get_subnets_count_filter_by_unknown_filter(self):
super(NsxV3TestSubnets,
self).test_get_subnets_count_filter_by_unknown_filter()
@with_disable_dhcp
def test_delete_subnet_dhcp_port_associated_with_other_subnets(self):
super(NsxV3TestSubnets,
self).test_get_subnets_count_filter_by_unknown_filter()
@with_disable_dhcp
def test_delete_subnet_with_other_subnet_on_network_still_in_use(self):
super(NsxV3TestSubnets, self).\
test_delete_subnet_with_other_subnet_on_network_still_in_use()
@with_force_slaac
def test_create_subnet_ipv6_gw_values(self):
super(NsxV3TestSubnets, self).test_create_subnet_ipv6_gw_values()
@with_force_slaac
def test_create_subnet_ipv6_out_of_cidr_global(self):
super(NsxV3TestSubnets,
self).test_create_subnet_ipv6_out_of_cidr_global()
@with_disable_dhcp
def test_update_subnet_inconsistent_ipv6_gatewayv4(self):
super(NsxV3TestSubnets,
self).test_update_subnet_inconsistent_ipv6_gatewayv4()
@with_disable_dhcp
def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self):
super(NsxV3TestSubnets,
self).test_update_subnet_inconsistent_ipv6_hostroute_np_v4()
def test_subnet_update_ipv4_and_ipv6_pd_v6stateless_subnets(self):
self.skipTest('Multiple fixed ips on a port are not supported')
def test_subnet_update_ipv4_and_ipv6_pd_slaac_subnets(self):
self.skipTest('Multiple fixed ips on a port are not supported')
class NsxV3TestPorts(test_plugin.TestPortsV2):
def test_create_port_with_ipv6_dhcp_stateful_subnet_in_fixed_ips(self):
self.skipTest('No DHCP v6 Support yet')
def test_update_port_update_ip_address_only(self):
self.skipTest('Multiple fixed ips on a port are not supported')
def test_update_port_with_new_ipv6_slaac_subnet_in_fixed_ips(self):
self.skipTest('Multiple fixed ips on a port are not supported')
def test_update_port_mac_v6_slaac(self):
self.skipTest('Multiple fixed ips on a port are not supported')
def test_requested_invalid_fixed_ips(self):
self.skipTest('Multiple fixed ips on a port are not supported')
def test_requested_subnet_id_v4_and_v6_slaac(self):
self.skipTest('Multiple fixed ips on a port are not supported')
def test_range_allocation(self):
self.skipTest('Multiple fixed ips on a port are not supported')
def test_create_port_anticipating_allocation(self):
self.skipTest('Multiple fixed ips on a port are not supported')
def test_create_port_additional_ip(self):
"""Test that creation of port with additional IP fails."""
with self.subnet() as subnet:
data = {'port': {'network_id': subnet['subnet']['network_id'],
'tenant_id': subnet['subnet']['tenant_id'],
'fixed_ips': [{'subnet_id':
subnet['subnet']['id']},
{'subnet_id':
subnet['subnet']['id']}]}}
port_req = self.new_create_request('ports', data)
res = port_req.get_response(self.api)
self.assertEqual(exc.HTTPBadRequest.code,
res.status_int)
def test_create_port_additional_ip_no_dhcp(self):
"""Creation of port with additional IP succeeds with DHCP off."""
with self.subnet(enable_dhcp=False) as subnet:
data = {'port': {'network_id': subnet['subnet']['network_id'],
'tenant_id': subnet['subnet']['tenant_id'],
'fixed_ips': [{'subnet_id':
subnet['subnet']['id']},
{'subnet_id':
subnet['subnet']['id']}]}}
port_req = self.new_create_request('ports', data)
res = port_req.get_response(self.api)
port = self.deserialize(self.fmt, res)
ips = port['port']['fixed_ips']
self.assertEqual(2, len(ips))
self.assertNotEqual(ips[0]['ip_address'],
ips[1]['ip_address'])
network_ip_net = netaddr.IPNetwork(subnet['subnet']['cidr'])
self.assertIn(ips[0]['ip_address'], network_ip_net)
self.assertIn(ips[1]['ip_address'], network_ip_net)
def test_update_port_add_additional_ip(self):
"""Test update of port with additional IP fails."""
with self.subnet() as subnet:
with self.port(subnet=subnet) as port:
data = {'port': {'admin_state_up': False,
'fixed_ips': [{'subnet_id':
subnet['subnet']['id']},
{'subnet_id':
subnet['subnet']['id']}]}}
req = self.new_update_request('ports', data,
port['port']['id'])
res = req.get_response(self.api)
self.assertEqual(exc.HTTPBadRequest.code,
res.status_int)
def test_update_port_add_additional_ip_no_dhcp(self):
"""Test update of port with additional IP succeeds if DHCP is off."""
with self.subnet(enable_dhcp=False) as subnet:
with self.port(subnet=subnet) as port:
data = {'port': {'admin_state_up': False,
'fixed_ips': [{'subnet_id':
subnet['subnet']['id']},
{'subnet_id':
subnet['subnet']['id']}]}}
req = self.new_update_request('ports', data,
port['port']['id'])
res = req.get_response(self.api)
port = self.deserialize(self.fmt, res)
ips = port['port']['fixed_ips']
self.assertEqual(2, len(ips))
self.assertNotEqual(ips[0]['ip_address'],
ips[1]['ip_address'])
network_ip_net = netaddr.IPNetwork(subnet['subnet']['cidr'])
self.assertIn(ips[0]['ip_address'], network_ip_net)
self.assertIn(ips[1]['ip_address'], network_ip_net)
def test_delete_network_port_exists_owned_by_network_race(self):
self.skipTest('Skip need to address in future')
def test_delete_network_port_exists_owned_by_network_port_not_found(self):
self.skipTest('Skip need to address in future')
def test_delete_network_port_exists_owned_by_network(self):
self.skipTest('Skip need to address in future')
def test_duplicate_mac_generation(self):
self.skipTest('No DHCP v6 Support yet')
@with_disable_dhcp
def test_update_port_update_ip(self):
return super(NsxV3TestPorts, self).test_update_port_update_ip()
def test_create_router_port_ipv4_and_ipv6_slaac_no_fixed_ips(self):
self.skipTest('No DHCP v6 Support yet')
def test_ip_allocation_for_ipv6_2_subnet_slaac_mode(self):
self.skipTest('Only one ipv6 subnet per network is supported')
def test_create_port_with_multiple_ipv4_and_ipv6_subnets(self):
self.skipTest('Only one ipv6 subnet per network is supported')