11
11
# - Refactor calls to COUNTERS_DB to reduce redundancy
12
12
# - Cache DB queries to reduce # of expensive queries
13
13
14
+ import click
14
15
import json
15
- import argparse
16
16
import os
17
17
import socket
18
18
import sys
19
19
20
20
from collections import OrderedDict
21
21
from natsort import natsorted
22
22
from tabulate import tabulate
23
+ from sonic_py_common import multi_asic
24
+ from utilities_common .general import load_db_config
25
+ import utilities_common .multi_asic as multi_asic_util
23
26
24
27
# mock the redis for unit test purposes #
25
28
try :
28
31
test_path = os .path .join (modules_path , "tests" )
29
32
sys .path .insert (0 , modules_path )
30
33
sys .path .insert (0 , test_path )
31
- import mock_tables . dbconnector
34
+ from tests . mock_tables import dbconnector
32
35
socket .gethostname = lambda : 'sonic_drops_test'
33
36
os .getuid = lambda : 27
37
+ if os .environ ["UTILITIES_UNIT_TESTING_TOPOLOGY" ] == "multi_asic" :
38
+ import tests .mock_tables .mock_multi_asic
39
+ dbconnector .load_namespace_config ()
40
+ else :
41
+ dbconnector .load_database_config ()
34
42
except KeyError :
35
43
pass
36
44
@@ -90,30 +98,32 @@ def get_dropstat_dir():
90
98
91
99
92
100
class DropStat (object ):
93
- def __init__ (self ):
94
- self .config_db = ConfigDBConnector ()
95
- self .config_db .connect ()
96
-
97
- self .db = SonicV2Connector (use_unix_socket_path = False )
98
- self .db .connect (self .db .COUNTERS_DB )
99
- self .db .connect (self .db .ASIC_DB )
100
- self .db .connect (self .db .APPL_DB )
101
- self .db .connect (self .db .CONFIG_DB )
101
+ def __init__ (self , namespace ):
102
+ self .namespaces = multi_asic .get_namespace_list (namespace )
103
+ self .multi_asic = multi_asic_util .MultiAsic (namespace_option = namespace )
104
+ self .db = None
105
+ self .config_db = None
106
+ self .cached_namespace = None
102
107
103
108
dropstat_dir = get_dropstat_dir ()
104
109
self .port_drop_stats_file = os .path .join (dropstat_dir , 'port-stats' )
105
- self .switch_drop_stats_file = os .path .join (dropstat_dir + 'switch-stats' )
106
- self .switch_std_drop_stats_file = os .path .join (dropstat_dir , 'switch-std-drop-stats' )
110
+ self .switch_drop_stats_file = os .path .join (dropstat_dir , 'switch-stats' )
111
+ self .switch_std_drop_stats_file = os .path .join (dropstat_dir , 'switch-std-drop-stats' )
107
112
108
113
self .stat_lookup = {}
109
114
self .reverse_stat_lookup = {}
110
115
116
+ @multi_asic_util .run_on_multi_asic
111
117
def show_drop_counts (self , group , counter_type ):
112
118
"""
113
119
Prints out the current drop counts at the port-level and
114
120
switch-level.
115
121
"""
116
122
123
+ if os .environ .get ("UTILITIES_UNIT_TESTING_DROPSTAT_CLEAN_CACHE" , "0" ) == "1" :
124
+ # Temp cache needs to be cleard to avoid interference from previous test cases
125
+ UserCache ().remove ()
126
+
117
127
self .show_switch_std_drop_counts (group , counter_type )
118
128
self .show_port_drop_counts (group , counter_type )
119
129
print ('' )
@@ -124,16 +134,36 @@ class DropStat(object):
124
134
Clears the current drop counts.
125
135
"""
126
136
127
- try :
128
- json .dump (self .get_counts_table (self .gather_counters (std_port_rx_counters + std_port_tx_counters , DEBUG_COUNTER_PORT_STAT_MAP ), COUNTERS_PORT_NAME_MAP ),
129
- open (self .port_drop_stats_file , 'w+' ))
137
+ counters_port_drop = {}
138
+ counters_switch_drop = {}
139
+ counters_switch_std_drop = {}
140
+ for ns in self .namespaces :
141
+ self .config_db = multi_asic .connect_config_db_for_ns (ns )
142
+ self .db = multi_asic .connect_to_all_dbs_for_ns (ns )
143
+
144
+ counts = self .get_counts_table (self .gather_counters (std_port_rx_counters + std_port_tx_counters , DEBUG_COUNTER_PORT_STAT_MAP ), COUNTERS_PORT_NAME_MAP )
145
+ if counts :
146
+ counters_port_drop .update (counts )
147
+
130
148
counters = self .gather_counters ([], DEBUG_COUNTER_SWITCH_STAT_MAP )
131
149
if counters :
132
- json .dump (self .get_counts (counters , self .get_switch_id ()), open (self .switch_drop_stats_file , 'w+' ))
150
+ counts = self .get_counts (counters , self .get_switch_id ())
151
+ counters_switch_drop .update (counts )
133
152
134
153
counters = self .get_configured_counters (DEBUG_COUNTER_SWITCH_STAT_MAP , True )
135
154
if counters :
136
- json .dump (self .get_counts (counters , self .get_switch_id ()), open (self .switch_std_drop_stats_file , 'w+' ))
155
+ counts = self .get_counts (counters , self .get_switch_id ())
156
+ counters_switch_std_drop .update (counts )
157
+
158
+ try :
159
+ if counters_port_drop :
160
+ json .dump (counters_port_drop , open (self .port_drop_stats_file , 'w+' ))
161
+
162
+ if counters_switch_drop :
163
+ json .dump (counters_switch_drop , open (self .switch_drop_stats_file , 'w+' ))
164
+
165
+ if counters_switch_std_drop :
166
+ json .dump (counters_switch_std_drop , open (self .switch_std_drop_stats_file , 'w+' ))
137
167
except IOError as e :
138
168
print (e )
139
169
sys .exit (e .errno )
@@ -321,12 +351,13 @@ class DropStat(object):
321
351
the given object type.
322
352
"""
323
353
354
+ if self .cached_namespace != self .multi_asic .current_namespace :
355
+ self .stat_lookup = {}
356
+ self .cached_namespace = self .multi_asic .current_namespace
357
+
324
358
if not self .stat_lookup .get (object_stat_map , None ):
325
359
stats_map = self .db .get_all (self .db .COUNTERS_DB , object_stat_map )
326
- if stats_map :
327
- self .stat_lookup [object_stat_map ] = stats_map
328
- else :
329
- self .stat_lookup [object_stat_map ] = None
360
+ self .stat_lookup [object_stat_map ] = stats_map if stats_map else None
330
361
331
362
return self .stat_lookup [object_stat_map ]
332
363
@@ -457,39 +488,22 @@ class DropStat(object):
457
488
else :
458
489
return PORT_STATE_NA
459
490
460
-
461
- def main ():
462
- parser = argparse .ArgumentParser (description = 'Display drop counters' ,
463
- formatter_class = argparse .RawTextHelpFormatter ,
464
- epilog = """
465
- Examples:
466
- dropstat
467
- """ )
468
-
469
- # Version
470
- parser .add_argument ('-v' , '--version' , action = 'version' , version = '%(prog)s 1.0' )
471
-
472
- # Actions
473
- parser .add_argument ('-c' , '--command' , type = str , help = 'Desired action to perform' )
474
-
475
- # Variables
476
- parser .add_argument ('-g' , '--group' , type = str , help = 'The group of the target drop counter' , default = None )
477
- parser .add_argument ('-t' , '--type' , type = str , help = 'The type of the target drop counter' , default = None )
478
-
479
- args = parser .parse_args ()
480
-
481
- command = args .command
482
-
483
- group = args .group
484
- counter_type = args .type
485
-
486
- dcstat = DropStat ()
491
+ @click .command (help = 'Display drop counters' )
492
+ @click .option ('-c' , '--command' , required = True , help = 'Desired action to perform' ,
493
+ type = click .Choice (['clear' , 'show' ], case_sensitive = False ))
494
+ @click .option ('-g' , '--group' , default = None , help = 'The group of the target drop counter' )
495
+ @click .option ('-t' , '--type' , 'counter_type' , default = None , help = 'The type of the target drop counter' )
496
+ @click .option ('-n' , '--namespace' , help = 'Namespace name' , default = None ,
497
+ type = click .Choice (multi_asic .get_namespace_list ()))
498
+ @click .version_option (version = '1.0' )
499
+ def main (command , group , counter_type , namespace ):
500
+ load_db_config ()
501
+
502
+ dcstat = DropStat (namespace )
487
503
if command == 'clear' :
488
504
dcstat .clear_drop_counts ()
489
- elif command == 'show' :
490
- dcstat .show_drop_counts (group , counter_type )
491
505
else :
492
- print ( "Command not recognized" )
506
+ dcstat . show_drop_counts ( group , counter_type )
493
507
494
508
495
509
if __name__ == '__main__' :
0 commit comments