无法在 ubuntu 14.04 上进行发布更新

无法在 ubuntu 14.04 上进行发布更新

我目前正在尝试将 ubuntu 14.04 升级到 xenial。我尝试进行发布更新,但失败并出现错误,例如 UnicodeDecodeError: 'utf-8' codec can't decrypt byte 0x96 in position 382: invalid start byte

它看起来像已知错误- 我尝试过,但没有找到有问题的软件包,因此禁用/删除了 nodesource 和 veeam 存储库的 2 个非标准 package.lst 文件。

回溯内容如下

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

日志中没有任何真正有用的信息。我该如何让 do-release update 工作?

答案1

问题在于升级脚本本身在某处遇到了无效数据。您需要找到并删除无效数据。

在这种情况下,问题出在软件包上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再次运行;那样可能会下载一个新的。在错误日志中看到“Original exception was”后面的第一行?带有 的那行/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 开始)。

相关内容