psql может подключаться к сокету домена unix, но py-postgresql с теми же параметрами получает «Отказано в доступе»

Описание проблемы:

Мой системный пользователь — milosz, который сопоставлен с пользователем PostgreSQL project_great в pg_ident.conf. Я использую одноранговую аутентификацию для подключения к базе данных PostgreSQL через сокет домена unix. Этот метод подключения работает при использовании psql, но не работает при использовании py-postgresql с теми же параметрами из скрипта Python.

Здесь я успешно подключаюсь к базе данных, используя psql:

$ psql -U project_great \
>      -d project_great \
>      -h /var/run/postgresql
psql (9.3.4)
Type "help" for help.

project_great=> 

Вот database_test.py:

#!/usr/bin/env python3

import postgresql

params = {
    'user':     'project_great',
    'database': 'project_great',
    'unix':     '/var/run/postgresql',
}

connection = postgresql.open(**params)

Здесь я пытаюсь подключиться к базе данных, запустив ./database_test.py:

$ ./database_test.py 
Traceback (most recent call last):
  File "./database_test.py", line 11, in <module>
    sys.exit(main(sys.argv))
  File "./database_test.py", line 13, in main
    connection = postgresql.open(**params)
  File "/home/milosz/devel/project_great/.virtualenv/lib/python3.3/site-packages/postgresql/__init__.py", line 94, in open
    c.connect()
  File "/home/milosz/devel/project_great/.virtualenv/lib/python3.3/site-packages/postgresql/driver/pq3.py", line 2422, in connect
    self._establish()
  File "/home/milosz/devel/project_great/.virtualenv/lib/python3.3/site-packages/postgresql/driver/pq3.py", line 2548, in _establish
    self.typio.raise_client_error(could_not_connect, creator = self, cause = exc)
  File "/home/milosz/devel/project_great/.virtualenv/lib/python3.3/site-packages/postgresql/driver/pq3.py", line 514, in raise_client_error
    raise client_error
postgresql.exceptions.ClientCannotConnectError: could not establish connection to server
  CODE: 08001
  LOCATION: CLIENT
CONNECTION: [failed]
  failures[0]:
    socket'/var/run/postgresql'
    Traceback (most recent call last):
      File "/home/milosz/devel/project_great/.virtualenv/lib/python3.3/site-packages/postgresql/protocol/client3.py", line 136, in connect
        self.socket = self.socket_factory(timeout = timeout)
      File "/home/milosz/devel/project_great/.virtualenv/lib/python3.3/site-packages/postgresql/python/socket.py", line 64, in __call__
        s.connect(self.socket_connect)
    PermissionError: [Errno 13] Permission denied

    The above exception was the direct cause of the following exception:

    postgresql.exceptions.ConnectionRejectionError: Permission denied
      CODE: 08004
      LOCATION: CLIENT
CONNECTOR: [Unix] pq://project_great@[unix::var:run:postgresql]/project_great
  category: None
DRIVER: postgresql.driver.pq3.Driver

Поскольку параметры двух подключений якобы одинаковы, а мои разрешения на сокет и содержащий его каталог довольно открыты, я не знаю, в чем проблема. Использование TCP не является решением; Я хочу использовать сокеты домена unix. В документации py-postgresql указано, что подключение с использованием unix доменные сокеты должны работать.

Конфигурация:

pg_hba.conf:

# TYPE   DATABASE  USER      ADDRESS             METHOD  OPTION
local    all       all                           peer    map=default

pg_ident.conf:

# MAPNAME       SYSTEM-USERNAME         PG-USERNAME
default         postgres                postgres
default         milosz                  project_great

postgresql.conf:

...
port = 5432
unix_socket_directories = '/var/run/postgresql'
...

Вот разрешения на мой каталог сокетов:

$ ll /var/run/postgresql/
total 8
drwxrwsr-x  2 postgres postgres 100 May 17 00:20 ./
drwxr-xr-x 31 root     root     900 May 17 00:41 ../
-rw-r--r--  1 postgres postgres   5 May 17 00:20 9.3-main.pid
srwxrwxrwx  1 postgres postgres   0 May 17 00:20 .s.PGSQL.5432=
-rw-------  1 postgres postgres  70 May 17 00:20 .s.PGSQL.5432.lock

Пользователю PostgreSQL project_great предоставлены все права доступа к базе данных project_great, и пользователь, и база данных существуют.

У меня нет ~/.pgpass.

Окружающая обстановка:

  • Убунту 13.10
  • Питон 3.3
  • Постгрес SQL 9.3
  • py-postgresql 1.1.0

person Milosz    schedule 17.05.2014    source источник
comment
Я бы прогнал оба под strace и сравнил.   -  person Craig Ringer    schedule 17.05.2014
comment
Отличный звонок. Я так и сделал и почти сразу нашел свою проблему. Пишу ответ на вопрос прямо сейчас.   -  person Milosz    schedule 17.05.2014


Ответы (1)


Крейг Рингер предложил запустить обе программы под strace, чтобы выяснить, есть ли существенная разница в системных вызовах. Я поискал /var/run/postgresql и обнаружил, что пока psql запускал connect вот так:

connect(4, {sa_family=AF_LOCAL, sun_path="/var/run/postgresql/.s.PGSQL.5432"}, 110) = 0

./database_test.py запускал connect вот так:

connect(4, {sa_family=AF_LOCAL, sun_path="/var/run/postgresql"}, 21) = -1 EACCES (Permission denied)

в чем и заключалась проблема.

В то время как psql ожидает путь к каталогу, в котором расположен сокет домена unix, py-postgresql ожидает полный путь к сокету. Поэтому исправление состояло в том, чтобы изменить database_test.py так:

#!/usr/bin/env python3

import postgresql

params = {
    'user':     'project_great',
    'database': 'project_great',
    'unix':     '/var/run/postgresql/.s.PGSQL.5432',
}

connection = postgresql.open(**params)

Честно говоря, я чувствую себя глупо из-за того, что не попробовал полный путь в качестве более раннего шага отладки!

person Milosz    schedule 17.05.2014
comment
Пожалуйста, сообщите об этом как об ошибке py-postgresql. Он должен быть совместим со всеми клиентами libpq, такими как psql, psycopg2 и т. д. (кстати, я без веской причины настоятельно рекомендую использовать psycopg2, а не py-postgresql). - person Craig Ringer; 17.05.2014