knife-ec2 0.6.4 → 0.6.6.rc.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.travis.yml +4 -0
- data/Gemfile +1 -7
- data/README.md +114 -0
- data/Rakefile +2 -1
- data/knife-ec2.gemspec +23 -18
- data/lib/chef/knife/ec2_base.rb +30 -2
- data/lib/chef/knife/ec2_server_create.rb +209 -22
- data/lib/chef/knife/ec2_server_delete.rb +33 -2
- data/lib/chef/knife/ec2_server_list.rb +79 -1
- data/lib/knife-ec2/version.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/ec2_server_create_spec.rb +253 -25
- data/spec/unit/ec2_server_delete_spec.rb +139 -0
- metadata +128 -112
- data/.rspec +0 -2
- data/Gemfile.lock +0 -104
- data/README.rdoc +0 -87
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
Knife EC2
|
2
|
+
=========
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/knife-ec2.png)](http://badge.fury.io/rb/knife-ec2)
|
4
|
+
[![Build Status](https://travis-ci.org/opscode/knife-ec2.png?branch=master)](https://travis-ci.org/opscode/knife-ec2)
|
5
|
+
[![Dependency Status](https://gemnasium.com/opscode/knife-ec2.png)](https://gemnasium.com/opscode/knife-ec2)
|
6
|
+
|
7
|
+
This is the official Opscode Knife plugin for EC2. This plugin gives knife the ability to create, bootstrap, and manage EC2 instances.
|
8
|
+
|
9
|
+
|
10
|
+
Installation
|
11
|
+
------------
|
12
|
+
If you're using bundler, simply add Chef and Knife EC2 to your `Gemfile`:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'chef'
|
16
|
+
gem 'knife-ec2'
|
17
|
+
```
|
18
|
+
|
19
|
+
If you are not using bundler, you can install the gem manually. Be sure you are running Chef 0.10.10 or higher, as earlier versions do not support plugins.
|
20
|
+
|
21
|
+
$ gem install chef
|
22
|
+
|
23
|
+
This plugin is distributed as a Ruby Gem. To install it, run:
|
24
|
+
|
25
|
+
$ gem install knife-ec2
|
26
|
+
|
27
|
+
Depending on your system's configuration, you may need to run this command with root privileges.
|
28
|
+
|
29
|
+
|
30
|
+
Configuration
|
31
|
+
-------------
|
32
|
+
In order to communicate with the Amazon's EC2 API you will have to tell Knife about your AWS Access Key and Secret Access Key. The easiest way to accomplish this is to create some entries in your `knife.rb` file:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
knife[:aws_access_key_id] = "Your AWS Access Key ID"
|
36
|
+
knife[:aws_secret_access_key] = "Your AWS Secret Access Key"
|
37
|
+
```
|
38
|
+
|
39
|
+
If your `knife.rb` file will be checked into a SCM system (ie readable by others) you may want to read the values from environment variables:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
knife[:aws_access_key_id] = ENV['AWS_ACCESS_KEY_ID']
|
43
|
+
knife[:aws_secret_access_key] = ENV['AWS_SECRET_ACCESS_KEY']
|
44
|
+
```
|
45
|
+
|
46
|
+
You also have the option of passing your AWS API Key/Secret into the individual knife subcommands using the `-A` (or `--aws-access-key-id`) `-K` (or `--aws-secret-access-key`) command options
|
47
|
+
|
48
|
+
```bash
|
49
|
+
# provision a new m1.small Ubuntu 10.04 webserver
|
50
|
+
$ knife ec2 server create -r 'role[webserver]' -I ami-7000f019 -f m1.small -A 'Your AWS Access Key ID' -K "Your AWS Secret Access Key"
|
51
|
+
```
|
52
|
+
|
53
|
+
If you are working with Amazon's command line tools, there is a good chance
|
54
|
+
you already have a file with these keys somewhere in this format:
|
55
|
+
|
56
|
+
AWSAccessKeyId=Your AWS Access Key ID
|
57
|
+
AWSSecretKey=Your AWS Secret Access Key
|
58
|
+
|
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"
|
63
|
+
|
64
|
+
Additionally the following options may be set in your `knife.rb`:
|
65
|
+
|
66
|
+
- flavor
|
67
|
+
- image
|
68
|
+
- availability_zone
|
69
|
+
- aws_ssh_key_id
|
70
|
+
- region
|
71
|
+
- distro
|
72
|
+
- template_file
|
73
|
+
|
74
|
+
|
75
|
+
Subcommands
|
76
|
+
-----------
|
77
|
+
This plugin provides the following Knife subcommands. Specific command options can be found by invoking the subcommand with a `--help` flag
|
78
|
+
|
79
|
+
|
80
|
+
#### `knife ec2 server create`
|
81
|
+
Provisions a new server in the Amazon EC2 and then perform a Chef bootstrap (using the SSH protocol). The goal of the bootstrap is to get Chef installed on the target system so it can run Chef Client with a Chef Server. The main assumption is a baseline OS installation exists (provided by the provisioning). It is primarily intended for Chef Client systems that talk to a Chef server.
|
82
|
+
|
83
|
+
#### `knife ec2 server delete`
|
84
|
+
Deletes an existing server in the currently configured AWS account. **By default, this does not delete the associated node and client objects from the Chef server. To do so, add the `--purge` flag**
|
85
|
+
|
86
|
+
#### `knife ec2 server list`
|
87
|
+
Outputs a list of all servers in the currently configured AWS account. **Note, this shows all instances associated with the account, some of which may not be currently managed by the Chef server.**
|
88
|
+
|
89
|
+
#### `knife ec2 instance data`
|
90
|
+
Generates instance metadata in meant to be used with Opscode's custom AMIs. This will read your knife configuration `~/.chef/knife.rb` for the validation certificate and Chef server URL to use and output in JSON format. The subcommand also accepts a list of roles/recipes that will be in the node's initial run list.
|
91
|
+
|
92
|
+
**Note**: Using Opscode's custom AMIs reflect an older way of launching instances in EC2 for Chef and should be considered DEPRECATED. Leveraging this plugins's `knife ec2 server create` subcommands with a base AMIs directly from your Linux distribution (ie Ubuntu AMIs from Canonical) is much preferred and more flexible. Although this subcommand will remain, the Opscode custom AMIs are currently out of date.
|
93
|
+
|
94
|
+
In-depth usage instructions can be found on the [Chef Wiki](http://wiki.opscode.com/display/chef/EC2+Bootstrap+Fast+Start+Guide).
|
95
|
+
|
96
|
+
License and Authors
|
97
|
+
-------------------
|
98
|
+
- Author:: Adam Jacob (<adam@opscode.com>)
|
99
|
+
|
100
|
+
```text
|
101
|
+
Copyright 2009-2013 Opscode, Inc.
|
102
|
+
|
103
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
104
|
+
you may not use this file except in compliance with the License.
|
105
|
+
You may obtain a copy of the License at
|
106
|
+
|
107
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
108
|
+
|
109
|
+
Unless required by applicable law or agreed to in writing, software
|
110
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
111
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
112
|
+
See the License for the specific language governing permissions and
|
113
|
+
limitations under the License.
|
114
|
+
```
|
data/Rakefile
CHANGED
@@ -27,8 +27,9 @@ require 'rdoc/task'
|
|
27
27
|
|
28
28
|
begin
|
29
29
|
require 'sdoc'
|
30
|
+
require 'rdoc/task'
|
30
31
|
|
31
|
-
|
32
|
+
RDoc::Task.new do |rdoc|
|
32
33
|
rdoc.title = "Chef Ruby API Documentation"
|
33
34
|
rdoc.main = "README.rdoc"
|
34
35
|
rdoc.options << '--fmt' << 'shtml' # explictly set shtml generator
|
data/knife-ec2.gemspec
CHANGED
@@ -1,24 +1,29 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path(
|
3
|
-
require
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'knife-ec2/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name
|
7
|
-
s.version
|
8
|
-
s.
|
9
|
-
s.
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
s.
|
14
|
-
s.extra_rdoc_files = ["README.rdoc", "LICENSE" ]
|
6
|
+
s.name = 'knife-ec2'
|
7
|
+
s.version = Knife::Ec2::VERSION
|
8
|
+
s.authors = ['Adam Jacob', 'Seth Chisamore']
|
9
|
+
s.email = ['adam@opscode.com', 'schisamo@opscode.com']
|
10
|
+
s.homepage = 'https://github.com/opscode/knife-ec2'
|
11
|
+
s.summary = %q{EC2 Support for Chef\'s Knife Command}
|
12
|
+
s.description = s.summary
|
13
|
+
s.license = 'Apache 2.0'
|
15
14
|
|
16
|
-
s.files
|
17
|
-
s.test_files
|
18
|
-
s.executables
|
19
|
-
s.add_dependency "fog", "~> 1.6"
|
20
|
-
s.add_dependency "chef", ">= 0.10.10"
|
21
|
-
%w(rspec-core rspec-expectations rspec-mocks rspec_junit_formatter).each { |gem| s.add_development_dependency gem }
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
18
|
|
23
|
-
s.
|
19
|
+
s.add_dependency 'fog', '~> 1.15.0'
|
20
|
+
s.add_dependency 'chef', '>= 0.10.10'
|
21
|
+
s.add_dependency 'knife-windows', '>= 0.5.12'
|
22
|
+
|
23
|
+
s.add_development_dependency 'rspec', '~> 2.14'
|
24
|
+
s.add_development_dependency 'rake', '~> 10.1'
|
25
|
+
s.add_development_dependency 'sdoc', '~> 0.3'
|
26
|
+
|
27
|
+
s.require_paths = ['lib']
|
24
28
|
end
|
29
|
+
|
data/lib/chef/knife/ec2_base.rb
CHANGED
@@ -34,6 +34,11 @@ class Chef
|
|
34
34
|
require 'chef/json_compat'
|
35
35
|
end
|
36
36
|
|
37
|
+
option :aws_credential_file,
|
38
|
+
:long => "--aws-credential-file FILE",
|
39
|
+
:description => "File containing AWS credentials as used by aws cmdline tools",
|
40
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:aws_credential_file] = key }
|
41
|
+
|
37
42
|
option :aws_access_key_id,
|
38
43
|
:short => "-A ID",
|
39
44
|
:long => "--aws-access-key-id KEY",
|
@@ -75,9 +80,26 @@ class Chef
|
|
75
80
|
end
|
76
81
|
end
|
77
82
|
|
83
|
+
def is_image_windows?
|
84
|
+
image_info = connection.images.get(@server.image_id)
|
85
|
+
return image_info.platform == 'windows'
|
86
|
+
end
|
87
|
+
|
78
88
|
def validate!(keys=[:aws_access_key_id, :aws_secret_access_key])
|
79
89
|
errors = []
|
80
90
|
|
91
|
+
unless Chef::Config[:knife][:aws_credential_file].nil?
|
92
|
+
unless (Chef::Config[:knife].keys & [:aws_access_key_id, :aws_secret_access_key]).empty?
|
93
|
+
errors << "Either provide a credentials file or the access key and secret keys but not both."
|
94
|
+
end
|
95
|
+
# File format:
|
96
|
+
# AWSAccessKeyId=somethingsomethingdarkside
|
97
|
+
# AWSSecretKey=somethingsomethingcomplete
|
98
|
+
entries = Hash[*File.read(Chef::Config[:knife][:aws_credential_file]).split(/[=\n]/)]
|
99
|
+
Chef::Config[:knife][:aws_access_key_id] = entries['AWSAccessKeyId']
|
100
|
+
Chef::Config[:knife][:aws_secret_access_key] = entries['AWSSecretKey']
|
101
|
+
end
|
102
|
+
|
81
103
|
keys.each do |k|
|
82
104
|
pretty_key = k.to_s.gsub(/_/, ' ').gsub(/\w+/){ |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
|
83
105
|
if Chef::Config[:knife][k].nil?
|
@@ -91,7 +113,13 @@ class Chef
|
|
91
113
|
end
|
92
114
|
|
93
115
|
end
|
116
|
+
|
117
|
+
def iam_name_from_profile(profile)
|
118
|
+
# The IAM profile object only contains the name as part of the arn
|
119
|
+
if profile && profile.key?('arn')
|
120
|
+
name = profile['arn'].split('/')[-1]
|
121
|
+
end
|
122
|
+
name ||= ''
|
123
|
+
end
|
94
124
|
end
|
95
125
|
end
|
96
|
-
|
97
|
-
|
@@ -18,13 +18,14 @@
|
|
18
18
|
#
|
19
19
|
|
20
20
|
require 'chef/knife/ec2_base'
|
21
|
+
require 'chef/knife/winrm_base'
|
21
22
|
|
22
23
|
class Chef
|
23
24
|
class Knife
|
24
25
|
class Ec2ServerCreate < Knife
|
25
26
|
|
26
27
|
include Knife::Ec2Base
|
27
|
-
|
28
|
+
include Knife::WinrmBase
|
28
29
|
deps do
|
29
30
|
require 'fog'
|
30
31
|
require 'readline'
|
@@ -50,6 +51,10 @@ class Chef
|
|
50
51
|
:description => "The AMI for the server",
|
51
52
|
:proc => Proc.new { |i| Chef::Config[:knife][:image] = i }
|
52
53
|
|
54
|
+
option :iam_instance_profile,
|
55
|
+
:long => "--iam-profile NAME",
|
56
|
+
:description => "The IAM instance profile to apply to this instance."
|
57
|
+
|
53
58
|
option :security_groups,
|
54
59
|
:short => "-G X,Y,Z",
|
55
60
|
:long => "--groups X,Y,Z",
|
@@ -66,6 +71,11 @@ class Chef
|
|
66
71
|
:long => "--associate-eip IP_ADDRESS",
|
67
72
|
:description => "Associate existing elastic IP address with instance after launch"
|
68
73
|
|
74
|
+
option :placement_group,
|
75
|
+
:long => "--placement-group PLACEMENT_GROUP",
|
76
|
+
:description => "The placement group to place a cluster compute instance",
|
77
|
+
:proc => Proc.new { |pg| Chef::Config[:knife][:placement_group] = pg }
|
78
|
+
|
69
79
|
option :tags,
|
70
80
|
:short => "-T T=V[,T=V,...]",
|
71
81
|
:long => "--tags Tag=Value[,Tag=Value...]",
|
@@ -127,12 +137,18 @@ class Chef
|
|
127
137
|
:long => "--bootstrap-version VERSION",
|
128
138
|
:description => "The version of Chef to install",
|
129
139
|
:proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
|
140
|
+
|
141
|
+
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 }
|
130
145
|
|
131
146
|
option :distro,
|
132
147
|
:short => "-d DISTRO",
|
133
148
|
:long => "--distro DISTRO",
|
134
149
|
:description => "Bootstrap a distro using a template; default is 'chef-full'",
|
135
|
-
:proc => Proc.new { |d| Chef::Config[:knife][:distro] = d }
|
150
|
+
:proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
|
151
|
+
:default => "chef-full"
|
136
152
|
|
137
153
|
option :template_file,
|
138
154
|
:long => "--template-file TEMPLATE",
|
@@ -158,6 +174,17 @@ class Chef
|
|
158
174
|
:description => "Comma separated list of roles/recipes to apply",
|
159
175
|
:proc => lambda { |o| o.split(/[\s,]+/) }
|
160
176
|
|
177
|
+
option :secret,
|
178
|
+
:short => "-s SECRET",
|
179
|
+
:long => "--secret ",
|
180
|
+
:description => "The secret key to use to encrypt data bag item values",
|
181
|
+
:proc => lambda { |s| Chef::Config[:knife][:secret] = s }
|
182
|
+
|
183
|
+
option :secret_file,
|
184
|
+
:long => "--secret-file SECRET_FILE",
|
185
|
+
:description => "A file containing the secret key to use to encrypt data bag item values",
|
186
|
+
:proc => lambda { |sf| Chef::Config[:knife][:secret_file] = sf }
|
187
|
+
|
161
188
|
option :json_attributes,
|
162
189
|
:short => "-j JSON",
|
163
190
|
:long => "--json-attributes JSON",
|
@@ -181,6 +208,18 @@ class Chef
|
|
181
208
|
:boolean => true,
|
182
209
|
:default => true
|
183
210
|
|
211
|
+
option :bootstrap_protocol,
|
212
|
+
:long => "--bootstrap-protocol protocol",
|
213
|
+
:description => "protocol to bootstrap windows servers. options: winrm/ssh",
|
214
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:bootstrap_protocol] = key },
|
215
|
+
:default => "winrm"
|
216
|
+
|
217
|
+
option :fqdn,
|
218
|
+
:long => "--fqdn FQDN",
|
219
|
+
:description => "Pre-defined FQDN",
|
220
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:fqdn] = key },
|
221
|
+
:default => nil
|
222
|
+
|
184
223
|
option :aws_user_data,
|
185
224
|
:long => "--user-data USER_DATA_FILE",
|
186
225
|
:short => "-u USER_DATA_FILE",
|
@@ -209,6 +248,30 @@ class Chef
|
|
209
248
|
:description => "The EC2 server attribute to use for SSH connection",
|
210
249
|
:default => nil
|
211
250
|
|
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
|
+
|
212
275
|
def tcp_test_ssh(hostname, ssh_port)
|
213
276
|
tcp_socket = TCPSocket.new(hostname, ssh_port)
|
214
277
|
readable = IO.select([tcp_socket], nil, nil, 5)
|
@@ -224,10 +287,60 @@ class Chef
|
|
224
287
|
false
|
225
288
|
rescue Errno::EPERM, Errno::ETIMEDOUT
|
226
289
|
false
|
290
|
+
# This happens on some mobile phone networks
|
291
|
+
rescue Errno::ECONNRESET
|
292
|
+
sleep 2
|
293
|
+
false
|
227
294
|
ensure
|
228
295
|
tcp_socket && tcp_socket.close
|
229
296
|
end
|
230
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
|
343
|
+
|
231
344
|
def run
|
232
345
|
$stdout.sync = true
|
233
346
|
|
@@ -248,6 +361,8 @@ class Chef
|
|
248
361
|
hashed_tags["Name"] = locate_config_value(:chef_node_name) || @server.id
|
249
362
|
end
|
250
363
|
|
364
|
+
printed_tags = hashed_tags.map{ |tag, val| "#{tag}: #{val}" }.join(", ")
|
365
|
+
|
251
366
|
msg_pair("Instance ID", @server.id)
|
252
367
|
msg_pair("Flavor", @server.flavor_id)
|
253
368
|
msg_pair("Image", @server.image_id)
|
@@ -266,7 +381,9 @@ class Chef
|
|
266
381
|
printed_security_group_ids = @server.security_group_ids.join(", ") if @server.security_group_ids
|
267
382
|
msg_pair("Security Group Ids", printed_security_group_ids) if vpc_mode? or @server.security_group_ids
|
268
383
|
|
269
|
-
msg_pair("
|
384
|
+
msg_pair("IAM Profile", locate_config_value(:iam_instance_profile))
|
385
|
+
|
386
|
+
msg_pair("Tags", printed_tags)
|
270
387
|
msg_pair("SSH Key", @server.key_name)
|
271
388
|
|
272
389
|
print "\n#{ui.color("Waiting for instance", :magenta)}"
|
@@ -277,7 +394,7 @@ class Chef
|
|
277
394
|
puts("\n")
|
278
395
|
|
279
396
|
# occasionally 'ready?' isn't, so retry a couple times if needed.
|
280
|
-
tries = 6
|
397
|
+
tries = 6
|
281
398
|
begin
|
282
399
|
create_tags(hashed_tags) unless hashed_tags.empty?
|
283
400
|
associate_eip(elastic_ip) if config[:associate_eip]
|
@@ -300,21 +417,44 @@ class Chef
|
|
300
417
|
end
|
301
418
|
msg_pair("Private IP Address", @server.private_ip_address)
|
302
419
|
|
303
|
-
print "\n#{ui.color("Waiting for sshd", :magenta)}"
|
304
420
|
|
305
|
-
|
306
|
-
|
307
|
-
|
421
|
+
#Check if Server is Windows or Linux
|
422
|
+
if is_image_windows?
|
423
|
+
protocol = locate_config_value(:bootstrap_protocol)
|
424
|
+
# Set distro to windows-chef-client-msi
|
425
|
+
config[:distro] = "windows-chef-client-msi" if (config[:distro].nil? || config[:distro] == "chef-full")
|
426
|
+
if protocol == 'winrm'
|
427
|
+
load_winrm_deps
|
428
|
+
print "\n#{ui.color("Waiting for winrm", :magenta)}"
|
429
|
+
print(".") until tcp_test_winrm(ssh_connect_host, locate_config_value(:winrm_port)) {
|
430
|
+
sleep 10
|
431
|
+
puts("done")
|
432
|
+
}
|
433
|
+
else
|
434
|
+
print "\n#{ui.color("Waiting for sshd", :magenta)}"
|
435
|
+
#If FreeSSHd, winsshd etc are available
|
436
|
+
print(".") until tcp_test_ssh(ssh_connect_host, config[:ssh_port]) {
|
437
|
+
sleep @initial_sleep_delay ||= (vpc_mode? ? 40 : 10)
|
438
|
+
puts("done")
|
439
|
+
}
|
440
|
+
end
|
441
|
+
bootstrap_for_windows_node(@server,ssh_connect_host).run
|
442
|
+
else
|
443
|
+
wait_for_sshd(ssh_connect_host)
|
444
|
+
bootstrap_for_linux_node(@server,ssh_connect_host).run
|
445
|
+
end
|
308
446
|
|
309
447
|
puts "\n"
|
310
448
|
msg_pair("Instance ID", @server.id)
|
311
449
|
msg_pair("Flavor", @server.flavor_id)
|
450
|
+
msg_pair("Placement Group", @server.placement_group) unless @server.placement_group.nil?
|
312
451
|
msg_pair("Image", @server.image_id)
|
313
452
|
msg_pair("Region", connection.instance_variable_get(:@region))
|
314
453
|
msg_pair("Availability Zone", @server.availability_zone)
|
315
454
|
msg_pair("Security Groups", printed_security_groups) unless vpc_mode? or (@server.groups.nil? and @server.security_group_ids)
|
316
455
|
msg_pair("Security Group Ids", printed_security_group_ids) if vpc_mode? or @server.security_group_ids
|
317
|
-
msg_pair("
|
456
|
+
msg_pair("IAM Profile", locate_config_value(:iam_instance_profile)) if locate_config_value(:iam_instance_profile)
|
457
|
+
msg_pair("Tags", printed_tags)
|
318
458
|
msg_pair("SSH Key", @server.key_name)
|
319
459
|
msg_pair("Root Device Type", @server.root_device_type)
|
320
460
|
if @server.root_device_type == "ebs"
|
@@ -349,29 +489,74 @@ class Chef
|
|
349
489
|
msg_pair("JSON Attributes",config[:json_attributes]) unless !config[:json_attributes] || config[:json_attributes].empty?
|
350
490
|
end
|
351
491
|
|
352
|
-
def
|
492
|
+
def bootstrap_common_params(bootstrap)
|
493
|
+
bootstrap.config[:run_list] = config[:run_list]
|
494
|
+
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
495
|
+
bootstrap.config[:distro] = locate_config_value(:distro)
|
496
|
+
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
497
|
+
bootstrap.config[:environment] = locate_config_value(:environment)
|
498
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
499
|
+
bootstrap.config[:first_boot_attributes] = locate_config_value(:json_attributes) || {}
|
500
|
+
bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:encrypted_data_bag_secret)
|
501
|
+
bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:encrypted_data_bag_secret_file)
|
502
|
+
bootstrap.config[:secret] = locate_config_value(:secret)
|
503
|
+
bootstrap.config[:secret_file] = locate_config_value(:secret_file)
|
504
|
+
# Modify global configuration state to ensure hint gets set by
|
505
|
+
# knife-bootstrap
|
506
|
+
Chef::Config[:knife][:hints] ||= {}
|
507
|
+
Chef::Config[:knife][:hints]["ec2"] ||= {}
|
508
|
+
bootstrap
|
509
|
+
end
|
510
|
+
|
511
|
+
def fetch_server_fqdn(ip_addr)
|
512
|
+
require 'resolv'
|
513
|
+
Resolv.getname(ip_addr)
|
514
|
+
end
|
515
|
+
|
516
|
+
def bootstrap_for_windows_node(server, fqdn)
|
517
|
+
if locate_config_value(:bootstrap_protocol) == 'winrm'
|
518
|
+
if locate_config_value(:kerberos_realm)
|
519
|
+
#Fetch AD/WINS based fqdn if any for Kerberos-based Auth
|
520
|
+
fqdn = locate_config_value(:fqdn) || fetch_server_fqdn(server.private_ip_address)
|
521
|
+
end
|
522
|
+
bootstrap = Chef::Knife::BootstrapWindowsWinrm.new
|
523
|
+
bootstrap.config[:winrm_user] = locate_config_value(:winrm_user)
|
524
|
+
bootstrap.config[:winrm_password] = windows_password
|
525
|
+
bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport)
|
526
|
+
bootstrap.config[:kerberos_keytab_file] = locate_config_value(:kerberos_keytab_file)
|
527
|
+
bootstrap.config[:kerberos_realm] = locate_config_value(:kerberos_realm)
|
528
|
+
bootstrap.config[:kerberos_service] = locate_config_value(:kerberos_service)
|
529
|
+
bootstrap.config[:ca_trust_file] = locate_config_value(:ca_trust_file)
|
530
|
+
bootstrap.config[:winrm_port] = locate_config_value(:winrm_port)
|
531
|
+
|
532
|
+
elsif locate_config_value(:bootstrap_protocol) == 'ssh'
|
533
|
+
bootstrap = Chef::Knife::BootstrapWindowsSsh.new
|
534
|
+
bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
|
535
|
+
bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
|
536
|
+
bootstrap.config[:ssh_port] = locate_config_value(:ssh_port)
|
537
|
+
bootstrap.config[:identity_file] = locate_config_value(:identity_file)
|
538
|
+
bootstrap.config[:no_host_key_verify] = locate_config_value(:no_host_key_verify)
|
539
|
+
else
|
540
|
+
ui.error("Unsupported Bootstrapping Protocol. Supported : winrm, ssh")
|
541
|
+
exit 1
|
542
|
+
end
|
543
|
+
bootstrap.name_args = [fqdn]
|
544
|
+
bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.id
|
545
|
+
bootstrap_common_params(bootstrap)
|
546
|
+
end
|
547
|
+
|
548
|
+
def bootstrap_for_linux_node(server,ssh_host)
|
353
549
|
bootstrap = Chef::Knife::Bootstrap.new
|
354
550
|
bootstrap.name_args = [ssh_host]
|
355
|
-
bootstrap.config[:run_list] = locate_config_value(:run_list) || []
|
356
551
|
bootstrap.config[:ssh_user] = config[:ssh_user]
|
357
552
|
bootstrap.config[:ssh_port] = config[:ssh_port]
|
358
553
|
bootstrap.config[:ssh_gateway] = config[:ssh_gateway]
|
359
554
|
bootstrap.config[:identity_file] = config[:identity_file]
|
360
555
|
bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server.id
|
361
|
-
bootstrap.config[:prerelease] = config[:prerelease]
|
362
|
-
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
363
|
-
bootstrap.config[:first_boot_attributes] = locate_config_value(:json_attributes) || {}
|
364
|
-
bootstrap.config[:distro] = locate_config_value(:distro) || "chef-full"
|
365
556
|
bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
|
366
|
-
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
367
|
-
bootstrap.config[:environment] = config[:environment]
|
368
557
|
# may be needed for vpc_mode
|
369
558
|
bootstrap.config[:host_key_verify] = config[:host_key_verify]
|
370
|
-
|
371
|
-
# knife-bootstrap
|
372
|
-
Chef::Config[:knife][:hints] ||= {}
|
373
|
-
Chef::Config[:knife][:hints]["ec2"] ||= {}
|
374
|
-
bootstrap
|
559
|
+
bootstrap_common_params(bootstrap)
|
375
560
|
end
|
376
561
|
|
377
562
|
def vpc_mode?
|
@@ -440,6 +625,8 @@ class Chef
|
|
440
625
|
}
|
441
626
|
server_def[:subnet_id] = locate_config_value(:subnet_id) if vpc_mode?
|
442
627
|
server_def[:private_ip_address] = locate_config_value(:private_ip_address) if vpc_mode?
|
628
|
+
server_def[:placement_group] = locate_config_value(:placement_group)
|
629
|
+
server_def[:iam_instance_profile_name] = locate_config_value(:iam_instance_profile)
|
443
630
|
|
444
631
|
if Chef::Config[:knife][:aws_user_data]
|
445
632
|
begin
|