Skip to content

Commit 84703ae

Browse files
New utility get_pg_node_state is added (#301)
Signature: def get_pg_node_state( os_ops: OsOperations, bin_dir: str, data_dir: str, utils_log_file: typing.Optional[str], ) -> PostgresNodeState: - It returns PostgresNodeState - PostgresNode::pid and PostgresNode::status use it Also - New RaiseError helper is added
1 parent a4055fc commit 84703ae

3 files changed

Lines changed: 187 additions & 152 deletions

File tree

src/node.py

Lines changed: 18 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,7 @@
4949
HBA_CONF_FILE, \
5050
RECOVERY_CONF_FILE, \
5151
PG_LOG_FILE, \
52-
UTILS_LOG_FILE, \
53-
PG_CTL__STATUS__OK, \
54-
PG_CTL__STATUS__NODE_IS_STOPPED, \
55-
PG_CTL__STATUS__BAD_DATADIR \
52+
UTILS_LOG_FILE
5653

5754
from .consts import \
5855
MAX_LOGICAL_REPLICATION_WORKERS, \
@@ -349,136 +346,16 @@ def pid(self):
349346
Return postmaster's PID if node is running, else 0.
350347
"""
351348

352-
self__data_dir = self.data_dir
349+
x = self._get_node_state()
350+
assert type(x) == utils.PostgresNodeState # noqa: E721
353351

354-
_params = [
355-
self._get_bin_path('pg_ctl'),
356-
"-D", self__data_dir,
357-
"status"
358-
] # yapf: disable
359-
360-
status_code, out, error = execute_utility2(
361-
self.os_ops,
362-
_params,
363-
self.utils_log_file,
364-
verbose=True,
365-
ignore_errors=True)
366-
367-
assert type(status_code) == int # noqa: E721
368-
assert type(out) == str # noqa: E721
369-
assert type(error) == str # noqa: E721
370-
371-
# -----------------
372-
if status_code == PG_CTL__STATUS__NODE_IS_STOPPED:
373-
return 0
374-
375-
# -----------------
376-
if status_code == PG_CTL__STATUS__BAD_DATADIR:
352+
if x.pid is None:
353+
assert x.node_status != NodeStatus.Running
377354
return 0
378355

379-
# -----------------
380-
if status_code != PG_CTL__STATUS__OK:
381-
errMsg = "Getting of a node status [data_dir is {0}] failed.".format(self__data_dir)
382-
383-
raise ExecUtilException(
384-
message=errMsg,
385-
command=_params,
386-
exit_code=status_code,
387-
out=out,
388-
error=error,
389-
)
390-
391-
# -----------------
392-
assert status_code == PG_CTL__STATUS__OK
393-
394-
if out == "":
395-
__class__._throw_error__pg_ctl_returns_an_empty_string(
396-
_params
397-
)
398-
399-
C_PID_PREFIX = "(PID: "
400-
401-
i = out.find(C_PID_PREFIX)
402-
403-
if i == -1:
404-
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
405-
out,
406-
_params
407-
)
408-
409-
assert i > 0
410-
assert i < len(out)
411-
assert len(C_PID_PREFIX) <= len(out)
412-
assert i <= len(out) - len(C_PID_PREFIX)
413-
414-
i += len(C_PID_PREFIX)
415-
start_pid_s = i
416-
417-
while True:
418-
if i == len(out):
419-
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
420-
out,
421-
_params
422-
)
423-
424-
ch = out[i]
425-
426-
if ch == ")":
427-
break
428-
429-
if ch.isdigit():
430-
i += 1
431-
continue
432-
433-
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
434-
out,
435-
_params
436-
)
437-
assert False
438-
439-
if i == start_pid_s:
440-
__class__._throw_error__pg_ctl_returns_an_unexpected_string(
441-
out,
442-
_params
443-
)
444-
445-
# TODO: Let's verify a length of pid string.
446-
447-
pid = int(out[start_pid_s:i])
448-
449-
if pid == 0:
450-
__class__._throw_error__pg_ctl_returns_a_zero_pid(
451-
out,
452-
_params
453-
)
454-
455-
assert pid != 0
456-
return pid
457-
458-
@staticmethod
459-
def _throw_error__pg_ctl_returns_an_empty_string(_params):
460-
errLines = []
461-
errLines.append("Utility pg_ctl returns empty string.")
462-
errLines.append("Command line is {0}".format(_params))
463-
raise RuntimeError("\n".join(errLines))
464-
465-
@staticmethod
466-
def _throw_error__pg_ctl_returns_an_unexpected_string(out, _params):
467-
errLines = []
468-
errLines.append("Utility pg_ctl returns an unexpected string:")
469-
errLines.append(out)
470-
errLines.append("------------")
471-
errLines.append("Command line is {0}".format(_params))
472-
raise RuntimeError("\n".join(errLines))
473-
474-
@staticmethod
475-
def _throw_error__pg_ctl_returns_a_zero_pid(out, _params):
476-
errLines = []
477-
errLines.append("Utility pg_ctl returns a zero pid. Output string is:")
478-
errLines.append(out)
479-
errLines.append("------------")
480-
errLines.append("Command line is {0}".format(_params))
481-
raise RuntimeError("\n".join(errLines))
356+
assert x.node_status == NodeStatus.Running
357+
assert type(x.pid) == int # noqa: E721
358+
return x.pid
482359

483360
@property
484361
def auxiliary_pids(self):
@@ -995,28 +872,17 @@ def status(self):
995872
Returns:
996873
An instance of :class:`.NodeStatus`.
997874
"""
875+
x = self._get_node_state()
876+
assert type(x) == utils.PostgresNodeState # noqa: E721
877+
return x.node_status
998878

999-
try:
1000-
_params = [
1001-
self._get_bin_path('pg_ctl'),
1002-
"-D", self.data_dir,
1003-
"status"
1004-
] # yapf: disable
1005-
status_code, out, error = execute_utility2(self.os_ops, _params, self.utils_log_file, verbose=True)
1006-
if error and 'does not exist' in error:
1007-
return NodeStatus.Uninitialized
1008-
elif 'no server running' in out:
1009-
return NodeStatus.Stopped
1010-
return NodeStatus.Running
1011-
1012-
except ExecUtilException as e:
1013-
# Node is not running
1014-
if e.exit_code == 3:
1015-
return NodeStatus.Stopped
1016-
1017-
# Node has no file dir
1018-
elif e.exit_code == 4:
1019-
return NodeStatus.Uninitialized
879+
def _get_node_state(self) -> utils.PostgresNodeState:
880+
return utils.get_pg_node_state(
881+
self._os_ops,
882+
self.bin_dir,
883+
self.data_dir,
884+
self.utils_log_file
885+
)
1020886

1021887
def get_control_data(self):
1022888
"""

src/raise_error.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
3+
class RaiseError:
4+
@staticmethod
5+
def pg_ctl_returns_an_empty_string(_params):
6+
errLines = []
7+
errLines.append("Utility pg_ctl returns an empty string.")
8+
errLines.append("Command line is {0}".format(_params))
9+
raise RuntimeError("\n".join(errLines))
10+
11+
@staticmethod
12+
def pg_ctl_returns_an_unexpected_string(out, _params):
13+
errLines = []
14+
errLines.append("Utility pg_ctl returns an unexpected string:")
15+
errLines.append(out)
16+
errLines.append("------------")
17+
errLines.append("Command line is {0}".format(_params))
18+
raise RuntimeError("\n".join(errLines))
19+
20+
@staticmethod
21+
def pg_ctl_returns_a_zero_pid(out, _params):
22+
errLines = []
23+
errLines.append("Utility pg_ctl returns a zero pid. Output string is:")
24+
errLines.append(out)
25+
errLines.append("------------")
26+
errLines.append("Command line is {0}".format(_params))
27+
raise RuntimeError("\n".join(errLines))

src/utils.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,17 @@
1010
from contextlib import contextmanager
1111
from packaging.version import Version, InvalidVersion
1212
import re
13+
import typing
1314

1415
from six import iteritems
1516

1617
from .exceptions import ExecUtilException
1718
from .config import testgres_config as tconf
19+
from .raise_error import RaiseError
20+
from .enums import NodeStatus
21+
from .consts import PG_CTL__STATUS__OK
22+
from .consts import PG_CTL__STATUS__NODE_IS_STOPPED
23+
from .consts import PG_CTL__STATUS__BAD_DATADIR
1824
from testgres.operations.os_ops import OsOperations
1925
from testgres.operations.remote_ops import RemoteOperations
2026
from testgres.operations.local_ops import LocalOperations
@@ -315,3 +321,139 @@ def clean_on_error(node):
315321
# TODO: should we wrap this in try-block?
316322
node.cleanup()
317323
raise
324+
325+
326+
class PostgresNodeState:
327+
node_status: NodeStatus
328+
pid: typing.Optional[int]
329+
330+
def __init__(
331+
self,
332+
node_status: NodeStatus,
333+
pid: typing.Optional[int]
334+
):
335+
assert type(node_status) == NodeStatus # noqa: E721
336+
assert pid is None or type(pid) == int # noqa: E721
337+
338+
self.node_status = node_status
339+
self.pid = pid
340+
return
341+
342+
343+
def get_pg_node_state(
344+
os_ops: OsOperations,
345+
bin_dir: str,
346+
data_dir: str,
347+
utils_log_file: typing.Optional[str],
348+
) -> PostgresNodeState:
349+
assert isinstance(os_ops, OsOperations)
350+
assert type(bin_dir) == str # noqa: E721
351+
assert type(data_dir) == str # noqa: E721
352+
assert utils_log_file is None or type(utils_log_file) == str # noqa: E721
353+
354+
_params = [
355+
os_ops.build_path(bin_dir, "pg_ctl"),
356+
"-D",
357+
data_dir,
358+
"status",
359+
]
360+
361+
status_code, out, error = execute_utility2(
362+
os_ops,
363+
_params,
364+
utils_log_file,
365+
verbose=True,
366+
ignore_errors=True,
367+
)
368+
369+
assert type(status_code) == int # noqa: E721
370+
assert type(out) == str # noqa: E721
371+
assert type(error) == str # noqa: E721
372+
373+
# -----------------
374+
if status_code == PG_CTL__STATUS__NODE_IS_STOPPED:
375+
return PostgresNodeState(NodeStatus.Stopped, None)
376+
377+
# -----------------
378+
if status_code == PG_CTL__STATUS__BAD_DATADIR:
379+
return PostgresNodeState(NodeStatus.Uninitialized, None)
380+
381+
# -----------------
382+
if status_code != PG_CTL__STATUS__OK:
383+
errMsg = "Getting of a node status [data_dir is {0}] failed.".format(
384+
data_dir
385+
)
386+
387+
raise ExecUtilException(
388+
message=errMsg,
389+
command=_params,
390+
exit_code=status_code,
391+
out=out,
392+
error=error,
393+
)
394+
395+
if out == "":
396+
RaiseError.pg_ctl_returns_an_empty_string(
397+
_params
398+
)
399+
400+
C_PID_PREFIX = "(PID: "
401+
402+
i = out.find(C_PID_PREFIX)
403+
404+
if i == -1:
405+
RaiseError.pg_ctl_returns_an_unexpected_string(
406+
out,
407+
_params
408+
)
409+
410+
assert i > 0
411+
assert i < len(out)
412+
assert len(C_PID_PREFIX) <= len(out)
413+
assert i <= len(out) - len(C_PID_PREFIX)
414+
415+
i += len(C_PID_PREFIX)
416+
start_pid_s = i
417+
418+
while True:
419+
if i == len(out):
420+
RaiseError.pg_ctl_returns_an_unexpected_string(
421+
out,
422+
_params
423+
)
424+
425+
ch = out[i]
426+
427+
if ch == ")":
428+
break
429+
430+
if ch.isdigit():
431+
i += 1
432+
continue
433+
434+
RaiseError.pg_ctl_returns_an_unexpected_string(
435+
out,
436+
_params
437+
)
438+
assert False
439+
440+
if i == start_pid_s:
441+
RaiseError.pg_ctl_returns_an_unexpected_string(
442+
out,
443+
_params
444+
)
445+
446+
# TODO: Let's verify a length of pid string.
447+
448+
pid = int(out[start_pid_s:i])
449+
450+
if pid == 0:
451+
RaiseError.pg_ctl_returns_a_zero_pid(
452+
out,
453+
_params
454+
)
455+
456+
assert pid != 0
457+
458+
# -----------------
459+
return PostgresNodeState(NodeStatus.Running, pid)

0 commit comments

Comments
 (0)