chef 0.10.0.beta.5 → 0.10.0.beta.6

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.
Files changed (40) hide show
  1. data/lib/chef/application.rb +13 -1
  2. data/lib/chef/application/client.rb +4 -2
  3. data/lib/chef/application/knife.rb +26 -2
  4. data/lib/chef/application/solo.rb +4 -3
  5. data/lib/chef/client.rb +2 -1
  6. data/lib/chef/cookbook_version.rb +2 -1
  7. data/lib/chef/knife.rb +129 -37
  8. data/lib/chef/knife/cookbook_metadata.rb +8 -3
  9. data/lib/chef/knife/cookbook_site_install.rb +3 -127
  10. data/lib/chef/knife/cookbook_site_vendor.rb +46 -0
  11. data/lib/chef/knife/cookbook_test.rb +13 -2
  12. data/lib/chef/knife/core/cookbook_scm_repo.rb +149 -0
  13. data/lib/chef/knife/core/generic_presenter.rb +184 -0
  14. data/lib/chef/knife/core/node_editor.rb +127 -0
  15. data/lib/chef/knife/core/node_presenter.rb +103 -0
  16. data/lib/chef/knife/core/object_loader.rb +75 -0
  17. data/lib/chef/knife/{subcommand_loader.rb → core/subcommand_loader.rb} +1 -1
  18. data/lib/chef/knife/core/text_formatter.rb +100 -0
  19. data/lib/chef/knife/{ui.rb → core/ui.rb} +53 -73
  20. data/lib/chef/knife/data_bag_from_file.rb +8 -2
  21. data/lib/chef/knife/environment_from_file.rb +14 -3
  22. data/lib/chef/knife/node_edit.rb +14 -105
  23. data/lib/chef/knife/node_from_file.rb +6 -1
  24. data/lib/chef/knife/node_show.rb +6 -0
  25. data/lib/chef/knife/role_from_file.rb +6 -1
  26. data/lib/chef/knife/search.rb +34 -19
  27. data/lib/chef/knife/status.rb +15 -1
  28. data/lib/chef/mixin/recipe_definition_dsl_core.rb +1 -4
  29. data/lib/chef/mixin/shell_out.rb +1 -0
  30. data/lib/chef/node.rb +17 -5
  31. data/lib/chef/resource.rb +42 -19
  32. data/lib/chef/rest.rb +14 -6
  33. data/lib/chef/rest/auth_credentials.rb +1 -1
  34. data/lib/chef/rest/rest_request.rb +26 -1
  35. data/lib/chef/runner.rb +2 -9
  36. data/lib/chef/version.rb +1 -1
  37. metadata +11 -7
  38. data/lib/chef/knife/bootstrap/client-install.vbs +0 -80
  39. data/lib/chef/knife/bootstrap/windows-gems.erb +0 -34
  40. data/lib/chef/knife/windows_bootstrap.rb +0 -157
@@ -26,6 +26,7 @@ class Chef
26
26
  deps do
27
27
  require 'chef/data_bag'
28
28
  require 'chef/data_bag_item'
29
+ require 'chef/knife/core/object_loader'
29
30
  require 'chef/json_compat'
30
31
  require 'chef/encrypted_data_bag_item'
31
32
  end
@@ -58,12 +59,17 @@ class Chef
58
59
  config[:secret] || config[:secret_file]
59
60
  end
60
61
 
62
+ def loader
63
+ @loader ||= Knife::Core::ObjectLoader.new(DataBagItem, ui)
64
+ end
65
+
61
66
  def run
62
67
  if @name_args.size != 2
63
68
  stdout.puts opt_parser
64
69
  exit(1)
65
70
  end
66
- item = load_from_file(Chef::DataBagItem, @name_args[1], @name_args[0])
71
+ @data_bag, @item_path = @name_args[0], @name_args[1]
72
+ item = loader.load_from("data_bags", @data_bag, @item_path)
67
73
  item = if use_encryption
68
74
  secret = read_secret
69
75
  Chef::EncryptedDataBagItem.encrypt_data_bag_item(item, secret)
@@ -74,7 +80,7 @@ class Chef
74
80
  dbag.data_bag(@name_args[0])
75
81
  dbag.raw_data = item
76
82
  dbag.save
77
- ui.info("Updated data_bag_item[#{@name_args[1]}]")
83
+ ui.info("Updated data_bag_item[#{dbag.data_bag}::#{dbag.id}]")
78
84
  end
79
85
  end
80
86
  end
@@ -20,8 +20,18 @@ class Chef
20
20
  class Knife
21
21
  class EnvironmentFromFile < Knife
22
22
 
23
+ deps do
24
+ require 'chef/environment'
25
+ require 'chef/knife/core/object_loader'
26
+ end
27
+
23
28
  banner "knife environment from file FILE (options)"
24
29
 
30
+ def loader
31
+ @loader ||= Knife::Core::ObjectLoader.new(Chef::Environment, ui)
32
+ end
33
+
34
+
25
35
  def run
26
36
  if @name_args[0].nil?
27
37
  show_usage
@@ -29,11 +39,12 @@ class Chef
29
39
  exit 1
30
40
  end
31
41
 
32
- updated = load_from_file(Chef::Environment, @name_args[0])
42
+
43
+ updated = loader.load_from("environments", @name_args[0])
33
44
  updated.save
34
45
  output(format_for_display(updated)) if config[:print_after]
35
- ui.warn("Updated Environment #{updated.name}!")
46
+ ui.info("Updated Environment #{updated.name}")
36
47
  end
37
48
  end
38
49
  end
39
- end
50
+ end
@@ -21,110 +21,14 @@ require 'chef/knife'
21
21
  class Chef
22
22
  class Knife
23
23
 
24
- module NodeEditController
25
- def edit_node
26
- abort "You specified the --no-editor option, nothing to edit" if config[:no_editor]
27
- assert_editor_set!
28
-
29
- updated_node_data = edit_data(view)
30
- apply_updates(updated_node_data)
31
- @updated_node
32
- end
33
-
34
- def view
35
- result = {}
36
- result["name"] = node.name
37
- result["chef_environment"] = node.chef_environment
38
- result["normal"] = node.normal_attrs
39
- result["run_list"] = node.run_list
40
-
41
- if config[:all_attributes]
42
- result["default"] = node.default_attrs
43
- result["override"] = node.override_attrs
44
- result["automatic"] = node.automatic_attrs
45
- end
46
- Chef::JSONCompat.to_json_pretty(result)
47
- end
48
-
49
- def edit_data(text)
50
- edited_data = tempfile_for(text) {|filename| system("#{config[:editor]} #{filename}")}
51
- Chef::JSONCompat.from_json(edited_data)
52
- end
53
-
54
- def apply_updates(updated_data)
55
- # TODO: should warn/error/ask for confirmation when changing the
56
- # name, since this results in a new node, not an edited node.
57
- @updated_node = Node.new.tap do |n|
58
- n.name( updated_data["name"] )
59
- n.chef_environment( updated_data["chef_environment"] )
60
- n.run_list( updated_data["run_list"])
61
- n.normal_attrs = updated_data["normal"]
62
-
63
- if config[:all_attributes]
64
- n.default_attrs = updated_data["default"]
65
- n.override_attrs = updated_data["override"]
66
- n.automatic_attrs = updated_data["automatic"]
67
- else
68
- n.default_attrs = node.default_attrs
69
- n.override_attrs = node.override_attrs
70
- n.automatic_attrs = node.automatic_attrs
71
- end
72
- end
73
- end
74
-
75
- def updated?
76
- pristine_copy = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(node), :create_additions => false)
77
- updated_copy = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@updated_node), :create_additions => false)
78
- unless pristine_copy == updated_copy
79
- updated_properties = %w{name normal chef_environment run_list default override automatic}.reject do |key|
80
- pristine_copy[key] == updated_copy[key]
81
- end
82
- end
83
- ( pristine_copy != updated_copy ) && updated_properties
84
- end
85
-
86
- private
87
-
88
- def abort(message)
89
- STDERR.puts("ERROR: #{message}")
90
- exit 1
91
- end
92
-
93
- def assert_editor_set!
94
- unless config[:editor]
95
- abort "You must set your EDITOR environment variable or configure your editor via knife.rb"
96
- end
97
- end
98
-
99
- def tempfile_for(data)
100
- # TODO: include useful info like the node name in the temp file
101
- # name
102
- basename = "knife-edit-" << rand(1_000_000_000_000_000).to_s.rjust(15, '0') << '.js'
103
- filename = File.join(Dir.tmpdir, basename)
104
- File.open(filename, "w+") do |f|
105
- f.sync = true
106
- f.puts data
107
- end
108
-
109
- yield filename
110
-
111
- IO.read(filename)
112
- ensure
113
- File.unlink(filename)
114
- end
115
- end
116
-
117
24
  class NodeEdit < Knife
118
- include NodeEditController
119
25
 
120
26
  deps do
121
27
  require 'chef/node'
122
28
  require 'chef/json_compat'
29
+ require 'chef/knife/core/node_editor'
123
30
  end
124
31
 
125
- attr_reader :node_name
126
- attr_reader :node
127
-
128
32
  banner "knife node edit NODE (options)"
129
33
 
130
34
  option :all_attributes,
@@ -134,17 +38,14 @@ class Chef
134
38
  :description => "Display all attributes when editing"
135
39
 
136
40
  def run
137
- node_name = @name_args[0]
138
-
139
41
  if node_name.nil?
140
42
  show_usage
141
43
  ui.fatal("You must specify a node name")
142
44
  exit 1
143
45
  end
144
46
 
145
- load_node(node_name)
146
- updated_node = edit_node
147
- if updated_values = updated?
47
+ updated_node = node_editor.edit_node
48
+ if updated_values = node_editor.updated?
148
49
  ui.info "Saving updated #{updated_values.join(', ')} on node #{node.name}"
149
50
  updated_node.save
150
51
  else
@@ -152,10 +53,18 @@ class Chef
152
53
  end
153
54
  end
154
55
 
155
- def load_node(node_name)
156
- @node = Chef::Node.load(node_name)
157
- # TODO: rescue errors with a helpful message
56
+ def node_name
57
+ @node_name ||= @name_args[0]
58
+ end
59
+
60
+ def node_editor
61
+ @node_editor ||= Knife::NodeEditor.new(node, ui, config)
62
+ end
63
+
64
+ def node
65
+ @node ||= Chef::Node.load(node_name)
158
66
  end
67
+
159
68
  end
160
69
  end
161
70
  end
@@ -25,12 +25,17 @@ class Chef
25
25
  deps do
26
26
  require 'chef/node'
27
27
  require 'chef/json_compat'
28
+ require 'chef/knife/core/object_loader'
28
29
  end
29
30
 
30
31
  banner "knife node from file FILE (options)"
31
32
 
33
+ def loader
34
+ @loader ||= Knife::Core::ObjectLoader.new(Chef::Node, ui)
35
+ end
36
+
32
37
  def run
33
- updated = load_from_file(Chef::Node, @name_args[0])
38
+ updated = loader.load_from('nodes', @name_args[0])
34
39
 
35
40
  updated.save
36
41
 
@@ -17,11 +17,14 @@
17
17
  #
18
18
 
19
19
  require 'chef/knife'
20
+ require 'chef/knife/core/node_presenter'
20
21
 
21
22
  class Chef
22
23
  class Knife
23
24
  class NodeShow < Knife
24
25
 
26
+ include Knife::Core::NodeFormattingOptions
27
+
25
28
  deps do
26
29
  require 'chef/node'
27
30
  require 'chef/json_compat'
@@ -29,9 +32,11 @@ class Chef
29
32
 
30
33
  banner "knife node show NODE (options)"
31
34
 
35
+ attrs_to_show = []
32
36
  option :attribute,
33
37
  :short => "-a [ATTR]",
34
38
  :long => "--attribute [ATTR]",
39
+ :proc => lambda {|val| attrs_to_show << val},
35
40
  :description => "Show only one attribute"
36
41
 
37
42
  option :run_list,
@@ -45,6 +50,7 @@ class Chef
45
50
  :description => "Show only the Chef environment"
46
51
 
47
52
  def run
53
+ ui.use_presenter Knife::Core::NodePresenter
48
54
  @node_name = @name_args[0]
49
55
 
50
56
  if @node_name.nil?
@@ -24,13 +24,18 @@ class Chef
24
24
 
25
25
  deps do
26
26
  require 'chef/role'
27
+ require 'chef/knife/core/object_loader'
27
28
  require 'chef/json_compat'
28
29
  end
29
30
 
30
31
  banner "knife role from file FILE (options)"
31
32
 
33
+ def loader
34
+ @loader ||= Knife::Core::ObjectLoader.new(Chef::Role, ui)
35
+ end
36
+
32
37
  def run
33
- updated = load_from_file(Chef::Role, @name_args[0])
38
+ updated = loader.load_from("roles", @name_args[0])
34
39
 
35
40
  updated.save
36
41
 
@@ -24,8 +24,11 @@ class Chef
24
24
 
25
25
  deps do
26
26
  require 'chef/search/query'
27
+ require 'chef/knife/core/node_presenter'
27
28
  end
28
29
 
30
+ include Knife::Core::NodeFormattingOptions
31
+
29
32
  banner "knife search INDEX QUERY (options)"
30
33
 
31
34
  option :sort,
@@ -70,48 +73,60 @@ class Chef
70
73
 
71
74
  def run
72
75
  if config[:query] && @name_args[1]
73
- puts "please specify query as an argument or an option via -q, not both"
74
- puts opt_parser
76
+ ui.error "please specify query as an argument or an option via -q, not both"
77
+ ui.msg opt_parser
75
78
  exit 1
76
79
  end
77
80
  raw_query = config[:query] || @name_args[1]
78
81
  if !raw_query || raw_query.empty?
79
- puts "no query specified"
80
- puts opt_parser
82
+ ui.error "no query specified"
83
+ ui.msg opt_parser
84
+ exit 1
85
+ end
86
+
87
+ if name_args[0].nil?
88
+ ui.error "you must specify an item type to search for"
81
89
  exit 1
82
90
  end
83
91
 
92
+ if name_args[0] == 'node'
93
+ ui.use_presenter Knife::Core::NodePresenter
94
+ end
95
+
96
+
84
97
  q = Chef::Search::Query.new
85
- display = { :total => 0, :start => config[:start] ? config[:start] : 0, :rows => [ ] }
86
98
  query = URI.escape(raw_query,
87
99
  Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
88
- rows = config[:rows] ? config[:rows] : 20
89
- start = config[:start] ? config[:start] : 0
100
+
101
+ result_items = []
102
+ result_count = 0
103
+
104
+ rows = config[:rows]
105
+ start = config[:start]
90
106
  begin
91
107
  q.search(@name_args[0], query, config[:sort], start, rows) do |item|
92
108
  formatted_item = format_for_display(item)
93
109
  if formatted_item.respond_to?(:has_key?) && !formatted_item.has_key?('id')
94
110
  formatted_item['id'] = item.has_key?('id') ? item['id'] : item.name
95
111
  end
96
- display[:rows] << formatted_item
97
- display[:total] += 1
112
+ result_items << formatted_item
113
+ result_count += 1
98
114
  end
99
115
  rescue Net::HTTPServerException => e
100
116
  msg = Chef::JSONCompat.from_json(e.response.body)["error"].first
101
- ui.msg("knife search failed: #{msg}")
117
+ ui.error("knife search failed: #{msg}")
102
118
  exit 1
103
119
  end
104
120
 
105
- if config[:id_only]
106
- if config[:attribute]
107
- display[:rows].each do |row|
108
- puts row[config[:attribute]] if row.has_key?(config[:attribute]) && !row[config[:attribute]].nil?
109
- end
110
- else
111
- puts display[:rows].join("\n")
112
- end
121
+ if ui.interchange?
122
+ output({:results => result_count, :rows => result_items})
113
123
  else
114
- output(display)
124
+ ui.msg "#{result_count} items found"
125
+ ui.msg("\n")
126
+ result_items.each do |item|
127
+ output(item)
128
+ ui.msg("\n")
129
+ end
115
130
  end
116
131
  end
117
132
  end
@@ -68,7 +68,21 @@ class Chef
68
68
  text = minutes_text
69
69
  end
70
70
 
71
- highline.say("<%= color('#{text}', #{color}) %> ago, #{node.name}, #{node['platform']} #{node['platform_version']}, #{fqdn}, #{ipaddress}#{run_list}")
71
+ line_parts = Array.new
72
+ line_parts << "<%= color('#{text}', #{color}) %> ago" << node.name
73
+ line_parts << fqdn if fqdn
74
+ line_parts << ipaddress if ipaddress
75
+ line_parts << run_list if run_list
76
+
77
+ if node['platform']
78
+ platform = node['platform']
79
+ if node['platform_version']
80
+ platform << " #{node['platform_version']}"
81
+ end
82
+ line_parts << platform
83
+ end
84
+
85
+ highline.say(line_parts.join(', ') + '.')
72
86
  end
73
87
 
74
88
  end
@@ -61,10 +61,7 @@ class Chef
61
61
  resource = Chef::Resource.const_get(rname).new(*args)
62
62
  resource.load_prior_resource
63
63
  resource.cookbook_name = cookbook_name
64
- # TODO: 5/21/2010 cw/dan: do we need recipe_name for
65
- # anything? it's not even possible that this ivar is set on
66
- # Chef::Provider.
67
- # resource.recipe_name = @recipe_name
64
+ resource.recipe_name = @recipe_name
68
65
  resource.params = @params
69
66
  resource.source_line = caller[0]
70
67
  # Determine whether this resource is being created in the context of an enclosing Provider
@@ -16,6 +16,7 @@
16
16
  # limitations under the License.
17
17
 
18
18
  require 'chef/shell_out'
19
+ require 'chef/config'
19
20
 
20
21
  class Chef
21
22
  module Mixin
@@ -19,6 +19,7 @@
19
19
  # limitations under the License.
20
20
  #
21
21
 
22
+ require 'forwardable'
22
23
  require 'chef/config'
23
24
  require 'chef/cookbook/cookbook_collection'
24
25
  require 'chef/nil_argument'
@@ -39,6 +40,10 @@ require 'chef/json_compat'
39
40
  class Chef
40
41
  class Node
41
42
 
43
+ extend Forwardable
44
+
45
+ def_delegators :construct_attributes, :keys, :each_key, :each_value, :key?, :has_key?
46
+
42
47
  attr_accessor :recipe_list, :couchdb, :couchdb_rev, :run_state, :run_list
43
48
  attr_accessor :override_attrs, :default_attrs, :normal_attrs, :automatic_attrs
44
49
  attr_reader :couchdb_id
@@ -363,11 +368,6 @@ class Chef
363
368
  args.length > 0 ? @run_list.reset!(args) : @run_list
364
369
  end
365
370
 
366
- def recipes(*args)
367
- Chef::Log.warn "Chef::Node#recipes method is deprecated. Please use Chef::Node#run_list"
368
- run_list(*args)
369
- end
370
-
371
371
  # Returns true if this Node expects a given role, false if not.
372
372
  def run_list?(item)
373
373
  run_list.detect { |r| r == item } ? true : false
@@ -468,6 +468,18 @@ class Chef
468
468
  index_hash
469
469
  end
470
470
 
471
+ def display_hash
472
+ display = {}
473
+ display["name"] = name
474
+ display["chef_environment"] = chef_environment
475
+ display["automatic"] = automatic_attrs
476
+ display["normal"] = normal_attrs
477
+ display["default"] = default_attrs
478
+ display["override"] = override_attrs
479
+ display["run_list"] = run_list.run_list
480
+ display
481
+ end
482
+
471
483
  # Serialize this object as a hash
472
484
  def to_json(*a)
473
485
  result = {