chef 0.9.8.beta.1 → 0.9.8.beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -200,15 +200,24 @@ class Chef
200
200
 
201
201
  def ask_question(question, opts={})
202
202
  question = question + "[#{opts[:default]}] " if opts[:default]
203
-
204
- stdout.print question
205
- a = stdin.readline.strip
206
203
 
207
- if opts[:default]
208
- a.empty? ? opts[:default] : a
204
+ if opts[:default] and config[:defaults]
205
+
206
+ opts[:default]
207
+
209
208
  else
210
- a
209
+
210
+ stdout.print question
211
+ a = stdin.readline.strip
212
+
213
+ if opts[:default]
214
+ a.empty? ? opts[:default] : a
215
+ else
216
+ a
217
+ end
218
+
211
219
  end
220
+
212
221
  end
213
222
 
214
223
  def configure_chef
@@ -58,13 +58,7 @@ class Chef
58
58
  :description => "Bootstrap a distro using a template",
59
59
  :default => "ubuntu10.04-gems"
60
60
 
61
- option :identity_file,
62
- :short => "-i IDENTITY_FILE",
63
- :long => "--identity-file IDENTITY_FILE",
64
- :description => "The SSH identity file used for authentication"
65
-
66
61
  option :use_sudo,
67
- :short => "-s",
68
62
  :long => "--sudo",
69
63
  :description => "Execute the bootstrap via sudo",
70
64
  :boolean => true
@@ -79,7 +73,7 @@ class Chef
79
73
  :long => "--run-list RUN_LIST",
80
74
  :description => "Comma separated list of roles/recipes to apply",
81
75
  :proc => lambda { |o| o.split(",") },
82
- :default => nil
76
+ :default => []
83
77
 
84
78
  def h
85
79
  @highline ||= HighLine.new
@@ -0,0 +1,32 @@
1
+ bash -c '
2
+ if [ ! -f /usr/bin/chef-client ]; then
3
+ echo "chef chef/chef_server_url string <%= Chef::Config[:chef_server_url] %>" | debconf-set-selections
4
+ [ -f /etc/apt/sources.list.d/opscode.list ] || echo "deb http://apt.opscode.com lucid main" > /etc/apt/sources.list.d/opscode.list
5
+ wget -O- http://apt.opscode.com/packages@opscode.com.gpg.key | apt-key add -
6
+ apt-get update
7
+ apt-get install -y chef
8
+ fi
9
+
10
+ <% unless Chef::Config[:validation_client_name] == "chef-validator" -%>
11
+ [ `grep -qx "validation_client_name \"<%= Chef::Config[:validation_client_name] %>\"" /etc/chef/client.rb` ] || echo "validation_client_name \"<%= Chef::Config[:validation_client_name] %>\"" >> /etc/chef/client.rb
12
+ <% end -%>
13
+
14
+ (
15
+ cat <<'EOP'
16
+ <%= IO.read(Chef::Config[:validation_key]) %>
17
+ EOP
18
+ ) > /tmp/validation.pem
19
+ awk NF /tmp/validation.pem > /etc/chef/validation.pem
20
+ rm /tmp/validation.pem
21
+
22
+ <% if @config[:chef_node_name] %>
23
+ [ `grep -qx "node_name \"<%= @config[:chef_node_name] %>\"" /etc/chef/client.rb` ] || echo "node_name \"<%= @config[:chef_node_name] %>\"" >> /etc/chef/client.rb
24
+ <% end -%>
25
+
26
+ (
27
+ cat <<'EOP'
28
+ <%= { "run_list" => @run_list }.to_json %>
29
+ EOP
30
+ ) > /etc/chef/first-boot.json
31
+
32
+ /usr/bin/chef-client -j /etc/chef/first-boot.json'
@@ -26,35 +26,57 @@ class Chef
26
26
  class CookbookCreate < Knife
27
27
  include Chef::Mixin::ShellOut
28
28
 
29
- banner "knife cookbook create COOKBOOK [COMPANY_NAME_FOR_COPYRIGHT] [EMAIL] [APACHE_LICENSE=false] (options)"
29
+ banner "knife cookbook create COOKBOOK (options)"
30
30
 
31
31
  option :cookbook_path,
32
32
  :short => "-o PATH",
33
33
  :long => "--cookbook-path PATH",
34
34
  :description => "The directory where the cookbook will be created"
35
35
 
36
+ option :readme_format,
37
+ :short => "-r FORMAT",
38
+ :long => "--readme-format FORMAT",
39
+ :description => "Format of the README file, supported formats are 'md' (markdown) and 'rdoc' (rdoc)",
40
+ :default => "rdoc"
41
+
42
+ option :cookbook_license,
43
+ :short => "-I LICENSE",
44
+ :long => "--license LICENSE",
45
+ :description => "License for cookbook, apachev2 or none"
46
+
47
+ option :cookbook_copyright,
48
+ :short => "-C COPYRIGHT",
49
+ :long => "--copyright COPYRIGHT",
50
+ :description => "Name of Copyright holder"
51
+
52
+ option :cookbook_email,
53
+ :short => "-E EMAIL",
54
+ :long => "--email EMAIL",
55
+ :description => "Email address of cookbook maintainer"
56
+
36
57
  def run
37
- if @name_args.length < 1
38
- show_usage
39
- Chef::Log.fatal("You must specify a cookbook name")
40
- exit 1
58
+ self.config = Chef::Config.merge!(config)
59
+ if @name_args.length < 1
60
+ show_usage
61
+ Chef::Log.fatal("You must specify a cookbook name")
62
+ exit 1
41
63
  end
42
64
 
43
- if default_cookbook_path_empty? && given_cookbook_path_empty?
65
+ if default_cookbook_path_empty? && parameter_empty?(config[:cookbook_path])
44
66
  raise ArgumentError, "Default cookbook_path is not specified in the knife.rb config file, and a value to -o is not provided. Nowhere to write the new cookbook to."
45
67
  end
46
68
 
47
- cookbook_path = given_cookbook_path_empty? ? Chef::Config[:cookbook_path].first : config[:cookbook_path]
69
+ cookbook_path = Array(config[:cookbook_path]).first
48
70
  cookbook_name = @name_args.first
49
- company_name = @name_args[1].nil? || @name_args[1].empty? ? "YOUR_COMPANY_NAME" : @name_args[1]
50
- email = @name_args[2].nil? || @name_args[2].empty? ? "YOUR_EMAIL" : @name_args[2]
51
- license = (@name_args[3].nil? || @name_args[3].to_s.empty? || @name_args[3] == false || @name_args[3] == 'false') ? :none : :apachev2
52
- create_cookbook(cookbook_path,cookbook_name, company_name, license)
71
+ copyright = config[:cookbook_copyright] || "YOUR_COMPANY_NAME"
72
+ email = config[:cookbook_email] || "YOUR_EMAIL"
73
+ license = ((config[:cookbook_license] != "false") && config[:cookbook_license]) || "none"
74
+ create_cookbook(cookbook_path,cookbook_name, copyright, license)
53
75
  create_readme(cookbook_path,cookbook_name)
54
- create_metadata(cookbook_path,cookbook_name, company_name, email, license)
76
+ create_metadata(cookbook_path,cookbook_name, copyright, email, license)
55
77
  end
56
78
 
57
- def create_cookbook(dir, cookbook_name, company_name, license)
79
+ def create_cookbook(dir, cookbook_name, copyright, license)
58
80
  msg("** Creating cookbook #{cookbook_name}")
59
81
  shell_out "mkdir -p #{File.join(dir, cookbook_name, "attributes")}"
60
82
  shell_out "mkdir -p #{File.join(dir, cookbook_name, "recipes")}"
@@ -71,11 +93,11 @@ class Chef
71
93
  # Cookbook Name:: #{cookbook_name}
72
94
  # Recipe:: default
73
95
  #
74
- # Copyright #{Time.now.year}, #{company_name}
96
+ # Copyright #{Time.now.year}, #{copyright}
75
97
  #
76
98
  EOH
77
99
  case license
78
- when :apachev2
100
+ when "apachev2"
79
101
  file.puts <<-EOH
80
102
  # Licensed under the Apache License, Version 2.0 (the "License");
81
103
  # you may not use this file except in compliance with the License.
@@ -90,7 +112,7 @@ EOH
90
112
  # limitations under the License.
91
113
  #
92
114
  EOH
93
- when :none
115
+ when "none"
94
116
  file.puts <<-EOH
95
117
  # All rights reserved - Do Not Redistribute
96
118
  #
@@ -102,9 +124,11 @@ EOH
102
124
 
103
125
  def create_readme(dir, cookbook_name)
104
126
  msg("** Creating README for cookbook: #{cookbook_name}")
105
- unless File.exists?(File.join(dir, cookbook_name, "README.rdoc"))
106
- open(File.join(dir, cookbook_name, "README.rdoc"), "w") do |file|
107
- file.puts <<-EOH
127
+ unless File.exists?(File.join(dir, cookbook_name, "README.#{config[:readme_format]}"))
128
+ open(File.join(dir, cookbook_name, "README.#{config[:readme_format]}"), "w") do |file|
129
+ case config[:readme_format]
130
+ when "rdoc"
131
+ file.puts <<-EOH
108
132
  = DESCRIPTION:
109
133
 
110
134
  = REQUIREMENTS:
@@ -114,27 +138,54 @@ EOH
114
138
  = USAGE:
115
139
 
116
140
  EOH
141
+ when "md","mkd","txt"
142
+ file.puts <<-EOH
143
+ Description
144
+ ===========
145
+
146
+ Requirements
147
+ ============
148
+
149
+ Attributes
150
+ ==========
151
+
152
+ Usage
153
+ =====
154
+
155
+ EOH
156
+ else
157
+ file.puts <<-EOH
158
+ Description
159
+
160
+ Requirements
161
+
162
+ Attributes
163
+
164
+ Usage
165
+
166
+ EOH
167
+ end
117
168
  end
118
169
  end
119
170
  end
120
171
 
121
- def create_metadata(dir, cookbook_name, company_name, email, license)
172
+ def create_metadata(dir, cookbook_name, copyright, email, license)
122
173
  msg("** Creating metadata for cookbook: #{cookbook_name}")
123
174
 
124
175
  license_name = case license
125
- when :apachev2
176
+ when "apachev2"
126
177
  "Apache 2.0"
127
- when :none
178
+ when "none"
128
179
  "All rights reserved"
129
180
  end
130
181
 
131
182
  unless File.exists?(File.join(dir, cookbook_name, "metadata.rb"))
132
183
  open(File.join(dir, cookbook_name, "metadata.rb"), "w") do |file|
133
- if File.exists?(File.join(dir, cookbook_name, 'README.rdoc'))
134
- long_description = "long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))"
184
+ if File.exists?(File.join(dir, cookbook_name, "README.#{config[:readme_format]}"))
185
+ long_description = "long_description IO.read(File.join(File.dirname(__FILE__), 'README.#{config[:readme_format]}'))"
135
186
  end
136
187
  file.puts <<-EOH
137
- maintainer "#{company_name}"
188
+ maintainer "#{copyright}"
138
189
  maintainer_email "#{email}"
139
190
  license "#{license_name}"
140
191
  description "Installs/Configures #{cookbook_name}"
@@ -146,14 +197,13 @@ EOH
146
197
  end
147
198
 
148
199
  private
149
- def default_cookbook_path_empty?
150
- Chef::Config[:cookbook_path].nil? || Chef::Config[:cookbook_path].empty?
151
- end
152
-
153
- def given_cookbook_path_empty?
154
- config[:cookbook_path].nil? || config[:cookbook_path].empty?
155
- end
200
+ def default_cookbook_path_empty?
201
+ Chef::Config[:cookbook_path].nil? || Chef::Config[:cookbook_path].empty?
202
+ end
156
203
 
204
+ def parameter_empty?(parameter)
205
+ parameter.nil? || parameter.empty?
206
+ end
157
207
  end
158
208
  end
159
- end
209
+ end
@@ -61,8 +61,13 @@ class Chef
61
61
  :description => "The ssh username",
62
62
  :default => "root"
63
63
 
64
+ option :ssh_password,
65
+ :short => "-P PASSWORD",
66
+ :long => "--ssh-password PASSWORD",
67
+ :description => "The ssh password"
68
+
64
69
  option :identity_file,
65
- :short => "-i IDENTITY_FILE",
70
+ :short => "-I IDENTITY_FILE",
66
71
  :long => "--identity-file IDENTITY_FILE",
67
72
  :description => "The SSH identity file used for authentication"
68
73
 
@@ -87,6 +92,17 @@ class Chef
87
92
  :description => "Your AWS region",
88
93
  :default => "us-east-1"
89
94
 
95
+ option :distro,
96
+ :short => "-d DISTRO",
97
+ :long => "--distro DISTRO",
98
+ :description => "Bootstrap a distro using a template",
99
+ :default => "ubuntu10.04-gems"
100
+
101
+ option :template_file,
102
+ :long => "--template-file TEMPLATE",
103
+ :description => "Full path to location of template to use",
104
+ :default => false
105
+
90
106
  def h
91
107
  @highline ||= HighLine.new
92
108
  end
@@ -124,8 +140,10 @@ class Chef
124
140
 
125
141
  # wait for it to be ready to do stuff
126
142
  server.wait_for { print "."; ready? }
143
+ puts "#{h.color("\nWaiting 10 seconds for SSH Host Key generation on", :magenta)}: #{server.dns_name}"
144
+ sleep 10
127
145
 
128
- print "\n\n"
146
+ print "\n"
129
147
 
130
148
  puts "#{h.color("Public DNS Name", :cyan)}: #{server.dns_name}"
131
149
  puts "#{h.color("Public IP Address", :cyan)}: #{server.ip_address}"
@@ -134,11 +152,15 @@ class Chef
134
152
 
135
153
  begin
136
154
  bootstrap = Chef::Knife::Bootstrap.new
137
- bootstrap.name_args = [ server.ip_address, @name_args ].flatten
155
+ bootstrap.name_args = server.dns_name
156
+ bootstrap.config[:run_list] = @name_args
138
157
  bootstrap.config[:ssh_user] = config[:ssh_user]
139
158
  bootstrap.config[:identity_file] = config[:identity_file]
140
159
  bootstrap.config[:chef_node_name] = server.id
141
160
  bootstrap.config[:prerelease] = config[:prerelease]
161
+ bootstrap.config[:distro] = config[:distro]
162
+ bootstrap.config[:use_sudo] = true
163
+ bootstrap.config[:template_file] = config[:template_file]
142
164
  bootstrap.run
143
165
  rescue Errno::ECONNREFUSED
144
166
  puts h.color("Connection refused on SSH, retrying - CTRL-C to abort")
@@ -74,10 +74,18 @@ class Chef
74
74
  end
75
75
 
76
76
  def format_values(hash)
77
- formatted_array = hash.map { |key, value| [key.to_s, value]}.flatten
77
+ formatted_array = flatten_one_level(hash.map { |key, value| [key.to_s, value]})
78
78
  Hash[*formatted_array]
79
79
  end
80
80
 
81
+ def flatten_one_level(array)
82
+ array.inject([]) do |flatter_array, values|
83
+ Array(values).each {|value| flatter_array << value }
84
+ flatter_array
85
+ end
86
+ end
87
+
88
+
81
89
  def assert_valid_platform_values!(platforms, value)
82
90
  unless value.kind_of?(Hash)
83
91
  msg = "platform dependent values must be specified in the format :platform => {:version => value} "
@@ -179,6 +179,7 @@ class Chef
179
179
  time = Time.now
180
180
  savetime = time.strftime("%Y%m%d%H%M%S")
181
181
  backup_filename = "#{@new_resource.path}.chef-#{savetime}"
182
+ backup_filename = backup_filename.sub(/^([A-Za-z]:)/, "") #strip drive letter on Windows
182
183
  # if :file_backup_path is nil, we fallback to the old behavior of
183
184
  # keeping the backup in the same directory. We also need to to_s it
184
185
  # so we don't get a type error around implicit to_str conversions.
@@ -100,11 +100,11 @@ class Chef
100
100
  def upgrade_package(name, version)
101
101
  if version
102
102
  run_command(
103
- :command => "zypper -n --no-gpg-checks update -l #{name}=#{version}"
103
+ :command => "zypper -n --no-gpg-checks install -l #{name}=#{version}"
104
104
  )
105
105
  else
106
106
  run_command(
107
- :command => "zypper -n --no-gpg-checks update -l #{name}"
107
+ :command => "zypper -n --no-gpg-checks install -l #{name}"
108
108
  )
109
109
  end
110
110
  end
@@ -64,8 +64,8 @@ class Chef
64
64
  if absolute_uri?(source)
65
65
  Chef::Provider::RemoteFile
66
66
  else
67
- # contentious...
68
67
  Chef::Log.warn("remote_file is deprecated for fetching files from cookbooks. Use cookbook_file instead")
68
+ Chef::Log.warn("From #{self.to_s} on #{source_line}")
69
69
  Chef::Provider::CookbookFile
70
70
  end
71
71
  end
@@ -5,9 +5,9 @@
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
7
7
  # You may obtain a copy of the License at
8
- #
8
+ #
9
9
  # http://www.apache.org/licenses/LICENSE-2.0
10
- #
10
+ #
11
11
  # Unless required by applicable law or agreed to in writing, software
12
12
  # distributed under the License is distributed on an "AS IS" BASIS,
13
13
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,6 +20,7 @@ require "pp"
20
20
  require "etc"
21
21
  require "mixlib/cli"
22
22
 
23
+ require 'chef/version'
23
24
  require "chef/client"
24
25
  require "chef/config"
25
26
 
@@ -31,74 +32,121 @@ module Shef
31
32
  LEADERS = Hash.new("")
32
33
  LEADERS[Chef::Recipe] = ":recipe"
33
34
  LEADERS[Chef::Node] = ":attributes"
34
-
35
+
35
36
  class << self
36
- attr_accessor :client_type, :options
37
+ attr_accessor :client_type
38
+ attr_accessor :options
39
+ attr_accessor :env
40
+ attr_writer :editor
41
+ end
42
+
43
+ # Start the irb REPL with shef's customizations
44
+ def self.start
45
+ setup_logger
46
+ # FUGLY HACK: irb gives us no other choice.
47
+ irb_help = [:help, :irb_help, IRB::ExtendCommandBundle::NO_OVERRIDE]
48
+ IRB::ExtendCommandBundle.instance_variable_get(:@ALIASES).delete(irb_help)
49
+
50
+ parse_opts
51
+
52
+ # HACK: this duplicates the functions of IRB.start, but we have to do it
53
+ # to get access to the main object before irb starts.
54
+ ::IRB.setup(nil)
55
+
56
+ irb = IRB::Irb.new
57
+
58
+ init(irb.context.main)
59
+
60
+
61
+ irb_conf[:IRB_RC].call(irb.context) if irb_conf[:IRB_RC]
62
+ irb_conf[:MAIN_CONTEXT] = irb.context
63
+
64
+ trap("SIGINT") do
65
+ irb.signal_handle
66
+ end
67
+
68
+ catch(:IRB_EXIT) do
69
+ irb.eval_input
70
+ end
71
+ end
72
+
73
+ def self.setup_logger
74
+ Chef::Config[:log_level] ||= :warn
75
+ Chef::Log.init(STDERR)
76
+ Mixlib::Authentication::Log.logger = Ohai::Log.logger = Chef::Log.logger
77
+ Chef::Log.level = Chef::Config[:log_level] || :warn
37
78
  end
38
-
79
+
39
80
  # Shef assumes it's running whenever it is defined
40
81
  def self.running?
41
82
  true
42
83
  end
43
-
84
+
44
85
  # Set the irb_conf object to something other than IRB.conf
45
86
  # usful for testing.
46
87
  def self.irb_conf=(conf_hash)
47
88
  @irb_conf = conf_hash
48
89
  end
49
-
90
+
50
91
  def self.irb_conf
51
92
  @irb_conf || IRB.conf
52
93
  end
53
-
94
+
54
95
  def self.configure_irb
55
96
  irb_conf[:HISTORY_FILE] = "~/.shef_history"
56
97
  irb_conf[:SAVE_HISTORY] = 1000
57
-
98
+
58
99
  irb_conf[:IRB_RC] = lambda do |conf|
59
100
  m = conf.main
60
- leader = LEADERS[m.class]
61
-
62
- def m.help
63
- shef_help
64
- end
65
101
 
66
- conf.prompt_c = "chef#{leader} > "
102
+ conf.prompt_c = "chef#{leader(m)} > "
67
103
  conf.return_format = " => %s \n"
68
- conf.prompt_i = "chef#{leader} > "
69
- conf.prompt_n = "chef#{leader} ?> "
70
- conf.prompt_s = "chef#{leader}%l> "
104
+ conf.prompt_i = "chef#{leader(m)} > "
105
+ conf.prompt_n = "chef#{leader(m)} ?> "
106
+ conf.prompt_s = "chef#{leader(m)}%l> "
71
107
  end
72
108
  end
73
-
109
+
110
+ def self.leader(main_object)
111
+ env_string = Shef.env ? " (#{Shef.env})" : ""
112
+ LEADERS[main_object.class] + env_string
113
+ end
114
+
74
115
  def self.session
75
- client_type.instance.reset! unless client_type.instance.node_built?
116
+ unless client_type.instance.node_built?
117
+ puts "Session type: #{client_type.session_type}"
118
+ client_type.instance.reset!
119
+ end
76
120
  client_type.instance
77
121
  end
78
-
79
- def self.init
122
+
123
+ def self.init(main)
80
124
  parse_json
81
125
  configure_irb
82
126
 
83
127
  session # trigger ohai run + session load
84
-
128
+
85
129
  session.node.consume_attributes(@json_attribs)
86
130
 
87
- greeting = begin
88
- " #{Etc.getlogin}@#{Shef.session.node.name}"
89
- rescue NameError
90
- ""
91
- end
131
+ Extensions.extend_context_object(main)
92
132
 
93
- version
133
+ main.version
94
134
  puts
95
135
 
96
136
  puts "run `help' for help, `exit' or ^D to quit."
97
137
  puts
98
138
  puts "Ohai2u#{greeting}!"
99
139
  end
100
-
140
+
141
+ def self.greeting
142
+ " #{Etc.getlogin}@#{Shef.session.node.fqdn}"
143
+ rescue NameError
144
+ ""
145
+ end
146
+
101
147
  def self.parse_json
148
+ # HACK: copied verbatim from chef/application/client, because it's not
149
+ # reusable as written there :(
102
150
  if Chef::Config[:json_attribs]
103
151
  begin
104
152
  json_io = open(Chef::Config[:json_attribs])
@@ -119,28 +167,48 @@ module Shef
119
167
  end
120
168
  end
121
169
  end
122
-
170
+
123
171
  def self.fatal!(message, exit_status)
124
172
  Chef::Log.fatal(message)
125
173
  exit exit_status
126
174
  end
127
-
175
+
128
176
  def self.client_type
129
177
  type = Shef::StandAloneSession
130
178
  type = Shef::SoloSession if Chef::Config[:shef_solo]
131
179
  type = Shef::ClientSession if Chef::Config[:client]
180
+ type = Shef::DoppelGangerSession if Chef::Config[:doppelganger]
132
181
  type
133
182
  end
134
-
183
+
135
184
  def self.parse_opts
136
185
  @options = Options.new
137
186
  @options.parse_opts
138
187
  end
139
-
188
+
189
+ def self.editor
190
+ @editor || Chef::Config[:editor] || ENV['EDITOR']
191
+ end
192
+
140
193
  class Options
141
194
  include Mixlib::CLI
142
195
 
143
- option :config_file,
196
+ def self.footer(text=nil)
197
+ @footer = text if text
198
+ @footer
199
+ end
200
+
201
+ banner("shef #{Chef::VERSION}\n\nUsage: shef [NAMED_CONF] (OPTIONS)")
202
+
203
+ footer(<<-FOOTER)
204
+ When no CONFIG is specified, shef attempts to load a default configuration file:
205
+ * If a NAMED_CONF is given, shef will load ~/.chef/NAMED_CONF/shef.rb
206
+ * If no NAMED_CONF is given shef will load ~/.chef/shef.rb if it exists
207
+ * Shef falls back to loading /etc/chef/client.rb or /etc/chef/solo.rb if -z or
208
+ -s options are given and no shef.rb can be found.
209
+ FOOTER
210
+
211
+ option :config_file,
144
212
  :short => "-c CONFIG",
145
213
  :long => "--config CONFIG",
146
214
  :description => "The configuration file to use"
@@ -151,8 +219,13 @@ module Shef
151
219
  :description => "Show this message",
152
220
  :on => :tail,
153
221
  :boolean => true,
154
- :show_options => true,
155
- :exit => 0
222
+ :proc => proc { print_help }
223
+
224
+ option :log_level,
225
+ :short => "-l LOG_LEVEL",
226
+ :long => '--log-level LOG_LEVEL',
227
+ :description => "Set the logging level",
228
+ :proc => proc { |level| Chef::Log.level = level.to_sym }
156
229
 
157
230
  option :standalone,
158
231
  :short => "-a",
@@ -194,31 +267,57 @@ module Shef
194
267
  :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
195
268
  :exit => 0
196
269
 
270
+ def self.print_help
271
+ instance = new
272
+ instance.parse_options([])
273
+ puts instance.opt_parser
274
+ puts
275
+ puts footer
276
+ puts
277
+ exit 1
278
+ end
279
+
197
280
  def self.setup!
198
281
  self.new.parse_opts
199
282
  end
200
283
 
201
284
  def parse_opts
202
- parse_options
285
+ remainder = parse_options
286
+ environment = remainder.first
203
287
  # We have to nuke ARGV to make sure irb's option parser never sees it.
204
288
  # otherwise, IRB complains about command line switches it doesn't recognize.
205
289
  ARGV.clear
206
- config[:config_file] = config_file_for_shef_mode
290
+ config[:config_file] = config_file_for_shef_mode(environment)
207
291
  config_msg = config[:config_file] || "none (standalone shef session)"
208
292
  puts "loading configuration: #{config_msg}"
209
293
  Chef::Config.from_file(config[:config_file]) if !config[:config_file].nil? && File.exists?(config[:config_file]) && File.readable?(config[:config_file])
210
294
  Chef::Config.merge!(config)
211
295
  end
212
-
296
+
213
297
  private
214
-
215
- def config_file_for_shef_mode
216
- return config[:config_file] if config[:config_file]
217
- return "/etc/chef/solo.rb" if config[:solo]
218
- return "/etc/chef/client.rb" if config[:client]
219
- nil
298
+
299
+ def config_file_for_shef_mode(environment)
300
+ if config[:config_file]
301
+ config[:config_file]
302
+ elsif environment
303
+ Shef.env = environment
304
+ config_file_to_try = ::File.join(ENV['HOME'], '.chef', environment, 'shef.rb')
305
+ unless ::File.exist?(config_file_to_try)
306
+ puts "could not find shef config for environment #{environment} at #{config_file_to_try}"
307
+ exit 1
308
+ end
309
+ config_file_to_try
310
+ elsif ENV['HOME'] && ::File.exist?(File.join(ENV['HOME'], '.chef', 'shef.rb'))
311
+ File.join(ENV['HOME'], '.chef', 'shef.rb')
312
+ elsif config[:solo]
313
+ "/etc/chef/solo.rb"
314
+ elsif config[:client]
315
+ "/etc/chef/client.rb"
316
+ else
317
+ nil
318
+ end
220
319
  end
221
320
 
222
321
  end
223
-
322
+
224
323
  end