우분투 14.04에서 릴리스 업데이트를 수행 할 수 없습니다


27

현재 우분투 14.04 상자를 xenial로 업그레이드하려고합니다. 릴리스 업데이트를 수행하려고하는데 UnicodeDecodeError와 같은 오류로 실패합니다 : 'utf-8'코덱이 위치 382에서 바이트 0x96을 디코딩 할 수 없습니다 : 잘못된 시작 바이트

그것은 알려진 버그 처럼 보입니다 -나는 그것을 시도했지만 문제가되는 패키지를 찾지 못했습니다. 노드 소스 및 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- 릴리스 업데이트가 작동하려면 어떻게해야합니까?

답변:


44

업그레이드 스크립트 자체가 유효하지 않은 데이터에 어딘가에 걸려 있습니다. 유효하지 않은 데이터를 찾아서 제거해야합니다.

이 경우 패키지 veeamsnap였습니다. 해당 패키지를 제거하면 문제가 해결됩니다. 그러나 각 사례마다 다르기 때문에 결론에 도달하기 위해 취한 단계를 설명하겠습니다. 상당히 복잡한 과정입니다.

python3 문자열 모두 UTF-8 이어야 하기 때문에 이것은 재미있는 것 입니다. 여기에 (실제로 발견 된) C- 모듈 ( apt_pkg)은 python3 문자열에 비 UTF-8 데이터를 삽입하여 문자열을 읽을 때 모든 시도를 중단합니다-오류 처리기 자체가 어떻게 예외를 던 졌는지 주목하십시오.

알 수없는 디버거 우리가 간다!

이와 같은 문제를 진단하는 가장 좋은 방법은 디버거가 실패한 줄보다 먼저 일시 중지되도록하는 것입니다. Python을 사용하면 이와 같은 일련의 중첩 호출이 있으면 디버거 일시 중지를 추가하는 가장 쉬운 방법은 파일 자체를 편집하는 것입니다.

  1. 예제를 사용하여 문제의 실패가 파일 /tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py행 806에 있음을 알 수 있으므로 텍스트 편집기를 시작하고 해당 행으로 이동하십시오. 실행마다 온도 경로가 다르므로 오류 출력에서 ​​임시 경로를 사용해야합니다!

    에디터 스크린 샷

  2. 여기에서 먼저 오류 바로 앞에 806 행 을 삽입 하여 디버거에 간단한 일시 중지를 추가 할 수 있습니다 import pdb; pdb.set_trace();. 이것이 파이썬이기 때문에 들여 쓰기가 중요합니다!

    디버깅 문의 스크린 샷

  3. 이제 수정 된 프로그램을 실행해야합니다. do-release-upgrade다시 실행하지 마십시오 . 아마 새 파일을 다운로드 할 것입니다. "원래 예외는"이후의 첫 번째 행인 오류 로그를 참조하십시오. 와 하나 /tmp/ubuntu-release-upgrader-woadaq_z/xenial? 그것이 당신이 달리고 싶은 것입니다. 따라서 해당 파일을 루트 (또는 sudo)로 실행하십시오.

    실행하면 디버거 (pdb)로 이동해야합니다.

    디버거의 스크린 샷

  4. 여기에서 총 패키지 수를 파악합니다. 그렇게 쉬운 방법은 실행하는 것입니다 sum(1 for _ in self). 조금 기다립니다 (시간이 걸릴 수 있음). 그러면 숫자가 인쇄됩니다. 이 경우에는 76028입니다.

    이제 오류가 처음 몇 단계에서 발생하지 않을 것이므로 수동으로> 75000 패키지를 단계별로 실행하고 싶지 않으며 예외 처리기를 추가 할 수 없습니다 (오류가 너무 나쁘기 때문에 Python 자체를 손상시킵니다) 대안이 필요합니다.

  5. 4 단계에서 추가 한 행을 제거하십시오. 코드를 편집하여 모든 패키지에 대해 증분 번호를 인쇄하십시오. 예를 들어, foo = 0802 행과 foo += 1; print(foo)807 행의 루프 위에 (오류 행 직전) 추가하십시오.

    숫자 인쇄 코드의 스크린 샷

  6. 3 단계에서와 동일한 명령을 사용하여 코드를 다시 실행하십시오. 큰 숫자 목록이 인쇄됩니다. 오류가 다시 인쇄 될 때까지 계속 실행하십시오. 창을 확대해야 할 수도 있습니다.

    숫자 출력 스크린 샷

    마지막 숫자는 충돌 한 패키지 여야합니다. 그 번호를 기록해 두십시오.

  7. 이제 어떤 패키지 / 번호가 충돌을 일으키는 지 알았으므로 이제는 해당 패키지에서만 실행할 조건으로 디버거 일시 중지를 추가해야합니다. 예를 들어 package 72285에서 충돌이 발생하면 다음 if foo == 72285: import pdb; pdb.set_trace()을 인쇄하는 줄 바로 뒤에 추가하십시오 foo.

    새로운 pdb 일시 정지 스크린 샷

  8. 코드를 다시 실행하십시오. 이제 들어가면 pdb충돌을 일으키는 패키지에 있어야합니다. 변수의 이름을 입력 pkg하여 값을 인쇄하면 현재 패키지의 이름을 알 수 있습니다.

    패키지 이름의 스크린 샷

    보다 일반적으로 변수 이름을 입력하면 출력이 인쇄됩니다.

  9. 문제가있는 패키지를 제거하고 깨끗한 do-release-upgrade에서 업그레이드를 다시 시도하십시오.


7
이것은 gdb에 대한 매우 훌륭하고 부드러운 소개이며, 거의 모든 사용자가 다른 수준의 숙련도로 사용할 수 있습니다. 나와 +1 및 kudos 그리고 BTW, 디버거에 pkg 를 입력 하면 803 행에 정의 된 것과 같은 이름의 변수 값이 인쇄 된다는 것을 추가 할 수 있습니다 . 즉, pkg 는 디버거 명령이 아닙니다. 건배.
MariusMatutiae

@MariusMatutiae 편집했습니다. 그리고 그것의 PDB) (이 실제로 문제의이 클래스를 해결하는 구체적으로 더 예정되었다, 그러나 그것의 좋은 당신이 쉽게 일반적인 소개로 참조 할 수 있음).

특히이 문제를 해결하기 위해 존재하지 않는 패키지 레코드에 대해 디버그 메시지가 인쇄하려는 항목을 인쇄하는 행을 스크립트에 추가하는 것이 쉽지 않을까요? (위에 logging.debug 메시지가 있습니다) 아니면 버그로 인해 pkg 변수를 전혀 인쇄 할 수 없으며 파이썬 디버거가 아무것도 인쇄 할 수 있다고 가정합니까?
CausingUnderflowsEverywhere

우리가 여전히 수퍼 유저 블로그를 가지고 있다면 이것은 훌륭한 추가 기능이 될 것입니다!
Canadian Luke REINSTATE MONICA

@CausingUnderflowsEverywhere 이론적으로는 그렇습니다. 실제로, 연결된 버그 보고서의 비슷한 제안은 분명히 작동하지 않았으며 (왜 OP가 나에게 말했는지에 대해서는 확실하지 않습니다) 다른 것이 충돌을 일으킨 경우 대화식으로 수행했습니다. 이 경우 record읽을 수없는 것은 재산 자체 라는 것을 알고 있습니다.
Bob
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.