Skip to content

Commit 4744d2a

Browse files
schisamodanielsdeleo
authored andcommitted
added bootstrap template support to rackspace server create
1 parent f9f4b31 commit 4744d2a

1 file changed

Lines changed: 96 additions & 68 deletions

File tree

chef/lib/chef/knife/rackspace_server_create.rb

Lines changed: 96 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
require 'chef/knife'
2020
require 'chef/json'
21+
require 'uuidtools'
2122

2223
class Chef
2324
class Knife
@@ -36,14 +37,29 @@ class RackspaceServerCreate < Knife
3637
:short => "-i IMAGE",
3738
:long => "--image IMAGE",
3839
:description => "The image of the server",
39-
:proc => Proc.new { |i| i.to_i },
40-
:default => 14362
40+
:proc => Proc.new { |i| i.to_i }
4141

4242
option :server_name,
43-
:short => "-N NAME",
43+
:short => "-S NAME",
4444
:long => "--server-name NAME",
45-
:description => "The server name",
46-
:default => "wtf"
45+
:description => "The server name. Defaults to a random UUID.",
46+
:default => UUIDTools::UUID.random_create.to_s
47+
48+
option :chef_node_name,
49+
:short => "-N NAME",
50+
:long => "--node-name NAME",
51+
:description => "The Chef node name for your new node"
52+
53+
option :ssh_user,
54+
:short => "-x USERNAME",
55+
:long => "--ssh-user USERNAME",
56+
:description => "The ssh username",
57+
:default => "root"
58+
59+
option :ssh_password,
60+
:short => "-P PASSWORD",
61+
:long => "--ssh-password PASSWORD",
62+
:description => "The ssh password"
4763

4864
option :api_key,
4965
:short => "-K KEY",
@@ -57,97 +73,109 @@ class RackspaceServerCreate < Knife
5773
:description => "Your rackspace API username",
5874
:proc => Proc.new { |username| Chef::Config[:knife][:rackspace_api_username] = username }
5975

76+
option :prerelease,
77+
:long => "--prerelease",
78+
:description => "Install the pre-release chef gems"
79+
80+
option :distro,
81+
:short => "-d DISTRO",
82+
:long => "--distro DISTRO",
83+
:description => "Bootstrap a distro using a template",
84+
:default => "ubuntu10.04-gems"
85+
86+
option :template_file,
87+
:long => "--template-file TEMPLATE",
88+
:description => "Full path to location of template to use",
89+
:default => false
90+
6091
def h
6192
@highline ||= HighLine.new
6293
end
6394

95+
def tcp_test_ssh(hostname)
96+
tcp_socket = TCPSocket.new(hostname, 22)
97+
readable = IO.select([tcp_socket], nil, nil, 5)
98+
if readable
99+
Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
100+
yield
101+
true
102+
else
103+
false
104+
end
105+
rescue Errno::ETIMEDOUT
106+
false
107+
rescue Errno::ECONNREFUSED
108+
sleep 2
109+
false
110+
ensure
111+
tcp_socket && tcp_socket.close
112+
end
113+
64114
def run
65115
require 'fog'
66116
require 'highline'
67117
require 'net/ssh/multi'
68118
require 'readline'
69119

120+
$stdout.sync = true
121+
70122
connection = Fog::Rackspace::Servers.new(
71123
:rackspace_api_key => Chef::Config[:knife][:rackspace_api_key],
72124
:rackspace_username => Chef::Config[:knife][:rackspace_api_username]
73125
)
74126

75-
server = connection.servers.new
76-
77-
server.flavor_id = config[:flavor]
78-
server.image_id = config[:image]
79-
server.name = config[:server_name]
80-
server.personality = [
81-
{
82-
'path' => '/etc/install-chef',
83-
'contents' => <<-EOH
84-
#!/bin/bash
85-
# Customized rc.local for chef installation
86-
87-
if [ ! -f /usr/bin/chef-client ]; then
88-
apt-get update
89-
apt-get install -y ruby ruby1.8-dev build-essential wget libruby-extras libruby1.8-extras
90-
cd /tmp
91-
wget http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz
92-
tar xvf rubygems-1.3.6.tgz
93-
cd rubygems-1.3.6
94-
ruby setup.rb
95-
cp /usr/bin/gem1.8 /usr/bin/gem
96-
gem install chef ohai --no-rdoc --no-ri --verbose
97-
fi
98-
99-
exit 0
100-
EOH
101-
},
102-
{
103-
'path' => "/etc/chef/validation.pem",
104-
'contents' => IO.read(Chef::Config[:validation_key])
105-
},
106-
{
107-
'path' => "/etc/chef/client.rb",
108-
'contents' => <<-EOH
109-
log_level :info
110-
log_location STDOUT
111-
chef_server_url "#{Chef::Config[:chef_server_url]}"
112-
validation_client_name "#{Chef::Config[:validation_client_name]}"
113-
EOH
114-
},
115-
{
116-
'path' => "/etc/chef/first-boot.json",
117-
'contents' => { "run_list" => @name_args }.to_json
118-
},
119-
]
120-
121-
server.save
122-
123-
$stdout.sync = true
127+
server = connection.servers.create(
128+
:name => config[:server_name],
129+
:image_id => config[:image],
130+
:flavor_id => config[:flavor]
131+
)
124132

133+
puts "#{h.color("Instance ID", :cyan)}: #{server.id}"
125134
puts "#{h.color("Name", :cyan)}: #{server.name}"
126135
puts "#{h.color("Flavor", :cyan)}: #{server.flavor_id}"
127136
puts "#{h.color("Image", :cyan)}: #{server.image_id}"
128-
puts "#{h.color("Public Address", :cyan)}: #{server.addresses["public"]}"
129-
puts "#{h.color("Private Address", :cyan)}: #{server.addresses["private"]}"
137+
puts "#{h.color("Public IP Address", :cyan)}: #{server.addresses["public"][0]}"
138+
puts "#{h.color("Private IP Address", :cyan)}: #{server.addresses["private"][0]}"
130139
puts "#{h.color("Password", :cyan)}: #{server.password}"
131-
140+
132141
print "\n#{h.color("Requesting server", :magenta)}"
133-
saved_password = server.password
134142

135143
# wait for it to be ready to do stuff
136144
server.wait_for { print "."; ready? }
137145

138-
puts "\nServer ready, waiting 15 seconds to bootstrap."
139-
sleep 15
146+
puts("\n")
147+
148+
print "\n#{h.color("Waiting for sshd", :magenta)}"
149+
150+
print(".") until tcp_test_ssh(server.addresses["public"][0]) { sleep @initial_sleep_delay ||= 10; puts("done") }
140151

141-
puts "\nBootstrapping #{h.color(server.name, :bold)}..."
152+
bootstrap_for_node(server).run
142153

143-
ssh = Chef::Knife::Ssh.new
144-
ssh.name_args = [ server.addresses["public"][0], "/bin/bash /etc/install-chef && /usr/bin/chef-client -j /etc/chef/first-boot.json" ]
145-
ssh.config[:ssh_user] = "root"
146-
ssh.config[:manual] = true
147-
ssh.config[:ssh_password] = saved_password
148-
ssh.password = saved_password
149-
ssh.run
154+
puts "\n"
155+
puts "#{h.color("Instance ID", :cyan)}: #{server.id}"
156+
puts "#{h.color("Name", :cyan)}: #{server.name}"
157+
puts "#{h.color("Flavor", :cyan)}: #{server.flavor_id}"
158+
puts "#{h.color("Image", :cyan)}: #{server.image_id}"
159+
puts "#{h.color("Public IP Address", :cyan)}: #{server.addresses["public"][0]}"
160+
puts "#{h.color("Private IP Address", :cyan)}: #{server.addresses["private"][0]}"
161+
puts "#{h.color("Password", :cyan)}: #{server.password}"
162+
puts "#{h.color("Run List", :cyan)}: #{@name_args.join(', ')}"
163+
end
150164

165+
def bootstrap_for_node(server)
166+
bootstrap = Chef::Knife::Bootstrap.new
167+
bootstrap.name_args = [server.addresses["public"][0]]
168+
bootstrap.config[:run_list] = @name_args
169+
bootstrap.config[:ssh_user] = config[:ssh_user] || "root"
170+
bootstrap.config[:ssh_password] = server.password
171+
bootstrap.config[:identity_file] = config[:identity_file]
172+
bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.id
173+
bootstrap.config[:prerelease] = config[:prerelease]
174+
bootstrap.config[:distro] = config[:distro]
175+
bootstrap.config[:use_sudo] = true
176+
bootstrap.config[:template_file] = config[:template_file]
177+
bootstrap.config[:environment] = config[:environment]
178+
bootstrap
151179
end
152180
end
153181
end

0 commit comments

Comments
 (0)