elbas 0.27.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +25 -35
- data/elbas.gemspec +15 -12
- data/lib/elbas.rb +15 -9
- data/lib/elbas/aws/ami.rb +71 -0
- data/lib/elbas/aws/autoscale_group.rb +43 -0
- data/lib/elbas/aws/base.rb +39 -0
- data/lib/elbas/aws/instance.rb +24 -0
- data/lib/elbas/aws/instance_collection.rb +36 -0
- data/lib/elbas/aws/launch_template.rb +32 -0
- data/lib/elbas/aws/snapshot.rb +21 -0
- data/lib/elbas/aws/taggable.rb +18 -0
- data/lib/elbas/capistrano.rb +14 -12
- data/lib/elbas/errors/no_launch_template.rb +6 -0
- data/lib/elbas/logger.rb +10 -2
- data/lib/elbas/retryable.rb +34 -9
- data/lib/elbas/tasks/elbas.rake +19 -10
- data/lib/elbas/version.rb +1 -1
- data/spec/aws/ami_spec.rb +140 -0
- data/spec/aws/autoscale_group_spec.rb +53 -0
- data/spec/aws/instance_collection_spec.rb +28 -0
- data/spec/aws/instance_spec.rb +30 -0
- data/spec/aws/launch_template_spec.rb +52 -0
- data/spec/aws/taggable_spec.rb +53 -0
- data/spec/spec_helper.rb +14 -24
- data/spec/support/stubs/CreateLaunchTemplateVersion.200.xml +16 -0
- data/spec/support/stubs/DescribeAutoScalingGroups.200.xml +60 -0
- data/spec/support/stubs/DescribeImages.200.xml +36 -1
- data/spec/support/stubs/DescribeInstances.200.xml +109 -2
- metadata +60 -21
- data/lib/elbas/ami.rb +0 -56
- data/lib/elbas/aws/autoscaling.rb +0 -21
- data/lib/elbas/aws/credentials.rb +0 -20
- data/lib/elbas/aws/ec2.rb +0 -13
- data/lib/elbas/aws_resource.rb +0 -36
- data/lib/elbas/launch_configuration.rb +0 -64
- data/lib/elbas/taggable.rb +0 -9
- data/spec/ami_spec.rb +0 -10
- data/spec/elbas_spec.rb +0 -69
data/lib/elbas/ami.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
module Elbas
|
2
|
-
class AMI < AWSResource
|
3
|
-
include Taggable
|
4
|
-
|
5
|
-
def self.create(&block)
|
6
|
-
ami = new
|
7
|
-
ami.cleanup do
|
8
|
-
ami.save
|
9
|
-
ami.tag 'Deployed-with' => 'ELBAS'
|
10
|
-
ami.tag 'ELBAS-Deploy-group' => ami.autoscale_group_name
|
11
|
-
yield ami
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def save
|
16
|
-
info "Creating EC2 AMI from EC2 Instance: #{base_ec2_instance.id}"
|
17
|
-
@aws_counterpart = ec2.images.create \
|
18
|
-
name: name,
|
19
|
-
instance_id: base_ec2_instance.id,
|
20
|
-
no_reboot: fetch(:aws_no_reboot_on_create_ami, true)
|
21
|
-
end
|
22
|
-
|
23
|
-
def destroy(images = [])
|
24
|
-
images.each do |i|
|
25
|
-
info "Deleting old AMI: #{i.id}"
|
26
|
-
snapshots = snapshots_attached_to i
|
27
|
-
i.delete
|
28
|
-
delete_snapshots snapshots
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
def name
|
34
|
-
timestamp "#{environment}-AMI"
|
35
|
-
end
|
36
|
-
|
37
|
-
def trash
|
38
|
-
ec2.images.with_owner('self').to_a.select do |ami|
|
39
|
-
deployed_with_elbas? ami
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def snapshots_attached_to(image)
|
44
|
-
image.block_device_mappings.map do |_, values|
|
45
|
-
ec2.snapshots[values[:snapshot_id]]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def delete_snapshots(snapshots)
|
50
|
-
snapshots.each do |snapshot|
|
51
|
-
info "Deleting snapshot: #{snapshot.id}"
|
52
|
-
snapshot.delete if snapshot.exists?
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module Elbas
|
2
|
-
module AWS
|
3
|
-
module AutoScaling
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
include Elbas::AWS::Credentials
|
6
|
-
include Capistrano::DSL
|
7
|
-
|
8
|
-
def autoscaling
|
9
|
-
@_autoscaling ||= ::AWS::AutoScaling.new(credentials)
|
10
|
-
end
|
11
|
-
|
12
|
-
def autoscale_group
|
13
|
-
@_autoscale_group ||= autoscaling.groups[autoscale_group_name]
|
14
|
-
end
|
15
|
-
|
16
|
-
def autoscale_group_name
|
17
|
-
fetch(:aws_autoscale_group)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Elbas
|
2
|
-
module AWS
|
3
|
-
module Credentials
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
include Capistrano::DSL
|
6
|
-
|
7
|
-
def credentials
|
8
|
-
@_credentials ||= begin
|
9
|
-
_credentials = {
|
10
|
-
access_key_id: fetch(:aws_access_key_id, ENV['AWS_ACCESS_KEY_ID']),
|
11
|
-
secret_access_key: fetch(:aws_secret_access_key, ENV['AWS_SECRET_ACCESS_KEY'])
|
12
|
-
}
|
13
|
-
|
14
|
-
_credentials.merge! region: fetch(:aws_region) if fetch(:aws_region)
|
15
|
-
_credentials
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/lib/elbas/aws/ec2.rb
DELETED
data/lib/elbas/aws_resource.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
module Elbas
|
2
|
-
class AWSResource
|
3
|
-
include Capistrano::DSL
|
4
|
-
include Elbas::AWS::AutoScaling
|
5
|
-
include Elbas::AWS::EC2
|
6
|
-
include Elbas::Retryable
|
7
|
-
include Logger
|
8
|
-
|
9
|
-
attr_reader :aws_counterpart
|
10
|
-
|
11
|
-
def cleanup(&block)
|
12
|
-
items = trash || []
|
13
|
-
yield
|
14
|
-
destroy items
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
def base_ec2_instance
|
20
|
-
@_base_ec2_instance ||= autoscale_group.ec2_instances.filter('instance-state-name', 'running').first
|
21
|
-
end
|
22
|
-
|
23
|
-
def environment
|
24
|
-
fetch(:rails_env, 'production')
|
25
|
-
end
|
26
|
-
|
27
|
-
def timestamp(str)
|
28
|
-
"#{str}-#{Time.now.to_i}"
|
29
|
-
end
|
30
|
-
|
31
|
-
def deployed_with_elbas?(resource)
|
32
|
-
resource.tags['Deployed-with'] == 'ELBAS' &&
|
33
|
-
resource.tags['ELBAS-Deploy-group'] == autoscale_group_name
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
module Elbas
|
2
|
-
class LaunchConfiguration < AWSResource
|
3
|
-
|
4
|
-
def self.create(ami, &block)
|
5
|
-
lc = new
|
6
|
-
lc.cleanup do
|
7
|
-
lc.save(ami)
|
8
|
-
yield lc
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def save(ami)
|
13
|
-
info "Creating an EC2 Launch Configuration for AMI: #{ami.aws_counterpart.id}"
|
14
|
-
with_retry do
|
15
|
-
@aws_counterpart = autoscaling.launch_configurations.create(name, ami.aws_counterpart.id, instance_size, create_options)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def attach_to_autoscale_group!
|
20
|
-
info 'Attaching Launch Configuration to AutoScale Group'
|
21
|
-
autoscale_group.update(launch_configuration: aws_counterpart)
|
22
|
-
end
|
23
|
-
|
24
|
-
def destroy(launch_configurations = [])
|
25
|
-
launch_configurations.each do |lc|
|
26
|
-
info "Deleting old launch configuration: #{lc.name}"
|
27
|
-
lc.delete
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
def name
|
33
|
-
timestamp "ELBAS-#{environment}-#{autoscale_group_name}-LC"
|
34
|
-
end
|
35
|
-
|
36
|
-
def instance_size
|
37
|
-
fetch(:aws_autoscale_instance_size, 'm1.small')
|
38
|
-
end
|
39
|
-
|
40
|
-
def create_options
|
41
|
-
options = {
|
42
|
-
security_groups: base_ec2_instance.security_groups.to_a,
|
43
|
-
detailed_instance_monitoring: fetch(:aws_launch_configuration_detailed_instance_monitoring, true),
|
44
|
-
associate_public_ip_address: fetch(:aws_launch_configuration_associate_public_ip, true)
|
45
|
-
}
|
46
|
-
|
47
|
-
if user_data = fetch(:aws_launch_configuration_user_data, nil)
|
48
|
-
options.merge user_data: user_data
|
49
|
-
end
|
50
|
-
|
51
|
-
options
|
52
|
-
end
|
53
|
-
|
54
|
-
def deployed_with_elbas?(lc)
|
55
|
-
lc.name.include? "ELBAS-#{environment}-#{autoscale_group_name}-LC"
|
56
|
-
end
|
57
|
-
|
58
|
-
def trash
|
59
|
-
autoscaling.launch_configurations.to_a.select do |lc|
|
60
|
-
deployed_with_elbas? lc
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
data/lib/elbas/taggable.rb
DELETED
data/spec/ami_spec.rb
DELETED
data/spec/elbas_spec.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
describe 'ELBAS' do
|
2
|
-
|
3
|
-
before do
|
4
|
-
allow_any_instance_of(Elbas::AWSResource).to receive(:autoscale_group_name) { 'production' }
|
5
|
-
webmock :get, /security-credentials/ => 'security-credentials.200.json'
|
6
|
-
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DescribeImages.200.xml') { Hash[body: /Action=DescribeImages/] }
|
7
|
-
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DescribeTags.200.xml') { Hash[body: /Action=DescribeTags/] }
|
8
|
-
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DescribeInstances.200.xml') { Hash[body: /Action=DescribeInstances/] }
|
9
|
-
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'CreateImage.200.xml') { Hash[body: /Action=CreateImage/] }
|
10
|
-
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DeregisterImage.200.xml') { Hash[body: /Action=DeregisterImage/] }
|
11
|
-
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'CreateTags.200.xml') { Hash[body: /Action=CreateTags/] }
|
12
|
-
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DescribeSnapshots.200.xml') { Hash[body: /Action=DescribeSnapshots/] }
|
13
|
-
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DeleteSnapshot.200.xml') { Hash[body: /Action=DeleteSnapshot/] }
|
14
|
-
webmock(:post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'DescribeLaunchConfigurations.200.xml') { Hash[body: /Action=DescribeLaunchConfigurations/] }
|
15
|
-
webmock(:post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'CreateLaunchConfiguration.200.xml') { Hash[body: /Action=CreateLaunchConfiguration/] }
|
16
|
-
webmock(:post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'DeleteLaunchConfiguration.200.xml') { Hash[body: /Action=DeleteLaunchConfiguration/] }
|
17
|
-
webmock(:post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'UpdateAutoScalingGroup.200.xml') { Hash[body: /Action=UpdateAutoScalingGroup/] }
|
18
|
-
end
|
19
|
-
|
20
|
-
let!(:ami) do
|
21
|
-
_ami = nil
|
22
|
-
Elbas::AMI.create { |ami| _ami = ami }
|
23
|
-
_ami
|
24
|
-
end
|
25
|
-
|
26
|
-
describe 'AMI creation & cleanup' do
|
27
|
-
it 'creates a new AMI on Amazon' do
|
28
|
-
expect(ami.aws_counterpart.id).to eq 'ami-4fa54026'
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'deletes any AMIs tagged with Deployed-with=ELBAS' do
|
32
|
-
expect(WebMock).to have_requested(:post, /ec2.(.*).amazonaws.com\/\z/).with(body: /Action=DeregisterImage&ImageId=ami-1a2b3c4d/)
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'deletes snapshots that are associated with the AMI' do
|
36
|
-
expect(WebMock).to have_requested(:post, /ec2.(.*).amazonaws.com\/\z/).with(body: /Action=DeleteSnapshot&SnapshotId=snap-1a2b3c4d/)
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'tags the new AMI with Deployed-with=ELBAS' do
|
40
|
-
expect(WebMock).to have_requested(:post, /ec2.(.*).amazonaws.com\/\z/).with(body: /Action=CreateTags&ResourceId.1=ami-4fa54026&Tag.1.Key=Deployed-with&Tag.1.Value=ELBAS/)
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'tags the new AMI with ELBAS-Deploy-group=<autoscale group name>' do
|
44
|
-
expect(WebMock).to have_requested(:post, /ec2.(.*).amazonaws.com\/\z/).with(body: /Action=CreateTags&ResourceId.1=ami-4fa54026&Tag.1.Key=ELBAS-Deploy-group&Tag.1.Value=production/)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe 'Launch configuration creation & cleanup' do
|
49
|
-
let!(:launch_configuration) do
|
50
|
-
_lc = nil
|
51
|
-
Elbas::LaunchConfiguration.create(ami) { |lc| _lc = lc }
|
52
|
-
_lc
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'creates a new Launch Configuration on AWS' do
|
56
|
-
expect(WebMock).to have_requested(:post, /autoscaling.(.*).amazonaws.com\/\z/).
|
57
|
-
with(body: /Action=CreateLaunchConfiguration&AssociatePublicIpAddress=true&ImageId=ami-4fa54026&InstanceMonitoring.Enabled=true&InstanceType=m1.small&LaunchConfigurationName=ELBAS-production/)
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'deletes any LCs with name =~ ELBAS-production' do
|
61
|
-
expect(WebMock).to have_requested(:post, /autoscaling.(.*).amazonaws.com\/\z/).with(body: /Action=DeleteLaunchConfiguration&LaunchConfigurationName=ELBAS-production-production-LC-1234567890/)
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'attaches the LC to the autoscale group' do
|
65
|
-
launch_configuration.attach_to_autoscale_group!
|
66
|
-
expect(WebMock).to have_requested(:post, /autoscaling.(.*).amazonaws.com\/\z/).with(body: /Action=UpdateAutoScalingGroup&AutoScalingGroupName=production&LaunchConfigurationName=ELBAS-production-production-LC-\d{10,}/)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|