diff --git a/check_s3_file_age.py b/check_s3_file_age.py index 4424248..9a8d9ec 100755 --- a/check_s3_file_age.py +++ b/check_s3_file_age.py @@ -31,22 +31,39 @@ # 3 = UNKNOWN/purple # -import ConfigParser -import os import datetime -import dateutil.parser -from dateutil.tz import * -import time -import socket -import boto +from datetime import timedelta, tzinfo +import botocore +import boto3 import argparse import re -#Parse command line arguments + +# A UTC class. +ZERO = timedelta(0) + + +class UTC(tzinfo): + """UTC""" + + def utcoffset(self, dt): + return ZERO + + def tzname(self, dt): + return "UTC" + + def dst(self, dt): + return ZERO + + +# Parse command line arguments parser = argparse.ArgumentParser(description='This script is a Nagios check that \ monitors the age of files that have \ been backed up to an S3 bucket.') +parser.add_argument('--profile', dest='profile', type=str, required=False, default='default', + help='AWS profile to use to connect') + parser.add_argument('--bucketname', dest='bucketname', type=str, required=True, help='Name of S3 bucket') @@ -59,7 +76,7 @@ help='Maximum age for files in an S3 bucket in hours. \ Default is 0 hours (disabled).') -parser.add_argument('--bucketfolder', dest='bucketfolder', type=str, default='', +parser.add_argument('--bucketfolder', dest='bucketfolder', type=str, default='', help='Folder to check inside bucket (optional).') #### # Add arg option for s3 region? @@ -74,11 +91,11 @@ args = parser.parse_args() -#Assign variables from command line arguments +# Assign variables from command line arguments bucketname = args.bucketname minfileage = args.minfileage maxfileage = args.maxfileage -bucketfolder = args.bucketfolder +bucketfolder = args.bucketfolder bucketfolder_regex = '^' + bucketfolder maxfilecount = 0 @@ -95,53 +112,66 @@ if (args.debug): print "DEBUG: Connecting to S3" -s3 = boto.connect_s3() +session = boto3.session.Session(profile_name=args.profile) +s3 = session.resource('s3') if (args.debug): print "DEBUG: S3 Connection: %s" % s3 # Check if bucket exists. Exit with critical if it doesn't -nonexistent = s3.lookup(bucketname) -if nonexistent is None: +bucket = s3.Bucket(bucketname) +exists = True + +try: + s3.meta.client.head_bucket(Bucket=bucketname) +except botocore.exceptions.ClientError as e: + # If a client error is thrown, then check that it was a 404 error. + # If it was a 404 error, then the bucket does not exist. + error_code = int(e.response['Error']['Code']) + if error_code == 404: + exists = False + +if exists is False: print "CRITICAL: No bucket found with a name of " + str(bucketname) exit(2) else: if (args.debug): print "DEBUG: Hooray the bucket " + str(bucketname) + " was found!" -bucket = s3.get_bucket(bucketname) if (args.debug): print "Bucket: %s" % bucket -#Figure out time delta between current time and max/min file age -maxagetime = datetime.datetime.now(tzutc()) - datetime.timedelta(hours=maxfileage) +# Figure out time delta between current time and max/min file age +maxagetime = datetime.datetime.now( + UTC()) - datetime.timedelta(hours=maxfileage) if (args.debug): - print 'MAX AGE TIME: ' + str(maxagetime) + print 'MAX AGE TIME: ' + str(maxagetime) -minagetime = datetime.datetime.now(tzutc()) - datetime.timedelta(hours=minfileage) +minagetime = datetime.datetime.now( + UTC()) - datetime.timedelta(hours=minfileage) if (args.debug): - print 'MIN AGE TIME: ' + str(minagetime) + print 'MIN AGE TIME: ' + str(minagetime) -#Loop through keys (files) in the S3 bucket and -#check each one for min and max file age. -for key in bucket.list(prefix=bucketfolder): - if (re.match(bucketfolder_regex,str(key.name))): +# Loop through keys (files) in the S3 bucket and +# check each one for min and max file age. +for key in bucket.objects.filter(Prefix=bucketfolder): + if (re.match(bucketfolder_regex, str(key.key))): if (args.listfiles): print '|' + str(key.storage_class) + '|' + str(key.name) + '|' \ - + str(dateutil.parser.parse(key.last_modified).replace(tzinfo=tzutc())) - if dateutil.parser.parse(key.last_modified) < maxagetime: + + str(key.last_modified.replace(tzinfo=UTC())) + if key.last_modified < maxagetime: if (args.listfiles): print 'Found file older than maxfileage of ' + str(maxfileage) + ' hours' maxfilecount += 1 - #print key.__dict__ - if dateutil.parser.parse(key.last_modified) > minagetime: + # print key.__dict__ + if key.last_modified > minagetime: if (args.listfiles): print 'Found file newer than minfileage of ' + str(minfileage) + ' hours' minfilecount += 1 totalfilecount += 1 -#Begin formatting status message for Nagios output -#This is conditionally formatted based on requested min/max options. +# Begin formatting status message for Nagios output +# This is conditionally formatted based on requested min/max options. msg = ' -' if minfileage > 0: msg = msg + ' MIN:' + str(minfileage) + 'hrs' @@ -149,15 +179,15 @@ msg = msg + ' MAX:' + str(maxfileage) + 'hrs' if maxfileage > 0: - msg = msg + ' - Files exceeding MAX time: ' + str(maxfilecount) + msg = msg + ' - Files exceeding MAX time: ' + str(maxfilecount) if minfileage > 0: - msg = msg + ' - Files meeting MIN time: ' + str(minfilecount) + msg = msg + ' - Files meeting MIN time: ' + str(minfilecount) msg = msg + ' - Total file count: ' + str(totalfilecount) -#I think there probably is a better way of doing this but what I have here works. +# I think there probably is a better way of doing this but what I have here works. # # Decide exit code for Nagios based on maxfilecount and minfilecount results. # @@ -191,4 +221,3 @@ print statusline exit(exitcode) -