knife-ec2 0.6.6 → 0.8.0

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.
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