cloudpack大阪の佐々木です。
またもCircleCIです。
今度はCloudFormationをテストをCircleCIでやってみます。
テストはawspecを使います。
設定
ソースコードはこちらに。
https://github.com/taishin/cfn-ci
CloudFormation
template.cform
VPC上にEC2を1台たてているだけです。
CloudFormationで作成されたリソース(セキュリティグループ等)は、名前にランダムな文字列が付与されていたり、テストコードに代入しにくいので、Tagで名前を設定しています。
awspecテストコード
- EC2
EC2はImageID、InstanceType、パブリックIPアドレスをもっていること、
適用されているセキュリティグループ、VPC等の確認をしています。
####で囲まれている部分はCircleCIの変数になるので、circle.ymlで書き換えるようにしています。(後述)
require 'spec_helper'
describe ec2('####INSTANCEID####') do
it { should exist }
it { should be_running }
its(:image_id) { should eq '####IMAGEID####' }
its(:instance_type) { should eq '####INSTANCETYPE####' }
its(:public_ip_address) { should match "^\\d{1,3}\.\\d{1,3}\.\\d{1,3}\.\\d{1,3}$" }
its(:key_name) { should eq '####KEYNAME####' }
it { should have_security_group('CFn-CI-SG-HTTP') }
it { should have_security_group('CFn-CI-SG-Base') }
it { should belong_to_vpc('CFn-CI-VPC') }
it { should belong_to_subnet('CFn-CI-Subnet1A') }
end
- VPC
VPCはCIDRのIPアドレス、ルーティングテーブルの確認をしています。
require 'spec_helper'
describe vpc('CFn-CI-VPC') do
it { should exist }
it { should be_available }
its(:cidr_block) { should eq '10.0.0.0/16' }
it { should have_route_table('CFn-CI-PubRT') }
end
describe subnet('CFn-CI-Subnet1A') do
it { should exist }
it { should be_available }
it { should belong_to_vpc('CFn-CI-VPC') }
its(:cidr_block) { should eq '10.0.1.0/24' }
end
describe subnet('CFn-CI-Subnet1C') do
it { should exist }
it { should be_available }
it { should belong_to_vpc('CFn-CI-VPC') }
its(:cidr_block) { should eq '10.0.2.0/24' }
end
describe route_table('CFn-CI-PubRT') do
it { should exist }
it { should belong_to_vpc('CFn-CI-VPC') }
it { should have_route('10.0.0.0/16').target(gateway: 'local') }
it { should have_route('0.0.0.0/0').target(gateway: 'CFn-CI-IGW') }
it { should have_subnet('CFn-CI-Subnet1C') }
it { should have_subnet('CFn-CI-Subnet1A') }
end
- SecurityGroup
セキュリティグループはルールの確認です。
require 'spec_helper'
describe security_group('CFn-CI-SG-Base') do
it { should exist }
its(:inbound) { should be_opened(22).protocol('tcp').for('0.0.0.0/0') }
its(:outbound) { should be_opened }
its(:inbound_rule_count) { should eq 1 }
its(:outbound_rule_count) { should eq 1 }
its(:inbound_permissions_count) { should eq 1 }
its(:outbound_permissions_count) { should eq 1 }
it { should belong_to_vpc('CFn-CI-VPC') }
end
describe security_group('CFn-CI-SG-HTTP') do
it { should exist }
its(:inbound) { should be_opened(80).protocol('tcp').for('0.0.0.0/0') }
its(:outbound) { should be_opened }
its(:inbound_rule_count) { should eq 1 }
its(:outbound_rule_count) { should eq 1 }
its(:inbound_permissions_count) { should eq 1 }
its(:outbound_permissions_count) { should eq 1 }
it { should belong_to_vpc('CFn-CI-VPC') }
end
circle.yml
circle.ymlではCloudFormationを実行し、EC2のInstanceIDを取得します。
SSH Key、インスタンスタイプ、AMI IDは変数で変更できるようにしているので、CloudFormation起動後、ec2_spec.rb-templateをsedで変更し、ec2_spec.rbを生成しています。
machine:
timezone: Asia/Tokyo
ruby:
version:
2.1.2
environment:
AWS_AMI_ID: ami-6154bb00
AWS_INSTANCE_TYPE: t2.micro
AWS_CF_STACK_NAME: cfn-ci
dependencies:
pre:
test:
pre:
- aws cloudformation create-stack --stack-name ${AWS_CF_STACK_NAME} --template-body file://template.cform --parameters ParameterKey=KeyName,ParameterValue=$AWS_KEY_NAME ParameterKey=ImageId,ParameterValue=$AWS_AMI_ID ParameterKey=InstanceType,ParameterValue=$AWS_INSTANCE_TYPE
- aws cloudformation wait stack-create-complete --stack-name ${AWS_CF_STACK_NAME}
- aws cloudformation describe-stacks --stack-name ${AWS_CF_STACK_NAME} | jq -r '.Stacks[].Outputs[] | select(.OutputKey == "InstanceId") | .OutputValue' > /tmp/instanceid.txt
- sed -e "s/####INSTANCEID####/`cat /tmp/instanceid.txt`/g" -e "s/####KEYNAME####/$AWS_KEY_NAME/g" -e "s/####IMAGEID####/$AWS_AMI_ID/g" -e "s/####INSTANCETYPE####/$AWS_INSTANCE_TYPE/g" spec/ec2_spec.rb-template > spec/ec2_spec.rb
override:
- bundle exec rake spec
post:
- aws cloudformation delete-stack --stack-name ${AWS_CF_STACK_NAME}
CircleCI
CircleCIの画面上の設定は、
http://qiita.com/taishin/items/89b42106582a2aa5495b
と同じく、
- AWS Permissions
- AccessKey
- SecrectAccesskey
- Environment Variables
- AWS_DEFAULT_REGION
- AWS_KEY_NAME
を設定します。
実行
Buildさせるとこんな感じでテストして、終わればCloudFormationを削除してくれます。