knife-ec2 0.6.6 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTdhZGU4M2U0NDY2Mzc2NjdlMzkxNGI2ZTkxMDcyMDZjODI4Mzk1Ng==
5
+ data.tar.gz: !binary |-
6
+ NzMzNmEyMDUwM2VkNTZkOGQ0MmYxZDBjZWIyODRkMzI4MzVlZmRkOA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ OTlmZjliMzM5MjRlYzc4NGQ4ZDU4YTM4ZDVkNzIwN2VkMjJhNzY1NDdiMjk0
10
+ MTJlYjU4ODdiOWJmODBlODdiNzVjYTc0YTY5MWQ3YzQzYzExOWE5MTMzY2Ew
11
+ MDc0ZDg2NmZiNDIxMGU3ZWQxMjg2NWRhOGU3MDAwOWQ5OTFiYjE=
12
+ data.tar.gz: !binary |-
13
+ OGMwNGVlMjgwNjY5ZTAwZTk3MGZlZDU4MWExNzUzNTVjYmU5MjY5MTkxMGVi
14
+ NDYwNjAyYmMwMTA3NWEzNTQ3MzU5YTBmMGU1ZTg2ZWYwZWRlZmQ4ZTE2YWZj
15
+ MGZhMmJjZDk5MzRkNzIyNzk2ZTQyNmQxZGFkOWE3NGU3MGZhNjM=
data/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ # knife-ec2 change log
2
+
3
+ Note: this log contains only changes from knife-ec2 release 0.8.0 and later
4
+ -- it does not contain the changes from prior release. To view change history
5
+ prior to release 0.8.0, please visit the [source repository](https://github.com/opscode/knife-ec2/commits).
6
+
7
+ ## Unreleased changes
8
+
9
+ None.
10
+
11
+ ## Last release: 0.8.0 (2014-03-10)
12
+
13
+ * [KNIFE-458](https://tickets.opscode.com/browse/KNIFE-458) Docs: Increase detail about necessary
14
+ options for VPC instance creation
15
+ * [KNIFE-456](https://tickets.opscode.com/browse/KNIFE-456) Documentation for :aws\_credential\_file difficult to read
16
+ * [KNIFE-455](https://tickets.opscode.com/browse/KNIFE-455) knife ec2 may try to use private ip for vpc bootstrap even with --associate-public-ip flag
17
+ * [KNIFE-453](https://tickets.opscode.com/browse/KNIFE-453) knife-ec2 doesn't handle aws credentials files with windows line endings
18
+ * [KNIFE-451](https://tickets.opscode.com/browse/KNIFE-451) Update Fog version to 1.20.0
19
+ * [KNIFE-430](https://tickets.opscode.com/browse/KNIFE-430) server creation tunnelling should wait for a valid banner before continuing
20
+ * [KNIFE-381](https://tickets.opscode.com/browse/KNIFE-381) Gabriel Rosendorf Add ability to associate public ip with VPC
21
+ instance on creation
22
+
23
+ ## Releases prior to 0.8.0
24
+ Please see <https://github.com/opscode/knife-ec2/commits> to view changes in
25
+ the form of commits to the source repository for releases before 0.8.0.
26
+
27
+
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,71 @@
1
+ # Contributing to knife-ec2
2
+
3
+ We are glad you want to contribute to Chef's knife-ec2 plugin! The first step is the desire to improve the project.
4
+
5
+ You can find the answers to additional frequently asked questions [on the wiki](http://wiki.opscode.com/display/chef/How+to+Contribute).
6
+
7
+ ## Quick-contribute
8
+
9
+ * Create an account on our [bug tracker](http://tickets.opscode.com/browse/KNIFE)
10
+ * Sign our contributor agreement (CLA) [
11
+ online](https://secure.echosign.com/public/hostedForm?formid=PJIF5694K6L)
12
+ (keep reading if you're contributing on behalf of your employer)
13
+ * Create a ticket for your change on the [bug tracker](http://tickets.opscode.com/browse/KNIFE)
14
+ * Link to your patch as a rebased git branch or pull request from the ticket
15
+ * Resolve the ticket as fixed
16
+
17
+ We regularly review contributions and will get back to you if we have any suggestions or concerns.
18
+
19
+ ## The Apache License and the CLA/CCLA
20
+
21
+ Licensing is very important to open source projects, it helps ensure the software continues to be available under the terms that the author desired.
22
+ Chef uses the Apache 2.0 license to strike a balance between open contribution and allowing you to use the software however you would like to.
23
+
24
+ The license tells you what rights you have that are provided by the copyright holder. It is important that the contributor fully understands what rights
25
+ they are licensing and agrees to them. Sometimes the copyright holder isn't the contributor, most often when the contributor is doing work for a company.
26
+
27
+ To make a good faith effort to ensure these criteria are met, Opscode requires a Contributor License Agreement (CLA) or a Corporate Contributor License
28
+ Agreement (CCLA) for all contributions. This is without exception due to some matters not being related to copyright and to avoid having to continually
29
+ check with our lawyers about small patches.
30
+
31
+ It only takes a few minutes to complete a CLA, and you retain the copyright to your contribution.
32
+
33
+ You can complete our contributor agreement (CLA) [
34
+ online](https://secure.echosign.com/public/hostedForm?formid=PJIF5694K6L). If you're contributing on behalf of your employer, have
35
+ your employer fill out our [Corporate CLA](https://secure.echosign.com/public/hostedForm?formid=PIE6C7AX856) instead.
36
+
37
+ ## Issue Tracking
38
+
39
+ You can file tickets to describe the bug you'd like to fix or feature you'd
40
+ like to add via the [knife-ec2 project](http://tickets.opscode.com/browse/KNIFE). For your contribution to be reviewed
41
+ and merged, you **must** file a ticket.
42
+
43
+ ## Contribution Details
44
+
45
+ Once you've created the ticket, you can make a pull request to
46
+ knife-ec2 on GitHub at <https://github.com/opscode/knife-ec2> that references
47
+ that ticket.
48
+
49
+ ## Testing Instructions
50
+
51
+ To run tests, run the following Ruby tool commands from the root of your local checkout of
52
+ knife-ec2:
53
+
54
+ bundle install
55
+ bundle exec rspec spec
56
+
57
+ **All tests must pass** before your contribution can be merged. Thus it's a good idea
58
+ to execute the tests without your change to be sure you understand how to run
59
+ them, as well as after to validate that you've avoided regressions.
60
+
61
+ All but the most trivial changes should include **at least one unit test case** to exercise the
62
+ new / changed code; please add tests to your pull request in this common case.
63
+
64
+ ## Further Resources
65
+
66
+ ### Fog
67
+
68
+ Knife-ec2 uses the Fog gem to interact with EC2's API. When there's a new
69
+ feature of EC2 that you'd like to utilize in knife-ec2 use cases, that feature
70
+ will probably be exposed by Fog. You can read about Fog
71
+ at its [project page](https://github.com/fog/fog).
data/DOC_CHANGES.md ADDED
@@ -0,0 +1,21 @@
1
+ <!---
2
+ This file is reset everytime when a new release is done. Contents of this file is for the currently unreleased version.
3
+ -->
4
+
5
+ # knife-ec2 doc changes
6
+
7
+ ## Command-line flag option --associate-ip for server create
8
+ The option --associate-ip was added to the knife-ec2 server create
9
+ subcommand.
10
+
11
+ ### server create
12
+
13
+ ### options
14
+
15
+ ```
16
+ --associate-public-ip
17
+ ```
18
+
19
+ Associate public IP address to the VPC instance so that the public IP is available
20
+ during bootstrapping. Only valid with VPC instances.
21
+
data/README.md CHANGED
@@ -4,8 +4,13 @@ Knife EC2
4
4
  [![Build Status](https://travis-ci.org/opscode/knife-ec2.png?branch=master)](https://travis-ci.org/opscode/knife-ec2)
5
5
  [![Dependency Status](https://gemnasium.com/opscode/knife-ec2.png)](https://gemnasium.com/opscode/knife-ec2)
6
6
 
7
- This is the official Opscode Knife plugin for EC2. This plugin gives knife the ability to create, bootstrap, and manage EC2 instances.
7
+ This is the official Chef Knife plugin for EC2. This plugin gives knife the ability to create, bootstrap, and manage EC2 instances.
8
8
 
9
+ * Documentation: <http://docs.opscode.com/plugin_knife_ec2.html>
10
+ * Source: <http://github.com/opscode/knife-ec2/tree/master>
11
+ * Tickets/Issues: <http://tickets.opscode.com/browse/KNIFE>
12
+ * IRC: `#chef` and `#chef-hacking` on Freenode
13
+ * Mailing list: <http://lists.opscode.com>
9
14
 
10
15
  Installation
11
16
  ------------
@@ -56,10 +61,12 @@ you already have a file with these keys somewhere in this format:
56
61
  AWSAccessKeyId=Your AWS Access Key ID
57
62
  AWSSecretKey=Your AWS Secret Access Key
58
63
 
59
- In this case, you can point the <tt>aws_credential_file</tt> option to
60
- this file in your <tt>knife.rb</tt> file, like so:
61
-
62
- knife[:aws_credential_file] = "/path/to/credentials/file/in/above/format"
64
+ In this case, you can point the <tt>aws_credential_file</tt> option to
65
+ this file in your <tt>knife.rb</tt> file, like so:
66
+
67
+ ```ruby
68
+ knife[:aws_credential_file] = "/path/to/credentials/file/in/above/format"
69
+ ```
63
70
 
64
71
  Additionally the following options may be set in your `knife.rb`:
65
72
 
@@ -106,10 +113,10 @@ In-depth usage instructions can be found on the [Chef Wiki](http://wiki.opscode.
106
113
 
107
114
  License and Authors
108
115
  -------------------
109
- - Author:: Adam Jacob (<adam@opscode.com>)
116
+ - Author:: Adam Jacob (<adam@getchef.com>)
110
117
 
111
118
  ```text
112
- Copyright 2009-2013 Opscode, Inc.
119
+ Copyright 2009-2014 Opscode, Inc.
113
120
 
114
121
  Licensed under the Apache License, Version 2.0 (the "License");
115
122
  you may not use this file except in compliance with the License.
data/knife-ec2.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.authors = ['Adam Jacob', 'Seth Chisamore']
9
9
  s.email = ['adam@opscode.com', 'schisamo@opscode.com']
10
10
  s.homepage = 'https://github.com/opscode/knife-ec2'
11
- s.summary = %q{EC2 Support for Chef\'s Knife Command}
11
+ s.summary = %q{EC2 Support for Chef's Knife Command}
12
12
  s.description = s.summary
13
13
  s.license = 'Apache 2.0'
14
14
 
@@ -16,13 +16,14 @@ Gem::Specification.new do |s|
16
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
 
19
- s.add_dependency 'fog', '~> 1.15.0'
20
- s.add_dependency 'chef', '>= 0.10.10'
19
+ s.add_dependency 'fog', '~> 1.20.0'
21
20
  s.add_dependency 'knife-windows', '>= 0.5.12'
22
21
 
23
- s.add_development_dependency 'rspec', '~> 2.14'
24
- s.add_development_dependency 'rake', '~> 10.1'
25
- s.add_development_dependency 'sdoc', '~> 0.3'
22
+ s.add_development_dependency 'mixlib-config', '~> 2.0'
23
+ s.add_development_dependency 'chef', '>= 0.10.10'
24
+ s.add_development_dependency 'rspec', '~> 2.14'
25
+ s.add_development_dependency 'rake', '~> 10.1'
26
+ s.add_development_dependency 'sdoc', '~> 0.3'
26
27
 
27
28
  s.require_paths = ['lib']
28
29
  end
@@ -95,7 +95,7 @@ class Chef
95
95
  # File format:
96
96
  # AWSAccessKeyId=somethingsomethingdarkside
97
97
  # AWSSecretKey=somethingsomethingcomplete
98
- entries = Hash[*File.read(Chef::Config[:knife][:aws_credential_file]).split(/[=\n]/)]
98
+ entries = Hash[*File.read(Chef::Config[:knife][:aws_credential_file]).split(/[=\n]/).map(&:chomp)]
99
99
  Chef::Config[:knife][:aws_access_key_id] = entries['AWSAccessKeyId']
100
100
  Chef::Config[:knife][:aws_secret_access_key] = entries['AWSSecretKey']
101
101
  end
@@ -71,6 +71,10 @@ class Chef
71
71
  :long => "--associate-eip IP_ADDRESS",
72
72
  :description => "Associate existing elastic IP address with instance after launch"
73
73
 
74
+ option :dedicated_instance,
75
+ :long => "--dedicated_instance",
76
+ :description => "Launch as a Dedicated instance (VPC ONLY)"
77
+
74
78
  option :placement_group,
75
79
  :long => "--placement-group PLACEMENT_GROUP",
76
80
  :description => "The placement group to place a cluster compute instance",
@@ -137,11 +141,11 @@ class Chef
137
141
  :long => "--bootstrap-version VERSION",
138
142
  :description => "The version of Chef to install",
139
143
  :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
140
-
144
+
141
145
  option :bootstrap_proxy,
142
- :long => "--bootstrap-proxy PROXY_URL",
143
- :description => "The proxy server for the node being bootstrapped",
144
- :proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p }
146
+ :long => "--bootstrap-proxy PROXY_URL",
147
+ :description => "The proxy server for the node being bootstrapped",
148
+ :proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p }
145
149
 
146
150
  option :distro,
147
151
  :short => "-d DISTRO",
@@ -212,7 +216,7 @@ class Chef
212
216
  :long => "--bootstrap-protocol protocol",
213
217
  :description => "protocol to bootstrap windows servers. options: winrm/ssh",
214
218
  :proc => Proc.new { |key| Chef::Config[:knife][:bootstrap_protocol] = key },
215
- :default => "winrm"
219
+ :default => nil
216
220
 
217
221
  option :fqdn,
218
222
  :long => "--fqdn FQDN",
@@ -245,101 +249,14 @@ class Chef
245
249
  option :server_connect_attribute,
246
250
  :long => "--server-connect-attribute ATTRIBUTE",
247
251
  :short => "-a ATTRIBUTE",
248
- :description => "The EC2 server attribute to use for SSH connection",
252
+ :description => "The EC2 server attribute to use for SSH connection. Use this attr for creating VPC instances along with --associate-eip",
249
253
  :default => nil
250
254
 
251
- def tcp_test_winrm(ip_addr, port)
252
- tcp_socket = TCPSocket.new(ip_addr, port)
253
- yield
254
- true
255
- rescue SocketError
256
- sleep 2
257
- false
258
- rescue Errno::ETIMEDOUT
259
- false
260
- rescue Errno::EPERM
261
- false
262
- rescue Errno::ECONNREFUSED
263
- sleep 2
264
- false
265
- rescue Errno::EHOSTUNREACH
266
- sleep 2
267
- false
268
- rescue Errno::ENETUNREACH
269
- sleep 2
270
- false
271
- ensure
272
- tcp_socket && tcp_socket.close
273
- end
274
-
275
- def tcp_test_ssh(hostname, ssh_port)
276
- tcp_socket = TCPSocket.new(hostname, ssh_port)
277
- readable = IO.select([tcp_socket], nil, nil, 5)
278
- if readable
279
- Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
280
- yield
281
- true
282
- else
283
- false
284
- end
285
- rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
286
- sleep 2
287
- false
288
- rescue Errno::EPERM, Errno::ETIMEDOUT
289
- false
290
- # This happens on some mobile phone networks
291
- rescue Errno::ECONNRESET
292
- sleep 2
293
- false
294
- ensure
295
- tcp_socket && tcp_socket.close
296
- end
297
-
298
- def decrypt_admin_password(encoded_password, key)
299
- require 'base64'
300
- require 'openssl'
301
- private_key = OpenSSL::PKey::RSA.new(key)
302
- encrypted_password = Base64.decode64(encoded_password)
303
- password = private_key.private_decrypt(encrypted_password)
304
- password
305
- end
306
-
307
- def check_windows_password_available(server_id)
308
- response = connection.get_password_data(server_id)
309
- if not response.body["passwordData"]
310
- return false
311
- end
312
- response.body["passwordData"]
313
- end
314
-
315
- def windows_password
316
- if not locate_config_value(:winrm_password)
317
- if locate_config_value(:identity_file)
318
- print "\n#{ui.color("Waiting for Windows Admin password to be available", :magenta)}"
319
- print(".") until check_windows_password_available(@server.id) {
320
- sleep 1000 #typically is available after 30 mins
321
- puts("done")
322
- }
323
- response = connection.get_password_data(@server.id)
324
- data = File.read(locate_config_value(:identity_file))
325
- config[:winrm_password] = decrypt_admin_password(response.body["passwordData"], data)
326
- else
327
- ui.error("Cannot find SSH Identity file, required to fetch dynamically generated password")
328
- exit 1
329
- end
330
- else
331
- locate_config_value(:winrm_password)
332
- end
333
- end
334
-
335
- def load_winrm_deps
336
- require 'winrm'
337
- require 'em-winrm'
338
- require 'chef/knife/winrm'
339
- require 'chef/knife/bootstrap_windows_winrm'
340
- require 'chef/knife/bootstrap_windows_ssh'
341
- require 'chef/knife/core/windows_bootstrap_context'
342
- end
255
+ option :associate_public_ip,
256
+ :long => "--associate-public-ip",
257
+ :description => "Associate public ip to VPC instance.",
258
+ :boolean => true,
259
+ :default => false
343
260
 
344
261
  def run
345
262
  $stdout.sync = true
@@ -398,7 +315,7 @@ class Chef
398
315
  begin
399
316
  create_tags(hashed_tags) unless hashed_tags.empty?
400
317
  associate_eip(elastic_ip) if config[:associate_eip]
401
- rescue Fog::Compute::AWS::NotFound, Fog::Errors::Error => e
318
+ rescue Fog::Compute::AWS::NotFound, Fog::Errors::Error
402
319
  raise if (tries -= 1) <= 0
403
320
  ui.warn("server not ready, retrying tag application (retries left: #{tries})")
404
321
  sleep 5
@@ -407,6 +324,10 @@ class Chef
407
324
 
408
325
  if vpc_mode?
409
326
  msg_pair("Subnet ID", @server.subnet_id)
327
+ msg_pair("Tenancy", @server.tenancy)
328
+ if config[:associate_public_ip]
329
+ msg_pair("Public DNS Name", @server.dns_name)
330
+ end
410
331
  if elastic_ip
411
332
  msg_pair("Public IP Address", @server.public_ip_address)
412
333
  end
@@ -417,10 +338,10 @@ class Chef
417
338
  end
418
339
  msg_pair("Private IP Address", @server.private_ip_address)
419
340
 
420
-
421
341
  #Check if Server is Windows or Linux
422
342
  if is_image_windows?
423
343
  protocol = locate_config_value(:bootstrap_protocol)
344
+ protocol ||= 'winrm'
424
345
  # Set distro to windows-chef-client-msi
425
346
  config[:distro] = "windows-chef-client-msi" if (config[:distro].nil? || config[:distro] == "chef-full")
426
347
  if protocol == 'winrm'
@@ -439,11 +360,12 @@ class Chef
439
360
  }
440
361
  ssh_override_winrm
441
362
  end
442
- bootstrap_for_windows_node(@server,ssh_connect_host).run
363
+ bootstrap_for_windows_node(@server, ssh_connect_host).run
443
364
  else
444
- wait_for_sshd(ssh_connect_host)
445
- ssh_override_winrm
446
- bootstrap_for_linux_node(@server,ssh_connect_host).run
365
+ print "\n#{ui.color("Waiting for sshd", :magenta)}"
366
+ wait_for_sshd(ssh_connect_host)
367
+ ssh_override_winrm
368
+ bootstrap_for_linux_node(@server, ssh_connect_host).run
447
369
  end
448
370
 
449
371
  puts "\n"
@@ -480,6 +402,10 @@ class Chef
480
402
  end
481
403
  if vpc_mode?
482
404
  msg_pair("Subnet ID", @server.subnet_id)
405
+ msg_pair("Tenancy", @server.tenancy)
406
+ if config[:associate_public_ip]
407
+ msg_pair("Public DNS Name", @server.dns_name)
408
+ end
483
409
  else
484
410
  msg_pair("Public DNS Name", @server.dns_name)
485
411
  msg_pair("Public IP Address", @server.public_ip_address)
@@ -511,36 +437,35 @@ class Chef
511
437
  end
512
438
 
513
439
  def fetch_server_fqdn(ip_addr)
514
- require 'resolv'
515
- Resolv.getname(ip_addr)
440
+ require 'resolv'
441
+ Resolv.getname(ip_addr)
516
442
  end
517
443
 
518
444
  def bootstrap_for_windows_node(server, fqdn)
519
- if locate_config_value(:bootstrap_protocol) == 'winrm'
520
- if locate_config_value(:kerberos_realm)
521
- #Fetch AD/WINS based fqdn if any for Kerberos-based Auth
522
- fqdn = locate_config_value(:fqdn) || fetch_server_fqdn(server.private_ip_address)
523
- end
524
- bootstrap = Chef::Knife::BootstrapWindowsWinrm.new
525
- bootstrap.config[:winrm_user] = locate_config_value(:winrm_user)
526
- bootstrap.config[:winrm_password] = windows_password
527
- bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport)
528
- bootstrap.config[:kerberos_keytab_file] = locate_config_value(:kerberos_keytab_file)
529
- bootstrap.config[:kerberos_realm] = locate_config_value(:kerberos_realm)
530
- bootstrap.config[:kerberos_service] = locate_config_value(:kerberos_service)
531
- bootstrap.config[:ca_trust_file] = locate_config_value(:ca_trust_file)
532
- bootstrap.config[:winrm_port] = locate_config_value(:winrm_port)
533
-
445
+ if locate_config_value(:bootstrap_protocol) == 'winrm' || locate_config_value(:bootstrap_protocol) == nil
446
+ if locate_config_value(:kerberos_realm)
447
+ #Fetch AD/WINS based fqdn if any for Kerberos-based Auth
448
+ fqdn = locate_config_value(:fqdn) || fetch_server_fqdn(server.private_ip_address)
449
+ end
450
+ bootstrap = Chef::Knife::BootstrapWindowsWinrm.new
451
+ bootstrap.config[:winrm_user] = locate_config_value(:winrm_user)
452
+ bootstrap.config[:winrm_password] = windows_password
453
+ bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport)
454
+ bootstrap.config[:kerberos_keytab_file] = locate_config_value(:kerberos_keytab_file)
455
+ bootstrap.config[:kerberos_realm] = locate_config_value(:kerberos_realm)
456
+ bootstrap.config[:kerberos_service] = locate_config_value(:kerberos_service)
457
+ bootstrap.config[:ca_trust_file] = locate_config_value(:ca_trust_file)
458
+ bootstrap.config[:winrm_port] = locate_config_value(:winrm_port)
534
459
  elsif locate_config_value(:bootstrap_protocol) == 'ssh'
535
- bootstrap = Chef::Knife::BootstrapWindowsSsh.new
536
- bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
537
- bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
538
- bootstrap.config[:ssh_port] = locate_config_value(:ssh_port)
539
- bootstrap.config[:identity_file] = locate_config_value(:identity_file)
540
- bootstrap.config[:no_host_key_verify] = locate_config_value(:no_host_key_verify)
460
+ bootstrap = Chef::Knife::BootstrapWindowsSsh.new
461
+ bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
462
+ bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
463
+ bootstrap.config[:ssh_port] = locate_config_value(:ssh_port)
464
+ bootstrap.config[:identity_file] = locate_config_value(:identity_file)
465
+ bootstrap.config[:no_host_key_verify] = locate_config_value(:no_host_key_verify)
541
466
  else
542
- ui.error("Unsupported Bootstrapping Protocol. Supported : winrm, ssh")
543
- exit 1
467
+ ui.error("Unsupported Bootstrapping Protocol. Supported : winrm, ssh")
468
+ exit 1
544
469
  end
545
470
  bootstrap.name_args = [fqdn]
546
471
  bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.id
@@ -572,7 +497,6 @@ class Chef
572
497
  end
573
498
 
574
499
  def validate!
575
-
576
500
  super([:image, :aws_ssh_key_id, :aws_access_key_id, :aws_secret_access_key])
577
501
 
578
502
  if ami.nil?
@@ -584,11 +508,22 @@ class Chef
584
508
  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.")
585
509
  exit 1
586
510
  end
511
+
587
512
  if !vpc_mode? and !!config[:private_ip_address]
588
513
  ui.error("You can only specify a private IP address if you are using VPC.")
589
514
  exit 1
590
515
  end
591
516
 
517
+ if config[:dedicated_instance] and !vpc_mode?
518
+ ui.error("You can only specify a Dedicated Instance if you are using VPC.")
519
+ exit 1
520
+ end
521
+
522
+ if !vpc_mode? and config[:associate_public_ip]
523
+ ui.error("--associate-public-ip option only applies to VPC instances, and you have not specified a subnet id.")
524
+ exit 1
525
+ end
526
+
592
527
  if config[:associate_eip]
593
528
  eips = connection.addresses.collect{|addr| addr if addr.domain == eip_scope}.compact
594
529
 
@@ -629,6 +564,8 @@ class Chef
629
564
  server_def[:private_ip_address] = locate_config_value(:private_ip_address) if vpc_mode?
630
565
  server_def[:placement_group] = locate_config_value(:placement_group)
631
566
  server_def[:iam_instance_profile_name] = locate_config_value(:iam_instance_profile)
567
+ server_def[:tenancy] = "dedicated" if vpc_mode? and locate_config_value(:dedicated_instance)
568
+ server_def[:associate_public_ip] = locate_config_value(:associate_public_ip) if vpc_mode? and config[:associate_public_ip]
632
569
 
633
570
  if Chef::Config[:knife][:aws_user_data]
634
571
  begin
@@ -683,9 +620,14 @@ class Chef
683
620
  end
684
621
 
685
622
  def wait_for_tunnelled_sshd(hostname)
686
- print(".")
687
- print(".") until tunnel_test_ssh(ssh_connect_host) {
688
- sleep @initial_sleep_delay ||= (vpc_mode? ? 40 : 10)
623
+ initial = true
624
+ print(".") until tunnel_test_ssh(hostname) {
625
+ if initial
626
+ initial = false
627
+ sleep (vpc_mode? ? 40 : 10)
628
+ else
629
+ sleep 10
630
+ end
689
631
  puts("done")
690
632
  }
691
633
  end
@@ -707,18 +649,28 @@ class Chef
707
649
  end
708
650
 
709
651
  def wait_for_direct_sshd(hostname, ssh_port)
710
- print(".") until tcp_test_ssh(ssh_connect_host, ssh_port) {
711
- sleep @initial_sleep_delay ||= (vpc_mode? ? 40 : 10)
652
+ initial = true
653
+ print(".") until tcp_test_ssh(hostname, ssh_port) {
654
+ if initial
655
+ initial = false
656
+ sleep (vpc_mode? ? 40 : 10)
657
+ else
658
+ sleep 10
659
+ end
712
660
  puts("done")
713
661
  }
714
662
  end
715
663
 
716
664
  def ssh_connect_host
717
665
  @ssh_connect_host ||= if config[:server_connect_attribute]
718
- server.send(config[:server_connect_attribute])
719
- else
720
- vpc_mode? ? server.private_ip_address : server.dns_name
721
- end
666
+ server.send(config[:server_connect_attribute])
667
+ else
668
+ if vpc_mode? && !config[:associate_public_ip]
669
+ server.private_ip_address
670
+ else
671
+ server.dns_name
672
+ end
673
+ end
722
674
  end
723
675
 
724
676
  def create_tags(hashed_tags)
@@ -754,6 +706,107 @@ class Chef
754
706
  config[:identity_file] = locate_config_value(:kerberos_keytab_file)
755
707
  end
756
708
  end
709
+
710
+ def tcp_test_winrm(ip_addr, port)
711
+ tcp_socket = TCPSocket.new(ip_addr, port)
712
+ yield
713
+ true
714
+ rescue SocketError
715
+ sleep 2
716
+ false
717
+ rescue Errno::ETIMEDOUT
718
+ false
719
+ rescue Errno::EPERM
720
+ false
721
+ rescue Errno::ECONNREFUSED
722
+ sleep 2
723
+ false
724
+ rescue Errno::EHOSTUNREACH
725
+ sleep 2
726
+ false
727
+ rescue Errno::ENETUNREACH
728
+ sleep 2
729
+ false
730
+ ensure
731
+ tcp_socket && tcp_socket.close
732
+ end
733
+
734
+ def tcp_test_ssh(hostname, ssh_port)
735
+ tcp_socket = TCPSocket.new(hostname, ssh_port)
736
+ readable = IO.select([tcp_socket], nil, nil, 5)
737
+ if readable
738
+ ssh_banner = tcp_socket.gets
739
+ if ssh_banner.nil? or ssh_banner.empty?
740
+ false
741
+ else
742
+ Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{ssh_banner}")
743
+ yield
744
+ true
745
+ end
746
+ else
747
+ false
748
+ end
749
+ rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
750
+ Chef::Log.debug("ssh failed to connect: #{hostname}")
751
+ sleep 2
752
+ false
753
+ rescue Errno::EPERM, Errno::ETIMEDOUT
754
+ Chef::Log.debug("ssh timed out: #{hostname}")
755
+ false
756
+ # This happens on some mobile phone networks
757
+ rescue Errno::ECONNRESET
758
+ Chef::Log.debug("ssh reset its connection: #{hostname}")
759
+ sleep 2
760
+ false
761
+ ensure
762
+ tcp_socket && tcp_socket.close
763
+ end
764
+
765
+ def decrypt_admin_password(encoded_password, key)
766
+ require 'base64'
767
+ require 'openssl'
768
+ private_key = OpenSSL::PKey::RSA.new(key)
769
+ encrypted_password = Base64.decode64(encoded_password)
770
+ password = private_key.private_decrypt(encrypted_password)
771
+ password
772
+ end
773
+
774
+ def check_windows_password_available(server_id)
775
+ response = connection.get_password_data(server_id)
776
+ if not response.body["passwordData"]
777
+ return false
778
+ end
779
+ response.body["passwordData"]
780
+ end
781
+
782
+ def windows_password
783
+ if not locate_config_value(:winrm_password)
784
+ if locate_config_value(:identity_file)
785
+ print "\n#{ui.color("Waiting for Windows Admin password to be available", :magenta)}"
786
+ print(".") until check_windows_password_available(@server.id) {
787
+ sleep 1000 #typically is available after 30 mins
788
+ puts("done")
789
+ }
790
+ response = connection.get_password_data(@server.id)
791
+ data = File.read(locate_config_value(:identity_file))
792
+ config[:winrm_password] = decrypt_admin_password(response.body["passwordData"], data)
793
+ else
794
+ ui.error("Cannot find SSH Identity file, required to fetch dynamically generated password")
795
+ exit 1
796
+ end
797
+ else
798
+ locate_config_value(:winrm_password)
799
+ end
800
+ end
801
+
802
+ def load_winrm_deps
803
+ require 'winrm'
804
+ require 'em-winrm'
805
+ require 'chef/knife/winrm'
806
+ require 'chef/knife/bootstrap_windows_winrm'
807
+ require 'chef/knife/bootstrap_windows_ssh'
808
+ require 'chef/knife/core/windows_bootstrap_context'
809
+ end
757
810
  end
758
811
  end
759
812
  end
@@ -1,6 +1,6 @@
1
1
  module Knife
2
2
  module Ec2
3
- VERSION = "0.6.6"
3
+ VERSION = "0.8.0"
4
4
  MAJOR, MINOR, TINY = VERSION.split('.')
5
5
  end
6
6
  end
data/spec/spec_helper.rb CHANGED
@@ -5,3 +5,13 @@ require 'chef/knife/ec2_server_create'
5
5
  require 'chef/knife/ec2_instance_data'
6
6
  require 'chef/knife/ec2_server_delete'
7
7
  require 'chef/knife/ec2_server_list'
8
+
9
+ # Clear config between each example
10
+ # to avoid dependencies between examples
11
+ RSpec.configure do |c|
12
+ c.before(:each) do
13
+ Chef::Config.reset
14
+ Chef::Config[:knife] ={}
15
+ end
16
+ end
17
+
@@ -23,7 +23,7 @@ require 'chef/knife/bootstrap_windows_winrm'
23
23
  require 'chef/knife/bootstrap_windows_ssh'
24
24
 
25
25
  describe Chef::Knife::Ec2ServerCreate do
26
- before do
26
+ before(:each) do
27
27
  @knife_ec2_create = Chef::Knife::Ec2ServerCreate.new
28
28
  @knife_ec2_create.initial_sleep_delay = 0
29
29
  @knife_ec2_create.stub(:tcp_test_ssh).and_return(true)
@@ -494,6 +494,33 @@ describe Chef::Knife::Ec2ServerCreate do
494
494
  @knife_ec2_create.ui.stub(:error)
495
495
  end
496
496
 
497
+ describe "when reading aws_credential_file" do
498
+ before do
499
+ Chef::Config[:knife].delete(:aws_access_key_id)
500
+ Chef::Config[:knife].delete(:aws_secret_access_key)
501
+
502
+ Chef::Config[:knife][:aws_credential_file] = '/apple/pear'
503
+ @access_key_id = 'access_key_id'
504
+ @secret_key = 'secret_key'
505
+ end
506
+
507
+ it "reads UNIX Line endings" do
508
+ File.stub(:read).
509
+ and_return("AWSAccessKeyId=#{@access_key_id}\nAWSSecretKey=#{@secret_key}")
510
+ @knife_ec2_create.validate!
511
+ Chef::Config[:knife][:aws_access_key_id].should == @access_key_id
512
+ Chef::Config[:knife][:aws_secret_access_key].should == @secret_key
513
+ end
514
+
515
+ it "reads DOS Line endings" do
516
+ File.stub(:read).
517
+ and_return("AWSAccessKeyId=#{@access_key_id}\r\nAWSSecretKey=#{@secret_key}")
518
+ @knife_ec2_create.validate!
519
+ Chef::Config[:knife][:aws_access_key_id].should == @access_key_id
520
+ Chef::Config[:knife][:aws_secret_access_key].should == @secret_key
521
+ end
522
+ end
523
+
497
524
  it "disallows security group names when using a VPC" do
498
525
  @knife_ec2_create.config[:subnet_id] = 'subnet-1a2b3c4d'
499
526
  @knife_ec2_create.config[:security_group_ids] = 'sg-aabbccdd'
@@ -514,6 +541,13 @@ describe Chef::Knife::Ec2ServerCreate do
514
541
 
515
542
  lambda { @knife_ec2_create.validate! }.should raise_error SystemExit
516
543
  end
544
+
545
+ it "disallows associate public ip option when not using a VPC" do
546
+ @knife_ec2_create.config[:associate_public_ip] = true
547
+ @knife_ec2_create.config[:subnet_id] = nil
548
+
549
+ lambda { @knife_ec2_create.validate! }.should raise_error SystemExit
550
+ end
517
551
  end
518
552
 
519
553
  describe "when creating the server definition" do
@@ -597,6 +631,37 @@ describe Chef::Knife::Ec2ServerCreate do
597
631
 
598
632
  server_def[:iam_instance_profile_name].should == nil
599
633
  end
634
+
635
+ it 'Set Tenancy Dedicated when both VPC mode and Flag is True' do
636
+ @knife_ec2_create.config[:dedicated_instance] = true
637
+ @knife_ec2_create.stub(:vpc_mode? => true)
638
+
639
+ server_def = @knife_ec2_create.create_server_def
640
+ server_def[:tenancy].should == "dedicated"
641
+ end
642
+
643
+ it 'Tenancy should be default with no vpc mode even is specified' do
644
+ @knife_ec2_create.config[:dedicated_instance] = true
645
+
646
+ server_def = @knife_ec2_create.create_server_def
647
+ server_def[:tenancy].should == nil
648
+ end
649
+
650
+ it 'Tenancy should be default with vpc but not requested' do
651
+ @knife_ec2_create.stub(:vpc_mode? => true)
652
+
653
+ server_def = @knife_ec2_create.create_server_def
654
+ server_def[:tenancy].should == nil
655
+ end
656
+
657
+ it "sets associate_public_ip to true if specified and in vpc_mode" do
658
+ @knife_ec2_create.config[:subnet_id] = 'subnet-1a2b3c4d'
659
+ @knife_ec2_create.config[:associate_public_ip] = true
660
+ server_def = @knife_ec2_create.create_server_def
661
+
662
+ server_def[:subnet_id].should == 'subnet-1a2b3c4d'
663
+ server_def[:associate_public_ip].should == true
664
+ end
600
665
  end
601
666
 
602
667
  describe "ssh_connect_host" do
@@ -620,7 +685,6 @@ describe Chef::Knife::Ec2ServerCreate do
620
685
  @knife_ec2_create.stub(:vpc_mode? => true)
621
686
  @knife_ec2_create.ssh_connect_host.should == 'private_ip'
622
687
  end
623
-
624
688
  end
625
689
 
626
690
  describe "with custom server attribute" do
@@ -630,4 +694,29 @@ describe Chef::Knife::Ec2ServerCreate do
630
694
  end
631
695
  end
632
696
  end
697
+
698
+ describe "tcp_test_ssh" do
699
+ # Normally we would only get the header after we send a client header, e.g. 'SSH-2.0-client'
700
+ it "should return true if we get an ssh header" do
701
+ @knife_ec2_create = Chef::Knife::Ec2ServerCreate.new
702
+ TCPSocket.stub(:new).and_return(StringIO.new("SSH-2.0-OpenSSH_6.1p1 Debian-4"))
703
+ IO.stub(:select).and_return(true)
704
+ @knife_ec2_create.should_receive(:tcp_test_ssh).and_yield.and_return(true)
705
+ @knife_ec2_create.tcp_test_ssh("blackhole.ninja", 22) {nil}
706
+ end
707
+
708
+ it "should return false if we do not get an ssh header" do
709
+ @knife_ec2_create = Chef::Knife::Ec2ServerCreate.new
710
+ TCPSocket.stub(:new).and_return(StringIO.new(""))
711
+ IO.stub(:select).and_return(true)
712
+ @knife_ec2_create.tcp_test_ssh("blackhole.ninja", 22).should be_false
713
+ end
714
+
715
+ it "should return false if the socket isn't ready" do
716
+ @knife_ec2_create = Chef::Knife::Ec2ServerCreate.new
717
+ TCPSocket.stub(:new)
718
+ IO.stub(:select).and_return(false)
719
+ @knife_ec2_create.tcp_test_ssh("blackhole.ninja", 22).should be_false
720
+ end
721
+ end
633
722
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-ec2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.6
5
- prerelease:
4
+ version: 0.8.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Adam Jacob
@@ -10,60 +9,67 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-10-31 00:00:00.000000000 Z
12
+ date: 2014-03-10 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: fog
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
18
  - - ~>
21
19
  - !ruby/object:Gem::Version
22
- version: 1.15.0
20
+ version: 1.20.0
23
21
  type: :runtime
24
22
  prerelease: false
25
23
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
24
  requirements:
28
25
  - - ~>
29
26
  - !ruby/object:Gem::Version
30
- version: 1.15.0
27
+ version: 1.20.0
31
28
  - !ruby/object:Gem::Dependency
32
- name: chef
29
+ name: knife-windows
33
30
  requirement: !ruby/object:Gem::Requirement
34
- none: false
35
31
  requirements:
36
32
  - - ! '>='
37
33
  - !ruby/object:Gem::Version
38
- version: 0.10.10
34
+ version: 0.5.12
39
35
  type: :runtime
40
36
  prerelease: false
41
37
  version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
38
  requirements:
44
39
  - - ! '>='
45
40
  - !ruby/object:Gem::Version
46
- version: 0.10.10
41
+ version: 0.5.12
47
42
  - !ruby/object:Gem::Dependency
48
- name: knife-windows
43
+ name: mixlib-config
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '2.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '2.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: chef
49
58
  requirement: !ruby/object:Gem::Requirement
50
- none: false
51
59
  requirements:
52
60
  - - ! '>='
53
61
  - !ruby/object:Gem::Version
54
- version: 0.5.12
55
- type: :runtime
62
+ version: 0.10.10
63
+ type: :development
56
64
  prerelease: false
57
65
  version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
66
  requirements:
60
67
  - - ! '>='
61
68
  - !ruby/object:Gem::Version
62
- version: 0.5.12
69
+ version: 0.10.10
63
70
  - !ruby/object:Gem::Dependency
64
71
  name: rspec
65
72
  requirement: !ruby/object:Gem::Requirement
66
- none: false
67
73
  requirements:
68
74
  - - ~>
69
75
  - !ruby/object:Gem::Version
@@ -71,7 +77,6 @@ dependencies:
71
77
  type: :development
72
78
  prerelease: false
73
79
  version_requirements: !ruby/object:Gem::Requirement
74
- none: false
75
80
  requirements:
76
81
  - - ~>
77
82
  - !ruby/object:Gem::Version
@@ -79,7 +84,6 @@ dependencies:
79
84
  - !ruby/object:Gem::Dependency
80
85
  name: rake
81
86
  requirement: !ruby/object:Gem::Requirement
82
- none: false
83
87
  requirements:
84
88
  - - ~>
85
89
  - !ruby/object:Gem::Version
@@ -87,7 +91,6 @@ dependencies:
87
91
  type: :development
88
92
  prerelease: false
89
93
  version_requirements: !ruby/object:Gem::Requirement
90
- none: false
91
94
  requirements:
92
95
  - - ~>
93
96
  - !ruby/object:Gem::Version
@@ -95,7 +98,6 @@ dependencies:
95
98
  - !ruby/object:Gem::Dependency
96
99
  name: sdoc
97
100
  requirement: !ruby/object:Gem::Requirement
98
- none: false
99
101
  requirements:
100
102
  - - ~>
101
103
  - !ruby/object:Gem::Version
@@ -103,12 +105,11 @@ dependencies:
103
105
  type: :development
104
106
  prerelease: false
105
107
  version_requirements: !ruby/object:Gem::Requirement
106
- none: false
107
108
  requirements:
108
109
  - - ~>
109
110
  - !ruby/object:Gem::Version
110
111
  version: '0.3'
111
- description: EC2 Support for Chef\'s Knife Command
112
+ description: EC2 Support for Chef's Knife Command
112
113
  email:
113
114
  - adam@opscode.com
114
115
  - schisamo@opscode.com
@@ -118,6 +119,9 @@ extra_rdoc_files: []
118
119
  files:
119
120
  - .gitignore
120
121
  - .travis.yml
122
+ - CHANGELOG.md
123
+ - CONTRIBUTING.md
124
+ - DOC_CHANGES.md
121
125
  - Gemfile
122
126
  - LICENSE
123
127
  - README.md
@@ -136,28 +140,27 @@ files:
136
140
  homepage: https://github.com/opscode/knife-ec2
137
141
  licenses:
138
142
  - Apache 2.0
143
+ metadata: {}
139
144
  post_install_message:
140
145
  rdoc_options: []
141
146
  require_paths:
142
147
  - lib
143
148
  required_ruby_version: !ruby/object:Gem::Requirement
144
- none: false
145
149
  requirements:
146
150
  - - ! '>='
147
151
  - !ruby/object:Gem::Version
148
152
  version: '0'
149
153
  required_rubygems_version: !ruby/object:Gem::Requirement
150
- none: false
151
154
  requirements:
152
155
  - - ! '>='
153
156
  - !ruby/object:Gem::Version
154
157
  version: '0'
155
158
  requirements: []
156
159
  rubyforge_project:
157
- rubygems_version: 1.8.23
160
+ rubygems_version: 2.1.11
158
161
  signing_key:
159
- specification_version: 3
160
- summary: EC2 Support for Chef\'s Knife Command
162
+ specification_version: 4
163
+ summary: EC2 Support for Chef's Knife Command
161
164
  test_files:
162
165
  - spec/spec_helper.rb
163
166
  - spec/unit/ec2_server_create_spec.rb