@@ -5,53 +5,54 @@ import swsssdk
5
5
import redis
6
6
import argparse
7
7
from multiprocessing import Pool
8
+ from functools import partial
8
9
9
- def ping_unix_path_single_instance ( inst_info ):
10
+ def handle_single_instance ( op , use_unix_socket , inst_info ):
10
11
inst_hostname = inst_info ['hostname' ]
11
- inst_unix_socket_path = inst_info ['unix_socket_path' ]
12
- r = redis .Redis (host = inst_hostname , unix_socket_path = inst_unix_socket_path )
13
- rsp = False
14
- msg = 'Could not connect to Redis at {}:{}: Connection refused' .format (inst_hostname , inst_unix_socket_path )
15
- try :
16
- rsp = r .ping ()
17
- except redis .exceptions .ConnectionError as e :
18
- pass
19
- return 'PONG' if rsp else msg
20
-
21
- def ping_tcp_single_instance (inst_info ):
22
- inst_hostname = inst_info ['hostname' ]
23
- inst_port = inst_info ['port' ]
24
- r = redis .Redis (host = inst_hostname , port = inst_port )
12
+ if use_unix_socket :
13
+ inst_unix_socket_path = inst_info ['unix_socket_path' ]
14
+ r = redis .Redis (host = inst_hostname , unix_socket_path = inst_unix_socket_path )
15
+ else :
16
+ inst_port = inst_info ['port' ]
17
+ r = redis .Redis (host = inst_hostname , port = inst_port )
25
18
rsp = False
26
- msg = 'Could not connect to Redis at {}:{}: Connection refused' .format (inst_hostname , inst_port )
19
+ msg = 'Could not connect to Redis at {}:{}: Connection refused' .format (inst_hostname ,
20
+ inst_unix_socket_path if use_unix_socket else inst_port )
27
21
try :
28
- rsp = r .ping ()
22
+ if op == 'PING' :
23
+ rsp = r .ping ()
24
+ elif op == 'SAVE' :
25
+ rsp = r .save ()
26
+ elif op == 'FLUSHALL' :
27
+ rsp = r .flushall ()
28
+ else :
29
+ raise ValueError ("Operation {} is not supported" .format (op ))
29
30
except redis .exceptions .ConnectionError as e :
30
31
pass
31
- return 'PONG' if rsp else msg
32
+ return None if rsp else msg
32
33
33
- def ping_all_instances (namespace , use_unix_socket = False ):
34
- ping_single_instance = ping_unix_path_single_instance
34
+ def handle_all_instances (namespace , op , use_unix_socket = False ):
35
35
# Use the tcp connectivity if namespace is local and unixsocket cmd_option is present.
36
- if namespace is None :
37
- if not use_unix_socket :
38
- ping_single_instance = ping_tcp_single_instance
36
+ if namespace is not None :
37
+ use_unix_socket = True
39
38
40
39
db_insts = swsssdk .SonicDBConfig .get_instancelist (namespace )
41
- # ping all redis instances together
42
- # TODO: if one of the ping failed, it could fail quickly and not necessary to wait all other pings
40
+ # Operate All Redis Instances in Parallel
41
+ # TODO: if one of the operations failed, it could fail quickly and not necessary to wait all other operations
43
42
p = Pool (len (db_insts ))
44
- rsps = p .map (ping_single_instance , [v for k , v in db_insts .items ()])
45
- msg = []
46
- for rsp in rsps :
47
- if rsp != 'PONG' :
48
- msg .append (rsp )
43
+ func = partial (handle_single_instance , op , use_unix_socket )
44
+ rsps = p .map (func , [v for k , v in db_insts .items ()])
45
+ msg = [rsp for rsp in rsps if rsp ]
46
+
49
47
if msg :
50
48
print ('\n ' .join (msg ))
51
49
sys .exit (1 )
52
- else :
50
+
51
+ if op == 'PING' :
53
52
print ('PONG' )
54
- sys .exit (0 )
53
+ else :
54
+ print ('OK' )
55
+ sys .exit (0 )
55
56
56
57
def execute_cmd (dbname , cmd , namespace , use_unix_socket = False ):
57
58
if namespace is None :
@@ -94,12 +95,13 @@ Example 1: sonic-db-cli -n asic0 CONFIG_DB keys \*
94
95
Example 2: sonic-db-cli -n asic2 APPL_DB HGETALL VLAN_TABLE:Vlan10
95
96
Example 3: sonic-db-cli APPL_DB HGET VLAN_TABLE:Vlan10 mtu
96
97
Example 4: sonic-db-cli -n asic3 APPL_DB EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 k1 k2 v1 v2
97
- Example 5: sonic-db-cli PING
98
- Example 6: sonic-db-cli -s PING
98
+ Example 5: sonic-db-cli PING | sonic-db-cli -s PING
99
+ Example 6: sonic-db-cli SAVE | sonic-db-cli -s SAVE
100
+ Example 7: sonic-db-cli FLUSHALL | sonic-db-cli -s FLUSHALL
99
101
""" )
100
102
parser .add_argument ('-s' , '--unixsocket' , help = "Override use of tcp_port and use unixsocket" , action = 'store_true' )
101
103
parser .add_argument ('-n' , '--namespace' , type = str , help = "Namespace string to use asic0/asic1.../asicn" , default = None )
102
- parser .add_argument ('db_or_op' , type = str , help = 'Database name Or Unary operation(only PING supported)' )
104
+ parser .add_argument ('db_or_op' , type = str , help = 'Database name Or Unary operation(only PING/SAVE/FLUSHALL supported)' )
103
105
parser .add_argument ('cmd' , nargs = '*' , type = str , help = 'Command to execute in database' )
104
106
105
107
args = parser .parse_args ()
@@ -110,11 +112,16 @@ Example 6: sonic-db-cli -s PING
110
112
swsssdk .SonicDBConfig .load_sonic_global_db_config (namespace = args .namespace )
111
113
if args .cmd :
112
114
execute_cmd (args .db_or_op , args .cmd , args .namespace , args .unixsocket )
113
- elif args .db_or_op == 'PING' :
114
- ping_all_instances (args .namespace , args .unixsocket )
115
- # TODO next PR will support 'SAVE' and 'FLUSHALL'
116
- # elif args.db_or_op == 'SAVE':
117
- # elif args.db_or_op == 'FLUSHALL':
115
+ elif args .db_or_op in ('PING' , 'SAVE' , 'FLUSHALL' ):
116
+ # redis-cli doesn't depend on database_config.json which could raise some exceptions
117
+ # sonic-db-cli catch all possible exceptions and handle it as a failure case which not return 'OK' or 'PONG'
118
+ try :
119
+ handle_all_instances (args .namespace , args .db_or_op , args .unixsocket )
120
+ except Exception as ex :
121
+ template = "An exception of type {0} occurred. Arguments:\n {1!r}"
122
+ message = template .format (type (ex ).__name__ , ex .args )
123
+ print (message , file = sys .stderr )
124
+ sys .exit (1 )
118
125
else :
119
126
parser .print_help ()
120
127
else :
0 commit comments