Skip to content

Commit c92652b

Browse files
author
Pearl Dsilva
committed
Marvin tests
1 parent e8c628e commit c92652b

File tree

5 files changed

+360
-3
lines changed

5 files changed

+360
-3
lines changed

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1870,7 +1870,7 @@ private Pair<String, Boolean> getVMNetworkDetails(NetworkVO networkVO, boolean i
18701870
String scheme = broadcastUri.getScheme();
18711871
String vlanId = Networks.BroadcastDomainType.getValue(broadcastUri);
18721872
Boolean shouldDelete = !((networkVO.getGuestType() == Network.GuestType.L2 || networkVO.getGuestType() == Network.GuestType.Isolated) &&
1873-
(scheme.equalsIgnoreCase("vlan") || scheme.equalsIgnoreCase("vxlan"))
1873+
(scheme.equalsIgnoreCase("vlan"))
18741874
&& isPersistent);
18751875
return new Pair<>(vlanId, shouldDelete);
18761876
}

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,8 @@ public Pair<NetworkGuru, NetworkVO> implementNetwork(final long networkId, final
13261326
implementNetworkElementsAndResources(dest, context, network, offering);
13271327

13281328
long dcId = dest.getDataCenter().getId();
1329-
if (network.getGuestType() == GuestType.L2 && offering.isPersistent()) {
1329+
if (network.getGuestType() == GuestType.L2 && offering.isPersistent() &&
1330+
(network.getBroadcastUri() != null && BroadcastDomainType.getSchemeValue(network.getBroadcastUri()) == BroadcastDomainType.Vlan)) {
13301331
setupPersistentNetwork(network, offering, dcId);
13311332
}
13321333
if (isSharedNetworkWithServices(network)) {
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
from marvin.cloudstackTestCase import cloudstackTestCase, unittest
19+
from marvin.lib.utils import (cleanup_resources,
20+
validateList,
21+
get_hypervisor_type, get_process_status)
22+
from marvin.lib.base import (Account,
23+
Cluster,
24+
Configurations,
25+
Host,
26+
VPC,
27+
VirtualMachine,
28+
Network,
29+
Router,
30+
ServiceOffering,
31+
NetworkOffering)
32+
from marvin.lib.common import (get_zone,
33+
get_template,
34+
verifyNetworkState,
35+
wait_for_cleanup, list_routers, list_hosts)
36+
from nose.plugins.attrib import attr
37+
from marvin.sshClient import SshClient
38+
from distutils.util import strtobool
39+
from pyVmomi import vim, vmodl
40+
from marvin.lib.vcenter import Vcenter
41+
import logging
42+
43+
logger = logging.getLogger('TestPesistentNetwork')
44+
stream_handler = logging.StreamHandler()
45+
logger.setLevel(logging.DEBUG)
46+
logger.addHandler(stream_handler)
47+
48+
49+
class TestL2PersistentNetworks(cloudstackTestCase):
50+
@classmethod
51+
def setUpClass(cls):
52+
cls.testClient = super(TestL2PersistentNetworks, cls).getClsTestClient()
53+
cls.api_client = cls.testClient.getApiClient()
54+
cls.hypervisor = cls.testClient.getHypervisorInfo()
55+
# Fill services from the external config file
56+
cls.services = cls.testClient.getParsedTestDataConfig()
57+
cls.hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][
58+
0].__dict__
59+
# Get Zone and templates
60+
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
61+
cls.template = get_template(
62+
cls.api_client,
63+
cls.zone.id,
64+
cls.services["ostype"]
65+
)
66+
67+
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
68+
cls.services["virtual_machine"]["template"] = cls.template.id
69+
cls.service_offering = ServiceOffering.create(
70+
cls.api_client,
71+
cls.services["service_offering"]
72+
)
73+
cls.l2_persistent_network_offering = cls.create_network_offering("nw_off_L2_persistent")
74+
cls.isolated_persistent_network_offering = cls.create_network_offering("nw_off_isolated_persistent")
75+
76+
# network will be deleted as part of account cleanup
77+
cls._cleanup = [
78+
cls.service_offering,
79+
cls.isolated_persistent_network_offering,
80+
cls.l2_persistent_network_offering]
81+
return
82+
83+
@classmethod
84+
def tearDownClass(cls):
85+
try:
86+
# Cleanup resources used
87+
cleanup_resources(cls.api_client, cls._cleanup)
88+
except Exception as e:
89+
raise Exception("Warning: Exception during cleanup : %s" % e)
90+
return
91+
92+
def setUp(self):
93+
self.apiclient = self.testClient.getApiClient()
94+
self.dbclient = self.testClient.getDbConnection()
95+
self.hypervisor = self.testClient.getHypervisorInfo()
96+
self.cleanup = []
97+
return
98+
99+
def tearDown(self):
100+
try:
101+
# Clean up, terminate the resources created
102+
cleanup_resources(self.apiclient, self.cleanup)
103+
self.cleanup[:] = []
104+
except Exception as e:
105+
raise Exception("Warning: Exception during cleanup : %s" % e)
106+
return
107+
108+
@classmethod
109+
def is_ssh_enabled(cls):
110+
conf = Configurations.list(cls.apiclient, name="kvm.ssh.to.agent")
111+
if not conf:
112+
return False
113+
else:
114+
return bool(strtobool(conf[0].value)) if conf[0].value else False
115+
116+
@classmethod
117+
def create_network_offering(cls, network_offering_type):
118+
network_offering = NetworkOffering.create(
119+
cls.api_client,
120+
cls.services[network_offering_type],
121+
conservemode=False
122+
)
123+
124+
# Update network offering state from disabled to enabled.
125+
NetworkOffering.update(
126+
network_offering,
127+
cls.api_client,
128+
id=network_offering.id,
129+
state="enabled")
130+
return network_offering
131+
132+
def get_ssh_client(self, ip, username, password, retries=10):
133+
""" Setup ssh client connection and return connection """
134+
try:
135+
ssh_client = SshClient(ip, 22, username, password, retries)
136+
except Exception as e:
137+
raise unittest.SkipTest("Unable to create ssh connection: " % e)
138+
139+
self.assertIsNotNone(
140+
ssh_client, "Failed to setup ssh connection to ip=%s" % ip)
141+
142+
return ssh_client
143+
144+
def list_all_hosts_in_zone(self, zone_id):
145+
hosts = Host.list(
146+
self.apiclient,
147+
type='Routing',
148+
resourcestate='Enabled',
149+
state='Up',
150+
zoneid=zone_id
151+
)
152+
return hosts
153+
154+
'''
155+
Verifies creation of bridge on KVM host
156+
'''
157+
def verify_bridge_creation(self, host, vlan_id):
158+
username = self.hostConfig["username"]
159+
password = self.hostConfig["password"]
160+
try:
161+
ssh_client = self.get_ssh_client(host.ipaddress, username, password)
162+
res = ssh_client.execute("ip addr | grep breth1-" + str(vlan_id) + " > /dev/null 2>&1; echo $?")
163+
return res[0]
164+
except Exception as e:
165+
self.fail(e)
166+
167+
'''
168+
Gets all port groups on the host
169+
'''
170+
def capture_host_portgroups(self, host):
171+
host_portgroups = []
172+
for portgroup in host.config.network.portgroup:
173+
host_portgroups.append(portgroup.spec.name)
174+
return host_portgroups
175+
176+
'''
177+
Fetches port group names based on VMware switch type - Distributed Virtual Switch(DVS) and
178+
Standard Virtual Switch(SVS)
179+
'''
180+
def get_port_group_name(self, switch_type, vlan_id, network_rate):
181+
if switch_type == 'DVS':
182+
return 'cloud.guest.' + str(vlan_id) + '.' + str(network_rate) + '.1-dvSwitch1'
183+
elif switch_type == 'SVS':
184+
return 'cloud.guest.' + str(vlan_id) + '.' + str(network_rate) + '.1-vSwitch1'
185+
else:
186+
return None
187+
188+
'''
189+
Verifies creation of port group on the Distributed vSwitch or a host in a cluster connected to
190+
a Standard vSwitch
191+
'''
192+
def verify_port_group_creation(self, vlan_id):
193+
config = self.get_vmware_dc_config(self.zone.id)
194+
vc_object = Vcenter(config[0][0], config[0][1], 'P@ssword123')
195+
dvs = vc_object.get_dvswitches()
196+
port_group_present = False
197+
if dvs is not None:
198+
port_group_name = self.get_port_group_name('DVS', vlan_id,
199+
self.isolated_persistent_network_offering.networkrate)
200+
port_group_present = port_group_name in dvs[0]['dvswitch']['portgroupNameList']
201+
202+
else:
203+
port_group_name = self.get_port_group_name('SVS', vlan_id,
204+
self.isolated_persistent_network_offering.networkrate)
205+
hosts = vc_object._get_obj([vim.HostSystem])
206+
host = hosts[0]['host']
207+
host_pg = self.capture_host_portgroups(host)
208+
port_group_present = port_group_name in host_pg
209+
return port_group_present
210+
211+
'''
212+
Fetch vmware datacenter login details
213+
'''
214+
def get_vmware_dc_config(self, zone_id):
215+
zid = self.dbclient.execute("select id from data_center where uuid='%s';" %
216+
zone_id)
217+
vmware_dc_id = self.dbclient.execute(
218+
"select vmware_data_center_id from vmware_data_center_zone_map where zone_id='%s';" %
219+
zid[0])
220+
vmware_dc_config = self.dbclient.execute(
221+
"select vcenter_host, username, password from vmware_data_center where id = '%s';" % vmware_dc_id[0])
222+
223+
return vmware_dc_config
224+
225+
'''
226+
Verify VLAN creation on specific host in a cluster
227+
'''
228+
def verify_vlan_network_creation(self, host, vlan_id):
229+
username = self.hostConfig["username"]
230+
password = self.hostConfig["password"]
231+
try:
232+
ssh_client = self.get_ssh_client(host.ipaddress, username, password)
233+
res = ssh_client.execute(
234+
"xe vlan-list | grep -x \"^\s*tag ( RO): \"" + str(vlan_id) + "> /dev/null 2>&1; echo $?")
235+
return res[0]
236+
except Exception as e:
237+
self.fail(e)
238+
239+
def verify_network_setup_on_host_per_cluster(self, hypervisor, vlan_id):
240+
clusters = Cluster.list(
241+
self.apiclient,
242+
zoneid=self.zone.id,
243+
allocationstate="Enabled",
244+
listall=True
245+
)
246+
for cluster in clusters:
247+
hosts = Host.list(self.apiclient,
248+
clusterid=cluster.id,
249+
type="Routing",
250+
state="Up",
251+
resourcestate="Enabled")
252+
host = hosts[0]
253+
if hypervisor == "xenserver":
254+
result = self.verify_vlan_network_creation(host, vlan_id)
255+
self.assertEqual(
256+
int(result),
257+
0,
258+
"Failed to find vlan on host: " + host.name + " in cluster: " + cluster.name)
259+
if hypervisor == "vmware":
260+
result = self.verify_port_group_creation(vlan_id)
261+
self.assertEqual(
262+
result,
263+
True,
264+
"Failed to find port group on hosts of cluster: " + cluster.name)
265+
266+
'''
267+
This test verifies that on creation of an Isolated network with network offering with isPersistent flag
268+
set to true the corresponding network resources are created without having to deploy a VM - VR created
269+
'''
270+
@attr(tags=["advanced", "isolated", "persistent", "network"], required_hardware="false")
271+
def test_01_isolated_persistent_network(self):
272+
network = Network.create(
273+
self.apiclient,
274+
self.services["isolated_network"],
275+
networkofferingid=self.isolated_persistent_network_offering.id,
276+
zoneid=self.zone.id)
277+
self.cleanup.append(network)
278+
networkVlan = network.vlan
279+
response = verifyNetworkState(
280+
self.apiclient,
281+
network.id,
282+
"implemented")
283+
exceptionOccured = response[0]
284+
isNetworkInDesiredState = response[1]
285+
exceptionMessage = response[2]
286+
287+
if (exceptionOccured or (not isNetworkInDesiredState)):
288+
self.fail(exceptionMessage)
289+
self.assertIsNotNone(
290+
networkVlan,
291+
"vlan must not be null for persistent network")
292+
293+
router = Router.list(self.apiclient, networkid=network.id)[0]
294+
router_host_id = router.hostid
295+
host = Host.list(self.apiclient, id=router_host_id)[0]
296+
if host.hypervisor.lower() in "kvm":
297+
result = self.verify_bridge_creation(host, networkVlan)
298+
self.assertEqual(
299+
int(result),
300+
0,
301+
"Failed to find bridge on the breth1$-{networkVlan}")
302+
elif host.hypervisor.lower() in ["xenserver", "vmware"]:
303+
self.verify_network_setup_on_host_per_cluster(host.hypervisor.lower(), networkVlan)
304+
305+
'''
306+
This test verifies that on creation of an L2 network with network offering with isPersistent flag
307+
set to true the corresponding network resources are created without having to deploy a VM - VR created
308+
'''
309+
@attr(tags=["advanced", "l2", "persistent", "network"], required_hardware="false")
310+
def test_02_L2_persistent_network(self):
311+
network_vlan = 90
312+
network = Network.create(
313+
self.apiclient,
314+
self.services["l2_network"],
315+
networkofferingid=self.l2_persistent_network_offering.id,
316+
zoneid=self.zone.id,
317+
vlan=network_vlan)
318+
self.cleanup.append(network)
319+
response = verifyNetworkState(
320+
self.apiclient,
321+
network.id,
322+
"implemented")
323+
exceptionOccured = response[0]
324+
isNetworkInDesiredState = response[1]
325+
exceptionMessage = response[2]
326+
327+
if (exceptionOccured or (not isNetworkInDesiredState)):
328+
self.fail(exceptionMessage)
329+
self.assertIsNotNone(
330+
network_vlan,
331+
"vlan must not be null for persistent network")
332+
333+
hosts = self.list_all_hosts_in_zone(self.zone.id)
334+
if self.hypervisor.lower() in "kvm":
335+
for host in hosts:
336+
result = self.verify_bridge_creation(host, network_vlan)
337+
self.assertEqual(
338+
int(result),
339+
0,
340+
"Failed to find bridge on the breth1-" + str(network_vlan))
341+
elif self.hypervisor.lower() in ["xenserver", "vmware"]:
342+
self.verify_network_setup_on_host_per_cluster(self.hypervisor.lower(), network_vlan)

tools/marvin/marvin/config/test_data.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,21 @@
306306
"StaticNat": "VirtualRouter"
307307
}
308308
},
309+
"nw_off_L2_persistent": {
310+
"name": 'Test L2 Network Offering persistent',
311+
"displaytext": 'Test L2 Network Offering persistent',
312+
"guestiptype": 'L2',
313+
"traffictype": 'GUEST',
314+
"ispersistent": 'True',
315+
"specifyVlan": 'True'
316+
},
309317
"network_offering_vlan": {
310318
"name": 'Test Network offering',
311319
"displaytext": 'Test Network offering',
312320
"guestiptype": 'Isolated',
313321
"supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding',
314322
"traffictype": 'GUEST',
315-
"specifyvlan": 'False',
323+
"specifyVlan": 'False',
316324
"availability": 'Optional',
317325
"serviceProviderList": {
318326
"Dhcp": 'VirtualRouter',
@@ -338,6 +346,10 @@
338346
"name": "Isolated Network",
339347
"displaytext": "Isolated Network"
340348
},
349+
"l2_network": {
350+
"name": "L2 Network",
351+
"displaytext": "L2 Network"
352+
},
341353
"netscaler_VPX": {
342354
"ipaddress": "10.223.240.174",
343355
"username": "nsroot",

0 commit comments

Comments
 (0)