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.
- checksums.yaml +4 -4
- data/lib/chef.rb +1 -0
- data/lib/chef/application/apply.rb +5 -0
- data/lib/chef/application/client.rb +10 -0
- data/lib/chef/application/knife.rb +5 -1
- data/lib/chef/application/solo.rb +5 -0
- data/lib/chef/chef_class.rb +130 -0
- data/lib/chef/client.rb +15 -7
- data/lib/chef/config.rb +13 -0
- data/lib/chef/event_loggers/windows_eventlog.rb +11 -5
- data/lib/chef/http.rb +13 -3
- data/lib/chef/http/basic_client.rb +21 -4
- data/lib/chef/http/socketless_chef_zero_client.rb +207 -0
- data/lib/chef/knife.rb +3 -0
- data/lib/chef/knife/bootstrap.rb +1 -1
- data/lib/chef/knife/core/status_presenter.rb +12 -11
- data/lib/chef/knife/ssh.rb +3 -1
- data/lib/chef/knife/status.rb +32 -7
- data/lib/chef/local_mode.rb +13 -3
- data/lib/chef/mixin/provides.rb +32 -0
- data/lib/chef/platform/provider_priority_map.rb +16 -7
- data/lib/chef/platform/resource_priority_map.rb +37 -0
- data/lib/chef/policy_builder/expand_node_object.rb +14 -0
- data/lib/chef/policy_builder/policyfile.rb +0 -1
- data/lib/chef/provider.rb +5 -20
- data/lib/chef/provider/package/rubygems.rb +4 -1
- data/lib/chef/provider/service/macosx.rb +66 -30
- data/lib/chef/provider_resolver.rb +10 -5
- data/lib/chef/resource.rb +5 -39
- data/lib/chef/resource/gem_package.rb +5 -0
- data/lib/chef/resource/link.rb +1 -1
- data/lib/chef/resource/macosx_service.rb +59 -0
- data/lib/chef/resource/remote_file.rb +0 -4
- data/lib/chef/resource_resolver.rb +101 -0
- data/lib/chef/rest.rb +4 -5
- data/lib/chef/search/query.rb +1 -1
- data/lib/chef/server_api.rb +1 -0
- data/lib/chef/version.rb +1 -1
- data/spec/data/lwrp/providers/buck_passer.rb +2 -1
- data/spec/data/lwrp/resources/bar.rb +1 -1
- data/spec/data/{big_json.json → nested.json} +2 -2
- data/spec/functional/event_loggers/windows_eventlog_spec.rb +14 -0
- data/spec/functional/resource/execute_spec.rb +1 -1
- data/spec/integration/client/client_spec.rb +12 -1
- data/spec/integration/client/ipv6_spec.rb +1 -1
- data/spec/integration/knife/common_options_spec.rb +3 -3
- data/spec/integration/recipes/lwrp_inline_resources_spec.rb +1 -1
- data/spec/integration/solo/solo_spec.rb +7 -5
- data/spec/unit/application/client_spec.rb +10 -0
- data/spec/unit/chef_class_spec.rb +91 -0
- data/spec/unit/client_spec.rb +13 -0
- data/spec/unit/http/basic_client_spec.rb +43 -6
- data/spec/unit/http/socketless_chef_zero_client_spec.rb +174 -0
- data/spec/unit/http_spec.rb +14 -0
- data/spec/unit/json_compat_spec.rb +7 -20
- data/spec/unit/knife/ssh_spec.rb +18 -0
- data/spec/unit/knife/status_spec.rb +69 -3
- data/spec/unit/knife_spec.rb +5 -0
- data/spec/unit/provider/package/rubygems_spec.rb +19 -0
- data/spec/unit/provider/service/macosx_spec.rb +230 -203
- data/spec/unit/provider_resolver_spec.rb +1 -0
- data/spec/unit/recipe_spec.rb +48 -0
- data/spec/unit/resource/link_spec.rb +15 -0
- data/spec/unit/resource_spec.rb +6 -6
- data/spec/unit/rest_spec.rb +9 -0
- data/spec/unit/search/query_spec.rb +24 -0
- data/spec/unit/shell_spec.rb +3 -1
- metadata +16 -9
- data/spec/data/big_json_plus_one.json +0 -2
data/spec/unit/http_spec.rb
CHANGED
@@ -20,6 +20,7 @@ require 'spec_helper'
|
|
20
20
|
|
21
21
|
require 'chef/http'
|
22
22
|
require 'chef/http/basic_client'
|
23
|
+
require 'chef/http/socketless_chef_zero_client'
|
23
24
|
|
24
25
|
class Chef::HTTP
|
25
26
|
public :create_url
|
@@ -27,6 +28,19 @@ end
|
|
27
28
|
|
28
29
|
describe Chef::HTTP do
|
29
30
|
|
31
|
+
context "when given a chefzero:// URL" do
|
32
|
+
|
33
|
+
let(:uri) { URI("chefzero://localhost:1") }
|
34
|
+
|
35
|
+
subject(:http) { Chef::HTTP.new(uri) }
|
36
|
+
|
37
|
+
it "uses the SocketlessChefZeroClient to handle requests" do
|
38
|
+
expect(http.http_client).to be_a_kind_of(Chef::HTTP::SocketlessChefZeroClient)
|
39
|
+
expect(http.http_client.url).to eq(uri)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
30
44
|
describe "create_url" do
|
31
45
|
|
32
46
|
it 'should return a correctly formatted url 1/3 CHEF-5261' do
|
@@ -72,32 +72,19 @@ describe Chef::JSONCompat do
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
|
76
|
-
|
75
|
+
# On FreeBSD 10.1 i386 rspec fails with a SystemStackError loading the expect line with more that 252 entries
|
76
|
+
# https://github.com/chef/chef/issues/3101
|
77
|
+
describe "with the file with 252 or less nested entries" do
|
78
|
+
let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'nested.json')) }
|
77
79
|
let(:hash) { Chef::JSONCompat.from_json(json) }
|
78
80
|
|
79
|
-
describe "when
|
81
|
+
describe "when the 252 json file is loaded" do
|
80
82
|
it "should create a Hash from the file" do
|
81
83
|
expect(hash).to be_kind_of(Hash)
|
82
84
|
end
|
83
85
|
|
84
|
-
it "should has 'test' as a
|
85
|
-
expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe "with a file with more than 300 nested entries" do
|
91
|
-
let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json_plus_one.json')) }
|
92
|
-
let(:hash) { Chef::JSONCompat.from_json(json, {:max_nesting => 301}) }
|
93
|
-
|
94
|
-
describe "when a big json file is loaded" do
|
95
|
-
it "should create a Hash from the file" do
|
96
|
-
expect(hash).to be_kind_of(Hash)
|
97
|
-
end
|
98
|
-
|
99
|
-
it "should has 'test' as a 301st nested value" do
|
100
|
-
expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
|
86
|
+
it "should has 'test' as a 252 nested value" do
|
87
|
+
expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
|
101
88
|
end
|
102
89
|
end
|
103
90
|
end
|
data/spec/unit/knife/ssh_spec.rb
CHANGED
@@ -96,6 +96,24 @@ describe Chef::Knife::Ssh do
|
|
96
96
|
should_return_specified_attributes
|
97
97
|
end
|
98
98
|
|
99
|
+
context "when cloud hostnames are available but empty" do
|
100
|
+
before do
|
101
|
+
@node_foo.automatic_attrs[:cloud][:public_hostname] = ''
|
102
|
+
@node_bar.automatic_attrs[:cloud][:public_hostname] = ''
|
103
|
+
end
|
104
|
+
|
105
|
+
it "returns an array of fqdns" do
|
106
|
+
configure_query([@node_foo, @node_bar])
|
107
|
+
expect(@knife).to receive(:session_from_list).with([
|
108
|
+
['foo.example.org', nil],
|
109
|
+
['bar.example.org', nil]
|
110
|
+
])
|
111
|
+
@knife.configure_session
|
112
|
+
end
|
113
|
+
|
114
|
+
should_return_specified_attributes
|
115
|
+
end
|
116
|
+
|
99
117
|
it "should raise an error if no host are found" do
|
100
118
|
configure_query([ ])
|
101
119
|
expect(@knife.ui).to receive(:fatal)
|
@@ -24,15 +24,81 @@ describe Chef::Knife::Status do
|
|
24
24
|
n.automatic_attrs["fqdn"] = "foobar"
|
25
25
|
n.automatic_attrs["ohai_time"] = 1343845969
|
26
26
|
end
|
27
|
-
|
28
|
-
|
29
|
-
allow(
|
27
|
+
allow(Time).to receive(:now).and_return(Time.at(1428573420))
|
28
|
+
@query = double("Chef::Search::Query")
|
29
|
+
allow(@query).to receive(:search).and_yield(node)
|
30
|
+
allow(Chef::Search::Query).to receive(:new).and_return(@query)
|
30
31
|
@knife = Chef::Knife::Status.new
|
31
32
|
@stdout = StringIO.new
|
32
33
|
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
|
33
34
|
end
|
34
35
|
|
35
36
|
describe "run" do
|
37
|
+
let(:opts) {{filter_result:
|
38
|
+
{ name: ["name"], ipaddress: ["ipaddress"], ohai_time: ["ohai_time"],
|
39
|
+
ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
|
40
|
+
platform_version: ["platform_version"], chef_environment: ["chef_environment"]}}}
|
41
|
+
|
42
|
+
it "should default to searching for everything" do
|
43
|
+
expect(@query).to receive(:search).with(:node, "*:*", opts)
|
44
|
+
@knife.run
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should filter healthy nodes" do
|
48
|
+
@knife.config[:hide_healthy] = true
|
49
|
+
expect(@query).to receive(:search).with(:node, "NOT ohai_time:[1428569820 TO 1428573420]", opts)
|
50
|
+
@knife.run
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should filter by environment" do
|
54
|
+
@knife.config[:environment] = "production"
|
55
|
+
expect(@query).to receive(:search).with(:node, "chef_environment:production", opts)
|
56
|
+
@knife.run
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should filter by environment and health" do
|
60
|
+
@knife.config[:environment] = "production"
|
61
|
+
@knife.config[:hide_healthy] = true
|
62
|
+
expect(@query).to receive(:search).with(:node, "chef_environment:production NOT ohai_time:[1428569820 TO 1428573420]", opts)
|
63
|
+
@knife.run
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not use partial search with long output" do
|
67
|
+
@knife.config[:long_output] = true
|
68
|
+
expect(@query).to receive(:search).with(:node, "*:*", {})
|
69
|
+
@knife.run
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with a custom query" do
|
73
|
+
before :each do
|
74
|
+
@knife.instance_variable_set(:@name_args, ["name:my_custom_name"])
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should allow a custom query to be specified" do
|
78
|
+
expect(@query).to receive(:search).with(:node, "name:my_custom_name", opts)
|
79
|
+
@knife.run
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should filter healthy nodes" do
|
83
|
+
@knife.config[:hide_healthy] = true
|
84
|
+
expect(@query).to receive(:search).with(:node, "name:my_custom_name NOT ohai_time:[1428569820 TO 1428573420]", opts)
|
85
|
+
@knife.run
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should filter by environment" do
|
89
|
+
@knife.config[:environment] = "production"
|
90
|
+
expect(@query).to receive(:search).with(:node, "name:my_custom_name AND chef_environment:production", opts)
|
91
|
+
@knife.run
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should filter by environment and health" do
|
95
|
+
@knife.config[:environment] = "production"
|
96
|
+
@knife.config[:hide_healthy] = true
|
97
|
+
expect(@query).to receive(:search).with(:node, "name:my_custom_name AND chef_environment:production NOT ohai_time:[1428569820 TO 1428573420]", opts)
|
98
|
+
@knife.run
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
36
102
|
it "should not colorize output unless it's writing to a tty" do
|
37
103
|
@knife.run
|
38
104
|
expect(@stdout.string.match(/foobar/)).not_to be_nil
|
data/spec/unit/knife_spec.rb
CHANGED
@@ -271,6 +271,11 @@ describe Chef::Knife do
|
|
271
271
|
expect(knife_command.config[:opt_with_default]).to eq("from-cli")
|
272
272
|
end
|
273
273
|
|
274
|
+
it "merges `listen` config to Chef::Config" do
|
275
|
+
Chef::Knife.run(%w[test yourself --no-listen], Chef::Application::Knife.options)
|
276
|
+
expect(Chef::Config[:listen]).to be(false)
|
277
|
+
end
|
278
|
+
|
274
279
|
context "verbosity is greater than zero" do
|
275
280
|
let(:fake_config) { "/does/not/exist/knife.rb" }
|
276
281
|
|
@@ -547,6 +547,25 @@ describe Chef::Provider::Package::Rubygems do
|
|
547
547
|
expect(@new_resource).to be_updated_by_last_action
|
548
548
|
end
|
549
549
|
|
550
|
+
it "installs the gem with rubygems.org as an added source" do
|
551
|
+
@new_resource.gem_binary('/foo/bar')
|
552
|
+
@new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
|
553
|
+
expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --source=#{@new_resource.source} --source=https://rubygems.org"
|
554
|
+
expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
|
555
|
+
@provider.run_action(:install)
|
556
|
+
expect(@new_resource).to be_updated_by_last_action
|
557
|
+
end
|
558
|
+
|
559
|
+
it "installs the gem with cleared sources and explict source when specified" do
|
560
|
+
@new_resource.gem_binary('/foo/bar')
|
561
|
+
@new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
|
562
|
+
@new_resource.clear_sources(true)
|
563
|
+
expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --clear-sources --source=#{@new_resource.source}"
|
564
|
+
expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
|
565
|
+
@provider.run_action(:install)
|
566
|
+
expect(@new_resource).to be_updated_by_last_action
|
567
|
+
end
|
568
|
+
|
550
569
|
context "when no version is given" do
|
551
570
|
let(:target_version) { nil }
|
552
571
|
|
@@ -58,248 +58,275 @@ describe Chef::Provider::Service::Macosx do
|
|
58
58
|
</plist>
|
59
59
|
XML
|
60
60
|
|
61
|
-
["
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
allow(provider).to receive(:shell_out!).
|
73
|
-
with(/plutil -convert xml1 -o/).
|
74
|
-
and_return(double("Status", :stdout => plutil_stdout))
|
75
|
-
|
76
|
-
allow(File).to receive(:stat).and_return(double("stat", :gid => 1001, :uid => 101))
|
77
|
-
end
|
78
|
-
|
79
|
-
context "#{service_name}" do
|
80
|
-
let(:new_resource) { Chef::Resource::Service.new(service_name) }
|
81
|
-
let!(:current_resource) { Chef::Resource::Service.new(service_name) }
|
82
|
-
|
83
|
-
describe "#load_current_resource" do
|
84
|
-
|
85
|
-
# CHEF-5223 "you can't glob for a file that hasn't been converged
|
86
|
-
# onto the node yet."
|
87
|
-
context "when the plist doesn't exist" do
|
88
|
-
|
89
|
-
def run_resource_setup_for_action(action)
|
90
|
-
new_resource.action(action)
|
91
|
-
provider.action = action
|
92
|
-
provider.load_current_resource
|
93
|
-
provider.define_resource_requirements
|
94
|
-
provider.process_resource_requirements
|
95
|
-
end
|
96
|
-
|
97
|
-
before do
|
98
|
-
allow(Dir).to receive(:glob).and_return([])
|
99
|
-
allow(provider).to receive(:shell_out!).
|
100
|
-
with(/plutil -convert xml1 -o/).
|
101
|
-
and_raise(Mixlib::ShellOut::ShellCommandFailed)
|
102
|
-
end
|
103
|
-
|
104
|
-
it "works for action :nothing" do
|
105
|
-
expect { run_resource_setup_for_action(:nothing) }.not_to raise_error
|
106
|
-
end
|
107
|
-
|
108
|
-
it "works for action :start" do
|
109
|
-
expect { run_resource_setup_for_action(:start) }.not_to raise_error
|
110
|
-
end
|
111
|
-
|
112
|
-
it "errors if action is :enable" do
|
113
|
-
expect { run_resource_setup_for_action(:enable) }.to raise_error(Chef::Exceptions::Service)
|
114
|
-
end
|
115
|
-
|
116
|
-
it "errors if action is :disable" do
|
117
|
-
expect { run_resource_setup_for_action(:disable) }.to raise_error(Chef::Exceptions::Service)
|
61
|
+
["Daemon", "Agent"].each do |service_type|
|
62
|
+
["redis-server", "io.redis.redis-server"].each do |service_name|
|
63
|
+
["10.9", "10.10"].each do |platform_version|
|
64
|
+
let(:plist) {'/Library/LaunchDaemons/io.redis.redis-server.plist'}
|
65
|
+
let(:session) { StringIO.new }
|
66
|
+
if service_type == 'Agent'
|
67
|
+
let(:plist) {'/Library/LaunchAgents/io.redis.redis-server.plist'}
|
68
|
+
let(:session) {'-S Aqua '}
|
69
|
+
let(:su_cmd) {'su igor -c'}
|
70
|
+
if platform_version != "10.10"
|
71
|
+
let(:su_cmd) {'su -l igor -c'}
|
118
72
|
end
|
119
73
|
end
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
end
|
135
|
-
|
136
|
-
it "sets resouce enabled state to true" do
|
137
|
-
expect(provider.current_resource.enabled).to be_truthy
|
138
|
-
end
|
74
|
+
let(:service_label) {'io.redis.redis-server'}
|
75
|
+
before do
|
76
|
+
allow(Dir).to receive(:glob).and_return([plist], [])
|
77
|
+
allow(Etc).to receive(:getlogin).and_return('igor')
|
78
|
+
allow(node).to receive(:[]).with("platform_version").and_return(platform_version)
|
79
|
+
cmd = "launchctl list #{service_label}"
|
80
|
+
allow(provider).to receive(:shell_out_with_systems_locale).
|
81
|
+
with(/(#{su_cmd} '#{cmd}'|#{cmd})/).
|
82
|
+
and_return(double("Status",
|
83
|
+
:stdout => launchctl_stdout, :exitstatus => 0))
|
84
|
+
allow(File).to receive(:exists?).and_return([true], [])
|
85
|
+
allow(provider).to receive(:shell_out_with_systems_locale!).
|
86
|
+
with(/plutil -convert xml1 -o/).
|
87
|
+
and_return(double("Status", :stdout => plutil_stdout))
|
139
88
|
end
|
140
89
|
|
141
|
-
|
142
|
-
let(:
|
143
|
-
|
144
|
-
|
145
|
-
|
90
|
+
context "#{service_name} that is a #{service_type} running Osx #{platform_version}" do
|
91
|
+
let(:new_resource) { Chef::Resource::MacosxService.new(service_name) }
|
92
|
+
let!(:current_resource) { Chef::Resource::MacosxService.new(service_name) }
|
93
|
+
|
94
|
+
describe "#load_current_resource" do
|
95
|
+
|
96
|
+
# CHEF-5223 "you can't glob for a file that hasn't been converged
|
97
|
+
# onto the node yet."
|
98
|
+
context "when the plist doesn't exist" do
|
99
|
+
|
100
|
+
def run_resource_setup_for_action(action)
|
101
|
+
new_resource.action(action)
|
102
|
+
provider.action = action
|
103
|
+
provider.load_current_resource
|
104
|
+
provider.define_resource_requirements
|
105
|
+
provider.process_resource_requirements
|
106
|
+
end
|
107
|
+
|
108
|
+
before do
|
109
|
+
allow(Dir).to receive(:glob).and_return([])
|
110
|
+
allow(File).to receive(:exists?).and_return([true], [])
|
111
|
+
allow(provider).to receive(:shell_out!).
|
112
|
+
with(/plutil -convert xml1 -o/).
|
113
|
+
and_raise(Mixlib::ShellOut::ShellCommandFailed)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "works for action :nothing" do
|
117
|
+
expect { run_resource_setup_for_action(:nothing) }.not_to raise_error
|
118
|
+
end
|
119
|
+
|
120
|
+
it "works for action :start" do
|
121
|
+
expect { run_resource_setup_for_action(:start) }.not_to raise_error
|
122
|
+
end
|
123
|
+
|
124
|
+
it "errors if action is :enable" do
|
125
|
+
expect { run_resource_setup_for_action(:enable) }.to raise_error(Chef::Exceptions::Service)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "errors if action is :disable" do
|
129
|
+
expect { run_resource_setup_for_action(:disable) }.to raise_error(Chef::Exceptions::Service)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "when launchctl returns pid in service list" do
|
134
|
+
let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
|
135
|
+
{
|
136
|
+
"LimitLoadToSessionType" = "System";
|
137
|
+
"Label" = "io.redis.redis-server";
|
138
|
+
"TimeOut" = 30;
|
139
|
+
"OnDemand" = false;
|
140
|
+
"LastExitStatus" = 0;
|
141
|
+
"PID" = 62803;
|
142
|
+
"Program" = "do_some.sh";
|
143
|
+
"ProgramArguments" = (
|
144
|
+
"path/to/do_something.sh";
|
145
|
+
"-f";
|
146
|
+
);
|
147
|
+
};
|
146
148
|
SVC_LIST
|
147
149
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
it "should throw an exception when reload action is attempted" do
|
152
|
-
expect {provider.run_action(:reload)}.to raise_error(Chef::Exceptions::UnsupportedAction)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
context "when launchctl returns empty service pid" do
|
156
|
-
let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
|
157
|
-
12761 - 0x100114220.old.machinit.thing
|
158
|
-
- - io.redis.redis-server
|
159
|
-
- - com.lol.stopped-thing
|
160
|
-
SVC_LIST
|
161
|
-
|
162
|
-
before do
|
163
|
-
provider.load_current_resource
|
164
|
-
end
|
150
|
+
before do
|
151
|
+
provider.load_current_resource
|
152
|
+
end
|
165
153
|
|
166
|
-
|
167
|
-
|
168
|
-
|
154
|
+
it "sets resource running state to true" do
|
155
|
+
expect(provider.current_resource.running).to be_truthy
|
156
|
+
end
|
169
157
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
158
|
+
it "sets resouce enabled state to true" do
|
159
|
+
expect(provider.current_resource.enabled).to be_truthy
|
160
|
+
end
|
161
|
+
end
|
174
162
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
163
|
+
describe "running unsupported actions" do
|
164
|
+
before do
|
165
|
+
allow(Dir).to receive(:glob).and_return(["#{plist}"], [])
|
166
|
+
allow(File).to receive(:exists?).and_return([true], [])
|
167
|
+
end
|
168
|
+
it "should throw an exception when reload action is attempted" do
|
169
|
+
expect {provider.run_action(:reload)}.to raise_error(Chef::Exceptions::UnsupportedAction)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
context "when launchctl returns empty service pid" do
|
173
|
+
let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
|
174
|
+
{
|
175
|
+
"LimitLoadToSessionType" = "System";
|
176
|
+
"Label" = "io.redis.redis-server";
|
177
|
+
"TimeOut" = 30;
|
178
|
+
"OnDemand" = false;
|
179
|
+
"LastExitStatus" = 0;
|
180
|
+
"Program" = "do_some.sh";
|
181
|
+
"ProgramArguments" = (
|
182
|
+
"path/to/do_something.sh";
|
183
|
+
"-f";
|
184
|
+
);
|
185
|
+
};
|
186
|
+
SVC_LIST
|
180
187
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
end
|
188
|
+
before do
|
189
|
+
provider.load_current_resource
|
190
|
+
end
|
185
191
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
provider.load_current_resource
|
190
|
-
end
|
192
|
+
it "sets resource running state to false" do
|
193
|
+
expect(provider.current_resource.running).to be_falsey
|
194
|
+
end
|
191
195
|
|
192
|
-
|
193
|
-
|
196
|
+
it "sets resouce enabled state to true" do
|
197
|
+
expect(provider.current_resource.enabled).to be_truthy
|
198
|
+
end
|
194
199
|
end
|
195
|
-
end
|
196
200
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
end
|
201
|
+
context "when launchctl doesn't return service entry at all" do
|
202
|
+
let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
|
203
|
+
Could not find service "io.redis.redis-server" in domain for system
|
204
|
+
SVC_LIST
|
202
205
|
|
203
|
-
|
204
|
-
|
206
|
+
it "sets service running state to false" do
|
207
|
+
provider.load_current_resource
|
208
|
+
expect(provider.current_resource.running).to be_falsey
|
209
|
+
end
|
210
|
+
|
211
|
+
context "and plist for service is not available" do
|
212
|
+
before do
|
213
|
+
allow(Dir).to receive(:glob).and_return([])
|
214
|
+
provider.load_current_resource
|
215
|
+
end
|
216
|
+
|
217
|
+
it "sets resouce enabled state to false" do
|
218
|
+
expect(provider.current_resource.enabled).to be_falsey
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context "and plist for service is available" do
|
223
|
+
before do
|
224
|
+
allow(Dir).to receive(:glob).and_return(["#{plist}"], [])
|
225
|
+
provider.load_current_resource
|
226
|
+
end
|
227
|
+
|
228
|
+
it "sets resouce enabled state to true" do
|
229
|
+
expect(provider.current_resource.enabled).to be_truthy
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "and several plists match service name" do
|
234
|
+
it "throws exception" do
|
235
|
+
allow(Dir).to receive(:glob).and_return(["#{plist}",
|
236
|
+
"/Users/wtf/something.plist"])
|
237
|
+
provider.load_current_resource
|
238
|
+
provider.define_resource_requirements
|
239
|
+
expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
|
240
|
+
end
|
241
|
+
end
|
205
242
|
end
|
206
243
|
end
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
allow(Dir).to receive(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist",
|
211
|
-
"/Users/wtf/something.plist"])
|
244
|
+
describe "#start_service" do
|
245
|
+
before do
|
246
|
+
allow(Chef::Resource::MacosxService).to receive(:new).and_return(current_resource)
|
212
247
|
provider.load_current_resource
|
213
|
-
|
214
|
-
expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
|
248
|
+
allow(current_resource).to receive(:running).and_return(false)
|
215
249
|
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
describe "#start_service" do
|
220
|
-
before do
|
221
|
-
allow(Chef::Resource::Service).to receive(:new).and_return(current_resource)
|
222
|
-
provider.load_current_resource
|
223
|
-
allow(current_resource).to receive(:running).and_return(false)
|
224
|
-
end
|
225
250
|
|
226
|
-
|
227
|
-
|
251
|
+
it "calls the start command if one is specified and service is not running" do
|
252
|
+
allow(new_resource).to receive(:start_command).and_return("cowsay dirty")
|
228
253
|
|
229
|
-
|
230
|
-
|
231
|
-
|
254
|
+
expect(provider).to receive(:shell_out_with_systems_locale!).with("cowsay dirty")
|
255
|
+
provider.start_service
|
256
|
+
end
|
232
257
|
|
233
|
-
|
234
|
-
|
235
|
-
|
258
|
+
it "shows warning message if service is already running" do
|
259
|
+
allow(current_resource).to receive(:running).and_return(true)
|
260
|
+
expect(Chef::Log).to receive(:debug).with("macosx_service[#{service_name}] already running, not starting")
|
236
261
|
|
237
|
-
|
238
|
-
|
262
|
+
provider.start_service
|
263
|
+
end
|
239
264
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
265
|
+
it "starts service via launchctl if service found" do
|
266
|
+
cmd = 'launchctl load -w ' + session + plist
|
267
|
+
expect(provider).to receive(:shell_out_with_systems_locale).
|
268
|
+
with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
|
269
|
+
and_return(0)
|
245
270
|
|
246
|
-
|
247
|
-
|
248
|
-
|
271
|
+
provider.start_service
|
272
|
+
end
|
273
|
+
end
|
249
274
|
|
250
|
-
|
251
|
-
|
252
|
-
|
275
|
+
describe "#stop_service" do
|
276
|
+
before do
|
277
|
+
allow(Chef::Resource::MacosxService).to receive(:new).and_return(current_resource)
|
253
278
|
|
254
|
-
|
255
|
-
|
256
|
-
|
279
|
+
provider.load_current_resource
|
280
|
+
allow(current_resource).to receive(:running).and_return(true)
|
281
|
+
end
|
257
282
|
|
258
|
-
|
259
|
-
|
283
|
+
it "calls the stop command if one is specified and service is running" do
|
284
|
+
allow(new_resource).to receive(:stop_command).and_return("kill -9 123")
|
260
285
|
|
261
|
-
|
262
|
-
|
263
|
-
|
286
|
+
expect(provider).to receive(:shell_out_with_systems_locale!).with("kill -9 123")
|
287
|
+
provider.stop_service
|
288
|
+
end
|
264
289
|
|
265
|
-
|
266
|
-
|
267
|
-
|
290
|
+
it "shows warning message if service is not running" do
|
291
|
+
allow(current_resource).to receive(:running).and_return(false)
|
292
|
+
expect(Chef::Log).to receive(:debug).with("macosx_service[#{service_name}] not running, not stopping")
|
268
293
|
|
269
|
-
|
270
|
-
|
294
|
+
provider.stop_service
|
295
|
+
end
|
271
296
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
297
|
+
it "stops the service via launchctl if service found" do
|
298
|
+
cmd = 'launchctl unload -w '+ plist
|
299
|
+
expect(provider).to receive(:shell_out_with_systems_locale).
|
300
|
+
with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
|
301
|
+
and_return(0)
|
277
302
|
|
278
|
-
|
279
|
-
|
280
|
-
|
303
|
+
provider.stop_service
|
304
|
+
end
|
305
|
+
end
|
281
306
|
|
282
|
-
|
283
|
-
|
284
|
-
|
307
|
+
describe "#restart_service" do
|
308
|
+
before do
|
309
|
+
allow(Chef::Resource::Service).to receive(:new).and_return(current_resource)
|
285
310
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
311
|
+
provider.load_current_resource
|
312
|
+
allow(current_resource).to receive(:running).and_return(true)
|
313
|
+
allow(provider).to receive(:sleep)
|
314
|
+
end
|
290
315
|
|
291
|
-
|
292
|
-
|
316
|
+
it "issues a command if given" do
|
317
|
+
allow(new_resource).to receive(:restart_command).and_return("reload that thing")
|
293
318
|
|
294
|
-
|
295
|
-
|
296
|
-
|
319
|
+
expect(provider).to receive(:shell_out_with_systems_locale!).with("reload that thing")
|
320
|
+
provider.restart_service
|
321
|
+
end
|
297
322
|
|
298
|
-
|
299
|
-
|
300
|
-
|
323
|
+
it "stops and then starts service" do
|
324
|
+
expect(provider).to receive(:unload_service)
|
325
|
+
expect(provider).to receive(:load_service);
|
301
326
|
|
302
|
-
|
327
|
+
provider.restart_service
|
328
|
+
end
|
329
|
+
end
|
303
330
|
end
|
304
331
|
end
|
305
332
|
end
|