From 0bd53f48ece26f3843e1267ff3adec80eaac3c4a Mon Sep 17 00:00:00 2001 From: Leopold Talirz Date: Mon, 1 Mar 2021 22:37:22 +0100 Subject: [PATCH] test whether postgres user exists 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 introdyce the `try_sudo` and `sudo_user` constructor arguments, which can be used to force `pgsu` to try the "sudo route" for a given system user. --- .gitignore | 4 ++++ pgsu/__init__.py | 35 ++++++++++++++++++++++------------- pyproject.toml | 1 + 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 1f0253f..4e24c02 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ __pycache__ *.pyc .tox/ *.egg-info +.idea +.vscode +build/ +dist/ diff --git a/pgsu/__init__.py b/pgsu/__init__.py index 648e0c8..82a6d1c 100644 --- a/pgsu/__init__.py +++ b/pgsu/__init__.py @@ -21,10 +21,15 @@ 'database': 'template1', } -# By default, try "sudo" only on Ubuntu -DEFAULT_TRY_SUDO = platform.system( -) == 'Linux' and 'Ubuntu' in platform.version() +# By default, try "sudo" only when 'postgres' user exists DEFAULT_UNIX_USER = 'postgres' +try: + import pwd + pwd.getpwnam(DEFAULT_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) @@ -63,7 +68,9 @@ def __init__(self, interactive=False, quiet=True, dsn=None, - determine_setup=True): + determine_setup=True, + try_sudo=DEFAULT_TRY_SUDO, + sudo_user=DEFAULT_UNIX_USER): """Store postgres connection info. :param interactive: use True for verdi commands @@ -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 `sudo_user` and run commands using passwordless `psql`. + :param sudo_user: UNIX user to try to "become", if connection via psycopg2 fails """ self.interactive = interactive if not quiet: @@ -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.sudo_user = sudo_user if determine_setup: self.determine_setup() @@ -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): @@ -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.sudo_user) if _sudo_exists(): dsn = self.dsn.copy() - dsn['user'] = self.unix_user + dsn['user'] = self.sudo_user if _try_su_psql(interactive=self.interactive, dsn=dsn): self.dsn = dsn @@ -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.sudo_user) self.setup_fail_counter += 1 return self._no_setup_detected() @@ -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) diff --git a/pyproject.toml b/pyproject.toml index 5c86010..3444549 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,6 @@ [tool.pylint.format] max-line-length = 120 +max-args = 7 [tool.pytest.ini_options] addopts = "--durations=0 --cov=pgsu"