elbas 0.27.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|