Class: Chef::Knife::OcaTemplateInstantiate

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from OcaBase

#connection, #dns_reverse_lookup, included, #locate_config_value, #msg_pair, #validate!

Instance Attribute Details

#initial_sleep_delayObject

Returns the value of attribute initial_sleep_delay.



43
44
45
# File 'lib/chef/knife/oca_template_instantiate.rb', line 43

def initial_sleep_delay
  @initial_sleep_delay
end

#serverObject (readonly)

Returns the value of attribute server.



44
45
46
# File 'lib/chef/knife/oca_template_instantiate.rb', line 44

def server
  @server
end

Instance Method Details

#bootstrap_for_node(server, fqdn) ⇒ Object



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/chef/knife/oca_template_instantiate.rb', line 301

def bootstrap_for_node(server,fqdn)
  bootstrap = Chef::Knife::Bootstrap.new
  bootstrap.name_args = [fqdn]
  bootstrap.config[:run_list] = config[:run_list]
  bootstrap.config[:ssh_user] = Chef::Config[:ssh_user] || config[:ssh_user] 
  bootstrap.config[:ssh_port] = Chef::Config[:ssh_port] || config[:ssh_port]
  if Chef::Config[:identity_file].nil? && config[:identity_file].nil? then
    bootstrap.config[:ssh_password] = Chef::Config[:ssh_password] || config[:ssh_password]
  else
    bootstrap.config[:identity_file] = Chef::Config[:identity_file] || config[:identity_file]
  end
  bootstrap.config[:chef_node_name] = config[:chef_node_name] || fqdn
  bootstrap.config[:prerelease] = config[:prerelease]
  bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
  bootstrap.config[:first_boot_attributes] = config[:json_attributes]
  bootstrap.config[:distro] = locate_config_value(:distro)
  bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
  bootstrap.config[:template_file] = locate_config_value(:template_file)
  bootstrap.config[:environment] = config[:environment]
  # may be needed for vpc_mode
  bootstrap.config[:host_key_verify] = config[:host_key_verify]
  bootstrap
end

#configure_knife(fqdn) ⇒ Object



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/chef/knife/oca_template_instantiate.rb', line 267

def configure_knife(fqdn)
  additional_config = IO.read(config[:config_file])

  configure = Chef::Knife::Configure.new
  configure.config[:defaults] = true
  configure.config[:initial] = true
  configure.config[:node_name] = Etc.getlogin
  configure.config[:client_key] = File.join(File.dirname(config[:config_file]), "#{Etc.getlogin}.pem")
  configure.config[:chef_server_url] = config[:chef_server_url_template].sub(/FQDN/, fqdn)
  configure.config[:admin_client_name] = 'chef-webui'
  configure.config[:admin_client_key] = File.join(Dir.pwd, 'webui.pem')
  configure.config[:validation_client_name] = 'chef-validator'
  configure.config[:validation_key] = File.join(Dir.pwd, 'validation.pem')
  configure.config[:repository] = config[:repository]
  configure.config[:config_file] = config[:config_file]
  # monkey patch Chef::Knife::Configure to not ask anything
  class << configure
    define_method(:ask_user_for_config_path) {} 
    define_method(:ask_user_for_config) do
      @chef_server            = config[:chef_server_url]
      @new_client_name        = config[:node_name]
      @admin_client_name      = config[:admin_client_name]
      @admin_client_key       = config[:admin_client_key]
      @validation_client_name = config[:validation_client_name]
      @validation_key         = config[:validation_key]
      @new_client_key         = config[:client_key]
      @chef_repo              = config[:repository]
    end
  end
  configure.run

  open(config[:config_file], 'a') { |f| f << "\n#{additional_config}\n" }
end

#retrieve_files(fqdn, files) ⇒ Object



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

def retrieve_files(fqdn, files)
  options = Hash.new
  options[:password] = Chef::Config[:ssh_password]
  options[:paranoid] = config[:host_key_verify]
  options[:port] = Chef::Config[:ssh_port] unless Chef::Config[:ssh_port].nil?
  Net::SCP.start(fqdn, Chef::Config[:ssh_user], options) do |scp|
    synch = Array.new
    files.each do |file|
      puts ui.color("Downloading file ", :magenta) << "#{fqdn}:#{file}" << ui.color(" to ", :magenta) << "#{Dir.pwd}" << ui.color(" ...", :magenta)
      synch << scp.download(file, Dir.pwd)
    end
    synch.each { |d| d.wait }
    puts('done')
  end
rescue => e
  puts ui.error("Downloading some files from the node failed. Error: #{e}")
  exit 1
end

#runObject



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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/chef/knife/oca_template_instantiate.rb', line 177

def run
  $stdout.sync = true

  validate!

  template_id = @name_args.first
  @template = connection.templates.get(template_id)
  instance_id = @template.instantiate
  @server = connection.virtual_machines.get(instance_id.to_s)

  hashed_tags={}
  tags.map{ |t| key,val=t.split('='); hashed_tags[key]=val} unless tags.nil?

  # Always set the Name tag
  unless hashed_tags.keys.include? "Name"
    hashed_tags["Name"] = locate_config_value(:chef_node_name) || @server.id
  end

  #hashed_tags.each_pair do |key,val|
  #  connection.tags.create :key => key, :value => val, :resource_id => @server.id
  #end

  msg_pair("Instance ID", @server.id)
  msg_pair("Template", @template.name)
  msg_pair("# CPUs", @template.template['VCPU'])
  msg_pair("Memory", @template.template['MEMORY'])
  msg_pair("Architecture", @template.template['OS']['ARCH'])

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

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

  puts("done\n")

  fqdn = dns_reverse_lookup(@server.template['NIC']['IP'])
  
  msg_pair("Public DNS Name", fqdn)
  msg_pair("Public IP Address", @server.template['NIC']['IP'])

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

  print(".") until tcp_test_ssh(fqdn) {
    sleep @initial_sleep_delay ||= 10
    puts("done")
  }

  if config[:is_chef_server] then
    retrieve_files(fqdn, config[:retrieve_files])
    configure_knife(fqdn)
  else
    bootstrap_for_node(@server,fqdn).run
  end

  puts "\n"
  msg_pair("Instance ID", @server.id)
  msg_pair("Template", @template.name)
  msg_pair("# CPUs", @template.template['VCPU'])
  msg_pair("Memory", @template.template['MEMORY'])
  msg_pair("Architecture", @template.template['OS']['ARCH'])
  msg_pair("Public DNS Name", fqdn)
  msg_pair("Public IP Address", @server.template['NIC']['IP'])
  msg_pair("Environment", config[:environment] || '_default')
  msg_pair("Run List", config[:run_list].join(', '))
  msg_pair("JSON Attributes",config[:json_attributes]) unless config[:json_attributes].empty?
  if config[:is_chef_server] then
    puts "\n"
    msg_pair("Knife config generated", config[:config_file])
  end
end

#tagsObject



325
326
327
328
329
330
331
332
# File 'lib/chef/knife/oca_template_instantiate.rb', line 325

def tags
 tags = locate_config_value(:tags)
  if !tags.nil? and tags.length != tags.to_s.count('=')
    ui.error("Tags should be entered in a key = value pair")
    exit 1
  end
 tags
end

#tcp_test_ssh(hostname) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/chef/knife/oca_template_instantiate.rb', line 145

def tcp_test_ssh(hostname)
  tcp_socket = TCPSocket.new(hostname, config[:ssh_port])
  readable = IO.select([tcp_socket], nil, nil, 5)
  if readable
    Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
    yield
    true
  else
    false
  end
rescue SocketError
  sleep 2
  false
rescue Errno::ETIMEDOUT
  false
rescue Errno::EPERM
  false
rescue Errno::ECONNREFUSED
  sleep 2
  false
# This happens on EC2 quite often
rescue Errno::EHOSTUNREACH
  sleep 2
  false
# This happens on EC2 sometimes
rescue Errno::ENETUNREACH
  sleep 2
  false
ensure
  tcp_socket && tcp_socket.close
end