やる気を削がれる出来事
アーマードコアⅥのデータが消し飛んだ。クラウドのデータも逝かれた。
今日PS5を久しぶりに起動しアーマードコアⅥをやろうとしたのだが、何故かニューゲームしかなくて、頭に疑問符を浮かべながらクラウドの同期確認をしたところ、クラウド側のデータが更新されてセーブデータが消し飛んだ。まるで意味が分からない。
下手糞ながら3周してパーツを全収集していたのにお釈迦になった。
別に対戦したかった訳ではないのだが、武器やパーツを付け替えて勝てそうなアセンを考えたかったのに、まさか一からやり直す羽目になるとは思いもしなかった。
あまりの理不尽極まりない事態に正直かなり参っている。

スピリチュアル界隈だとここから何を学べたかという話になるのだろうが、正直なところここから学べることなんてあるだろうか?
精神が鍛えられた?単にやる気を削がれたうえ、一からやり直すという保証もないのに精神が鍛えられるはずもない。単なる詭弁である。
バックアップを取った方が良かった?娯楽にまで徹底した対策が必要なのであれば息が詰まる。
そんな生き方は誰も望まない。いったいどこで緊張を解けというのだろうか。。。
話のネタになった?こんなつまらない話など一時だけの話題にしかならない。
そんなことのためにセーブデータが犠牲になったというなら糞喰らえである。
万が一にでも私の方に過失があったなら、貴重な学びを得たと胸を張って言えるが、過失無き理不尽は単なる理不尽である。私はそれを喜ぶようなマゾヒストではない。断じて違う。
例えば、通り魔に襲われて貴重な学びを得たと言う者はいない。仮にそんな経験をしても対策のしようが無い。防犯グッズを買っておけばよかったなんていうのはお門違いだ。
対策をしたところでそれが完璧に動作する保証はない、完璧に動作したところで有効である保証もない。トライ&エラーで有効な手段を探るわけにもいかない。そもそも、状況によって有効かどうかは変わる。そして、そう何度も起きるわけがないのだ。
いつか必ず起きる災害と違って、通り魔には一生遭遇しないことも多い。
それなのにいつ如何なる時も様々な状況を想定して防犯対策を強いられるのはおかしな話だ。
膨大な可能性の海の中で、確率の低い事象にまで一々対策していられないのだ。
そういえば、少し前にJICAが4都市でアフリカのホームタウン化を計画していたが、あれが実現すれば通り魔犯罪が日常になる可能性がある。よりによってアフリカでも有数の犯罪大国から受け入れようとするのはそこはかとなく悪意を感じる。恐らく恣意的なものだろう。偶然も重なれば必然なのだ。
それにしても身体能力に秀でた外国人に襲われる恐怖は計り知れないものがある。
女性は特にそうだろう。気の毒なことだ。
そういえば、熊の被害も増えているのだったか。それなんてディストピア。
動物は電磁波に敏感らしいので、あちらこちらに電磁波をまき散らされるのは参るのだろう。
事務所が難波にあった時は私も出社するたびに体調を崩したものだ。
当時は高所が駄目だと思っていたが、電磁波(特に5G)の影響だったかもしれない。
そういう可能性も微レ存。
サーバー再起動処理
さて、成果物の棚卸しの第一弾として、AWSのサーバー再起動のために組んだPythonコードを下記に添付する。
とはいえ、会社の情報が洩れそうな部分は伏字や抜粋していない。(子クラスなど)
あくまで掲載しても問題なさそうな部分だけである。
対象のサーバーは冗長構成で構成されており、ロードバランサーからの切り離しや、EC2内で稼働しているソフトウェア(ジョブ管理ソフト(JobCenterやSystemwalker)など)を個別に切り離す必要があった。(役割によっても切り離し手順が異なる。)
ロードバランサーについては、切り離しに5分間の待機が必要だったためLambdaの稼働時間はかなりぎりぎりだったのを覚えている。
結局AWS側のリソース不足でサーバーが再稼働出来ない不具合がしばしば起きたため、利用が停止された。今回はその供養も兼ねている。使えそうな部分があればぜひ使ってやってほしい。
raize の使用方法が間違っているといった点についてはご愛敬。
言い訳としては、実務での使用回数が数回程度しかなかったのと、そもそもプログラミングをする機会が年に1回あればいい方だったので細かい文法は毎回覚え直しだったのだ。。。
仕事では主にLinuxOSのメンテナンスの対応ばかりだった。
お陰でLinuxOSのアップグレード作業という貴重な体験もさせてもらえたが。。。
import boto3
import time
from datetime import datetime, timedelta, timezone
# 関数名 : lambda_handler
# 機能 : ハンドラー関数(エントリポイントとして機能)
def lambda_handler(event, context):
# ====== パラメータ設定 ==================================
# タイムスタンプを取得
print('StartTime:' + get_timestamp())
print('Start ServerReboot')
sv_reboot = RebootXXXXX() # ServerRebootの継承クラス
#sv_reboot.detach_nlb()
#sv_reboot.attach_nlb()
if not sv_reboot.exec():
print('Faield to ServerReboot')
raise 'Failed to ServerReboot'
print('End ServerReboot')
print('EndTime:' + get_timestamp())
# 正常終了
return 'End ServerReboot'
# 関数名 : get_timestamp
# 戻り値 : 文字列(str)
# 引数 : datefmt(str)
# 機能 : タイムスタンプを取得
def get_timestamp(datefmt = '%Y-%m-%dT%H:%M:%S.%fZ'):
# タイムゾーンの生成
JST = timezone(timedelta(hours = +9), 'JST')
# タイムスタンプを取得
return datetime.now(JST).strftime(datefmt)
# 関数名 : create_filter
# 戻り値 : リスト(list)
# 引数 : filter(str)
# : values(list)
# 機能 : フィルターを作成
# : valuesはリスト
def create_filter(filter, values):
filters = [
{
'Name': filter,
'Values': values
}
]
return filters
# 関数名 : create_filter_and
# 戻り値 : リスト(list)
# 引数 : filter1(str)
# : values1(list)
# : filter2(str)
# : values2(list)
# 機能 : AND条件のフィルターを作成
# : values1、values2はリスト
def create_filter_and(filter1, values1, filter2, values2):
filters = [
{
'Name': filter1,
'Values': values1
},
{
'Name': filter2,
'Values': values2
}
]
return filters
# SNS操作クラス
class SNSAction:
# 関数名 : __init__
# 戻り値 : None
# 引数 : None
# 機能 : コンストラクタ
def __init__(self):
# SNSのインスタンスを生成
self.sns = boto3.client('sns', region_name = 'ap-northeast-1')
# 関数名 : send_message
# 戻り値 : None
# 引数 : topic_arn(str)
# : subject(str)
# : send_message(list)
# 機能 : AWS/SNSの機能を使用しメール通知を行う
def send_message(self, topic_arn, subject, send_message):
try:
# AWS/SNSでメールを送信。
response = self.sns.publish(
TopicArn = topic_arn, # AWS/SNSのトピックARNをセット
Message = send_message, # 送信メッセージをセット
Subject = subject # 件名をセット
)
messageid = response['MessageId']
print('MessageId:' + messageid)
except Exception as ex:
# メール送信に失敗した場合、エラーを発生させる。
print('Failed to SendMessage')
print(ex)
raise ex
# 関数名 : create_topic
# 戻り値 : 文字列(str)
# 引数 : topic_name(str)
# 機能 : トピック名を引数にトピックARNを取得する
def create_topic(self, topic_name):
response = ''
try:
response = self.sns.create_topic(Name = topic_name)['TopicArn'] # 設定したトピック名からトピックARNを取得
except Exception as ex:
# トピックARNの取得に失敗した場合、エラーを発生される。
print('Failed to CreateTopic')
print(ex)
raise ex
return response
# SSM操作クラス
class SSMAction:
# メンバ変数定義
__ssmcmd_status = '' # SSMコマンドのステータス
__ssmcmd_output = '' # SSMコマンドの実行結果
__ssmcmd_exitcode = '' # SSMコマンドの終了コード
# 関数名 : __init__
# 戻り値 : None
# 引数 : None
# 機能 : コンストラクタ
def __init__(self):
# SSMのインスタンスを生成
self.ssm = boto3.client('ssm', region_name = 'ap-northeast-1')
# 関数名 : describe_instance_information
# 戻り値 : 真偽値(True:実行可能、False:実行不可)
# 引数 : instanceids(list)
# 機能 : SSMが実行可能状態かチェック
def describe_instance_information(self, instanceids):
try:
response = self.ssm.describe_instance_information(
InstanceInformationFilterList = [
{
'key': 'InstanceIds',
'valueSet': instanceids
}])
#print(response)
if len(response['InstanceInformationList']) == 0:
return False
except Exception as ex:
# 異常終了
print('Failed to SSM DescribeInstancesInformation')
print(ex)
raise ex
return True
# 関数名 : send_command
# 戻り値 : 文字列(str)
# 引数 : instanceids(list)
# : commands(list)
# : timeoutsec(integer)
# 機能 : SSMにコマンドを送信する
def send_command(self, instanceids, commands, timeoutsec = 60):
commandid = ''
try:
# ssmにコマンドを送信
response = self.ssm.send_command(
InstanceIds = instanceids, #コマンドを送信するEC2インスタンスID
DocumentName = 'AWS-RunShellScript', #AWS/CLIを使用
TimeoutSeconds = timeoutsec, #処理開始から1分後にタイムアウト
Parameters = {
'commands': commands #CLIコマンドをセット
})
if len(response) > 0:
#実行結果を確認するため、CommandIdを取得
commandid = response['Command']['CommandId']
except Exception as ex:
# 異常終了
print('Failed to SSM SendCommand')
print(ex)
raise ex
return str(commandid)
# 関数名 : list_command_invocations
# 戻り値 : 辞書型(dict)
# 引数 : commandid(str)
# : details(Boolean)
# 機能 : SSMコマンドのレスポンスを取得
def list_command_invocations(self, commandid, details = True):
response = {}
try:
# SSMに送信したコマンドの実行結果を取得する。
response = self.ssm.list_command_invocations(
CommandId = commandid, # コマンドIDをセット
Details = details) # 詳細情報を取得する
except Exception as ex:
# 異常終了
print('Failed to SSM ListCommandInvocations')
print(ex)
raise ex
return response
# 関数名 : list_command_invocations
# 戻り値 : 辞書型(dict)
# 引数 : commandid(str)
# : filters(list)
# : details(Boolean)
# 機能 : SSMコマンドのレスポンスを取得
#def list_command_invocations(self, commandid, filters, details = True):
# response = {}
# try:
# # SSMに送信したコマンドの実行結果を取得する。
# response = self.ssm.list_command_invocations(
# CommandId = commandid, # コマンドIDをセット
# Filters = filters, # フィルターをセット
# Details = details) # 詳細情報を取得する
# except Exception as ex:
# # 異常終了
# print('Failed to SSM ListCommandInvocations')
# print(ex)
# raise ex
# return response
# 関数名 : get_ssmcmd_results
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : commandid(str)
# : interval(float)
# : maxattempts(integer)
# 機能 : SSMコマンドの実行結果を取得
def get_ssmcmd_results(self, commandid, interval, maxattempts = 60):
cnt_attempt = 0
#実行結果を取得できるまでループ
while True:
cnt_attempt += 1
if cnt_attempt > maxattempts:
# タイムアウト
self.clear_result()
print('Failed to SSM Command Timeout')
return False
#SSMコマンドの実行結果を取得
response = self.list_command_invocations(commandid)
#print(response)
#実行結果の詳細情報が空なら待ち
if len(response['CommandInvocations']) == 0:
print('list_command_invocations waiting')
#一定時間スリープ
time.sleep(interval)
continue
status = response['CommandInvocations'][0]['Status'] #コマンドのステータスを取得
# SSMコマンドが実行中ではないなら実行結果を取得する
if not self.ssmcmd_status_waiting(status):
self.__ssmcmd_exitcode = response['CommandInvocations'][0]['CommandPlugins'][0]['ResponseCode'] #コマンドの終了コードを取得
self.__ssmcmd_output = response['CommandInvocations'][0]['CommandPlugins'][0]['Output'] #コマンドの実行結果を取得
self.__ssmcmd_status = status # 実行結果のステータスを記録する
#コマンドの実行結果が Success(成功) 以外なら
if not self.ssmcmd_status_success(self.__ssmcmd_status):
# 異常終了
return False
#実行結果取得後、ループを抜ける
break
else:
#一定時間スリープ
print('waiting:' + status)
time.sleep(interval)
# 正常終了
return True
# 関数名 : ssmcmd_status_success
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : status(str)
# 機能 : SSMコマンドの実行結果がSuccess(成功)かチェック
def ssmcmd_status_success(self, status):
# Success:成功以外のステータスの場合はFalse
if status == 'Success':
return True
return False
# 関数名 : ssmcmd_status_waiting
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : status(str)
# 機能 : SSMコマンドの実行結果がPending(待ち状態)、もしくはInProgress(処理中)かチェック
def ssmcmd_status_waiting(self, status):
# ステータスがPending(待ち状態)、もしくはInProgress(処理中)の場合はTrue
if status == 'Pending': return True
if status == 'InProgress': return True
return False
# 関数名 : get_ssmcmd_exitcode
# 戻り値 : 数値(integer)
# 引数 : None
# 機能 : SSMコマンドの終了コードを返す
def get_ssmcmd_exitcode(self):
return self.__ssmcmd_exitcode
# 関数名 : get_ssmcmd_output
# 戻り値 : 文字列(str)
# 引数 : None
# 機能 : SSMコマンドの実行結果を返す
def get_ssmcmd_output(self):
return self.__ssmcmd_output
# 関数名 : get_ssmcmd_status
# 戻り値 : 文字列(str)
# 引数 : None
# 機能 : SSMコマンドのステータスを返す
def get_ssmcmd_status(self):
return self.__ssmcmd_status
# 関数名 : clear_result
# 戻り値 : None
# 引数 : None
# 機能 : 出力結果をクリア
def clear_result(self):
self.__ssmcmd_status = '' # SSMコマンドのステータス
self.__ssmcmd_output = '' # SSMコマンドの実行結果
self.__ssmcmd_exitcode = '' # SSMコマンドの終了コード
# EC2操作クラス
class EC2Action:
# 関数名 : __init__
# 戻り値 : None
# 引数 : None
# 機能 : コンストラクタ
def __init__(self):
# EC2のインスタンスを生成
self.ec2 = boto3.client('ec2', region_name = 'ap-northeast-1')
# 関数名 : reboot_instances
# 戻り値 : なし
# 引数 : instanceids(list)
# 機能 : EC2を再起動する
def reboot_instances(self, instanceids):
try:
# ssmにコマンドを送信
self.ec2.reboot_instances(InstanceIds = instanceids, DryRun = False)
except Exception as ex:
# 異常終了
print('Failed to EC2 RebootInstances')
print(ex)
raise ex
# 関数名 : stop_instances
# 戻り値 : なし
# 引数 : instanceids(list)
# 機能 : EC2を停止する
def stop_instances(self, instanceids):
try:
# ssmにコマンドを送信
self.ec2.stop_instances(InstanceIds = instanceids, DryRun = False)
except Exception as ex:
# 異常終了
print('Failed to EC2 StopInstances')
print(ex)
raise ex
# 関数名 : start_instances
# 戻り値 : なし
# 引数 : instanceids(list)
# 機能 : EC2を起動する
def start_instances(self, instanceids):
try:
# ssmにコマンドを送信
self.ec2.start_instances(InstanceIds = instanceids, DryRun = False)
except Exception as ex:
# 異常終了
print('Failed to EC2 StartInstances')
print(ex)
raise ex
# 関数名 : get_ec2_instanceid
# 戻り値 : 文字列(str)
# 引数 : filters(list)
# 機能 : EC2を再起動する
def get_ec2_instanceid(self, filters):
response = []
try:
response = self.ec2.describe_instances(Filters = filters)
except Exception as ex:
print('Failed to EC2 DescribeInstances')
print(ex)
raise ex
return response['Reservations'][0]['Instances'][0]['InstanceId']
# 関数名 : wait_instance_stopped
# 戻り値 : なし
# 引数 : instanceids(list)
# : delay(integer)
# : maxattempts(integer)
# 機能 : EC2を再起動する
def wait_instance_stopped(self, instanceids, delay = 15, maxattempts = 40):
try:
# Waiterを生成
waiter = self.ec2.get_waiter('instance_stopped')
# EC2のインスタンスが起動するまで待ち
waiter.wait(
Filters = [],
InstanceIds = instanceids,
DryRun = False,
#MaxResults = 5,
#NextToken = '',
WaiterConfig = {
'Delay': delay, # 指定した間隔でポーリング
'MaxAttempts': maxattempts # 指定した回数ポーリング試行
})
except Exception as ex:
# 異常終了
print('Failed to EC2 Waiter InstanceStopped')
print(ex)
raise ex
# 関数名 : wait_instance_running
# 戻り値 : なし
# 引数 : instanceids(list)
# : delay(integer)
# : maxattempts(integer)
# 機能 : EC2を再起動する
def wait_instance_running(self, instanceids, delay = 15, maxattempts = 40):
try:
# Waiterを生成
waiter = self.ec2.get_waiter('instance_running')
# EC2のインスタンスが起動するまで待ち
waiter.wait(
Filters = [],
InstanceIds = instanceids,
DryRun = False,
#MaxResults = 5,
#NextToken = '',
WaiterConfig = {
'Delay': delay, # 指定した間隔でポーリング
'MaxAttempts': maxattempts # 指定した回数ポーリング試行
})
except Exception as ex:
# 異常終了
print('Failed to EC2 Waiter InstanceRunning')
print(ex)
raise ex
# 関数名 : wait_instance_status_ok
# 戻り値 : なし
# 引数 : instanceids(list)
# : delay(integer)
# : maxattempts(integer)
# 機能 : EC2を再起動する
def wait_instance_status_ok(self, instanceids, allinstances = True, delay = 15, maxattempts = 40):
try:
# Waiterを生成
waiter = self.ec2.get_waiter('instance_status_ok')
# EC2のインスタンスが起動するまで待ち
waiter.wait(
Filters = [],
InstanceIds = instanceids,
DryRun = False,
#MaxResults = 5,
#NextToken = '',
IncludeAllInstances = allinstances, # ステータスがRunning以外のインスタンスも確認
WaiterConfig = {
'Delay': delay, # 指定した間隔でポーリング
'MaxAttempts': maxattempts # 指定した回数ポーリング試行
})
except Exception as ex:
# 異常終了
print('Failed to EC2 Waiter InstanceRunning')
print(ex)
raise ex
# ElasticLoadBalancingV2操作クラス
class ELBV2Action:
# 関数名 : __init__
# 戻り値 : None
# 引数 : None
# 機能 : コンストラクタ
def __init__(self):
# ElasticLoadBalancingV2のインスタンスを生成
self.elbv2 = boto3.client('elbv2', region_name = 'ap-northeast-1')
# 関数名 : register_targets
# 戻り値 : なし
# 引数 : targetgrp_arn(str)
# : ec2_instanceid(str)
# : port(integer)
# : az(str)
# 機能 : ELBのターゲットグループにEC2インスタンスIDを紐付け
# : ターゲットグループの種類が"instance"の場合は別の関数を使用
#def register_targets(self, targetgrp_arn, ec2_instanceid, port, az = 'all'):
# try:
# self.elbv2.register_targets(
# TargetGroupArn = targetgrp_arn, # ターゲットグループのARNリソース名
# Targets = [
# {
# 'Id': ec2_instanceid, # EC2インスタンスID
# 'Port': port, # ポート番号
# 'AvailabilityZone': az # アベイラビリティーゾーン
# },
# ])
# except Exception as ex:
# print('Failed to ELBV2 RegisterTargets')
# print(ex)
# raise ex
# 関数名 : register_targets
# 戻り値 : なし
# 引数 : targetgrp_arn(str)
# : ec2_instanceid(str)
# : port(integer)
# 機能 : ELBのターゲットグループにEC2インスタンスIDを紐付け
# : ターゲットグループの種類が"instance"の場合はこの関数を使用
def register_targets(self, targetgrp_arn, ec2_instanceid, port):
try:
self.elbv2.register_targets(
TargetGroupArn = targetgrp_arn, # ターゲットグループのARNリソース名
Targets = [
{
'Id': ec2_instanceid, # EC2インスタンスID
'Port': port # ポート番号
},
])
except Exception as ex:
print('Failed to ELBV2 RegisterTargets')
print(ex)
raise ex
# 関数名 : deregister_targets
# 戻り値 : なし
# 引数 : targetgrp_arn(str)
# : ec2_instanceid(str)
# : port(integer)
# : az(str)
# 機能 : ELBのターゲットグループからEC2インスタンスIDを削除
# : ターゲットグループの種類が"instance"の場合は別の関数を使用
#def deregister_targets(self, targetgrp_arn, ec2_instanceid, port, az = 'all'):
# try:
# self.elbv2.deregister_targets(
# TargetGroupArn = targetgrp_arn, # ターゲットグループのARNリソース名
# Targets = [
# {
# 'Id': ec2_instanceid, # EC2インスタンスID
# 'Port': port, # ポート番号
# 'AvailabilityZone': az # アベイラビリティーゾーン
# },
# ])
# except Exception as ex:
# print('Failed to ELBV2 RegisterTargets')
# print(ex)
# raise ex
# 関数名 : deregister_targets
# 戻り値 : なし
# 引数 : targetgrp_arn(str)
# : ec2_instanceid(str)
# : port(integer)
# 機能 : ELBのターゲットグループからEC2インスタンスIDを削除
# : ターゲットグループの種類が"instance"の場合はこの関数を使用
def deregister_targets(self, targetgrp_arn, ec2_instanceid, port):
try:
self.elbv2.deregister_targets(
TargetGroupArn = targetgrp_arn, # ターゲットグループのARNリソース名
Targets = [
{
'Id': ec2_instanceid, # EC2インスタンスID
'Port': port # ポート番号
},
])
except Exception as ex:
print('Failed to ELBV2 RegisterTargets')
print(ex)
raise ex
# 関数名 : wait_target_deregistered
# 戻り値 : なし
# 引数 : targetgrp_arn(str)
# : ec2_instanceid(str)
# : port(integer)
# : delay(integer)
# : maxattempts(integer)
# 機能 : ELBのターゲットグループからEC2インスタンスIDを削除されるまで待機
def wait_target_deregistered(self, targetgrp_arn, ec2_instanceid, port, delay = 15, maxattempts = 40):
try:
# Waiterを生成
waiter = self.elbv2.get_waiter('target_deregistered')
# EC2のインスタンスが起動するまで待ち
waiter.wait(
TargetGroupArn = targetgrp_arn, # ターゲットグループのARNリソース名
Targets = [
{
'Id': ec2_instanceid, # EC2インスタンスID
'Port': port # ポート番号
},
],
WaiterConfig = {
'Delay': delay, # 指定した間隔でポーリング
'MaxAttempts': maxattempts # 指定した回数ポーリング試行
})
except Exception as ex:
# 異常終了
print('Failed to ELBV2 Waiter TargetDeregistered')
print(ex)
raise ex
# 関数名 : describe_load_balancers
# 戻り値 : 辞書型(dict)
# 引数 : elb_name(str)
# 機能 : ロードバランサー名を元にロードバランサーの情報を取得
def describe_load_balancers(self, elb_names):
response = {}
try:
response = self.elbv2.describe_load_balancers(
Names = elb_names
)
except Exception as ex:
print('Failed to ELBV2 DescribeLoadBalancers')
print(ex)
raise ex
return response
# 関数名 : get_load_balancer_arn
# 戻り値 : リスト(list)
# 引数 : elb_name(str)
# 機能 : ロードバランサー名を元にロードバランサーの情報を取得
def get_load_balancer_arn(self, elb_names):
response = self.describe_load_balancers(elb_names)
#arns = []
#for loadbalancer in response['LoadBalancers']
# arns.append(loadbalancer['LoadBalancerArn'])
# ロードバランサーARNを取得
#return arns
return response['LoadBalancers'][0]['LoadBalancerArn']
# 関数名 : describe_target_groups
# 戻り値 : 辞書型(dict)
# 引数 : elb_arn(str)
# 機能 : ロードバランサーARNを元にターゲットグループの情報を取得
def describe_target_groups(self, elb_arn):
response = {}
try:
response = self.elbv2.describe_target_groups(LoadBalancerArn = elb_arn)
except Exception as ex:
print('Failed to ELBV2 DescribeTargetGroups')
print(ex)
raise ex
return response
# 関数名 : describe_target_health
# 戻り値 : 辞書型(dict)
# 引数 : targetgrp_arn(str)
# : ec2_instanceid(str)
# 機能 : ターゲットグループARNとEC2インスタンスIDを元にヘルスチェック対象の情報を取得
# : ターゲットグループの種類が"instance"の場合はこの関数を使用
def describe_target_health(self, targetgrp_arn, ec2_instanceid):
response = {}
try:
response = self.elbv2.describe_target_health(
TargetGroupArn = targetgrp_arn,
Tragets = [
{
'Id': ec2_instanceid
}])
except Exception as ex:
print('Failed to ELBV2 DescribeTargetHealth')
print(ex)
raise ex
return response
# 親クラス
class ServerReboot:
# Lambda関数名
functionname = ''
# リブート対象のEC2インスタンスID
target_instanceid = ''
# リブート対象のEC2インスタンス名
target_instancename = ''
# 関数名 : __init__
# 戻り値 : None
# 引数 : None
# 機能 : コンストラクタ
def __init__(self):
# 各リソース操作クラスの生成
self.ec2_action = EC2Action()
self.ssm_action = SSMAction()
self.sns_action = SNSAction()
self.elbv2_action = ELBV2Action()
# 関数名 : lambda_lock
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : None
# 機能 : 対象EC2の/tmpフォルダにロックファイルを作成し、Lambdaの冪統制を確保する
def lambda_lock(self):
# ====== Lambdaロック処理 =========================================
# SSMコマンドが実行できる環境でないなら終了
if not self.check_ssm_agent([self.target_instanceid]):
# 異常終了
return False
# SSMコマンドの生成
commands = [
'/RDR/BC/unyo/shell/lambda_lock.sh ' + self.functionname
]
print('Start Lambda Lock')
# EDIAP1SVに対し再起動前処理を送信
commandid = self.ssm_action.send_command([self.target_instanceid], commands)
print('End Lambda Lock')
#コマンドIDを表示
print('CommandId:' + commandid)
interval = 1.0
# 終了コードが0(正常終了)ならTrueを返す
return self.check_ssmcmd_exitcode(commandid, interval)
# 関数名 : lambda_unlock
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : None
# 機能 : 対象EC2の/tmpフォルダにロックファイルを作成し、Lambdaの冪統制を確保する
def lambda_unlock(self):
# ====== Lambdaロック処理 =========================================
# SSMコマンドが実行できる環境でないなら終了
if not self.check_ssm_agent([self.target_instanceid]):
# 異常終了
return False
# SSMコマンドの生成
commands = [
'/RDR/BC/unyo/shell/lambda_unlock.sh ' + self.functionname
]
print('Start Lambda Unlock')
# EDIAP1SVに対し再起動前処理を送信
commandid = self.ssm_action.send_command([self.target_instanceid], commands)
print('End Lambda Unlock')
#コマンドIDを表示
print('CommandId:' + commandid)
interval = 1.0
# 終了コードが0(正常終了)ならTrueを返す
return self.check_ssmcmd_exitcode(commandid, interval)
# 関数名 : reboot
# 戻り値 : None
# 引数 : None
# 機能 : EC2を再起動
def reboot(self):
try:
#self.ec2_action.reboot_instances([self.target_instanceid])
self.stop()
self.wait_stopped()
self.start()
except Exception as ex:
# 異常終了
# 再起動に失敗した場合、各ソフトウェアを切り戻す
print('Failed to EC2 RebortInstances')
print(ex)
self.attach()
self.send_error_message('Failed to EC2 RebortInstances')
return False
return True
# 関数名 : stop
# 戻り値 : None
# 引数 : None
# 機能 : EC2を停止
def stop(self):
# EC2インスタンスを停止
self.ec2_action.stop_instances([self.target_instanceid])
# 関数名 : start
# 戻り値 : None
# 引数 : None
# 機能 : EC2を起動
def start(self):
# EC2インスタンスを起動
self.ec2_action.start_instances([self.target_instanceid])
# 関数名 : wait
# 戻り値 : None
# 引数 : None
# 機能 : EC2再起動まで待機
def wait(self):
try:
# EC2インスタンスの再起動まで待機
self.wait_status_ok()
# SSMコマンドが実行可能になるまで待機
self.wait_ssm_agent([self.target_instanceid])
time.sleep(10) # APEXが起動するまで待機
except Exception as ex:
# 異常終了
# 起動待機処理に失敗した場合、各ソフトウェアを切り戻す
print('Failed to EC2 Wait')
print(ex)
self.attach()
self.send_error_message('Failed to EC2 Wait')
return False
return True
# 関数名 : wait_ssm_agent
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : instanceids(list)
# : delay(integer)
# : maxattempts(integer)
# 機能 : SSMコマンドが実行可能になるまで待機
def wait_ssm_agent(self, instanceids, delay = 15, maxattempts = 40):
for i in range(maxattempts):
if self.check_ssm_agent(instanceids):
# 正常終了
return True
# 一定時間スリープ
time.sleep(delay)
# 異常終了
return False
# 関数名 : check_ssm_agent
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : instanceids(list)
# 機能 : SSMコマンドが実行可能か確認
def check_ssm_agent(self, instanceids):
return self.ssm_action.describe_instance_information(instanceids)
# 関数名 : wait_stopped
# 戻り値 : None
# 引数 : None
# 機能 : EC2停止まで待機
def wait_stopped(self):
# EC2インスタンスの停止まで待機
self.ec2_action.wait_instance_stopped([self.target_instanceid])
# 関数名 : wait_running
# 戻り値 : None
# 引数 : None
# 機能 : EC2起動まで待機
def wait_running(self):
# EC2インスタンスの起動まで待機
self.ec2_action.wait_instance_running([self.target_instanceid])
# 関数名 : wait_status_ok
# 戻り値 : None
# 引数 : None
# 機能 : EC2起動まで待機
def wait_status_ok(self):
# EC2インスタンスの起動まで待機
self.ec2_action.wait_instance_status_ok([self.target_instanceid])
# 関数名 : alive_monitoring
# 戻り値 : None
# 引数 : None
# 機能 : 死活監視処理
def alive_monitoring(self):
return True
# 関数名 : detach
# 戻り値 : None
# 引数 : None
# 機能 : 切り離し処理
def detach(self):
return True
# 関数名 : attach
# 戻り値 : None
# 引数 : None
# 機能 : 切り戻し処理
def attach(self):
return True
# 関数名 : server_reboot
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : None
# 機能 : EC2を再起動
def server_reboot(self):
try:
# ====== 死活監視処理開始 ==============================================
if not self.alive_monitoring():
# 異常終了
return False
# ====== 切り離し処理開始 ==============================================
if not self.detach():
# 異常終了
return False
# ====== EC2再起動処理開始 =============================================
self.reboot()
# ====== 起動待機処理開始 ==============================================
self.wait()
# ====== 切り戻し処理開始 ==============================================
if not self.attach():
# 異常終了
return False
except Exception as ex:
print('Failed to ' + self.functionname)
self.send_error_message('Failed to ' + self.functionname)
return False
# 正常終了
return True
# 関数名 : exec
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : None
# 機能 : 再起動の実行
def exec(self):
# ====== Lambda ロック処理開始 =========================================
if not self.lambda_lock():
print('Failed to Lambda Lock')
# 異常終了
return False
# サーバー再起動を実行
result = self.server_reboot()
# ====== Lambda ロック解除処理開始 =========================================
if not self.lambda_unlock():
print('Failed to Lambda Unlock')
# 異常終了
return False
return result
# 関数名 : check_ssmcmd_exitcode
# 戻り値 : 真偽値(True:正常終了、False:異常終了)
# 引数 : commandid(str)
# : interval(integer)
# 機能 : SSMコマンドの終了コードをチェック
# 修正 : 試行回数を60から240の修正(2021/01/20)
def check_ssmcmd_exitcode(self, commandid, interval, maxattempts = 240):
print('Start Check SSMCommand Status')
# SSMコマンドの実行結果を取得(True or False)
response = self.ssm_action.get_ssmcmd_results(commandid, interval, maxattempts)
output = self.ssm_action.get_ssmcmd_output()
exitcode = self.ssm_action.get_ssmcmd_exitcode()
status = self.ssm_action.get_ssmcmd_status()
print('SSMCommand Status:' + status)
print('SSMCommand ExitCode:' + str(exitcode))
print(output)
if not response:
print('Failed to SSMCommand Status')
return False
# 終了コードの確認
if exitcode == 0:
# 正常終了
print('End Check SSMCommand ExitCode')
return True
# 終了コードが不正な値
print('Failed to SSMCommand ExitCode')
return False
# 関数名 : send_error_message
# 戻り値 : None
# 引数 : error_message(list)
# 機能 : 障害通知を送信する。
def send_error_message(self, error_message):
# タイムスタンプを取得
timestamp = get_timestamp()
# 実行時には対象のトピック名に変更
topic_name = 'SAMPLE-SSM-TOPIC' # メール送信を行うAWS/SNSのトピック名をセット
topic_arn = self.sns_action.create_topic(topic_name) # 設定したトピック名からトピックARNを取得
subject = 'AWS/Lambda Error (' + self.functionname + ')' # 固定値で件名をセット
# 送信メッセージを作成
send_message = timestamp + '\n\n'\
+ 'Lambda Error: ' + self.functionname + '\n'\
+ 'Instance Name: ' + self.target_instancename + '\n'\
+ 'Instance Id: ' + self.target_instanceid + '\n'\
+ 'Error: ' + error_message + '\n'
# AWS/SNSの機能を使用し、障害メール通知を行う
self.sns_action.send_message(topic_arn, subject, send_message)