Skip to content

Commit 42a050c

Browse files
authored
CLIENT LIST fix to allow multiple client_ids (#1563)
* CLIENT LIST fix to allow multiple client_ids Support for CLIENT KILL with the USER filter Part of #1546 * test fix
1 parent febede1 commit 42a050c

File tree

2 files changed

+32
-8
lines changed

2 files changed

+32
-8
lines changed

redis/commands.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -302,15 +302,16 @@ def client_kill(self, address):
302302
return self.execute_command('CLIENT KILL', address)
303303

304304
def client_kill_filter(self, _id=None, _type=None, addr=None,
305-
skipme=None, laddr=None):
305+
skipme=None, laddr=None, user=None):
306306
"""
307307
Disconnects client(s) using a variety of filter options
308308
:param id: Kills a client by its unique ID field
309309
:param type: Kills a client by type where type is one of 'normal',
310310
'master', 'slave' or 'pubsub'
311311
:param addr: Kills a client by its 'address:port'
312312
:param skipme: If True, then the client calling the command
313-
:param laddr: Kills a cient by its 'local (bind) address:port'
313+
:param laddr: Kills a client by its 'local (bind) address:port'
314+
:param user: Kills a client for a specific user name
314315
will not get killed even if it is identified by one of the filter
315316
options. If skipme is not provided, the server defaults to skipme=True
316317
"""
@@ -334,6 +335,8 @@ def client_kill_filter(self, _id=None, _type=None, addr=None,
334335
args.extend((b'ADDR', addr))
335336
if laddr is not None:
336337
args.extend((b'LADDR', laddr))
338+
if user is not None:
339+
args.extend((b'USER', user))
337340
if not args:
338341
raise DataError("CLIENT KILL <filter> <value> ... ... <filter> "
339342
"<value> must specify at least one filter")
@@ -346,7 +349,7 @@ def client_info(self):
346349
"""
347350
return self.execute_command('CLIENT INFO')
348351

349-
def client_list(self, _type=None, client_id=None):
352+
def client_list(self, _type=None, client_id=[]):
350353
"""
351354
Returns a list of currently connected clients.
352355
If type of client specified, only that type will be returned.
@@ -362,9 +365,11 @@ def client_list(self, _type=None, client_id=None):
362365
client_types,))
363366
args.append(b'TYPE')
364367
args.append(_type)
365-
if client_id is not None:
368+
if not isinstance(client_id, list):
369+
raise DataError("client_id must be a list")
370+
if client_id != []:
366371
args.append(b"ID")
367-
args.append(client_id)
372+
args.append(' '.join(client_id))
368373
return self.execute_command('CLIENT LIST', *args)
369374

370375
def client_getname(self):

tests/test_commands.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -321,13 +321,19 @@ def test_client_list_type(self, r):
321321
assert isinstance(clients, list)
322322

323323
@skip_if_server_version_lt('6.2.0')
324-
def test_client_list_client_id(self, r):
324+
def test_client_list_client_id(self, r, request):
325325
clients = r.client_list()
326-
client_id = clients[0]['id']
327-
clients = r.client_list(client_id=client_id)
326+
clients = r.client_list(client_id=[clients[0]['id']])
328327
assert len(clients) == 1
329328
assert 'addr' in clients[0]
330329

330+
# testing multiple client ids
331+
_get_client(redis.Redis, request, flushdb=False)
332+
_get_client(redis.Redis, request, flushdb=False)
333+
_get_client(redis.Redis, request, flushdb=False)
334+
clients_listed = r.client_list(client_id=clients[:-1])
335+
assert len(clients_listed) > 1
336+
331337
@skip_if_server_version_lt('5.0.0')
332338
def test_client_id(self, r):
333339
assert r.client_id() > 0
@@ -448,6 +454,19 @@ def test_client_kill_filter_by_laddr(self, r, r2):
448454
client_2_addr = clients_by_name['redis-py-c2'].get('laddr')
449455
assert r.client_kill_filter(laddr=client_2_addr)
450456

457+
@skip_if_server_version_lt('2.8.12')
458+
def test_client_kill_filter_by_user(self, r, request):
459+
killuser = 'user_to_kill'
460+
r.acl_setuser(killuser, enabled=True, reset=True,
461+
commands=['+get', '+set', '+select'],
462+
keys=['cache:*'], nopass=True)
463+
_get_client(redis.Redis, request, flushdb=False, username=killuser)
464+
r.client_kill_filter(user=killuser)
465+
clients = r.client_list()
466+
for c in clients:
467+
assert c['user'] != killuser
468+
r.acl_deluser(killuser)
469+
451470
@skip_if_server_version_lt('2.9.50')
452471
def test_client_pause(self, r):
453472
assert r.client_pause(1)

0 commit comments

Comments
 (0)