Nie można wykonać aktualizacji wersji na Ubuntu 14.04

27

Obecnie próbuję uaktualnić system Ubuntu 14.04 do Xenial. Próbuję zrobić aktualizację wydania, a jej błąd kończy się niepowodzeniem z błędami takimi jak UnicodeDecodeError: kodek „utf-8” nie może zdekodować bajtu 0x96 na pozycji 382: nieprawidłowy bajt początkowy

Wygląda jak znany błąd - próbowałem tego i nie miałem szczęścia znaleźć szkodliwego pakietu, a także wyłączyłem / usunąłem moje 2 niestandardowe pliki package.lst dla repozytoriów nodesource i veeam.

Trackback czyta coś takiego

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

W dziennikach nie ma nic naprawdę pomocnego. Jak mogę uzyskać aktualizację do wydania?

Journeyman Geek
źródło

Odpowiedzi:

44

To, co tam masz, to sam skrypt aktualizacji, który potyka się o nieprawidłowe dane. Musisz znaleźć i usunąć nieprawidłowe dane.

W tym przypadku była to paczka veeamsnap. Usunięcie tego pakietu powinno go naprawić. Ponieważ jednak jest inaczej w każdym przypadku, opiszę kroki podjęte w celu osiągnięcia tego wniosku. Jest to dość skomplikowany proces.

To jest zabawne, ponieważ wszystkie ciągi python3 powinny być w UTF-8. To, co masz tutaj (odkryte po fakcie), to moduł C ( apt_pkg) w jakiś sposób wstawiający dane spoza UTF-8 do łańcucha python3, a zatem przerywający każdą próbę odczytu łańcucha - zauważ, jak sama procedura obsługi błędów również zgłasza wyjątek?

Wchodzimy w nieznany debugger !

Najlepszym sposobem na zdiagnozowanie takich problemów jest spowodowanie wstrzymania debugera przed awarią linii. W Pythonie, gdy masz serię takich zagnieżdżonych wywołań, najłatwiejszym sposobem dodania pauzy debuggera jest edycja samego pliku.

  1. Korzystając z Twojego przykładu, możemy zobaczyć, że awaria jest w /tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.pylinii pliku 806, więc uruchommy edytor tekstu i przejdźmy do tej linii. Ścieżka temp będzie inna dla każdego uruchomienia, więc upewnij się, że używasz ścieżki z wyjścia błędu!

    zrzut ekranu edytora

  2. Stąd możemy najpierw dodać prostą pauzę do debuggera , wstawiając import pdb; pdb.set_trace();wiersz 806 tuż ​​przed błędem. Ponieważ jest to Python, wcięcie jest ważne!

    zrzut ekranu instrukcji debugowania

  3. Teraz musimy uruchomić zmodyfikowany program. Nie biegnij do-release-upgradeponownie; prawdopodobnie pobierze nowy. Widzisz w dziennikach błędów, pierwszy wiersz po „Pierwotnym wyjątkiem był”? Ten z /tmp/ubuntu-release-upgrader-woadaq_z/xenial? To ten, który chcesz uruchomić. Uruchom więc ten plik jako root (lub sudo).

    Uruchomienie, które powinno doprowadzić cię do debuggera (pdb):

    zrzut ekranu z debuggera

  4. Z tego miejsca ustalamy, ile jest w sumie pakietów. Łatwy sposób to zrobić , to uruchomienie sum(1 for _ in self). Poczekaj chwilę (może to chwilę potrwać), aby wydrukować numer. W tym przypadku tak było 76028.

    Teraz, ponieważ błąd prawdopodobnie nie występuje w pierwszych kilku, a my nie chcemy ręcznie przechodzić przez> 75000 pakietów i nie możemy dodać procedury obsługi wyjątków (ponieważ błąd jest tak zły, że psuje sam Python) , potrzebujemy alternatywy.

  5. Usuń wiersz dodany w kroku 4. Edytuj kod, aby wydrukować liczbę rosnącą dla każdej paczki. Na przykład dodaj foo = 0powyżej pętli na linii 802 i foo += 1; print(foo)linii 807 (tuż przed błędną linią).

    zrzut ekranu kodu drukującego cyfry

  6. Uruchom kod ponownie, używając tego samego polecenia, co w kroku 3. Spowoduje to wydrukowanie dużej listy liczb. Pozwól mu działać, dopóki błąd nie zostanie ponownie wydrukowany. Może być konieczne powiększenie okna:

    zrzut ekranu wyjścia liczbowego

    Ten ostatni numer powinien być paczką, na której się rozbił. Zanotuj ten numer.

  7. Teraz, gdy wiesz, który pakiet / numer powoduje awarię, nadszedł czas, aby dodać pauzę debugera z warunkiem wykonania tylko na tym pakiecie. Na przykład, jeśli zawiesisz się na pakiecie 72285, dodaj if foo == 72285: import pdb; pdb.set_trace()tuż po linii, która jest drukowana foo:

    zrzut ekranu nowej pauzy pdb

  8. Uruchom kod ponownie. Teraz, gdy wejdziesz w pdbto, powinieneś znaleźć się na pakiecie, który powoduje awarię. Możesz wpisać nazwę zmiennej, pkgaby wydrukować jej wartość, która poda nazwę bieżącego pakietu:

    zrzut ekranu z nazwą pakietu

    Mówiąc bardziej ogólnie, wpisanie nazwy dowolnej zmiennej spowoduje wydrukowanie jej wyniku.

  9. Usuń niepoprawny pakiet i spróbuj ponownie przeprowadzić aktualizację (z czystej aktualizacji do-release-upgrade).

Kok
źródło
7
To bardzo miłe, bardzo delikatne wprowadzenie do gdb, które może być używane z różnymi poziomami biegłości przez prawie każdego użytkownika. +1 ode mnie i podziękowania. A BTW, możesz po prostu dodać, że wpisanie pkg w debuggerze wypisze wartość zmiennej o tej samej nazwie, jak zdefiniowano w linii 803. Innymi słowy, pkg nie jest instrukcją debuggera. Twoje zdrowie.
MariusMatutiae
@MariusMatutiae Edytowane. I to jest pdb;) (To rzeczywiście było bardziej specyficzne, aby rozwiązać tę klasę problemów, ale fajnie, że łatwo jest ci się podążać za ogólnym intrem.)
Bob
Aby rozwiązać ten problem, czy nie byłoby łatwiej po prostu dodać wiersz do skryptu, który wypisuje cokolwiek komunikat debugowania chce wydrukować dla rekordu pakietu, który nie istnieje? (Tam jest komunikat, że logowanie.debug bezpośrednio powyżej). Czy to zakłada, że ​​zmienna pkg może w ogóle nie zostać wydrukowana z powodu błędu, a debugger w Pythonie może w ogóle coś wydrukować?
CausingUnderflowsEverwhere
Jeśli nadal będziemy mieć blog Super User, byłby to doskonały dodatek!
Kanadyjczyk Luke REINSTATE MONICA
@CausingUnderflowsEverywhere Teoretycznie tak. W praktyce podobna sugestia z połączonego raportu o błędach najwyraźniej nie zadziałała (nie jestem pewien dlaczego, tylko z tego, co powiedział mi OP) i skończyłem robić to interaktywnie na wypadek, gdyby coś innego spowodowało awarię - np. Nie wiedz, że w tym przypadku nie recordmożna było odczytać samej własności.
Bob