はじめに
AWS EC2リザーブドインスタンスの有効期限は1年または3年です。有効期限が迫ってきても、気づかない場合があります。今回、ClowdWatch Eventsをトリガー(1日毎に実行)としてLambda関数を実行し、指定したしきい値以下になったリザーブドインスタンス1件毎に、期限が迫ってきている旨をSNSに通知するLambda関数を作成しました。
ソースコード
Threshold(目的のしきい値)とTopicARN(通知先のSNS TopicのARN)はLambda関数の環境変数で指定するようにしました。
import boto3
import json
import logging
import os
from datetime import datetime, timezone
logger = logging.getLogger()
logger.setLevel(logging.INFO)
ec2client = boto3.client('ec2')
snsclient = boto3.client('sns')
def lambda_handler(event, context):
try:
Threshold = int(os.environ['Threshold'])
except KeyError as e:
logger.error('env error: Specify Threshold')
raise e
except ValueError as e:
logger.error('env error: Specify Threshold with base 10 integer')
raise e
try:
TopicARN = os.environ['TopicARN']
except KeyError as e:
logger.error('env error: Specify TopicARN')
raise e
res = ec2client.describe_reserved_instances(
Filters=[{
'Name': 'state',
'Values': ['active']
}])
if len(res['ReservedInstances']) == 0:
logger.info('no-op by no reserved instances')
return {}
now = datetime.now(timezone.utc)
published = False
for instance in res['ReservedInstances']:
days = (instance['End'] - now).days
if days <= Threshold:
snsclient.publish(
TopicArn=TopicARN,
Subject='[Warn] EC2 ReservedInstance will expire in {} days'.format(days),
Message=json.dumps({
'ReservedInstancesId': instance['ReservedInstancesId'],
'End': instance['End'].isoformat(sep='T')
})
)
published = True
if published:
logger.info('published')
return {}
logger.info('no-op by no problems')
return {}
このプログラムで要注意なのは、ここで扱う日付型の変数はすべて aware である、という点です。具体的には now の取り扱いで、単に now = datetime.now() とすると、now は naive な日付として扱われます。一方、boto3 を通して得られる日付型変数(具体的には instance[‘END’] )は aware です。naive な日付と aware な日付とを計算しようとすると、エラー “can’t subtract offset-naive and offset-aware datetimes” が発生します。