Skip to content
Snippets Groups Projects
test_apt.py 5.37 KiB
Newer Older
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
#!/usr/bin/env python3

"""
Criticality: Normal
Check updates, apt state and unattended upgrade config.
"""

import apt as apt_mod
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
import apt_pkg
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
import os
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
from pathlib import Path
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
import sys

try:
    from requests.packages.urllib3.exceptions import InsecureRequestWarning

    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
except ImportError:
    requests.packages.urllib3.disable_warnings()

Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
sys.path.append(str(Path(__file__).parents[1].resolve()))

import utils as u  # noqa: E402
from utils_lib.apt import Apt  # noqa: E402
from utils_lib.os import line_in_file  # noqa: E402


def main():
    warnings = 0
    errors = 0
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed

    os.environ["DEBIAN_FRONTEND"] = "noninteractive"
    os.environ["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed

    print("Checking APT state:")

    try:
        apt = Apt(update=True)
    except apt_mod.cache.FetchFailedException as apt_cache_err:
        if str(apt_cache_err).endswith("no longer has a Release file."):
            u.error("system out of support")
            errors += 1
        else:
Stéphane Diemer's avatar
Stéphane Diemer committed
            u.error("Apt error: {}".format(apt_cache_err))
            errors += 1
        apt = Apt()

    # detect pending upgrade
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    upgradable = len(apt.upgradable_packages)
    if upgradable:
        u.info("there is {} upgrade pending".format(upgradable))
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    else:
        u.success("system up-to-date")

    # detect pending auto-remove
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    removable = len(apt.removable_packages)
    if removable:
        u.warning("there is {} auto-removable packages".format(removable))
        warnings += 1
    else:
        u.success("system clean")

Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    # detect rc state
    purgeable = len(apt.purgeable_packages)
    if purgeable:
        u.info("there is {} packages in rc state".format(purgeable))

Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    try:
        installed = apt.install("sl")
    except apt_pkg.Error as apt_install_err:
        u.warning(apt_install_err)
        warnings += 1
    else:
        if installed:
            u.success("installation successful")
            apt.remove("sl")
        else:
            u.error("installation failed")
            errors += 1

    # unattended-upgrades
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    if (
        Path("/etc/apt/apt.conf.d/20auto-upgrades").exists()
        and Path("/etc/apt/apt.conf.d/50unattended-upgrades").exists()
        and line_in_file(
            r'^APT::Periodic::Update-Package-Lists "1";$',
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
            "/etc/apt/apt.conf.d/20auto-upgrades",
        )
        and line_in_file(
            r'^APT::Periodic::Unattended-Upgrade "1";$',
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
            "/etc/apt/apt.conf.d/20auto-upgrades",
        )
        and line_in_file(
            r"^Unattended-Upgrade::(?:(?:Allowed-Origins)|(?:Origins-Pattern)) {$",
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
            "/etc/apt/apt.conf.d/50unattended-upgrades",
        )
    ):
        u.success("automatic security updates enabled")
    else:
        u.warning("automatic security updates not enabled")
        warnings += 1

    # check ubicast repository presence
    ubicast_repo = Path("/etc/apt/sources.list.d/skyreach.list").exists()
    ubicast_package = (
        True
        if apt.is_installed("ubicast-mediaserver")
        or apt.is_installed("ubicast-monitor")
        or apt.is_installed("ubicast-skyreach")
        or apt.is_installed("ubicast-skyreach-erp")
        or apt.is_installed("celerity-server")
        or apt.is_installed("celerity-utils")
        or apt.is_installed("celerity-workers")
        # older versions
        or apt.is_installed("python3-mediaserver")
        or apt.is_installed("python3-mediaserver-monitor")
        or apt.is_installed("campus-manager")
        else False
    )
    if ubicast_repo and ubicast_package:
        u.success("ubicast repository present")
    elif not ubicast_repo and ubicast_package:
        u.error("ubicast repository missing")
        errors += 1
    elif not ubicast_repo and not ubicast_package:
        u.info("no ubicast repository and service installed")
    else:
        u.info("no ubicast service installed")

    # check ubicast repository url
    regexp_repo = (
        r"^deb (http[s]?://[A-Za-z0-9\.\-\_]+) packaging/apt/([A-Za-z0-9\.\-\_]+)/$"
    )
    repo_url_match = line_in_file(regexp_repo, "/etc/apt/sources.list.d/skyreach.list")
    if repo_url_match:
        url, apt_token = repo_url_match.groups()
        u.success("url: {}, token: {}[...]".format(url, apt_token[:8]))
    else:
        url, apt_token = None, None
        u.error("incorrect ubicast repository url or token")
        errors += 1

    # check server avalability
    if url:
        server_response = requests.get(url, verify=False)
        if server_response.ok:
            u.success("request to {} succeeded".format(url))
        else:
            u.error("request to {} failed: {}".format(url, server_response.text))
            errors += 1

    # check repository avalability
    if url and apt_token:
        apt_url = "{}/packaging/apt/{}/Packages".format(url, apt_token)
        repo_response = requests.get(apt_url, verify=False)
        apt_url = "{}/packaging/apt/{}[...]/Packages".format(url, apt_token[:8])
        if repo_response.ok:
            u.success("request to {} succeeded".format(apt_url))
        else:
            u.error("request to {} failed: {}".format(apt_url, repo_response.text))
            errors += 1

Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    if errors:
        return 1
    elif warnings:
        return 3
    else:
        return 0


if __name__ == "__main__":
    exit(main())