chef 12.0.0.alpha.1-x86-mingw32 → 12.0.0.alpha.2-x86-mingw32

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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef/application.rb +8 -1
  3. data/lib/chef/application/apply.rb +4 -0
  4. data/lib/chef/application/client.rb +7 -7
  5. data/lib/chef/application/solo.rb +21 -13
  6. data/lib/chef/chef_fs/chef_fs_data_store.rb +60 -6
  7. data/lib/chef/chef_fs/config.rb +78 -4
  8. data/lib/chef/chef_fs/data_handler/acl_data_handler.rb +2 -2
  9. data/lib/chef/chef_fs/data_handler/client_data_handler.rb +1 -1
  10. data/lib/chef/chef_fs/data_handler/container_data_handler.rb +1 -1
  11. data/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb +1 -1
  12. data/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb +1 -1
  13. data/lib/chef/chef_fs/data_handler/data_handler_base.rb +76 -2
  14. data/lib/chef/chef_fs/data_handler/environment_data_handler.rb +1 -1
  15. data/lib/chef/chef_fs/data_handler/group_data_handler.rb +1 -1
  16. data/lib/chef/chef_fs/data_handler/node_data_handler.rb +1 -1
  17. data/lib/chef/chef_fs/data_handler/organization_data_handler.rb +30 -0
  18. data/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb +17 -0
  19. data/lib/chef/chef_fs/data_handler/organization_members_data_handler.rb +17 -0
  20. data/lib/chef/chef_fs/data_handler/role_data_handler.rb +1 -1
  21. data/lib/chef/chef_fs/data_handler/user_data_handler.rb +2 -1
  22. data/lib/chef/chef_fs/file_system.rb +0 -1
  23. data/lib/chef/chef_fs/file_system/acl_entry.rb +1 -1
  24. data/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb +1 -1
  25. data/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb +5 -1
  26. data/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb +73 -13
  27. data/lib/chef/chef_fs/file_system/chef_server_root_dir.rb +44 -5
  28. data/lib/chef/chef_fs/file_system/cookbook_dir.rb +1 -1
  29. data/lib/chef/chef_fs/file_system/cookbooks_dir.rb +3 -3
  30. data/lib/chef/chef_fs/file_system/org_entry.rb +34 -0
  31. data/lib/chef/chef_fs/file_system/organization_invites_entry.rb +58 -0
  32. data/lib/chef/chef_fs/file_system/organization_members_entry.rb +57 -0
  33. data/lib/chef/chef_fs/file_system/rest_list_entry.rb +13 -4
  34. data/lib/chef/chef_fs/knife.rb +1 -1
  35. data/lib/chef/client.rb +8 -2
  36. data/lib/chef/config.rb +75 -57
  37. data/lib/chef/config_fetcher.rb +6 -21
  38. data/lib/chef/dsl/data_query.rb +48 -3
  39. data/lib/chef/dsl/platform_introspection.rb +42 -0
  40. data/lib/chef/dsl/reboot_pending.rb +6 -3
  41. data/lib/chef/encrypted_data_bag_item.rb +1 -1
  42. data/lib/chef/encrypted_data_bag_item/encryptor.rb +12 -0
  43. data/lib/chef/exceptions.rb +2 -0
  44. data/lib/chef/http/basic_client.rb +14 -0
  45. data/lib/chef/http/json_output.rb +7 -2
  46. data/lib/chef/knife.rb +36 -121
  47. data/lib/chef/knife/bootstrap.rb +68 -54
  48. data/lib/chef/knife/bootstrap/archlinux-gems.erb +6 -1
  49. data/lib/chef/knife/bootstrap/chef-aix.erb +5 -0
  50. data/lib/chef/knife/bootstrap/chef-full.erb +5 -1
  51. data/lib/chef/knife/core/bootstrap_context.rb +70 -29
  52. data/lib/chef/knife/search.rb +56 -12
  53. data/lib/chef/knife/serve.rb +1 -1
  54. data/lib/chef/local_mode.rb +10 -4
  55. data/lib/chef/mixin/deep_merge.rb +6 -3
  56. data/lib/chef/mixin/shell_out.rb +33 -17
  57. data/lib/chef/null_logger.rb +72 -0
  58. data/lib/chef/platform.rb +2 -1
  59. data/lib/chef/platform/provider_mapping.rb +1 -1
  60. data/lib/chef/platform/rebooter.rb +54 -0
  61. data/lib/chef/provider/ifconfig.rb +15 -16
  62. data/lib/chef/provider/link.rb +1 -1
  63. data/lib/chef/provider/mount/mount.rb +1 -1
  64. data/lib/chef/provider/mount/solaris.rb +102 -64
  65. data/lib/chef/provider/package/aix.rb +4 -12
  66. data/lib/chef/provider/package/ips.rb +8 -12
  67. data/lib/chef/provider/package/macports.rb +4 -12
  68. data/lib/chef/provider/package/pacman.rb +2 -6
  69. data/lib/chef/provider/package/portage.rb +2 -6
  70. data/lib/chef/provider/package/rpm.rb +4 -12
  71. data/lib/chef/provider/package/solaris.rb +4 -12
  72. data/lib/chef/provider/reboot.rb +69 -0
  73. data/lib/chef/provider/service/debian.rb +10 -10
  74. data/lib/chef/provider/service/freebsd.rb +89 -73
  75. data/lib/chef/provider/service/gentoo.rb +2 -2
  76. data/lib/chef/provider/service/init.rb +6 -4
  77. data/lib/chef/provider/service/insserv.rb +3 -3
  78. data/lib/chef/provider/service/macosx.rb +2 -2
  79. data/lib/chef/provider/service/simple.rb +6 -4
  80. data/lib/chef/provider/service/solaris.rb +1 -1
  81. data/lib/chef/provider/service/systemd.rb +9 -9
  82. data/lib/chef/provider/service/upstart.rb +6 -6
  83. data/lib/chef/provider/subversion.rb +6 -6
  84. data/lib/chef/provider/user/dscl.rb +32 -28
  85. data/lib/chef/provider/user/windows.rb +6 -6
  86. data/lib/chef/provider/whyrun_safe_ruby_block.rb +1 -1
  87. data/lib/chef/providers.rb +1 -0
  88. data/lib/chef/recipe.rb +0 -1
  89. data/lib/chef/resource.rb +3 -5
  90. data/lib/chef/resource/mount.rb +9 -0
  91. data/lib/chef/resource/reboot.rb +48 -0
  92. data/lib/chef/resources.rb +1 -0
  93. data/lib/chef/run_context.rb +25 -0
  94. data/lib/chef/search/query.rb +122 -14
  95. data/lib/chef/util/path_helper.rb +54 -6
  96. data/lib/chef/util/windows/net_user.rb +4 -1
  97. data/lib/chef/version.rb +1 -1
  98. data/lib/chef/win32/api/file.rb +1 -5
  99. data/lib/chef/win32/api/net.rb +1 -0
  100. data/lib/chef/workstation_config_loader.rb +177 -0
  101. data/spec/functional/http/simple_spec.rb +57 -1
  102. data/spec/functional/mixin/shell_out_spec.rb +2 -2
  103. data/spec/functional/provider/whyrun_safe_ruby_block_spec.rb +51 -0
  104. data/spec/functional/rebooter_spec.rb +105 -0
  105. data/spec/functional/resource/deploy_revision_spec.rb +0 -4
  106. data/spec/functional/resource/file_spec.rb +26 -3
  107. data/spec/functional/resource/group_spec.rb +5 -3
  108. data/spec/functional/resource/link_spec.rb +16 -16
  109. data/spec/functional/resource/reboot_spec.rb +103 -0
  110. data/spec/integration/client/client_spec.rb +4 -8
  111. data/spec/integration/client/ipv6_spec.rb +1 -1
  112. data/spec/integration/knife/cookbook_api_ipv6_spec.rb +3 -2
  113. data/spec/integration/knife/delete_spec.rb +39 -0
  114. data/spec/integration/knife/deps_spec.rb +30 -20
  115. data/spec/integration/knife/download_spec.rb +77 -1
  116. data/spec/integration/knife/list_spec.rb +221 -0
  117. data/spec/integration/knife/raw_spec.rb +1 -1
  118. data/spec/integration/knife/show_spec.rb +2 -2
  119. data/spec/integration/knife/upload_spec.rb +154 -1
  120. data/spec/support/pedant/run_pedant.rb +0 -1
  121. data/spec/support/shared/functional/http.rb +8 -1
  122. data/spec/support/shared/integration/integration_helper.rb +11 -19
  123. data/spec/support/shared/unit/platform_introspector.rb +22 -0
  124. data/spec/unit/application/apply.rb +11 -1
  125. data/spec/unit/application/solo_spec.rb +19 -3
  126. data/spec/unit/chef_fs/config_spec.rb +58 -0
  127. data/spec/unit/config_fetcher_spec.rb +1 -3
  128. data/spec/unit/config_spec.rb +247 -220
  129. data/spec/unit/dsl/data_query_spec.rb +165 -23
  130. data/spec/unit/dsl/reboot_pending_spec.rb +1 -7
  131. data/spec/unit/encrypted_data_bag_item_spec.rb +1 -1
  132. data/spec/unit/knife/bootstrap_spec.rb +354 -182
  133. data/spec/unit/knife/core/bootstrap_context_spec.rb +67 -30
  134. data/spec/unit/knife_spec.rb +3 -30
  135. data/spec/unit/mixin/deep_merge_spec.rb +14 -0
  136. data/spec/unit/mixin/shell_out_spec.rb +134 -64
  137. data/spec/unit/provider/ifconfig/debian_spec.rb +19 -9
  138. data/spec/unit/provider/ifconfig/redhat_spec.rb +16 -14
  139. data/spec/unit/provider/ifconfig_spec.rb +3 -3
  140. data/spec/unit/provider/link_spec.rb +5 -5
  141. data/spec/unit/provider/mount/mount_spec.rb +10 -1
  142. data/spec/unit/provider/mount/solaris_spec.rb +185 -11
  143. data/spec/unit/provider/package/aix_spec.rb +5 -17
  144. data/spec/unit/provider/package/ips_spec.rb +8 -21
  145. data/spec/unit/provider/package/macports_spec.rb +12 -12
  146. data/spec/unit/provider/package/pacman_spec.rb +4 -12
  147. data/spec/unit/provider/package/portage_spec.rb +5 -15
  148. data/spec/unit/provider/package/rpm_spec.rb +7 -22
  149. data/spec/unit/provider/package/solaris_spec.rb +5 -16
  150. data/spec/unit/provider/service/arch_service_spec.rb +8 -14
  151. data/spec/unit/provider/service/debian_service_spec.rb +1 -1
  152. data/spec/unit/provider/service/freebsd_service_spec.rb +457 -225
  153. data/spec/unit/provider/service/gentoo_service_spec.rb +2 -2
  154. data/spec/unit/provider/service/init_service_spec.rb +10 -10
  155. data/spec/unit/provider/service/insserv_service_spec.rb +3 -4
  156. data/spec/unit/provider/service/invokercd_service_spec.rb +8 -9
  157. data/spec/unit/provider/service/macosx_spec.rb +5 -5
  158. data/spec/unit/provider/service/simple_service_spec.rb +4 -6
  159. data/spec/unit/provider/service/solaris_smf_service_spec.rb +1 -3
  160. data/spec/unit/provider/service/systemd_service_spec.rb +20 -20
  161. data/spec/unit/provider/service/upstart_service_spec.rb +15 -17
  162. data/spec/unit/provider/subversion_spec.rb +5 -6
  163. data/spec/unit/provider/user/dscl_spec.rb +2 -1
  164. data/spec/unit/provider/user/windows_spec.rb +7 -0
  165. data/spec/unit/provider/whyrun_safe_ruby_block_spec.rb +2 -2
  166. data/spec/unit/resource/mount_spec.rb +9 -0
  167. data/spec/unit/resource_spec.rb +0 -4
  168. data/spec/unit/rest_spec.rb +1 -1
  169. data/spec/unit/run_context_spec.rb +15 -0
  170. data/spec/unit/search/query_spec.rb +196 -40
  171. data/spec/unit/util/path_helper_spec.rb +111 -28
  172. data/spec/unit/workstation_config_loader_spec.rb +283 -0
  173. metadata +36 -20
  174. data/lib/chef/knife/bootstrap/centos5-gems.erb +0 -62
  175. data/lib/chef/knife/bootstrap/fedora13-gems.erb +0 -44
  176. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +0 -53
  177. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +0 -48
  178. data/lib/chef/knife/bootstrap/ubuntu12.04-gems.erb +0 -46
  179. data/spec/support/shared/integration/chef_zero_support.rb +0 -130
  180. data/spec/unit/knife/config_file_selection_spec.rb +0 -135
@@ -7,11 +7,9 @@ class Chef
7
7
  class ConfigFetcher
8
8
 
9
9
  attr_reader :config_location
10
- attr_reader :config_file_jail
11
10
 
12
- def initialize(config_location, config_file_jail=nil)
11
+ def initialize(config_location)
13
12
  @config_location = config_location
14
- @config_file_jail = config_file_jail
15
13
  end
16
14
 
17
15
  def fetch_json
@@ -48,24 +46,11 @@ class Chef
48
46
  def config_missing?
49
47
  return false if remote_config?
50
48
 
51
- # Check if the config file exists, and check if it is underneath the config file jail
52
- begin
53
- real_config_file = Pathname.new(config_location).realpath.to_s
54
- rescue Errno::ENOENT
55
- return true
56
- end
57
-
58
- # If realpath succeeded, the file exists
59
- return false if !config_file_jail
60
-
61
- begin
62
- real_jail = Pathname.new(config_file_jail).realpath.to_s
63
- rescue Errno::ENOENT
64
- Chef::Log.warn("Config file jail #{config_file_jail} does not exist: will not load any config file.")
65
- return true
66
- end
67
-
68
- !Chef::ChefFS::PathUtils.descendant_of?(real_config_file, real_jail)
49
+ # Check if the config file exists
50
+ Pathname.new(config_location).realpath.to_s
51
+ false
52
+ rescue Errno::ENOENT
53
+ return true
69
54
  end
70
55
 
71
56
  def http
@@ -53,14 +53,60 @@ class Chef
53
53
  raise
54
54
  end
55
55
 
56
- def data_bag_item(bag, item)
56
+ def data_bag_item(bag, item, secret=nil)
57
57
  DataBag.validate_name!(bag.to_s)
58
58
  DataBagItem.validate_id!(item)
59
- DataBagItem.load(bag, item)
59
+
60
+ item = DataBagItem.load(bag, item)
61
+ if encrypted?(item.raw_data)
62
+ Log.debug("Data bag item looks encrypted: #{bag.inspect} #{item.inspect}")
63
+
64
+ # Try to load the data bag item secret, if secret is not provided.
65
+ # Chef::EncryptedDataBagItem.load_secret may throw a variety of errors.
66
+ begin
67
+ secret ||= EncryptedDataBagItem.load_secret
68
+ item = EncryptedDataBagItem.new(item.raw_data, secret)
69
+ rescue Exception
70
+ Log.error("Failed to load secret for encrypted data bag item: #{bag.inspect} #{item.inspect}")
71
+ raise
72
+ end
73
+ end
74
+
75
+ item
60
76
  rescue Exception
61
77
  Log.error("Failed to load data bag item: #{bag.inspect} #{item.inspect}")
62
78
  raise
63
79
  end
80
+
81
+ private
82
+
83
+ # Tries to autodetect if the item's raw hash appears to be encrypted.
84
+ def encrypted?(raw_data)
85
+ data = raw_data.reject { |k, _| k == "id" } # Remove the "id" key.
86
+ # Assume hashes containing only the "id" key are not encrypted.
87
+ # Otherwise, remove the keys that don't appear to be encrypted and compare
88
+ # the result with the hash. If some entry has been removed, then some entry
89
+ # doesn't appear to be encrypted and we assume the entire hash is not encrypted.
90
+ data.empty? ? false : data.reject { |_, v| !looks_like_encrypted?(v) } == data
91
+ end
92
+
93
+ # Checks if data looks like it has been encrypted by
94
+ # Chef::EncryptedDataBagItem::Encryptor::VersionXEncryptor. Returns
95
+ # true only when there is an exact match between the VersionXEncryptor
96
+ # keys and the hash's keys.
97
+ def looks_like_encrypted?(data)
98
+ return false unless data.is_a?(Hash) && data.has_key?("version")
99
+ case data["version"]
100
+ when 1
101
+ Chef::EncryptedDataBagItem::Encryptor::Version1Encryptor.encryptor_keys.sort == data.keys.sort
102
+ when 2
103
+ Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor.encryptor_keys.sort == data.keys.sort
104
+ when 3
105
+ Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor.encryptor_keys.sort == data.keys.sort
106
+ else
107
+ false # version means something else... assume not encrypted.
108
+ end
109
+ end
64
110
  end
65
111
  end
66
112
  end
@@ -68,4 +114,3 @@ end
68
114
  # **DEPRECATED**
69
115
  # This used to be part of chef/mixin/language. Load the file to activate the deprecation code.
70
116
  require 'chef/mixin/language'
71
-
@@ -50,8 +50,12 @@ class Chef
50
50
 
51
51
  def value_for_node(node)
52
52
  platform, version = node[:platform].to_s, node[:platform_version].to_s
53
+ # Check if we match a version constraint via Chef::VersionConstraint and Chef::Version::Platform
54
+ matched_value = match_versions(node)
53
55
  if @values.key?(platform) && @values[platform].key?(version)
54
56
  @values[platform][version]
57
+ elsif matched_value
58
+ matched_value
55
59
  elsif @values.key?(platform) && @values[platform].key?("default")
56
60
  @values[platform]["default"]
57
61
  elsif @values.key?("default")
@@ -63,6 +67,44 @@ class Chef
63
67
 
64
68
  private
65
69
 
70
+ def match_versions(node)
71
+ begin
72
+ platform, version = node[:platform].to_s, node[:platform_version].to_s
73
+ return nil unless @values.key?(platform)
74
+ node_version = Chef::Version::Platform.new(version)
75
+ key_matches = []
76
+ keys = @values[platform].keys
77
+ keys.each do |k|
78
+ begin
79
+ if Chef::VersionConstraint.new(k).include?(node_version)
80
+ key_matches << k
81
+ end
82
+ rescue Chef::Exceptions::InvalidVersionConstraint => e
83
+ Chef::Log.debug "Caught InvalidVersionConstraint. This means that a key in value_for_platform cannot be interpreted as a Chef::VersionConstraint."
84
+ Chef::Log.debug(e)
85
+ end
86
+ end
87
+ return @values[platform][version] if key_matches.include?(version)
88
+ case key_matches.length
89
+ when 0
90
+ return nil
91
+ when 1
92
+ return @values[platform][key_matches.first]
93
+ else
94
+ raise "Multiple matches detected for #{platform} with values #{@values}. The matches are: #{key_matches}"
95
+ end
96
+ rescue Chef::Exceptions::InvalidCookbookVersion => e
97
+ # Lets not break because someone passes a weird string like 'default' :)
98
+ Chef::Log.debug(e)
99
+ Chef::Log.debug "InvalidCookbookVersion exceptions are common and expected here: the generic constraint matcher attempted to match something which is not a constraint. Moving on to next version or constraint"
100
+ return nil
101
+ rescue Chef::Exceptions::InvalidPlatformVersion => e
102
+ Chef::Log.debug "Caught InvalidPlatformVersion, this means that Chef::Version::Platform does not know how to turn #{node_version} into an x.y.z format"
103
+ Chef::Log.debug(e)
104
+ return nil
105
+ end
106
+ end
107
+
66
108
  def set(platforms, value)
67
109
  if platforms.to_s == 'default'
68
110
  @values["default"] = value
@@ -27,10 +27,13 @@ class Chef
27
27
  include Chef::DSL::PlatformIntrospection
28
28
 
29
29
  # Returns true if the system needs a reboot or is expected to reboot
30
- # Raises UnsupportedPlatform if this functionality isn't provided yet
30
+ # Note that we will silently miss any other platform-specific reboot notices besides Windows+Ubuntu.
31
31
  def reboot_pending?
32
32
 
33
- if platform?("windows")
33
+ # don't break when used as a mixin in contexts without #node (e.g. specs).
34
+ if self.respond_to?(:node, true) && node.run_context.reboot_requested?
35
+ true
36
+ elsif platform?("windows")
34
37
  # PendingFileRenameOperations contains pairs (REG_MULTI_SZ) of filenames that cannot be updated
35
38
  # due to a file being in use (usually a temporary file and a system file)
36
39
  # \??\c:\temp\test.sys!\??\c:\winnt\system32\test.sys
@@ -53,7 +56,7 @@ class Chef
53
56
  # This should work for Debian as well if update-notifier-common happens to be installed. We need an API for that.
54
57
  File.exists?('/var/run/reboot-required')
55
58
  else
56
- raise Chef::Exceptions::UnsupportedPlatform.new(node[:platform])
59
+ false
57
60
  end
58
61
  end
59
62
  end
@@ -128,7 +128,7 @@ class Chef::EncryptedDataBagItem
128
128
  def self.load_secret(path=nil)
129
129
  path ||= Chef::Config[:encrypted_data_bag_secret]
130
130
  if !path
131
- raise ArgumentError, "No secret specified to load_secret and no secret found at #{Chef::Config.platform_specific_path('/etc/chef/encrypted_data_bag_secret')}"
131
+ raise ArgumentError, "No secret specified and no secret found at #{Chef::Config.platform_specific_path('/etc/chef/encrypted_data_bag_secret')}"
132
132
  end
133
133
  secret = case path
134
134
  when /^\w+:\/\//
@@ -125,6 +125,10 @@ class Chef::EncryptedDataBagItem
125
125
  def serialized_data
126
126
  FFI_Yajl::Encoder.encode(:json_wrapper => plaintext_data)
127
127
  end
128
+
129
+ def self.encryptor_keys
130
+ %w( encrypted_data iv version cipher )
131
+ end
128
132
  end
129
133
 
130
134
  class Version2Encryptor < Version1Encryptor
@@ -149,6 +153,10 @@ class Chef::EncryptedDataBagItem
149
153
  Base64.encode64(raw_hmac)
150
154
  end
151
155
  end
156
+
157
+ def self.encryptor_keys
158
+ super + %w( hmac )
159
+ end
152
160
  end
153
161
 
154
162
  class Version3Encryptor < Version1Encryptor
@@ -207,6 +215,10 @@ class Chef::EncryptedDataBagItem
207
215
  end
208
216
  end
209
217
 
218
+ def self.encryptor_keys
219
+ super + %w( auth_tag )
220
+ end
221
+
210
222
  end
211
223
 
212
224
  end
@@ -347,5 +347,7 @@ class Chef
347
347
  class EncodeError < RuntimeError; end
348
348
  class ParseError < RuntimeError; end
349
349
  end
350
+
351
+ class InvalidSearchQuery < ArgumentError; end
350
352
  end
351
353
  end
@@ -71,6 +71,20 @@ class Chef
71
71
  end
72
72
  Chef::Log.debug("---- End HTTP Status/Header Data ----")
73
73
 
74
+ # For non-400's, log the request and response bodies
75
+ if !response.code || !response.code.start_with?('2')
76
+ if response.body
77
+ Chef::Log.debug("---- HTTP Response Body ----")
78
+ Chef::Log.debug(response.body)
79
+ Chef::Log.debug("---- End HTTP Response Body -----")
80
+ end
81
+ if req_body
82
+ Chef::Log.debug("---- HTTP Request Body ----")
83
+ Chef::Log.debug(req_body)
84
+ Chef::Log.debug("---- End HTTP Request Body ----")
85
+ end
86
+ end
87
+
74
88
  yield response if block_given?
75
89
  # http_client.request may not have the return signature we want, so
76
90
  # force the issue:
@@ -26,6 +26,9 @@ class Chef
26
26
  # Middleware that takes an HTTP response, parses it as JSON if possible.
27
27
  class JSONOutput
28
28
 
29
+ attr_accessor :raw_output
30
+ attr_accessor :inflate_json_class
31
+
29
32
  def initialize(opts={})
30
33
  @raw_output = opts[:raw_output]
31
34
  @inflate_json_class = opts[:inflate_json_class]
@@ -44,10 +47,12 @@ class Chef
44
47
  # needed to keep conditional get stuff working correctly.
45
48
  return [http_response, rest_request, return_value] if return_value == false
46
49
  if http_response['content-type'] =~ /json/
47
- if @raw_output
50
+ if http_response.body.nil?
51
+ return_value = nil
52
+ elsif raw_output
48
53
  return_value = http_response.body.to_s
49
54
  else
50
- if @inflate_json_class
55
+ if inflate_json_class
51
56
  return_value = Chef::JSONCompat.from_json(http_response.body.chomp)
52
57
  else
53
58
  return_value = Chef::JSONCompat.parse(http_response.body.chomp)
data/lib/chef/knife.rb CHANGED
@@ -20,7 +20,7 @@
20
20
  require 'forwardable'
21
21
  require 'chef/version'
22
22
  require 'mixlib/cli'
23
- require 'chef/config_fetcher'
23
+ require 'chef/workstation_config_loader'
24
24
  require 'chef/mixin/convert_to_class_name'
25
25
  require 'chef/mixin/path_sanity'
26
26
  require 'chef/knife/core/subcommand_loader'
@@ -159,6 +159,27 @@ class Chef
159
159
  end
160
160
  end
161
161
 
162
+ # Shared with subclasses
163
+ @@chef_config_dir = nil
164
+
165
+ def self.load_config(explicit_config_file)
166
+ config_loader = WorkstationConfigLoader.new(explicit_config_file, Chef::Log)
167
+ Chef::Log.debug("Using configuration from #{config_loader.config_location}")
168
+ config_loader.load
169
+
170
+ ui.warn("No knife configuration file found") if config_loader.no_config_found?
171
+ @@chef_config_dir = config_loader.chef_config_dir
172
+
173
+ config_loader
174
+ rescue Exceptions::ConfigurationError => e
175
+ ui.error(ui.color("CONFIGURATION ERROR:", :red) + e.message)
176
+ exit 1
177
+ end
178
+
179
+ def self.chef_config_dir
180
+ @@chef_config_dir
181
+ end
182
+
162
183
  # Run knife for the given +args+ (ARGV), adding +options+ to the list of
163
184
  # CLI options that the subcommand knows how to handle.
164
185
  # ===Arguments
@@ -166,6 +187,16 @@ class Chef
166
187
  # options::: A Mixlib::CLI option parser hash. These +options+ are how
167
188
  # subcommands know about global knife CLI options
168
189
  def self.run(args, options={})
190
+ # Fallback debug logging. Normally the logger isn't configured until we
191
+ # read the config, but this means any logging that happens before the
192
+ # config file is read may be lost. If the KNIFE_DEBUG variable is set, we
193
+ # setup the logger for debug logging to stderr immediately to catch info
194
+ # from early in the setup process.
195
+ if ENV['KNIFE_DEBUG']
196
+ Chef::Log.init($stderr)
197
+ Chef::Log.level(:debug)
198
+ end
199
+
169
200
  load_commands
170
201
  subcommand_class = subcommand_class_from(args)
171
202
  subcommand_class.options = options.merge!(subcommand_class.options)
@@ -239,40 +270,12 @@ class Chef
239
270
  exit 10
240
271
  end
241
272
 
242
- def self.working_directory
243
- a = if Chef::Platform.windows?
244
- ENV['CD']
245
- else
246
- ENV['PWD']
247
- end || Dir.pwd
248
-
249
- a
250
- end
251
-
252
273
  def self.reset_config_path!
253
274
  @@chef_config_dir = nil
254
275
  end
255
276
 
256
277
  reset_config_path!
257
278
 
258
-
259
- # search upward from current_dir until .chef directory is found
260
- def self.chef_config_dir
261
- if @@chef_config_dir.nil? # share this with subclasses
262
- @@chef_config_dir = false
263
- full_path = working_directory.split(File::SEPARATOR)
264
- (full_path.length - 1).downto(0) do |i|
265
- candidate_directory = File.join(full_path[0..i] + [".chef" ])
266
- if File.exist?(candidate_directory) && File.directory?(candidate_directory)
267
- @@chef_config_dir = candidate_directory
268
- break
269
- end
270
- end
271
- end
272
- @@chef_config_dir
273
- end
274
-
275
-
276
279
  public
277
280
 
278
281
  # Create a new instance of the current class configured for the given
@@ -322,39 +325,6 @@ class Chef
322
325
  config_file_settings
323
326
  end
324
327
 
325
- def self.config_fetcher(candidate_config)
326
- Chef::ConfigFetcher.new(candidate_config, Chef::Config.config_file_jail)
327
- end
328
-
329
- def self.locate_config_file
330
- candidate_configs = []
331
-
332
- # Look for $KNIFE_HOME/knife.rb (allow multiple knives config on same machine)
333
- if ENV['KNIFE_HOME']
334
- candidate_configs << File.join(ENV['KNIFE_HOME'], 'knife.rb')
335
- end
336
- # Look for $PWD/knife.rb
337
- if Dir.pwd
338
- candidate_configs << File.join(Dir.pwd, 'knife.rb')
339
- end
340
- # Look for $UPWARD/.chef/knife.rb
341
- if chef_config_dir
342
- candidate_configs << File.join(chef_config_dir, 'knife.rb')
343
- end
344
- # Look for $HOME/.chef/knife.rb
345
- if ENV['HOME']
346
- candidate_configs << File.join(ENV['HOME'], '.chef', 'knife.rb')
347
- end
348
-
349
- candidate_configs.each do | candidate_config |
350
- fetcher = config_fetcher(candidate_config)
351
- if !fetcher.config_missing?
352
- return candidate_config
353
- end
354
- end
355
- return nil
356
- end
357
-
358
328
  # Apply Config in this order:
359
329
  # defaults from mixlib-cli
360
330
  # settings from config file, via Chef::Config[:knife]
@@ -386,6 +356,8 @@ class Chef
386
356
  Chef::Config[:log_level] = :debug
387
357
  end
388
358
 
359
+ Chef::Config[:log_level] = :debug if ENV['KNIFE_DEBUG']
360
+
389
361
  Chef::Config[:node_name] = config[:node_name] if config[:node_name]
390
362
  Chef::Config[:client_key] = config[:client_key] if config[:client_key]
391
363
  Chef::Config[:chef_server_url] = config[:chef_server_url] if config[:chef_server_url]
@@ -416,70 +388,13 @@ class Chef
416
388
  end
417
389
 
418
390
  def configure_chef
419
- if !config[:config_file]
420
- located_config_file = self.class.locate_config_file
421
- config[:config_file] = located_config_file if located_config_file
422
- end
423
-
424
- # Don't try to load a knife.rb if it wasn't specified.
425
- if config[:config_file]
426
- Chef::Config.config_file = config[:config_file]
427
- fetcher = Chef::ConfigFetcher.new(config[:config_file], Chef::Config.config_file_jail)
428
- if fetcher.config_missing?
429
- ui.error("Specified config file #{config[:config_file]} does not exist#{Chef::Config.config_file_jail ? " or is not under config file jail #{Chef::Config.config_file_jail}" : ""}!")
430
- exit 1
431
- end
432
- Chef::Log.debug("Using configuration from #{config[:config_file]}")
433
- read_config(fetcher.read_config, config[:config_file])
434
- else
435
- # ...but do log a message if no config was found.
436
- Chef::Config[:color] = config[:color]
437
- ui.warn("No knife configuration file found")
438
- end
391
+ config_loader = self.class.load_config(config[:config_file])
392
+ config[:config_file] = config_loader.config_location
439
393
 
440
394
  merge_configs
441
395
  apply_computed_config
442
396
  end
443
397
 
444
- def read_config(config_content, config_file_path)
445
- Chef::Config.from_string(config_content, config_file_path)
446
- rescue SyntaxError => e
447
- ui.error "You have invalid ruby syntax in your config file #{config_file_path}"
448
- ui.info(ui.color(e.message, :red))
449
- if file_line = e.message[/#{Regexp.escape(config_file_path)}:[\d]+/]
450
- line = file_line[/:([\d]+)$/, 1].to_i
451
- highlight_config_error(config_file_path, line)
452
- end
453
- exit 1
454
- rescue Exception => e
455
- ui.error "You have an error in your config file #{config_file_path}"
456
- ui.info "#{e.class.name}: #{e.message}"
457
- filtered_trace = e.backtrace.grep(/#{Regexp.escape(config_file_path)}/)
458
- filtered_trace.each {|line| ui.msg(" " + ui.color(line, :red))}
459
- if !filtered_trace.empty?
460
- line_nr = filtered_trace.first[/#{Regexp.escape(config_file_path)}:([\d]+)/, 1]
461
- highlight_config_error(config_file_path, line_nr.to_i)
462
- end
463
-
464
- exit 1
465
- end
466
-
467
- def highlight_config_error(file, line)
468
- config_file_lines = []
469
- IO.readlines(file).each_with_index {|l, i| config_file_lines << "#{(i + 1).to_s.rjust(3)}: #{l.chomp}"}
470
- if line == 1
471
- lines = config_file_lines[0..3]
472
- lines[0] = ui.color(lines[0], :red)
473
- else
474
- lines = config_file_lines[Range.new(line - 2, line)]
475
- lines[1] = ui.color(lines[1], :red)
476
- end
477
- ui.msg ""
478
- ui.msg ui.color(" # #{file}", :white)
479
- lines.each {|l| ui.msg(l)}
480
- ui.msg ""
481
- end
482
-
483
398
  def show_usage
484
399
  stdout.puts("USAGE: " + self.opt_parser.to_s)
485
400
  end