Created
December 13, 2012 14:37
-
-
Save scottwb/4276748 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env/ruby | |
require 'socket' | |
# AWS API Credentials | |
AWS_ACCESS_KEY_ID = "your-aws-access-key-id" | |
AWS_SECRET_ACCESS_KEY = "your-aws-secret-access-key" | |
# Node details | |
NODE_NAME = "webserver-01.example.com" | |
CHEF_ENVIRONMENT = "production" | |
INSTANCE_SIZE = "m1.large" | |
EBS_ROOT_VOL_SIZE = 70 # in GB | |
REGION = "us-west-2" | |
AVAILABILITY_ZONE = "us-west-2b" | |
AMI_NAME = "ami-46c54c76" | |
SECURITY_GROUP = "Web Servers" | |
RUN_LIST = "role[base],role[iis]" | |
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> | |
$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", | |
"--aws-access-key-id #{AWS_ACCESS_KEY_ID}", | |
"--aws-secret-access-key #{AWS_SECRET_ACCESS_KEY}", | |
"--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}", | |
"--groups '#{SECURITY_GROUP}'", | |
"--user-data #{USER_DATA_FILE}", | |
"--verbose" | |
].join(" ") | |
# Run `knife ec2 server create` to provision the new instance and | |
# read the output until we know it's public 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 =~ /^Public IP Address: (.*)$/ | |
ip_addr = $1.strip | |
Process.kill("TERM", pipe.pid) | |
break | |
end | |
end | |
rescue EOFError | |
# done | |
end | |
end | |
if id_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..." | |
start_time = Time.now | |
begin | |
s = TCPSocket.new ip_addr, 5985 | |
rescue Errno:ETIMEOUT => e | |
puts "Still waiting..." | |
retry | |
end | |
s.close | |
# 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 |
this doesn't work...
if id_addr.nil? on linenumber 74 must me ip_addr
Besides that the following error occur:
./bootstrap-windows.rb:86: syntax error, unexpected tSYMBEG, expecting keyword_do or '{' or '('
rescue Errno:ETIMEOUT => e
May also need to open firewall ports
netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow
netsh advfirewall firewall add rule name="WinRM 5986" protocol=TCP dir=in localport=5986 action=allow
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wow this is awesome... Many thanks!!! can't wait to give it a shot... very clever implementation.