lib/chef/knife/ec2_server_create.rb in knife-ec2-0.6.2 vs lib/chef/knife/ec2_server_create.rb in knife-ec2-0.6.4
- old
+ new
@@ -60,10 +60,14 @@
:short => "-g X,Y,Z",
:long => "--security-group-ids X,Y,Z",
:description => "The security group ids for this server; required when using VPC",
:proc => Proc.new { |security_group_ids| security_group_ids.split(',') }
+ option :associate_eip,
+ :long => "--associate-eip IP_ADDRESS",
+ :description => "Associate existing elastic IP address with instance after launch"
+
option :tags,
:short => "-T T=V[,T=V,...]",
:long => "--tags Tag=Value[,Tag=Value...]",
:description => "The tags for this server",
:proc => Proc.new { |tags| tags.split(',') }
@@ -108,11 +112,10 @@
:short => "-w GATEWAY",
:long => "--ssh-gateway GATEWAY",
:description => "The ssh gateway server",
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
-
option :identity_file,
:short => "-i IDENTITY_FILE",
:long => "--identity-file IDENTITY_FILE",
:description => "The SSH identity file used for authentication"
@@ -165,10 +168,15 @@
:short => "-s SUBNET-ID",
:long => "--subnet SUBNET-ID",
:description => "create node in this Virtual Private Cloud Subnet ID (implies VPC mode)",
:proc => Proc.new { |key| Chef::Config[:knife][:subnet_id] = key }
+ option :private_ip_address,
+ :long => "--private-ip-address IP-ADDRESS",
+ :description => "allows to specify the private IP address of the instance in VPC mode",
+ :proc => Proc.new { |ip| Chef::Config[:knife][:private_ip_address] = ip }
+
option :host_key_verify,
:long => "--[no-]host-key-verify",
:description => "Verify host key, enabled by default.",
:boolean => true,
:default => true
@@ -223,24 +231,25 @@
def run
$stdout.sync = true
validate!
+ requested_elastic_ip = config[:associate_eip] if config[:associate_eip]
+
+ # For VPC EIP assignment we need the allocation ID so fetch full EIP details
+ elastic_ip = connection.addresses.detect{|addr| addr if addr.public_ip == requested_elastic_ip}
+
@server = connection.servers.create(create_server_def)
hashed_tags={}
tags.map{ |t| key,val=t.split('='); hashed_tags[key]=val} unless tags.nil?
# Always set the Name tag
unless hashed_tags.keys.include? "Name"
hashed_tags["Name"] = locate_config_value(:chef_node_name) || @server.id
end
- hashed_tags.each_pair do |key,val|
- connection.tags.create :key => key, :value => val, :resource_id => @server.id
- end
-
msg_pair("Instance ID", @server.id)
msg_pair("Flavor", @server.flavor_id)
msg_pair("Image", @server.image_id)
msg_pair("Region", connection.instance_variable_get(:@region))
msg_pair("Availability Zone", @server.availability_zone)
@@ -258,19 +267,34 @@
msg_pair("Security Group Ids", printed_security_group_ids) if vpc_mode? or @server.security_group_ids
msg_pair("Tags", hashed_tags)
msg_pair("SSH Key", @server.key_name)
- print "\n#{ui.color("Waiting for server", :magenta)}"
+ print "\n#{ui.color("Waiting for instance", :magenta)}"
- # wait for it to be ready to do stuff
+ # wait for instance to come up before acting against it
@server.wait_for { print "."; ready? }
puts("\n")
+ # occasionally 'ready?' isn't, so retry a couple times if needed.
+ tries = 6
+ begin
+ create_tags(hashed_tags) unless hashed_tags.empty?
+ associate_eip(elastic_ip) if config[:associate_eip]
+ rescue Fog::Compute::AWS::NotFound => e
+ raise if (tries -= 1) <= 0
+ ui.warn("server not ready, retrying tag application (retries left: #{tries})")
+ sleep 5
+ retry
+ end
+
if vpc_mode?
msg_pair("Subnet ID", @server.subnet_id)
+ if elastic_ip
+ msg_pair("Public IP Address", @server.public_ip_address)
+ end
else
msg_pair("Public DNS Name", @server.dns_name)
msg_pair("Public IP Address", @server.public_ip_address)
msg_pair("Private DNS Name", @server.private_dns_name)
end
@@ -371,11 +395,23 @@
if vpc_mode? and !!config[:security_groups]
ui.error("You are using a VPC, security groups specified with '-G' are not allowed, specify one or more security group ids with '-g' instead.")
exit 1
end
+ if !vpc_mode? and !!config[:private_ip_address]
+ ui.error("You can only specify a private IP address if you are using VPC.")
+ exit 1
+ end
+ if config[:associate_eip]
+ eips = connection.addresses.collect{|addr| addr if addr.domain == eip_scope}.compact
+
+ unless eips.detect{|addr| addr.public_ip == config[:associate_eip] && addr.server_id == nil}
+ ui.error("Elastic IP requested is not available.")
+ exit 1
+ end
+ end
end
def tags
tags = locate_config_value(:tags)
if !tags.nil? and tags.length != tags.to_s.count('=')
@@ -383,20 +419,29 @@
exit 1
end
tags
end
+ def eip_scope
+ if vpc_mode?
+ "vpc"
+ else
+ "standard"
+ end
+ end
+
def create_server_def
server_def = {
:image_id => locate_config_value(:image),
:groups => config[:security_groups],
:security_group_ids => locate_config_value(:security_group_ids),
:flavor_id => locate_config_value(:flavor),
:key_name => Chef::Config[:knife][:aws_ssh_key_id],
:availability_zone => locate_config_value(:availability_zone)
}
server_def[:subnet_id] = locate_config_value(:subnet_id) if vpc_mode?
+ server_def[:private_ip_address] = locate_config_value(:private_ip_address) if vpc_mode?
if Chef::Config[:knife][:aws_user_data]
begin
server_def.merge!(:user_data => File.read(Chef::Config[:knife][:aws_user_data]))
rescue
@@ -483,9 +528,20 @@
@ssh_connect_host ||= if config[:server_connect_attribute]
server.send(config[:server_connect_attribute])
else
vpc_mode? ? server.private_ip_address : server.dns_name
end
+ end
+
+ def create_tags(hashed_tags)
+ hashed_tags.each_pair do |key,val|
+ connection.tags.create :key => key, :value => val, :resource_id => @server.id
+ end
+ end
+
+ def associate_eip(elastic_ip)
+ connection.associate_address(server.id, elastic_ip.public_ip, nil, elastic_ip.allocation_id)
+ @server.wait_for { public_ip_address == elastic_ip.public_ip }
end
end
end
end