aws-sdk ruby で EC2 instance snapshot の取得を自動化 #ec2

# aws-sdk ruby で EC2 instance :camera: snapshot の取得を自動化
## :musical_score: 概要
awd-sdk ruby で EC2 の Instance の :camera: スナップショット取得を自動化します。

## :hand: この記事を読む前に
手動で行った場合の記事が以下になります。（参照先は restore 込）
<i class="fa fa-external-link" style="font-size:1em;"></i> [EC2 instance snapshot and restore](http://qiita.com/tbpgr/items/2456a28506ec44d23a0a)

## :musical_note: 前提
* 環境変数の設定には dotenv を利用します。
    * <i class="fa fa-external-link" style="font-size:1em;"></i> [Ruby | dotenv gem で 環境変数をスマートに管理](http://qiita.com/tbpgr/items/b7126c3d2d8f0329b11c)
* AWS の キーの取得については下記を参照
    * <i class="fa fa-external-link" style="font-size:1em;"></i> [AWS-SDK Ruby で EC2 のインスタンス名からインスタンス id / ip address を取得する](http://qiita.com/tbpgr/items/580651b875ecdfdf0551)

## <i class="fa fa-gears" style="font-size:1em;"></i> 設定ファイル
### <i class="fa fa-gear" style="font-size:1em;"></i> Gemfile の設定
~~~
source "https://rubygems.org"

gem "dotenv"
gem "aws-sdk"
~~~

### <i class="fa fa-gear" style="font-size:1em;"></i> .env ファイルの設定
* AWS Management Console で必要な値を取得し、 .env ファイルに設定をする

~~~
ACCESS_KEY_ID = "your access key"
SECRET_ACCESS_KEY = "your secret access key"
EC2_ENDPOINT = "end point"
~~~

## <i class="fa fa-code" style="font-size:1em;"></i> 主処理

~~~ruby
require 'aws-sdk'
require 'dotenv'
require 'pry'

class SnapshotExecutor
  def initialize(search_word, snapshot_desc)
    Dotenv.load
    @ec2 = AWS::EC2.new(
      access_key_id:     ENV["ACCESS_KEY_ID"],
      secret_access_key: ENV["SECRET_ACCESS_KEY"],
      ec2_endpoint:      ENV["EC2_ENDPOINT"]
    )
    @search_word = search_word
    @snapshot_desc = "#{snapshot_desc} #{Time.now}"
  end

  def create_snapshot
    snapshot = volume(instance_id).create_snapshot(@snapshot_desc)
    wait_until_snapshot_complete(snapshot)
    show_complete_message(snapshot)
  end

  def volume(instance_id)
    @ec2.volumes.select { |e|e.attachments.to_a.size == 1}
                 .find { |e|e.attachments.first.instance.id == instance_id }
  end

  def instance_id
    instance.id
  end

  private

  def show_complete_message(snapshot)
    if snapshot.status == :error
      raise "Snapshot can't be created"
    else
      print "Snapshot was created '#{snapshot.id}'"
    end
  end

  def wait_until_snapshot_complete(snapshot)
    print 'Waiting snapshot complete'
    loop {
      break if [:completed, :error].include?(snapshot.status)
      sleep 1
      print "."
    }
    puts
  end

  def instance
    instances = @ec2.instances.select { |e|e.tags['Name'] =~ /#{@search_word}/ }
    validate_empty_instance(instances)
    validate_too_many_instance(instances)
    instances.first
  end

  def validate_empty_instance(instances)
    return unless instances.empty?
    STDERR.puts ("No instance. Confirm your instance search keyword '#{@search_word}'.")
    exit(false)
  end

  def validate_too_many_instance(instances)
    return if instances.size < 2
    STDERR.puts ("Too many instance. Confirm your instance search keyword '#{@search_word}'.")
    exit(false)
  end
end

# vagrant という名前を含むインスタンスが一つだけある前提です
se = SnapshotExecutor.new('vagrant', 'test_snapshot_vagrant')
se.create_snapshot
~~~

## <i class="fa fa-check-circle" style="font-size:1em;"></i> 結果確認

* 実行

~~~bash
$ ruby snapshot.rb
Please report a bug if this causes problems.
Waiting snapshot complete.................................................................................................................................................
Snapshot was created 'snap-91b7fa08'
~~~

* ブラウザで確認

![snap.png](https://qiita-image-store.s3.amazonaws.com/0/43480/9f21b9d5-9ec2-2473-b06f-3e4148628d95.png)

## :books: 外部資料
* <i class="fa fa-external-link" style="font-size:1em;"></i> [AWS SDK for Ruby | API Document](http://docs.aws.amazon.com/AWSRubySDK/latest/frames.html)