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