Skip to content

Commit 012a934

Browse files
committed
Merge pull request #124 from test-kitchen/tball/errors
Fixing error where aws returns DNS name as empty string
2 parents b994f18 + aa765ca commit 012a934

File tree

3 files changed

+108
-13
lines changed

3 files changed

+108
-13
lines changed

.rubocop.yml

+6
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ Style/Next:
77

88
Style/DoubleNegation:
99
Enabled: false
10+
11+
Metrics/CyclomaticComplexity:
12+
Max: 30
13+
14+
Metrics/PerceivedComplexity:
15+
Max: 30

lib/kitchen/driver/ec2.rb

+21-12
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
require "json"
2121
require "aws"
2222
require "kitchen"
23-
require "kitchen/driver/ec2_version"
23+
require_relative "ec2_version"
2424
require_relative "aws/client"
2525
require_relative "aws/instance_generator"
26+
require "aws-sdk-core/waiters/errors"
2627

2728
module Kitchen
2829

@@ -60,6 +61,7 @@ class Ec2 < Kitchen::Driver::Base # rubocop:disable Metrics/ClassLength
6061
end
6162
default_config :username, nil
6263
default_config :associate_public_ip, nil
64+
default_config :interface, nil
6365

6466
required_config :aws_ssh_key_id
6567
required_config :image_id
@@ -194,14 +196,21 @@ def create(state) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
194196
t = config[:retryable_tries] * config[:retryable_sleep]
195197
info "Waited #{c}/#{t}s for instance <#{state[:server_id]}> to become ready."
196198
end
197-
server = server.wait_until(
198-
:max_attempts => config[:retryable_tries],
199-
:delay => config[:retryable_sleep],
200-
:before_attempt => wait_log
201-
) do |s|
202-
hostname = hostname(s)
203-
# Euca instances often report ready before they have an IP
204-
s.state.name == "running" && !hostname.nil? && hostname != "0.0.0.0"
199+
begin
200+
server = server.wait_until(
201+
:max_attempts => config[:retryable_tries],
202+
:delay => config[:retryable_sleep],
203+
:before_attempt => wait_log
204+
) do |s|
205+
hostname = hostname(s, config[:interface])
206+
# Euca instances often report ready before they have an IP
207+
s.exists? && s.state.name == "running" && !hostname.nil? && hostname != "0.0.0.0"
208+
end
209+
rescue ::Aws::Waiters::Errors::WaiterFailed
210+
error("Ran out of time waiting for the server with id [#{state[:server_id]}]" \
211+
" to become ready, attempting to destroy it")
212+
destroy(state)
213+
raise
205214
end
206215

207216
info("EC2 instance <#{state[:server_id]}> ready.")
@@ -217,7 +226,7 @@ def destroy(state)
217226
server = ec2.get_instance(state[:server_id])
218227
unless server.nil?
219228
instance.transport.connection(state).close
220-
server.terminate unless server.nil?
229+
server.terminate
221230
end
222231
if state[:spot_request_id]
223232
debug("Deleting spot request <#{state[:server_id]}>")
@@ -235,8 +244,6 @@ def default_ami
235244
region && region[instance.platform.name]
236245
end
237246

238-
private
239-
240247
def ec2
241248
@ec2 ||= Aws::Client.new(
242249
config[:region],
@@ -354,6 +361,8 @@ def hostname(server, interface_type = nil)
354361
potential_hostname = nil
355362
INTERFACE_TYPES.values.each do |type|
356363
potential_hostname ||= server.send(type)
364+
# AWS returns an empty string if the dns name isn't populated yet
365+
potential_hostname = nil if potential_hostname == ""
357366
end
358367
potential_hostname
359368
end

spec/kitchen/driver/ec2_spec.rb

+81-1
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,92 @@
7171
end
7272
end
7373

74-
describe "finalize_config!" do
74+
describe "#finalize_config!" do
7575
it "defaults the availability zone if not provided" do
7676
expect(config[:availability_zone]).to eq(nil)
7777
driver.finalize_config!(instance)
7878
expect(config[:availability_zone]).to eq("us-east-1b")
7979
end
8080
end
8181

82+
describe "#hostname" do
83+
let(:public_dns_name) { nil }
84+
let(:public_ip_address) { nil }
85+
let(:private_ip_address) { nil }
86+
let(:server) {
87+
double("server",
88+
:public_dns_name => public_dns_name,
89+
:public_ip_address => public_ip_address,
90+
:private_ip_address => private_ip_address
91+
)
92+
}
93+
94+
it "returns nil if all sources are nil" do
95+
expect(driver.hostname(server)).to eq(nil)
96+
end
97+
98+
it "raises an error if provided an unknown interface" do
99+
expect { driver.hostname(server, "foobar") }.to raise_error(Kitchen::UserError)
100+
end
101+
102+
shared_examples "an interface type provided" do
103+
it "returns public_dns_name when requested" do
104+
expect(driver.hostname(server, "dns")).to eq(public_dns_name)
105+
end
106+
it "returns public_ip_address when requested" do
107+
expect(driver.hostname(server, "public")).to eq(public_ip_address)
108+
end
109+
it "returns private_ip_address when requested" do
110+
expect(driver.hostname(server, "private")).to eq(private_ip_address)
111+
end
112+
end
113+
114+
context "private_ip_address is populated" do
115+
let(:private_ip_address) { "10.0.0.1" }
116+
117+
it "returns the private_ip_address" do
118+
expect(driver.hostname(server)).to eq(private_ip_address)
119+
end
120+
121+
include_examples "an interface type provided"
122+
end
123+
124+
context "public_ip_address is populated" do
125+
let(:private_ip_address) { "10.0.0.1" }
126+
let(:public_ip_address) { "127.0.0.1" }
127+
128+
it "returns the public_ip_address" do
129+
expect(driver.hostname(server)).to eq(public_ip_address)
130+
end
131+
132+
include_examples "an interface type provided"
133+
end
134+
135+
context "public_dns_name is populated" do
136+
let(:private_ip_address) { "10.0.0.1" }
137+
let(:public_ip_address) { "127.0.0.1" }
138+
let(:public_dns_name) { "public_dns_name" }
139+
140+
it "returns the public_dns_name" do
141+
expect(driver.hostname(server)).to eq(public_dns_name)
142+
end
143+
144+
include_examples "an interface type provided"
145+
end
146+
147+
context "public_dns_name returns as empty string" do
148+
let(:public_dns_name) { "" }
149+
it "returns nil" do
150+
expect(driver.hostname(server)).to eq(nil)
151+
end
152+
153+
context "and private_ip_address is populated" do
154+
let(:private_ip_address) { "10.0.0.1" }
155+
it "returns the private_ip_address" do
156+
expect(driver.hostname(server)).to eq(private_ip_address)
157+
end
158+
end
159+
end
160+
end
161+
82162
end

0 commit comments

Comments
 (0)