Class: KnifeCloudstack::CsServerCreate

Inherits:
Chef::Knife
  • Object
show all
Defined in:
lib/chef/knife/cs_server_create.rb

Constant Summary collapse

BOOTSTRAP_DELAY =

Seconds to delay between detecting ssh and initiating the bootstrap

3
SSH_POLL_INTERVAL =

Seconds to wait between ssh pings

2

Instance Method Summary collapse

Instance Method Details

#bootstrap_for_node(host) ⇒ Object



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/chef/knife/cs_server_create.rb', line 310

def bootstrap_for_node(host)
  bootstrap = Chef::Knife::Bootstrap.new
  bootstrap.name_args = [host]
  bootstrap.config[:run_list] = config[:run_list]
  bootstrap.config[:ssh_user] = config[:ssh_user]
  bootstrap.config[:ssh_password] = config[:ssh_password]
  bootstrap.config[:identity_file] = config[:identity_file]
  bootstrap.config[:chef_node_name] = config[:chef_node_name] if config[:chef_node_name]
  bootstrap.config[:prerelease] = config[:prerelease]
  bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
  bootstrap.config[:distro] = locate_config_value(:distro)
  bootstrap.config[:use_sudo] = true
  bootstrap.config[:template_file] = locate_config_value(:template_file)
  bootstrap.config[:environment] = config[:environment]
  # may be needed for vpc_mode
  bootstrap.config[:no_host_key_verify] = config[:no_host_key_verify]
  bootstrap
end

#create_port_forwarding_rules(ip_address_id, server_id, connection) ⇒ Object



266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/chef/knife/cs_server_create.rb', line 266

def create_port_forwarding_rules(ip_address_id, server_id, connection)
  rules = locate_config_value(:port_rules)
  return unless rules

  rules.each do |rule|
    args = rule.split(':')
    public_port = args[0]
    private_port = args[1] || args[0]
    protocol = args[2] || "TCP"
    connection.create_port_forwarding_rule(ip_address_id, private_port, protocol, public_port, server_id)
  end

end

#find_or_create_public_ip(server, connection) ⇒ Object



251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/chef/knife/cs_server_create.rb', line 251

def find_or_create_public_ip(server, connection)
  nic = connection.get_server_default_nic(server) || {}
  puts "#{ui.color("Not allocating public IP for server", :red)}" unless config[:public_ip]

  if (config[:public_ip] == false) || (nic['type'] != 'Virtual') then
    nic['ipaddress']
  else
    # create ip address, ssh forwarding rule and optional forwarding rules
    ip_address = connection.associate_ip_address(server['zoneid'])
    ssh_rule = connection.create_port_forwarding_rule(ip_address['id'], "22", "TCP", "22", server['id'])
    create_port_forwarding_rules(ip_address['id'], server['id'], connection)
    ssh_rule['ipaddress']
  end
end

#is_ssh_open?(ip) ⇒ Boolean

noinspection RubyArgCount,RubyResolve

Returns:

  • (Boolean)


281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/chef/knife/cs_server_create.rb', line 281

def is_ssh_open?(ip)
  s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
  sa = Socket.sockaddr_in(22, ip)

  begin
    s.connect_nonblock(sa)
  rescue Errno::EINPROGRESS
    resp = IO.select(nil, [s], nil, 1)
    if resp.nil?
      sleep SSH_POLL_INTERVAL
      return false
    end

    begin
      s.connect_nonblock(sa)
    rescue Errno::EISCONN
      Chef::Log.debug("sshd accepting connections on #{ip}")
      yield
      return true
    rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
      sleep SSH_POLL_INTERVAL
      return false
    end
  ensure
    s && s.close
  end
end

#locate_config_value(key) ⇒ Object



329
330
331
332
# File 'lib/chef/knife/cs_server_create.rb', line 329

def locate_config_value(key)
  key = key.to_sym
  Chef::Config[:knife][key] || config[key]
end

#runObject



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/chef/knife/cs_server_create.rb', line 166

def run

  # validate hostname and options
  hostname = @name_args.first
  unless /^[a-zA-Z0-9][a-zA-Z0-9-]*$/.match hostname then
    ui.error "Invalid hostname. Please specify a short hostname, not an fqdn (e.g. 'myhost' instead of 'myhost.domain.com')."
    exit 1
  end
  validate_options

  $stdout.sync = true

  connection = CloudstackClient::Connection.new(
      locate_config_value(:cloudstack_url),
      locate_config_value(:cloudstack_api_key),
      locate_config_value(:cloudstack_secret_key)
  )

  print "#{ui.color("Waiting for server", :magenta)}"
  server = connection.create_server(
      hostname,
      locate_config_value(:cloudstack_service),
      locate_config_value(:cloudstack_template),
      locate_config_value(:cloudstack_zone),
      locate_config_value(:cloudstack_disk),
      locate_config_value(:cloudstack_networks)
  )
  
#puts "#"*100
#puts server
#puts "#"*100

  private_ip = find_or_create_public_ip(server, connection)

  puts "\n\n"
  puts "#{ui.color("Name", :cyan)}: #{server['name']}"
  puts "#{ui.color("Private IP", :cyan)}: #{private_ip}"


  print "\n#{ui.color("Waiting for sshd", :magenta)}"

  print(".") until is_ssh_open?(private_ip) {
    sleep BOOTSTRAP_DELAY
    puts "\n"
  }

  server_info = { 'hostname' => hostname, 'private_ip' => private_ip, 'password' => server['password'] }
  puts "\n"
   
  puts "server_info :"+server_info.to_json+"\n"

  return unless config[:no_bootstrap]
    
  config[:ssh_password] = server['password']
  bootstrap_for_node(private_ip).run

  puts "\n"
  puts "#{ui.color("Name", :cyan)}: #{server['name']}"
  puts "#{ui.color("Public IP", :cyan)}: #{private_ip}"
  puts "#{ui.color("Environment", :cyan)}: #{config[:environment] || '_default'}"
  puts "#{ui.color("Run List", :cyan)}: #{config[:run_list].join(', ')}"
end

#validate_optionsObject



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/chef/knife/cs_server_create.rb', line 229

def validate_options

  unless locate_config_value :cloudstack_template
    ui.error "Cloudstack template not specified"
    exit 1
  end

  unless locate_config_value :cloudstack_service
    ui.error "Cloudstack service offering not specified"
    exit 1
  end

  identity_file = locate_config_value :identity_file
  ssh_user = locate_config_value :ssh_user
  ssh_password = locate_config_value :ssh_password
  #unless identity_file || (ssh_user && ssh_password)
  #  ui.error("You must specify either an ssh identity file or an ssh user and password")
    #exit 1
  #end
end