Резервное копирование мультисайта с использованием user discourse вместо DB_USER или значения из multisite.yml

РЕДАКТИРОВАНИЕ/Tl;dr: В ActiveRecord::Base.connection_pool.db_config.configuration_hash имя пользователя находится в ключе user, а не username, но Discourse ищет его в username.

Простой PR: FIX: backup_restore.rb wants db user from user, not username by pfaffman · Pull Request #28229 · discourse/discourse · GitHub

У меня есть мультисайтовая установка, использующая хостинг PostgreSQL от Digital Ocean. Всё работает нормально, но при попытке создания резервной копии возникает ошибка:

[2024-08-05 16:13:31] pg_dump: ошибка: не удалось подключиться к серверу "private-forum-cluster-postgresql-prod-do-user-1230.j.db.ondigitalocean.com" (10.11.1.6), порт 25060: FATAL:  сбой аутентификации по паролю для пользователя "discourse"

Но пользователь — не discourse. В других местах используется правильный пользователь, включая ActiveRecord::Base.connection_pool.db_config.configuration_hash и BackupRestore.database_configuration (когда я запускаю эти команды в RAILS_DB=sitename rails c). Переменная окружения PG_USER не установлена (насколько я могу видеть).

Похоже, что проблема в этом:

Я отредактировал файл внутри контейнера (чтобы брать данные из DISCOURSE_DB_USER, что на тот момент казалось хорошей идеей), и резервное копирование теперь работает. Не знаю, следует ли извлекать информацию о подключении из multisite.yml, но игнорирование DB_USER кажется неправильным.

Или, может быть, мне просто нужно сделать имя пользователя discourse, как, полагаю, делают все остальные?

РЕДАКТИРОВАНИЕ: Стоп. Нет.

config['username'] должно быть config['user']

    config = ActiveRecord::Base.connection_pool.db_config.configuration_hash

возвращает следующее!

   
=> {:adapter=>"postgresql",
 :database=>"theDatabase",
 :pool=>25,
 :port=>25060,
 :timeout=>5000,
 :host=>"private-forum-cluster-postgresql-prod-do-user-123-0.j.db.ondigitalocean.com",
 :user=>"theCurrentUsername",
 :password=>"supersecret",
 :host_names=>["forum.example.com"],
 :db_key=>"mydb",
 :prepared_statements=>false}

Поэтому

    config["username"] || username || ENV["USER"] || "postgres",

должно быть

    config["user"] || username || ENV["USER"] || "postgres",
2 лайка

@pfaffman Боюсь, нам пришлось откатить это, так как это нарушило восстановление резервных копий в наших продакшн-окружениях.

Наш пример конфигурации для нескольких сайтов (и, собственно, продакшн-конфигурация) содержит его под ключом ‘username’:

2 лайка

Очень извиняюсь! Я всё ещё не понимаю, как это работает для всего, кроме резервного копирования.

Хм.

Возможно, в этом моя проблема. Но как тогда это работает для всего остального?

Возможно, для всего остального используется глобальная настройка из переменной окружения.

2 лайка

Мне очень жаль.

Я не подумал, что ActiveRecord::Base.connection_pool.db_config.configuration_hash — это просто то, что я ввёл в файл multisite.yml.

Я переименовал все свои ошибочные поля user: в username:, и теперь резервное копирование работает.

Моё объяснение (которое я не проверял) заключается в том, что остальная часть Rails переопределяет db_username из GlobalSettings, если там оно установлено, но когда нужно получить эту информацию для внешнего вызова pg_dump, она берётся из конфигурации multisite.

Я всё ещё считаю, что это баг: при резервном копировании используется другой пользователь, и исправление должно заключаться в том, чтобы включить чтение env['DISCOURSE_DB_USERNAME'] где-то в этом операторе присваивания. Но я не готов рисковать и снова ломать продакшн, а теперь всё работает.

Тебе стоит отменить лайк моего сообщения и убрать мою бейдж! :crying_cat_face:

2 лайка

Ничего страшного, такое бывает. В идеале это должно было быть обнаружено в CI, но, видимо, у нас нет покрытия для этой логики (возможно, это сложно, поскольку настройка базы данных в тестах всё равно отличается).

Спасибо, что задокументировали то, что вы нашли — это, безусловно, поможет другим в будущем. Я согласен, что такая несогласованность здесь — это плохо, и было бы хорошо исправить это в какой-то момент.

3 лайка