|
#!/usr/bin/env/ruby |
|
|
|
require 'socket' |
|
|
|
KNIFE_CONFIG = "~/.chef/knife.rb" |
|
|
|
# Node details |
|
NODE_NAME = "webserver-01.example.com" |
|
CHEF_ENVIRONMENT = "production" |
|
INSTANCE_SIZE = "m3.large" |
|
EBS_ROOT_VOL_SIZE = 70 # in GB |
|
REGION = "us-west-2" |
|
AVAILABILITY_ZONE = "us-west-2b" |
|
AMI_NAME = "ami-904be6f8" # Microsoft Windows Server 2012 R2 Base |
|
SECURITY_GROUP_IDS = "sg-a1b2c3d4" |
|
SUBNET = "subnet-a1b2c3d4" |
|
RUN_LIST = "recipe[java]" |
|
USER_DATA_FILE = "/tmp/userdata.txt" |
|
USERNAME = "Administrator" |
|
PASSWORD = "YourAdminPassword" |
|
|
|
# Write user data file that sets up WinRM and sets the Administrator password. |
|
File.open(USER_DATA_FILE, "w") do |f| |
|
f.write <<EOT |
|
<script> |
|
winrm quickconfig -q & winrm set winrm/config/winrs @{MaxMemoryPerShellMB="300"} & winrm set winrm/config @{MaxTimeoutms="1800000"} & winrm set winrm/config/service @{AllowUnencrypted="true"} & winrm set winrm/config/service/auth @{Basic="true"} |
|
</script> |
|
<powershell> |
|
netsh advfirewall firewall add rule name="WinRM in" protocol=TCP dir=in profile=any localport=5985 remoteip=any localip=any action=allow |
|
$admin = [adsi]("WinNT://./administrator, user") |
|
$admin.psbase.invoke("SetPassword", "#{PASSWORD}") |
|
</powershell> |
|
EOT |
|
end |
|
|
|
# Define the command to provision the instance |
|
provision_cmd = [ |
|
"knife ec2 server create", |
|
"--config '#{KNIFE_CONFIG}'", |
|
"--tags 'Name=#{NODE_NAME}'", |
|
"--environment '#{CHEF_ENVIRONMENT}'", |
|
"--flavor #{INSTANCE_SIZE}", |
|
"--ebs-size #{EBS_ROOT_VOL_SIZE}", |
|
"--region #{REGION}", |
|
"--availability-zone #{AVAILABILITY_ZONE}", |
|
"--image #{AMI_NAME}", |
|
"--security-group-ids '#{SECURITY_GROUP_IDS}'", |
|
"--subnet '#{SUBNET}'", |
|
"--user-data #{USER_DATA_FILE}", |
|
"--verbose" |
|
].join(" ") |
|
|
|
puts provision_cmd |
|
|
|
# Run `knife ec2 server create` to provision the new instance and |
|
# read the output until we know it's VPC private IP address. At that point, |
|
# knife is going to wait until the instance responds on the SSH port. Of |
|
# course, being Windows, this will never happen, so we need to go ahead and |
|
# kill knife and then proceed with the rest of this script to wait until |
|
# WinRM is up and we can bootstrap the node with Chef over WinRM. |
|
ip_addr = nil |
|
IO.popen(provision_cmd) do |pipe| |
|
begin |
|
while line = pipe.readline |
|
puts line |
|
if line =~ /^Private IP Address: (.*)$/ |
|
ip_addr = $1.strip |
|
Process.kill("TERM", pipe.pid) |
|
break |
|
end |
|
end |
|
rescue EOFError |
|
# done |
|
end |
|
end |
|
if ip_addr.nil? |
|
puts "ERROR: Unable to get new instance's IP address" |
|
exit -1 |
|
end |
|
|
|
# Now the new instance is provisioned, but we have no idea when it will |
|
# be ready to go. The first thing we'll do is wait until the WinRM port |
|
# responds to connections. |
|
puts "Waiting for WinRM..." |
|
begin |
|
TCPSocket.new(ip_addr, 5985).close |
|
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT |
|
puts "Still waiting..." |
|
retry |
|
end |
|
|
|
# You'd think we'd be good to go now...but NOPE! There is still more Windows |
|
# bootstrap crap going on, and we have no idea what we need to wait on. So, |
|
# in a last-ditch effort to make this all work, we've seen that 120 seconds |
|
# ought to be enough... |
|
wait_time = 120 |
|
while wait_time > 0 |
|
puts "Better wait #{wait_time} more seconds..." |
|
sleep 1 |
|
wait_time -= 1 |
|
end |
|
puts "Finally ready to try bootstrapping instance..." |
|
|
|
# Define the command to bootstrap the already-provisioned instance with Chef |
|
bootstrap_cmd = [ |
|
"knife bootstrap windows winrm #{ip_addr}", |
|
"-x #{USERNAME}", |
|
"-P '#{PASSWORD}'", |
|
"--environment #{CHEF_ENVIRONMENT}", |
|
"--node-name #{NODE_NAME}", |
|
"--run-list #{RUN_LIST}", |
|
"--verbose" |
|
].join(' ') |
|
|
|
# Now we can bootstrap the instance with Chef and the configured run list. |
|
status = system(bootstrap_cmd) ? 0 : -1 |
|
exit status |
Can you please update knife.rb file here and how you ran this file from chef workstation in powershell?