diff --git a/plugin_test/vapor/vapor/conftest.py b/plugin_test/vapor/vapor/conftest.py index d759a0702..939e0d7d9 100644 --- a/plugin_test/vapor/vapor/conftest.py +++ b/plugin_test/vapor/vapor/conftest.py @@ -8,9 +8,9 @@ from stepler.nova.fixtures import * # noqa from vapor.fixtures.contrail import * # noqa from vapor.fixtures.contrail_resources import * # noqa -from vapor.fixtures.ipams import * # noqa from vapor.fixtures.different_tenants_resources import * # noqa from vapor.fixtures.dns import * # noqa +from vapor.fixtures.instance_ip import * # noqa from vapor.fixtures.ipams import * # noqa from vapor.fixtures.networks import * # noqa from vapor.fixtures.nodes import * # noqa @@ -18,7 +18,8 @@ from vapor.fixtures.policies import * # noqa from vapor.fixtures.security_groups import * # noqa from vapor.fixtures.skip import * # noqa from vapor.fixtures.subnets import * # noqa -from vapor.fixtures.system_services import * # noqa +from vapor.fixtures.system_services import * # noqa +from vapor.fixtures.virtual_interface import * # noqa pytest_plugins = [ 'vapor.plugins.xfail', diff --git a/plugin_test/vapor/vapor/fixtures/instance_ip.py b/plugin_test/vapor/vapor/fixtures/instance_ip.py new file mode 100644 index 000000000..ba4064511 --- /dev/null +++ b/plugin_test/vapor/vapor/fixtures/instance_ip.py @@ -0,0 +1,43 @@ +"""Contrail InstanceIP fixtures.""" + +# 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 pytest +from pycontrail import exceptions +from pycontrail import types +from stepler.third_party import utils + + +@pytest.fixture +def contrail_create_instance_ip(contrail_api_client): + """Fixture to create contrail InstanceIP.""" + + ips = [] + + def _create(network, iface, ip_address, subnet_uuid=None): + name, = utils.generate_ids() + ip = types.InstanceIp( + name=name, instance_ip_address=ip_address, subnet_uuid=subnet_uuid) + ip.add_virtual_machine_interface(iface) + ip.add_virtual_network(network) + ips.append(ip) + contrail_api_client.instance_ip_create(ip) + return ip + + yield _create + + for ip in ips: + try: + contrail_api_client.instance_ip_delete(id=ip.uuid) + except exceptions.NoIdError: + pass diff --git a/plugin_test/vapor/vapor/fixtures/subnets.py b/plugin_test/vapor/vapor/fixtures/subnets.py index f9c501963..b9c066161 100644 --- a/plugin_test/vapor/vapor/fixtures/subnets.py +++ b/plugin_test/vapor/vapor/fixtures/subnets.py @@ -14,8 +14,20 @@ import pycontrail.types as types import pytest +def _get_ipam_refs(network): + for ipam_ref in network.get_network_ipam_refs() or []: + yield ipam_ref + + +def _get_subnets(network): + for ipam_ref in _get_ipam_refs(network): + for subnet in ipam_ref['attr'].ipam_subnets: + yield subnet + + @pytest.fixture -def contrail_create_subnet(contrail_api_client): +def contrail_create_subnet(contrail_api_client, contrail_default_ipam): + """Callable fixture to create subnet and delete it after test.""" networks = [] @@ -23,15 +35,41 @@ def contrail_create_subnet(contrail_api_client): ipam=None, ip_prefix='10.0.0.0', ip_prefix_len=24): + # Refresh network data + network = contrail_api_client.virtual_network_read(id=network.uuid) + ipam = ipam or contrail_default_ipam + + ipam_subnets = [] + update_exists = False + for ipam_ref in _get_ipam_refs(network): + if ipam_ref['uuid'] == ipam.uuid: + ipam_subnets = ipam_ref['attr'].ipam_subnets + update_exists = True + + # Store subnet uuids before adding new + subnet_uuids = { + x.subnet_uuid + for x in _get_subnets(network) if x.subnet_uuid is not None + } + networks.append((network, ipam)) + subnet_type = types.SubnetType( ip_prefix=ip_prefix, ip_prefix_len=ip_prefix_len) - vn_sub = types.VnSubnetsType( - [types.IpamSubnetType(subnet=subnet_type)]) - network.add_network_ipam(ipam, vn_sub) + ipam_subnets.append(types.IpamSubnetType(subnet=subnet_type)) + vn_sub = types.VnSubnetsType(ipam_subnets=ipam_subnets) + if update_exists: + network.set_network_ipam(ipam, vn_sub) + else: + network.add_network_ipam(ipam, vn_sub) contrail_api_client.virtual_network_update(network) - return + # Reread network data after update + network = contrail_api_client.virtual_network_read(id=network.uuid) + for subnet in _get_subnets(network): + if subnet.subnet_uuid not in subnet_uuids: + break + return subnet yield _contrail_create_subnet diff --git a/plugin_test/vapor/vapor/fixtures/virtual_interface.py b/plugin_test/vapor/vapor/fixtures/virtual_interface.py new file mode 100644 index 000000000..5d7c062e6 --- /dev/null +++ b/plugin_test/vapor/vapor/fixtures/virtual_interface.py @@ -0,0 +1,40 @@ +# 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 pytest +from pycontrail import exceptions +from pycontrail import types +from stepler.third_party import utils + + +@pytest.fixture +def create_virtual_interface(contrail_api_client, contrail_current_project): + """Callable fixture to create virtual machine interface(port).""" + + ifaces = [] + + def _create(network): + iface_name, = utils.generate_ids() + iface = types.VirtualMachineInterface( + name=iface_name, parent_obj=contrail_current_project) + iface.add_virtual_network(network) + ifaces.append(iface) + contrail_api_client.virtual_machine_interface_create(iface) + return iface + + yield _create + + for iface in reversed(ifaces): + try: + contrail_api_client.virtual_machine_interface_delete(id=iface.uuid) + except exceptions.NoIdError: + pass diff --git a/plugin_test/vapor/vapor/tests/common/test_base.py b/plugin_test/vapor/vapor/tests/common/test_base.py index 4c46e3fe7..60257531d 100644 --- a/plugin_test/vapor/vapor/tests/common/test_base.py +++ b/plugin_test/vapor/vapor/tests/common/test_base.py @@ -13,7 +13,7 @@ import sys from hamcrest import (assert_that, calling, raises, contains_string, has_item, - has_entry, is_not, empty, equal_to) # noqa H301 + has_entry, is_not, empty, equal_to, all_of) # noqa H301 from neutronclient.common import exceptions as neutron_exceptions from stepler import config as stepler_config from stepler.third_party import utils @@ -303,3 +303,61 @@ def test_file_transfer_with_scp( actual_size = server2_ssh.check_call( 'stat -c %s {}'.format(path)).stdout collector.check(actual_size, equal_to(str(size))) + + +def test_various_type_of_subnets_associated_with_vn( + cirros_image, + flavor, + security_group, + contrail_network, + contrail_current_project, + contrail_create_subnet, + create_virtual_interface, + contrail_create_instance_ip, + server_steps, + create_floating_ip, + public_network): + """Validate that 2 subnets with different CIDR on single VN works. + + Steps: + #. Create network + #. Create subnet_1 + #. Create subnet 2 with different CIDR + #. Create 2 ports on VN for each subnet + #. Boot nova server with created ports + #. Execute `sudo cirros-dhcpd up ` for all interfaces on server + #. Check that server gets correct IP addresses on all interfaces + """ + ip1 = '10.0.0.10' + ip2 = '10.10.0.10' + iface_names = ('eth0', 'eth1') + contrail_create_subnet( + contrail_network, ip_prefix='10.0.0.0', ip_prefix_len=24) + contrail_create_subnet( + contrail_network, ip_prefix='10.10.0.0', ip_prefix_len=16) + + iface1 = create_virtual_interface(contrail_network) + iface2 = create_virtual_interface(contrail_network) + + ip1 = contrail_create_instance_ip(contrail_network, iface1, ip1) + ip2 = contrail_create_instance_ip(contrail_network, iface2, ip2) + server = server_steps.create_servers( + image=cirros_image, + flavor=flavor, + nics=[{ + 'port-id': iface1.uuid, + }, { + 'port-id': iface2.uuid + }], + security_groups=[security_group], + username=stepler_config.CIRROS_USERNAME, + password=stepler_config.CIRROS_PASSWORD)[0] + floating_ip = create_floating_ip(public_network, port={'id': iface1.uuid}) + with server_steps.get_server_ssh( + server, floating_ip['floating_ip_address']) as server_ssh: + with server_ssh.sudo(): + for name in iface_names: + server_ssh.check_call('/sbin/cirros-dhcpc up {}'.format(name)) + result = server_ssh.check_call('ip a') + assert_that(result.stdout, + all_of(*[contains_string(name) for name in iface_names]))