Skip to content

Commit

Permalink
vmupdate: improve waiting for apt-get update lock
Browse files Browse the repository at this point in the history
"apt-get update" doesn't support waiting for other instances to finish,
it exits immediately instead. With CLI apt-get version, it's possible to
get it waiting externally (by taking the lock manually, and then
make apt-get not try to lock it again). Unfortunately the same cannot
be done for the API version, because there is no way (I can find)
to disable locking in the apt.Cache.update() function.

Workaround for missing feature https://bugs.debian.org/1069167
  • Loading branch information
marmarek committed Jan 5, 2025
1 parent 1d8ebf9 commit d5759de
Showing 1 changed file with 18 additions and 5 deletions.
23 changes: 18 additions & 5 deletions vmupdate/agent/source/apt/apt_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import fcntl
import os
import contextlib
from typing import List

from source.common.package_manager import PackageManager
Expand All @@ -38,12 +39,21 @@ def __init__(self, log_handler, log_level,):
# to prevent a warning: `debconf: unable to initialize frontend: Dialog`
os.environ['DEBIAN_FRONTEND'] = 'noninteractive'

def wait_for_lock(self):
@contextlib.contextmanager
def apt_lock(self):
"""
Wait for any other apt-get instance to finish.
Contex manager for locking compatible with 'apt-get update' lock.
"""
with open("/var/lib/apt/lists/lock", "rb+") as f_lock:
fcntl.lockf(f_lock.fileno(), fcntl.LOCK_EX)
yield

def wait_for_lock(self):
"""
Wait for any other apt-get instance to finish.
"""
with self.apt_lock():
pass

def refresh(self, hard_fail: bool) -> ProcessResult:
"""
Expand All @@ -52,9 +62,12 @@ def refresh(self, hard_fail: bool) -> ProcessResult:
:param hard_fail: raise error if some repo is unavailable
:return: (exit_code, stdout, stderr)
"""
self.wait_for_lock()
cmd = [self.package_manager, "-q", "update"]
result = self.run_cmd(cmd)
# apply lock externally to wait for it, until
# https://bugs.debian.org/1069167 gets implemented
with self.apt_lock():
cmd = [self.package_manager,
"-o", "Debug::NoLocking=true", "-q", "update"]
result = self.run_cmd(cmd)
# 'apt-get update' reports error with exit code 100, but updater as a
# whole reserves it for "no updates"
if result.code == 100:
Expand Down

0 comments on commit d5759de

Please sign in to comment.