chef 12.2.1 → 12.3.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef.rb +1 -0
  3. data/lib/chef/application/apply.rb +5 -0
  4. data/lib/chef/application/client.rb +10 -0
  5. data/lib/chef/application/knife.rb +5 -1
  6. data/lib/chef/application/solo.rb +5 -0
  7. data/lib/chef/chef_class.rb +130 -0
  8. data/lib/chef/client.rb +15 -7
  9. data/lib/chef/config.rb +13 -0
  10. data/lib/chef/event_loggers/windows_eventlog.rb +11 -5
  11. data/lib/chef/http.rb +13 -3
  12. data/lib/chef/http/basic_client.rb +21 -4
  13. data/lib/chef/http/socketless_chef_zero_client.rb +207 -0
  14. data/lib/chef/knife.rb +3 -0
  15. data/lib/chef/knife/bootstrap.rb +1 -1
  16. data/lib/chef/knife/core/status_presenter.rb +12 -11
  17. data/lib/chef/knife/ssh.rb +3 -1
  18. data/lib/chef/knife/status.rb +32 -7
  19. data/lib/chef/local_mode.rb +13 -3
  20. data/lib/chef/mixin/provides.rb +32 -0
  21. data/lib/chef/platform/provider_priority_map.rb +16 -7
  22. data/lib/chef/platform/resource_priority_map.rb +37 -0
  23. data/lib/chef/policy_builder/expand_node_object.rb +14 -0
  24. data/lib/chef/policy_builder/policyfile.rb +0 -1
  25. data/lib/chef/provider.rb +5 -20
  26. data/lib/chef/provider/package/rubygems.rb +4 -1
  27. data/lib/chef/provider/service/macosx.rb +66 -30
  28. data/lib/chef/provider_resolver.rb +10 -5
  29. data/lib/chef/resource.rb +5 -39
  30. data/lib/chef/resource/gem_package.rb +5 -0
  31. data/lib/chef/resource/link.rb +1 -1
  32. data/lib/chef/resource/macosx_service.rb +59 -0
  33. data/lib/chef/resource/remote_file.rb +0 -4
  34. data/lib/chef/resource_resolver.rb +101 -0
  35. data/lib/chef/rest.rb +4 -5
  36. data/lib/chef/search/query.rb +1 -1
  37. data/lib/chef/server_api.rb +1 -0
  38. data/lib/chef/version.rb +1 -1
  39. data/spec/data/lwrp/providers/buck_passer.rb +2 -1
  40. data/spec/data/lwrp/resources/bar.rb +1 -1
  41. data/spec/data/{big_json.json → nested.json} +2 -2
  42. data/spec/functional/event_loggers/windows_eventlog_spec.rb +14 -0
  43. data/spec/functional/resource/execute_spec.rb +1 -1
  44. data/spec/integration/client/client_spec.rb +12 -1
  45. data/spec/integration/client/ipv6_spec.rb +1 -1
  46. data/spec/integration/knife/common_options_spec.rb +3 -3
  47. data/spec/integration/recipes/lwrp_inline_resources_spec.rb +1 -1
  48. data/spec/integration/solo/solo_spec.rb +7 -5
  49. data/spec/unit/application/client_spec.rb +10 -0
  50. data/spec/unit/chef_class_spec.rb +91 -0
  51. data/spec/unit/client_spec.rb +13 -0
  52. data/spec/unit/http/basic_client_spec.rb +43 -6
  53. data/spec/unit/http/socketless_chef_zero_client_spec.rb +174 -0
  54. data/spec/unit/http_spec.rb +14 -0
  55. data/spec/unit/json_compat_spec.rb +7 -20
  56. data/spec/unit/knife/ssh_spec.rb +18 -0
  57. data/spec/unit/knife/status_spec.rb +69 -3
  58. data/spec/unit/knife_spec.rb +5 -0
  59. data/spec/unit/provider/package/rubygems_spec.rb +19 -0
  60. data/spec/unit/provider/service/macosx_spec.rb +230 -203
  61. data/spec/unit/provider_resolver_spec.rb +1 -0
  62. data/spec/unit/recipe_spec.rb +48 -0
  63. data/spec/unit/resource/link_spec.rb +15 -0
  64. data/spec/unit/resource_spec.rb +6 -6
  65. data/spec/unit/rest_spec.rb +9 -0
  66. data/spec/unit/search/query_spec.rb +24 -0
  67. data/spec/unit/shell_spec.rb +3 -1
  68. metadata +16 -9
  69. data/spec/data/big_json_plus_one.json +0 -2
@@ -373,6 +373,9 @@ class Chef
373
373
  Chef::Config[:environment] = config[:environment] if config[:environment]
374
374
 
375
375
  Chef::Config.local_mode = config[:local_mode] if config.has_key?(:local_mode)
376
+
377
+ Chef::Config.listen = config[:listen] if config.has_key?(:listen)
378
+
376
379
  if Chef::Config.local_mode && !Chef::Config.has_key?(:cookbook_path) && !Chef::Config.has_key?(:chef_repo_path)
377
380
  Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd)
378
381
  end
@@ -378,7 +378,7 @@ class Chef
378
378
  command = render_template
379
379
 
380
380
  if config[:use_sudo]
381
- command = config[:use_sudo_password] ? "echo '#{config[:ssh_password]}' | sudo -S #{command}" : "sudo #{command}"
381
+ command = config[:use_sudo_password] ? "echo '#{config[:ssh_password]}' | sudo -SH #{command}" : "sudo -H #{command}"
382
382
  end
383
383
 
384
384
  command
@@ -66,16 +66,16 @@ class Chef
66
66
  list.each do |node|
67
67
  result = {}
68
68
 
69
- result["name"] = node.name
70
- result["chef_environment"] = node.chef_environment
71
- ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress]
72
- fqdn = (node[:ec2] && node[:ec2][:public_hostname]) || node[:fqdn]
69
+ result["name"] = node["name"] || node.name
70
+ result["chef_environment"] = node["chef_environment"]
71
+ ip = (node["ec2"] && node["ec2"]["public_ipv4"]) || node["ipaddress"]
72
+ fqdn = (node["ec2"] && node["ec2"]["public_hostname"]) || node["fqdn"]
73
73
  result["ip"] = ip if ip
74
74
  result["fqdn"] = fqdn if fqdn
75
- result["run_list"] = node.run_list if config[:run_list]
76
- result["ohai_time"] = node[:ohai_time]
77
- result["platform"] = node[:platform] if node[:platform]
78
- result["platform_version"] = node[:platform_version] if node[:platform_version]
75
+ result["run_list"] = node.run_list if config["run_list"]
76
+ result["ohai_time"] = node["ohai_time"]
77
+ result["platform"] = node["platform"] if node["platform"]
78
+ result["platform_version"] = node["platform_version"] if node["platform_version"]
79
79
 
80
80
  if config[:long_output]
81
81
  result["default"] = node.default_attrs
@@ -99,11 +99,12 @@ class Chef
99
99
  # special case ec2 with their split horizon whatsis.
100
100
  ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress]
101
101
  fqdn = (node[:ec2] && node[:ec2][:public_hostname]) || node[:fqdn]
102
+ name = node['name'] || node.name
102
103
 
103
- hours, minutes, seconds = time_difference_in_hms(node["ohai_time"])
104
+ hours, minutes, _ = time_difference_in_hms(node["ohai_time"])
104
105
  hours_text = "#{hours} hour#{hours == 1 ? ' ' : 's'}"
105
106
  minutes_text = "#{minutes} minute#{minutes == 1 ? ' ' : 's'}"
106
- run_list = "#{node.run_list}" if config[:run_list]
107
+ run_list = "#{node['run_list']}" if config[:run_list]
107
108
  if hours > 24
108
109
  color = :red
109
110
  text = hours_text
@@ -116,7 +117,7 @@ class Chef
116
117
  end
117
118
 
118
119
  line_parts = Array.new
119
- line_parts << @ui.color(text, color) + ' ago' << node.name
120
+ line_parts << @ui.color(text, color) + ' ago' << name
120
121
  line_parts << fqdn if fqdn
121
122
  line_parts << ip if ip
122
123
  line_parts << run_list if run_list
@@ -175,7 +175,9 @@ class Chef
175
175
  if config[:attribute_from_cli]
176
176
  Chef::Log.debug("Using node attribute '#{config[:attribute_from_cli]}' from the command line as the ssh target")
177
177
  host = extract_nested_value(item, config[:attribute_from_cli])
178
- elsif item[:cloud] && item[:cloud][:public_hostname]
178
+ elsif item[:cloud] &&
179
+ item[:cloud][:public_hostname] &&
180
+ !item[:cloud][:public_hostname].empty?
179
181
  Chef::Log.debug("Using node attribute 'cloud[:public_hostname]' automatically as the ssh target")
180
182
  host = item[:cloud][:public_hostname]
181
183
  else
@@ -18,10 +18,12 @@
18
18
 
19
19
  require 'chef/knife'
20
20
  require 'chef/knife/core/status_presenter'
21
+ require 'chef/knife/core/node_presenter'
21
22
 
22
23
  class Chef
23
24
  class Knife
24
25
  class Status < Knife
26
+ include Knife::Core::NodeFormattingOptions
25
27
 
26
28
  deps do
27
29
  require 'chef/search/query'
@@ -44,20 +46,43 @@ class Chef
44
46
  :long => "--hide-healthy",
45
47
  :description => "Hide nodes that have run chef in the last hour"
46
48
 
49
+ def append_to_query(term)
50
+ @query << " AND " unless @query.empty?
51
+ @query << term
52
+ end
53
+
47
54
  def run
48
55
  ui.use_presenter Knife::Core::StatusPresenter
49
- all_nodes = []
50
- q = Chef::Search::Query.new
51
- query = @name_args[0] ? @name_args[0].dup : '*:*'
56
+
57
+ if config[:long_output]
58
+ opts = {}
59
+ else
60
+ opts = {filter_result:
61
+ { name: ["name"], ipaddress: ["ipaddress"], ohai_time: ["ohai_time"],
62
+ ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
63
+ platform_version: ["platform_version"], chef_environment: ["chef_environment"]}}
64
+ end
65
+
66
+ @query ||= ""
67
+ append_to_query(@name_args[0]) if @name_args[0]
68
+ append_to_query("chef_environment:#{config[:environment]}") if config[:environment]
69
+
52
70
  if config[:hide_healthy]
53
71
  time = Time.now.to_i
54
- query_unhealthy = "NOT ohai_time:[" << (time - 60*60).to_s << " TO " << time.to_s << "]"
55
- query << ' AND ' << query_unhealthy << @name_args[0] if @name_args[0]
56
- query = query_unhealthy unless @name_args[0]
72
+ # AND NOT is not valid lucene syntax, so don't use append_to_query
73
+ @query << " " unless @query.empty?
74
+ @query << "NOT ohai_time:[#{(time - 60*60).to_s} TO #{time.to_s}]"
57
75
  end
58
- q.search(:node, query) do |node|
76
+
77
+ @query = @query.empty? ? "*:*" : @query
78
+
79
+ all_nodes = []
80
+ q = Chef::Search::Query.new
81
+ Chef::Log.info("Sending query: #{@query}")
82
+ q.search(:node, @query, opts) do |node|
59
83
  all_nodes << node
60
84
  end
85
+
61
86
  output(all_nodes.sort { |n1, n2|
62
87
  if (config[:sort_reverse] || Chef::Config[:knife][:sort_status_reverse])
63
88
  (n2["ohai_time"] or 0) <=> (n1["ohai_time"] or 0)
@@ -18,6 +18,7 @@ require 'chef/config'
18
18
 
19
19
  class Chef
20
20
  module LocalMode
21
+
21
22
  # Create a chef local server (if the configuration requires one) for the
22
23
  # duration of the given block.
23
24
  #
@@ -59,12 +60,21 @@ class Chef
59
60
  server_options = {}
60
61
  server_options[:data_store] = data_store
61
62
  server_options[:log_level] = Chef::Log.level
63
+
62
64
  server_options[:host] = Chef::Config.chef_zero.host
63
65
  server_options[:port] = parse_port(Chef::Config.chef_zero.port)
64
66
  @chef_zero_server = ChefZero::Server.new(server_options)
65
- @chef_zero_server.start_background
66
- Chef::Log.info("Started chef-zero at #{@chef_zero_server.url} with #{@chef_fs.fs_description}")
67
- Chef::Config.chef_server_url = @chef_zero_server.url
67
+
68
+ if Chef::Config[:listen]
69
+ @chef_zero_server.start_background
70
+ else
71
+ @chef_zero_server.start_socketless
72
+ end
73
+
74
+ local_mode_url = @chef_zero_server.local_mode_url
75
+
76
+ Chef::Log.info("Started chef-zero at #{local_mode_url} with #{@chef_fs.fs_description}")
77
+ Chef::Config.chef_server_url = local_mode_url
68
78
  end
69
79
  end
70
80
 
@@ -0,0 +1,32 @@
1
+
2
+ require 'chef/mixin/descendants_tracker'
3
+
4
+ class Chef
5
+ module Mixin
6
+ module Provides
7
+ include Chef::Mixin::DescendantsTracker
8
+
9
+ def node_map
10
+ @node_map ||= Chef::NodeMap.new
11
+ end
12
+
13
+ def provides(short_name, opts={}, &block)
14
+ if !short_name.kind_of?(Symbol)
15
+ # YAGNI: this is probably completely unnecessary and can be removed?
16
+ Chef::Log.deprecation "Passing a non-Symbol to Chef::Resource#provides will be removed"
17
+ if short_name.kind_of?(String)
18
+ short_name.downcase!
19
+ short_name.gsub!(/\s/, "_")
20
+ end
21
+ short_name = short_name.to_sym
22
+ end
23
+ node_map.set(short_name, true, opts, &block)
24
+ end
25
+
26
+ # provides a node on the resource (early binding)
27
+ def provides?(node, resource_name)
28
+ node_map.get(node, resource_name)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,6 +1,4 @@
1
1
 
2
- require 'chef/providers'
3
-
4
2
  class Chef
5
3
  class Platform
6
4
  class ProviderPriorityMap
@@ -10,7 +8,22 @@ class Chef
10
8
  load_default_map
11
9
  end
12
10
 
11
+ def get_priority_array(node, resource_name)
12
+ priority_map.get(node, resource_name.to_sym)
13
+ end
14
+
15
+ def set_priority_array(resource_name, priority_array, *filter)
16
+ priority(resource_name.to_sym, priority_array.to_a, *filter)
17
+ end
18
+
19
+ def priority(*args)
20
+ priority_map.set(*args)
21
+ end
22
+
23
+ private
24
+
13
25
  def load_default_map
26
+ require 'chef/providers'
14
27
 
15
28
  #
16
29
  # Linux
@@ -71,13 +84,9 @@ class Chef
71
84
  end
72
85
 
73
86
  def priority_map
87
+ require 'chef/node_map'
74
88
  @priority_map ||= Chef::NodeMap.new
75
89
  end
76
-
77
- def priority(*args)
78
- priority_map.set(*args)
79
- end
80
-
81
90
  end
82
91
  end
83
92
  end
@@ -0,0 +1,37 @@
1
+ class Chef
2
+ class Platform
3
+ class ResourcePriorityMap
4
+ include Singleton
5
+
6
+ def initialize
7
+ load_default_map
8
+ end
9
+
10
+ def get_priority_array(node, resource_name)
11
+ priority_map.get(node, resource_name.to_sym)
12
+ end
13
+
14
+ def set_priority_array(resource_name, priority_array, *filter)
15
+ priority resource_name.to_sym, priority_array.to_a, *filter
16
+ end
17
+
18
+ def priority(*args)
19
+ priority_map.set(*args)
20
+ end
21
+
22
+ private
23
+
24
+ def load_default_map
25
+ require 'chef/resources'
26
+
27
+ # MacOSX
28
+ priority :package, Chef::Resource::HomebrewPackage, os: "darwin"
29
+ end
30
+
31
+ def priority_map
32
+ require 'chef/node_map'
33
+ @priority_map ||= Chef::NodeMap.new
34
+ end
35
+ end
36
+ end
37
+ end
@@ -24,6 +24,7 @@ require 'chef/rest'
24
24
  require 'chef/run_context'
25
25
  require 'chef/config'
26
26
  require 'chef/node'
27
+ require 'chef/chef_class'
27
28
 
28
29
  class Chef
29
30
  module PolicyBuilder
@@ -54,6 +55,15 @@ class Chef
54
55
  @run_list_expansion = nil
55
56
  end
56
57
 
58
+ # This method injects the run_context and provider and resource priority
59
+ # maps into the Chef class. The run_context has to be injected here, the provider and
60
+ # resource maps could be moved if a better place can be found to do this work.
61
+ #
62
+ # @param run_context [Chef::RunContext] the run_context to inject
63
+ def setup_chef_class(run_context)
64
+ Chef.set_run_context(run_context)
65
+ end
66
+
57
67
  def setup_run_context(specific_recipes=nil)
58
68
  if Chef::Config[:solo]
59
69
  Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
@@ -68,6 +78,10 @@ class Chef
68
78
  run_context = Chef::RunContext.new(node, cookbook_collection, @events)
69
79
  end
70
80
 
81
+ # TODO: this is really obviously not the place for this
82
+ # FIXME: need same edits
83
+ setup_chef_class(run_context)
84
+
71
85
  # TODO: this is not the place for this. It should be in Runner or
72
86
  # CookbookCompiler or something.
73
87
  run_context.load(@run_list_expansion)
@@ -385,4 +385,3 @@ class Chef
385
385
  end
386
386
  end
387
387
  end
388
-
@@ -22,7 +22,7 @@ require 'chef/mixin/convert_to_class_name'
22
22
  require 'chef/mixin/enforce_ownership_and_permissions'
23
23
  require 'chef/mixin/why_run'
24
24
  require 'chef/mixin/shell_out'
25
- require 'chef/mixin/descendants_tracker'
25
+ require 'chef/mixin/provides'
26
26
  require 'chef/platform/service_helpers'
27
27
  require 'chef/node_map'
28
28
 
@@ -30,26 +30,11 @@ class Chef
30
30
  class Provider
31
31
  include Chef::Mixin::WhyRun
32
32
  include Chef::Mixin::ShellOut
33
- extend Chef::Mixin::DescendantsTracker
33
+ extend Chef::Mixin::Provides
34
34
 
35
- class << self
36
- def node_map
37
- @node_map ||= Chef::NodeMap.new
38
- end
39
-
40
- def provides(resource_name, opts={}, &block)
41
- node_map.set(resource_name.to_sym, true, opts, &block)
42
- end
43
-
44
- # provides a node on the resource (early binding)
45
- def provides?(node, resource)
46
- node_map.get(node, resource.resource_name)
47
- end
48
-
49
- # supports the given resource and action (late binding)
50
- def supports?(resource, action)
51
- true
52
- end
35
+ # supports the given resource and action (late binding)
36
+ def self.supports?(resource, action)
37
+ true
53
38
  end
54
39
 
55
40
  attr_accessor :new_resource
@@ -538,8 +538,11 @@ class Chef
538
538
  def install_via_gem_command(name, version)
539
539
  if @new_resource.source =~ /\.gem$/i
540
540
  name = @new_resource.source
541
+ elsif @new_resource.clear_sources
542
+ src = ' --clear-sources'
543
+ src << (@new_resource.source && " --source=#{@new_resource.source}" || '')
541
544
  else
542
- src = @new_resource.source && " --source=#{@new_resource.source} --source=https://rubygems.org"
545
+ src = @new_resource.source && " --source=#{@new_resource.source} --source=https://rubygems.org"
543
546
  end
544
547
  if !version.nil? && version.length > 0
545
548
  shell_out!("#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \"#{version}\"#{src}#{opts}", :env=>nil)
@@ -16,8 +16,10 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
+ require 'etc'
19
20
  require 'rexml/document'
20
21
  require 'chef/resource/service'
22
+ require 'chef/resource/macosx_service'
21
23
  require 'chef/provider/service/simple'
22
24
  require 'chef/util/path_helper'
23
25
 
@@ -27,6 +29,7 @@ class Chef
27
29
  class Macosx < Chef::Provider::Service::Simple
28
30
 
29
31
  provides :service, os: "darwin"
32
+ provides :macosx_service, os: "darwin"
30
33
 
31
34
  def self.gather_plist_dirs
32
35
  locations = %w{/Library/LaunchAgents
@@ -40,18 +43,32 @@ class Chef
40
43
  PLIST_DIRS = gather_plist_dirs
41
44
 
42
45
  def load_current_resource
43
- @current_resource = Chef::Resource::Service.new(@new_resource.name)
46
+ @current_resource = Chef::Resource::MacosxService.new(@new_resource.name)
44
47
  @current_resource.service_name(@new_resource.service_name)
45
48
  @plist_size = 0
46
- @plist = find_service_plist
49
+ @plist = @new_resource.plist ? @new_resource.plist : find_service_plist
47
50
  @service_label = find_service_label
51
+ # LauchAgents should be loaded as the console user.
52
+ @console_user = @plist ? @plist.include?('LaunchAgents') : false
53
+ @session_type = @new_resource.session_type
54
+
55
+ if @console_user
56
+ @console_user = Etc.getlogin
57
+ Chef::Log.debug("#{new_resource} console_user: '#{@console_user}'")
58
+ cmd = "su "
59
+ param = !node['platform_version'].include?('10.10') ? '-l ' : ''
60
+ @base_user_cmd = cmd + param + "#{@console_user} -c"
61
+ # Default LauchAgent session should be Aqua
62
+ @session_type = 'Aqua' if @session_type.nil?
63
+ end
64
+
65
+ Chef::Log.debug("#{new_resource} Plist: '#{@plist}' service_label: '#{@service_label}'")
48
66
  set_service_status
49
67
 
50
68
  @current_resource
51
69
  end
52
70
 
53
71
  def define_resource_requirements
54
- #super
55
72
  requirements.assert(:reload) do |a|
56
73
  a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload"
57
74
  end
@@ -61,6 +78,12 @@ class Chef
61
78
  a.failure_message Chef::Exceptions::Service, "Several plist files match service name. Please use full service name."
62
79
  end
63
80
 
81
+ requirements.assert(:all_actions) do |a|
82
+ a.assertion {::File.exists?(@plist.to_s) }
83
+ a.failure_message Chef::Exceptions::Service,
84
+ "Could not find plist for #{@new_resource}"
85
+ end
86
+
64
87
  requirements.assert(:enable, :disable) do |a|
65
88
  a.assertion { !@service_label.to_s.empty? }
66
89
  a.failure_message Chef::Exceptions::Service,
@@ -69,7 +92,7 @@ class Chef
69
92
 
70
93
  requirements.assert(:all_actions) do |a|
71
94
  a.assertion { @plist_size > 0 }
72
- # No failrue here in original code - so we also will not
95
+ # No failure here in original code - so we also will not
73
96
  # fail. Instead warn that the service is potentially missing
74
97
  a.whyrun "Assuming that the service would have been previously installed and is currently disabled." do
75
98
  @current_resource.enabled(false)
@@ -85,7 +108,7 @@ class Chef
85
108
  if @new_resource.start_command
86
109
  super
87
110
  else
88
- shell_out_with_systems_locale!("launchctl load -w '#{@plist}'", :user => @owner_uid, :group => @owner_gid)
111
+ load_service
89
112
  end
90
113
  end
91
114
  end
@@ -97,7 +120,7 @@ class Chef
97
120
  if @new_resource.stop_command
98
121
  super
99
122
  else
100
- shell_out_with_systems_locale!("launchctl unload '#{@plist}'", :user => @owner_uid, :group => @owner_gid)
123
+ unload_service
101
124
  end
102
125
  end
103
126
  end
@@ -106,9 +129,9 @@ class Chef
106
129
  if @new_resource.restart_command
107
130
  super
108
131
  else
109
- stop_service
132
+ unload_service
110
133
  sleep 1
111
- start_service
134
+ load_service
112
135
  end
113
136
  end
114
137
 
@@ -121,10 +144,7 @@ class Chef
121
144
  if @current_resource.enabled
122
145
  Chef::Log.debug("#{@new_resource} already enabled, not enabling")
123
146
  else
124
- shell_out!(
125
- "launchctl load -w '#{@plist}'",
126
- :user => @owner_uid, :group => @owner_gid
127
- )
147
+ load_service
128
148
  end
129
149
  end
130
150
 
@@ -132,38 +152,49 @@ class Chef
132
152
  unless @current_resource.enabled
133
153
  Chef::Log.debug("#{@new_resource} not enabled, not disabling")
134
154
  else
135
- shell_out!(
136
- "launchctl unload -w '#{@plist}'",
137
- :user => @owner_uid, :group => @owner_gid
138
- )
155
+ unload_service
156
+ end
157
+ end
158
+
159
+ def load_service
160
+ session = @session_type ? "-S #{@session_type} " : ''
161
+ cmd = 'launchctl load -w ' + session + @plist
162
+ shell_out_as_user(cmd)
163
+ end
164
+
165
+ def unload_service
166
+ cmd = 'launchctl unload -w ' + @plist
167
+ shell_out_as_user(cmd)
168
+ end
169
+
170
+ def shell_out_as_user(cmd)
171
+ if @console_user
172
+ shell_out_with_systems_locale("#{@base_user_cmd} '#{cmd}'")
173
+ else
174
+ shell_out_with_systems_locale(cmd)
175
+
139
176
  end
140
177
  end
141
178
 
142
179
  def set_service_status
143
180
  return if @plist == nil or @service_label.to_s.empty?
144
181
 
145
- cmd = shell_out(
146
- "launchctl list #{@service_label}",
147
- :user => @owner_uid, :group => @owner_gid
148
- )
182
+ cmd = "launchctl list #{@service_label}"
183
+ res = shell_out_as_user(cmd)
149
184
 
150
- if cmd.exitstatus == 0
185
+ if res.exitstatus == 0
151
186
  @current_resource.enabled(true)
152
187
  else
153
188
  @current_resource.enabled(false)
154
189
  end
155
190
 
156
191
  if @current_resource.enabled
157
- @owner_uid = ::File.stat(@plist).uid
158
- @owner_gid = ::File.stat(@plist).gid
159
-
160
- shell_out!(
161
- "launchctl list", :user => @owner_uid, :group => @owner_gid
162
- ).stdout.each_line do |line|
163
- case line
164
- when /(\d+|-)\s+(?:\d+|-)\s+(.*\.?)#{@service_label}/
192
+ res.stdout.each_line do |line|
193
+ case line.downcase
194
+ when /\s+\"pid\"\s+=\s+(\d+).*/
165
195
  pid = $1
166
196
  @current_resource.running(!pid.to_i.zero?)
197
+ Chef::Log.debug("Current PID for #{@service_label} is #{pid}")
167
198
  end
168
199
  end
169
200
  else
@@ -178,6 +209,9 @@ class Chef
178
209
  # onto the node yet."
179
210
  return nil if @plist.nil?
180
211
 
212
+ # Plist must exist by this point
213
+ raise Chef::Exceptions::FileNotFound, "Cannot find #{@plist}!" unless ::File.exists?(@plist)
214
+
181
215
  # Most services have the same internal label as the name of the
182
216
  # plist file. However, there is no rule saying that *has* to be
183
217
  # the case, and some core services (notably, ssh) do not follow
@@ -185,7 +219,9 @@ class Chef
185
219
 
186
220
  # plist files can come in XML or Binary formats. this command
187
221
  # will make sure we get XML every time.
188
- plist_xml = shell_out!("plutil -convert xml1 -o - #{@plist}").stdout
222
+ plist_xml = shell_out_with_systems_locale!(
223
+ "plutil -convert xml1 -o - #{@plist}"
224
+ ).stdout
189
225
 
190
226
  plist_doc = REXML::Document.new(plist_xml)
191
227
  plist_doc.elements[