Skip to content

Commit 2c2d2c5

Browse files
author
v.shepard
committed
PBCKP-588 test fix test_restore_after_failover
1 parent 72e6d5d commit 2c2d2c5

File tree

5 files changed

+74
-61
lines changed

5 files changed

+74
-61
lines changed

testgres/node.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -625,9 +625,11 @@ def status(self):
625625
"-D", self.data_dir,
626626
"status"
627627
] # yapf: disable
628-
out = execute_utility(_params, self.utils_log_file)
629-
if 'no server running' in out:
628+
status_code, out, err = execute_utility(_params, self.utils_log_file, verbose=True)
629+
if 'does not exist' in err:
630630
return NodeStatus.Uninitialized
631+
elif'no server running' in out:
632+
return NodeStatus.Stopped
631633
return NodeStatus.Running
632634

633635
except ExecUtilException as e:
@@ -712,14 +714,17 @@ def start(self, params=[], wait=True):
712714
] + params # yapf: disable
713715

714716
try:
715-
execute_utility(_params, self.utils_log_file)
717+
exit_status, out, error = execute_utility(_params, self.utils_log_file, verbose=True)
718+
if 'does not exist' in error:
719+
raise Exception
720+
if 'server started' in out:
721+
self.is_started = True
716722
except Exception as e:
717723
msg = 'Cannot start node'
718724
files = self._collect_special_files()
719725
raise_from(StartNodeException(msg, files), e)
720726

721727
self._maybe_start_logger()
722-
self.is_started = True
723728
return self
724729

725730
def stop(self, params=[], wait=True):

testgres/operations/local_ops.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def exec_command(self, cmd, wait_exit=False, verbose=False,
5252
:return: The output of the subprocess.
5353
"""
5454
if isinstance(cmd, list):
55-
cmd = " ".join(cmd)
55+
cmd = ' '.join(item.decode('utf-8') if isinstance(item, bytes) else item for item in cmd)
5656
log.debug(f"Executing command: `{cmd}`")
5757

5858
if os.name == 'nt':
@@ -98,8 +98,7 @@ def exec_command(self, cmd, wait_exit=False, verbose=False,
9898

9999
# Environment setup
100100
def environ(self, var_name):
101-
cmd = f"echo ${var_name}"
102-
return self.exec_command(cmd, encoding='utf-8').strip()
101+
return os.environ.get(var_name)
103102

104103
def find_executable(self, executable):
105104
return find_executable(executable)
@@ -108,17 +107,6 @@ def is_executable(self, file):
108107
# Check if the file is executable
109108
return os.access(file, os.X_OK)
110109

111-
def add_to_path(self, new_path):
112-
pathsep = self.pathsep
113-
# Check if the directory is already in PATH
114-
path = self.environ("PATH")
115-
if new_path not in path.split(pathsep):
116-
if self.remote:
117-
self.exec_command(f"export PATH={new_path}{pathsep}{path}")
118-
else:
119-
os.environ["PATH"] = f"{new_path}{pathsep}{path}"
120-
return pathsep
121-
122110
def set_env(self, var_name, var_val):
123111
# Check if the directory is already in PATH
124112
os.environ[var_name] = var_val
@@ -128,8 +116,7 @@ def get_user(self):
128116
return getpass.getuser()
129117

130118
def get_name(self):
131-
cmd = 'python3 -c "import os; print(os.name)"'
132-
return self.exec_command(cmd).strip()
119+
return os.name
133120

134121
# Work with dirs
135122
def makedirs(self, path, remove_existing=False):

testgres/operations/os_ops.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ def is_executable(self, file):
2929
# Check if the file is executable
3030
raise NotImplementedError()
3131

32-
def add_to_path(self, new_path):
33-
raise NotImplementedError()
34-
3532
def set_env(self, var_name, var_val):
3633
# Check if the directory is already in PATH
3734
raise NotImplementedError()

testgres/operations/remote_ops.py

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@
2020
error_markers = [b'error', b'Permission denied']
2121

2222

23+
class PsUtilProcessProxy:
24+
def __init__(self, ssh, pid):
25+
self.ssh = ssh
26+
self.pid = pid
27+
28+
def kill(self):
29+
command = f"kill {self.pid}"
30+
self.ssh.exec_command(command)
31+
32+
def cmdline(self):
33+
command = f"ps -p {self.pid} -o cmd --no-headers"
34+
stdin, stdout, stderr = self.ssh.exec_command(command)
35+
cmdline = stdout.read().decode('utf-8').strip()
36+
return cmdline.split()
37+
38+
2339
class RemoteOperations(OsOperations):
2440
def __init__(self, host="127.0.0.1", hostname='localhost', port=None, ssh_key=None, username=None):
2541
super().__init__(username)
@@ -71,7 +87,7 @@ def exec_command(self, cmd: str, wait_exit=False, verbose=False, expect_error=Fa
7187
self.ssh = self.ssh_connect()
7288

7389
if isinstance(cmd, list):
74-
cmd = " ".join(cmd)
90+
cmd = ' '.join(item.decode('utf-8') if isinstance(item, bytes) else item for item in cmd)
7591
if input:
7692
stdin, stdout, stderr = self.ssh.exec_command(cmd)
7793
stdin.write(input)
@@ -140,17 +156,6 @@ def is_executable(self, file):
140156
is_exec = self.exec_command(f"test -x {file} && echo OK")
141157
return is_exec == b"OK\n"
142158

143-
def add_to_path(self, new_path):
144-
pathsep = self.pathsep
145-
# Check if the directory is already in PATH
146-
path = self.environ("PATH")
147-
if new_path not in path.split(pathsep):
148-
if self.remote:
149-
self.exec_command(f"export PATH={new_path}{pathsep}{path}")
150-
else:
151-
os.environ["PATH"] = f"{new_path}{pathsep}{path}"
152-
return pathsep
153-
154159
def set_env(self, var_name: str, var_val: str):
155160
"""
156161
Set the value of an environment variable.
@@ -243,9 +248,17 @@ def mkdtemp(self, prefix=None):
243248
raise ExecUtilException("Could not create temporary directory.")
244249

245250
def mkstemp(self, prefix=None):
246-
cmd = f"mktemp {prefix}XXXXXX"
247-
filename = self.exec_command(cmd).strip()
248-
return filename
251+
if prefix:
252+
temp_dir = self.exec_command(f"mktemp {prefix}XXXXX", encoding='utf-8')
253+
else:
254+
temp_dir = self.exec_command("mktemp", encoding='utf-8')
255+
256+
if temp_dir:
257+
if not os.path.isabs(temp_dir):
258+
temp_dir = os.path.join('/home', self.username, temp_dir.strip())
259+
return temp_dir
260+
else:
261+
raise ExecUtilException("Could not create temporary directory.")
249262

250263
def copytree(self, src, dst):
251264
if not os.path.isabs(dst):
@@ -291,7 +304,7 @@ def write(self, filename, data, truncate=False, binary=False, read_and_write=Fal
291304
data = data.encode(encoding)
292305
if isinstance(data, list):
293306
# ensure each line ends with a newline
294-
data = [s if s.endswith('\n') else s + '\n' for s in data]
307+
data = [(s if isinstance(s, str) else s.decode('utf-8')).rstrip('\n') + '\n' for s in data]
295308
tmp_file.writelines(data)
296309
else:
297310
tmp_file.write(data)
@@ -351,8 +364,8 @@ def isfile(self, remote_file):
351364

352365
def isdir(self, dirname):
353366
cmd = f"if [ -d {dirname} ]; then echo True; else echo False; fi"
354-
response = self.exec_command(cmd, encoding='utf-8')
355-
return response.strip() == "True"
367+
response = self.exec_command(cmd)
368+
return response.strip() == b"True"
356369

357370
def remove_file(self, filename):
358371
cmd = f"rm {filename}"
@@ -366,16 +379,16 @@ def kill(self, pid, signal):
366379

367380
def get_pid(self):
368381
# Get current process id
369-
return self.exec_command("echo $$")
382+
return int(self.exec_command("echo $$", encoding='utf-8'))
370383

371384
def get_remote_children(self, pid):
372385
command = f"pgrep -P {pid}"
373386
stdin, stdout, stderr = self.ssh.exec_command(command)
374387
children = stdout.readlines()
375-
return [int(child_pid.strip()) for child_pid in children]
388+
return [PsUtilProcessProxy(self.ssh, int(child_pid.strip())) for child_pid in children]
376389

377390
# Database control
378-
def db_connect(self, dbname, user, password=None, host="127.0.0.1", port=5432):
391+
def db_connect(self, dbname, user, password=None, host="127.0.0.1", port=5432, ssh_key=None):
379392
"""
380393
Connects to a PostgreSQL database on the remote system.
381394
Args:
@@ -389,19 +402,26 @@ def db_connect(self, dbname, user, password=None, host="127.0.0.1", port=5432):
389402
This function establishes a connection to a PostgreSQL database on the remote system using the specified
390403
parameters. It returns a connection object that can be used to interact with the database.
391404
"""
392-
with sshtunnel.open_tunnel(
393-
(host, 22), # Remote server IP and SSH port
394-
ssh_username=self.username,
395-
ssh_pkey=self.ssh_key,
396-
remote_bind_address=(host, port), # PostgreSQL server IP and PostgreSQL port
397-
local_bind_address=('localhost', port), # Local machine IP and available port
398-
):
405+
tunnel = sshtunnel.open_tunnel(
406+
(host, 22), # Remote server IP and SSH port
407+
ssh_username=user or self.username,
408+
ssh_pkey=ssh_key or self.ssh_key,
409+
remote_bind_address=(host, port), # PostgreSQL server IP and PostgreSQL port
410+
local_bind_address=('localhost', port) # Local machine IP and available port
411+
)
412+
413+
tunnel.start()
414+
415+
try:
399416
conn = pglib.connect(
400-
host=host,
401-
port=port,
417+
host=host, # change to 'localhost' because we're connecting through a local ssh tunnel
418+
port=tunnel.local_bind_port, # use the local bind port set up by the tunnel
402419
dbname=dbname,
403-
user=user,
420+
user=user or self.username,
404421
password=password
405422
)
406423

407-
return conn
424+
return conn
425+
except Exception as e:
426+
tunnel.stop()
427+
raise e

testgres/utils.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def release_port(port):
4545
bound_ports.discard(port)
4646

4747

48-
def execute_utility(args, logfile=None):
48+
def execute_utility(args, logfile=None, verbose=False):
4949
"""
5050
Execute utility (pg_ctl, pg_dump etc).
5151
@@ -56,24 +56,28 @@ def execute_utility(args, logfile=None):
5656
Returns:
5757
stdout of executed utility.
5858
"""
59-
command = u' '.join(args)
60-
exit_status, out, error = tconf.os_ops.exec_command(command, verbose=True)
59+
exit_status, out, error = tconf.os_ops.exec_command(args, verbose=True)
6160
# decode result
6261
out = '' if not out else out
6362
if isinstance(out, bytes):
6463
out = out.decode('utf-8')
64+
if isinstance(error, bytes):
65+
error = error.decode('utf-8')
6566

6667
# write new log entry if possible
6768
if logfile:
6869
try:
69-
tconf.os_ops.write(filename=logfile, data=command, truncate=True)
70+
tconf.os_ops.write(filename=logfile, data=args, truncate=True)
7071
if out:
7172
# comment-out lines
7273
lines = [u'\n'] + ['# ' + line for line in out.splitlines()] + [u'\n']
7374
tconf.os_ops.write(filename=logfile, data=lines)
7475
except IOError:
75-
log.warn(f"Problem with writing to logfile `{logfile}` during run command `{command}`")
76-
return out
76+
log.warn(f"Problem with writing to logfile `{logfile}` during run command `{args}`")
77+
if verbose:
78+
return exit_status, out, error
79+
else:
80+
return out
7781

7882

7983
def get_bin_path(filename):

0 commit comments

Comments
 (0)