voixicron.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #! /usr/bin/env python3
  2. """
  3. This script checks for available updates on Void Linux using xbps and notifies
  4. the configured administrator account about them. It currently requires
  5. python 3.x and no additional packages and is supposed to be run with cron or
  6. another scheduled execution mechanism.
  7. """
  8. import subprocess
  9. import smtplib
  10. import socket
  11. import re
  12. from email.mime.multipart import MIMEMultipart
  13. from email.mime.text import MIMEText
  14. # Email server to be used to send the notification
  15. ADMIN_EMAIL = "root"
  16. # Mail server to be used to send the notification
  17. MAIL_SERVER = "localhost"
  18. # Port to use on the mail server
  19. MAIL_SERVER_PORT = 25
  20. # User name to log in to the mail server
  21. MAIL_SERVER_USER = ""
  22. # Password to log in to the mail server
  23. MAIL_SERVER_PASSWORD = ""
  24. AVAILABLE_UPDATES = []
  25. DEVNULL = open("/dev/null", "w")
  26. try:
  27. XBPS_INSTALL_RESULT = subprocess.check_output(["xbps-install", "-Sun"],
  28. stderr=DEVNULL)
  29. except subprocess.CalledProcessError:
  30. pass
  31. else:
  32. XBPS_INSTALL_RESULT = XBPS_INSTALL_RESULT.decode("utf-8").split("\n")
  33. for line in XBPS_INSTALL_RESULT:
  34. if "update" in line:
  35. try:
  36. package = line.split(" ")[0]
  37. package_regex = "^([A-Za-z0-9-]*)-([0-9].*_[0-9])$"
  38. match_object = re.match(package_regex, package)
  39. package_name = match_object.groups()[0]
  40. new_package_version = match_object.groups()[1]
  41. except IndexError:
  42. continue
  43. else:
  44. try:
  45. xbps_query_result = subprocess.check_output(
  46. ["xbps-query", "--show", package_name], stderr=DEVNULL)
  47. except subprocess.CalledProcessError:
  48. pass
  49. else:
  50. xbps_query_result = xbps_query_result.decode(
  51. "utf-8").split("\n")
  52. for line in xbps_query_result:
  53. if "pkgver" in line:
  54. installed_package = line.split(
  55. ":")[1].strip()
  56. match = re.match(package_regex,
  57. installed_package)
  58. installed_package_version = match.groups()[1]
  59. package_update = {
  60. "name": package_name,
  61. "new_version": new_package_version,
  62. "old_version": installed_package_version,
  63. }
  64. AVAILABLE_UPDATES.append(package_update)
  65. break
  66. if AVAILABLE_UPDATES:
  67. HOSTNAME = socket.getfqdn()
  68. MSG = MIMEMultipart()
  69. MAIL_TEXT = "The following package updates are available on host %s:\n\n"\
  70. % HOSTNAME
  71. MSG["Subject"] = "%s updates available on host %s"\
  72. % (len(AVAILABLE_UPDATES), HOSTNAME)
  73. MSG["From"] = "voixicron@%s" % HOSTNAME
  74. MSG["To"] = ADMIN_EMAIL
  75. for update in AVAILABLE_UPDATES:
  76. MAIL_TEXT += "%s (%s -> %s)\n"\
  77. % (update["name"],
  78. update["old_version"],
  79. update["new_version"])
  80. MSG_TEXT = MIMEText(MAIL_TEXT.encode("utf-8"), _charset="utf-8")
  81. MSG.attach(MSG_TEXT)
  82. SERVER_CONNECTION = smtplib.SMTP(MAIL_SERVER, MAIL_SERVER_PORT)
  83. try:
  84. SERVER_CONNECTION.connect()
  85. except (smtplib.SMTPConnectError, smtplib.SMTPServerDisconnected,
  86. socket.error):
  87. pass
  88. else:
  89. try:
  90. SERVER_CONNECTION.starttls()
  91. except smtplib.SMTPException:
  92. pass
  93. if MAIL_SERVER_USER:
  94. try:
  95. SERVER_CONNECTION.login(MAIL_SERVER_USER, MAIL_SERVER_PASSWORD)
  96. except smtplib.SMTPAuthenticationError:
  97. pass
  98. except smtplib.SMTPException:
  99. pass
  100. try:
  101. SERVER_CONNECTION.sendmail("voixicron@%s" % HOSTNAME, ADMIN_EMAIL,
  102. MSG.as_string())
  103. except smtplib.SMTPRecipientsRefused:
  104. pass
  105. except smtplib.SMTPSenderRefused:
  106. pass
  107. else:
  108. SERVER_CONNECTION.quit()
  109. DEVNULL.close()