AWS-CLIによるAMI作成と削除自動化（JSON取得によるRedmineチケット駆動）

# はじめに
本記事では、AWS-CLIによるAMI作成方法と削除方法について記述します。
また、JenkinsとRedmineを使用したAMI作成・削除の自動化の実現例も合わせて記述します。

# 実現イメージ
チケット起票（Redmine）→チケット内容取得（Jenkins）→取得内容に合わせてAWS-CLI実行（Jenkins）→起票
チケット更新（Jenkins,Redmine）※

※AWS-CLI実行結果を起票されたチケットに対して更新します。（AMIIDやチケットステータスを更新）

# AMI作成
### コマンド
```bash:AMI作成
aws ec2 create-image --instance-id EC2インスタンスID --name "任意のAMI名" --reboot
```

### 説明
*--instanceid*：AMIの元となるEC2インスタンスIDを指定してください。インスタンスIDはAWSコンソールまたはAWS-CLIだとdescribe-instancesで参照できます。
*--name*：作成するAMIの名前を指定します。文字の範囲ですが、ASCIIコードまでしか対応されていなかった気がします。曖昧ですみません…
*--reboot/--no reboot*：AMI作成時にインスタンスを再起動するかを指定します。--no rebootでインスタンスが稼働中にAMIを作成することができます。ただし、公式ドキュメントには以下のように記載されています。可能な限り--rebootを指定して、インスタンスとAMIが同じ状態であることを担保したほうが良いと思います。

```
[No reboot] を選択した場合、Amazon では作成されたイメージのファイルシステムの整合性を保証できません。
```

# AMI削除
### コマンド
```bash:AMI削除
aws ec2 deregister-image --image-id 削除したいAMIID
```
```bash:SnapShot削除
aws ec2 delete-snapshot --snapshot-id AMIに紐づくSnapShotIDを指定
```

### 説明
*--image-id*：削除したいAMIIDを指定します。
*SnapShot削除*：AMIに紐づくSnapShotを削除しない限り、課金されます。

# 実装例
## Jenkins側（シェルの実行）
```bash
#!/bin/bash

#JSON形式でチケット情報を取得(終了チケットを含めて取得)
JSON=$(curl -v -H "Content-Type: application/json" -X GET --data-binary "@issue.json" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定" http://RedmineURLをここに指定/issues.json?status_id=%2a)

#チケットID取得
TicketId=$(echo ${JSON} | jq '.issues[].id')
#チケットステータス取得
TicketStatus=$(echo ${JSON} | jq '.issues[].status | .id')
#チケット進捗率取得
TicketDoneRatio=$(echo ${JSON} | jq '.issues[].done_ratio')
#インスタンスID取得
InstanceId=$(echo ${JSON} | jq '.issues[].description' | sed -e 's/\\r\\n/,/g' | awk -F, '{print $1}' | awk -F: '{print $2}')
#AMI名取得
AmiName=$(echo ${JSON} | jq '.issues[].subject' | sed -e 's/[\" ,]//g')

#取得した値を配列化
TICKET_ID=(`echo ${TicketId}`)
TICKET_STATUS=(`echo ${TicketStatus}`)
TICKET_DONE_RATIO=(`echo ${TicketDoneRatio}`)
INSTANCE_ID=(`echo ${InstanceId}`)
AMI_NAME=(`echo ${AmiName}`)


COUNT=0
for rec in ${TICKET_ID[@]}
do
    #チケットステータスが新規のチケットを対象とする
	if [ ${TICKET_STATUS[$COUNT]} -eq "1" ]; then
    #チケットステータスが新規のみAMI作成
    	#AMI作成
    	RET=$(aws ec2 create-image --instance-id ${INSTANCE_ID[$COUNT]} --name "${AMI_NAME[$COUNT]}" --reboot)
        
        #作成したAMIIDを取得
    	AmiId=$(echo ${RET} | python -m json.tool | grep "ImageId" | awk -F: '{print $2}' | sed -e 's/[\" ,]//g')
        
        #AMIの元となるインスタンスのタグ情報取得
        NameTag=$(aws ec2 describe-instances --instance-ids ${INSTANCE_ID[$COUNT]} | jq '.Reservations[].Instances[] | .Tags[] | select(.Key=="Name").Value')
        ApplicationTag=$(aws ec2 describe-instances --instance-ids ${INSTANCE_ID[$COUNT]} | jq '.Reservations[].Instances[] | .Tags[] | select(.Key=="Application").Value')
        CostcenterTag=$(aws ec2 describe-instances --instance-ids ${INSTANCE_ID[$COUNT]} | jq '.Reservations[].Instances[] | .Tags[] | select(.Key=="Costcenter").Value')
        OwnerTag=$(aws ec2 describe-instances --instance-ids ${INSTANCE_ID[$COUNT]} | jq '.Reservations[].Instances[] | .Tags[] | select(.Key=="Owner").Value')
        
        
        #作成したAMIにタグを付与
        aws ec2 create-tags --resources ${AmiId} --tags Key=Name,Value=${NameTag}
        aws ec2 create-tags --resources ${AmiId} --tags Key=Application,Value=${ApplicationTag}
        aws ec2 create-tags --resources ${AmiId} --tags Key=Costcenter,Value=${CostcenterTag}
        aws ec2 create-tags --resources ${AmiId} --tags Key=Owner,Value=${OwnerTag}
        #チケットIDをタグに追加
        aws ec2 create-tags --resources ${AmiId} --tags Key=TicketId,Value=${TICKET_ID[$COUNT]}
        
        #作成したAMIIDをチケットの履歴に追加
        curl -v -H "Content-Type: application/json" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定" -X PUT -d '{"issue":{"notes":"AmiId:'$AmiId'"}}' http://RedmineURLをここに指定/issues/${TICKET_ID[$COUNT]}.json
        
    	#チケットステータスを"進行中"に更新
        curl --include http://RedmineURLをここに指定/issues/${TICKET_ID[$COUNT]}.xml -X PUT -d '<issue><status_id>2</status_id></issue>' -H "Content-Type: text/xml" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定"

    #チケットステータスが進行中かつ進捗率が0%のチケットを対象とする        
    elif [ ${TICKET_STATUS[$COUNT]} -eq "5" ] && [ ${TICKET_DONE_RATIO[$COUNT]} -eq 0 ]; then
        #チケットステータスが"終了"かつ進捗率が"0%"の場合、AMI削除
        
        #AMI情報取得
        AmiList=$(aws ec2 describe-tags --filters "Name=resource-type,Values=image" "Name=key,Values=TicketId" "Name=value,Values=${TICKET_ID[$COUNT]}")
        
        #AMIID取得
        DeleteAmiId=$(echo ${AmiList} | jq '.Tags[].ResourceId' | sed -e 's/[\" ,]//g')
        
		#SnapShot情報取得
        SnapShotId=$(aws ec2 describe-images --image-ids $DeleteAmiId | jq '.Images[].BlockDeviceMappings[].Ebs | .SnapshotId' | sed -e 's/[\" ,]//g')
        #取得した値を配列化
		SNAPSHOT_ID=(`echo ${SnapShotId}`)

        #AMI削除
		aws ec2 deregister-image --image-id $DeleteAmiId
        
        #スナップショット削除
        #INT=0
        for item in ${SNAPSHOT_ID[@]}
        do
        	aws ec2 delete-snapshot --snapshot-id ${SNAPSHOT_ID[$INT]}
            INT=`expr $INT + 1`
        done
        
        
        #進捗率を"100%"に更新
        curl --include http://RedmineURLをここに指定/issues/${TICKET_ID[$COUNT]}.xml -X PUT -d '<issue><done_ratio>100</done_ratio></issue>' -H "Content-Type: text/xml" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定"
        
        #削除した旨をチケットの履歴に追加
        curl --include http://RedmineURLをここに指定/issues/${TICKET_ID[$COUNT]}.xml -X PUT -d "<issue><notes>deleted the AMI.</notes></issue>" -H "Content-Type: text/xml" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定"
    fi
    
    COUNT=`expr $COUNT + 1`
done
```


## Redmine側
###チケット記述ルール（チケットテンプレートを活用）
題名：作成したいAMI名を入力
説明：
InstanceId:i-XXXXXXXX（作成したいAMIの元となるEC2インスタンスIDを入力）
Description:開発環境のAMIです。（AMIの情報を入力※入力内容は自由です）