• AWS SDK for Rubyを使ってEC2インスタンスのステータスを確認する

    アプリケーション側で、任意のAWSのEC2インスタンスについて、現在の稼働状況をリアルタイムに確認したい時がある。例えば外部アプリケーションからEC2インスタンスを起動させたり、停止させたりする場合などに、インスタンスの稼動状況を確認してステータスが変わったら次のプロセスを実行したいとかいうケースが、それに当てはまる。

    SDK for Rubyでは、AWS::EC2クラスのclient.describe_instance_statusメソッドで特定のECインスタンスのステータスを取得することができる。インスタンスのステータスにはsystem_statusinstance_statusの2種類があって、正確な稼動状態を確認したい場合はこの2つのステータスを取得する必要がある。 そして、注意しないといけないのが、インスタンスが停止している時はステータスが存在していないということだ。つまり、停止しているインスタンスに対してclient.describe_instance_statusメソッドを実行した場合、ステータス情報が格納されているinstance_status_setオブジェクトの中身が取得できないので、それを踏まえてコーディングしないと、ステータス取得エラーとなってしまう。 例えば、停止状態のインスタンスを起動した場合のステータスを監視する時など、最初はインスタンスが停止しているので、instance_status_setオブジェクト内にステータスがないということをあらかじめ想定して処理を作る必要がある。 また、ターミネートされたインスタンスはclient.describe_instance_statusメソッドを実行する対象自体がないことので、こちらも注意する必要がある。

    さて、上記もろもろを踏まえてEC2インスタンスのステータス確認するRubyプログラムを作ってみた。

    chkins.rb
    # encoding: utf-8
    require "aws-sdk"
    
    def check_instance_status
    
        ec2 = AWS::EC2.new(
          :access_key_id => Params[:access_key_id], 
          :secret_access_key => Params[:secret_access_key], 
          :region => Params[:region]
        )
    
        AWS.memoize do
          status = []
          if ec2.instances[Params[:instance_id]].exists?
            ec2info = ec2.client.describe_instance_status({ 'instance_ids' => [Params[:instance_id]] })
            if ec2info.instance_status_set.empty?
              # instance has stopped
              status << 'stopped'
              message = '%s has stopped'
            else
              ec2info.instance_status_set.map { |i| 
                sys_status = i.respond_to?(:system_status) ? i.system_status.details[0].status : nil
                ins_status = i.respond_to?(:instance_status) ? i.instance_status.details[0].status : nil
                status << sys_status << ins_status
              }
              if status.include?('passed')
                # instance is running
                message = '%s is running'
    
              elsif status.include?('initializing')
                # instance is initializing
                message = '%s is starting'
    
              else
                # otherwise
                message = '%s is unknown status'
    
              end
            end
          else
            # instance has terminated
            status << 'terminated'
            message = '%s has already terminated'
          end
          puts sprintf("#{message}. status: %s", "Instance: #{Params[:instance_id]}", status)
        end
    end
    
    begin
      # init
      Params = { 
        :access_key_id => ARGV[0], 
        :secret_access_key => ARGV[1], 
        :region => ARGV[2], 
        :instance_id => ARGV[3], 
        :timeout => ARGV[4].nil? ? 1 : ARGV[4].to_i
      }
      raise 'Parameter is missing.' if Params.values.include?(nil)
    
      for i in 1..Params[:timeout] do
        sleep 1 if i > 1
        check_instance_status
      end
    
    rescue => e
      puts e
    end
    

    プログラム実行時の引数として、

    ...