#!/usr/bin/env python3 # -*- encoding: utf-8 -*- ##################################################################### # (c) 2016- by Sven Velt, Germany # # sven-mymonplugins@velt.biz # # # # This file is part of "velt.biz - My Monitoring Plugins" # # a fork of "team(ix) Monitoring Plugins" in 2015 # # URL: https://gogs.velt.biz/velt.biz/MyMonPlugins/ # # # # This file is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published # # by the Free Software Foundation, either version 2 of the License, # # or (at your option) any later version. # # # # This file 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 file. If not, see . # ##################################################################### import os import subprocess import sys import time try: from MyMonPlugin import MonitoringPlugin except ImportError: print('==========================') print('AIKS! Python import error!') print('==========================\n') print('Could not find class "MonitoringPlugin"!\n') print('Did you download "%s"' % os.path.basename(sys.argv[0])) print('without "MyMonPlugin/"?\n') print('Please go back to') print('https://gogs.velt.biz/velt.biz/MyMonPlugins and:') print('- get a full archive at http://gogs.velt.biz/velt.biz/MyMonPlugins/releases') print('- or a master snapshot at http://gogs.velt.biz/velt.biz/MyMonPlugins/archive/master.tar.gz\n') sys.exit(127) plugin = MonitoringPlugin( pluginname='check_apk', tagforstatusline='APK', description='Check APK package manager for updates', version='0.1', ) plugin.add_cmdlineoption('-P', '--path-apk', 'apk', 'full path to apk', default='/sbin/apk') plugin.add_cmdlineoption('-S', '--sync-repo-index', 'sync_repo_index', 'sync repository index files at startup', default=False, action='store_true') plugin.add_cmdlineoption('', '--ignore-sync-failure', 'fail_on_sync_failure', 'ignore repo index sync failures', default=True, action='store_false') plugin.add_cmdlineoption('', '--sudo', 'sudo', 'call "apk" with sudo', default=False, action='store_true') plugin.add_cmdlineoption('', '--mymonplugins-testmode', 'mymonplugins_testmode', None, default=False, action='store_true') plugin.parse_cmdlineoptions() ############################################################################## ##### Testmode if plugin.options.mymonplugins_testmode: mymonplugins_testmode = {} mymonplugins_testmode['apk update'] = '''fetch http://dl-cdn.alpinelinux.org/alpine/latest-stable/main/x86_64/APKINDEX.tar.gz fetch http://dl-cdn.alpinelinux.org/alpine/latest-stable/community/x86_64/APKINDEX.tar.gz v3.17.3-13-g98fa1f428e9 [http://dl-cdn.alpinelinux.org/alpine/latest-stable/main] v3.17.3-12-g492f704d069 [http://dl-cdn.alpinelinux.org/alpine/latest-stable/community] OK: 17824 distinct packages available '''.split('\n') mymonplugins_testmode['apk -s upgrade'] = '''(1/6) Upgrading alpine-release (3.17.2-r0 -> 3.17.3-r0) (2/6) Upgrading libcrypto3 (3.0.8-r1 -> 3.0.8-r3) (3/6) Upgrading libssl3 (3.0.8-r1 -> 3.0.8-r3) (4/6) Upgrading alpine-base (3.17.2-r0 -> 3.17.3-r0) (5/6) Upgrading mkinitfs (3.7.0-r0 -> 3.7.0-r1) (6/6) Upgrading openssl (3.0.8-r1 -> 3.0.8-r3) OK: 258 MiB in 220 packages '''.split('\n') ############################################################################## def run_command(cmdline, needs_sudo=False): tstart = time.time() if needs_sudo and plugin.options.sudo: new = ['sudo', '-n', '--'] new.extend(cmdline) cmdline = new plugin.verbose(1, 'Running command line: %s' % subprocess.list2cmdline(cmdline)) try: cmd = subprocess.Popen( cmdline, stdout = subprocess.PIPE, stderr = subprocess.PIPE ) except OSError: plugin.back2nagios(plugin.RETURNCODE['UNKNOWN'], 'Could not execute command line: %s' % subprocess.list2cmdline(cmdline)) (sout,serr) = cmd.communicate() plugin.verbose(2, 'Runtime %.3fs' % (time.time() - tstart, ) ) sout = sout.rstrip().decode('utf-8').split('\n') if sout == ['']: sout = [] serr = serr.rstrip().decode('utf-8').split('\n') if serr == ['']: serr = [] return( (sout, serr, cmd.returncode,) ) ############################################################################## if plugin.options.sync_repo_index: plugin.verbose(1, '-S/--sync_repo_index given') cmdline = [plugin.options.apk, 'update', '--no-progress',] (sout, serr, rc) = run_command(cmdline, needs_sudo=True) sout and plugin.verbose(3, sout, prefix='stdout: ') serr and plugin.verbose(3, serr, prefix='stderr: ') plugin.verbose(2, 'Return code: %d' % rc) if plugin.options.fail_on_sync_failure and (rc != 0 or 'ERROR:' in ' '.join(serr)): if 'Permission denied' in ' '.join(serr): plugin.back2nagios(plugin.RETURNCODE['CRITICAL'], 'Syncing of repository index files failed, permission denied. Do you need "--sudo"?', multiline=serr) plugin.back2nagios(plugin.RETURNCODE['CRITICAL'], 'Syncing of repository index files failed', multiline=serr) ############################################################################## cmdline = [plugin.options.apk, 'upgrade', '--simulate', '--no-progress',] (sout, serr, rc) = run_command(cmdline) sout and plugin.verbose(3, sout, prefix='stdout: ') serr and plugin.verbose(3, serr, prefix='stderr: ') plugin.verbose(2, 'Return code: %d' % rc) if plugin.options.sudo and 'sudo: ' in ' '.join(serr): # Running with sudo if rc == 1: # sudo RC 1: a password is required plugin.back2nagios(plugin.RETURNCODE['CRITICAL'], ' '.join(serr)) if rc == 8: # RC 8: Transaction aborted due to unresolved shlibs. plugin.back2nagios(plugin.RETURNCODE['WARNING'], serr[-1], serr[:-1]) elif rc not in [0, 6]: # RC 0: Packages to update # RC 6: Package(s) already installed plugin.back2nagios(plugin.RETURNCODE['WARNING'], 'Unknown returncode "%s", please contact the author of plugin or open an issue!' % rc) action = {'Upgrading':[], 'Installing':[], 'Purging':[], } action_verb = {'Upgrading':'upgrade', 'Installing':'install', 'Purging':'purge', } for line in sout[0:-1]: cols = line.split(' ') # Append package name to action type list action[cols[1]].append(cols[2]) if len(sout) == 1: plugin.remember_check('Updates', plugin.RETURNCODE['OK'], 'Everything uptodate') else: out = [] multiline = [] for act in list(action.keys()): pkgs = action.pop(act) pkgs.sort() l = len(pkgs) out.append('%s package%s to %s' % (l, l != 1 and 's' or '', action_verb[act]) ) l and multiline.append('%s(%s): %s' % (act, l, ', '.join(pkgs)) ) out = ', '.join(out) plugin.remember_check('Updates', plugin.RETURNCODE['CRITICAL'], out, multilineoutput=multiline) # Exit plugin.brain2output() plugin.exit()