Невозможно сделать обновление релиза на Ubuntu 14.04

27

В настоящее время я пытаюсь обновить коробку Ubuntu 14.04 до xenial. Я пытаюсь сделать обновление выпуска, и его сбой с ошибками, такими как UnicodeDecodeError: кодек «utf-8» не может декодировать байт 0x96 в позиции 382: недопустимый начальный байт

Это похоже на известную ошибку - я пробовал это, и мне не повезло найти нарушающий пакет, и отключил / удалил 2 моих нестандартных файла package.lst для репозиториев nodeource и veeam.

Traceback читает что-то вроде этого

Traceback (most recent call last):
  File "/tmp/ubuntu-release-upgrader-woadaq_z/xenial", line 8, in <module>
    sys.exit(main())
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeMain.py", line 242, in main
    if app.run():
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1876, in run
    return self.fullUpgrade()
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1757, in fullUpgrade
    if not self.doPostInitialUpdate():
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 943, in doPostInitialUpdate
    self.tasks = self.cache.installedTasks
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py", line 806, in installedTasks
    for line in pkg._pcache._records.record.split("\n"):
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x96 in position 382: invalid start byte
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/problem_report.py", line 416, in add_to_existing
    self.write(f)
  File "/usr/lib/python3/dist-packages/problem_report.py", line 369, in write
    block = f.read(1048576)
  File "/usr/lib/python3.4/codecs.py", line 319, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte

Original exception was:
Traceback (most recent call last):
  File "/tmp/ubuntu-release-upgrader-woadaq_z/xenial", line 8, in <module>
    sys.exit(main())
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeMain.py", line 242, in main
    if app.run():
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1876, in run
    return self.fullUpgrade()
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1757, in fullUpgrade
    if not self.doPostInitialUpdate():
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 943, in doPostInitialUpdate
    self.tasks = self.cache.installedTasks
  File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py", line 806, in installedTasks
    for line in pkg._pcache._records.record.split("\n"):
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x96 in position 382: invalid start byte
=== Command terminated with exit status 1 (Mon Apr  3 09:31:21 2017) ===

И нет ничего действительно полезного в журналах. Как мне получить обновление до релиза?

Подмастерье Компьютерщик
источник

Ответы:

44

То, что у вас есть, это сам скрипт обновления, который где-то отключает недействительные данные. Вам необходимо найти и удалить неверные данные.

В данном случае это был пакет veeamsnap. Удаление этого пакета должно исправить это. Но так как это отличается для каждого случая, я опишу шаги, предпринятые для достижения такого вывода. Это довольно сложный процесс.

Это забавно, потому что все строки python3 должны быть в UTF-8. То, что вы здесь (обнаружили после факта), - это модуль C ( apt_pkg), который каким-то образом вставляет данные, не относящиеся к UTF-8, в строку python3, поэтому разбивает все попытки чтения строки - обратите внимание, как сам обработчик ошибок также генерирует исключение?

Заходим в неизвестный отладчик !

Лучший способ диагностировать подобные проблемы - это заставить отладчик сделать паузу до сбоя линии. В Python, когда у вас есть ряд вложенных вызовов, подобных этому, самый простой способ добавить паузу отладчика - это отредактировать сам файл.

  1. Используя ваш пример, мы видим, что рассматриваемая ошибка находится в /tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.pyстроке 806 файла , поэтому давайте запустим текстовый редактор и перейдем к этой строке. Временной путь будет отличаться для каждого запуска, поэтому убедитесь, что вы используете тот, который указан в выводе ошибки!

    скриншот редактора

  2. Отсюда мы можем сначала добавить простую паузу в отладчике , вставив import pdb; pdb.set_trace();строку 806 непосредственно перед ошибкой. Поскольку это Python, отступ важен!

    скриншот заявления об отладке

  3. Теперь нам нужно запустить измененную программу. Не беги do-release-upgradeснова; это, вероятно, загрузит новый. Видите в журналах ошибок, первая строка после «Исходное исключение было»? Тот, с кем /tmp/ubuntu-release-upgrader-woadaq_z/xenial? Это тот, кого вы хотите запустить. Запустите этот файл от имени пользователя root (или sudo).

    Запуск, который должен привести вас в отладчик (pdb):

    скриншот отладчика

  4. Отсюда мы выясняем, сколько всего пакетов. Самый простой способ сделать это - бежать sum(1 for _ in self). Подождите немного (это может занять некоторое время), и он напечатает число. В данном случае так и было 76028.

    Теперь, поскольку ошибка, вероятно, не возникает в первые несколько, и мы не хотим вручную проходить через> 75000 пакетов, и мы не можем добавить обработчик исключений (поскольку ошибка настолько плоха, что нарушает сам Python) нам нужна альтернатива.

  5. Удалите строку, добавленную в шаге 4. Измените код, чтобы напечатать увеличивающийся номер для каждой упаковки. Например, добавьте foo = 0вышеуказанный цикл в строке 802 и foo += 1; print(foo)в строке 807 (непосредственно перед строкой с ошибками).

    скриншот номера, печатающего код

  6. Запустите код еще раз, используя ту же команду, что и в шаге 3. Он напечатает большой список чисел. Пусть он продолжает работать, пока не напечатает ошибку снова. Возможно, вам придется увеличить окно:

    скриншот вывода номера

    Этот последний номер должен быть пакетом, на котором он разбился. Запомните это число.

  7. Теперь, когда вы знаете, какой пакет / номер вызывает сбой, пришло время добавить паузу отладчика с условием выполнения только для этого пакета. Например, если вы потерпели крах в пакете 72285, добавьте if foo == 72285: import pdb; pdb.set_trace()сразу после строки, которая печатает foo:

    скриншот новой паузы pdb

  8. Запустите код еще раз. Теперь, когда вы попадете в pdbнего, должен быть пакет, который вызывает сбой. Вы можете ввести имя переменной, pkgчтобы напечатать ее значение, которое сообщит вам имя текущего пакета:

    снимок экрана с названием пакета

    В целом, ввод имени любой переменной напечатает ее вывод.

  9. Удалите поврежденный пакет и попробуйте обновить снова (из чистого do-release-upgrade).

боб
источник
7
Это очень хорошее, очень нежное введение в gdb, которое может использоваться с разным уровнем мастерства практически любым пользователем. +1 от меня и слава. И, кстати, вы можете просто добавить, что ввод pkg в отладчике напечатает значение переменной с тем же именем, как это определено в строке 803. Другими словами, pkg не является инструкцией отладчика. Приветствия.
MariusMatutiae
@MariusMatutiae Отредактировано. И это pdb;) (На самом деле это было больше предназначено для того, чтобы быть специфичным для решения этого класса проблем, но приятно, что вам легко следовать в качестве общего вступления.)
Bob
В частности, чтобы решить эту проблему, не проще ли добавить в скрипт строку, которая печатает все, что захочет распечатать отладочное сообщение, для записи пакета, которая не существует? (Это сообщение logging.debug прямо выше) Или это предполагает, что переменная pkg вообще не может быть напечатана из-за ошибки, а отладчик python может печатать что угодно вообще?
CausingUnderflowsEverywhere
Если у нас все еще есть блог Super User, это было бы отличным дополнением к нему!
Канадский Люк ОБНОВЛЯЕТ МОНИКУ
@CausingUnderflowsEverywhere Теоретически да. На практике подобное предложение из связанного отчета об ошибках, по-видимому, не сработало (я не уверен, почему, просто из того, что сказал мне OP), и я закончил делать это в интерактивном режиме в случае, если что-то еще вызвало сбой - например, не Знайте, что в этом случае это было само recordсвойство, которое не могло быть прочитано.
Боб