RLTest 0.7.14__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
RLTest/redis_std.py ADDED
@@ -0,0 +1,649 @@
1
+ from __future__ import print_function
2
+
3
+ import os
4
+ import subprocess
5
+ import sys
6
+ import time
7
+ import uuid
8
+ import platform
9
+ import psutil
10
+ import signal
11
+ import redis
12
+
13
+ from .random_port import get_random_port
14
+ from .utils import Colors, wait_for_conn, fix_modules, fix_modulesArgs
15
+
16
+ MASTER = 'master'
17
+ SLAVE = 'slave'
18
+
19
+
20
+ class StandardEnv(object):
21
+ def __init__(self, redisBinaryPath, port=6379, modulePath=None, moduleArgs=None, outputFilesFormat=None,
22
+ dbDirPath=None, useSlaves=False, serverId=1, password=None, libPath=None, clusterEnabled=False, decodeResponses=False,
23
+ useAof=False, useRdbPreamble=True, debugger=None, sanitizer=None, noCatch=False, noLog=False, unix=False, verbose=False, useTLS=False,
24
+ tlsCertFile=None, tlsKeyFile=None, tlsCaCertFile=None, clusterNodeTimeout=None, tlsPassphrase=None, enableDebugCommand=False, protocol=2,
25
+ terminateRetries=None, terminateRetrySecs=None, enableProtectedConfigs=False, enableModuleCommand=False, loglevel=None,
26
+ redisConfigFile=None
27
+ ):
28
+ self.uuid = uuid.uuid4().hex
29
+ self.redisBinaryPath = os.path.expanduser(redisBinaryPath) if redisBinaryPath.startswith(
30
+ '~/') else redisBinaryPath
31
+
32
+ self.modulePath = fix_modules(modulePath)
33
+ self.moduleArgs = fix_modulesArgs(self.modulePath, moduleArgs, haveSeqs=False)
34
+ self.outputFilesFormat = self.uuid + '.' + outputFilesFormat
35
+ self.useSlaves = useSlaves
36
+ self.masterServerId = serverId
37
+ self.password = password
38
+ self.clusterEnabled = clusterEnabled
39
+ self.decodeResponses = decodeResponses
40
+ self.useAof = useAof
41
+ self.useRdbPreamble = useRdbPreamble
42
+ self.envIsUp = False
43
+ self.debugger = debugger
44
+ self.sanitizer = sanitizer
45
+ self.noCatch = noCatch
46
+ self.noLog = noLog
47
+ self.loglevel = loglevel
48
+ self.environ = os.environ.copy()
49
+ self.useUnix = unix
50
+ self.dbDirPath = dbDirPath
51
+ self.masterProcess = None
52
+ self.masterStdout = None
53
+ self.masterStderr = None
54
+ self.masterExitCode = None
55
+ self.slaveProcess = None
56
+ self.slaveStdout = None
57
+ self.slaveStderr = None
58
+ self.slaveExitCode = None
59
+ self.verbose = verbose
60
+ self.role = MASTER
61
+ self.useTLS = useTLS
62
+ self.tlsCertFile = tlsCertFile
63
+ self.tlsKeyFile = tlsKeyFile
64
+ self.tlsCaCertFile = tlsCaCertFile
65
+ self.clusterNodeTimeout = clusterNodeTimeout
66
+ self.tlsPassphrase = tlsPassphrase
67
+ self.enableDebugCommand = enableDebugCommand
68
+ self.enableModuleCommand = enableModuleCommand
69
+ self.enableProtectedConfigs = enableProtectedConfigs
70
+ self.protocol = protocol
71
+ self.terminateRetries = terminateRetries
72
+ self.terminateRetrySecs = terminateRetrySecs
73
+ self.redisConfigFile = redisConfigFile
74
+
75
+ if port > 0:
76
+ self.port = port
77
+ self.slavePort = port + 1 if self.useSlaves else 0
78
+ elif port == 0:
79
+ self.port = get_random_port()
80
+ self.slavePort = get_random_port() if self.useSlaves else 0
81
+ else:
82
+ self.port = -1
83
+ self.slavePort = -1
84
+
85
+ if self.has_interactive_debugger and serverId > 1:
86
+ assert self.noCatch and not self.useSlaves and not self.clusterEnabled
87
+
88
+ if self.useUnix:
89
+ if self.clusterEnabled:
90
+ raise ValueError('Unix sockets cannot be used with cluster mode')
91
+ self.port = -1
92
+
93
+ if self.useTLS:
94
+ if self.useUnix:
95
+ raise ValueError('Unix sockets cannot be used with TLS enabled mode')
96
+ if self.tlsCertFile is None:
97
+ raise ValueError('When useTLS option is True tlsCertFile must be defined')
98
+ if os.path.isfile(self.tlsCertFile) is False:
99
+ raise ValueError(
100
+ 'When useTLS option is True tlsCertFile must exist. specified path {}'.format(self.tlsCertFile))
101
+ if self.tlsKeyFile is None:
102
+ raise ValueError('When useTLS option is True tlsKeyFile must be defined')
103
+ if os.path.isfile(self.tlsKeyFile) is False:
104
+ raise ValueError(
105
+ 'When useTLS option is True tlsKeyFile must exist. specified path {}'.format(self.tlsKeyFile))
106
+ if self.tlsCaCertFile is None:
107
+ raise ValueError('When useTLS option is True tlsCaCertFile must be defined')
108
+ if not os.path.isfile(self.tlsCaCertFile):
109
+ raise ValueError(
110
+ 'When useTLS option is True tlsCaCertFile must exist. specified path {}'.format(self.tlsCaCertFile))
111
+
112
+ if libPath:
113
+ self.libPath = os.path.expanduser(libPath) if libPath.startswith('~/') else libPath
114
+ else:
115
+ self.libPath = None
116
+ if self.libPath:
117
+ if 'LD_LIBRARY_PATH' in self.environ.keys():
118
+ self.environ['LD_LIBRARY_PATH'] = self.libPath + ":" + self.environ['LD_LIBRARY_PATH']
119
+ else:
120
+ self.environ['LD_LIBRARY_PATH'] = self.libPath
121
+
122
+ self.masterCmdArgs = self.createCmdArgs(MASTER)
123
+ self.masterOSEnv = self.createCmdOSEnv(MASTER)
124
+ if self.useSlaves:
125
+ self.slaveServerId = serverId + 1
126
+ self.slaveCmdArgs = self.createCmdArgs(SLAVE)
127
+ self.slaveOSEnv = self.createCmdOSEnv(SLAVE)
128
+
129
+ self.envIsHealthy = True
130
+
131
+ def _getFileName(self, role, suffix):
132
+ return (self.outputFilesFormat + suffix) % (
133
+ 'master-%d' % self.masterServerId if role == MASTER else 'slave-%d' % self.slaveServerId)
134
+
135
+ def _getValgrindFilePath(self, role):
136
+ return os.path.join(self.dbDirPath, self._getFileName(role, '.valgrind.log'))
137
+
138
+ def getMasterPort(self):
139
+ return self.port
140
+
141
+ def getPassword(self):
142
+ return self.password
143
+
144
+ def getUnixPath(self, role):
145
+ basename = '{}-{}.sock'.format(self.uuid, role)
146
+ return os.path.abspath(os.path.join(self.dbDirPath, basename))
147
+
148
+ def getTLSCertFile(self):
149
+ return os.path.abspath(self.tlsCertFile)
150
+
151
+ def getTLSKeyFile(self):
152
+ return os.path.abspath(self.tlsKeyFile)
153
+
154
+ def getTLSCACertFile(self):
155
+ return os.path.abspath(self.tlsCaCertFile)
156
+
157
+ @property
158
+ def has_interactive_debugger(self):
159
+ return self.debugger and self.debugger.is_interactive
160
+
161
+ def _getRedisVersion(self):
162
+ options = {
163
+ 'stderr': subprocess.PIPE,
164
+ 'stdin': subprocess.PIPE,
165
+ 'stdout': subprocess.PIPE,
166
+ }
167
+ p = subprocess.Popen(args=[self.redisBinaryPath, '--version'], **options)
168
+ while p.poll() is None:
169
+ time.sleep(0.1)
170
+ exit_code = p.poll()
171
+ if exit_code != 0:
172
+ raise Exception('Could not extract Redis version')
173
+ out, err = p.communicate()
174
+ out = out.decode('utf-8')
175
+ v = out[out.find("v=") + 2:out.find("sha=") - 1].split('.')
176
+ return int(v[0]) * 10000 + int(v[1]) * 100 + int(v[2])
177
+
178
+ def createCmdArgs(self, role):
179
+ cmdArgs = []
180
+ if self.debugger:
181
+ cmdArgs += self.debugger.generate_command(self._getValgrindFilePath(role) if not self.noCatch else None)
182
+
183
+ cmdArgs += [self.redisBinaryPath]
184
+
185
+ if self.redisConfigFile:
186
+ cmdArgs += [self.redisConfigFile]
187
+
188
+ if self.port > -1:
189
+ if self.useTLS:
190
+ cmdArgs += ['--port', str(0), '--tls-port', str(self.getPort(role))]
191
+ else:
192
+ cmdArgs += ['--port', str(self.getPort(role))]
193
+ else:
194
+ cmdArgs += ['--port', str(0), '--unixsocket', self.getUnixPath(role)]
195
+
196
+ if self.modulePath:
197
+ if self.moduleArgs and len(self.modulePath) != len(self.moduleArgs):
198
+ print(Colors.Bred('Number of module args sets in Env does not match number of modules'))
199
+ print(self.modulePath)
200
+ print(self.moduleArgs)
201
+ sys.exit(1)
202
+ for pos, module in enumerate(self.modulePath):
203
+ cmdArgs += ['--loadmodule', module]
204
+ if self.moduleArgs:
205
+ module_args = self.moduleArgs[pos]
206
+ if module_args:
207
+ # make sure there are no spaces within args
208
+ args = []
209
+ for arg in module_args:
210
+ if arg.strip() != '':
211
+ args += arg.split(' ')
212
+ cmdArgs += args
213
+
214
+ if self.noLog:
215
+ cmdArgs += ['--logfile', '/dev/null']
216
+ elif self.outputFilesFormat is not None and not self.noCatch:
217
+ cmdArgs += ['--logfile', self._getFileName(role, '.log')]
218
+ if self.loglevel is not None:
219
+ cmdArgs += ['--loglevel', self.loglevel]
220
+ if self.outputFilesFormat is not None:
221
+ cmdArgs += ['--dbfilename', self._getFileName(role, '.rdb')]
222
+ if role == SLAVE:
223
+ cmdArgs += ['--slaveof', 'localhost', str(self.port)]
224
+ if self.password:
225
+ cmdArgs += ['--masterauth', self.password]
226
+ if self.password:
227
+ cmdArgs += ['--requirepass', self.password]
228
+ if self.clusterEnabled and role is not SLAVE:
229
+ # creating .cluster.conf in /tmp as lock fails on NFS
230
+ cmdArgs += ['--cluster-enabled', 'yes', '--cluster-config-file', '/tmp/' + self._getFileName(role, '.cluster.conf'),
231
+ '--cluster-node-timeout', '5000' if self.clusterNodeTimeout is None else str(self.clusterNodeTimeout)]
232
+ if self.useTLS:
233
+ cmdArgs += ['--tls-cluster', 'yes']
234
+ if self.useAof:
235
+ cmdArgs += ['--appendonly', 'yes']
236
+ cmdArgs += ['--appendfilename', self._getFileName(role, '.aof')]
237
+ if not self.useRdbPreamble:
238
+ cmdArgs += ['--aof-use-rdb-preamble', 'no']
239
+ if self.useTLS:
240
+ cmdArgs += ['--tls-cert-file', self.getTLSCertFile()]
241
+ cmdArgs += ['--tls-key-file', self.getTLSKeyFile()]
242
+ cmdArgs += ['--tls-ca-cert-file', self.getTLSCACertFile()]
243
+ if self.tlsPassphrase:
244
+ cmdArgs += ['--tls-key-file-pass', self.tlsPassphrase]
245
+
246
+ cmdArgs += ['--tls-replication', 'yes']
247
+
248
+ if self._getRedisVersion() > 70000:
249
+ if self.enableDebugCommand:
250
+ cmdArgs += ['--enable-debug-command', 'yes']
251
+ if self.enableProtectedConfigs:
252
+ cmdArgs += ['--enable-protected-configs', 'yes']
253
+ if self.enableModuleCommand:
254
+ cmdArgs += ['--enable-module-command', 'yes']
255
+ return cmdArgs
256
+
257
+ def createCmdOSEnv(self, role):
258
+ if self.sanitizer != 'addr' and self.sanitizer != 'address':
259
+ return self.environ
260
+ osenv = self.environ.copy()
261
+ san_log = self._getFileName(role, '.asan.log')
262
+ asan_options = osenv.get("ASAN_OPTIONS")
263
+ osenv["ASAN_OPTIONS"] = "{OPT}:log_path={DIR}".format(OPT=asan_options, DIR=san_log)
264
+ return osenv
265
+
266
+ def waitForRedisToStart(self, con, proc):
267
+ wait_for_conn(con, proc, retries=1000 if self.debugger else 200)
268
+ self._waitForAOFChild(con)
269
+
270
+ def getPid(self, role):
271
+ return self.masterProcess.pid if role == MASTER else self.slaveProcess.pid
272
+
273
+ def getPort(self, role):
274
+ return self.port if role == MASTER else self.slavePort
275
+
276
+ def getServerId(self, role):
277
+ return self.masterServerId if role == MASTER else self.slaveServerId
278
+
279
+ def _printEnvData(self, prefix='', role=MASTER):
280
+ print(Colors.Yellow(prefix + 'pid: %d' % (self.getPid(role))))
281
+ if self.useUnix:
282
+ print(Colors.Yellow(prefix + 'unix_socket_path: %s' % (self.getUnixPath(role))))
283
+ else:
284
+ print(Colors.Yellow(prefix + 'port: %d' % (self.getPort(role))))
285
+ print(Colors.Yellow(prefix + 'binary path: %s' % (self.redisBinaryPath)))
286
+ print(Colors.Yellow(prefix + 'server id: %d' % (self.getServerId(role))))
287
+ print(Colors.Yellow(prefix + 'using debugger: {}'.format(bool(self.debugger))))
288
+ if self.modulePath:
289
+ print(Colors.Yellow(prefix + 'module: %s' % (self.modulePath)))
290
+ if self.moduleArgs:
291
+ print(Colors.Yellow(prefix + 'module args: %s' % (self.moduleArgs)))
292
+ if self.outputFilesFormat:
293
+ print(Colors.Yellow(prefix + 'log file: %s' % (self._getFileName(role, '.log'))))
294
+ print(Colors.Yellow(prefix + 'db file name: %s' % self._getFileName(role, '.rdb')))
295
+ if self.dbDirPath:
296
+ print(Colors.Yellow(prefix + 'db dir path: %s' % (self.dbDirPath)))
297
+ if self.libPath:
298
+ print(Colors.Yellow(prefix + 'library path: %s' % (self.libPath)))
299
+ if self.useTLS:
300
+ print(Colors.Yellow(prefix + 'TLS Cert File: %s' % (self.getTLSCertFile())))
301
+ print(Colors.Yellow(prefix + 'TLS Key File: %s' % (self.getTLSKeyFile())))
302
+ print(Colors.Yellow(prefix + 'TLS CA Cert File: %s' % (self.getTLSCACertFile())))
303
+
304
+ def printEnvData(self, prefix=''):
305
+ print(Colors.Yellow(prefix + 'master:'))
306
+ self._printEnvData(prefix + '\t', MASTER)
307
+ if self.useSlaves:
308
+ print(Colors.Yellow(prefix + 'slave:'))
309
+ self._printEnvData(prefix + '\t', SLAVE)
310
+
311
+ def getInformationBeforeDispose(self):
312
+ res = {}
313
+ instances = [(MASTER, self.getConnection(), self.masterProcess)]
314
+ if self.useSlaves:
315
+ instances.append((SLAVE, self.getSlaveConnection(), self.slaveProcess))
316
+ for role, conn, proc in instances:
317
+ info = None
318
+ try:
319
+ info = conn.execute_command('info', 'everything')
320
+ except redis.exceptions.RedisError:
321
+ pass
322
+ res[role] = {
323
+ 'info': info
324
+ }
325
+ return res
326
+
327
+ def getInformationAfterDispose(self):
328
+ res = {}
329
+ instances = [(MASTER, self.masterStdout, self.masterStderr)]
330
+ if self.useSlaves:
331
+ instances.append((SLAVE, self.slaveStdout, self.slaveStderr))
332
+ for role, stdout, stderr in instances:
333
+ stdoutStr = None
334
+ stderrStr = None
335
+ logs = None
336
+ try:
337
+ stdoutStr = stdout.read().decode('utf8')
338
+ except (NameError, AttributeError):
339
+ pass
340
+
341
+ try:
342
+ stderrStr = stderr.read().decode('utf8')
343
+ except (NameError, AttributeError):
344
+ pass
345
+
346
+ try:
347
+ with open(os.path.join(self.dbDirPath, self._getFileName(role, '.log'))) as f:
348
+ logs = f.read()
349
+ except os.FileNoteFoundError:
350
+ pass
351
+
352
+ res[role] = {
353
+ 'stdout': stdoutStr,
354
+ 'stderr': stderrStr,
355
+ 'logs': logs,
356
+ }
357
+ return res
358
+
359
+ def startEnv(self, masters = True, slaves = True):
360
+ if self.envIsUp and self.envIsHealthy:
361
+ return # env is already up
362
+ stdoutPipe = subprocess.PIPE
363
+ stderrPipe = subprocess.PIPE
364
+ stdinPipe = subprocess.PIPE
365
+ if self.noCatch:
366
+ stdoutPipe = sys.stdout
367
+ stderrPipe = sys.stderr
368
+
369
+ if self.has_interactive_debugger:
370
+ stdinPipe = sys.stdin
371
+
372
+ options = {
373
+ 'stderr': stderrPipe,
374
+ 'stdin': stdinPipe,
375
+ 'stdout': stdoutPipe,
376
+ }
377
+
378
+ if self.verbose:
379
+ print(Colors.Green("Redis master command: " + ' '.join(self.masterCmdArgs)))
380
+ if masters and self.masterProcess is None:
381
+ self.masterProcess = subprocess.Popen(args=self.masterCmdArgs, env=self.masterOSEnv, cwd=self.dbDirPath,
382
+ **options)
383
+ time.sleep(0.1)
384
+ if self._isAlive(self.masterProcess):
385
+ con = self.getConnection()
386
+ self.waitForRedisToStart(con, self.masterProcess)
387
+ else:
388
+ self.masterProcess = None
389
+ if self.useSlaves and slaves and self.slaveProcess is None:
390
+ if self.verbose:
391
+ print(Colors.Green("Redis slave command: " + ' '.join(self.slaveCmdArgs)))
392
+ self.slaveProcess = subprocess.Popen(args=self.slaveCmdArgs, env=self.slaveOSEnv, cwd=self.dbDirPath,
393
+ **options)
394
+ time.sleep(0.1)
395
+ if self._isAlive(self.slaveProcess):
396
+ con = self.getSlaveConnection()
397
+ self.waitForRedisToStart(con, self.slaveProcess)
398
+ else:
399
+ self.slaveProcess = None
400
+
401
+ self.envIsUp = self.masterProcess is not None or self.slaveProcess is not None
402
+ self.envIsHealthy = self.masterProcess is not None and (self.slaveProcess is not None if self.useSlaves else True)
403
+
404
+ # self.masterStdout = self.masterProcess.stdout if self.masterProcess else None
405
+ # self.masterStderr = self.masterProcess.stderr if self.masterProcess else None
406
+
407
+ # if self.slaveProcess is not None:
408
+ # self.slaveStdout = self.slaveProcess.stdout if self.slaveProcess else None
409
+ # self.slaveStderr = self.slaveProcess.stderr if self.slaveProcess else None
410
+
411
+ def _isAlive(self, process):
412
+ if not process:
413
+ return False
414
+ # check if child process has terminated
415
+ if process.poll() is None:
416
+ return True
417
+ return False
418
+
419
+ def _segfault(self, role, retries=3):
420
+ process = self.masterProcess if role == MASTER else self.slaveProcess
421
+ if not self._isAlive(process):
422
+ return
423
+ for _ in range(retries):
424
+ if process.poll() is None: # None returns if the processes is not finished yet, retry until redis exits
425
+ time.sleep(1)
426
+ process.send_signal(signal.SIGSEGV)
427
+ else:
428
+ return
429
+ print(Colors.Bred('Failed killing processes with sigsegv, forcely kill the processes.'))
430
+ for _ in range(retries):
431
+ if process.poll() is None: # None returns if the processes is not finished yet, retry until redis exits
432
+ time.sleep(1)
433
+ process.kill()
434
+ else:
435
+ return
436
+ print(Colors.Bred('Failed killing processes with sigkill.'))
437
+
438
+ def stopEnvWithSegFault(self, masters = True, slaves = True):
439
+ if self.masterProcess is not None and masters is True:
440
+ self._segfault(MASTER)
441
+ if self.useSlaves and self.slaveProcess is not None and slaves is True:
442
+ self._segfault(SLAVE)
443
+
444
+ def _stopProcess(self, role):
445
+ process = self.masterProcess if role == MASTER else self.slaveProcess
446
+ serverId = self.masterServerId if role == MASTER else self.slaveServerId
447
+ if not self._isAlive(process):
448
+ if not self.has_interactive_debugger:
449
+ # on interactive debugger its expected that then process will not be alive
450
+ print('\t' + Colors.Bred('process is not alive, might have crash durring test execution, '
451
+ 'check this out. server id : %s' % str(serverId)))
452
+ if self.outputFilesFormat is not None and not self.noCatch:
453
+ self.verbose_analyse_server_log(role)
454
+ return
455
+ try:
456
+ if platform.system() == 'Darwin':
457
+ # On macOS, with lldb, killing lldb process does not terminate inferior processes
458
+ p0 = psutil.Process(pid=process.pid)
459
+ pchi = p0.children(recursive=True)
460
+ for p in pchi:
461
+ try:
462
+ p.terminate()
463
+ p.wait()
464
+ except:
465
+ pass
466
+
467
+ if self.terminateRetries is None:
468
+ # ask once, then wait for process to exit
469
+ process.terminate()
470
+ while True:
471
+ if process.poll() is None: # None returns if the processes is not finished yet, retry until redis exits
472
+ time.sleep(0.1)
473
+ else:
474
+ break
475
+ else:
476
+ # keep asking every few seconds until process has exited, otherwise kill
477
+ if self.terminateRetrySecs is None:
478
+ self.terminateRetrySecs = 1
479
+ done = False
480
+ for i in range(0, self.terminateRetries):
481
+ process.terminate()
482
+ if process.poll() is None: # None returns if the processes is not finished yet, retry until redis exits
483
+ time.sleep(self.terminateRetrySecs)
484
+ else:
485
+ done = True
486
+ break
487
+ if not done:
488
+ process.kill()
489
+
490
+ if role == MASTER:
491
+ self.masterExitCode = process.poll()
492
+ else:
493
+ self.slaveExitCode = process.poll()
494
+ except OSError as e:
495
+ print('\t' + Colors.Bred(
496
+ 'OSError caught while waiting for {0} process to end: {1}'.format(role, e.__str__())))
497
+ pass
498
+
499
+ def verbose_analyse_server_log(self, role):
500
+ path = "{0}".format(self._getFileName(role, '.log'))
501
+ if self.dbDirPath is not None:
502
+ path = "{0}/{1}".format(self.dbDirPath, self._getFileName(role, '.log'))
503
+ print('\t' + Colors.Bred('check the redis log at: {0}'.format(path)))
504
+ print('\t' + Colors.Yellow('Printing only REDIS BUG REPORT START and STACK TRACE'))
505
+ with open(path) as file:
506
+ bug_report_found = False
507
+ for line in file:
508
+ if "REDIS BUG REPORT START" in line:
509
+ bug_report_found = True
510
+ if "------ INFO OUTPUT ------" in line:
511
+ break
512
+ if bug_report_found is True:
513
+ print('\t\t' + Colors.Yellow(line.rstrip()))
514
+
515
+ def stopEnv(self, masters = True, slaves = True):
516
+ if self.masterProcess is not None and masters is True:
517
+ self._stopProcess(MASTER)
518
+ self.masterProcess = None
519
+ if self.useSlaves and self.slaveProcess is not None and slaves is True:
520
+ self._stopProcess(SLAVE)
521
+ self.slaveProcess = None
522
+ self.envIsUp = self.masterProcess is not None or self.slaveProcess is not None
523
+ self.envIsHealthy = self.masterProcess is not None and (self.slaveProcess is not None if self.useSlaves else True)
524
+
525
+ def _getConnection(self, role):
526
+ if self.useUnix:
527
+ return redis.StrictRedis(unix_socket_path=self.getUnixPath(role),
528
+ password=self.password, decode_responses=self.decodeResponses, protocol=self.protocol)
529
+ elif self.useTLS:
530
+ return redis.StrictRedis('localhost', self.getPort(role),
531
+ password=self.password,
532
+ ssl=True,
533
+ ssl_password=self.tlsPassphrase,
534
+ ssl_keyfile=self.getTLSKeyFile(),
535
+ ssl_certfile=self.getTLSCertFile(),
536
+ ssl_cert_reqs=None,
537
+ ssl_ca_certs=self.getTLSCACertFile(),
538
+ decode_responses=self.decodeResponses,
539
+ protocol=self.protocol
540
+ )
541
+ else:
542
+ return redis.StrictRedis('localhost', self.getPort(role),
543
+ password=self.password, decode_responses=self.decodeResponses, protocol=self.protocol)
544
+
545
+ def getConnection(self, shardId=1):
546
+ return self._getConnection(MASTER)
547
+
548
+ # List containing a connection for each of the master nodes
549
+ def getOSSMasterNodesConnectionList(self):
550
+ return [self.getConnection()]
551
+
552
+ def getSlaveConnection(self):
553
+ if self.useSlaves:
554
+ return self._getConnection(SLAVE)
555
+ raise Exception('asked for slave connection but no slave exists')
556
+
557
+ # List of nodes that initial bootstrapping can be done from
558
+ def getMasterNodesList(self):
559
+ node_info = {"host": None, "port": None, "unix_socket_path": None, "password": None}
560
+ node_info["password"] = self.password
561
+ if self.useUnix:
562
+ node_info["unix_socket_path"] = self.getUnixPath(MASTER)
563
+
564
+ else:
565
+ node_info["host"] = 'localhost'
566
+ node_info["port"] = self.getPort(MASTER)
567
+ return [node_info]
568
+
569
+ def getConnectionByKey(self, key, command):
570
+ return self.getConnection()
571
+
572
+ def flush(self):
573
+ self.getConnection().flushall()
574
+
575
+ def _waitForAOFChild(self, con):
576
+ import time
577
+ # Wait until file is available
578
+ while True:
579
+ info = con.info('persistence')
580
+ if info['aof_rewrite_scheduled'] or info['aof_rewrite_in_progress']:
581
+ time.sleep(0.1)
582
+ else:
583
+ break
584
+
585
+ def dumpAndReload(self, restart=False, shardId=None, timeout_sec=0):
586
+ conns = []
587
+ conns.append(self.getConnection())
588
+ if self.useSlaves:
589
+ conns.append(self.getSlaveConnection())
590
+ if restart:
591
+ for con in conns:
592
+ self._waitForAOFChild(con)
593
+ con.bgrewriteaof()
594
+ self._waitForAOFChild(con)
595
+
596
+ self.stopEnv()
597
+ self.startEnv()
598
+ else:
599
+ [con.save() for con in conns]
600
+ try:
601
+ # Given we've already saved on the prior step, there is no need to SAVE again on the DEBUG RELOAD
602
+ [con.execute_command('DEBUG', 'RELOAD', 'NOSAVE') for con in conns]
603
+ except redis.RedisError as err:
604
+ raise err
605
+
606
+ def broadcast(self, *cmd):
607
+ try:
608
+ self.getConnection().execute_command(*cmd)
609
+ except Exception as e:
610
+ print(e)
611
+
612
+ def checkExitCode(self):
613
+ ret = True
614
+
615
+ if self.masterExitCode != 0:
616
+ print('\t' + Colors.Bred('bad exit code for serverId %s' % str(self.masterServerId)))
617
+ ret = False
618
+ if self.useSlaves and (self.slaveExitCode is None or self.slaveExitCode != 0):
619
+ print('\t' + Colors.Bred('bad exit code for serverId %s' % str(self.slaveServerId)))
620
+ ret = False
621
+ return ret
622
+
623
+ def isUp(self):
624
+ return self.envIsUp
625
+
626
+ def isHealthy(self):
627
+ return self.envIsHealthy
628
+
629
+ def isUnixSocket(self):
630
+ return self.useUnix
631
+
632
+ def isTcp(self):
633
+ return not (self.useUnix)
634
+
635
+ def isTLS(self):
636
+ return self.useTLS
637
+
638
+ def exists(self, val):
639
+ return self.getConnection().exists(val)
640
+
641
+ def hmset(self, *args):
642
+ return self.getConnection().hmset(*args)
643
+
644
+ def keys(self, reg):
645
+ return self.getConnection().keys(reg)
646
+
647
+ def setTerminateRetries(self, retries=3, seconds=1):
648
+ self.terminateRetries = retries
649
+ self.terminateRetrySecs = seconds