Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions testgres/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,11 @@
Copyright (c) 2016, Postgres Professional
"""

from .node import PostgresNode

from functools import wraps

def get_new_node(name=None, base_dir=None):
"""
Create a new node (select port automatically).

Args:
name: node's application name.
base_dir: path to node's data directory.
from .node import PostgresNode

Returns:
An instance of PostgresNode.
"""

return PostgresNode(name=name, base_dir=base_dir)
@wraps(PostgresNode.__init__)
def get_new_node(**kwargs):
return PostgresNode(**kwargs)
1 change: 1 addition & 0 deletions testgres/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
RECOVERY_CONF_FILE = "recovery.conf"
PG_AUTO_CONF_FILE = "postgresql.auto.conf"
PG_CONF_FILE = "postgresql.conf"
PG_PID_FILE = 'postmaster.pid'
HBA_CONF_FILE = "pg_hba.conf"

# names for log files
Expand Down
96 changes: 52 additions & 44 deletions testgres/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
HBA_CONF_FILE, \
RECOVERY_CONF_FILE, \
PG_LOG_FILE, \
UTILS_LOG_FILE
UTILS_LOG_FILE, \
PG_PID_FILE

from .decorators import \
method_decorator, \
Expand Down Expand Up @@ -66,32 +67,33 @@
class PostgresNode(object):
def __init__(self, name=None, port=None, base_dir=None):
"""
Create a new node manually.
Create a new node.

Args:
name: node's application name.
port: port to accept connections.
base_dir: path to node's data directory.
"""

# private
self._should_free_port = port is None
self._base_dir = base_dir
self._logger = None
self._master = None

# basic
self.host = '127.0.0.1'
self.name = name or generate_app_name()
self.port = port or reserve_port()
self.base_dir = base_dir

# defaults for __exit__()
self.cleanup_on_good_exit = testgres_config.node_cleanup_on_good_exit
self.cleanup_on_bad_exit = testgres_config.node_cleanup_on_bad_exit
self.shutdown_max_attempts = 3

# private
self._should_free_port = port is None
self._logger = None
self._master = None

# create directories if needed
self._prepare_dirs()
# NOTE: for compatibility
self.utils_log_name = self.utils_log_file
self.pg_log_name = self.pg_log_file

def __enter__(self):
return self
Expand Down Expand Up @@ -121,19 +123,37 @@ def master(self):
return self._master

@property
def data_dir(self):
return os.path.join(self.base_dir, DATA_DIR)
def base_dir(self):
if not self._base_dir:
self._base_dir = mkdtemp(prefix=TMP_NODE)

# NOTE: it's safe to create a new dir
if not os.path.exists(self._base_dir):
os.makedirs(self._base_dir)

return self._base_dir

@property
def logs_dir(self):
return os.path.join(self.base_dir, LOGS_DIR)
path = os.path.join(self.base_dir, LOGS_DIR)

# NOTE: it's safe to create a new dir
if not os.path.exists(path):
os.makedirs(path)

return path

@property
def data_dir(self):
# NOTE: we can't run initdb without user's args
return os.path.join(self.base_dir, DATA_DIR)

@property
def utils_log_name(self):
def utils_log_file(self):
return os.path.join(self.logs_dir, UTILS_LOG_FILE)

@property
def pg_log_name(self):
def pg_log_file(self):
return os.path.join(self.logs_dir, PG_LOG_FILE)

def _try_shutdown(self, max_attempts):
Expand Down Expand Up @@ -189,21 +209,11 @@ def _create_recovery_conf(self, username):

self.append_conf(RECOVERY_CONF_FILE, line)

def _prepare_dirs(self):
if not self.base_dir:
self.base_dir = mkdtemp(prefix=TMP_NODE)

if not os.path.exists(self.base_dir):
os.makedirs(self.base_dir)

if not os.path.exists(self.logs_dir):
os.makedirs(self.logs_dir)

def _maybe_start_logger(self):
if testgres_config.use_python_logging:
# spawn new logger if it doesn't exist or is stopped
if not self._logger or not self._logger.is_alive():
self._logger = TestgresLogger(self.name, self.pg_log_name)
self._logger = TestgresLogger(self.name, self.pg_log_file)
self._logger.start()

def _maybe_stop_logger(self):
Expand All @@ -219,7 +229,7 @@ def _collect_special_files(self):
(os.path.join(self.data_dir, PG_AUTO_CONF_FILE), 0),
(os.path.join(self.data_dir, RECOVERY_CONF_FILE), 0),
(os.path.join(self.data_dir, HBA_CONF_FILE), 0),
(self.pg_log_name, testgres_config.error_log_lines)
(self.pg_log_file, testgres_config.error_log_lines)
]

for f, num_lines in files:
Expand Down Expand Up @@ -254,12 +264,9 @@ def init(self, initdb_params=None, **kwargs):
This instance of PostgresNode.
"""

# create directories if needed
self._prepare_dirs()

# initialize this PostgreSQL node
cached_initdb(data_dir=self.data_dir,
logfile=self.utils_log_name,
logfile=self.utils_log_file,
params=initdb_params)

# initialize default config files
Expand Down Expand Up @@ -398,7 +405,7 @@ def status(self):
"-D", self.data_dir,
"status"
]
execute_utility(_params, self.utils_log_name)
execute_utility(_params, self.utils_log_file)
return NodeStatus.Running

except ExecUtilException as e:
Expand All @@ -416,7 +423,7 @@ def get_pid(self):
"""

if self.status():
pid_file = os.path.join(self.data_dir, 'postmaster.pid')
pid_file = os.path.join(self.data_dir, PG_PID_FILE)
with io.open(pid_file) as f:
return int(f.readline())

Expand All @@ -433,7 +440,7 @@ def get_control_data(self):
_params += ["-D"] if pg_version_ge('9.5') else []
_params += [self.data_dir]

data = execute_utility(_params, self.utils_log_name)
data = execute_utility(_params, self.utils_log_file)

out_dict = {}

Expand All @@ -458,13 +465,13 @@ def start(self, params=[]):
_params = [
get_bin_path("pg_ctl"),
"-D", self.data_dir,
"-l", self.pg_log_name,
"-l", self.pg_log_file,
"-w", # wait
"start"
] + params

try:
execute_utility(_params, self.utils_log_name)
execute_utility(_params, self.utils_log_file)
except ExecUtilException as e:
msg = 'Cannot start node'
files = self._collect_special_files()
Expand Down Expand Up @@ -493,7 +500,7 @@ def stop(self, params=[]):
"stop"
] + params

execute_utility(_params, self.utils_log_name)
execute_utility(_params, self.utils_log_file)

self._maybe_stop_logger()

Expand All @@ -514,13 +521,13 @@ def restart(self, params=[]):
_params = [
get_bin_path("pg_ctl"),
"-D", self.data_dir,
"-l", self.pg_log_name,
"-l", self.pg_log_file,
"-w", # wait
"restart"
] + params

try:
execute_utility(_params, self.utils_log_name)
execute_utility(_params, self.utils_log_file)
except ExecUtilException as e:
msg = 'Cannot restart node'
files = self._collect_special_files()
Expand Down Expand Up @@ -549,7 +556,7 @@ def reload(self, params=[]):
"reload"
] + params

execute_utility(_params, self.utils_log_name)
execute_utility(_params, self.utils_log_file)

def pg_ctl(self, params):
"""
Expand All @@ -569,7 +576,7 @@ def pg_ctl(self, params):
"-w" # wait
] + params

return execute_utility(_params, self.utils_log_name)
return execute_utility(_params, self.utils_log_file)

def free_port(self):
"""
Expand All @@ -578,6 +585,7 @@ def free_port(self):
"""

if self._should_free_port:
self._should_free_port = False
release_port(self.port)

def cleanup(self, max_attempts=3):
Expand Down Expand Up @@ -717,7 +725,7 @@ def tmpfile():
"-d", dbname
]

execute_utility(_params, self.utils_log_name)
execute_utility(_params, self.utils_log_file)

return filename

Expand Down Expand Up @@ -953,7 +961,7 @@ def pgbench_run(self,
**kwargs):
"""
Run pgbench with some options.
This event is logged (see self.utils_log_name).
This event is logged (see self.utils_log_file).

Args:
dbname: database name to connect to.
Expand Down Expand Up @@ -996,7 +1004,7 @@ def pgbench_run(self,
# should be the last one
_params.append(dbname)

return execute_utility(_params, self.utils_log_name)
return execute_utility(_params, self.utils_log_file)

def connect(self, dbname=None, username=None, password=None):
"""
Expand Down