Skip to content

Commit

Permalink
feat: load deb822 sources; use add-apt-repository to add (#137)
Browse files Browse the repository at this point in the history
Ubuntu 24.04 uses [deb288 format](https://manpages.ubuntu.com/manpages/noble/en/man5/sources.list.5.html) sources, which python-libjuju does not currently support (as pointed out by @yanksyoon and @NucciTheBoss in #135). This merge commit adds support for reading `*sources` files.

`RepositoryMapping` now automatically findes them in `/etc/apt/sources.list.d` when initialised. Additionally, to avoid an `InvalidSourceError` if `/etc/apt/sources.list` exists but only includes a comment about the new sources location (as it does on noble), we ignore this error if `/etc/apt/sources.list.d/ubuntu.sources` exists.

This merge commit also cleans up the `add` method by calling `add-apt-repository` internally instead of writing directly to a file. Note that this means that adding a disabled repository no longer has any effect (previously it would write a a file containing a single, commented-out one-line repository definition).

Original commit messages below.

---

* feat: support deb822 style source specification

Ubuntu 24.04 adopts the deb822 style source specification. Such files
are listed in /etc/apt/sources.list.d/*sources, and allow the
specification of sources in a multi-line format

* refactor: separate file reading and object updating from parsing lines

* refactor: preserve line nos when parsing deb822 lines into paragraphs

* refactor: move turning numbered lines into options dict to helper

* feat: support inline comments in deb822 source files

* tests: add some unit tests for _iter_deb822_paragraphs

* fix: raise an InvalidSourceError on missing required deb822 keys

* tests: add some unit tests for _get_deb822_options

* fix: correctly handle newline terminated lines in paragraph iteration

* tests: add some unit tests for _iter_deb822_paragraphs

* tests: add some tests for _parse_deb822_lines

* feat: add the number of errors to the debug output in load_deb822

* tests: add some unit tests for load_deb822

* tests: add a unit test for initialiasing RepositoryMapping with deb822

* style: tox -e fmt tests/unit/test_apt.py

* fix: correct docstring

* fix: python3.8 context managers and clean up linter directives

* feat: make DebianRepository aware of deb822 format for some operations

add: add ability to write a deb822 format file
disable: raise NotImplementedError for deb822 format files
gpg_key: use existing import_key functionality to provide keys specified
    in the stanza itself as a file for compatibility
Also refactor Deb822 functionality to a separate class.
Also move deb822 unit tests to the more appropriate test_repo.py

* fix: remove extraneous information from docstring

* feat: use apt-add-repository for RepositoryMapping.add

* refactor: logic and testing cleanup

* style: type annotate integration test helper function

* feat: support apt autoremove in remove_package

* feat: debug useful information on error in apt.update

* feat: log when writing to a sources file in from_repo_line

* feat: make the apt directories (private) attributes (for testing)

* style: correct RepositoryMapping.__iter__ annotation and add FIXME

* feat: log the filename as well as the number of repos when parsing

* feat: refactor RepositoryMapping.add to possible support remove as well

* feat: allow _Deb822Stanza from an empty set of lines

* tests: add unit tests that use files on disk

* tests: update integration tests

* feat: use sourceslist (one-per-line) format for add-apt-repository

* feat: call _add_apt_repository in from_repo_line (don't reimplement logic)

* tests: re-enable package cleanup in integration tests

* tests: add test case from hardware-observer charm and cleanup keys

* tests: refactor deb822 unit tests

* tests: iterate on deb822 tests

* tests: fully refactor and expand deb822 unit tests

* style: make linting happy

* test: fix an erroneous assert in integration tests

* refactor: clean up diff, signatures, etc

* refactor: move keys to files

* fix: don't warn about key file on remove

* style: use tuple for endswith

* style: paragraph -> stanza, repositories -> repos

* test: switch from inkscape to terminator ppa for ci

* test: switch from terminator to fish ppa for ci

* chore: remove ValueError from RepositoryMapping.add

* test: remove old tests from test_repo.py
  • Loading branch information
james-garner-canonical authored Dec 5, 2024
1 parent 8e034ef commit f1952df
Show file tree
Hide file tree
Showing 34 changed files with 1,368 additions and 197 deletions.
583 changes: 481 additions & 102 deletions lib/charms/operator_libs_linux/v0/apt.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/integration/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from subprocess import CalledProcessError, check_output


def get_command_path(command):
def get_command_path(command: str) -> str:
try:
return check_output(["which", command]).decode().strip()
except CalledProcessError:
Expand Down
29 changes: 29 additions & 0 deletions tests/integration/keys/FISH_KEY.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBGY0i8EBEAC787CEn0bb9R6lgxSjwEzrfUGK2HVfUoSfKiKILlU/p+nwdBdx
zKOGEtl2O8W4Q+KZkwEbD4llJKPFhzjF2CeP2qRKd/PLpiZoKhAr/NR7klQveqGx
Hop3uXsdGFxsNv2z0VEyJ7vhO+X0AuAW9BcXpXBexltrIzqbuGg+BKTwAOc5qaWx
xzDgcTvXR7xeudHv4vqXez93pd93WaRnjNB0vOUm03cKqFvfzfn1mJruThO3WE6S
ISjC/rQF4IquNS5ncA2+NLfb7fsPpYUmfKCTucYK2i929Xw/cwLfqE668kQLfJ6G
TiUK6B0EMK/Cvb/LYdN7RMXFrnWt6FnZORZM+9u4ZiCIa60OfW+xXjhmU6Lln3ZV
enhcD0qZHqZLQIxWGxK9rKJsasoBFnbDzBNyMM6BfukQqh6VP3UzdXixPCW1lOFl
omsPj3eoqmIf6tmyINMiJbmQrZmJ7Zn1tpTqScfdPJU06z26hcTQrn2+rvHtQV5V
ebj9JMqvKuk5mG7zkjFgMHoqP6jLlVqsReCfY66VuYLg4o2m0r2F+wv7ZfFXYcCq
LOycszdQe/SgJHobJc/yt/brZMrqFmGtYAERU7NcbRceuc4i2k1VnlygBT1AuvGT
HoSgm9ct0MZlfKRLhkZm+izwxLqxVSAsB/DZJ3uWp4XsKx4XHjw2VFw5aQARAQAB
tChMYXVuY2hwYWQgUFBBIGZvciBGaXNoIHNoZWxsIG1haW50YWluZXJziQJOBBMB
CgA4FiEEiEIecD7cevVJZ97Uc8n8yeK7SNoFAmY0i8ECGwMFCwkIBwIGFQoJCAsC
BBYCAwECHgECF4AACgkQc8n8yeK7SNoJUA//bnOSCrdit87tvsDmaok9+kQ2YYqL
X4KVsKxI2QVsKhRXPJb3yRwQRLArEUhT8yg5kQBIaHKdDhAkH9PRFZeCin25x/lq
LvjpnyslhlI9fhnImC21KqAPs8Svrb2LrvtfQK+072Fw5bISGJ6qlINU1vmJ0AIF
poojZaudcGLiQym1hkyf7HU4loHdkyUKX0jCTS8c9E8pRrDpwdHkKI3pEZpVWva1
zsmPgYXR/RRCt4zV4/lwX2WiCmYBBGdXn3D2mfA+ONfExngDfjpzXAQ8Dp9m3bDI
AmtlaKRjHa9VKKd0wt6LH2JYmt52lUwoEvoiVf8M0poKrmPN+ft8EaOMpgORS8ut
RZzVndHx4jFyZ+pVDt00J16Bblq6MSaGZalPneIfycx4tuwPPTX7CALUeMQ0V/Gy
p053yvotLwsBC6KGjKugxUzgbSlp7WWiPEbYXZfjb7IZpNmKXtuvfyBo8rs3icez
ZkUmljl2J27bhSIUZQ124ham6yQ3B8MfXUdctiWUCkOdunqUuBeHa5yeKJHTcFUH
Y5nyyn79L5VLZ6YlwYn9qW0V/LvfnW2JmrXTVFjEhfUoEm0Zck8UBqWn2wfSagTI
2KWU87IgN3MF7QG5EiLEAUA/DfagBwgjCpRFH8VUeWqMjTkQs9kjB/kvCcvHGp8g
WVimNlxjmpCZsvk=
=5r0P
-----END PGP PUBLIC KEY BLOCK-----
19 changes: 19 additions & 0 deletions tests/integration/keys/HPEPUBLICKEY2048_KEY1.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)

mQENBFZp0LkBCACXajRw3b4x7G7dulNYj0hUID4BtVFq/MjEb6PHckTxGxZDoQRX
RK54tiTFA9wq3b4P3yEFnOjbjRoI0d7Ls67FADugFO+cDCtsV9yuDlaYP/U/h2nX
N0R4AdYbsVd5yr6xr+GAy66Hmx5jFH3kbC+zJpOcI0tU9hcyU7gjbxu6KQ1ypI2Q
VRKf8sRBJXgmkOlbYx35ZUMFcmVxrLJXvUuxmAVXgT9f5M3Z3rsGt/ab+/+1TFSb
RsaqHsIPE0QH8ikqW4IeDQAo1T99pCdf7FWr45KFFTo7O4AZdLMWVgqeFHaSoZxJ
307VIINsWiwQoPp0tfU5NOOOwB1Sv3x9QgFtABEBAAG0P0hld2xldHQgUGFja2Fy
ZCBFbnRlcnByaXNlIENvbXBhbnkgUlNBLTIwNDgtMjUgPHNpZ25ocEBocGUuY29t
PokBPQQTAQIAJwUCVmnQuQIbLwUJEswDAAYLCQgHAwIGFQgCCQoLAxYCAQIeAQIX
gAAKCRDCCK3eJsK3l9G+B/0ekblsBeN+xHIJ28pvo2aGb2KtWBwbT1ugI+aIS17K
UQyHZJUQH+ZeRLvosuoiQEdcGIqmOxi2hVhSCQAOV1LAonY16ACveA5DFAEBz1+a
WQyx6sOLLEAVX1VqGlBXxh3XLEUWOhlAf1gZPNtHsmURTUy2h1Lv/Yoj8KLyuK2n
DmrLOS3Ro+RqWocaJfvAgXKgt6Fq/ChDUHOnar7lGswzMsbE/yzLJ7He4y89ImK+
2ktR5HhDuxqgCe9CWH6Q/1WGhUa0hZ3nbluq7maa+kPe2g7JcRzPH/nJuDCAOZ7U
6mHE8j0kMQMYjgaYEx2wc02aQRmPyxhbDLjSbtjomXRr
=voON
-----END PGP PUBLIC KEY BLOCK-----
30 changes: 30 additions & 0 deletions tests/integration/keys/HPPUBLICKEY1024.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.0 (MingW32)

mQGiBEIxWpoRBADb06sJgnD7MJnm2Ny1nmTFLDSZ8vkubP+pmfn9N9TE26oit+KI
OnVTRVbSPl3F15wTjSBGR453MEfnzp1NrMk1GIa/m1nKAmgQ4t1714C4jQab0to+
gP51XhPhtAGt7BggorQw2RXa4KdTCh8ByOIaDKRYcESmMazSZ+Pscy2XRwCgm771
21RCM0RcG2dmHZZgKH8fTscD/RiY3CHI2jJl9WosIYXbZpOySzrLn0lRCRdNdpew
Y5m1f3lhqoSvJk7pXjs4U+3XlOlUhgWl5HiXuWSVyPu2ilfGdfgpJslawI85fBQg
Ul5kcrjLHHsApeG8oGStFJE2JAc+0D+whmGmJbjWKwuZJmgpm9INplA4h1BYJbx+
6A3MBACFiMTttDPpJ+5eWr1VSZwxCZNqvPWmjpL5Nh9F8xzE7q+ad2CFKSebvRrv
Jf7Y2m+wY9bmo5nJ3wHYEX3Aatt+QVF10G6wTdIz/Ohm/Pc4Li4NhzYOv7FKxVam
97UN0O8Rsl4GhE2eE8H+Q3QYFvknAWoTj3Rq3/A5FA6FsRFhxbQwSGV3bGV0dC1Q
YWNrYXJkIENvbXBhbnkgKEhQIENvZGVzaWduaW5nIFNlcnZpY2UpiGQEExECACQF
AkIxWpoCGwMFCRLMAwAGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQUnvFOiaJuIc1
2wCgj2UotUgSegPHmcKdApY+4WFaz/QAnjI58l5bDD8eElBCErHVoq9uPMczuQIN
BEIxWqUQCADnBXqoU8QeZPEy38oI0GrN2q7nvS+4UBQeIRVy8x+cOqDRDcE8PHej
7NtxP698U0WFGK47GszjiV4WTnvexuJk0B5AMEBHana8fVj7uRUcmyYZqOZd7EXn
Q3Ivi8itfkTICkhZi7bmGsSF0iJ0eAI5n2bCqJykNQvJ6a3dWJKP8EgaBCZj+TGL
WWJHDZsrn8g4BeaNS/MbmsCLAk8N6bWMGzAKfgxUraMCwuZ9fVyHFavHdeChUtna
qnF4uw0hHLaGWmTJjziXVvVC1a8+inTxPZkVpAvD0A+/LNlkP7TtAdaVOJqv3+a3
ybMQL851bRTFyt+H0XGHhzhhtuu9+DyfAAMFCADRWGxIfniVG7O4wtwLD3sWzR/W
LmFlJYu4s9rSDgn3NDjigQzZoVtbuv3Z9IZxBMoYa50MuybuVDp55z/wmxvYoW2G
25kOFDKx/UmkKkUBLdokb5V1p9j5SJorGBSfsNAHflhmBhyuMP4CDISbBUSN7oO1
Oj41jNxpqhy+8ayygSVcTNwMe909J/HdC//xFANLDhjKPf3ZAulWNhOvjTlpF46B
yt1l8ZNinIeE7CFL7H+LlMl2Ml6wsOkrxsSauBis6nER4sYVqrMdzpUU2Sr2hj6Q
sJ+9TS+IURcnxL/M851KCwLhwZKdphQjT3mXXsoCx/l3rI6cxpwYgjiKiZhOiE8E
GBECAA8FAkIxWqUCGwwFCRLMAwAACgkQUnvFOiaJuIenewCdHcEvMxBYprqRjKUw
04EypyFtZTgAn0wds0nbpd2+VZ5WHbVRfU4y5Y5Y
=+cX+
-----END PGP PUBLIC KEY BLOCK-----
19 changes: 19 additions & 0 deletions tests/integration/keys/HPPUBLICKEY2048.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.10 (MingW32)

mQENBFC+QboBCAC1bodHD7AmR00SkDMB4u9MXy+Z5vv8wbmGRaKDBYScpAknOljX
d5tBADffAetd1hgLnrLKN8vHdIsYkmUyeEeEsnIUKtwvbx/f6PoZZPOIIIRh1d2W
Mjw9qXIE+tgr2gWlq0Gi5BZzaKse1+khRQ2rewJBppblSGWgcmCMIq8OwAsrdbtr
z7+37c/g/Y2VfAahc23YZW9LQ5MiaI4nS4JMZbWPYtBdF78B/D2t5FvmvDG0Cgjk
Qi1U9IVjiFKixuoi6nRsvBLFYL/cI+vo4iyUC5x7qmKd8gN7A030gS67VrleNRki
q0vaF6J46XpIl4o58t23FSAKKRbTwavYzdMpABEBAAG0NEhld2xldHQtUGFja2Fy
ZCBDb21wYW55IFJTQSAoSFAgQ29kZXNpZ25pbmcgU2VydmljZSmJAT4EEwECACgF
AlC+QboCGwMFCRLMAwAGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJELBwaApc
4tR2x7sH/A3D4XxEEyrX6Z3HeWSSA80+n+r5QwfXm5unxsWEL3JyNg6sojlrJY4K
8k4ih4nkY4iblChTCSQwnqKXqkL5U+RIr+AJoPx+55M98u4eRTVYMHZD7/jFq85z
ZFGUkFkars9E2aRzWhqbz0LINb9OUeX0tT5qQseHflO2PaJykxNPC14WhsBKC2lg
dZWnGhO5QJFp69AnSp4k+Uo/1LMk87YEJIL1NDR0lrlKgRvFfFyTpRBt+Qb1Bb7g
rjN0171g8t5GaPWamN3Oua/v4aZg15f3xydRF8y9TsYjiNz+2TzRjKv7AkpZaJST
06CqMjCgiZ6UFFGN0/oqLnwxdP3Mmh4=
=aphN
-----END PGP PUBLIC KEY BLOCK-----
19 changes: 19 additions & 0 deletions tests/integration/keys/HPPUBLICKEY2048_KEY1.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (MingW32)

mQENBFRtGAgBCADlSku65P14hVdx9E/W0n6MwuB3WGqmsyKNoa3HezFdMjWERldI
NNUdi8O28cZ6j2+Hi9L1HeQIQ9+7FHpR3JyQePBJtRX8WSEusfRtML98opDhJxKm
8Jyxb7aTvCwdNHz3yxADINkMtOj5oRm7VCr8XHkG7YU27ELs8B+BXWvjO21oSosi
FurnhT+H3hQsYXfYA55aa21q0qX+L5dFJSNdzZVo7m9ybioVv2R5+PfBvdaSxCnm
OpcGXFaKAsqVHeTW0pd3sdkin1rkbhOBaU5lFBt2ZiMtKpKHpT8TZnqHpFHFbgi8
j2ARJj4IDct2OGILddUIZSFyue6WE2hpV5c/ABEBAAG0OEhld2xldHQtUGFja2Fy
ZCBDb21wYW55IFJTQSAoSFAgQ29kZXNpZ25pbmcgU2VydmljZSkgLSAxiQE+BBMB
AgAoBQJUbRgIAhsDBQkSzAMABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRD6
3Y1ksSdeo6BJCADOfIPPLPpIOnFK9jH4t8lLUd+RyMc+alA3uTDPUJa/ZHa6DHfh
42iaPYVEV8OG0tnbMlHmwvsZ5c1/MRMw1UbxCvD88P2qM4SUrUjQUlSCms2GLGvF
ftFXBiOJQ7/yBc9o+yoSvwPrrTxSCk4+Sqm0IfVXVzChDM9dM9YPY2Vzjd+LUaYC
3X+eSuggUDO0TmJLJd7tZdF9fVXq3lr63BZ5PY98MTCuOoeSMDa9FIUQf6vn6UUJ
MDSRZ9OzhpNJOKR+ShVRwDK6My8gtVIW1EAW2w3VQWI2UNF07aLeO8UG6nTNWA23
+OuZkUdgQovjcq01caSefgOkmiQOx6d74CAk
=X+eo
-----END PGP PUBLIC KEY BLOCK-----
201 changes: 148 additions & 53 deletions tests/integration/test_apt.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,38 @@


import logging
import os
import subprocess
from pathlib import Path
from typing import List
from urllib.request import urlopen

from charms.operator_libs_linux.v0 import apt
from helpers import get_command_path

logger = logging.getLogger(__name__)

KEY_DIR = Path(__file__).parent / "keys"

def test_install_package():
try:
apt.update()
apt.add_package("zsh")
apt.add_package(["golang-cfssl", "jq"])
except apt.PackageNotFoundError:
logger.error("A specified package not found in package cache or on system")
except apt.PackageError as e:
logger.error("Could not install package. Reason: {}".format(e.message))

def test_install_packages():
apt.update()
apt.add_package("zsh")
assert get_command_path("zsh") == "/usr/bin/zsh"
apt.add_package(["golang-cfssl", "jq"])
assert get_command_path("cfssl") == "/usr/bin/cfssl"
assert get_command_path("jq") == "/usr/bin/jq"


def test_install_package_error():
package = apt.DebianPackage(
name="ceci-n'est-pas-un-paquet",
version="1.0",
epoch="",
arch="amd64",
state=apt.PackageState.Available,
)
try:
package = apt.DebianPackage(
"ceci-n'est-pas-un-paquet",
"1.0",
"",
"amd64",
apt.PackageState.Available,
)
package.ensure(apt.PackageState.Present)
except apt.PackageError as e:
assert "Unable to locate package" in str(e)
Expand All @@ -44,53 +44,148 @@ def test_install_package_error():
def test_remove_package():
# First ensure the package is present
cfssl = apt.DebianPackage.from_apt_cache("golang-cfssl")
if not cfssl.present:
apt.add_package("golang-cfssl")
assert get_command_path("cfssl") == "/usr/bin/cfssl"
assert not cfssl.present
# Add package
apt.add_package("golang-cfssl")
assert get_command_path("cfssl")
subprocess.run(["cfssl", "version"], check=True)
# Now remove the package and check its bins disappear too
apt.remove_package("golang-cfssl")
assert get_command_path("cfssl") == ""


def test_install_package_external_repository():
repositories = apt.RepositoryMapping()

# Get the Hashicorp GPG key
key = urlopen("https://apt.releases.hashicorp.com/gpg").read().decode()

# Add the hashicorp repository if it doesn't already exist
if "deb-apt.releases.hashicorp.com-focal" not in repositories:
line = "deb [arch=amd64] https://apt.releases.hashicorp.com focal main"
repo = apt.DebianRepository.from_repo_line(line)
# Import the repository's key
repo.import_key(key)
repositories.add(repo)

assert not get_command_path("cfssl")


def test_install_package_from_external_repository():
repo_id = "deb-https://repo.mongodb.org/apt/ubuntu-jammy/mongodb-org/8.0"
repos = apt.RepositoryMapping()
assert repo_id not in repos
assert not get_command_path("mongod")
## steps
key = urlopen("https://www.mongodb.org/static/pgp/server-8.0.asc").read().decode()
key_file = apt.import_key(key)
line = (
"deb [ arch=amd64,arm64 signed-by={} ]"
" https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse"
).format(key_file)
## if: use implicit write_file
repo = apt.DebianRepository.from_repo_line(line) # write_file=True by default
assert repo_id not in repos
## if: don't use implicit write_file
# repo = apt.DebianRepository.from_repo_line(line, write_file=False)
# repos.add(repo)
# assert repo_id in repos
## fi
assert repo_id in apt.RepositoryMapping()
apt.update()
apt.add_package("terraform")

assert get_command_path("terraform") == "/usr/local/bin/terraform"
apt.add_package("mongodb-org")
assert get_command_path("mongod")
subprocess.run(["mongod", "--version"], check=True)
## cleanup
os.remove(key_file)
apt._add_repository(repo, remove=True) # pyright: ignore[reportPrivateUsage]
assert repo_id not in apt.RepositoryMapping()
apt.update()
apt.remove_package("mongodb-org")
assert get_command_path("mongod") # mongodb-org is a metapackage
subprocess.run(["apt", "autoremove"], check=True)
assert not get_command_path("mongod")


def test_install_higher_version_package_from_external_repository():
repo_id = "deb-https://ppa.launchpadcontent.net/fish-shell/release-3/ubuntu/-jammy"
repos = apt.RepositoryMapping()
assert repo_id not in repos
## version before
if not get_command_path("fish"):
apt.add_package("fish")
assert get_command_path("fish")
version_before = subprocess.run(
["fish", "--version"],
capture_output=True,
check=True,
text=True,
).stdout
apt.remove_package("fish")
assert not get_command_path("fish")
## steps
repo = apt.DebianRepository(
enabled=True,
repotype="deb",
uri="https://ppa.launchpadcontent.net/fish-shell/release-3/ubuntu/",
release="jammy",
groups=["main"],
)
repos.add(repo) # update_cache=False by default
assert repo_id in repos
assert repo_id in apt.RepositoryMapping()
key_file = apt.import_key((KEY_DIR / "FISH_KEY.asc").read_text())
apt.update()
apt.add_package("fish")
assert get_command_path("fish")
version_after = subprocess.run(
["fish", "--version"],
capture_output=True,
check=True,
text=True,
).stdout
assert version_after > version_before # lexical comparison :(
## cleanup
os.remove(key_file)
apt._add_repository(repo, remove=True) # pyright: ignore[reportPrivateUsage]
assert repo_id not in apt.RepositoryMapping()
apt.update()
apt.remove_package("fish")
assert not get_command_path("fish")


def test_list_file_generation_external_repository():
repositories = apt.RepositoryMapping()
def test_install_hardware_observer_ssacli():
"""Test the ability to install a package used by the hardware-observer charm.
# Get the mongo GPG key
key = urlopen(" https://www.mongodb.org/static/pgp/server-5.0.asc").read().decode()
Here we follow the order of operations and arguments used in the charm:
for key in HP_KEYS:
apt.import_key(key)
# Add the mongo repository if it doesn't already exist
repo_name = "deb-https://repo.mongodb.org/apt/ubuntu-focal/mongodb-org/5.0"
if repo_name not in repositories:
line = "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse"
repo = apt.DebianRepository.from_repo_line(line)
# Import the repository's key
repo.import_key(key)
repositories = apt.RepositoryMapping()
repo = apt.DebianRepository.from_repo_line(...)
repositories.add(repo)
apt.add_package(self.pkg, update_cache=True)
"""
line = "deb http://downloads.linux.hpe.com/SDR/repo/mcp stretch/current non-free"
repo_id = apt._repo_to_identifier( # pyright: ignore[reportPrivateUsage]
apt.DebianRepository.from_repo_line(line, write_file=False)
)
assert repo_id not in apt.RepositoryMapping()
assert not get_command_path("ssacli")
key_files: List[str] = [] # just for cleanup
## steps
for path in (
KEY_DIR / "HPEPUBLICKEY2048_KEY1.asc",
KEY_DIR / "HPPUBLICKEY2048_KEY1.asc",
KEY_DIR / "HPPUBLICKEY2048.asc",
KEY_DIR / "HPPUBLICKEY1024.asc",
):
key_file = apt.import_key(path.read_text())
key_files.append(key_file)
repos = apt.RepositoryMapping()
repo = apt.DebianRepository.from_repo_line(line) # write_file=True by default
assert repo_id in apt.RepositoryMapping()
# repo added to system but repos doesn't know about it yet
assert repo_id not in repos
repos.add(repo)
assert repo_id in repos
# `add` call is redundant with `from_repo_line` from system pov
# but adds an entry to the RepositoryMapping
apt.add_package("ssacli", update_cache=True)
# apt.update not required since update_cache=True
assert get_command_path("ssacli")
## cleanup
for key_file in key_files:
os.remove(key_file)
apt._add_repository(repo, remove=True) # pyright: ignore[reportPrivateUsage]
assert repo_id not in apt.RepositoryMapping()
apt.update()
apt.add_package("mongodb-org")

assert get_command_path("mongod") == "/usr/bin/mongod"
apt.remove_package("ssacli")
assert not get_command_path("ssacli")


def test_from_apt_cache_error():
Expand Down
Loading

0 comments on commit f1952df

Please sign in to comment.