Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ Misc
Bug fixes and minor changes
---------------------------

+ `#15`_, `#18`_: Send a report also in the case of certain errors
from zypper.
+ `#16`_, `#17`_: Review of the test framework.

.. _#14: https://github.com/RKrahl/auto-patch/pull/14
.. _#15: https://github.com/RKrahl/auto-patch/issues/15
.. _#16: https://github.com/RKrahl/auto-patch/issues/16
.. _#17: https://github.com/RKrahl/auto-patch/pull/17
.. _#18: https://github.com/RKrahl/auto-patch/pull/18


1.1.0 (2022-10-03)
Expand Down
47 changes: 29 additions & 18 deletions scripts/auto-patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ def logging_add_report(cfg, stream):
root = logging.getLogger()
report_hdlr = logging.StreamHandler(stream=stream)
report_hdlr.setLevel(cfg.get('report_level'))
report_hdlr.setFormatter(logging.Formatter(fmt="\n%(message)s"))
fmt = "\n%(levelname)s: %(message)s"
report_hdlr.setFormatter(logging.Formatter(fmt=fmt))
root.addHandler(report_hdlr)
try:
yield None
Expand Down Expand Up @@ -292,31 +293,40 @@ def patch(stdout=None):
err.Message += (". Giving up after %d tries." % try_count)
raise err

def make_report(logfile):
logfile.seek(0)
report = logfile.read()
log.debug(report)
if config['mailreport'].getboolean('report'):
msg = EmailMessage()
msg.set_content(report)
msg['From'] = config['mailreport'].get('mailfrom')
msg['To'] = config['mailreport'].get('mailto')
msg['Subject'] = config['mailreport'].get('subject')
mailhost = config['mailreport'].get('mailhost')
with smtplib.SMTP(mailhost) as smtp:
smtp.send_message(msg)

def main():
setup_logging(config['logging'])
with tempfile.TemporaryFile(mode='w+t') as tmpf:
exit_code = 0
with logging_add_report(config['logging'], tmpf):
have_patches = patch(stdout=tmpf)
if have_patches:
tmpf.seek(0)
report = tmpf.read()
log.debug(report)
if config['mailreport'].getboolean('report'):
msg = EmailMessage()
msg.set_content(report)
msg['From'] = config['mailreport'].get('mailfrom')
msg['To'] = config['mailreport'].get('mailto')
msg['Subject'] = config['mailreport'].get('subject')
mailhost = config['mailreport'].get('mailhost')
with smtplib.SMTP(mailhost) as smtp:
smtp.send_message(msg)
try:
have_patches = patch(stdout=tmpf)
except (ZypperCommitError, ZypperRPMScriptfailed,
ZypperSignal) as err:
log.error(err)
exit_code = err.ExitCode
if exit_code or have_patches:
make_report(tmpf)
return exit_code

if __name__ == "__main__":
try:
main()
exit_code = main()
except (ZypperPrivilegesError, ZypperNoReposError, ZypperLockedError,
ZypperCommitError, ZypperSignal, ZypperReposSkipped,
ZypperRPMScriptfailed) as err:
ZypperReposSkipped) as err:
log.error(err)
sys.exit(err.ExitCode)
except ZypperExitException as err:
Expand All @@ -327,3 +337,4 @@ def main():
log.critical("Internal error %s: %s", type(err).__name__, err,
exc_info=err)
sys.exit(-1)
sys.exit(exit_code)
5 changes: 4 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def run(self, exitcode=0):
p.join()
assert p.exitcode == exitcode

def check_report(self):
def check_report(self, extra_msg=None):
with open("report.pickle", "rb") as f:
host = pickle.load(f)
msg = pickle.load(f)
Expand All @@ -132,4 +132,7 @@ def check_report(self):
idx = body.find(res.stdout, idx)
assert idx >= 0
idx += len(res.stdout)
if extra_msg:
idx = body.find(extra_msg, idx)
assert idx >= 0
return host, msg
12 changes: 12 additions & 0 deletions tests/test_02_exitcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,15 @@ def test_error_permission(tmpdir):
# assert that no mail report has been sent:
with pytest.raises(FileNotFoundError):
caller.check_report()


def test_error_scripterr(tmpdir):
"""A %post() scriptlet from one of the packages failed.

This may happen, though rarely. The auto-patch should report the
error, but still deliver a report.
"""
with tmpdir.as_cwd():
caller = AutoPatchCaller.get_caller("err_scripterr")
caller.run(exitcode=107)
caller.check_report(extra_msg="ERROR:")
16 changes: 16 additions & 0 deletions tests/zypper-result-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -435,5 +435,21 @@
"returncode": 5,
"stderr": "Root privileges are required to run this command.\n"
}
],
"err_scripterr": [
{
"cmd": "patch-check",
"returncode": 100,
"stdout": "\nCategory | Patches\n------------+--------\nrecommended | 1\n\n1 patch needed (0 security patches)\n"
},
{
"cmd": "list-patches",
"stdout": "\nRepository | Name | Category | Severity | Interactive | Status | Since | Summary\n-------------------------------------------------------------+-----------------------------+-------------+----------+-------------+--------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\nUpdate repository with updates from SUSE Linux Enterprise 15 | openSUSE-SLE-15.6-2025-2574 | recommended | moderate | --- | needed | 2025-08-08 | Recommended update for python3-PyNaCl, python3-atomicwrites, python3-cryptography, python3-cryptography-vectors, python3-more-itertools, python3-paramiko, python3-pip, python3-pyOpenSSL, python3-pytest, python3-setuptools\n\n1 patch needed (0 security patches)\n\n"
},
{
"cmd": "patch",
"returncode": 107,
"stdout": "\nThe following 2 packages are going to be upgraded:\n python3-pip python3-pytest\n\nThe following NEW patch is going to be installed:\n openSUSE-SLE-15.6-2025-2574\n\n2 packages to upgrade.\n\nPackage download size: 2.2 MiB\n\nPackage install size change:\n | 10.2 MiB required by packages that will be installed\n -1.8 MiB | - 12.0 MiB released by packages that will be removed\n\nBackend: classic_rpmtrans\nContinue? [y/n/v/...? shows all options] (y): y\n\n"
}
]
}