AWS構築環境のテストをawspecを使って実行してみた

記事タイトルとURLをコピーする

こんにちは、技術3課の森です。
とうとう9月になりましたね。秋ですね。秋といえば、「食」です。秋刀魚が早く食べたい時期になってきました。
とはいえ、食べ過ぎと飲み過ぎは体を悪くしますので、健康診断でしっかりみてもらうといいかもしれません。
健康診断といえば、テスト。今回はテストについてのブログです。


はじめに

今回は、AWS環境を構築した後に、テストをしようと思い、色々探していたところ、出会ったのが、awspecです。
サーバーワークスでは、永田さんを中心にAWS環境の構築を自動化してしまおうという取り組みをされています。詳しくはこちらを。

ここで作成される定義書(YAML)を使って、awspecのインプットにしております。

作業環境構築

awspecのインストール

awspecのインストールを行います。コマンド一行でOKです。

$ gem install awspec

awspecの環境構築

次に、awspecを使って実行できる環境作りを行います。

awspecの初期化

実行に必要なファイルなどを用意するためのコマンドを実行します。

$ awspec init

これを実行すると以下のような状態となります。

$ tree
.
├── Rakefile
└── spec
    └── spec_helper.rb

クレデンシャル情報の追加

awspecを実行する環境がテストする環境であれば、IAM Roleを付与することでOKですが、異なる場合はクレデンシャル情報を用意する必要がございます。
今回は、お試しということで、「ReadOnlyAccess」ポリシーを適用したIAM Userを作成し、アクセスキーとシークレットアクセスキーを用意しています。
spec/secrets.ymlを作成し、以下の情報を入れてください。(「X」になっているところはそれぞれ、アクセスキーとシークレットアクセスキーを入力してください

region: ap-northeast-1
aws_access_key_id: XXXXXXXXXXXXXXXXXXXX
aws_secret_access_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

実装

ここから実装に入ります。

準備

今回は、YAMLを読み込んでテストを実行するようにしますので、いくつか準備として、コードを追加する必要がございます。

Rakefile

まずは、Rakefileに以下の情報を追加します。

require 'yaml'

spec/spec_helper.rb

次に、spec_helper.rbに以下の情報を追加します。

@properties = YAML.load_file("aws_environment.yml")

コード作成

ここでコードの作成に移ります。環境構築自動化のYAMLファイルの例をまずは記載します。(ある程度抜粋します)

Resources:
    EC2Instances:
      - name: TEST_EC2
        ebs_optimized: false
        source_dest_check: true
        key_name: test_ec2_key
        instance_type: m4.large
        image_id: ami-bbf2f9dc
        tags:
          - Name: TEST_EC2
          - AUTO_START: ON
        block_device_mappings:
          - volume_type: gp2
            volume_size: 1000
            encrypted: false
            tags:
              - Name: EBS_TEST_EC2_01
              - DiskName: root
        network_interfaces:
          - subnet: subnet-TEST-AZ-1
            security_groups:
              - TESTSG-AP-in-01
              - TESTSG-AP-ext-01
            private_ip_addresses:
              - 10.0.1.11
              - 10.1.1.11
            tags:
              - Name: NI_TEST_EC2
              - ENI: EXT

次は、コードです。

require 'spec_helper'

properties = @properties

print properties['Resources']['EC2Instances']
properties['Resources']['EC2Instances'].each do |ec2|
    describe ec2(ec2['name']) do
        it { should exist }
        its(:ebs_optimized) { should eq ec2['ebs_optimized'] }
        its(:source_dest_check) { should eq ec2['source_dest_check'] }
        its(:key_name) { should eq ec2['key_name'] }
        its(:instance_type) { should eq ec2['instance_type'] }
        its(:image_id) { should eq ec2['image_id'] }
        it { should have_tag('Name').value(ec2['tags'][0]['Name']) }
        it { should have_tag('AUTO_START').value(ec2['tags'][1]['AUTO_START']) }
        ##EBS##
        ec2['block_device_mappings'].each do |ebs|
            describe ebs(ebs['tags'][0]['Name']) do
                it { should exist }
                it { should be_attached_to(ec2['name']) }
                its(:volume_type) { should eq ebs['volume_type'] }
                its(:size) { should eq ebs['volume_size'] }
                its(:encrypted) { should eq ebs['encrypted'] }
                it { should have_tag('Name').value(ebs['tags'][0]['Name']) }
                it { should have_tag('DiskName').value(ebs['tags'][1]['DiskName']) }
            end
        end
        ##EBS##
        ##NetworkInterface##
        ec2['network_interfaces'].each do |eni|
            describe network_interface(eni['tags'][0]['Name']) do
                it { should exist }
                it { belong_to_subnet(eni['subnet']) }
                eni['security_groups'].each do |sg|
                    it { should have_security_group(sg) }
                end
                eni['private_ip_addresses'].each do |pip|
                    it { should have_private_ip_address(pip) }
                end
                it { should have_tag('Name').value(eni['tags'][0]['Name']) }
                it { should have_tag('ENI').value(eni['tags'][1]['ENI']) }
            end
        end
        ##NetworkInterface##
    end
end

これで、実行準備は完了です。

テスト実行

これでテストを実行します。実行結果も以下のような感じで出力されます。

$ rake spec
/Users/awspecuser/.rbenv/versions/2.3.4/bin/ruby -I/Users/awspecuser/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/gems/rspec-support-3.6.0/lib:/Users/awspecuser/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/gems/rspec-core-3.6.0/lib /Users/awspecuser/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/gems/rspec-core-3.6.0/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb
..................................................................

Finished in 2.66 seconds (files took 1.25 seconds to load)
66 examples, 0 failures

最後に

これで、テストが簡単にできるようになります。
ベースとなるコード(今回で言う「ec2_spec.rb」)を作るのに多少時間はかかるものの、ある程度汎用的には作っているので、YAMLの中身を変えれば、試験はどこでも可能になります。
(クレデンシャル情報には注意が必要)
とは言え、awspecはリソースの全てのパラメータを見れるわけではないので、目視確認は必要になります。
でも、かなりいいモノですので、是非ご活用いただければなと考えております