Skip to content

Commit

Permalink
fix(apt): Allow opt-in for calling apt update multiple times
Browse files Browse the repository at this point in the history
This is required to configure apt when dependency is not installed.

Fixes canonicalGH-5223
  • Loading branch information
holmanb committed Apr 29, 2024
1 parent acc68de commit 734958e
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 13 deletions.
4 changes: 3 additions & 1 deletion cloudinit/config/cc_apt_configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,9 @@ def _ensure_dependencies(cfg, aa_repo_match, cloud):
if not shutil.which(command):
missing_packages.append(PACKAGE_DEPENDENCY_BY_COMMAND[command])
if missing_packages:
cloud.distro.install_packages(sorted(missing_packages))
cloud.distro.install_packages(
sorted(missing_packages), allow_subsequent_updates=True
)


def add_apt_key(ent, cloud, gpg, hardened=False, file_name=None):
Expand Down
24 changes: 15 additions & 9 deletions cloudinit/distros/package_management/apt.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,16 @@ def from_config(cls, runner: helpers.Runners, cfg: Mapping) -> "Apt":
def available(self) -> bool:
return bool(subp.which(self.apt_get_command[0]))

def update_package_sources(self):
self.runner.run(
"update-sources",
self.run_package_command,
["update"],
freq=PER_INSTANCE,
)
def update_package_sources(self, allow_subsequent_updates: bool = False):
if allow_subsequent_updates:
self.run_package_command(["update"])
else:
self.runner.run(
"update-sources",
self.run_package_command,
["update"],
freq=PER_INSTANCE,
)

@functools.lru_cache(maxsize=1)
def get_all_packages(self):
Expand All @@ -140,8 +143,11 @@ def get_unavailable_packages(self, pkglist: Iterable[str]):
not in self.get_all_packages()
]

def install_packages(self, pkglist: Iterable) -> UninstalledPackages:
self.update_package_sources()
def install_packages(
self, pkglist: Iterable, allow_subsequent_updates: bool = False
) -> UninstalledPackages:
if not allow_subsequent_updates:
self.update_package_sources()
pkglist = util.expand_package_list("%s=%s", list(pkglist))
unavailable = self.get_unavailable_packages(
[x.split("=")[0] for x in pkglist]
Expand Down
4 changes: 3 additions & 1 deletion cloudinit/distros/package_management/package_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ def update_package_sources(self):
...

@abstractmethod
def install_packages(self, pkglist: Iterable) -> UninstalledPackages:
def install_packages(
self, pkglist: Iterable, allow_subsequent_updates: bool = False
) -> UninstalledPackages:
"""Install the given packages.
Return a list of packages that failed to install.
Expand Down
4 changes: 3 additions & 1 deletion cloudinit/distros/package_management/snap.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ def available(self) -> bool:
def update_package_sources(self):
pass

def install_packages(self, pkglist: Iterable) -> UninstalledPackages:
def install_packages(
self, pkglist: Iterable, allow_subsequent_updates: bool = False
) -> UninstalledPackages:
# Snap doesn't provide us with a mechanism to know which packages
# are available or have failed, so install one at a time
pkglist = util.expand_package_list("%s=%s", list(pkglist))
Expand Down
4 changes: 3 additions & 1 deletion tests/unittests/config/test_cc_apt_configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,9 @@ def fake_which(cmd):
which.side_effect = fake_which
cc_apt._ensure_dependencies(cfg, matcher, mycloud)
if expected_install:
install_packages.assert_called_once_with(expected_install)
install_packages.assert_called_once_with(
expected_install, allow_subsequent_updates=True
)
else:
install_packages.assert_not_called()

Expand Down

0 comments on commit 734958e

Please sign in to comment.