I'm a cloud engineer at foot of the small mountain

クラウド・ETL/ELT・Nocode・BigQuery などを中心に書ければね。最近触ったサービス・フレームワークなどのメモ

Lambda とEventBridgeで起動中のEC2とRDSをTeamsに通知してみた

普段から検証用に EC2 や RDS を頻繁に作成するのですが、検証後にそのまま放置してしまい、月末に注意を受けることが多々あります。

まぁ起動中なのかどうかは、コンソールをみれば一発でわかりますが、実際はそれすらも忘れてやれてませんでした。

なので、今回は EC2・RDS の起動中のリソースをチェックして、Teams に通知するものを作ってみました。

構成

使用している AWS サービスは Lambda と EventBridge だけです。
内容は Lambda で EC2 と RDS のステータスを確認し、 EventBridge で1日1回実行するようにしました。
最終的に確認結果は Teams にLambda から連携するような形です。

Teams でWebhook を作成

通知したいチャネルの・・・をクリックしてコネクタを選択します。
f:id:sennanvolar44:20210626214734p:plain

構成をクリックします。
f:id:sennanvolar44:20210626214907p:plain

Webhook 名やアイコンを設定後、以下のようにURL が表示されますので、コピーして保持しておきます。
f:id:sennanvolar44:20210626215056p:plain

これでTeams の設定は完了です。続いて Lambda でチェック処理を設定します。

Lambda でチェック処理

最初に今回使用したコードは以下になります。

import boto3
import pprint
import urllib3 
import json
import logging

from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
 http = urllib3.PoolManager() 
 teams="https://xxxxxx/xxxx/xxxx/"

 ############ EC2 ##############
 client = boto3.client('ec2')
 responce = client.describe_instances(Filters=[{'Name':'instance-state-name','Values': ['running']}])

 all_list = []
 cnt = 0
 for reservation in responce['Reservations']:
  for instance in reservation['Instances']:
      ec2_tags = dict([(tag['Key'], tag['Value']) for tag in instance['Tags']])
      if ec2_tags!='':
       if cnt == 0:
        all_list.append(" <b>**** EC2 **** </b>")
       all_list.append(ec2_tags['Name'])
       cnt+=1


 ############ RDS ##############
 rds = boto3.client('rds')
 responserds = rds.describe_db_instances()
 cnt = 0

 for i in responserds['DBInstances']:
  if i['DBInstanceStatus'] == 'available':
     db_instance_name = i['DBInstanceIdentifier']
     if cnt == 0:
      all_list.append("")
      all_list.append(" <b>**** RDS **** </b>")
     all_list.append(db_instance_name)
     cnt+=1

 ############ Teams に通知 ##############

 if all_list == []:
 # 起動中のものがない場合は通知しない
  pass
 else:
  request_data = {
      'title': "以下のリソースが起動中です。<br>",
      'text': ' <br>'.join(all_list)
      }

  request = Request(
      teams, 
      data=json.dumps(request_data).encode('utf-8'),
      method="POST"
  )

  try:
   with urlopen(request) as response:
        response_body = response.read().decode('utf-8')
        logger.info(response_body)
  except HTTPError as err:
      logger.error(err.code)
  except URLError as err:
      logger.error(err.reason)

そんなに特別なことをしているわけではありませんが、少しだけ部分的にみていきます。

 http = urllib3.PoolManager() 
 teams="https://xxxxxx/xxxx/xxxx/"

urllib3はHTTP通信用のモジュールのようで、今回は Teams にHTTPで連携するので定義してます。
下段で定義しているURL は Teams のチャネルでWebhook を構成したときに取得できるURLです。後ほど取得方法も説明します。


 client = boto3.client('ec2')
 responce = client.describe_instances(Filters=[{'Name':'instance-state-name','Values': ['running']}])

boto3 というAWS SDK を使用して EC2 や RDS のリソース情報を取得し、 describe_instances で起動中のインスタンスで絞ってインスタンス情報を取得しています。
describe_instances の詳しい内容は下記リファレンスを参照してください。

boto3.amazonaws.com


 for reservation in responce['Reservations']:
  for instance in reservation['Instances']:
      ec2_tags = dict([(tag['Key'], tag['Value']) for tag in instance['Tags']])
      if ec2_tags!='':
       if cnt == 0:
        all_list.append(" <b>**** EC2 **** </b>")
       all_list.append(ec2_tags['Name'])
       cnt+=1

'Reservations'、'Instances' はお決まりっぽい。レスポンスがこうなので。
f:id:sennanvolar44:20210626211612p:plain 最終的にはインスタンス名だけを取得して、配列に追加していきます。


RDS も EC2 とほぼほぼ同じ構成です。なので説明は割愛します。


  request_data = {
      'title': "以下のリソースが起動中です。<br>",
      'text': ' <br>'.join(all_list)
      }

  request = Request(
      teams, 
      data=json.dumps(request_data).encode('utf-8'),
      method="POST"
  )

上段は Teams に投げるタイトルとメッセージ内容です。 インスタンス名が配列にセットされているので、それぞれ改行しながら抜き出している形です。

下段は、Teams に実際に投げるリクエストの定義です。中身のデータはjson.dumps でJSON に変換してエンコードします。


  try:
   with urlopen(request) as response:
        response_body = response.read().decode('utf-8')
        logger.info(response_body)
  except HTTPError as err:
      logger.error(err.code)
  except URLError as err:
      logger.error(err.reason)

最後は Teams にリクエストを投げるところです。

これで、リソースの状況をチェックして Teams に連携するところまでができました。これでLambda でテストを実行すれば、アドホックですがTeams に通知を出すことができます。

EventBrigde で定期実行の設定を行う

Lambda の画面からトリガーを追加をクリックします。
※設定後なので既にEventBridgeが表示されてます f:id:sennanvolar44:20210626215747p:plain

EventBridge を選択します。
f:id:sennanvolar44:20210626215906p:plain

あとは新規ルール作成でスケジュールを選択し、実行したいタイミングをCron式で設定します。なお時間はGMT なので、ローカルタイムゾーンでちゃんと時間が合ってるか確認した方が良いですね。
f:id:sennanvolar44:20210626220821p:plain

これで全ての設定が完了しました!

通知イメージ

あとは時間まで待つと、こんな感じで Teams に通知がきます!
※色々インスタンス名に個人名など入ってたのでぼかしてます f:id:sennanvolar44:20210626221159p:plain