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) ===

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

1 ответ1

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).

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .