Обнаружение/предотвращение множественных установок apt-get/dpkg

У меня есть скрипты, которые новые пользователи запускают для настройки своей системы, в основном скрипт bash с большим циклом for, например:

DEBCOUNT=${#DEBS[@]}
for (( i=0; i<${DEBCOUNT}; i++ ));
do
  PACKAGE=${DEBS[$i]}
  dpkg -s ${PACKAGE} >> /dev/null
  if [ ${PIPESTATUS[0]} -ne 0 ]; then
    echo -n  =========== Installing ${PACKAGE}
    echo "  ( $((${i}*100/${DEBCOUNT}))% )"

    apt-get -qq install -y --force-yes  ${PACKAGE}
    if [ $? -ne 0 ]; then
      echo ERROR: Failed to install required package ${PACKAGE}
      exit 1
    fi
  else
    echo -n  =========== Skipping ${PACKAGE}
    echo "  ( $((${i}*100/${DEBCOUNT}))% )"
  fi
done

Большой массив DEBS представляет собой список из 50 пакетов для установки в новую систему (в основном это компиляторы и редакторы).

Он отлично работает, за исключением случая, когда какой-то системный процесс срабатывает и начинает обновлять базы данных APT в фоновом режиме. Затем происходит сбой с dpkg: error: dpkg status database is locked by another process.

Есть ли элегантный/надежный способ избежать этой ошибки? Либо обнаружив его и каким-то образом ожидая, пока он освободится, либо путем предотвращения его в первую очередь.

Ответы

  • Я не хочу просто удалить файл блокировки. Попытка установить мои вещи и все, что система делает одновременно, неизбежно что-то сломает.
  • Я не могу выполнить единственную проверку при запуске, поскольку то, что я вижу, указывает на то, что другой процесс ожидает того, что я хочу, и прыгает между двумя моими apt-get.
  • Это не один процесс, выполняющий блокировку. Иногда я думаю, что это программа обновления программного обеспечения Ubuntu, иногда я думаю, что это cron задание, выполняющее большой apt-get update .

person Yeraze    schedule 12.05.2014    source источник
comment
почему бы не использовать все пакеты одним махом с помощью apt-get вместо того, чтобы устанавливать пакеты один за другим? Кроме того, я всегда буду избегать --force-yes, так как вы будете упускать из виду основную проблему, пробиваясь через нее.   -  person slayedbylucifer    schedule 12.05.2014
comment
вы не можете установить два пакета одновременно в Ubuntu.   -  person Avinash Raj    schedule 12.05.2014
comment
Большой командой был первоначальный дизайн, но несколько пакетов пришли из PPA и оставляли систему в странном состоянии, если их не удалось установить. выяснить, какие из них пропали. Это безопаснее (хотя и медленнее).   -  person Yeraze    schedule 12.05.2014
comment
@avinash Duh .. в этом суть вопроса .. как мне предотвратить это от другого процесса? Или как мне обнаружить это и узнать, когда это безопасно?   -  person Yeraze    schedule 12.05.2014
comment
Не уверен, насколько это эффективно, но попробуйте запустить rm -f /var/lib/dpkg/lock непосредственно перед командой apt-get ... в цикле for. Таким образом, вы снимете блокировку (если она есть) перед запуском установки пакета.   -  person slayedbylucifer    schedule 12.05.2014
comment
Обходной путь: until dpkg -s ${PACKAGE} >> /dev/null; do sleep 1; done ? Возможно, проверьте фактическое значение $?, если переустановка пакета возвращает ошибку...   -  person anishsane    schedule 12.05.2014
comment
Почему бы вам просто не проверить перед запуском скрипта, если программа обновления youbuntu находится в ps -ef, и убить ее с -15 уровнем.   -  person Max    schedule 12.05.2014


Ответы (3)


Я пришел сюда с тем же вопросом, чтобы определить, заблокирован ли файл блокировки, используемый apt-get и dpkg, не говоря уже о том, является ли это наиболее подходящим тестом для выполнения (это в моем случае). В итоге я использовал следующий фрагмент кода Python:

import fcntl

def is_dpkg_active():
    """
    Check whether ``apt-get`` or ``dpkg`` is currently active.

    This works by checking whether the lock file ``/var/lib/dpkg/lock`` is
    locked by an ``apt-get`` or ``dpkg`` process, which in turn is done by
    momentarily trying to acquire the lock. This means that the current process
    needs to have sufficient privileges.

    :returns: ``True`` when the lock is already taken (``apt-get`` or ``dpkg``
              is running), ``False`` otherwise.
    :raises: :py:exc:`exceptions.IOError` if the required privileges are not
             available.

    .. note:: ``apt-get`` doesn't acquire this lock until it needs it, for
              example an ``apt-get update`` run consists of two phases (first
              fetching updated package lists and then updating the local
              package index) and only the second phase claims the lock (because
              the second phase writes the local package index which is also
              read from and written to by ``dpkg``).
    """
    with open('/var/lib/dpkg/lock', 'w') as handle:
        try:
            fcntl.lockf(handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
            return False
        except IOError:
            return True
person xolox    schedule 04.08.2014

Правильное решение — заменить ваш сложный скрипт фиктивным пакетом, который Depends: во всех других пакетах, которые вы хотите установить.

Пакет equivs — это простой (хотя поначалу не очень интуитивный) способ создания такого фиктивного пакета.

Кстати, это не специальный взлом; вот как например пакет Debian build-essential включает всю цепочку сборки.

person tripleee    schedule 12.05.2014
comment
Можете ли вы рассказать больше о настройке Depends:? Это где-то конфиг? Это какие-то специальные настройки пакета? Как мне это использовать или где я могу найти дополнительную информацию? - person Xeoncross; 05.06.2014
comment
Это объявление в файле debian/control в исходном коде пакета, который вы собираете. Действительно, ознакомьтесь с equivs документацией. - person tripleee; 05.06.2014

Ответ @tripleee - лучший, но если по какой-то причине вы не можете этого сделать (и я знаю, что в некоторых редких случаях это правда - потому что это происходит для нас), правильно будет ввести одну команду, вместо использования цикла:

apt-get -qq install -y --force-yes $DEBS
person Flimzy    schedule 14.05.2014
comment
Что ж, это все еще не решает основную проблему: даже один массивный apt-get завершится ошибкой, если средство обновления программного обеспечения или задание cron обновляет базу данных APT в фоновом режиме. Есть ли способ определить, что APT уже используется, и подождать? - person Yeraze; 19.05.2014
comment
Тогда лучшим вариантом будет запуск в цикле, и если вы обнаружите сбой, повторите попытку. Если вы обнаружите успех, выйдите из цикла. - person Flimzy; 19.05.2014
comment
Ну, некоторые сбои являются катастрофическими: (не удается разрешить зависимость, сервер не работает и т. д.). Я просто хочу обнаружить один простой: (не удается получить блокировку). - person Yeraze; 19.05.2014
comment
@Yeraze: Вы можете определить это, изучив вывод ошибок из apt-get и выполнив поиск, например, слова «блокировка». - person Flimzy; 19.05.2014