knife-ec2 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -23,7 +23,7 @@ Bundler::GemHelper.install_tasks
23
23
 
24
24
  # require 'rubygems'
25
25
  # require 'rake/gempackagetask'
26
- require 'rake/rdoctask'
26
+ require 'rdoc/task'
27
27
 
28
28
  begin
29
29
  require 'sdoc'
@@ -62,6 +62,10 @@ class Chef
62
62
  :description => "The security group ids for this server; required when using VPC",
63
63
  :proc => Proc.new { |security_group_ids| security_group_ids.split(',') }
64
64
 
65
+ option :associate_eip,
66
+ :long => "--associate-eip IP_ADDRESS",
67
+ :description => "Associate existing elastic IP address with instance after launch"
68
+
65
69
  option :tags,
66
70
  :short => "-T T=V[,T=V,...]",
67
71
  :long => "--tags Tag=Value[,Tag=Value...]",
@@ -110,7 +114,6 @@ class Chef
110
114
  :description => "The ssh gateway server",
111
115
  :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
112
116
 
113
-
114
117
  option :identity_file,
115
118
  :short => "-i IDENTITY_FILE",
116
119
  :long => "--identity-file IDENTITY_FILE",
@@ -167,6 +170,11 @@ class Chef
167
170
  :description => "create node in this Virtual Private Cloud Subnet ID (implies VPC mode)",
168
171
  :proc => Proc.new { |key| Chef::Config[:knife][:subnet_id] = key }
169
172
 
173
+ option :private_ip_address,
174
+ :long => "--private-ip-address IP-ADDRESS",
175
+ :description => "allows to specify the private IP address of the instance in VPC mode",
176
+ :proc => Proc.new { |ip| Chef::Config[:knife][:private_ip_address] = ip }
177
+
170
178
  option :host_key_verify,
171
179
  :long => "--[no-]host-key-verify",
172
180
  :description => "Verify host key, enabled by default.",
@@ -225,6 +233,11 @@ class Chef
225
233
 
226
234
  validate!
227
235
 
236
+ requested_elastic_ip = config[:associate_eip] if config[:associate_eip]
237
+
238
+ # For VPC EIP assignment we need the allocation ID so fetch full EIP details
239
+ elastic_ip = connection.addresses.detect{|addr| addr if addr.public_ip == requested_elastic_ip}
240
+
228
241
  @server = connection.servers.create(create_server_def)
229
242
 
230
243
  hashed_tags={}
@@ -235,10 +248,6 @@ class Chef
235
248
  hashed_tags["Name"] = locate_config_value(:chef_node_name) || @server.id
236
249
  end
237
250
 
238
- hashed_tags.each_pair do |key,val|
239
- connection.tags.create :key => key, :value => val, :resource_id => @server.id
240
- end
241
-
242
251
  msg_pair("Instance ID", @server.id)
243
252
  msg_pair("Flavor", @server.flavor_id)
244
253
  msg_pair("Image", @server.image_id)
@@ -260,15 +269,30 @@ class Chef
260
269
  msg_pair("Tags", hashed_tags)
261
270
  msg_pair("SSH Key", @server.key_name)
262
271
 
263
- print "\n#{ui.color("Waiting for server", :magenta)}"
272
+ print "\n#{ui.color("Waiting for instance", :magenta)}"
264
273
 
265
- # wait for it to be ready to do stuff
274
+ # wait for instance to come up before acting against it
266
275
  @server.wait_for { print "."; ready? }
267
276
 
268
277
  puts("\n")
269
278
 
279
+ # occasionally 'ready?' isn't, so retry a couple times if needed.
280
+ tries = 6
281
+ begin
282
+ create_tags(hashed_tags) unless hashed_tags.empty?
283
+ associate_eip(elastic_ip) if config[:associate_eip]
284
+ rescue Fog::Compute::AWS::NotFound => e
285
+ raise if (tries -= 1) <= 0
286
+ ui.warn("server not ready, retrying tag application (retries left: #{tries})")
287
+ sleep 5
288
+ retry
289
+ end
290
+
270
291
  if vpc_mode?
271
292
  msg_pair("Subnet ID", @server.subnet_id)
293
+ if elastic_ip
294
+ msg_pair("Public IP Address", @server.public_ip_address)
295
+ end
272
296
  else
273
297
  msg_pair("Public DNS Name", @server.dns_name)
274
298
  msg_pair("Public IP Address", @server.public_ip_address)
@@ -373,7 +397,19 @@ class Chef
373
397
  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.")
374
398
  exit 1
375
399
  end
400
+ if !vpc_mode? and !!config[:private_ip_address]
401
+ ui.error("You can only specify a private IP address if you are using VPC.")
402
+ exit 1
403
+ end
404
+
405
+ if config[:associate_eip]
406
+ eips = connection.addresses.collect{|addr| addr if addr.domain == eip_scope}.compact
376
407
 
408
+ unless eips.detect{|addr| addr.public_ip == config[:associate_eip] && addr.server_id == nil}
409
+ ui.error("Elastic IP requested is not available.")
410
+ exit 1
411
+ end
412
+ end
377
413
  end
378
414
 
379
415
  def tags
@@ -385,6 +421,14 @@ class Chef
385
421
  tags
386
422
  end
387
423
 
424
+ def eip_scope
425
+ if vpc_mode?
426
+ "vpc"
427
+ else
428
+ "standard"
429
+ end
430
+ end
431
+
388
432
  def create_server_def
389
433
  server_def = {
390
434
  :image_id => locate_config_value(:image),
@@ -395,6 +439,7 @@ class Chef
395
439
  :availability_zone => locate_config_value(:availability_zone)
396
440
  }
397
441
  server_def[:subnet_id] = locate_config_value(:subnet_id) if vpc_mode?
442
+ server_def[:private_ip_address] = locate_config_value(:private_ip_address) if vpc_mode?
398
443
 
399
444
  if Chef::Config[:knife][:aws_user_data]
400
445
  begin
@@ -486,6 +531,17 @@ class Chef
486
531
  vpc_mode? ? server.private_ip_address : server.dns_name
487
532
  end
488
533
  end
534
+
535
+ def create_tags(hashed_tags)
536
+ hashed_tags.each_pair do |key,val|
537
+ connection.tags.create :key => key, :value => val, :resource_id => @server.id
538
+ end
539
+ end
540
+
541
+ def associate_eip(elastic_ip)
542
+ connection.associate_address(server.id, elastic_ip.public_ip, nil, elastic_ip.allocation_id)
543
+ @server.wait_for { public_ip_address == elastic_ip.public_ip }
544
+ end
489
545
  end
490
546
  end
491
547
  end
@@ -1,6 +1,6 @@
1
1
  module Knife
2
2
  module Ec2
3
- VERSION = "0.6.2"
3
+ VERSION = "0.6.4"
4
4
  MAJOR, MINOR, TINY = VERSION.split('.')
5
5
  end
6
6
  end
@@ -38,6 +38,13 @@ describe Chef::Knife::Ec2ServerCreate do
38
38
  @ec2_connection = mock(Fog::Compute::AWS)
39
39
  @ec2_connection.stub_chain(:tags).and_return mock('create', :create => true)
40
40
  @ec2_connection.stub_chain(:images, :get).and_return mock('ami', :root_device_type => 'not_ebs')
41
+ @ec2_connection.stub_chain(:addresses).and_return [mock('addesses', {
42
+ :domain => 'standard',
43
+ :public_ip => '111.111.111.111',
44
+ :server_id => nil,
45
+ :allocation_id => ''})]
46
+
47
+
41
48
  @ec2_servers = mock()
42
49
  @new_ec2_server = mock()
43
50
 
@@ -60,30 +67,56 @@ describe Chef::Knife::Ec2ServerCreate do
60
67
  end
61
68
 
62
69
  describe "run" do
63
- it "creates an EC2 instance and bootstraps it" do
64
- @new_ec2_server.should_receive(:wait_for).and_return(true)
70
+ before do
65
71
  @ec2_servers.should_receive(:create).and_return(@new_ec2_server)
66
72
  @ec2_connection.should_receive(:servers).and_return(@ec2_servers)
73
+ @ec2_connection.should_receive(:addresses)
67
74
 
75
+ @eip = "111.111.111.111"
68
76
  Fog::Compute::AWS.should_receive(:new).and_return(@ec2_connection)
69
77
 
70
78
  @knife_ec2_create.stub!(:puts)
71
79
  @knife_ec2_create.stub!(:print)
72
80
  @knife_ec2_create.config[:image] = '12345'
73
81
 
74
-
75
82
  @bootstrap = Chef::Knife::Bootstrap.new
76
83
  Chef::Knife::Bootstrap.stub!(:new).and_return(@bootstrap)
77
84
  @bootstrap.should_receive(:run)
85
+ end
86
+
87
+ it "creates an EC2 instance and bootstraps it" do
88
+ @new_ec2_server.should_receive(:wait_for).and_return(true)
89
+ @knife_ec2_create.run
90
+ @knife_ec2_create.server.should_not == nil
91
+ end
92
+
93
+ it "creates an EC2 instance, assigns existing EIP and bootstraps it" do
94
+ @knife_ec2_create.config[:associate_eip] = @eip
95
+
96
+ @new_ec2_server.stub!(:public_ip_address).and_return(@eip)
97
+ @ec2_connection.should_receive(:associate_address).with(@ec2_server_attribs[:id], @eip, nil, '')
98
+ @new_ec2_server.should_receive(:wait_for).at_least(:twice).and_return(true)
99
+
78
100
  @knife_ec2_create.run
79
101
  @knife_ec2_create.server.should_not == nil
80
102
  end
103
+
104
+ it "retries if it receives Fog::Compute::AWS::NotFound" do
105
+ @new_ec2_server.should_receive(:wait_for).and_return(true)
106
+ @knife_ec2_create.should_receive(:create_tags).and_raise(Fog::Compute::AWS::NotFound)
107
+ @knife_ec2_create.should_receive(:create_tags).and_return(true)
108
+ @knife_ec2_create.should_receive(:sleep).and_return(true)
109
+ @knife_ec2_create.ui.should_receive(:warn).with(/retrying/)
110
+ @knife_ec2_create.run
111
+ end
81
112
  end
113
+
82
114
  describe "when setting tags" do
83
115
  before do
84
116
  Fog::Compute::AWS.should_receive(:new).and_return(@ec2_connection)
85
117
  @knife_ec2_create.stub!(:bootstrap_for_node).and_return mock("bootstrap", :run => true)
86
118
  @ec2_connection.stub!(:servers).and_return(@ec2_servers)
119
+ @ec2_connection.should_receive(:addresses)
87
120
  @new_ec2_server.stub!(:wait_for).and_return(true)
88
121
  @ec2_servers.stub!(:create).and_return(@new_ec2_server)
89
122
  @knife_ec2_create.stub!(:puts)
@@ -216,6 +249,12 @@ describe Chef::Knife::Ec2ServerCreate do
216
249
 
217
250
  lambda { @knife_ec2_create.validate! }.should raise_error SystemExit
218
251
  end
252
+
253
+ it "disallows private ips when not using a VPC" do
254
+ @knife_ec2_create.config[:private_ip_address] = '10.0.0.10'
255
+
256
+ lambda { @knife_ec2_create.validate! }.should raise_error SystemExit
257
+ end
219
258
  end
220
259
 
221
260
  describe "when creating the server definition" do
@@ -270,6 +309,15 @@ describe Chef::Knife::Ec2ServerCreate do
270
309
  { "VirtualName" => "ephemeral2", "DeviceName" => "/dev/sdd" },
271
310
  { "VirtualName" => "ephemeral3", "DeviceName" => "/dev/sde" }]
272
311
  end
312
+
313
+ it "sets the specified private ip address" do
314
+ @knife_ec2_create.config[:subnet_id] = 'subnet-1a2b3c4d'
315
+ @knife_ec2_create.config[:private_ip_address] = '10.0.0.10'
316
+ server_def = @knife_ec2_create.create_server_def
317
+
318
+ server_def[:subnet_id].should == 'subnet-1a2b3c4d'
319
+ server_def[:private_ip_address].should == '10.0.0.10'
320
+ end
273
321
  end
274
322
 
275
323
  describe "ssh_connect_host" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-ec2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-10-24 00:00:00.000000000 Z
13
+ date: 2013-04-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: fog