考えなしでAWSを使っていると、とにかくわけのわからないIDがManagement Console上に並ぶことになる。少なくとも今使っているEC2インスタンスに紐付くEBSボリュームだけでもNameタグをつけることができないものかと考えたのでした。

AWS CLIのqueryオプション

AWS CLIにも抵抗は無くなってきたけど、まだまだ調べながらでないと使いこなせない。”–filters”で絞り込みができるけど、コマンドごとに使えるオプションを毎度確認しなければいけないの面倒だなと思っていたら、”–query”でもJMESPathとやらで実装されているかなり高機能な絞り込みができることがわかった。これだけできればjq使わなくても大丈夫そう。詳細はみんな大好きクラスメソッドさんのブログを。

Nameタグが空ではないEC2を取得

まずはNameタグを設定しているEC2のNameタグとアタッチされているEBSボリュームID一覧を取ってみる。この時点で既にかなりややこしい。”not_null”ではなく、”contains”を使えば部分一致で絞り込みもできる。

aws ec2 describe-instances ¥
--query 'Reservations[].Instances[?not_null(Tags[?Key==`Name`].Value)].[Tags[?Key==`Name`].Value,BlockDeviceMappings[].Ebs[].VolumeId]'

Nameタグが空のEBSボリュームを取得

結果的には使わなかったけど、空のものを抽出する場合はこんな感じで。Nameタグが設定されていないEBSボリュームIDを取ってみる。

aws ec2 describe-volumes ¥
--query 'Volumes[?Tags[?Key==`Name`].Value==`null`].VolumeId'

Nameタグが空のEBSボリュームにEC2のNameタグからNameタグをつけるスクリプト

結局シェルしか使えない自分はシェルで文字列操作。他の言語にもそろそろ手を出そう出そうと思い続けてもう何年になるだろう。最初に紹介した結果を”–output text”すると、NameタグとEBSボリュームID(スペース区切り)が交互に出力されることがわかった。配列っぽい処理を本当はもっと上手にできると思うのだけど、それでも何とかなって、どこでも使えるシェルから卒業できません。

#!/bin/bash
EC2NAME=
EBSIDS=
EBSNAME=
#Nameタグが空ではないEC2インスタンスのNameタグとEBSボリュームを取得しながらwhile文に流し込む
#NameタグとEBSボリュームが交互にlineに入る
aws ec2 describe-instances \
--query 'Reservations[].Instances[?not_null(Tags[?Key==`Name`].Value)].[Tags[?Key==`Name`].Value,BlockDeviceMappings[].Ebs[].VolumeId]' \
--output text \
| while read line
do
  #Nameタグを変数に
  if [ "$EC2NAME" = "" ]; then
    EC2NAME=$line
    EBSIDS=
    continue
  fi
  #EBSボリュームIDを変数に
  if [ "$EBSIDS" = "" ]; then
    EBSIDS=$line
    EBSNUM=1
    #スペース区切りのボリュームIDをfor文に流し込む
    for EBSID in $EBSIDS
    do
      #EBSボリュームのNameタグを取得
      EBSNAME=`aws ec2 describe-volumes \
      --query 'Volumes[].Tags[?Key==\`Name\`].Value' \
      --filters "Name=volume-id,Values=$EBSID" \
      --output text`
      #EBSボリュームにNameタグが無いものにだけEC2のNameタグを加工したタグを設定
      if [ "$EBSNAME" = "" ]; then
        EBSNAME=EBS-$EC2NAME-$EBSNUM
        echo "# aws ec2 create-tags --resources $EBSID --tags Key=Name,Value=$EBSNAME"
        aws ec2 create-tags --resources $EBSID --tags Key=Name,Value=$EBSNAME
        EBSNUM=$((EBSNUM+1))
      fi
    done
    EC2NAME=
  fi
done

EC2インスタンスにアタッチされたEBSボリュームが複数あったケースを考慮していない点はご愛嬌。あとはこれをcron的な何かに仕込んでおけば自動的にやってくれるはず。潜在的にこんな需要はけっこうあると思うのだけど。

相変わらず特殊文字の対処にも悪戦苦闘。EC2のNameタグを利用して、AMI作成時にAMI、Snapshotに自動でタグを付与するスクリプトも作りたい。

TOP