No se puede hacer la actualización de lanzamiento en ubuntu 14.04

27

Actualmente estoy tratando de actualizar un cuadro de Ubuntu 14.04 a xenial. Estoy tratando de hacer una actualización de lanzamiento, y falla con errores como UnicodeDecodeError: el códec 'utf-8' no puede decodificar el byte 0x96 en la posición 382: byte de inicio no válido

Parece un error conocido : lo intenté y no tuve suerte de encontrar el paquete ofensivo, y deshabilité / eliminé mis 2 archivos package.lst no estándar para los repositorios de noeource y veeam.

El rastreo lee algo como esto

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

Y no hay nada realmente útil en los registros. ¿Cómo conseguiría que funcione la actualización de lanzamiento?

Journeyman Geek
fuente

Respuestas:

44

Lo que tienes allí es el script de actualización en sí mismo tropezando con datos no válidos en alguna parte. Necesita encontrar y eliminar los datos no válidos.

En este caso, fue el paquete veeamsnap. Eliminar ese paquete debería solucionarlo. Pero debido a que esto es diferente para cada caso, describiré los pasos tomados para llegar a esa conclusión. Es un proceso bastante complicado.

Esta es divertida, porque las cadenas python3 deberían estar todas en UTF-8. Lo que tienes aquí (descubierto después del hecho) es un módulo C ( apt_pkg) que de alguna manera inserta datos que no son UTF-8 en una cadena de python3, por lo tanto, interrumpe cada intento de leer la cadena. ¿Ves cómo el controlador de errores también arrojó una excepción?

¡Al depurador desconocido vamos!

La mejor manera de diagnosticar problemas como este es hacer que el depurador haga una pausa antes de la línea que falla. Con Python, cuando tiene una serie de llamadas anidadas como esta, la forma más fácil de agregar una pausa del depurador es editar el archivo en sí.

  1. Usando su ejemplo, podemos ver que la falla en cuestión está en la /tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.pylínea 806 del archivo , así que activemos un editor de texto y vayamos a esa línea. La ruta temporal será diferente para cada ejecución, ¡así que asegúrese de usar la de su salida de error!

    captura de pantalla del editor

  2. Desde aquí, primero podemos agregar una pausa simple en el depurador , insertando import pdb; pdb.set_trace();en la línea 806 justo antes del error. ¡Porque esto es Python, la sangría es importante!

    captura de pantalla de la declaración de depuración

  3. Ahora necesitamos ejecutar el programa modificado. No corras de do-release-upgradenuevo; eso probablemente descargará uno nuevo. ¿Ves en los registros de errores, la primera línea después de "La excepción original fue"? ¿El que tiene /tmp/ubuntu-release-upgrader-woadaq_z/xenial? Ese es el que quieres correr. Entonces ejecute ese archivo, como root (o sudo).

    Ejecución que debería llevarlo al depurador (pdb):

    captura de pantalla del depurador

  4. A partir de aquí, calculamos cuántos paquetes hay en total. La manera fácil de hacerlo es correr sum(1 for _ in self). Espere un poco (esto puede tomar un tiempo) e imprimirá un número. En este caso, lo fue 76028.

    Ahora, dado que el error probablemente no ocurre en los primeros, y no queremos pasar manualmente por> 75000 paquetes, y no podemos agregar un controlador de excepción (porque el error es tan grave que rompe Python) Necesitamos una alternativa.

  5. Elimine la línea agregada en el paso 4. Edite el código para imprimir un número incremental para cada paquete. Por ejemplo, agregue foo = 0encima del bucle en la línea 802 y foo += 1; print(foo)en la línea 807 (justo antes de la línea de error).

    captura de pantalla del código de impresión de números

  6. Vuelva a ejecutar el código, utilizando el mismo comando que en el paso 3. Imprimirá una gran lista de números. Deje que siga funcionando hasta que imprima el error nuevamente. Es posible que deba agrandar su ventana:

    captura de pantalla de salida de número

    Ese último número debería ser el paquete en el que se estrelló. Tenga en cuenta ese número.

  7. Ahora que sabe qué paquete / número causa el bloqueo, es hora de agregar la pausa del depurador con la condición de que solo se ejecute en ese paquete. Por ejemplo, si se bloquea el paquete 72285, agregue if foo == 72285: import pdb; pdb.set_trace()justo después de la línea que se imprime foo:

    captura de pantalla de la nueva pausa pdb

  8. Ejecute el código nuevamente. Ahora, cuando entras pdb, debe estar en el paquete que causa el bloqueo. Puede escribir el nombre de la variable pkgpara imprimir su valor, que le indicará el nombre del paquete actual:

    captura de pantalla del nombre del paquete

    En términos más generales, escribir el nombre de cualquier variable imprimirá su salida.

  9. Elimine el paquete ofensivo e intente la actualización nuevamente (desde una actualización limpia).

Mover
fuente
77
Esta es una introducción muy agradable y muy suave a gdb, que puede ser utilizada con diferentes niveles de competencia por casi cualquier usuario. +1 de mi parte, y felicitaciones. Y, por cierto, puede agregar que escribir pkg en el depurador imprimirá el valor de la variable del mismo nombre, como se define en la línea 803. En otras palabras, pkg no es una instrucción de depurador. Aclamaciones.
MariusMatutiae
@MariusMatutiae Editado. Y es pdb;) (Esto en realidad tenía la intención de ser más específico para resolver esta clase de problemas, pero es bueno que le resulte fácil seguirlo como introducción general.)
Bob
Para resolver este problema en particular, ¿no sería más fácil agregar una línea al script que imprima lo que el mensaje de depuración quiera imprimir para un registro de paquete que no existe? (Hay ese mensaje logging.debug justo arriba) ¿O esto supone que la variable pkg podría no poder imprimirse debido al error, y el depurador de python puede imprimir cualquier cosa?
CausingUnderflowsEverywhere
Si todavía tenemos el blog Super User, ¡esta sería una excelente adición a él!
Canadian Luke REINSTATE MONICA
@CausingUnderflowsEverywhere En teoría, sí. En la práctica, una sugerencia similar del informe de error vinculado aparentemente no funcionó (no estoy seguro de por qué, solo por lo que OP me dijo) y terminé haciéndolo interactivamente en caso de que algo más desencadenara el bloqueo, por ejemplo, no Sabemos que en este caso fue la recordpropiedad misma la que no se pudo leer.
Bob