123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- #! /usr/bin/env python3
- """
- This script checks for available updates on Void Linux using xbps and notifies
- the configured administrator account about them. It currently requires
- python 3.x and no additional packages and is supposed to be run with cron or
- another scheduled execution mechanism.
- """
- import subprocess
- import smtplib
- import socket
- import re
- import logging
- import sys
- from email.mime.multipart import MIMEMultipart
- from email.mime.text import MIMEText
- __version__ = "0.1"
- # Email server to be used to send the notification
- ADMIN_EMAIL = "root"
- # Mail server to be used to send the notification
- MAIL_SERVER = "localhost"
- # Port to use on the mail server
- MAIL_SERVER_PORT = 25
- # User name to log in to the mail server
- MAIL_SERVER_USER = ""
- # Password to log in to the mail server
- MAIL_SERVER_PASSWORD = ""
- # Log level for the stderr/stdout output
- LOG_LEVEL = logging.ERROR
- AVAILABLE_UPDATES = []
- DEVNULL = open("/dev/null", "w")
- LOGGER = logging.getLogger("voixicron")
- LOGGER.setLevel(LOG_LEVEL)
- CONSOLE_HANDLER = logging.StreamHandler()
- LOGGER.addHandler(CONSOLE_HANDLER)
- try:
- XBPS_INSTALL_RESULT = subprocess.check_output(["xbps-install", "-Sun"],
- stderr=DEVNULL)
- except subprocess.CalledProcessError as error:
- LOGGER.error("Could not get list of updated packages, xbps-install error:"
- " %s", error.output)
- sys.exit(1)
- else:
- XBPS_INSTALL_RESULT = XBPS_INSTALL_RESULT.decode("utf-8").split("\n")
- for line in XBPS_INSTALL_RESULT:
- if "update" in line:
- try:
- package = line.split(" ")[0]
- package_regex = "^([A-Za-z0-9-._]*)-([0-9].*_[0-9]*)$"
- match_object = re.match(package_regex, package)
- if match_object:
- package_name = match_object.groups()[0]
- new_package_version = match_object.groups()[1]
- else:
- LOGGER.error("Not match for package %s", package)
- continue
- except IndexError:
- continue
- else:
- try:
- xbps_query_result = subprocess.check_output(
- ["xbps-query", "--show", package_name], stderr=DEVNULL)
- except subprocess.CalledProcessError as error:
- LOGGER.debug("Querying the installed version of package %s"
- " failed with error message: %s",
- package_name, error.output)
- else:
- xbps_query_result = xbps_query_result.decode(
- "utf-8").split("\n")
- for line in xbps_query_result:
- if "pkgver" in line:
- installed_package = line.split(
- ":")[1].strip()
- match = re.match(package_regex,
- installed_package)
- if match:
- installed_package_version = match.groups()[1]
- package_update = {
- "name": package_name,
- "new_version": new_package_version,
- "old_version": installed_package_version,
- }
- else:
- LOGGER.error("Unable to detect installed "
- "version of package %s",
- package_name)
- package_update = {
- "name": package_name,
- "new_version": new_package_version,
- "old_version": "unknown",
- }
- AVAILABLE_UPDATES.append(package_update)
- break
- if AVAILABLE_UPDATES:
- HOSTNAME = socket.getfqdn()
- MSG = MIMEMultipart()
- MAIL_TEXT = "The following package updates are available on host %s:\n\n"\
- % HOSTNAME
- MSG["Subject"] = "%s updates available on host %s"\
- % (len(AVAILABLE_UPDATES), HOSTNAME)
- MSG["From"] = "voixicron@%s" % HOSTNAME
- MSG["To"] = ADMIN_EMAIL
- for update in AVAILABLE_UPDATES:
- MAIL_TEXT += "%s (%s -> %s)\n"\
- % (update["name"],
- update["old_version"],
- update["new_version"])
- MAIL_TEXT += "\n\nYou can install the updates by issuing the command:" \
- "\n\n\txbps-install -Su\n\nas root on %s\n\n--\nvoixicron"\
- % HOSTNAME
- MSG_TEXT = MIMEText(MAIL_TEXT.encode("utf-8"), _charset="utf-8")
- MSG.attach(MSG_TEXT)
- SERVER_CONNECTION = smtplib.SMTP(MAIL_SERVER, MAIL_SERVER_PORT)
- try:
- SERVER_CONNECTION.connect()
- except (smtplib.SMTPConnectError, smtplib.SMTPServerDisconnected,
- socket.error):
- LOGGER.error("Failed to establish a connection to the SMTP server")
- else:
- try:
- SERVER_CONNECTION.starttls()
- except smtplib.SMTPException:
- pass
- if MAIL_SERVER_USER:
- try:
- SERVER_CONNECTION.login(MAIL_SERVER_USER, MAIL_SERVER_PASSWORD)
- except smtplib.SMTPAuthenticationError:
- LOGGER.error("Authentication on the mail server with user %s "
- "failed.", MAIL_SERVER_USER)
- except smtplib.SMTPException:
- LOGGER.error("Error during authentication on the mail server.")
- try:
- SERVER_CONNECTION.sendmail("voixicron@%s" % HOSTNAME, ADMIN_EMAIL,
- MSG.as_string())
- except smtplib.SMTPRecipientsRefused:
- LOGGER.error("The mail server refused the recipient.")
- except smtplib.SMTPSenderRefused:
- LOGGER.error("The mail server refused the sender.")
- else:
- SERVER_CONNECTION.quit()
- DEVNULL.close()
|