chef-sugar-ng 4.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/lock.yml +3 -0
- data/.github/reaction.yml +1 -0
- data/.gitignore +26 -0
- data/.kitchen.yml +16 -0
- data/.travis.yml +17 -0
- data/CHANGELOG.md +261 -0
- data/CONTRIBUTING.md +20 -0
- data/Gemfile +2 -0
- data/LICENSE +201 -0
- data/README.md +540 -0
- data/Rakefile +11 -0
- data/chef-sugar-ng.gemspec +33 -0
- data/lib/chef/sugar.rb +51 -0
- data/lib/chef/sugar/architecture.rb +171 -0
- data/lib/chef/sugar/cloud.rb +192 -0
- data/lib/chef/sugar/constraints.rb +108 -0
- data/lib/chef/sugar/constraints_dsl.rb +83 -0
- data/lib/chef/sugar/core_extensions.rb +19 -0
- data/lib/chef/sugar/core_extensions/array.rb +34 -0
- data/lib/chef/sugar/core_extensions/object.rb +27 -0
- data/lib/chef/sugar/core_extensions/string.rb +66 -0
- data/lib/chef/sugar/data_bag.rb +146 -0
- data/lib/chef/sugar/docker.rb +40 -0
- data/lib/chef/sugar/filters.rb +227 -0
- data/lib/chef/sugar/init.rb +62 -0
- data/lib/chef/sugar/ip.rb +48 -0
- data/lib/chef/sugar/kernel.rb +49 -0
- data/lib/chef/sugar/kitchen.rb +40 -0
- data/lib/chef/sugar/node.rb +213 -0
- data/lib/chef/sugar/platform.rb +327 -0
- data/lib/chef/sugar/platform_family.rb +179 -0
- data/lib/chef/sugar/ruby.rb +51 -0
- data/lib/chef/sugar/run_context.rb +41 -0
- data/lib/chef/sugar/shell.rb +147 -0
- data/lib/chef/sugar/vagrant.rb +77 -0
- data/lib/chef/sugar/version.rb +21 -0
- data/lib/chef/sugar/virtualization.rb +151 -0
- data/libraries/chef-sugar.rb +1 -0
- data/metadata.rb +24 -0
- data/recipes/default.rb +20 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/shared_examples.rb +20 -0
- data/spec/unit/chef/sugar/architecture_spec.rb +129 -0
- data/spec/unit/chef/sugar/cloud_spec.rb +149 -0
- data/spec/unit/chef/sugar/constraints_spec.rb +45 -0
- data/spec/unit/chef/sugar/core_extensions/array_spec.rb +10 -0
- data/spec/unit/chef/sugar/core_extensions/object_spec.rb +62 -0
- data/spec/unit/chef/sugar/core_extensions/string_spec.rb +48 -0
- data/spec/unit/chef/sugar/data_bag_spec.rb +118 -0
- data/spec/unit/chef/sugar/docker_spec.rb +39 -0
- data/spec/unit/chef/sugar/init_spec.rb +74 -0
- data/spec/unit/chef/sugar/ip_spec.rb +53 -0
- data/spec/unit/chef/sugar/kernel_spec.rb +16 -0
- data/spec/unit/chef/sugar/kitchen_spec.rb +18 -0
- data/spec/unit/chef/sugar/node_spec.rb +172 -0
- data/spec/unit/chef/sugar/platform_family_spec.rb +166 -0
- data/spec/unit/chef/sugar/platform_spec.rb +342 -0
- data/spec/unit/chef/sugar/ruby_spec.rb +39 -0
- data/spec/unit/chef/sugar/run_context_spec.rb +19 -0
- data/spec/unit/chef/sugar/shell_spec.rb +104 -0
- data/spec/unit/chef/sugar/vagrant_spec.rb +37 -0
- data/spec/unit/chef/sugar/virtualization_spec.rb +135 -0
- data/spec/unit/recipes/default_spec.rb +9 -0
- metadata +202 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chef::Sugar::Constraints do
|
4
|
+
describe '#version' do
|
5
|
+
let(:version) { described_class.version('1.2.3') }
|
6
|
+
|
7
|
+
it 'returns a new version object' do
|
8
|
+
expect(version).to be_a(Chef::Sugar::Constraints::Version)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'behaves like a String' do
|
12
|
+
expect(version).to be_a(String)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns true with the version is satisifed' do
|
16
|
+
expect(version).to be_satisfies('~> 1.2.0')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns false when the version is not satisfed' do
|
20
|
+
expect(version).to_not be_satisfies('~> 2.0.0')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#constraint' do
|
25
|
+
let(:constraint) { described_class.constraint('~> 1.2.0') }
|
26
|
+
|
27
|
+
it 'returns a new constraint object' do
|
28
|
+
expect(constraint).to be_a(Chef::Sugar::Constraints::Constraint)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns true when the constraint is satisfied' do
|
32
|
+
expect(constraint).to be_satisfied_by('1.2.3')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns false when the constraint is not satisfied' do
|
36
|
+
expect(constraint).to_not be_satisfied_by('2.0.0')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#chef_version' do
|
41
|
+
it 'is a DSL method' do
|
42
|
+
expect(Chef::Sugar::DSL).to be_method_defined(:chef_version)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chef/sugar/core_extensions'
|
3
|
+
|
4
|
+
describe Object do
|
5
|
+
describe '#blank?' do
|
6
|
+
it 'includes the method' do
|
7
|
+
expect(described_class).to be_method_defined(:blank?)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'returns true for nil' do
|
11
|
+
expect(nil).to be_blank
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns true for false' do
|
15
|
+
expect(false).to be_blank
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns true for the empty string' do
|
19
|
+
expect('').to be_blank
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns true for the empty array' do
|
23
|
+
expect([]).to be_blank
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'returns true for the empty hash' do
|
27
|
+
expect({}).to be_blank
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns false for a non-empty string' do
|
31
|
+
expect(' ').to_not be_blank
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'returns false for a non-empty string with unicode' do
|
35
|
+
expect("\u00a0").to_not be_blank
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns false for a non-empty string with special characters' do
|
39
|
+
expect("\n\t").to_not be_blank
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns false for any object' do
|
43
|
+
expect(Object.new).to_not be_blank
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns false for true' do
|
47
|
+
expect(true).to_not be_blank
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns false for a fixnum' do
|
51
|
+
expect(1).to_not be_blank
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns false for an array with items' do
|
55
|
+
expect(['foo']).to_not be_blank
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns false for an array with items' do
|
59
|
+
expect({'foo' => 'bar'}).to_not be_blank
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chef/sugar/core_extensions'
|
3
|
+
|
4
|
+
describe String do
|
5
|
+
describe '#satisfies?' do
|
6
|
+
it 'includes the method' do
|
7
|
+
expect(described_class).to be_method_defined(:satisfies?)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#satisfied_by?' do
|
12
|
+
it 'includes the method' do
|
13
|
+
expect(described_class).to be_method_defined(:satisfied_by?)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#flush' do
|
18
|
+
context 'when given a single-line string' do
|
19
|
+
it 'strips trailing whitespace' do
|
20
|
+
string = <<-EOH
|
21
|
+
This is a string
|
22
|
+
EOH
|
23
|
+
expect(string.flush).to eq('This is a string')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when given a multi-line string' do
|
28
|
+
it 'removes the leading number of whitespaces' do
|
29
|
+
string = <<-EOH
|
30
|
+
def method
|
31
|
+
"This is a string!"
|
32
|
+
end
|
33
|
+
EOH
|
34
|
+
expect(string.flush).to eq(%Q(def method\n "This is a string!"\nend))
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'leaves a newline when given' do
|
38
|
+
string = <<-EOH
|
39
|
+
def method
|
40
|
+
"This is a string!"
|
41
|
+
end
|
42
|
+
|
43
|
+
EOH
|
44
|
+
expect(string.flush).to eq(%Q(def method\n "This is a string!"\nend\n))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chef::Sugar::DataBag do
|
4
|
+
describe '#encrypted_data_bag_item' do
|
5
|
+
before { allow(Chef::EncryptedDataBagItem).to receive(:load) }
|
6
|
+
|
7
|
+
it 'loads the encrypted data bag item' do
|
8
|
+
expect(Chef::EncryptedDataBagItem).to receive(:load)
|
9
|
+
.with('accounts', 'github', 'secret_key')
|
10
|
+
|
11
|
+
described_class.encrypted_data_bag_item('accounts', 'github', 'secret_key')
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when Chef::Config is set' do
|
15
|
+
it 'loads the secret key from the Chef::Config' do
|
16
|
+
allow(Chef::Config).to receive(:[]).with(:encrypted_data_bag_secret).and_return('/data/path')
|
17
|
+
allow(File).to receive(:read).with('/data/path').and_return('B@c0n')
|
18
|
+
|
19
|
+
expect(Chef::EncryptedDataBagItem).to receive(:load)
|
20
|
+
.with('accounts', 'github', 'B@c0n')
|
21
|
+
|
22
|
+
described_class.encrypted_data_bag_item('accounts', 'github')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when Chef::Config is not set and no value is given' do
|
27
|
+
it 'raises an exception' do
|
28
|
+
expect {
|
29
|
+
described_class.encrypted_data_bag_item('accounts', 'github')
|
30
|
+
}.to raise_error(Chef::Sugar::DataBag::EncryptedDataBagSecretNotGiven)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#encrypted_data_bag_item_for_environment' do
|
36
|
+
let(:node) { double(:node, chef_environment: 'production') }
|
37
|
+
|
38
|
+
context 'when the environment exists' do
|
39
|
+
it 'loads the data from the environment' do
|
40
|
+
allow(Chef::EncryptedDataBagItem).to receive(:load).and_return(
|
41
|
+
'production' => {
|
42
|
+
'username' => 'sethvargo',
|
43
|
+
'password' => 'bacon',
|
44
|
+
}
|
45
|
+
)
|
46
|
+
|
47
|
+
expect(described_class.encrypted_data_bag_item_for_environment(node, 'accounts', 'github', 'secret_key')).to eq(
|
48
|
+
'password' => 'bacon',
|
49
|
+
'username' => 'sethvargo',
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when the environment does not exist' do
|
55
|
+
it 'loads the data from the default bucket' do
|
56
|
+
allow(Chef::EncryptedDataBagItem).to receive(:load).and_return(
|
57
|
+
'staging' => {
|
58
|
+
'username' => 'sethvargo',
|
59
|
+
'password' => 'bacon',
|
60
|
+
},
|
61
|
+
'default' => {
|
62
|
+
'username' => 'schisamo',
|
63
|
+
'password' => 'ham',
|
64
|
+
}
|
65
|
+
)
|
66
|
+
|
67
|
+
expect(described_class.encrypted_data_bag_item_for_environment(node, 'accounts', 'github', 'secret_key')).to eq(
|
68
|
+
'password' => 'ham',
|
69
|
+
'username' => 'schisamo',
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#data_bag_item_for_environment' do
|
76
|
+
let(:node) { double(:node, chef_environment: 'production') }
|
77
|
+
|
78
|
+
context 'when the environment exists' do
|
79
|
+
it 'loads the data from the environment' do
|
80
|
+
allow(Chef::DataBagItem).to receive(:load).and_return(
|
81
|
+
'production' => {
|
82
|
+
'username' => 'sethvargo',
|
83
|
+
'comment' => 'loves bacon',
|
84
|
+
},
|
85
|
+
'default' => {
|
86
|
+
'username' => 'schisamo',
|
87
|
+
'comment' => 'more of a ham guy',
|
88
|
+
}
|
89
|
+
)
|
90
|
+
|
91
|
+
expect(described_class.data_bag_item_for_environment(node, 'accounts', 'github')).to eq(
|
92
|
+
'comment' => 'loves bacon',
|
93
|
+
'username' => 'sethvargo',
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'when the environment does not exist' do
|
99
|
+
it 'loads the data from the default bucket' do
|
100
|
+
allow(Chef::DataBagItem).to receive(:load).and_return(
|
101
|
+
'staging' => {
|
102
|
+
'username' => 'sethvargo',
|
103
|
+
'comment' => 'loves bacon',
|
104
|
+
},
|
105
|
+
'default' => {
|
106
|
+
'username' => 'schisamo',
|
107
|
+
'comment' => 'more of a ham guy',
|
108
|
+
}
|
109
|
+
)
|
110
|
+
|
111
|
+
expect(described_class.data_bag_item_for_environment(node, 'accounts', 'github')).to eq(
|
112
|
+
'comment' => 'more of a ham guy',
|
113
|
+
'username' => 'schisamo',
|
114
|
+
)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chef::Sugar::Docker do
|
4
|
+
it_behaves_like 'a chef sugar'
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
allow(File).to receive(:exist?)
|
8
|
+
.with("/.dockerenv")
|
9
|
+
.and_return(false)
|
10
|
+
allow(File).to receive(:exist?)
|
11
|
+
.with("/.dockerinit")
|
12
|
+
.and_return(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#docker?' do
|
16
|
+
it 'is true when the file /.dockerenv is present' do
|
17
|
+
allow(File).to receive(:exist?)
|
18
|
+
.with("/.dockerenv")
|
19
|
+
.and_return(true)
|
20
|
+
|
21
|
+
node = { 'docker' => nil }
|
22
|
+
expect(described_class.docker?(node)).to be true
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'is true when the file /.dockerinit is present' do
|
26
|
+
allow(File).to receive(:exist?)
|
27
|
+
.with("/.dockerinit")
|
28
|
+
.and_return(true)
|
29
|
+
|
30
|
+
node = { 'docker' => nil }
|
31
|
+
expect(described_class.docker?(node)).to be true
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'is false when the node is not on cloud' do
|
35
|
+
node = { 'docker' => nil }
|
36
|
+
expect(described_class.docker?(node)).to be false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chef::Sugar::Init do
|
4
|
+
it_behaves_like 'a chef sugar'
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
allow(IO).to receive(:read)
|
8
|
+
.with("/proc/1/comm")
|
9
|
+
.and_return("init")
|
10
|
+
allow(File).to receive(:executable?)
|
11
|
+
.with("/sbin/initctl")
|
12
|
+
.and_return(false)
|
13
|
+
allow(File).to receive(:executable?)
|
14
|
+
.with("/sbin/runit-init")
|
15
|
+
.and_return(false)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#systemd?' do
|
19
|
+
it 'is true when /proc/1/comm is systemd' do
|
20
|
+
allow(IO).to receive(:read)
|
21
|
+
.with("/proc/1/comm")
|
22
|
+
.and_return("systemd")
|
23
|
+
|
24
|
+
node = {}
|
25
|
+
expect(described_class.systemd?(node)).to be true
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'is false when /proc/1/comm is not systemd' do
|
29
|
+
node = {}
|
30
|
+
expect(described_class.systemd?(node)).to be false
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'is false when /proc/1/comm does not exist' do
|
34
|
+
allow(File).to receive(:exist?)
|
35
|
+
.with("/proc/1/comm")
|
36
|
+
.and_return(false)
|
37
|
+
|
38
|
+
node = {}
|
39
|
+
expect(described_class.systemd?(node)).to be false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#upstart?' do
|
44
|
+
it 'is true when /sbin/initctl is executable' do
|
45
|
+
allow(File).to receive(:executable?)
|
46
|
+
.with("/sbin/initctl")
|
47
|
+
.and_return(true)
|
48
|
+
|
49
|
+
node = {}
|
50
|
+
expect(described_class.upstart?(node)).to be true
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'is false when /sbin/initctl is not executable' do
|
54
|
+
node = {}
|
55
|
+
expect(described_class.upstart?(node)).to be false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#runit?' do
|
60
|
+
it 'is true when /sbin/runit-init is executable' do
|
61
|
+
allow(File).to receive(:executable?)
|
62
|
+
.with("/sbin/runit-init")
|
63
|
+
.and_return(true)
|
64
|
+
|
65
|
+
node = {}
|
66
|
+
expect(described_class.runit?(node)).to be true
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'is false when /sbin/runit-init is not executable' do
|
70
|
+
node = {}
|
71
|
+
expect(described_class.runit?(node)).to be false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chef::Sugar::IP do
|
4
|
+
it_behaves_like 'a chef sugar'
|
5
|
+
|
6
|
+
let(:node) { { 'ipaddress' => '1.2.3.4' } }
|
7
|
+
let(:other) { { 'ipaddress' => '5.6.7.8' } }
|
8
|
+
|
9
|
+
context 'when not on a cloud' do
|
10
|
+
it 'returns the default IP address' do
|
11
|
+
expect(described_class.best_ip_for(node, other)).to eq(other['ipaddress'])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when the target is on the cloud' do
|
16
|
+
before do
|
17
|
+
other['cloud'] = {}
|
18
|
+
other['cloud']['provider'] = 'ec2'
|
19
|
+
other['cloud']['local_ipv4'] = '9.10.11.12'
|
20
|
+
other['cloud']['public_ipv4'] = '13.14.15.16'
|
21
|
+
|
22
|
+
node['cloud'] = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when the current node is not on the cloud' do
|
26
|
+
it 'uses the public ipv4' do
|
27
|
+
expect(described_class.best_ip_for(node, other)).to eq('13.14.15.16')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when the current node is on a different cloud' do
|
32
|
+
before do
|
33
|
+
node['cloud'] = {}
|
34
|
+
node['cloud']['provider'] = 'rackspace'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'uses the public ipv4' do
|
38
|
+
expect(described_class.best_ip_for(node, other)).to eq('13.14.15.16')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when the current node is on the same cloud' do
|
43
|
+
before do
|
44
|
+
node['cloud'] = {}
|
45
|
+
node['cloud']['provider'] = 'ec2'
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'uses the local ipv4' do
|
49
|
+
expect(described_class.best_ip_for(node, other)).to eq('9.10.11.12')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|