debusine-admin migrate without PostgreSQL: raise exception

I found this installing debusine-server in a host without Postgresql (might happen the same in other circumstances when debusine cannot connect to the DB).

journalctl had debusine errors (Python exceptions). Running sudo -u debusine-server debusine-admin migrate the output is:

root@VM-889f1184-ddc9-408d-9197-259fcafb0849:~# sudo -u debusine-server debusine-admin migrate
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/django/db/backends/base/base.py", line 219, in ensure_connection
    self.connect()
  File "/usr/lib/python3/dist-packages/django/utils/asyncio.py", line 33, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/base/base.py", line 200, in connect
    self.connection = self.get_new_connection(conn_params)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/utils/asyncio.py", line 33, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/postgresql/base.py", line 187, in get_new_connection
    connection = Database.connect(**conn_params)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/psycopg2/__init__.py", line 122, in connect
    conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
psycopg2.OperationalError: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
	Is the server running locally and accepting connections on that socket?


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

Traceback (most recent call last):
  File "/usr/bin/debusine-admin", line 47, in <module>
    main()
  File "/usr/bin/debusine-admin", line 29, in main
    execute_from_command_line(sys.argv)
  File "/usr/lib/python3/dist-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python3/dist-packages/django/core/management/__init__.py", line 413, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python3/dist-packages/django/core/management/base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/lib/python3/dist-packages/django/core/management/base.py", line 398, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/core/management/base.py", line 89, in wrapped
    res = handle_func(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/core/management/commands/migrate.py", line 75, in handle
    self.check(databases=[database])
  File "/usr/lib/python3/dist-packages/django/core/management/base.py", line 419, in check
    all_issues = checks.run_checks(
                 ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/core/checks/registry.py", line 76, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/core/checks/model_checks.py", line 34, in check_all_models
    errors.extend(model.check(**kwargs))
                  ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/models/base.py", line 1303, in check
    *cls._check_indexes(databases),
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/models/base.py", line 1695, in _check_indexes
    connection.features.supports_covering_indexes or
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
                                         ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/postgresql/features.py", line 92, in is_postgresql_11
    return self.connection.pg_version >= 110000
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
                                         ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/postgresql/base.py", line 329, in pg_version
    with self.temporary_connection():
  File "/usr/lib/python3.11/contextlib.py", line 137, in __enter__
    return next(self.gen)
           ^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/base/base.py", line 603, in temporary_connection
    with self.cursor() as cursor:
         ^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/utils/asyncio.py", line 33, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/base/base.py", line 259, in cursor
    return self._cursor()
           ^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/base/base.py", line 235, in _cursor
    self.ensure_connection()
  File "/usr/lib/python3/dist-packages/django/utils/asyncio.py", line 33, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/base/base.py", line 218, in ensure_connection
    with self.wrap_database_errors:
  File "/usr/lib/python3/dist-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/lib/python3/dist-packages/django/db/backends/base/base.py", line 219, in ensure_connection
    self.connect()
  File "/usr/lib/python3/dist-packages/django/utils/asyncio.py", line 33, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/base/base.py", line 200, in connect
    self.connection = self.get_new_connection(conn_params)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/utils/asyncio.py", line 33, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/django/db/backends/postgresql/base.py", line 187, in get_new_connection
    connection = Database.connect(**conn_params)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/psycopg2/__init__.py", line 122, in connect
    conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
django.db.utils.OperationalError: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
	Is the server running locally and accepting connections on that socket?

For debusine specific commands we have a nicer error:

root@VM-889f1184-ddc9-408d-9197-259fcafb0849:~# sudo -u debusine-server debusine-admin list_workers
CommandError: Database error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
	Is the server running locally and accepting connections on that socket?
root@VM-889f1184-ddc9-408d-9197-259fcafb0849:~# 

To fix this:

  • Perhaps we could make "migrate" have a nicer error handling?
  • To avoid the error logs at least: in our debusine-server.service we have:
ExecStartPre=/usr/bin/debusine-admin check
ExecStart=/usr/bin/daphne --unix-socket=/var/lib/debusine/server/daphne.sock debusine.project.asgi:application

But: sudo -u debusine-server debusine-admin check Raises the error already.

We could also have debusine-admin debusine-check with a nicer error handling (this would avoid at least spamming the logs).