diff --git a/lib/elbas/aws/autoscale_group.rb b/lib/elbas/aws/autoscale_group.rb index 22fe965..d0ab64a 100644 --- a/lib/elbas/aws/autoscale_group.rb +++ b/lib/elbas/aws/autoscale_group.rb @@ -1,10 +1,11 @@ module Elbas module AWS class AutoscaleGroup < Base - attr_reader :name + attr_reader :name, :hostname_method - def initialize(name) + def initialize(name, hostname_method) @name = name + @hostname_method = find_hostname_method(hostname_method) @aws_counterpart = query_autoscale_group_by_name(name) end @@ -13,7 +14,7 @@ def instance_ids end def instances - InstanceCollection.new instance_ids + InstanceCollection.new instance_ids, hostname_method end def launch_template @@ -47,6 +48,16 @@ def aws_launch_template_specification aws_counterpart.mixed_instances_policy&.launch_template &.launch_template_specification end + + def find_hostname_method(method) + methods = [ + :public_dns_name, + :public_ip_address, + :private_dns_name, + :private_ip_address + ] + methods.include?(method) ? method : methods[0] + end end end end diff --git a/lib/elbas/aws/instance.rb b/lib/elbas/aws/instance.rb index 0530215..7a5911f 100644 --- a/lib/elbas/aws/instance.rb +++ b/lib/elbas/aws/instance.rb @@ -3,19 +3,15 @@ module AWS class Instance < Base STATE_RUNNING = 16.freeze - attr_reader :aws_counterpart, :id, :state + attr_reader :aws_counterpart, :id, :state, :hostname - def initialize(id, public_dns, state) + def initialize(id, hostname, state) @id = id - @public_dns = public_dns + @hostname = hostname @state = state @aws_counterpart = aws_namespace::Instance.new id, client: aws_client end - def hostname - @public_dns - end - def running? state == STATE_RUNNING end diff --git a/lib/elbas/aws/instance_collection.rb b/lib/elbas/aws/instance_collection.rb index c0ac6cf..7b02bac 100644 --- a/lib/elbas/aws/instance_collection.rb +++ b/lib/elbas/aws/instance_collection.rb @@ -5,10 +5,10 @@ class InstanceCollection < Base attr_reader :instances - def initialize(ids) + def initialize(ids, hostname_method) @ids = ids @instances = query_instances_by_ids(ids).map do |i| - Instance.new(i.instance_id, i.public_dns_name, i.state.code) + Instance.new(i.instance_id, i.send(hostname_method), i.state.code) end end diff --git a/lib/elbas/aws/launch_template.rb b/lib/elbas/aws/launch_template.rb index c23a45a..2569153 100644 --- a/lib/elbas/aws/launch_template.rb +++ b/lib/elbas/aws/launch_template.rb @@ -16,6 +16,12 @@ def update(ami) source_version: self.version }).launch_template_version + aws_client.modify_launch_template({ + dry_run: false, + launch_template_id: latest&.launch_template_id, + default_version: latest&.version_number.to_s + }) + self.class.new( latest&.launch_template_id, latest&.launch_template_name, diff --git a/lib/elbas/capistrano.rb b/lib/elbas/capistrano.rb index f7502b7..ef59fce 100644 --- a/lib/elbas/capistrano.rb +++ b/lib/elbas/capistrano.rb @@ -8,7 +8,12 @@ def autoscale(groupname, properties = {}) set :aws_autoscale_group_name, groupname - asg = Elbas::AWS::AutoscaleGroup.new groupname + skip_ami = properties.delete(:skip_ami) + hostname_method = properties.delete(:hostname_method) + + set :hostname_method, hostname_method + + asg = Elbas::AWS::AutoscaleGroup.new groupname, hostname_method instances = asg.instances.running instances.each.with_index do |instance, i| @@ -22,7 +27,9 @@ def autoscale(groupname, properties = {}) end if instances.any? - after 'deploy', 'elbas:deploy' + unless skip_ami + after 'deploy', 'elbas:deploy' + end else error <<~MESSAGE Could not create AMI because no running instances were found in the specified diff --git a/lib/elbas/tasks/elbas.rake b/lib/elbas/tasks/elbas.rake index e3d2490..8106a8b 100644 --- a/lib/elbas/tasks/elbas.rake +++ b/lib/elbas/tasks/elbas.rake @@ -12,7 +12,7 @@ namespace :elbas do end task :deploy do - asg = Elbas::AWS::AutoscaleGroup.new fetch(:aws_autoscale_group_name) + asg = Elbas::AWS::AutoscaleGroup.new fetch(:aws_autoscale_group_name), fetch(:hostname_method) info "Creating AMI from a running instance..." ami = Elbas::AWS::AMI.create asg.instances.running.sample diff --git a/spec/aws/autoscale_group_spec.rb b/spec/aws/autoscale_group_spec.rb index e187d97..169395f 100644 --- a/spec/aws/autoscale_group_spec.rb +++ b/spec/aws/autoscale_group_spec.rb @@ -1,5 +1,5 @@ describe Elbas::AWS::AutoscaleGroup do - subject { Elbas::AWS::AutoscaleGroup.new 'test-asg' } + subject { Elbas::AWS::AutoscaleGroup.new 'test-asg', nil } before do webmock :post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'DescribeAutoScalingGroups.200.xml', @@ -64,4 +64,23 @@ end end + + describe ' assigning hostname_method' do + it 'should default to public dns' do + group = Elbas::AWS::AutoscaleGroup.new 'test-asg', nil + expect(group.hostname_method).to eq :public_dns_name + end + + it 'should assign acceptable alternatives' do + [:public_ip_address, :private_dns_name, :private_ip_address]. each do |method| + group = Elbas::AWS::AutoscaleGroup.new 'test-asg', method + expect(group.hostname_method).to eq method + end + end + + it 'should fall back to public dns with bad method name' do + group = Elbas::AWS::AutoscaleGroup.new 'test-asg', :hostname + expect(group.hostname_method).to eq :public_dns_name + end + end end diff --git a/spec/aws/instance_collection_spec.rb b/spec/aws/instance_collection_spec.rb index 7b9f459..1bd27fc 100644 --- a/spec/aws/instance_collection_spec.rb +++ b/spec/aws/instance_collection_spec.rb @@ -1,6 +1,4 @@ describe Elbas::AWS::InstanceCollection do - subject { Elbas::AWS::InstanceCollection.new ['i-1234567890', 'i-500'] } - scenarios = [ { context: 'Single AWS reservation', mock_response_file: 'DescribeInstances.200.xml' }, { context: 'Multiple AWS reservation', mock_response_file: 'DescribeInstances_MultipleReservations.200.xml' } @@ -8,6 +6,7 @@ scenarios.each do |scenario| context scenario[:context] do + subject { Elbas::AWS::InstanceCollection.new ['i-1234567890', 'i-500'], :public_dns_name } before do webmock :post, %r{ec2.(.*).amazonaws.com\/\z} => scenario[:mock_response_file], with: Hash[body: /Action=DescribeInstances/] @@ -35,4 +34,24 @@ end end + context 'Multiple AWS running, no public dns' do + subject { Elbas::AWS::InstanceCollection.new ['i-1234567890', 'i-500'], :private_ip_address } + before do + webmock :post, %r{ec2.(.*).amazonaws.com\/\z} => 'DescribeInstances.200.xml', + with: Hash[body: /Action=DescribeInstances/] + end + + describe '#instances' do + it 'returns Instance objects with name/hostname/state' do + expect(subject.instances[0].id).to eq 'i-1234567890' + expect(subject.instances[0].hostname).to eq '10.0.0.12' + expect(subject.instances[0].state).to eq 16 + + expect(subject.instances[1].id).to eq 'i-500' + expect(subject.instances[1].hostname).to eq '10.0.0.12' + expect(subject.instances[1].state).to eq 32 + end + end + end + end diff --git a/spec/aws/instance_spec.rb b/spec/aws/instance_spec.rb index def2643..593207b 100644 --- a/spec/aws/instance_spec.rb +++ b/spec/aws/instance_spec.rb @@ -1,29 +1,31 @@ describe Elbas::AWS::Instance do - subject { Elbas::AWS::Instance.new 'i-1234567890', 'ec2-1234567890.amazonaws.com', 16 } + context 'with Public DNS' do + subject { Elbas::AWS::Instance.new 'i-1234567890', 'ec2-1234567890.amazonaws.com', 16 } - describe '#initialize' do - it 'sets the AWS counterpart' do - expect(subject.aws_counterpart).to be_a_kind_of ::Aws::EC2::Instance - expect(subject.aws_counterpart.id).to eq 'i-1234567890' + describe '#initialize' do + it 'sets the AWS counterpart' do + expect(subject.aws_counterpart).to be_a_kind_of ::Aws::EC2::Instance + expect(subject.aws_counterpart.id).to eq 'i-1234567890' + end end - end - describe '#hostname' do - it 'returns the public DNS' do - expect(subject.hostname).to eq 'ec2-1234567890.amazonaws.com' + describe '#hostname' do + it 'returns the public DNS' do + expect(subject.hostname).to eq 'ec2-1234567890.amazonaws.com' + end end - end - describe '#running?' do - it 'returns true if the state code is 16 ("running")' do - expect(subject).to receive(:state) { 16 } - expect(subject).to be_running - end + describe '#running?' do + it 'returns true if the state code is 16 ("running")' do + expect(subject).to receive(:state) { 16 } + expect(subject).to be_running + end - it 'returns false for every other state code' do - [0, 32, 48, 64, 80].each do |code| - expect(subject).to receive(:state) { code } - expect(subject).to_not be_running + it 'returns false for every other state code' do + [0, 32, 48, 64, 80].each do |code| + expect(subject).to receive(:state) { code } + expect(subject).to_not be_running + end end end end diff --git a/spec/capistrano_spec.rb b/spec/capistrano_spec.rb index 542e366..2795cc3 100644 --- a/spec/capistrano_spec.rb +++ b/spec/capistrano_spec.rb @@ -21,6 +21,11 @@ expect(env.servers.first.hostname).to eq 'ec2-1234567890.amazonaws.com' end + it 'uses the hostname_method' do + autoscale 'test-asg', hostname_method: :private_ip_address + expect(env.servers.first.hostname).to eq '10.0.0.12' + end + it 'passes along the properties' do autoscale 'test-asg', roles: [:db], primary: true expect(env.servers.first.properties.roles).to match_array [:db]