Class: Chef::Application

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

Direct Known Subclasses

Client, Knife, Solo

Defined Under Namespace

Classes: Client, Knife, Solo, Wakeup, WindowsService

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeApplication

Returns a new instance of Application.


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/chef/application.rb', line 34

def initialize
  super

  @chef_client = nil
  @chef_client_json = nil
  trap("TERM") do
    Chef::Application.fatal!("SIGTERM received, stopping", 1)
  end

  trap("INT") do
    Chef::Application.fatal!("SIGINT received, stopping", 2)
  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

  # 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


152
153
154
155
156
157
158
159
160
161
# File 'lib/chef/application.rb', line 152

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


169
170
171
172
# File 'lib/chef/application.rb', line 169

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


164
165
166
167
# File 'lib/chef/application.rb', line 164

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

Instance Method Details

#configure_chefObject

Parse the configuration file


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/chef/application.rb', line 76

def configure_chef
  parse_options

  begin
    case config[:config_file]
    when /^(http|https):\/\//
      Chef::REST.new("", nil, nil).fetch(config[:config_file]) { |f| apply_config(f.path) }
    else
      ::File::open(config[:config_file]) { |f| apply_config(f.path) }
    end
  rescue Errno::ENOENT => error
    Chef::Log.warn("*****************************************")
    Chef::Log.warn("Did not find config file: #{config[:config_file]}, using command line options.")
    Chef::Log.warn("*****************************************")

    Chef::Config.merge!(config)
  rescue SocketError => error
    Chef::Application.fatal!("Error getting config file #{Chef::Config[:config_file]}", 2)
  rescue Chef::Exceptions::ConfigurationError => error
    Chef::Application.fatal!("Error processing config file #{Chef::Config[:config_file]} with error #{error.message}", 2)
  rescue Exception => error
    Chef::Application.fatal!("Unknown error processing config file #{Chef::Config[:config_file]} with error #{error.message}", 2)
  end

end

#configure_loggingObject

Initialize and configure the logger. If the configured log location is not STDOUT, but stdout is a TTY and we're not daemonizing, we set up a secondary logger with output to stdout. This way, we magically do the right thing when the user has configured logging to a file but they're running chef in the shell to debug something.

If the user has configured a formatter, then we skip the magical logger to keep the output pretty.


110
111
112
113
114
115
116
117
118
119
120
# File 'lib/chef/application.rb', line 110

def configure_logging
  require 'pp'
  Chef::Log.init(Chef::Config[:log_location])
  if ( Chef::Config[:log_location] != STDOUT ) && STDOUT.tty? && (!Chef::Config[:daemonize]) && (Chef::Config.formatter == "null")
    stdout_logger = Logger.new(STDOUT)
    STDOUT.sync = true
    stdout_logger.formatter = Chef::Log.logger.formatter
    Chef::Log.loggers <<  stdout_logger
  end
  Chef::Log.level = Chef::Config[:log_level]
end

#reconfigureObject

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


63
64
65
66
# File 'lib/chef/application.rb', line 63

def reconfigure
  configure_chef
  configure_logging
end

#runObject

Get this party started


69
70
71
72
73
# File 'lib/chef/application.rb', line 69

def run
  reconfigure
  setup_application
  run_application
end

#run_applicationObject

Actually run the application


128
129
130
# File 'lib/chef/application.rb', line 128

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

#run_chef_clientObject

Initializes Chef::Client instance and runs it


133
134
135
136
137
138
139
140
141
142
# File 'lib/chef/application.rb', line 133

def run_chef_client
  @chef_client = Chef::Client.new(
    @chef_client_json, 
    :override_runlist => config[:override_runlist]
  )
  @chef_client_json = nil

  @chef_client.run
  @chef_client = nil
end

#setup_applicationObject

Called prior to starting the application, by the run method


123
124
125
# File 'lib/chef/application.rb', line 123

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