Class: Chef::Application

Inherits:
Object show all
Includes:
Mixlib::CLI
Defined in:
lib/chef/application.rb,
lib/chef/application/windows_service.rb,
lib/chef/application/windows_service_manager.rb

Direct Known Subclasses

Apply, Client, Knife, Solo

Defined Under Namespace

Classes: Apply, Client, Knife, Solo, WindowsService, WindowsServiceManager

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeApplication

Returns a new instance of Application.



35
36
37
38
39
40
41
42
43
# File 'lib/chef/application.rb', line 35

def initialize
  super

  @chef_client = nil
  @chef_client_json = nil

  # Always switch to a readable directory. Keeps subsequent Dir.chdir() {}
  # from failing due to permissions when launched as a less privileged user.
end

Class Method Details

.debug_stacktrace(e) ⇒ Object



375
376
377
378
379
380
381
382
383
384
# File 'lib/chef/application.rb', line 375

def debug_stacktrace(e)
  message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
  chef_stacktrace_out = "Generated at #{Time.now.to_s}\n"
  chef_stacktrace_out += message

  Chef::FileCache.store("chef-stacktrace.out", chef_stacktrace_out)
  Chef::Log.fatal("Stacktrace dumped to #{Chef::FileCache.load("chef-stacktrace.out", false)}")
  Chef::Log.debug(message)
  true
end

.exit!(msg, err = -1)) ⇒ Object



392
393
394
395
# File 'lib/chef/application.rb', line 392

def exit!(msg, err = -1)
  Chef::Log.debug(msg)
  Process.exit err
end

.fatal!(msg, err = -1)) ⇒ Object

Log a fatal error message to both STDERR and the Logger, exit the application



387
388
389
390
# File 'lib/chef/application.rb', line 387

def fatal!(msg, err = -1)
  Chef::Log.fatal(msg)
  Process.exit err
end

Instance Method Details

#auto_log_level?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/chef/application.rb', line 158

def auto_log_level?
  Chef::Config[:log_level] == :auto
end

#configure_chefObject

Parse configuration (options and config file)



83
84
85
86
# File 'lib/chef/application.rb', line 83

def configure_chef
  parse_options
  load_config_file
end

#configure_encodingObject

Sets the default external encoding to UTF-8 (users can change this, but they shouldn’t)



185
186
187
# File 'lib/chef/application.rb', line 185

def configure_encoding
  Encoding.default_external = Chef::Config[:ruby_encoding]
end

#configure_loggingObject

Initialize and configure the logger.

Loggers and Formatters

In Chef 10.x and previous, the Logger was the primary/only way that Chef communicated information to the user. In Chef 10.14, a new system, “output formatters” was added, and in Chef 11.0+ it is the default when running chef in a console (detected by ‘STDOUT.tty?`). Because output formatters are more complex than the logger system and users have less experience with them, the config option `force_logger` is provided to restore the Chef 10.x behavior.

Conversely, for users who want formatter output even when chef is running unattended, the ‘force_formatter` option is provided.

Auto Log Level

When ‘log_level` is set to `:auto` (default), the log level will be `:warn` when the primary output mode is an output formatter (see using_output_formatter?) and `:info` otherwise.

Automatic STDOUT Logging

When ‘force_logger` is configured (e.g., Chef 10 mode), a second logger with output on STDOUT is added when running in a console (STDOUT is a tty) and the configured log_location isn’t STDOUT. This accounts for the case that a user has configured a log_location in client.rb, but is running chef-client by hand to troubleshoot a problem.



129
130
131
132
133
134
135
136
137
138
# File 'lib/chef/application.rb', line 129

def configure_logging
  Chef::Log.init(MonoLogger.new(Chef::Config[:log_location]))
  if want_additional_logger?
    configure_stdout_logger
  end
  Chef::Log.level = resolve_log_level
rescue StandardError => error
  Chef::Log.fatal("Failed to open or create log file at #{Chef::Config[:log_location]}: #{error.class} (#{error.message})")
  Chef::Application.fatal!("Aborting due to invalid 'log_location' configuration", 2)
end

#configure_proxy_environment_variablesObject

Configure and set any proxy environment variables according to the config.



177
178
179
180
181
182
# File 'lib/chef/application.rb', line 177

def configure_proxy_environment_variables
  configure_http_proxy
  configure_https_proxy
  configure_ftp_proxy
  configure_no_proxy
end

#configure_stdout_loggerObject



140
141
142
143
144
# File 'lib/chef/application.rb', line 140

def configure_stdout_logger
  stdout_logger = MonoLogger.new(STDOUT)
  stdout_logger.formatter = Chef::Log.logger.formatter
  Chef::Log.loggers <<  stdout_logger
end

#load_config_fileObject

Parse the config file



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/chef/application.rb', line 89

def load_config_file
  config_fetcher = Chef::ConfigFetcher.new(config[:config_file])
  if config[:config_file].nil?
    Chef::Log.warn("No config file found or specified on command line, using command line options.")
  elsif config_fetcher.config_missing?
    pp config_missing: true
    Chef::Log.warn("*****************************************")
    Chef::Log.warn("Did not find config file: #{config[:config_file]}, using command line options.")
    Chef::Log.warn("*****************************************")
  else
    config_content = config_fetcher.read_config
    apply_config(config_content, config[:config_file])
  end
  Chef::Config.merge!(config)
end

#reconfigureObject

Reconfigure the application. You’ll want to override and super this method.



46
47
48
49
50
51
# File 'lib/chef/application.rb', line 46

def reconfigure
  configure_chef
  configure_logging
  configure_proxy_environment_variables
  configure_encoding
end

#resolve_log_levelObject

if log_level is ‘:auto`, convert it to :warn (when using output formatter) or :info (no output formatter). See also using_output_formatter?



164
165
166
167
168
169
170
171
172
173
174
# File 'lib/chef/application.rb', line 164

def resolve_log_level
  if auto_log_level?
    if using_output_formatter?
      :warn
    else
      :info
    end
  else
    Chef::Config[:log_level]
  end
end

#runObject

Get this party started



54
55
56
57
58
59
# File 'lib/chef/application.rb', line 54

def run
  setup_signal_handlers
  reconfigure
  setup_application
  run_application
end

#run_applicationObject

Actually run the application



195
196
197
# File 'lib/chef/application.rb', line 195

def run_application
  raise Chef::Exceptions::Application, "#{self.to_s}: you must override run_application"
end

#run_chef_client(specific_recipes = []) ⇒ Object

Initializes Chef::Client instance and runs it



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
# File 'lib/chef/application.rb', line 200

def run_chef_client(specific_recipes = [])
  Chef::LocalMode.with_server_connectivity do
    override_runlist = config[:override_runlist]
    if specific_recipes.size > 0
      override_runlist ||= []
    end
    @chef_client = Chef::Client.new(
      @chef_client_json,
      :override_runlist => config[:override_runlist],
      :specific_recipes => specific_recipes,
      :runlist => config[:runlist]
    )
    @chef_client_json = nil

    if can_fork?
      fork_chef_client # allowed to run client in forked process
    else
      # Unforked interval runs are disabled, so this runs chef-client
      # once and then exits. If TERM signal is received, will "ignore"
      # the signal to finish converge.
      run_with_graceful_exit_option
    end
    @chef_client = nil
  end
end

#setup_applicationObject

Called prior to starting the application, by the run method



190
191
192
# File 'lib/chef/application.rb', line 190

def setup_application
  raise Chef::Exceptions::Application, "#{self.to_s}: you must override setup_application"
end

#setup_signal_handlersObject



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/chef/application.rb', line 61

def setup_signal_handlers
  trap("INT") do
    Chef::Application.fatal!("SIGINT received, stopping", 2)
  end

  trap("TERM") do
    Chef::Application.fatal!("SIGTERM received, stopping", 3)
  end

  unless Chef::Platform.windows?
    trap("QUIT") do
      Chef::Log.info("SIGQUIT received, call stack:\n  " + caller.join("\n  "))
    end

    trap("HUP") do
      Chef::Log.info("SIGHUP received, reconfiguring")
      reconfigure
    end
  end
end

#using_output_formatter?Boolean

Use of output formatters is assumed if ‘force_formatter` is set or if `force_logger` is not set and STDOUT is to a console (tty)

Returns:

  • (Boolean)


154
155
156
# File 'lib/chef/application.rb', line 154

def using_output_formatter?
  Chef::Config[:force_formatter] || (!Chef::Config[:force_logger] && STDOUT.tty?)
end

#want_additional_logger?Boolean

Based on config and whether or not STDOUT is a tty, should we setup a secondary logger for stdout?

Returns:

  • (Boolean)


148
149
150
# File 'lib/chef/application.rb', line 148

def want_additional_logger?
  ( Chef::Config[:log_location] != STDOUT ) && STDOUT.tty? && (!Chef::Config[:daemonize]) && (Chef::Config[:force_logger])
end