Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require Ruby 2.3 and aws-sdk-ec2 #419

Merged
merged 2 commits into from
Mar 15, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ RuboCop::RakeTask.new(:style) do |task|
end

desc "Run all quality tasks"
task :quality => [:style, :stats]
task quality: [:style, :stats]

require "yard"
YARD::Rake::YardocTask.new

task default: [:test, :quality]
4 changes: 2 additions & 2 deletions kitchen-ec2.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ Gem::Specification.new do |gem|
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR).grep(/LICENSE|^lib/)
gem.require_paths = ["lib"]

gem.required_ruby_version = ">= 2.2.2"
gem.required_ruby_version = ">= 2.3"

gem.add_dependency "test-kitchen", ">= 1.4.1", "< 3"
gem.add_dependency "excon"
gem.add_dependency "multi_json"
gem.add_dependency "aws-sdk", "~> 2"
gem.add_dependency "aws-sdk-ec2", "~> 1.0"
gem.add_dependency "retryable", "~> 2.0"

gem.add_development_dependency "rspec", "~> 3.2"
Expand Down
18 changes: 9 additions & 9 deletions lib/kitchen/driver/aws/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

require "aws-sdk"
require "aws-sdk-ec2"
require "aws-sdk-core/credentials"
require "aws-sdk-core/shared_credentials"
require "aws-sdk-core/instance_profile_credentials"
Expand All @@ -41,12 +41,12 @@ def initialize(
ssl_verify_peer = true
)
::Aws.config.update(
:region => region,
:profile => profile_name,
:http_proxy => http_proxy,
:ssl_verify_peer => ssl_verify_peer
region: region,
profile: profile_name,
http_proxy: http_proxy,
ssl_verify_peer: ssl_verify_peer
)
::Aws.config.update(:retry_limit => retry_limit) unless retry_limit.nil?
::Aws.config.update(retry_limit: retry_limit) unless retry_limit.nil?
end

def create_instance(options)
Expand All @@ -59,9 +59,9 @@ def get_instance(id)

def get_instance_from_spot_request(request_id)
resource.instances(
:filters => [{
:name => "spot-instance-request-id",
:values => [request_id],
filters: [{
name: "spot-instance-request-id",
values: [request_id],
}]
).to_a[0]
end
Expand Down
50 changes: 25 additions & 25 deletions lib/kitchen/driver/aws/instance_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# limitations under the License.

require "base64"
require "aws-sdk"
require "aws-sdk-ec2"

module Kitchen

Expand All @@ -45,12 +45,12 @@ def ec2_instance_data # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
# Support for looking up security group id and subnet id using tags.

if config[:subnet_id].nil? && config[:subnet_filter]
config[:subnet_id] = ::Aws::EC2::Client.
new(:region => config[:region]).describe_subnets(
:filters => [
config[:subnet_id] = ::Aws::EC2::Client
.new(region: config[:region]).describe_subnets(
filters: [
{
:name => "tag:#{config[:subnet_filter][:tag]}",
:values => [config[:subnet_filter][:value]],
name: "tag:#{config[:subnet_filter][:tag]}",
values: [config[:subnet_filter][:value]],
},
]
)[0][0].subnet_id
Expand All @@ -62,12 +62,12 @@ def ec2_instance_data # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
end

if config[:security_group_ids].nil? && config[:security_group_filter]
security_group = ::Aws::EC2::Client.
new(:region => config[:region]).describe_security_groups(
:filters => [
security_group = ::Aws::EC2::Client
.new(region: config[:region]).describe_security_groups(
filters: [
{
:name => "tag:#{config[:security_group_filter][:tag]}",
:values => [config[:security_group_filter][:value]],
name: "tag:#{config[:security_group_filter][:tag]}",
values: [config[:security_group_filter][:value]],
},
]
)[0][0]
Expand All @@ -81,27 +81,27 @@ def ec2_instance_data # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
end

i = {
:instance_type => config[:instance_type],
:ebs_optimized => config[:ebs_optimized],
:image_id => config[:image_id],
:key_name => config[:aws_ssh_key_id],
:subnet_id => config[:subnet_id],
:private_ip_address => config[:private_ip_address],
instance_type: config[:instance_type],
ebs_optimized: config[:ebs_optimized],
image_id: config[:image_id],
key_name: config[:aws_ssh_key_id],
subnet_id: config[:subnet_id],
private_ip_address: config[:private_ip_address],
}

availability_zone = config[:availability_zone]
if availability_zone
if availability_zone =~ /^[a-z]$/i
availability_zone = "#{config[:region]}#{availability_zone}"
end
i[:placement] = { :availability_zone => availability_zone.downcase }
i[:placement] = { availability_zone: availability_zone.downcase }
end
tenancy = config[:tenancy]
if tenancy
if i.key?(:placement)
i[:placement][:tenancy] = tenancy
else
i[:placement] = { :tenancy => tenancy }
i[:placement] = { tenancy: tenancy }
end
end
unless config[:block_device_mappings].nil? || config[:block_device_mappings].empty?
Expand All @@ -110,14 +110,14 @@ def ec2_instance_data # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
i[:security_group_ids] = Array(config[:security_group_ids]) if config[:security_group_ids]
i[:user_data] = prepared_user_data if prepared_user_data
if config[:iam_profile_name]
i[:iam_instance_profile] = { :name => config[:iam_profile_name] }
i[:iam_instance_profile] = { name: config[:iam_profile_name] }
end
if !config.fetch(:associate_public_ip, nil).nil?
i[:network_interfaces] =
[{
:device_index => 0,
:associate_public_ip_address => config[:associate_public_ip],
:delete_on_termination => true,
device_index: 0,
associate_public_ip_address: config[:associate_public_ip],
delete_on_termination: true,
}]
# If specifying `:network_interfaces` in the request, you must specify
# network specific configs in the network_interfaces block and not at
Expand All @@ -137,14 +137,14 @@ def ec2_instance_data # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
if availability_zone =~ /^[a-z]$/i
availability_zone = "#{config[:region]}#{availability_zone}"
end
i[:placement] = { :availability_zone => availability_zone.downcase }
i[:placement] = { availability_zone: availability_zone.downcase }
end
tenancy = config[:tenancy]
if tenancy
if i.key?(:placement)
i[:placement][:tenancy] = tenancy
else
i[:placement] = { :tenancy => tenancy }
i[:placement] = { tenancy: tenancy }
end
end
unless config[:instance_initiated_shutdown_behavior].nil? ||
Expand Down
6 changes: 3 additions & 3 deletions lib/kitchen/driver/aws/standard_platform.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def initialize(driver, name, version, architecture)
#
# The list of supported architectures
#
SUPPORTED_ARCHITECTURES = %w{x86_64 i386 arm64}
SUPPORTED_ARCHITECTURES = %w{x86_64 i386 arm64}.freeze

#
# Find the best matching image for the given image search.
Expand All @@ -98,11 +98,11 @@ def find_image(image_search)
driver.debug("Searching for images matching #{image_search} ...")
# Convert to ec2 search format (pairs of name+values)
filters = image_search.map do |key, value|
{ :name => key.to_s, :values => Array(value).map(&:to_s) }
{ name: key.to_s, values: Array(value).map(&:to_s) }
end

# We prefer most recent first
images = driver.ec2.resource.images(:filters => filters)
images = driver.ec2.resource.images(filters: filters)
images = sort_images(images)
show_returned_images(images)

Expand Down
6 changes: 3 additions & 3 deletions lib/kitchen/driver/aws/standard_platform/centos.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ def sort_by_version(images)
# 7.1 -> [ img1, img2, img3 ]
# 6 -> [ img4, img5 ]
# ...
images.group_by { |image| self.class.from_image(driver, image).version }.
sort_by { |k, _v| (k && k.include?(".") ? k.to_f : "#{k}.999".to_f) }.
reverse.flat_map { |_k, v| v }
images.group_by { |image| self.class.from_image(driver, image).version }
.sort_by { |k, _v| (k && k.include?(".") ? k.to_f : "#{k}.999".to_f) }
.reverse.flat_map { |_k, v| v }
end

def self.from_image(driver, image)
Expand Down
6 changes: 3 additions & 3 deletions lib/kitchen/driver/aws/standard_platform/windows.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ def sort_by_version(images)
# 2008r2rtm -> [ img1, img2, img3 ]
# 2012r2sp1 -> [ img4, img5 ]
# ...
images.group_by { |image| self.class.from_image(driver, image).windows_version_parts }.
sort_by { |version, _platform_images| version }.
reverse.flat_map { |_version, platform_images| platform_images }
images.group_by { |image| self.class.from_image(driver, image).windows_version_parts }
.sort_by { |version, _platform_images| version }
.reverse.flat_map { |_version, platform_images| platform_images }
end

def self.from_image(driver, image)
Expand Down
52 changes: 24 additions & 28 deletions lib/kitchen/driver/ec2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,13 @@
require_relative "aws/standard_platform/freebsd"
require_relative "aws/standard_platform/ubuntu"
require_relative "aws/standard_platform/windows"
require "aws-sdk-ec2"
require "aws-sdk-core/waiters/errors"
require "retryable"
require "time"
require "etc"
require "socket"

Aws.eager_autoload!

module Kitchen

module Driver
Expand Down Expand Up @@ -96,9 +95,6 @@ class Ec2 < Kitchen::Driver::Base

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+
::Aws.eager_autoload! unless RUBY_VERSION.to_f >= 2.3
end

def self.validation_warn(driver, old_key, new_key)
Expand Down Expand Up @@ -252,15 +248,15 @@ def create(state)
# 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
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)

# Get information about the AMI (image) used to create the image.
image_data = ec2.client.describe_images({ :image_ids => [server.image_id] })[0][0]
image_data = ec2.client.describe_images({ image_ids: [server.image_id] })[0][0]

state[:server_id] = server.id
info("EC2 instance <#{state[:server_id]}> created.")
Expand Down Expand Up @@ -303,7 +299,7 @@ def destroy(state)
if state[:spot_request_id]
debug("Deleting spot request <#{state[:server_id]}>")
ec2.client.cancel_spot_instance_requests(
:spot_instance_request_ids => [state[:spot_request_id]]
spot_instance_request_ids: [state[:spot_request_id]]
)
state.delete(:spot_request_id)
end
Expand Down Expand Up @@ -433,7 +429,7 @@ def submit_spot(state)
state[:spot_request_id] = spot_request_id
ec2.client.wait_until(
:spot_instance_request_fulfilled,
:spot_instance_request_ids => [spot_request_id]
spot_instance_request_ids: [spot_request_id]
) do |w|
w.max_attempts = config[:retryable_tries]
w.delay = config[:retryable_sleep]
Expand All @@ -449,9 +445,9 @@ def submit_spot(state)
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,
:valid_until => Time.now + request_duration,
spot_price: config[:spot_price].to_s,
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]
Expand All @@ -467,19 +463,19 @@ def tag_server(server)
# we convert the value to a string because
# nils should be passed as an empty String
# and Integers need to be represented as Strings
{ :key => k, :value => v.to_s }
{ key: k, value: v.to_s }
end
server.create_tags(:tags => tags)
server.create_tags(tags: tags)
end
end

def tag_volumes(server)
if config[:tags] && !config[:tags].empty?
tags = config[:tags].map do |k, v|
{ :key => k, :value => v.to_s }
{ key: k, value: v.to_s }
end
server.volumes.each do |volume|
volume.create_tags(:tags => tags)
volume.create_tags(tags: tags)
end
end
end
Expand All @@ -493,8 +489,8 @@ def wait_until_volumes_ready(server, state)
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]}"] }]
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
Expand Down Expand Up @@ -542,9 +538,9 @@ def wait_with_destroy(server, state, status_msg, &block)
begin
with_request_limit_backoff(state) do
server.wait_until(
:max_attempts => config[:retryable_tries],
:delay => config[:retryable_sleep],
:before_attempt => wait_log,
max_attempts: config[:retryable_tries],
delay: config[:retryable_sleep],
before_attempt: wait_log,
&block
)
end
Expand All @@ -559,7 +555,7 @@ def wait_with_destroy(server, state, status_msg, &block)
def fetch_windows_admin_password(server, state)
wait_with_destroy(server, state, "to fetch windows admin password") do |aws_instance|
enc = server.client.get_password_data(
:instance_id => state[:server_id]
instance_id: state[:server_id]
).password_data
# Password data is blank until password is available
!enc.nil? && !enc.empty?
Expand Down Expand Up @@ -595,7 +591,7 @@ def with_request_limit_backoff(state)
"public" => "public_ip_address",
"private" => "private_ip_address",
"private_dns" => "private_dns_name",
}
}.freeze

#
# Lookup hostname of provided server. If interface_type is provided use
Expand Down Expand Up @@ -668,7 +664,7 @@ def default_windows_user_data
#Firewall Config
& netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public protocol=tcp localport=5985 remoteip=localsubnet new remoteip=any >> $logfile
Set-ItemProperty -Name LocalAccountTokenFilterPolicy -Path HKLM:\\software\\Microsoft\\Windows\\CurrentVersion\\Policies\\system -Value 1
EOH
EOH

# Preparing custom static admin user if we defined something other than Administrator
custom_admin_script = ""
Expand Down Expand Up @@ -712,8 +708,8 @@ def show_chosen_image
end

def image_info(image)
root_device = image.block_device_mappings.
find { |b| b.device_name == image.root_device_name }
root_device = image.block_device_mappings
.find { |b| b.device_name == image.root_device_name }
volume_type = " #{root_device.ebs.volume_type}" if root_device && root_device.ebs

" Architecture: #{image.architecture}," \
Expand Down
Loading