10
10
import tarfile
11
11
import StringIO
12
12
import subprocess
13
+ from datetime import datetime
13
14
from swsscommon import swsscommon
14
15
15
16
def ensure_system (cmd ):
@@ -20,6 +21,8 @@ def ensure_system(cmd):
20
21
def pytest_addoption (parser ):
21
22
parser .addoption ("--dvsname" , action = "store" , default = None ,
22
23
help = "dvs name" )
24
+ parser .addoption ("--keeptb" , action = "store_true" , default = False ,
25
+ help = "keep testbed after test" )
23
26
24
27
class AsicDbValidator (object ):
25
28
def __init__ (self , dvs ):
@@ -110,14 +113,14 @@ def __init__(self, ctn_name, pid, i):
110
113
ensure_system ("nsenter -t %d -n ip link set arp off dev %s" % (pid , self .vifname ))
111
114
ensure_system ("nsenter -t %d -n sysctl -w net.ipv6.conf.%s.disable_ipv6=1" % (pid , self .vifname ))
112
115
113
- def __del__ (self ):
116
+ def destroy (self ):
114
117
if self .cleanup :
115
118
pids = subprocess .check_output ("ip netns pids %s" % (self .nsname ), shell = True )
116
119
if pids :
117
120
for pid in pids .split ('\n ' ):
118
121
if len (pid ) > 0 :
119
122
os .system ("kill %s" % int (pid ))
120
- os . system ("ip netns delete %s" % self .nsname )
123
+ ensure_system ("ip netns delete %s" % self .nsname )
121
124
122
125
def runcmd (self , cmd ):
123
126
return os .system ("ip netns exec %s %s" % (self .nsname , cmd ))
@@ -126,25 +129,28 @@ def runcmd_async(self, cmd):
126
129
return subprocess .Popen ("ip netns exec %s %s" % (self .nsname , cmd ), shell = True )
127
130
128
131
class DockerVirtualSwitch (object ):
129
- def __init__ (self , name = None ):
130
- self .pnames = ['fpmsyncd ' ,
131
- 'intfmgrd' ,
132
- 'intfsyncd ' ,
133
- 'neighsyncd ' ,
134
- 'orchagent ' ,
135
- 'portsyncd ' ,
136
- 'redis-server ' ,
137
- 'rsyslogd ' ,
138
- 'syncd ' ,
139
- 'teamsyncd' ,
140
- 'vlanmgrd' ,
141
- 'zebra' ]
142
- self .mount = "/var/run/redis-vs"
143
- self .redis_sock = self .mount + '/' + "redis.sock"
132
+ def __init__ (self , name = None , keeptb = False ):
133
+ self .basicd = ['redis-server ' ,
134
+ 'rsyslogd' ]
135
+ self . swssd = [ 'orchagent ' ,
136
+ 'intfmgrd ' ,
137
+ 'intfsyncd ' ,
138
+ 'neighsyncd ' ,
139
+ 'portsyncd ' ,
140
+ 'vlanmgrd ' ,
141
+ 'vrfmgrd ' ,
142
+ 'portmgrd' ]
143
+ self . syncd = [ 'syncd' ]
144
+ self . rtd = [ 'fpmsyncd' , 'zebra' ]
145
+ self .teamd = [ 'teamsyncd' , 'teammgrd' ]
146
+ self .alld = self .basicd + self . swssd + self . syncd + self . rtd + self . teamd
144
147
self .client = docker .from_env ()
145
148
146
149
self .ctn = None
147
- self .cleanup = True
150
+ if keeptb :
151
+ self .cleanup = False
152
+ else :
153
+ self .cleanup = True
148
154
if name != None :
149
155
# get virtual switch container
150
156
for ctn in self .client .containers .list ():
@@ -183,6 +189,11 @@ def __init__(self, name=None):
183
189
server = VirtualServer (self .ctn_sw .name , self .ctn_sw_pid , i )
184
190
self .servers .append (server )
185
191
192
+ # mount redis to base to unique directory
193
+ self .mount = "/var/run/redis-vs/{}" .format (self .ctn_sw .name )
194
+ os .system ("mkdir -p {}" .format (self .mount ))
195
+ self .redis_sock = self .mount + '/' + "redis.sock"
196
+
186
197
# create virtual switch container
187
198
self .ctn = self .client .containers .run ('docker-sonic-vs' , privileged = True , detach = True ,
188
199
network_mode = "container:%s" % self .ctn_sw .name ,
@@ -207,8 +218,9 @@ def destroy(self):
207
218
if self .cleanup :
208
219
self .ctn .remove (force = True )
209
220
self .ctn_sw .remove (force = True )
221
+ os .system ("rm -rf {}" .format (self .mount ))
210
222
for s in self .servers :
211
- del ( s )
223
+ s . destroy ( )
212
224
213
225
def check_ready (self , timeout = 30 ):
214
226
'''check if all processes in the dvs is ready'''
@@ -232,13 +244,17 @@ def check_ready(self, timeout=30):
232
244
233
245
# check if all processes are running
234
246
ready = True
235
- for pname in self .pnames :
247
+ for pname in self .alld :
236
248
try :
237
249
if process_status [pname ] != "RUNNING" :
238
250
ready = False
239
251
except KeyError :
240
252
ready = False
241
253
254
+ # check if start.sh exited
255
+ if process_status ["start.sh" ] != "EXITED" :
256
+ ready = False
257
+
242
258
if ready == True :
243
259
break
244
260
@@ -251,6 +267,20 @@ def check_ready(self, timeout=30):
251
267
def restart (self ):
252
268
self .ctn .restart ()
253
269
270
+ # start processes in SWSS
271
+ def start_swss (self ):
272
+ cmd = ""
273
+ for pname in self .swssd :
274
+ cmd += "supervisorctl start {}; " .format (pname )
275
+ self .runcmd (['sh' , '-c' , cmd ])
276
+
277
+ # stop processes in SWSS
278
+ def stop_swss (self ):
279
+ cmd = ""
280
+ for pname in self .swssd :
281
+ cmd += "supervisorctl stop {}; " .format (pname )
282
+ self .runcmd (['sh' , '-c' , cmd ])
283
+
254
284
def init_asicdb_validator (self ):
255
285
self .asicdb = AsicDbValidator (self )
256
286
@@ -273,6 +303,57 @@ def copy_file(self, path, filename):
273
303
self .ctn .put_archive (path , tarstr .getvalue ())
274
304
tarstr .close ()
275
305
306
+ def get_logs (self , modname = None ):
307
+ stream , stat = self .ctn .get_archive ("/var/log/" )
308
+ if modname == None :
309
+ log_dir = "log"
310
+ else :
311
+ log_dir = "log/{}" .format (modname )
312
+ os .system ("rm -rf {}" .format (log_dir ))
313
+ os .system ("mkdir -p {}" .format (log_dir ))
314
+ p = subprocess .Popen (["tar" , "--no-same-owner" , "-C" , "./{}" .format (log_dir ), "-x" ], stdin = subprocess .PIPE )
315
+ for x in stream :
316
+ p .stdin .write (x )
317
+ p .stdin .close ()
318
+ p .wait ()
319
+ if p .returncode :
320
+ raise RuntimeError ("Failed to unpack the archive." )
321
+ os .system ("chmod a+r -R log" )
322
+
323
+ def add_log_marker (self ):
324
+ marker = "=== start marker {} ===" .format (datetime .now ().isoformat ())
325
+ self .ctn .exec_run ("logger {}" .format (marker ))
326
+ return marker
327
+
328
+ def SubscribeAsicDbObject (self , objpfx ):
329
+ r = redis .Redis (unix_socket_path = self .redis_sock , db = swsscommon .ASIC_DB )
330
+ pubsub = r .pubsub ()
331
+ pubsub .psubscribe ("__keyspace@1__:ASIC_STATE:%s*" % objpfx )
332
+ return pubsub
333
+
334
+ def CountSubscribedObjects (self , pubsub , ignore = None , timeout = 10 ):
335
+ nadd = 0
336
+ ndel = 0
337
+ idle = 0
338
+ while True and idle < timeout :
339
+ message = pubsub .get_message ()
340
+ if message :
341
+ print message
342
+ if ignore :
343
+ fds = message ['channel' ].split (':' )
344
+ if fds [2 ] in ignore :
345
+ continue
346
+ if message ['data' ] == 'hset' :
347
+ nadd += 1
348
+ elif message ['data' ] == 'del' :
349
+ ndel += 1
350
+ idle = 0
351
+ else :
352
+ time .sleep (1 )
353
+ idle += 1
354
+
355
+ return (nadd , ndel )
356
+
276
357
def get_map_iface_bridge_port_id (self , asic_db ):
277
358
port_id_2_iface = self .asicdb .portoidmap
278
359
tbl = swsscommon .Table (asic_db , "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT" )
@@ -481,21 +562,20 @@ def setReadOnlyAttr(self, obj, attr, val):
481
562
482
563
ntf .send ("set_ro" , key , fvp )
483
564
484
- # start processes in SWSS
485
- def start_swss (self ):
486
- self .runcmd (['sh' , '-c' , 'supervisorctl start orchagent; supervisorctl start portsyncd; supervisorctl start intfsyncd; \
487
- supervisorctl start neighsyncd; supervisorctl start intfmgrd; supervisorctl start vlanmgrd; \
488
- supervisorctl start buffermgrd; supervisorctl start arp_update' ])
489
-
490
- # stop processes in SWSS
491
- def stop_swss (self ):
492
- self .runcmd (['sh' , '-c' , 'supervisorctl stop orchagent; supervisorctl stop portsyncd; supervisorctl stop intfsyncd; \
493
- supervisorctl stop neighsyncd; supervisorctl stop intfmgrd; supervisorctl stop vlanmgrd; \
494
- supervisorctl stop buffermgrd; supervisorctl stop arp_update' ])
495
-
496
565
@pytest .yield_fixture (scope = "module" )
497
566
def dvs (request ):
498
567
name = request .config .getoption ("--dvsname" )
499
- dvs = DockerVirtualSwitch (name )
568
+ keeptb = request .config .getoption ("--keeptb" )
569
+ dvs = DockerVirtualSwitch (name , keeptb )
500
570
yield dvs
571
+ if name == None :
572
+ dvs .get_logs (request .module .__name__ )
573
+ else :
574
+ dvs .get_logs ()
501
575
dvs .destroy ()
576
+
577
+ @pytest .yield_fixture
578
+ def testlog (request , dvs ):
579
+ dvs .runcmd ("logger === start test %s ===" % request .node .name )
580
+ yield testlog
581
+ dvs .runcmd ("logger === finish test %s ===" % request .node .name )
0 commit comments