Skip to content

Commit

Permalink
test whether postgres user exists (#25)
Browse files Browse the repository at this point in the history
So far, `pgsu` only tried the "sudo route" when it detected that it was
running on Ubuntu Linux.
It was reported that this test can fail when running on Windows
Subsystem for Linux.
Furthermore, this test might be too strict and exclude other Linux
distributions with similar postgresql setup (unverified).

Here, we switch from the check of the distribution name to a check
whether the `postgres` system user exists.

Furthermore, we introduce the `try_sudo` and `postgres_unix_user` constructor
arguments, which can be used to force `pgsu` to try the "sudo route" for
a given unix user.
  • Loading branch information
ltalirz authored Mar 9, 2021
1 parent f453385 commit 6641d0c
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ jobs:
run: |
conda install -y -c anaconda postgresql
initdb -D test_db
pg_ctl -D test_db start
pg_ctl -D test_db -o "-d 5" start # start with debugging
- name: Install pgsu
run: |
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ __pycache__
*.pyc
.tox/
*.egg-info
.idea
.vscode
build/
dist/
37 changes: 23 additions & 14 deletions pgsu/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,15 @@
'database': 'template1',
}

# By default, try "sudo" only on Ubuntu
DEFAULT_TRY_SUDO = platform.system(
) == 'Linux' and 'Ubuntu' in platform.version()
DEFAULT_UNIX_USER = 'postgres'
# By default, try "sudo" only when 'postgres' user exists
DEFAULT_POSTGRES_UNIX_USER = 'postgres'
try:
import pwd
pwd.getpwnam(DEFAULT_POSTGRES_UNIX_USER)
DEFAULT_TRY_SUDO = True
except (KeyError, ModuleNotFoundError):
# user not found or pwd module not found (=not Unix)
DEFAULT_TRY_SUDO = False

LOGGER = logging.getLogger('pgsu')
LOGGER.setLevel(logging.DEBUG)
Expand Down Expand Up @@ -63,7 +68,9 @@ def __init__(self,
interactive=False,
quiet=True,
dsn=None,
determine_setup=True):
determine_setup=True,
try_sudo=DEFAULT_TRY_SUDO,
postgres_unix_user=DEFAULT_POSTGRES_UNIX_USER):
"""Store postgres connection info.
:param interactive: use True for verdi commands
Expand All @@ -72,7 +79,9 @@ def __init__(self,
It is sufficient to provide only those values that deviate from the defaults.
:param determine_setup: Whether to determine setup upon instantiation.
You may set this to False and use the 'determine_setup()' method instead.
:param unix_user: UNIX user to try to "become", if connection via psycopg2 fails
:param try_sudo: If connection via psycopg2 fails, whether to try and use `sudo` to become
the `postgres_unix_user` and run commands using passwordless `psql`.
:param postgres_unix_user: UNIX user to try to "become", if connection via psycopg2 fails
"""
self.interactive = interactive
if not quiet:
Expand All @@ -88,9 +97,8 @@ def __init__(self,
if dsn is not None:
self.dsn.update(dsn)

# Used on Ubuntu only!
self.try_sudo = DEFAULT_TRY_SUDO
self.unix_user = DEFAULT_UNIX_USER
self.try_sudo = try_sudo
self.postgres_unix_user = postgres_unix_user

if determine_setup:
self.determine_setup()
Expand Down Expand Up @@ -136,7 +144,7 @@ def determine_setup(self):
# First try the host specified (works if 'host' has setting 'trust' in pg_hba.conf).
# Then try local connection (works if 'local' has setting 'trust' in pg_hba.conf).
# Then try 'host' localhost via TCP/IP.
for pg_host in unique_list([self.dsn.get('host'), None, 'localhost']): # yapf: disable
for pg_host in unique_list([self.dsn.get('host'), None, 'localhost']): # yapf: disable
dsn['host'] = pg_host

if _try_connect_psycopg(**dsn):
Expand All @@ -149,10 +157,10 @@ def determine_setup(self):
# Check if 'sudo' is available and try to become 'postgres'.
if self.try_sudo:
LOGGER.debug('Trying to connect by becoming the "%s" unix user...',
self.unix_user)
self.postgres_unix_user)
if _sudo_exists():
dsn = self.dsn.copy()
dsn['user'] = self.unix_user
dsn['user'] = self.postgres_unix_user

if _try_su_psql(interactive=self.interactive, dsn=dsn):
self.dsn = dsn
Expand All @@ -161,7 +169,7 @@ def determine_setup(self):
else:
LOGGER.info(
'Could not find `sudo` to become the the "%s" unix user.',
self.unix_user)
self.postgres_unix_user)

self.setup_fail_counter += 1
return self._no_setup_detected()
Expand All @@ -181,7 +189,8 @@ def _no_setup_detected(self):

@property
def is_connected(self):
"""Whether connection to PostgreSQL cluster has been established."""
"""Whether successful way of connecting to PostgreSQL cluster has been determined.
"""
return self.connection_mode in (PostgresConnectionMode.PSYCOPG,
PostgresConnectionMode.PSQL)

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[tool.pylint.format]
max-line-length = 120
max-args = 7

[tool.pytest.ini_options]
addopts = "--durations=0 --cov=pgsu"

0 comments on commit 6641d0c

Please sign in to comment.