vmware-nsx/vmware_nsx_tempest/tests/nsxv/scenario/test_dhcp_121.py

516 lines
25 KiB
Python

# Copyright 2016 OpenStack Foundation
# 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 re
import socket
import struct
import sys
import time
import netaddr
from tempest.common.utils.linux import remote_client
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
from tempest import test
from vmware_nsx_tempest.services import nsxv_client
from vmware_nsx_tempest.tests.nsxv.scenario import (
manager_topo_deployment as dmgr)
from vmware_nsx_tempest.tests.nsxv.scenario import (
network_addon_methods as HELO)
CONF = config.CONF
LOG = dmgr.manager.log.getLogger(__name__)
DHCP_121_DEPLOY_TOPO = "Testcase DHCP-121 option [%s] deploying"
DHCP_121_DEPLOY_COMPLETED = "Testcase [%s] deploy test-completed."
Metadataserver_ip = '169.254.169.254'
class TestDHCP121BasicOps(dmgr.TopoDeployScenarioManager):
"""Base class provides DHCP 121 options operations.
1) Creates an instance
2) Ssh to instance and then check below information:
a) check metadata routes avialable or not
b) check host routes avialble or not
c) clear host-routes from subnet and check routes present on vm or not
d) update subnet to disbale dhcp and check metadata routes not visible
on instance
3) Check at beckend(nsx-v) for host-routes and metadata route information
4) Delete of host routes from subnet will make it deleted from beckend
5) Negative test where try to make subnet dhcp disable but host-routes
present and vice-versa
6) Create large no of host-routes for subnet and check validation at
beckend
"""
@classmethod
def skip_checks(cls):
super(TestDHCP121BasicOps, cls).skip_checks()
if not ((CONF.network.project_networks_reachable
or CONF.network.public_network_id) and
CONF.network.public_network_cidr):
msg = ('Either project_networks_reachable must be "true", or '
'public_network_id must be defined.')
raise cls.skipException(msg)
manager_ip = re.search(r"(\d{1,3}\.){3}\d{1,3}",
CONF.nsxv.manager_uri).group(0)
cls.vsm = nsxv_client.VSMClient(
manager_ip, CONF.nsxv.user, CONF.nsxv.password)
nsxv_version = cls.vsm.get_vsm_version()
# Raise skip testcase exception if nsx-v version is less than 6.2.3
if (nsxv_version and nsxv_version < '6.2.3'):
msg = ('NSX-v version should be greater than or equal to 6.2.3')
raise cls.skipException(msg)
@classmethod
def resource_setup(cls):
super(TestDHCP121BasicOps, cls).resource_setup()
@classmethod
def resource_cleanup(cls):
super(TestDHCP121BasicOps, cls).resource_cleanup()
def tearDown(self):
self.remove_project_network()
super(TestDHCP121BasicOps, self).tearDown()
def remove_project_network(self):
project_name = 'green'
tenant = getattr(self, project_name, None)
if tenant:
servers_client = tenant['client_mgr'].servers_client
dmgr.delete_all_servers(servers_client)
self.disassociate_floatingip(tenant['fip1'],
and_delete=True)
def check_server_connected(self, serv):
# Fetch tenant-network from where vm deployed
serv_net = list(serv['addresses'].keys())[0]
serv_addr = serv['addresses'][serv_net][0]
host_ip = serv_addr['addr']
self.waitfor_host_connected(host_ip)
def create_project_network_subnet(self,
name_prefix='dhcp-project'):
network_name = data_utils.rand_name(name_prefix)
network, subnet = self.create_network_subnet(
name=network_name)
return (network['id'], network, subnet)
def dhcp_121_metadata_hostroutes_check_on_vm_nsxv(self, vm_env):
self.serv_fip = vm_env['fip1']['floating_ip_address']
username, password = self.get_image_userpass()
# Connect to instance launched using ssh lib
client = remote_client.RemoteClient(self.serv_fip, username=username,
password=password)
# Executes route over launched instance
cmd = ('/sbin/route -n')
out_data = client.exec_command(cmd)
self.assertIn(Metadataserver_ip, out_data)
LOG.info("Metadata routes available on vm")
cmd = ('wget http://169.254.169.254 -O sample.txt')
client.exec_command(cmd)
cmd = ('cat sample.txt')
out_data = client.exec_command(cmd)
# Check metadata server inforamtion available or not
self.assertIn('latest', out_data)
LOG.info("metadata server is acessible")
# Fetch dhcp edge infor from nsx-v
exc_edge = self.vsm.get_dhcp_edge_info()
self.assertIsNotNone(exc_edge)
# Fetch host-route and metadata info from nsx-v
dhcp_options_info = {}
dhcp_options_info = \
exc_edge['staticBindings']['staticBindings'][0]['dhcpOptions']
# Check Host Route information avaialable at beckend
self.assertIn(
Metadataserver_ip,
dhcp_options_info['option121'][
'staticRoutes'][0]['destinationSubnet'])
# Storing sec-group, network, subnet, router, server info in dict
project_dict = dict(security_group=vm_env['security_group'],
network=vm_env['network'], subnet=vm_env['subnet'],
router=vm_env['router'],
client_mgr=vm_env['client_mgr'],
serv1=vm_env['serv1'], fip1=vm_env['fip1'])
return project_dict
def dhcp_121_hostroutes_clear(self, vm_env):
# Fetch next hop information from tempest.conf
next_hop = CONF.network.project_network_cidr
self.nexthop_host_route = next_hop.rsplit('.', 1)[0]
# Floating-ip of VM
self.serv_fip = vm_env['fip1']['floating_ip_address']
username, password = self.get_image_userpass()
subnet_id = vm_env['subnet']['id']
subnet_info = self.subnets_client.show_subnet(subnet_id)
self.nexthop1 = subnet_info['subnet']['gateway_ip']
# Update subnet with host routes
public_net_cidr = CONF.network.public_network_cidr
_subnet_data = {'host_routes': [{'destination': '10.20.0.0/32',
'nexthop': '10.100.1.1'}],
'new_host_routes': [{'destination': public_net_cidr,
'nexthop': self.nexthop1}]}
new_host_routes = _subnet_data['new_host_routes']
kwargs = {'host_routes': new_host_routes}
new_name = "New_subnet"
# Update subnet with host-route info
self.subnets_client.update_subnet(
subnet_id, name=new_name, **kwargs)
# Connect to instance launched using ssh lib
client = remote_client.RemoteClient(self.serv_fip, username=username,
password=password)
# Executes route over instance launched
fixed_ip = vm_env['fip1']['fixed_ip_address']
client._renew_lease_udhcpc(fixed_ip)
cmd = ('/sbin/route -n')
out_data = client.exec_command(cmd)
self.assertIn(
_subnet_data['new_host_routes'][0]['nexthop'], out_data)
self.assertIn(self.nexthop_host_route, out_data)
LOG.info("Host routes available on vm")
# Check Host route info at beckend
exc_edge = self.vsm.get_dhcp_edge_info()
self.assertIsNotNone(exc_edge)
# Fetch host-route and metadata info from nsx-v
dhcp_options_info = {}
dhcp_options_info = exc_edge['staticBindings']['staticBindings'][0][
'dhcpOptions']['option121']['staticRoutes']
# Check Host Route information avaialable at beckend
for destination_net in dhcp_options_info:
dest = _subnet_data['new_host_routes'][0]['destination']
dest_subnet = destination_net['destinationSubnet']
dest_router = destination_net['router']
if (dest in dest_subnet and self.nexthop1 in dest_router):
LOG.info("Host routes available on nsxv")
# Update subnet with no host-routes
_subnet_data1 = {'new_host_routes': []}
new_host_routes = _subnet_data1['new_host_routes']
kwargs = {'host_routes': new_host_routes}
new_name = "New_subnet"
self.subnets_client.update_subnet(
subnet_id, name=new_name, **kwargs)
# Executes route over instance launched
fixed_ip = vm_env['fip1']['fixed_ip_address']
client._renew_lease_udhcpc(fixed_ip)
cmd = ('/sbin/route -n')
out_data = client.exec_command(cmd)
self.assertIsNotNone(out_data)
# Check Host routes on VM shouldn't be avialable
self.assertNotIn(
_subnet_data['new_host_routes'][0]['destination'], out_data)
# Check Host-routes at beckend after deletion
exc_edge = self.vsm.get_dhcp_edge_info()
self.assertIsNotNone(exc_edge)
dhcp_options_info = []
dhcp_options_info = exc_edge['staticBindings']['staticBindings'][0][
'dhcpOptions']['option121']['staticRoutes']
# Check Host Route information avaialable at beckend
for destination_net in dhcp_options_info:
if (_subnet_data['new_host_routes'][0]['destination']
not in destination_net['destinationSubnet']):
LOG.info("Host routes not available on nsxv")
project_dict = dict(security_group=vm_env['security_group'],
network=vm_env['network'], subnet=vm_env['subnet'],
router=vm_env['router'],
client_mgr=vm_env['client_mgr'],
serv1=vm_env['serv1'], fip1=vm_env['fip1'])
return project_dict
def create_project_network_subnet_with_cidr(self,
name_prefix='dhcp-project',
cidr=None):
network_name = data_utils.rand_name(name_prefix)
network, subnet = self.create_network_subnet_with_cidr(
name=network_name, cidr=cidr)
return (network, subnet)
def create_port(self, network_id):
port_client = self.manager.ports_client
return HELO.create_port(self, network_id=network_id,
client=port_client)
def create_network_subnet_with_cidr(self, client_mgr=None,
tenant_id=None, name=None, cidr=None):
client_mgr = client_mgr or self.manager
tenant_id = tenant_id
name = name or data_utils.rand_name('topo-deploy-network')
net_network = self.create_network(
client=client_mgr.networks_client,
tenant_id=tenant_id, name=name)
net_subnet = self.create_subnet(
client=client_mgr.subnets_client,
network=net_network,
cidr=cidr, name=net_network['name'])
return net_network, net_subnet
def setup_vm_enviornment(self, client_mgr, t_id,
check_outside_world=True,
cidr_offset=0):
t_network, t_subnet, t_router = self.setup_project_network(
self.public_network_id, namestart=("deploy-%s-dhcp" % t_id),
cidr_offset=1)
t_security_group = self._create_security_group(
security_groups_client=self.security_groups_client,
security_group_rules_client=self.security_group_rules_client,
namestart='adm')
username, password = self.get_image_userpass()
security_groups = [{'name': t_security_group['id']}]
t_serv1 = self.create_server_on_network(
t_network, security_groups,
image=self.get_server_image(),
flavor=self.get_server_flavor(),
name=t_network['name'])
self.check_server_connected(t_serv1)
t_floatingip = self.create_floatingip_for_server(
t_serv1, client_mgr=self.admin_manager)
msg = ("Associate t_floatingip[%s] to server[%s]"
% (t_floatingip, t_serv1['name']))
self._check_floatingip_connectivity(
t_floatingip, t_serv1, should_connect=True, msg=msg)
vm_enviornment = dict(security_group=t_security_group,
network=t_network, subnet=t_subnet,
router=t_router, client_mgr=client_mgr,
serv1=t_serv1, fip1=t_floatingip)
return vm_enviornment
class TestDhcpMetadata(TestDHCP121BasicOps):
@test.attr(type='nsxv')
@decorators.idempotent_id('95d06aba-895f-47f8-b47d-ae48c6853a85')
def test_dhcp_121_metadata_check_on_vm_nsxv(self):
LOG.info("Testcase DHCP-121 option metadata check on vm and "
"on nsx deploying")
self.vm_env = self.setup_vm_enviornment(self.manager, 'green', True)
self.green = self.dhcp_121_metadata_hostroutes_check_on_vm_nsxv(
self.vm_env)
LOG.info("Testcase DHCP-121 option metadata check on vm and on "
"nsx completed")
class TestDhcpHostroutesClear(TestDHCP121BasicOps):
@test.attr(type='nsxv')
@decorators.idempotent_id('6bec6eb4-8632-493d-a895-a3ee87cb3002')
def test_dhcp_121_hostroutes_clear(self):
LOG.info("Testcase DHCP-121 option host routes clear deploying")
self.vm_env = self.setup_vm_enviornment(self.manager, 'green', True)
self.green = self.dhcp_121_hostroutes_clear(self.vm_env)
LOG.info("Testcase DHCP-121 option host routes clear completed")
class TestDhcpNegative(TestDHCP121BasicOps):
@test.attr(type='nsxv')
@decorators.idempotent_id('a58dc6c5-9f28-4184-baf7-37ded52593c4')
def test_dhcp121_negative_test(self):
LOG.info("Testcase DHCP-121 option negative test deploying")
t_net_id, t_network, t_subnet =\
self.create_project_network_subnet('admin')
subnet_id = t_subnet['id']
kwargs = {'enable_dhcp': 'false'}
new_name = "New_subnet"
# Update subnet with disable dhcp subnet
self.subnets_client.update_subnet(
subnet_id, name=new_name, **kwargs)
# Fetch next hop information from tempest.conf
next_hop = CONF.network.project_network_cidr
self.nexthop_host_route = next_hop.rsplit('.', 1)[0]
self.nexthop1 = self.nexthop_host_route + ".2"
username, password = self.get_image_userpass()
# Update subnet with host routes
_subnet_data = {'host_routes': [{'destination': '10.20.0.0/32',
'nexthop': '10.100.1.1'}],
'new_host_routes': [{'destination': '10.20.0.0/32',
'nexthop': self.nexthop1}]}
new_host_routes = _subnet_data['new_host_routes']
kwargs = {'host_routes': new_host_routes}
new_name = "New_subnet"
# Update subnet with host-route info
try:
self.subnets_client.update_subnet(
subnet_id, name=new_name, **kwargs)
except exceptions.BadRequest:
e = sys.exc_info()[0].__dict__['message']
if (e == "Bad request"):
LOG.info("Invalid input for operation: "
"Host routes can only be supported when "
"DHCP is enabled")
pass
subnet_id = t_subnet['id']
kwargs = {'enable_dhcp': 'true'}
new_name = "New_subnet"
# Update subnet with disable dhcp subnet
self.subnets_client.update_subnet(
subnet_id, name=new_name, **kwargs)
# Update subnet with host routes
_subnet_data = {'host_routes': [{'destination': '10.20.0.0/32',
'nexthop': '10.100.1.1'}],
'new_host_routes': [{'destination': '10.20.0.0/32',
'nexthop': self.nexthop1}]}
new_host_routes = _subnet_data['new_host_routes']
kwargs = {'host_routes': new_host_routes}
new_name = "Subnet_host_routes"
# Update subnet with host-route info
self.subnets_client.update_subnet(
subnet_id, name=new_name, **kwargs)
# Disable dhcp subnet
kwargs = {'enable_dhcp': 'false'}
# Update subnet with disable dhcp subnet
try:
self.subnets_client.update_subnet(
subnet_id, name=new_name, **kwargs)
except exceptions.BadRequest:
e = sys.exc_info()[0].__dict__['message']
if (e == "Bad request"):
LOG.info("Can't disable DHCP while using host routes")
pass
LOG.info("Testcase DHCP-121 option negative test completed")
class TestDhcpMultiHostRoute(TestDHCP121BasicOps):
@test.attr(type='nsxv')
@decorators.idempotent_id('c3ca96d7-b704-4d94-b42d-e7bae94b82cd')
def test_dhcp121_multi_host_route(self):
LOG.info("Testcase DHCP-121 option multi host routes deploying")
t_net_id, t_network, t_subnet =\
self.create_project_network_subnet('admin')
# Fetch next hop information from tempest.conf
next_hop = CONF.network.project_network_cidr
self.nexthop_host_route = next_hop.rsplit('.', 1)[0]
self.nexthop1 = self.nexthop_host_route + ".2"
# Update subnet with host routes
_subnet_data = {'host_routes': [{'destination': '10.20.0.0/32',
'nexthop': '10.100.1.1'}],
'new_host_routes': [{'destination': '10.20.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.21.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.22.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.23.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.24.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.25.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.26.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.27.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.28.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.29.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.30.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.31.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.32.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.33.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.34.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.35.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.36.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.37.0.0/32',
'nexthop': self.nexthop1},
{'destination': '10.38.0.0/32',
'nexthop': self.nexthop1}]}
new_host_routes = _subnet_data['new_host_routes']
kwargs = {'host_routes': new_host_routes}
new_name = "New_subnet"
subnet_id = t_subnet['id']
# Update subnet with host-route info
subnet = self.subnets_client.update_subnet(
subnet_id, name=new_name, **kwargs)
'''
Above No of host-routes added are 19 so checking len of
subnet host_routes equal to 19 or not
'''
if (len(subnet['subnet']['host_routes']) == 19):
LOG.info("Multiple entries for host routes available")
LOG.info("Testcase DHCP-121 option multi host routes completed")
class TestDhcpHostRoutesBetweenVms(TestDHCP121BasicOps):
@test.attr(type='nsxv')
@decorators.idempotent_id('34e6d23f-db00-446e-8299-57ff2c0911b2')
def test_host_routes_between_vms(self):
client_mgr = self.manager
next_hop = CONF.network.project_network_cidr
ip = next_hop.rsplit('/', 1)[0]
ip2int = lambda ipstr: struct.unpack('!I', socket.inet_aton(ipstr))[0]
ss = (ip2int(ip))
int2ip = lambda n: socket.inet_ntoa(struct.pack('!I', n))
new_network_cidr = (int2ip(ss + 256))
net_mask = str(CONF.network.project_network_mask_bits)
new_network_cidr = new_network_cidr + '/' + net_mask
cidr = netaddr.IPNetwork(new_network_cidr)
self.green = self.setup_vm_enviornment(self.manager, 'green', True)
network, subnet =\
self.create_project_network_subnet_with_cidr('dhcp121-tenant',
cidr=cidr)
net_id = network['id']
# Create Port
port = self.create_port(net_id)
HELO.router_add_port_interface(self, net_router=self.green['router'],
net_port=port, client_mgr=client_mgr)
t_security_group = self._create_security_group(
security_groups_client=self.security_groups_client,
security_group_rules_client=self.security_group_rules_client,
namestart='adm')
username, password = self.get_image_userpass()
security_groups = [{'name': t_security_group['name']}]
_subnet_data = {'host_routes': [{'destination': '10.20.0.0/32',
'nexthop': '10.100.1.1'}],
'new_host_routes': [{
'destination': CONF.network.public_network_cidr,
'nexthop': port['fixed_ips'][0]['ip_address']}]}
subnet_client = client_mgr.subnets_client
subnet_id = subnet['id']
new_name = "New_subnet"
new_host_routes = _subnet_data['new_host_routes']
kwargs = {'host_routes': new_host_routes}
# Update subnet with host-route info
subnet_client.update_subnet(
subnet_id, name=new_name, **kwargs)
# launched dest vm
t_serv2 = self.create_server_on_network(
network, security_groups,
image=self.get_server_image(),
flavor=self.get_server_flavor(),
name=network['name'])
self.check_server_connected(t_serv2)
time.sleep(dmgr.WAITTIME_FOR_CONNECTIVITY)
# Connect to instance launched using ssh lib
self.serv_fip = self.green['fip1']['floating_ip_address']
username, password = self.get_image_userpass()
client = remote_client.RemoteClient(self.serv_fip, username=username,
password=password)
network_name = network['name']
dest_ip = t_serv2['addresses'][network_name][0]['addr']
# Ping dest vm from source vm
cmd = ('ping %s -c 3' % dest_ip)
out_data = client.exec_command(cmd)
desired_output = "64 bytes from %s" % dest_ip
self.assertIn(desired_output, out_data)