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 )
0 commit comments