Skip to content

Commit e0e4d79

Browse files
committed
Add e2e test
1 parent eb55cc5 commit e0e4d79

File tree

2 files changed

+368
-2
lines changed

2 files changed

+368
-2
lines changed

test/integration/smoke/test_network.py

Lines changed: 318 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717
# under the License.
1818
""" BVT tests for Network Life Cycle
1919
"""
20+
import json
21+
2022
# Import Local Modules
2123
from marvin.codes import (FAILED, STATIC_NAT_RULE, LB_RULE,
2224
NAT_RULE, PASS)
2325
from marvin.cloudstackTestCase import cloudstackTestCase
2426
from marvin.cloudstackException import CloudstackAPIException
2527
from marvin.cloudstackAPI import rebootRouter
2628
from marvin.sshClient import SshClient
27-
from marvin.lib.utils import cleanup_resources, get_process_status, get_host_credentials
29+
from marvin.lib.utils import cleanup_resources, get_process_status, get_host_credentials, random_gen
2830
from marvin.lib.base import (Account,
2931
VirtualMachine,
3032
ServiceOffering,
@@ -37,7 +39,9 @@
3739
LoadBalancerRule,
3840
Router,
3941
NIC,
40-
Cluster)
42+
Template,
43+
Cluster,
44+
SSHKeyPair)
4145
from marvin.lib.common import (get_domain,
4246
get_free_vlan,
4347
get_zone,
@@ -58,9 +62,11 @@
5862
from ddt import ddt, data
5963
import unittest
6064
# Import System modules
65+
import os
6166
import time
6267
import logging
6368
import random
69+
import tempfile
6470

6571
_multiprocess_shared_ = True
6672

@@ -2113,3 +2119,313 @@ def test_03_destroySharedNetwork(self):
21132119
0,
21142120
"Failed to find the placeholder IP"
21152121
)
2122+
2123+
2124+
class TestSharedNetworkWithConfigDrive(cloudstackTestCase):
2125+
2126+
@classmethod
2127+
def setUpClass(cls):
2128+
cls.testClient = super(TestSharedNetworkWithConfigDrive, cls).getClsTestClient()
2129+
cls.apiclient = cls.testClient.getApiClient()
2130+
2131+
cls.services = cls.testClient.getParsedTestDataConfig()
2132+
# Get Zone, Domain and templates
2133+
cls.domain = get_domain(cls.apiclient)
2134+
cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
2135+
cls.hv = cls.testClient.getHypervisorInfo()
2136+
2137+
if cls.hv.lower() == 'simulator':
2138+
cls.skip = True
2139+
return
2140+
else:
2141+
cls.skip = False
2142+
2143+
cls._cleanup = []
2144+
2145+
template = Template.register(
2146+
cls.apiclient,
2147+
cls.services["test_templates_cloud_init"][cls.hv],
2148+
zoneid=cls.zone.id,
2149+
hypervisor=cls.hv,
2150+
)
2151+
template.download(cls.apiclient)
2152+
cls._cleanup.append(template)
2153+
2154+
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
2155+
cls.services["virtual_machine"]["template"] = template.id
2156+
cls.services["virtual_machine"]["username"] = "ubuntu"
2157+
# Create Network Offering
2158+
cls.services["shared_network_offering_configdrive"]["specifyVlan"] = "True"
2159+
cls.services["shared_network_offering_configdrive"]["specifyIpRanges"] = "True"
2160+
cls.shared_network_offering = NetworkOffering.create(cls.apiclient,
2161+
cls.services["shared_network_offering_configdrive"],
2162+
conservemode=True)
2163+
2164+
cls.isolated_network_offering = NetworkOffering.create(
2165+
cls.apiclient,
2166+
cls.services["isolated_network_offering"],
2167+
conservemode=True
2168+
)
2169+
2170+
# Update network offering state from disabled to enabled.
2171+
NetworkOffering.update(
2172+
cls.isolated_network_offering,
2173+
cls.apiclient,
2174+
id=cls.isolated_network_offering.id,
2175+
state="enabled"
2176+
)
2177+
2178+
# Update network offering state from disabled to enabled.
2179+
NetworkOffering.update(cls.shared_network_offering, cls.apiclient, state="enabled")
2180+
2181+
cls.service_offering = ServiceOffering.create(cls.apiclient, cls.services["service_offering"])
2182+
physical_network, vlan = get_free_vlan(cls.apiclient, cls.zone.id)
2183+
# create network using the shared network offering created
2184+
2185+
cls.services["shared_network"]["acltype"] = "domain"
2186+
cls.services["shared_network"]["vlan"] = vlan
2187+
cls.services["shared_network"]["networkofferingid"] = cls.shared_network_offering.id
2188+
cls.services["shared_network"]["physicalnetworkid"] = physical_network.id
2189+
2190+
cls.setSharedNetworkParams("shared_network")
2191+
cls.shared_network = Network.create(cls.apiclient,
2192+
cls.services["shared_network"],
2193+
networkofferingid=cls.shared_network_offering.id,
2194+
zoneid=cls.zone.id)
2195+
2196+
cls.isolated_network = Network.create(
2197+
cls.apiclient,
2198+
cls.services["isolated_network"],
2199+
networkofferingid=cls.isolated_network_offering.id,
2200+
zoneid=cls.zone.id
2201+
)
2202+
2203+
cls._cleanup.extend([
2204+
cls.shared_network,
2205+
cls.service_offering,
2206+
cls.shared_network,
2207+
cls.shared_network_offering,
2208+
cls.isolated_network
2209+
])
2210+
cls.tmp_files = []
2211+
cls.keypair = cls.generate_ssh_keys()
2212+
return
2213+
2214+
@classmethod
2215+
def generate_ssh_keys(cls):
2216+
"""Generates ssh key pair
2217+
2218+
Writes the private key into a temp file and returns the file name
2219+
2220+
:returns: generated keypair
2221+
:rtype: MySSHKeyPair
2222+
"""
2223+
cls.keypair = SSHKeyPair.create(
2224+
cls.apiclient,
2225+
name=random_gen() + ".pem")
2226+
2227+
cls._cleanup.append(SSHKeyPair(cls.keypair.__dict__, None))
2228+
cls.debug("Created keypair with name: %s" % cls.keypair.name)
2229+
cls.debug("Writing the private key to local file")
2230+
pkfile = tempfile.gettempdir() + os.sep + cls.keypair.name
2231+
cls.keypair.private_key_file = pkfile
2232+
cls.tmp_files.append(pkfile)
2233+
cls.debug("File path: %s" % pkfile)
2234+
with open(pkfile, "w+") as f:
2235+
f.write(cls.keypair.privatekey)
2236+
os.chmod(pkfile, 0o400)
2237+
2238+
return cls.keypair
2239+
2240+
def setUp(self):
2241+
self.apiclient = self.testClient.getApiClient()
2242+
self.dbclient = self.testClient.getDbConnection()
2243+
if self.skip:
2244+
self.skipTest("Hypervisor is simulator - skipping Test..")
2245+
self.cleanup = []
2246+
2247+
@classmethod
2248+
def tearDownClass(cls):
2249+
try:
2250+
# Cleanup resources used
2251+
cleanup_resources(cls.apiclient, cls._cleanup)
2252+
for tmp_file in cls.tmp_files:
2253+
os.remove(tmp_file)
2254+
except Exception as e:
2255+
raise Exception("Warning: Exception during cleanup : %s" % e)
2256+
return
2257+
2258+
def tearDown(self):
2259+
cleanup_resources(self.apiclient, self.cleanup)
2260+
return
2261+
2262+
@classmethod
2263+
def setSharedNetworkParams(cls, network, range=20):
2264+
2265+
# @range: range decides the endip. Pass the range as "x" if you want the difference between the startip
2266+
# and endip as "x"
2267+
# Set the subnet number of shared networks randomly prior to execution
2268+
# of each test case to avoid overlapping of ip addresses
2269+
shared_network_subnet_number = random.randrange(1, 254)
2270+
cls.services[network]["gateway"] = "172.16." + str(shared_network_subnet_number) + ".1"
2271+
cls.services[network]["startip"] = "172.16." + str(shared_network_subnet_number) + ".2"
2272+
cls.services[network]["endip"] = "172.16." + str(shared_network_subnet_number) + "." + str(range + 1)
2273+
cls.services[network]["netmask"] = "255.255.255.0"
2274+
logger.debug("Executing command '%s'" % cls.services[network])
2275+
2276+
def _mount_config_drive(self, ssh):
2277+
"""
2278+
This method is to verify whether configdrive iso
2279+
is attached to vm or not
2280+
Returns mount path if config drive is attached else None
2281+
"""
2282+
mountdir = "/root/iso"
2283+
cmd = "sudo blkid -t LABEL='config-2' " \
2284+
"/dev/sr? /dev/hd? /dev/sd? /dev/xvd? -o device"
2285+
tmp_cmd = [
2286+
'sudo bash -c "if [ ! -d {0} ]; then mkdir {0}; fi"'.format(mountdir),
2287+
"sudo umount %s" % mountdir]
2288+
self.debug("Unmounting drive from %s" % mountdir)
2289+
for tcmd in tmp_cmd:
2290+
ssh.execute(tcmd)
2291+
2292+
self.debug("Trying to find ConfigDrive device")
2293+
configDrive = ssh.execute(cmd)
2294+
if not configDrive:
2295+
self.warn("ConfigDrive is not attached")
2296+
return None
2297+
2298+
res = ssh.execute("sudo mount {} {}".format(str(configDrive[0]), mountdir))
2299+
if str(res).lower().find("read-only") > -1:
2300+
self.debug("ConfigDrive iso is mounted at location %s" % mountdir)
2301+
return mountdir
2302+
else:
2303+
return None
2304+
2305+
def _umount_config_drive(self, ssh, mount_path):
2306+
"""unmount config drive inside guest vm
2307+
2308+
:param ssh: SSH connection to the VM
2309+
:type ssh: marvin.sshClient.SshClient
2310+
:type mount_path: str
2311+
"""
2312+
ssh.execute("sudo umount -d %s" % mount_path)
2313+
# Give the VM time to unlock the iso device
2314+
time.sleep(0.5)
2315+
# Verify umount
2316+
result = ssh.execute("sudo ls %s" % mount_path)
2317+
self.assertTrue(len(result) == 0,
2318+
"After umount directory should be empty "
2319+
"but contains: %s" % result)
2320+
2321+
def _get_config_drive_data(self, ssh, file, name, fail_on_missing=True):
2322+
"""Fetches the content of a file file on the config drive
2323+
2324+
:param ssh: SSH connection to the VM
2325+
:param file: path to the file to fetch
2326+
:param name: description of the file
2327+
:param fail_on_missing:
2328+
whether the test should fail if the file is missing
2329+
:type ssh: marvin.sshClient.SshClient
2330+
:type file: str
2331+
:type name: str
2332+
:type fail_on_missing: bool
2333+
:returns: the content of the file
2334+
:rtype: str
2335+
"""
2336+
cmd = "sudo cat %s" % file
2337+
res = ssh.execute(cmd)
2338+
content = '\n'.join(res)
2339+
2340+
if fail_on_missing and "No such file or directory" in content:
2341+
self.debug("{} is not found".format(name))
2342+
self.fail("{} is not found".format(name))
2343+
2344+
return content
2345+
2346+
def _get_ip_address_output(self, ssh):
2347+
cmd = "ip address"
2348+
res = ssh.execute(cmd)
2349+
return '\n'.join(res)
2350+
2351+
@attr(tags=["advanced", "shared"], required_hardware="true")
2352+
def test_01_deployVMInSharedNetwork(self):
2353+
try:
2354+
self.virtual_machine = VirtualMachine.create(self.apiclient, self.services["virtual_machine"],
2355+
networkids=[self.shared_network.id, self.isolated_network.id],
2356+
serviceofferingid=self.service_offering.id,
2357+
keypair=self.keypair.name
2358+
)
2359+
self.cleanup.append(self.virtual_machine)
2360+
except Exception as e:
2361+
self.fail("Exception while deploying virtual machine: %s" % e)
2362+
2363+
public_ips = list_publicIP(
2364+
self.apiclient,
2365+
associatednetworkid=self.isolated_network.id
2366+
)
2367+
public_ip = public_ips[0]
2368+
FireWallRule.create(
2369+
self.apiclient,
2370+
ipaddressid=public_ip.id,
2371+
protocol=self.services["natrule"]["protocol"],
2372+
cidrlist=['0.0.0.0/0'],
2373+
startport=self.services["natrule"]["publicport"],
2374+
endport=self.services["natrule"]["publicport"]
2375+
)
2376+
2377+
nat_rule = NATRule.create(
2378+
self.apiclient,
2379+
self.virtual_machine,
2380+
self.services["natrule"],
2381+
public_ip.id
2382+
)
2383+
2384+
private_key_file_location = self.keypair.private_key_file if self.keypair else None
2385+
ssh = self.virtual_machine.get_ssh_client(ipaddress=nat_rule.ipaddress,
2386+
keyPairFileLocation=private_key_file_location, retries=5)
2387+
2388+
mount_path = self._mount_config_drive(ssh)
2389+
2390+
network_data_content = self._get_config_drive_data(ssh, mount_path + "/openstack/latest/network_data.json",
2391+
"network_data")
2392+
2393+
network_data = json.loads(network_data_content)
2394+
2395+
self._umount_config_drive(ssh, mount_path)
2396+
2397+
ip_address_output = self._get_ip_address_output(ssh)
2398+
2399+
self.assertTrue('links' in network_data, "network_data.json doesn't contain links")
2400+
self.assertTrue('networks' in network_data, "network_data.json doesn't contain networks")
2401+
self.assertTrue('services' in network_data, "network_data.json doesn't contain services")
2402+
2403+
for x in ['links', 'networks', 'services']:
2404+
self.assertTrue(x in network_data, "network_data.json doesn't contain " + x)
2405+
self.assertEqual(len(network_data[x]), 2, "network_data.json doesn't contain 2 " + x)
2406+
2407+
self.assertIn(network_data['links'][0]['ethernet_mac_address'],
2408+
[self.virtual_machine.nic[0].macaddress, self.virtual_machine.nic[1].macaddress],
2409+
"macaddress doesn't match")
2410+
self.assertIn(network_data['links'][1]['ethernet_mac_address'],
2411+
[self.virtual_machine.nic[0].macaddress, self.virtual_machine.nic[1].macaddress],
2412+
"macaddress doesn't match")
2413+
2414+
self.assertIn(network_data['networks'][0]['ip_address'],
2415+
[self.virtual_machine.nic[0].ipaddress, self.virtual_machine.nic[1].ipaddress],
2416+
"ip address doesn't match")
2417+
self.assertIn(network_data['networks'][1]['ip_address'],
2418+
[self.virtual_machine.nic[0].ipaddress, self.virtual_machine.nic[1].ipaddress],
2419+
"ip address doesn't match")
2420+
self.assertIn(network_data['networks'][0]['netmask'],
2421+
[self.virtual_machine.nic[0].netmask, self.virtual_machine.nic[1].netmask],
2422+
"netmask doesn't match")
2423+
self.assertIn(network_data['networks'][1]['netmask'],
2424+
[self.virtual_machine.nic[0].netmask, self.virtual_machine.nic[1].netmask],
2425+
"netmask doesn't match")
2426+
2427+
self.assertEqual(network_data['services'][0]['type'], 'dns', "network_data.json doesn't contain dns service")
2428+
self.assertEqual(network_data['services'][1]['type'], 'dns', "network_data.json doesn't contain dns service")
2429+
2430+
self.assertTrue(self.virtual_machine.nic[0].ipaddress in ip_address_output, "ip address doesn't match")
2431+
self.assertTrue(self.virtual_machine.nic[1].ipaddress in ip_address_output, "ip address doesn't match")

0 commit comments

Comments
 (0)