Class: Chef::Knife::Bootstrap

Inherits:
Chef::Knife show all
Includes:
DataBagSecretOptions
Defined in:
lib/chef/knife/bootstrap.rb

Instance Attribute Summary

Attributes inherited from Chef::Knife

#name_args, #ui

Instance Method Summary collapse

Methods included from DataBagSecretOptions

#encryption_secret_provided?, #encryption_secret_provided_ignore_encrypt_flag?, included, #read_secret, #validate_secrets

Methods included from EncryptedDataBagItem::CheckEncrypted

#encrypted?

Methods inherited from Chef::Knife

#api_key, #apply_computed_config, category, chef_config_dir, common_name, #config_file_settings, config_loader, #configure_chef, #create_object, #delete_object, dependency_loaders, deps, #format_rest_error, guess_category, #humanize_exception, #humanize_http_exception, inherited, #initialize, list_commands, load_commands, load_config, load_deps, #merge_configs, msg, #noauth_rest, #parse_options, reset_config_loader!, reset_subcommands!, #rest, run, #run_with_pretty_exceptions, #server_url, #show_usage, snake_case_name, subcommand_category, subcommand_class_from, subcommand_loader, subcommands, subcommands_by_category, ui, unnamed?, use_separate_defaults?, #username

Methods included from Mixin::ConvertToClassName

#constantize, #convert_to_class_name, #convert_to_snake_case, #filename_to_qualified_string, #snake_case_basename

Methods included from Mixin::PathSanity

#enforce_path_sanity

Constructor Details

This class inherits a constructor from Chef::Knife

Instance Method Details

#bootstrap_templateObject



201
202
203
204
205
206
# File 'lib/chef/knife/bootstrap.rb', line 201

def bootstrap_template
  # The order here is important. We want to check if we have the new Chef 12 option is set first.
  # Knife cloud plugins unfortunately all set a default option for the :distro so it should be at
  # the end.
  config[:bootstrap_template] || config[:template_file] || config[:distro] || default_bootstrap_template
end

#default_bootstrap_templateObject



197
198
199
# File 'lib/chef/knife/bootstrap.rb', line 197

def default_bootstrap_template
  "chef-full"
end

#find_templateObject



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
# File 'lib/chef/knife/bootstrap.rb', line 208

def find_template
  template = bootstrap_template

  # Use the template directly if it's a path to an actual file
  if File.exists?(template)
    Chef::Log.debug("Using the specified bootstrap template: #{File.dirname(template)}")
    return template
  end

  # Otherwise search the template directories until we find the right one
  bootstrap_files = []
  bootstrap_files << File.join(File.dirname(__FILE__), 'bootstrap', "#{template}.erb")
  bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{template}.erb") if Chef::Knife.chef_config_dir
  bootstrap_files << File.join(ENV['HOME'], '.chef', 'bootstrap', "#{template}.erb") if ENV['HOME']
  bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{template}.erb"))
  bootstrap_files.flatten!

  template_file = Array(bootstrap_files).find do |bootstrap_template|
    Chef::Log.debug("Looking for bootstrap template in #{File.dirname(bootstrap_template)}")
    File.exists?(bootstrap_template)
  end

  unless template_file
    ui.info("Can not find bootstrap definition for #{template}")
    raise Errno::ENOENT
  end

  Chef::Log.debug("Found bootstrap template in #{File.dirname(template_file)}")

  template_file
end

#knife_sshObject



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/chef/knife/bootstrap.rb', line 280

def knife_ssh
  ssh = Chef::Knife::Ssh.new
  ssh.ui = ui
  ssh.name_args = [ server_name, ssh_command ]

  # command line arguments and config file values are now merged into config in Chef::Knife#merge_configs
  ssh.config[:ssh_user] = config[:ssh_user]
  ssh.config[:ssh_password] = config[:ssh_password]
  ssh.config[:ssh_port] = config[:ssh_port]
  ssh.config[:ssh_gateway] = config[:ssh_gateway]
  ssh.config[:forward_agent] = config[:forward_agent]
  ssh.config[:identity_file] = config[:identity_file]
  ssh.config[:manual] = true
  ssh.config[:host_key_verify] = config[:host_key_verify]
  ssh.config[:on_error] = :raise
  ssh
end

#knife_ssh_with_password_authObject



298
299
300
301
302
303
# File 'lib/chef/knife/bootstrap.rb', line 298

def knife_ssh_with_password_auth
  ssh = knife_ssh
  ssh.config[:identity_file] = nil
  ssh.config[:ssh_password] = ssh.get_password
  ssh
end

#render_templateObject



240
241
242
243
244
245
246
# File 'lib/chef/knife/bootstrap.rb', line 240

def render_template
  template_file = find_template
  template = IO.read(template_file).chomp
  secret = encryption_secret_provided_ignore_encrypt_flag? ? read_secret : nil
  context = Knife::Core::BootstrapContext.new(config, config[:run_list], Chef::Config, secret)
  Erubis::Eruby.new(template).evaluate(context)
end

#runObject



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

def run
  validate_name_args!
  @node_name = Array(@name_args).first

  $stdout.sync = true
  ui.info("Connecting to #{ui.color(@node_name, :bold)}")

  begin
    knife_ssh.run
  rescue Net::SSH::AuthenticationFailed
    if config[:ssh_password]
      raise
    else
      ui.info("Failed to authenticate #{config[:ssh_user]} - trying password auth")
      knife_ssh_with_password_auth.run
    end
  end
end

#server_nameObject



276
277
278
# File 'lib/chef/knife/bootstrap.rb', line 276

def server_name
  Array(@name_args).first
end

#ssh_commandObject



305
306
307
308
309
310
311
312
313
# File 'lib/chef/knife/bootstrap.rb', line 305

def ssh_command
  command = render_template

  if config[:use_sudo]
    command = config[:use_sudo_password] ? "echo '#{config[:ssh_password]}' | sudo -S #{command}" : "sudo #{command}"
  end

  command
end

#validate_name_args!Object



267
268
269
270
271
272
273
274
# File 'lib/chef/knife/bootstrap.rb', line 267

def validate_name_args!
  if Array(@name_args).first.nil?
    ui.error("Must pass an FQDN or ip to bootstrap")
    exit 1
  elsif Array(@name_args).first == "windows"
    ui.warn("Hostname containing 'windows' specified. Please install 'knife-windows' if you are attempting to bootstrap a Windows node via WinRM.")
  end
end