chef 12.0.0.alpha.1 → 12.0.0.alpha.2

Sign up to get free protection for your applications and to get access to all the features.
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