Skip to content

Commit 1d68e91

Browse files
authored
Fix node cleanup (#135)
* Add expect_error to pg_upgrade * Fix node cleanup - rmdirs * Add cleanup parameter - clean full dir
1 parent a128b12 commit 1d68e91

File tree

2 files changed

+38
-12
lines changed

2 files changed

+38
-12
lines changed

testgres/node.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -914,13 +914,14 @@ def free_port(self):
914914
self._should_free_port = False
915915
release_port(self.port)
916916

917-
def cleanup(self, max_attempts=3):
917+
def cleanup(self, max_attempts=3, full=False):
918918
"""
919919
Stop node if needed and remove its data/logs directory.
920920
NOTE: take a look at TestgresConfig.node_cleanup_full.
921921
922922
Args:
923923
max_attempts: how many times should we try to stop()?
924+
full: clean full base dir
924925
925926
Returns:
926927
This instance of :class:`.PostgresNode`.
@@ -929,12 +930,12 @@ def cleanup(self, max_attempts=3):
929930
self._try_shutdown(max_attempts)
930931

931932
# choose directory to be removed
932-
if testgres_config.node_cleanup_full:
933+
if testgres_config.node_cleanup_full or full:
933934
rm_dir = self.base_dir # everything
934935
else:
935936
rm_dir = self.data_dir # just data, save logs
936937

937-
self.os_ops.rmdirs(rm_dir, ignore_errors=True)
938+
self.os_ops.rmdirs(rm_dir, ignore_errors=False)
938939

939940
return self
940941

@@ -1629,7 +1630,7 @@ def set_auto_conf(self, options, config='postgresql.auto.conf', rm_options={}):
16291630

16301631
self.os_ops.write(path, auto_conf, truncate=True)
16311632

1632-
def upgrade_from(self, old_node, options=None):
1633+
def upgrade_from(self, old_node, options=None, expect_error=False):
16331634
"""
16341635
Upgrade this node from an old node using pg_upgrade.
16351636
@@ -1657,11 +1658,11 @@ def upgrade_from(self, old_node, options=None):
16571658
"--old-datadir", old_node.data_dir,
16581659
"--new-datadir", self.data_dir,
16591660
"--old-port", str(old_node.port),
1660-
"--new-port", str(self.port),
1661+
"--new-port", str(self.port)
16611662
]
16621663
upgrade_command += options
16631664

1664-
return self.os_ops.exec_command(upgrade_command)
1665+
return self.os_ops.exec_command(upgrade_command, expect_error=expect_error)
16651666

16661667
def _get_bin_path(self, filename):
16671668
if self.bin_dir:

testgres/operations/local_ops.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import stat
55
import subprocess
66
import tempfile
7+
import time
78

89
import psutil
910

@@ -19,13 +20,18 @@
1920

2021
CMD_TIMEOUT_SEC = 60
2122
error_markers = [b'error', b'Permission denied', b'fatal']
23+
err_out_markers = [b'Failure']
2224

2325

24-
def has_errors(output):
26+
def has_errors(output=None, error=None):
2527
if output:
2628
if isinstance(output, str):
2729
output = output.encode(get_default_encoding())
28-
return any(marker in output for marker in error_markers)
30+
return any(marker in output for marker in err_out_markers)
31+
if error:
32+
if isinstance(error, str):
33+
error = error.encode(get_default_encoding())
34+
return any(marker in error for marker in error_markers)
2935
return False
3036

3137

@@ -107,8 +113,8 @@ def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False,
107113
process, output, error = self._run_command(cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding)
108114
if get_process:
109115
return process
110-
if process.returncode != 0 or (has_errors(error) and not expect_error):
111-
self._raise_exec_exception('Utility exited with non-zero code. Error `{}`', cmd, process.returncode, error)
116+
if (process.returncode != 0 or has_errors(output=output, error=error)) and not expect_error:
117+
self._raise_exec_exception('Utility exited with non-zero code. Error `{}`', cmd, process.returncode, error or output)
112118

113119
if verbose:
114120
return process.returncode, output, error
@@ -142,8 +148,27 @@ def makedirs(self, path, remove_existing=False):
142148
except FileExistsError:
143149
pass
144150

145-
def rmdirs(self, path, ignore_errors=True):
146-
return rmtree(path, ignore_errors=ignore_errors)
151+
def rmdirs(self, path, ignore_errors=True, retries=3, delay=1):
152+
"""
153+
Removes a directory and its contents, retrying on failure.
154+
155+
:param path: Path to the directory.
156+
:param ignore_errors: If True, ignore errors.
157+
:param retries: Number of attempts to remove the directory.
158+
:param delay: Delay between attempts in seconds.
159+
"""
160+
for attempt in range(retries):
161+
try:
162+
rmtree(path, ignore_errors=ignore_errors)
163+
if not os.path.exists(path):
164+
return True
165+
except FileNotFoundError:
166+
return True
167+
except Exception as e:
168+
print(f"Error: Failed to remove directory {path} on attempt {attempt + 1}: {e}")
169+
time.sleep(delay)
170+
print(f"Error: Failed to remove directory {path} after {retries} attempts.")
171+
return False
147172

148173
def listdir(self, path):
149174
return os.listdir(path)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy