check_forgejo_upgrade/check_forgejo_upgrade
Benjamin Renard 27a7385bed
All checks were successful
Run tests / test-precommit (push) Successful in 1m2s
Fix checking current version since semantic versioning adoption (v7.0.0)
2024-04-25 23:34:56 +02:00

127 lines
3.8 KiB
Python
Executable file

#!/usr/bin/python3
"""
Icinga/Nagios plugin to check Forgejo instance upgrade status.
Copyright (c) 2023 Benjamin Renard <brenard@zionetrix.net>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""
import argparse
import logging
import re
import subprocess # nosec
import sys
import requests
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--debug", action="store_true")
parser.add_argument("-p", "--path", type=str, help="Forgejo bin path", default="forgejo")
parser.add_argument(
"-U",
"--url",
type=str,
help="Forgejo releases URL",
default="https://codeberg.org/api/v1/repos/forgejo/forgejo/releases",
)
parser.add_argument(
"--pre-release",
action="store_true",
help="Allow pre-release (default: only stable release are considered)",
)
parser.add_argument(
"--draft",
action="store_true",
help="Allow draft release (default: only stable release are considered)",
)
parser.add_argument(
"-t", "--timeout", type=int, help="Specify timeout for HTTP requests (default: 20)", default=20
)
options = parser.parse_args()
logging.basicConfig(level=logging.DEBUG if options.debug else logging.WARNING)
CURRENT = None
cmd = [options.path, "--version"]
logging.debug("Command use to retrieve current version of Forgejo: %s", " ".join(cmd))
OUTPUT = None
EXCEPTION = None
try:
OUTPUT = subprocess.check_output(cmd) # nosec
logging.debug("Output:\n%s", OUTPUT)
m = re.search(r"version ([^ ]+)(\+gitea-| built)", OUTPUT.decode("utf8", errors="ignore"))
if m:
CURRENT = m.group(1)
except Exception as err: # pylint: disable=broad-except
EXCEPTION = err
logging.debug("Current version: %s", CURRENT)
if not CURRENT:
print("UNKNOWN - Fail to retrieve current Forgejo")
print(f'Command: {" ".join(cmd)}')
print("Output:")
print(OUTPUT if OUTPUT else "")
print("Exception:")
print(EXCEPTION if EXCEPTION else "")
sys.exit(3)
CURRENT = CURRENT.replace("+", "-")
logging.debug("Cleaned current version: %s", CURRENT)
LATEST = None
LATEST_NAME = None
try:
logging.debug("Get releases from %s...", options.url)
r = requests.get(options.url, timeout=options.timeout)
data = r.json()
logging.debug("Data retrieve:\n%s", data)
for item in data:
if not options.pre_release and item["prerelease"]:
logging.debug("Ignore pre-release %s", item["name"])
continue
if not options.draft and item["draft"]:
logging.debug("Ignore draft release %s", item["name"])
continue
LATEST = item
LATEST_NAME = re.sub("^v", "", item["name"])
break
except Exception: # pylint: disable=broad-except # nosec
pass
if not LATEST:
print("UNKNOWN - Fail to retrieve latest Forgejo release from the project RSS feed")
print(f"Current version: {CURRENT}")
sys.exit(3)
logging.debug("Latest version is %s", LATEST_NAME)
if LATEST_NAME == CURRENT:
print(
f"OK - The latest release of Forgejo is currently used "
f"({LATEST_NAME}, published on {LATEST['published_at']})"
)
sys.exit(0)
print(
"WARNING - The version of Forgejo currently used is not the latest "
f"({CURRENT} vs {LATEST_NAME}), published on {LATEST['published_at']})"
)
print(LATEST["body"])
print(f"URL: {LATEST['html_url']}")
sys.exit(1)