Skip to content
This repository was archived by the owner on Feb 11, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/vagrant-aws/action/read_ssh_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def read_ssh_info(aws, machine)

# Read the DNS info
return {
:host => server.dns_name || server.private_ip_address,
:host => server.public_ip_address || server.dns_name || server.private_ip_address,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to make public_ip_address default over dns_name?
Or maybe we should just drop dns_name altogether?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No good reason. I just thought it made more sense to return an EIP if it was requested rather than a DNS name. We could potentially drop either one.

Also, private_ip_address will only work if the user has some direct connection to an instance in a VPC, such as over a VPN.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes private_ip_address was added precisely for that.

Otherwise the PR looks good, I'll be merging it soon. Thanks.

:port => 22
}
end
Expand Down
42 changes: 41 additions & 1 deletion lib/vagrant-aws/action/run_instance.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "log4r"
require 'json'

require 'vagrant/util/retryable'

Expand Down Expand Up @@ -34,14 +35,15 @@ def call(env)
subnet_id = region_config.subnet_id
tags = region_config.tags
user_data = region_config.user_data
elastic_ip = region_config.elastic_ip

# If there is no keypair then warn the user
if !keypair
env[:ui].warn(I18n.t("vagrant_aws.launch_no_keypair"))
end

# If there is a subnet ID then warn the user
if subnet_id
if subnet_id and !elastic_ip
env[:ui].warn(I18n.t("vagrant_aws.launch_vpc_warning"))
end

Expand All @@ -54,6 +56,7 @@ def call(env)
env[:ui].info(" -- Keypair: #{keypair}") if keypair
env[:ui].info(" -- Subnet ID: #{subnet_id}") if subnet_id
env[:ui].info(" -- Private IP: #{private_ip_address}") if private_ip_address
env[:ui].info(" -- Elastic IP: #{elastic_ip}") if elastic_ip
env[:ui].info(" -- User Data: yes") if user_data
env[:ui].info(" -- Security Groups: #{security_groups.inspect}") if !security_groups.empty?
env[:ui].info(" -- User Data: #{user_data}") if user_data
Expand Down Expand Up @@ -117,6 +120,12 @@ def call(env)

@logger.info("Time to instance ready: #{env[:metrics]["instance_ready_time"]}")

# Allocate and associate an elastic IP if requested
if elastic_ip
domain = subnet_id ? 'vpc' : 'standard'
do_elastic_ip(env, domain, server)
end

if !env[:interrupted]
env[:metrics]["instance_ssh_time"] = Util::Timer.time do
# Wait for SSH to be ready.
Expand Down Expand Up @@ -150,6 +159,37 @@ def recover(env)
end
end

def do_elastic_ip(env, domain, server)
allocation = env[:aws_compute].allocate_address(domain)
if allocation.body['publicIp'].nil?
@logger.debug("Could not allocate Elastic IP.")
return nil
end
@logger.debug("Public IP #{allocation.body['publicIp']}")

# Associate the address and save the metadata to a hash
if domain == 'vpc'
# VPC requires an allocation ID to assign an IP
association = env[:aws_compute].associate_address(server.id, nil, nil, allocation.body['allocationId'])
h = { :allocation_id => allocation.body['allocationId'], :association_id => association.body['associationId'], :public_ip => allocation.body['publicIp'] }
else
# Standard EC2 instances only need the allocated IP address
association = env[:aws_compute].associate_address(server.id, allocation.body['publicIp'])
h = { :public_ip => allocation.body['publicIp'] }
end

unless association.body['return']
@logger.debug("Could not associate Elastic IP.")
return nil
end

# Save this IP to the data dir so it can be released when the instance is destroyed
ip_file = env[:machine].data_dir.join('elastic_ip')
ip_file.open('w+') do |f|
f.write(h.to_json)
end
end

def terminate(env)
destroy_env = env.dup
destroy_env.delete(:interrupted)
Expand Down
21 changes: 21 additions & 0 deletions lib/vagrant-aws/action/terminate_instance.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "log4r"
require "json"

module VagrantPlugins
module AWS
Expand All @@ -17,9 +18,29 @@ def call(env)
env[:ui].info(I18n.t("vagrant_aws.terminating"))
server.destroy
env[:machine].id = nil

# Release the elastic IP
ip_file = env[:machine].data_dir.join('elastic_ip')
if ip_file.file?
release_address(env,ip_file.read)
ip_file.delete
end

@app.call(env)
end

# Release an elastic IP address
def release_address(env,eip)
h = JSON.parse(eip)
# Use association_id and allocation_id for VPC, use public IP for EC2
if h['association_id']
env[:aws_compute].disassociate_address(nil,h['association_id'])
env[:aws_compute].release_address(h['allocation_id'])
else
env[:aws_compute].disassociate_address(h['public_ip'])
env[:aws_compute].release_address(h['public_ip'])
end
end
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions lib/vagrant-aws/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ class Config < Vagrant.plugin("2", :config)
# @return [String]
attr_accessor :private_ip_address

# Acquire and attach an elastic IP address (VPC).
#
# @return [Boolean]
attr_accessor :elastic_ip

# The name of the AWS region in which to create the instance.
#
# @return [String]
Expand Down Expand Up @@ -103,6 +108,7 @@ def initialize(region_specific=false)
@tags = {}
@user_data = UNSET_VALUE
@use_iam_profile = UNSET_VALUE
@elastic_ip = UNSET_VALUE

# Internal state (prefix with __ so they aren't automatically
# merged)
Expand Down Expand Up @@ -193,6 +199,9 @@ def finalize!
# Default the private IP to nil since VPC is not default
@private_ip_address = nil if @private_ip_address == UNSET_VALUE

# Acquire an elastic IP if requested
@elastic_ip = nil if @elastic_ip == UNSET_VALUE

# Default region is us-east-1. This is sensible because AWS
# generally defaults to this as well.
@region = "us-east-1" if @region == UNSET_VALUE
Expand Down