#!/usr/bin/env python """ Icinga/Nagios plugin to check if pip upgrade is available Copyright (c) 2022 Benjamin Renard 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 sys import subprocess import argparse import json import os import logging import traceback # nagios exit code STATUS = { 'OK': 0, 'WARNING': 1, 'CRITICAL': 2, 'UNKNOWN': 3 } parser = argparse.ArgumentParser() parser.add_argument( '-d', '--debug', action="store_true", dest="debug", default=False ) parser.add_argument( '-b', '--bin', action="store", dest="bin", help="Python binary path", type=str ) parser.add_argument( action="store", dest="packages", help=( "Python package(s) to check. By default, all installed" "packages are checked." ), nargs='*', default=[] ) options = parser.parse_args() logging.basicConfig( level=logging.DEBUG if options.debug else logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') if options.bin and not os.path.exists(options.bin): print(f'UNKNOWN - python executable "{options.bin}" not found') sys.exit(STATUS['UNKNOWN']) cmd = [ options.bin if options.bin else sys.executable, '-m', 'pip', 'list', '--format', 'json', '--outdated' ] logging.debug('Execute external command: %s', ' '.join(cmd)) output = subprocess.check_output(cmd) logging.debug('Output:\n%s', output) try: outdated_packages = dict( (package['name'], package) for package in json.loads(output) if not options.packages or package['name'] in options.packages ) except Exception as exc: # pylint: disable=broad-except print('UNKNOWN - Exception occured parsing pip output') traceback.print_exc(exc) sys.exit(STATUS['UNKNOWN']) if outdated_packages: if len(outdated_packages) > 1: print(f'WARNING - {len(outdated_packages)} upgrades available') print('\n'.join([ f' - {name} ({p["version"]} => {p["latest_version"]})' for name, p in outdated_packages.items() ])) else: name = next(iter(outdated_packages)) p = outdated_packages[name] print( f'WARNING - available upgrade for {name} ' f'({p["version"]} => {p["latest_version"]})' ) sys.exit(STATUS['WARNING']) if options.packages and len(options.packages) == 1: print(f'OK - {options.packages[0]} is uptodate') else: print('OK - all packages is uptodate') sys.exit(STATUS['OK'])