lib/kitchen/driver/ec2.rb in kitchen-ec2-1.2.0 vs lib/kitchen/driver/ec2.rb in kitchen-ec2-1.3.0
- old
+ new
@@ -79,11 +79,13 @@
default_config :username, nil
default_config :associate_public_ip, nil
default_config :interface, nil
default_config :http_proxy, ENV["HTTPS_PROXY"] || ENV["HTTP_PROXY"]
default_config :retry_limit, 3
+ default_config :tenancy, "default"
default_config :instance_initiated_shutdown_behavior, nil
+ default_config :ssl_verify_peer, true
def initialize(*args, &block)
super
# AWS Ruby SDK loading isn't thread safe, so as soon as we know we're
# going to use EC2, autoload it. Seems to have been fixed in Ruby 2.3+
@@ -192,20 +194,24 @@
# See https://github.com/aws/aws-sdk-ruby/issues/859
# Tagging can fail with a NotFound error even though we waited until the server exists
# Waiting can also fail, so we have to also retry on that. If it means we re-tag the
# instance, so be it.
+ # Tagging an instance is possible before volumes are attached. Tagging the volumes after
+ # instance creation is consistent.
Retryable.retryable(
:tries => 10,
:sleep => lambda { |n| [2**n, 30].min },
:on => ::Aws::EC2::Errors::InvalidInstanceIDNotFound
) do |r, _|
info("Attempting to tag the instance, #{r} retries")
tag_server(server)
state[:server_id] = server.id
info("EC2 instance <#{state[:server_id]}> created.")
+ wait_until_volumes_ready(server, state)
+ tag_volumes(server)
wait_until_ready(server, state)
end
if windows_os? &&
instance.transport[:username] =~ /administrator/i &&
@@ -294,13 +300,18 @@
search_platform.find_image(image_search)
end
end
def update_username(state)
- # TODO: if the user explicitly specified the transport's default username,
- # do NOT overwrite it!
- if instance.transport[:username] == instance.transport.class.defaults[:username]
+ # BUG: With the following equality condition on username, if the user specifies 'root'
+ # as the transport's username then we will overwrite that value with one from the standard
+ # platform definitions. This seems difficult to handle here as the default username is
+ # provided by the underlying transport classes, and is often non-nil (eg; 'root'), leaving
+ # us no way to distinguish a user-set value from the transport's default.
+ # See https://github.com/test-kitchen/kitchen-ec2/pull/273
+ if actual_platform &&
+ instance.transport[:username] == instance.transport.class.defaults[:username]
debug("No SSH username specified: using default username #{actual_platform.username} " \
" for image #{config[:image_id]}, which we detected as #{actual_platform}.")
state[:username] = actual_platform.username
end
end
@@ -311,11 +322,12 @@
config[:shared_credentials_profile],
config[:aws_access_key_id],
config[:aws_secret_access_key],
config[:aws_session_token],
config[:http_proxy],
- config[:retry_limit]
+ config[:retry_limit],
+ config[:ssl_verify_peer]
)
end
def instance_generator
@instance_generator ||= Aws::InstanceGenerator.new(config, ec2, instance.logger)
@@ -354,13 +366,15 @@
end
ec2.get_instance_from_spot_request(spot_request_id)
end
def create_spot_request
+ request_duration = config[:retryable_tries] * config[:retryable_sleep]
request_data = {
:spot_price => config[:spot_price].to_s,
- :launch_specification => instance_generator.ec2_instance_data
+ :launch_specification => instance_generator.ec2_instance_data,
+ :valid_until => Time.now + request_duration
}
if config[:block_duration_minutes]
request_data[:block_duration_minutes] = config[:block_duration_minutes]
end
@@ -376,10 +390,38 @@
end
server.create_tags(:tags => tags)
end
end
+ def tag_volumes(server)
+ tags = []
+ config[:tags].each do |k, v|
+ tags << { :key => k, :value => v }
+ end
+ server.volumes.each do |volume|
+ volume.create_tags(:tags => tags)
+ end
+ end
+
+ # Compares the requested volume count vs what has actually been set to be
+ # attached to the instance. The information requested through
+ # ec2.client.described_volumes is updated before the instance volume
+ # information.
+ def wait_until_volumes_ready(server, state)
+ wait_with_destroy(server, state, "volumes to be ready") do |aws_instance|
+ described_volume_count = 0
+ ready_volume_count = 0
+ if aws_instance.exists?
+ described_volume_count = ec2.client.describe_volumes(:filters => [
+ { :name => "attachment.instance-id", :values => ["#{state[:server_id]}"] }]
+ ).volumes.length
+ aws_instance.volumes.each { ready_volume_count += 1 }
+ end
+ (described_volume_count > 0) && (described_volume_count == ready_volume_count)
+ end
+ end
+
# Normally we could use `server.wait_until_running` but we actually need
# to check more than just the instance state
def wait_until_ready(server, state)
wait_with_destroy(server, state, "to become ready") do |aws_instance|
hostname = hostname(aws_instance, config[:interface])
@@ -511,13 +553,18 @@
"Adding $username to Administrators" >> $logfile
& net.exe localgroup Administrators /add $username >> $logfile
EOH
end
+ if actual_platform.version =~ /2016/
+ logfile_name = 'C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Log\\kitchen-ec2.log'
+ else
+ logfile_name = 'C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs\\kitchen-ec2.log'
+ end
# Returning the fully constructed PowerShell script to user_data
Kitchen::Util.outdent!(<<-EOH)
<powershell>
- $logfile="C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs\\kitchen-ec2.log"
+ $logfile=#{logfile_name}
# Allow script execution
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force
#PS Remoting and & winrm.cmd basic config
Enable-PSRemoting -Force -SkipNetworkProfileCheck
& winrm.cmd set winrm/config '@{MaxTimeoutms="1800000"}' >> $logfile