372 lines
17 KiB
Python
372 lines
17 KiB
Python
# Copyright 2016 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 collections
|
|
|
|
from oslo_log import log as logging
|
|
|
|
from tempest import config
|
|
from tempest.lib.common.utils import data_utils
|
|
from tempest.lib.common.utils import test_utils
|
|
from tempest.lib import decorators
|
|
from tempest import test
|
|
|
|
from vmware_nsx_tempest_plugin.tests.scenario import manager
|
|
|
|
CONF = config.CONF
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
Floating_IP_tuple = collections.namedtuple('Floating_IP_tuple',
|
|
['floating_ip', 'server'])
|
|
|
|
|
|
class TestMultiHVNetworkOps(manager.NetworkScenarioTest):
|
|
|
|
"""Test suite for multi-hypervisor network operations
|
|
|
|
Assume the NSX backend already configured both ESX and KVM hypervisors.
|
|
Also, in tempest conf there should be two image configured, one for
|
|
ESX hypervisor and the other one is for KVM hypervisor.
|
|
|
|
These test cases test the following steps
|
|
- Create a class level network topology which contains router, network
|
|
and external network. Router sets gateway on external network and add
|
|
interface of the network.
|
|
- Create floating ip and loginable security group.
|
|
- Boot two VMs on this network. One uses ESX image and the other one uses
|
|
KVM image type.
|
|
- Test external and internal connectivity of the VMs.
|
|
|
|
"""
|
|
|
|
@classmethod
|
|
def skip_checks(cls):
|
|
super(TestMultiHVNetworkOps, cls).skip_checks()
|
|
if not (CONF.network.project_networks_reachable or
|
|
CONF.network.public_network_id):
|
|
msg = ('Either project_networks_reachable must be "true", or '
|
|
'public_network_id must be defined.')
|
|
raise cls.skipException(msg)
|
|
for ext in ['router', 'security-group']:
|
|
if not test.is_extension_enabled(ext, 'network'):
|
|
msg = "%s extension not enabled." % ext
|
|
raise cls.skipException(msg)
|
|
|
|
@classmethod
|
|
def setup_credentials(cls):
|
|
cls.set_network_resources()
|
|
super(TestMultiHVNetworkOps, cls).setup_credentials()
|
|
|
|
def setUp(self):
|
|
super(TestMultiHVNetworkOps, self).setUp()
|
|
self.keypairs = {}
|
|
self.servers = []
|
|
self.esx_image = CONF.compute.image_ref
|
|
self.kvm_image = CONF.compute.image_ref_alt
|
|
self.config_drive = CONF.compute_feature_enabled.config_drive
|
|
|
|
def _create_router(self, router_name=None, admin_state_up=True,
|
|
external_network_id=None, enable_snat=None,
|
|
**kwargs):
|
|
ext_gw_info = {}
|
|
if external_network_id:
|
|
ext_gw_info['network_id'] = external_network_id
|
|
if enable_snat is not None:
|
|
ext_gw_info['enable_snat'] = enable_snat
|
|
body = self.routers_client.create_router(
|
|
name=router_name, external_gateway_info=ext_gw_info,
|
|
admin_state_up=admin_state_up, **kwargs)
|
|
router = body.get('router', body)
|
|
self.addCleanup(self._delete_router, router)
|
|
return router
|
|
|
|
def _delete_router(self, router):
|
|
body = self.ports_client.list_ports(device_id=router['id'])
|
|
interfaces = body['ports']
|
|
for i in interfaces:
|
|
test_utils.call_and_ignore_notfound_exc(
|
|
self.routers_client.remove_router_interface, router['id'],
|
|
subnet_id=i['fixed_ips'][0]['subnet_id'])
|
|
self.routers_client.delete_router(router['id'])
|
|
|
|
def _create_subnet(self, network, cidr, subnets_client=None, **kwargs):
|
|
client = subnets_client or self.subnets_client
|
|
body = client.create_subnet(
|
|
name=data_utils.rand_name('subnet-default1'),
|
|
network_id=network['id'], tenant_id=network['tenant_id'],
|
|
cidr=cidr, ip_version=4, **kwargs)
|
|
subnet = body.get('subnet', body)
|
|
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
|
client.delete_subnet, subnet['id'])
|
|
return subnet
|
|
|
|
def _create_subnet_v6(self, network, cidr, subnets_client=None, **kwargs):
|
|
client = subnets_client or self.subnets_client
|
|
body = client.create_subnet(
|
|
name=data_utils.rand_name('ipv6_subnet-default1'),
|
|
network_id=network['id'], tenant_id=network['tenant_id'],
|
|
cidr=cidr, ip_version=6, ipv6_ra_mode='slaac',
|
|
ipv6_address_mode='slaac', **kwargs)
|
|
subnet = body.get('subnet', body)
|
|
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
|
client.delete_subnet, subnet['id'])
|
|
return subnet
|
|
|
|
def _setup_l2_topo(self, **kwargs):
|
|
self.security_group = self._create_security_group()
|
|
self.network, self.subnet, self.router = self.create_networks(**kwargs)
|
|
esx_server_name = data_utils.rand_name('server-esx')
|
|
kvm_server_name = data_utils.rand_name('server-kvm')
|
|
# Create a VM on ESX hypervisor
|
|
esx_server = self._create_server(esx_server_name, self.network,
|
|
image_id=self.esx_image)
|
|
# Create a VM on KVM hypervisor
|
|
self._create_server(kvm_server_name, self.network,
|
|
image_id=self.kvm_image)
|
|
floating_ip = self.create_floating_ip(esx_server)
|
|
self.floating_ip_tuple = Floating_IP_tuple(floating_ip, esx_server)
|
|
|
|
def _setup_l2_ipv6_topo(self):
|
|
self.security_group = self._create_security_group()
|
|
self.network = self._create_network()
|
|
rulesets = [
|
|
dict(
|
|
direction='ingress',
|
|
protocol='icmpv6',
|
|
ethertype='IPv6',
|
|
),
|
|
dict(
|
|
direction='egress',
|
|
protocol='icmpv6',
|
|
ethertype='IPv6',
|
|
)
|
|
]
|
|
rules = []
|
|
for ruleset in rulesets:
|
|
rules.append(
|
|
self._create_security_group_rule(
|
|
tenant_id=self.network['tenant_id'],
|
|
secgroup=self.security_group,
|
|
**ruleset))
|
|
self.subnet = self._create_subnet(self.network,
|
|
cidr='14.168.1.0/24')
|
|
self.subnet_v6 = self._create_subnet_v6(self.network,
|
|
cidr='3010::/64')
|
|
self.router = self._create_router(
|
|
router_name=data_utils.rand_name('router-default1'),
|
|
external_network_id=CONF.network.public_network_id)
|
|
self.routers_client.add_router_interface(
|
|
self.router['id'], subnet_id=self.subnet['id'])
|
|
self.routers_client.add_router_interface(
|
|
self.router['id'], subnet_id=self.subnet_v6['id'])
|
|
self.addCleanup(self.routers_client.remove_router_interface,
|
|
self.router['id'], subnet_id=self.subnet['id'])
|
|
self.addCleanup(self.routers_client.remove_router_interface,
|
|
self.router['id'], subnet_id=self.subnet_v6['id'])
|
|
esx_server_name = data_utils.rand_name('server-esx')
|
|
kvm_server_name = data_utils.rand_name('server-kvm')
|
|
# Create a VM on ESX hypervisor
|
|
esx_server = self._create_server(esx_server_name, self.network,
|
|
image_id=self.esx_image)
|
|
# Create a VM on KVM hypervisor
|
|
self._create_server(kvm_server_name, self.network,
|
|
image_id=self.kvm_image)
|
|
floating_ip = self.create_floating_ip(esx_server)
|
|
self.floating_ip_tuple = Floating_IP_tuple(floating_ip, esx_server)
|
|
|
|
def _setup_l3_ipv6_topo(self):
|
|
self.security_group = self._create_security_group()
|
|
self.network = self._create_network()
|
|
rulesets = [
|
|
dict(
|
|
direction='ingress',
|
|
protocol='icmpv6',
|
|
ethertype='IPv6',
|
|
),
|
|
dict(
|
|
direction='egress',
|
|
protocol='icmpv6',
|
|
ethertype='IPv6',
|
|
)
|
|
]
|
|
rules = []
|
|
for ruleset in rulesets:
|
|
rules.append(
|
|
self._create_security_group_rule(
|
|
tenant_id=self.network['tenant_id'],
|
|
secgroup=self.security_group,
|
|
**ruleset))
|
|
self.subnet = self._create_subnet(self.network,
|
|
cidr='14.168.1.0/24')
|
|
self.subnet_v6 = self._create_subnet_v6(self.network,
|
|
cidr='3010::/64')
|
|
self.network_1 = self._create_network()
|
|
self.subnet_1 = self._create_subnet(self.network_1,
|
|
cidr='14.169.1.0/24')
|
|
self.subnet_v6_1 = self._create_subnet_v6(self.network_1,
|
|
cidr='3110::/64')
|
|
self.router = self._create_router(
|
|
router_name=data_utils.rand_name('router-default1'),
|
|
external_network_id=CONF.network.public_network_id)
|
|
self.routers_client.add_router_interface(
|
|
self.router['id'], subnet_id=self.subnet['id'])
|
|
self.routers_client.add_router_interface(
|
|
self.router['id'], subnet_id=self.subnet_v6['id'])
|
|
self.routers_client.add_router_interface(
|
|
self.router['id'], subnet_id=self.subnet_1['id'])
|
|
self.routers_client.add_router_interface(
|
|
self.router['id'], subnet_id=self.subnet_v6_1['id'])
|
|
self.addCleanup(self.routers_client.remove_router_interface,
|
|
self.router['id'], subnet_id=self.subnet_1['id'])
|
|
self.addCleanup(self.routers_client.remove_router_interface,
|
|
self.router['id'], subnet_id=self.subnet_v6_1['id'])
|
|
esx_server_name = data_utils.rand_name('server-esx')
|
|
kvm_server_name = data_utils.rand_name('server-kvm')
|
|
# Create a VM on ESX hypervisor
|
|
esx_server = self._create_server(esx_server_name, self.network,
|
|
image_id=self.esx_image)
|
|
# Create a VM on KVM hypervisor
|
|
self._create_server(kvm_server_name, self.network_1,
|
|
image_id=self.kvm_image)
|
|
floating_ip = self.create_floating_ip(esx_server)
|
|
self.floating_ip_tuple = Floating_IP_tuple(floating_ip, esx_server)
|
|
|
|
def _create_server(self, name, network, image_id=None):
|
|
keypair = self.create_keypair()
|
|
self.keypairs[keypair['name']] = keypair
|
|
security_groups = [{'name': self.security_group['name']}]
|
|
network = {'uuid': network['id']}
|
|
server = self.create_server(name=name, networks=[network],
|
|
key_name=keypair['name'],
|
|
config_drive=self.config_drive,
|
|
security_groups=security_groups,
|
|
image_id=image_id,
|
|
wait_until='ACTIVE')
|
|
self.servers.append(server)
|
|
return server
|
|
|
|
def _get_server_key(self, server):
|
|
return self.keypairs[server['key_name']]['private_key']
|
|
|
|
def _list_ports(self, *args, **kwargs):
|
|
"""List ports using admin creds """
|
|
ports_list = self.admin_manager.ports_client.list_ports(
|
|
*args, **kwargs)
|
|
return ports_list['ports']
|
|
|
|
def get_internal_ipv6_ips(self, server, network, device="compute"):
|
|
internal_ips = [p['fixed_ips'][1]['ip_address'] for p in
|
|
self.admin_manager.ports_client.list_ports(
|
|
tenant_id=server['tenant_id'],
|
|
network_id=network['id'])['ports'] if
|
|
p['device_owner'].startswith(device)]
|
|
return internal_ips
|
|
|
|
def _check_network_internal_connectivity(self, network,
|
|
should_connect=True):
|
|
floating_ip, server = self.floating_ip_tuple
|
|
# test internal connectivity to the network ports on the network
|
|
network_ips = (p['fixed_ips'][0]['ip_address'] for p in
|
|
self._list_ports(tenant_id=server['tenant_id'],
|
|
network_id=network['id'])
|
|
if p['device_owner'].startswith('network'))
|
|
self._check_server_connectivity(floating_ip,
|
|
network_ips,
|
|
should_connect)
|
|
|
|
def _check_network_vm_ipv6_connectivity(self, network,
|
|
should_connect=True):
|
|
floating_ip, server = self.floating_ip_tuple
|
|
# test internal connectivity to the other VM on the same network
|
|
compute_ips = self.get_internal_ipv6_ips(server, network)
|
|
self._check_server_connectivity(floating_ip,
|
|
compute_ips,
|
|
should_connect)
|
|
|
|
def _check_network_vm_connectivity(self, network,
|
|
should_connect=True):
|
|
floating_ip, server = self.floating_ip_tuple
|
|
# test internal connectivity to the other VM on the same network
|
|
compute_ips = (p['fixed_ips'][0]['ip_address'] for p in
|
|
self._list_ports(tenant_id=server['tenant_id'],
|
|
network_id=network['id'])
|
|
if p['device_owner'].startswith('compute'))
|
|
self._check_server_connectivity(floating_ip,
|
|
compute_ips,
|
|
should_connect)
|
|
|
|
def _check_server_connectivity(self, floating_ip, address_list,
|
|
should_connect=True):
|
|
ip_address = floating_ip['floating_ip_address']
|
|
private_key = self._get_server_key(self.floating_ip_tuple.server)
|
|
ssh_source = self.get_remote_client(ip_address,
|
|
private_key=private_key)
|
|
for remote_ip in address_list:
|
|
if should_connect:
|
|
msg = ("Timed out waiting for %s to become "
|
|
"reachable") % remote_ip
|
|
else:
|
|
msg = "ip address %s is reachable" % remote_ip
|
|
try:
|
|
self.assertTrue(self._check_remote_connectivity
|
|
(ssh_source, remote_ip, should_connect),
|
|
msg)
|
|
except Exception:
|
|
LOG.exception("Unable to access %(dest)s via ssh to "
|
|
"floating-ip %(src)s",
|
|
{'dest': remote_ip, 'src': floating_ip})
|
|
raise
|
|
|
|
@decorators.attr(type='nsxv3')
|
|
@decorators.idempotent_id('42373fef-cb05-47c9-bb67-32b7a3b48168')
|
|
def test_multi_hv_network_l2_ops(self):
|
|
"""Test connectivity between ESX VM and KVM VM on same network
|
|
|
|
Boot VM on the same network with both ESX and KVM images and test
|
|
L2 network connectivity if they are on the same L2 network.
|
|
|
|
"""
|
|
self._setup_l2_topo()
|
|
self._check_network_internal_connectivity(network=self.network)
|
|
self._check_network_vm_connectivity(network=self.network)
|
|
|
|
@decorators.attr(type='nsxv3')
|
|
@decorators.idempotent_id('b6ed294d-8557-4fab-b7dc-c1088213f873')
|
|
def test_multi_hv_network_ipv6_l2_ops(self):
|
|
"""Test connectivity between ESX VM and KVM VM on same network
|
|
|
|
Boot VM on the same network with both ESX and KVM images and test
|
|
L2 network connectivity if they are on the same L2 IPv6 network.
|
|
|
|
"""
|
|
self._setup_l2_ipv6_topo()
|
|
self._check_network_internal_connectivity(network=self.network)
|
|
self._check_network_vm_connectivity(network=self.network)
|
|
self._check_network_vm_ipv6_connectivity(network=self.network)
|
|
|
|
@decorators.attr(type='nsxv3')
|
|
@decorators.idempotent_id('b6ed294d-8557-4fab-b7dc-c1088213f873')
|
|
def test_multi_hv_network_ipv6_l3_ops(self):
|
|
"""Test connectivity between ESX VM and KVM VM on diff network
|
|
|
|
Boot VM on the same network with both ESX and KVM images and test
|
|
L3 network connectivity if they are on the diff IPv6 networks.
|
|
|
|
"""
|
|
self._setup_l3_ipv6_topo()
|
|
self._check_network_internal_connectivity(network=self.network)
|
|
self._check_network_vm_connectivity(network=self.network)
|
|
self._check_network_vm_ipv6_connectivity(network=self.network_1)
|