Impossibile eseguire l'aggiornamento della versione su Ubuntu 14.04


27

Attualmente sto cercando di aggiornare una scatola Ubuntu 14.04 a xenial. Sto provando a fare l'aggiornamento del rilascio e il suo fallimento con errori come UnicodeDecodeError: il codec 'utf-8' non può decodificare il byte 0x96 nella posizione 382: byte iniziale non valido

Sembra un bug noto - l'ho provato e non ho avuto fortuna a trovare il pacchetto offensivo e ho disabilitato / rimosso i miei 2 file package.lst non standard per i repository nodesource e veeam.

Il traceback legge qualcosa del genere

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

E non c'è nulla di veramente utile nei registri. Come farei a far funzionare l'aggiornamento di do-release?

Risposte:


44

Quello che hai lì è lo stesso script di aggiornamento che inciampa su dati non validi da qualche parte. Devi trovare e rimuovere i dati non validi.

In questo caso, era il pacchetto veeamsnap. La rimozione di quel pacchetto dovrebbe risolverlo. Ma poiché questo è diverso per ogni caso, descriverò i passi compiuti per giungere a tale conclusione. È un processo abbastanza complicato.

Questo è divertente, perché le stringhe python3 dovrebbero essere tutte in UTF-8. Quello che hai qui (scoperto dopo il fatto) è un modulo C ( apt_pkg) che in qualche modo inserisce dati non UTF-8 in una stringa python3, interrompendo quindi ogni tentativo di leggere la stringa - noti come anche il gestore degli errori ha lanciato un'eccezione?

Andiamo nello sconosciuto debugger !

Il modo migliore per diagnosticare problemi come questo è far sospendere il debugger prima che la linea fallisca. Con Python, quando si dispone di una serie di chiamate nidificate come questa, il modo più semplice per aggiungere una pausa di debugger è modificare il file stesso.

  1. Usando il tuo esempio, possiamo vedere che l'errore in questione si trova nella /tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.pyriga del file 806, quindi accendiamo un editor di testo e andiamo a quella riga. Il percorso temporaneo sarà diverso per ogni corsa, quindi assicurati di utilizzare quello dal tuo output di errore!

    screenshot dell'editor

  2. Da qui, possiamo prima aggiungere una semplice pausa nel debugger , inserendo import pdb; pdb.set_trace();nella riga 806 poco prima dell'errore. Poiché questo è Python, il rientro è importante!

    screenshot dell'istruzione di debug

  3. Ora dobbiamo eseguire il programma modificato. Non correre di do-release-upgradenuovo; che probabilmente ne scaricherà uno nuovo. Vedi nei log degli errori, la prima riga dopo "Eccezione originale"? Quello con /tmp/ubuntu-release-upgrader-woadaq_z/xenial? È quello che vuoi correre. Quindi esegui quel file, come root (o sudo).

    L'esecuzione che dovrebbe farti entrare nel debugger (pdb):

    screenshot del debugger

  4. Da qui, scopriamo quanti pacchetti ci sono in totale. Il modo più semplice per farlo è eseguire sum(1 for _ in self). Aspetta un po '(questo può richiedere del tempo) e stamperà un numero. In questo caso, lo era 76028.

    Ora, poiché l'errore probabilmente non si verifica nei primi, e non vogliamo scorrere manualmente> 75000 pacchetti e non possiamo aggiungere un gestore di eccezioni (perché l'errore è così grave che rompe Python stesso) , abbiamo bisogno di un'alternativa.

  5. Rimuovere la riga aggiunta nel passaggio 4. Modificare il codice per stampare un numero crescente per ogni pacchetto. Ad esempio, aggiungi foo = 0sopra il loop sulla riga 802 e foo += 1; print(foo)sulla riga 807 (appena prima della riga di errore).

    screenshot del codice di stampa numerica

  6. Eseguire nuovamente il codice, usando lo stesso comando del passaggio 3. Verrà stampato un ampio elenco di numeri. Lasciarlo funzionare fino a quando non stampa di nuovo l'errore. Potrebbe essere necessario ingrandire la finestra:

    screenshot dell'output numerico

    L'ultimo numero dovrebbe essere il pacchetto su cui si è schiantato. Prendi nota di quel numero.

  7. Ora che sai quale pacchetto / numero causa l'arresto, è tempo di aggiungere la pausa del debugger con una condizione da eseguire solo su quel pacchetto. Ad esempio, se si arresta in modo anomalo sul pacchetto 72285, aggiungere if foo == 72285: import pdb; pdb.set_trace()subito dopo la riga che stampa foo:

    screenshot della nuova pausa pdb

  8. Esegui di nuovo il codice. Ora quando entri pdbdovrebbe essere sul pacchetto che causa l'arresto anomalo. Puoi digitare il nome della variabile pkgper stampare il suo valore, che ti dirà il nome del pacchetto corrente:

    screenshot del nome del pacchetto

    Più in generale, digitando il nome di qualsiasi variabile verrà stampato il suo output.

  9. Rimuovere il pacchetto offensivo e riprovare a eseguire l'aggiornamento (da un do-release-upgrade pulito).


7
Questa è un'introduzione molto piacevole e molto delicata a gdb, che può essere utilizzata con diversi livelli di competenza praticamente da qualsiasi utente. +1 da me e complimenti. E, a proposito, puoi semplicemente aggiungere che digitando pkg nel debugger verrà stampato il valore della variabile con lo stesso nome, come definito nella riga 803. In altre parole, pkg non è un'istruzione debugger. Saluti.
MariusMatutiae,

@MariusMatutiae Edited. Ed è pdb;) (In realtà questo era più inteso per essere specifico per risolvere questa classe di problemi, ma è bello che tu trovi facile da seguire come introduzione generale.)
Bob

Per risolvere questo problema in particolare, non sarebbe più semplice aggiungere una riga allo script che stampa ciò che quel messaggio di debug desidera stampare per un record del pacchetto che non esiste? (C'è quel messaggio logging.debug proprio sopra) O questo presuppone che la variabile pkg potrebbe non essere affatto stampabile a causa del bug e il debugger python può stampare qualcosa?
CausingUnderflowsOwherewhere

Se avessimo ancora il blog Super User, questa sarebbe un'aggiunta eccellente ad esso!
Canadian Luke REINSTATE MONICA

@CausingUnderflowsEverywhere In teoria, sì. In pratica, un suggerimento simile dalla segnalazione di bug collegata apparentemente non ha funzionato (non sono sicuro del perché, proprio da quello che mi ha detto OP) e ho finito per farlo in modo interattivo nel caso in cui qualcos'altro abbia scatenato l'incidente - ad es. sappi che in questo caso era la recordproprietà stessa che non poteva essere letta.
Bob
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.