Skip to content

Commit

Permalink
MSYS-882 Fixes enviornment and run_list params not recognised
Browse files Browse the repository at this point in the history
Signed-off-by: Vasu1105 <vasundhara.jagdale@msystechnologies.com>
  • Loading branch information
Vasu1105 committed Oct 9, 2018
1 parent 3d4e496 commit 67ed323
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 126 deletions.
9 changes: 6 additions & 3 deletions lib/chef/azure/chefhandlers/exception_handler.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

require 'chef/log'
require 'chef/azure/helpers/shared'
require 'json'
Expand Down Expand Up @@ -30,14 +31,14 @@ def report
load_azure_env
message = "Check log file for details...\nBacktrace:\n"
message << Array(backtrace).join("\n")
report_heart_beat_to_azure(AzureHeartBeat::READY, 0, "chef-service is running properly. Chef client run failed with error- #{message}")
report_heart_beat_to_azure(AzureHeartBeat::NOTREADY, 1, "chef-service is running properly. Chef client run failed with error- #{message}")
end
end

def load_run_list
first_boot = File.read("#{bootstrap_directory}/first-boot.json")
first_boot = JSON.parse(first_boot)
run_list = first_boot["run_list"]
run_list = first_boot["target_runlist"]

# Using old way to set node's runlist attribute. Not possible to use
# Validatorless bootstraps to solve this problem, As 'User.pem'
Expand All @@ -50,7 +51,9 @@ def load_run_list
# set runlist
def set_run_list(node, entries)
node.run_list.run_list_items.clear
entries.each { |e| node.run_list << e }
if entries
entries.each { |e| node.run_list << e }
end
end
end
end
2 changes: 1 addition & 1 deletion lib/chef/azure/commands/disable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def run
if @exit_code == 0
report_heart_beat_to_azure(AzureHeartBeat::READY, 0, "chef-service is disabled")
else
report_heart_beat_to_azure(AzureHeartBeat::NOTREADY, 0, "chef-service disable failed")
report_heart_beat_to_azure(AzureHeartBeat::NOTREADY, 1, "chef-service disable failed")
end

return @exit_code
Expand Down
228 changes: 139 additions & 89 deletions lib/chef/azure/commands/enable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,19 @@ def initialize(extension_root, *enable_args)
def run
load_env

report_heart_beat_to_azure(AzureHeartBeat::NOTREADY, 0, "Enabling chef-service...")

enable_chef

if @exit_code == 0
if @chef_client_error
report_heart_beat_to_azure(AzureHeartBeat::READY, 0, "chef-service is enabled. Chef client run failed with error- #{@chef_client_error}")
report_heart_beat_to_azure(AzureHeartBeat::READY, 0, "chef-#{@daemon} is enabled. Chef client run failed with error- #{@chef_client_error}")
else
report_heart_beat_to_azure(AzureHeartBeat::READY, 0, "chef-service is enabled.")
report_heart_beat_to_azure(AzureHeartBeat::READY, 0, "chef-#{@daemon} is enabled.")
end
else
if @chef_client_error
report_heart_beat_to_azure(AzureHeartBeat::NOTREADY, 0, "chef-service enable failed. Chef client run failed with error- #{@chef_client_error}")
report_heart_beat_to_azure(AzureHeartBeat::NOTREADY, 1, "chef-#{@daemon} enable failed. Chef client run failed with error- #{@chef_client_error}")
else
report_heart_beat_to_azure(AzureHeartBeat::NOTREADY, 0, "chef-service enable failed.")
report_heart_beat_to_azure(AzureHeartBeat::NOTREADY, 1, "chef-#{@daemon} enable failed.")
end
end

Expand All @@ -65,19 +63,26 @@ def enable_chef
# - Install the Chef service
# - Start the Chef service
begin
configure_chef_only_once
# "node-registered" file also indicates that enabled was called once and
# configs are already generated.
if File.exist?("#{bootstrap_directory}/node-registered")
puts "#{Time.now} Node is already registered..."
else
configure_chef_only_once
end

@daemon = value_from_json_file(handler_settings_file, 'runtimeSettings', '0', 'handlerSettings', 'publicSettings', 'daemon')
@daemon = (@daemon.nil? || @daemon.empty? || @daemon == "service") ? "service" : "task"
report_heart_beat_to_azure(AzureHeartBeat::NOTREADY, 0, "Enabling chef #{@daemon}...")

if @exit_code == 0
report_status_to_azure("chef-extension enabled", "success")
daemon = value_from_json_file(handler_settings_file, 'runtimeSettings', '0', 'handlerSettings', 'publicSettings', 'daemon')
daemon = "service" if (daemon.nil? || daemon.empty?)
if(daemon == "service" || !windows?)
if(@daemon == "service" || !windows?)
enable_chef_service
elsif daemon == "task" && windows?
elsif @daemon == "task" && windows?
enable_chef_sch_task
end
end

rescue => e
Chef::Log.error e
report_status_to_azure "#{e} - Check log file for details", "error"
Expand Down Expand Up @@ -180,100 +185,145 @@ def enable_chef_sch_task
# => Perform node registration executing first chef run
# => run the user supplied runlist from first_boot.json in async manner
def configure_chef_only_once
# "node-registered" file also indicates that enabled was called once and
# configs are already generated.
bootstrap_options = value_from_json_file(handler_settings_file,'runtimeSettings','0','handlerSettings', 'publicSettings', 'bootstrap_options')
bootstrap_options = eval(bootstrap_options) ? eval(bootstrap_options) : {}

if File.directory?("#{bootstrap_directory}")
puts "#{Time.now} Bootstrap directory [#{bootstrap_directory}] already exists, skipping creation..."
else
puts "#{Time.now} Bootstrap directory [#{bootstrap_directory}] does not exist, creating..."
FileUtils.mkdir_p("#{bootstrap_directory}")
end

puts "#{Time.now} Creating chef configuration files"

copy_settings_file

if not File.exists?("#{bootstrap_directory}/node-registered")
if File.directory?("#{bootstrap_directory}")
puts "Bootstrap directory [#{bootstrap_directory}] already exists, skipping creation..."
load_settings

begin
require 'chef/azure/core/bootstrap_context'

config = configure_settings(bootstrap_options)

Chef::Config[:validation_key_content] = @validation_key
Chef::Config[:client_key_content] = @client_key
Chef::Config[:chef_server_ssl_cert_content] = @chef_server_ssl_cert
template_file = File.expand_path(File.dirname(File.dirname(__FILE__)))
runlist = @run_list.empty? ? [] : escape_runlist(@run_list)
load_cloud_attributes_in_hints if ! @ohai_hints.empty?

if windows?
context = Chef::Knife::Core::WindowsBootstrapContext.new(config, runlist, Chef::Config, config[:secret])
template_file += "\\bootstrap\\windows-chef-client-msi.erb"
bootstrap_bat_file ||= "#{ENV['TMP']}/bootstrap.bat"
template = IO.read(template_file).chomp
bash_template = Erubis::Eruby.new(template).evaluate(context)
File.open(bootstrap_bat_file, 'w') {|f| f.write(bash_template)}
bootstrap_command = "cmd.exe /C #{bootstrap_bat_file}"
else
puts "Bootstrap directory [#{bootstrap_directory}] does not exist, creating..."
FileUtils.mkdir_p("#{bootstrap_directory}")
context = Chef::Knife::Core::BootstrapContext.new(config, runlist, Chef::Config, config[:secret])
template_file += '/bootstrap/chef-full.erb'
template = IO.read(template_file).chomp
bootstrap_command = Erubis::Eruby.new(template).evaluate(context)
end

puts "#{Time.now} Creating chef configuration files"
result = shell_out(bootstrap_command)
result.error!
puts "#{Time.now} Created chef configuration files"

# remove the temp bootstrap file
FileUtils.rm(bootstrap_bat_file) if windows?
rescue Mixlib::ShellOut::ShellCommandFailed => e
Chef::Log.warn "chef-client configuration files creation failed (#{e})"
@chef_client_error = "chef-client configuration files creation failed (#{e})"
return
rescue => e
Chef::Log.error e
@chef_client_error = "chef-client configuration files creation failed (#{e})"
return
end

copy_settings_file
if @extended_logs == 'true'
@chef_client_success_file = windows? ? "c:\\chef_client_success" : "/tmp/chef_client_success"
end

load_settings
# Runs chef-client with custom recipe to set the run_list and environment
begin
current_dir = File.expand_path(File.dirname(File.dirname(__FILE__)))
first_client_run_recipe_path = windows? ? "#{current_dir}\\first_client_run_recipe.rb" : "#{current_dir}/first_client_run_recipe.rb"
command = "chef-client #{first_client_run_recipe_path} -j #{bootstrap_directory}/first-boot.json -c #{bootstrap_directory}/client.rb -L #{@azure_plugin_log_location}/chef-client.log --once"
command += " -E #{config[:environment]}" if config[:environment]
result = shell_out(command)
result.error!
rescue Mixlib::ShellOut::ShellCommandFailed => e
Chef::Log.error "First chef-client run failed. (#{e})"
@chef_client_error = "First chef-client run failed (#{e})"
return
rescue => e
Chef::Log.error e
@chef_client_error = "First chef-client run failed (#{e})"
end

params = "-c #{bootstrap_directory}/client.rb -L #{@azure_plugin_log_location}/chef-client.log --once "

# Runs chef-client in background using scheduled task if windows else using process
if windows?
puts "#{Time.now} Creating scheduled task with runlist #{runlist}.."
schtask = "SCHTASKS.EXE /Create /TN \"Chef Client First Run\" /RU \"NT Authority\\System\" /RP /RL \"HIGHEST\" /SC ONCE /TR \"cmd /c 'C:\\opscode\\chef\\bin\\chef-client #{params}'\" /ST \"#{Time.now.strftime('%H:%M')}\" /F"

begin
require 'chef/azure/core/bootstrap_context'
config = {}
bootstrap_options = value_from_json_file(handler_settings_file,'runtimeSettings','0','handlerSettings', 'publicSettings', 'bootstrap_options')
bootstrap_options = eval(bootstrap_options) ? eval(bootstrap_options) : {}

config[:environment] = bootstrap_options['environment']
config[:chef_node_name] = bootstrap_options['chef_node_name'] if bootstrap_options['chef_node_name']
config[:chef_extension_root] = @chef_extension_root
config[:user_client_rb] = @client_rb
config[:log_location] = @azure_plugin_log_location
Chef::Config[:validation_key_content] = @validation_key
Chef::Config[:client_key_content] = @client_key
Chef::Config[:chef_server_ssl_cert_content] = @chef_server_ssl_cert
config[:chef_server_url] = bootstrap_options['chef_server_url'] if bootstrap_options['chef_server_url']
config[:validation_client_name] = bootstrap_options['validation_client_name'] if bootstrap_options['validation_client_name']
template_file = File.expand_path(File.dirname(File.dirname(__FILE__)))
config[:secret] = @secret
config[:node_verify_api_cert] = bootstrap_options['node_verify_api_cert'] if bootstrap_options['node_verify_api_cert']
config[:node_ssl_verify_mode] = bootstrap_options['node_ssl_verify_mode'] if bootstrap_options['node_ssl_verify_mode']
runlist = @run_list.empty? ? [] : escape_runlist(@run_list)
load_cloud_attributes_in_hints if ! @ohai_hints.empty?
config[:first_boot_attributes] = @first_boot_attributes

if windows?
context = Chef::Knife::Core::WindowsBootstrapContext.new(config, runlist, Chef::Config, config[:secret])
template_file += "\\bootstrap\\windows-chef-client-msi.erb"
bootstrap_bat_file ||= "#{ENV['TMP']}/bootstrap.bat"
template = IO.read(template_file).chomp
bash_template = Erubis::Eruby.new(template).evaluate(context)
File.open(bootstrap_bat_file, 'w') {|f| f.write(bash_template)}
bootstrap_command = "cmd.exe /C #{bootstrap_bat_file}"

result = shell_out(bootstrap_command)
result.error!
puts "#{Time.now} Created chef configuration files"
# remove the temp bootstrap file
FileUtils.rm(bootstrap_bat_file)
else
context = Chef::Knife::Core::BootstrapContext.new(config, runlist, Chef::Config, config[:secret])
template_file += '/bootstrap/chef-full.erb'
template = IO.read(template_file).chomp
bootstrap_command = Erubis::Eruby.new(template).evaluate(context)
result = shell_out(bootstrap_command)
result.error!
puts "#{Time.now} Created chef configuration files"
end
result = @extended_logs == 'true' ? shell_out("#{schtask} && touch #{@chef_client_success_file}") : shell_out(schtask)
result.error!
@chef_client_run_start_time = Time.now

# call to run scheduled task immediately after creation
result = shell_out("SCHTASKS.EXE /Run /TN \"Chef Client First Run\"")
result.error!
rescue Mixlib::ShellOut::ShellCommandFailed => e
Chef::Log.warn "chef-client configuration files creation failed (#{e})"
@chef_client_error = "chef-client configuration files creation failed (#{e})"
return
Chef::Log.error "Creation or running of scheduled task for first chef-client run failed (#{e})"
@chef_client_error = "Creation or running of scheduled task for first chef-client run failed (#{e})"
rescue => e
Chef::Log.error e
@chef_client_error = "chef-client configuration files creation failed (#{e})"
return
end
# Now the run chef-client with runlist in background, as we done want enable command to wait, else long running chef-client with runlist will timeout azure.
puts "#{Time.now} Launching chef-client to register node with the runlist"
params = "-c #{bootstrap_directory}/client.rb -j #{bootstrap_directory}/first-boot.json -L #{@azure_plugin_log_location}/chef-client.log --once "
params += " -E #{config[:environment]}" if config[:environment]

if @extended_logs == 'true'
if windows?
@chef_client_success_file = "c:\\chef_client_success"
else
@chef_client_success_file = "/tmp/chef_client_success"
end
@child_pid = Process.spawn "chef-client #{params} && touch #{@chef_client_success_file}"
@chef_client_run_start_time = Time.now
else
@child_pid = Process.spawn "chef-client #{params}"
@chef_client_error = "Creation or running of scheduled task for first chef-client run failed (#{e})"
end
puts "#{Time.now} Created and ran scheduled task for first chef-client run with runlist #{runlist}"
else
command = @extended_logs == 'true' ? "chef-client #{params} && touch #{@chef_client_success_file}" : "chef-client #{params}"
@child_pid = Process.spawn command
@chef_client_run_start_time = Time.now
Process.detach @child_pid
puts "#{Time.now} Successfully launched chef-client process with PID [#{@child_pid}]"
end
end

# creates the configurations options hash
def configure_settings(bootstrap_options)
config = {
environment: bootstrap_options['environment'],
chef_extension_root: @chef_extension_root,
user_client_rb: @client_rb,
log_location: @azure_plugin_log_location,
secret: @secret,
first_boot_attributes: @first_boot_attributes
}

if bootstrap_options['chef_node_name']
config[:chef_node_name] = bootstrap_options['chef_node_name']
else
chef_client = Chef::Client.new
chef_client.run_ohai
config[:chef_node_name] = chef_client.node_name
end

config[:chef_server_url] = bootstrap_options['chef_server_url'] if bootstrap_options['chef_server_url']
config[:validation_client_name] = bootstrap_options['validation_client_name'] if bootstrap_options['validation_client_name']
config[:node_verify_api_cert] = bootstrap_options['node_verify_api_cert'] if bootstrap_options['node_verify_api_cert']
config[:node_ssl_verify_mode] = bootstrap_options['node_ssl_verify_mode'] if bootstrap_options['node_ssl_verify_mode']

config
end

def chef_client_log_path
chef_config
@chef_config[:log_location] ? @chef_config[:log_location] : "#{@azure_plugin_log_location}/chef-client.log"
Expand Down
2 changes: 1 addition & 1 deletion lib/chef/azure/core/bootstrap_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def client_key
end

def first_boot
@run_list.empty? ? Hash(@config[:first_boot_attributes]) : Hash(@config[:first_boot_attributes]).merge(:run_list => @run_list)
@run_list.empty? ? Hash(@config[:first_boot_attributes]) : Hash(@config[:first_boot_attributes]).merge(:target_runlist => @run_list)
end

def config_content
Expand Down
2 changes: 1 addition & 1 deletion lib/chef/azure/core/windows_bootstrap_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def bootstrap_directory

def first_boot
attributes = (@config[:first_boot_attributes] || {})
first_boot_attributes_and_run_list = @run_list.empty? ? attributes : attributes.merge(:run_list => @run_list)
first_boot_attributes_and_run_list = @run_list.empty? ? attributes : attributes.merge(:target_runlist => @run_list)
escape_and_echo(first_boot_attributes_and_run_list.to_json)
end

Expand Down
2 changes: 2 additions & 0 deletions lib/chef/azure/first_client_run_recipe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node.attributes["target_runlist"].each {|value| node.run_list << value}
node.save
1 change: 1 addition & 0 deletions lib/chef/azure/helpers/shared.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def load_azure_env
def report_heart_beat_to_azure(status, code, message)
# update @azure_heart_beat_file
Chef::Log.info "Reporting heartbeat..."
Chef::Log.info "Reporting heartbeat... Status: #{status}, code: #{code}, message: #{message} "
AzureHeartBeat.update(@azure_heart_beat_file, status, code, message)
end

Expand Down
Loading

0 comments on commit 67ed323

Please sign in to comment.