kitchen-nodes-lobatoa 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,285 @@
1
+ require 'erb'
2
+ require 'fakefs/safe'
3
+ require 'kitchen'
4
+ require 'kitchen/driver/dummy'
5
+ require 'kitchen/provisioner/nodes'
6
+ require 'kitchen/transport/dummy'
7
+ require 'kitchen/transport/winrm'
8
+ require 'kitchen/transport/ssh'
9
+ require 'winrm'
10
+
11
+ # rubocop:disable Metrics/BlockLength
12
+ describe Kitchen::Provisioner::Nodes do
13
+ let(:config) do
14
+ {
15
+ test_base_path: '/b',
16
+ kitchen_root: '/r',
17
+ run_list: ['recipe[cookbook::default]'],
18
+ attributes: { att_key: 'att_val' },
19
+ client_rb: { environment: 'my_env' },
20
+ reset_node_files: false
21
+ }
22
+ end
23
+ let(:instance) do
24
+ double(
25
+ 'instance',
26
+ name: 'test_suite',
27
+ suite: suite,
28
+ platform: platform,
29
+ transport: transport,
30
+ driver: Kitchen::Driver::Dummy.new
31
+ )
32
+ end
33
+ let(:transport) { Kitchen::Transport::Ssh.new }
34
+ let(:platform) { double('platform', os_type: nil, name: 'ubuntu') }
35
+ let(:suite) { double('suite', name: 'suite') }
36
+ let(:state) { { hostname: '192.168.1.10' } }
37
+ let(:node) { JSON.parse(File.read(subject.node_file), symbolize_names: true) }
38
+
39
+ before do
40
+ FakeFS.activate!
41
+ FileUtils.mkdir_p(config[:test_base_path])
42
+ allow_any_instance_of(Kitchen::StateFile)
43
+ .to receive(:read).and_return(state)
44
+ allow(transport).to receive(:connection)
45
+ .and_return(Kitchen::Transport::Base::Connection.new)
46
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
47
+ .to receive(:node_execute).with('hostname -f')
48
+ .and_return("fakehostname\n\n")
49
+ end
50
+ after do
51
+ FakeFS.deactivate!
52
+ FakeFS::FileSystem.clear
53
+ end
54
+
55
+ subject { Kitchen::Provisioner::Nodes.new(config).finalize_config!(instance) }
56
+
57
+ describe '#create_node' do
58
+ context 'node file does not exist' do
59
+ before do
60
+ allow(Dir).to receive(:exist?).and_return(false)
61
+ end
62
+
63
+ it 'creates node' do
64
+ subject.create_node
65
+
66
+ expect(File).to exist(subject.node_file)
67
+ end
68
+ end
69
+ context 'node file exists' do
70
+ before do
71
+ allow(Dir).to receive(:exist?).and_return(true)
72
+ expect(File).to receive(:exist?).with(subject.node_file).and_return(true)
73
+ end
74
+
75
+ context 'config[:reset_node_files] = false' do
76
+ it 'does not update the node file' do
77
+ expect(File).not_to receive(:open)
78
+
79
+ subject.create_node
80
+ end
81
+ end
82
+
83
+ context 'config[:reset_node_files] = true' do
84
+ before do
85
+ config[:reset_node_files] = true
86
+ end
87
+
88
+ it 'updates the node file' do
89
+ expect(File).to receive(:open)
90
+
91
+ subject.create_node
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ it 'sets the id' do
98
+ subject.create_node
99
+
100
+ expect(node[:id]).to eq instance.name
101
+ end
102
+
103
+ it 'sets the environment' do
104
+ subject.create_node
105
+
106
+ expect(node[:chef_environment]).to eq config[:client_rb][:environment]
107
+ end
108
+
109
+ it 'sets the runlist' do
110
+ subject.create_node
111
+
112
+ expect(node[:run_list]).to eq config[:run_list]
113
+ end
114
+
115
+ it 'expands the runlist' do
116
+ subject.create_node
117
+
118
+ expect(node[:automatic][:recipes]).to eq ['cookbook::default']
119
+ end
120
+
121
+ it 'sets the named_runlist' do
122
+ subject.create_node
123
+
124
+ expect(node[:named_run_list]).to eq config[:named_run_list]
125
+ end
126
+
127
+ it 'sets the normal attributes' do
128
+ subject.create_node
129
+
130
+ expect(node[:normal]).to eq config[:attributes]
131
+ end
132
+
133
+ it 'sets the ip address' do
134
+ subject.create_node
135
+
136
+ expect(node[:automatic][:ipaddress]).to eq state[:hostname]
137
+ end
138
+
139
+ it 'sets the fqdn' do
140
+ subject.create_node
141
+
142
+ expect(node[:automatic][:fqdn]).to eq 'fakehostname'
143
+ end
144
+
145
+ context 'cannot obtain fqdn' do
146
+ before do
147
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
148
+ .to receive(:node_execute).with('hostname -f')
149
+ .and_raise(Kitchen::Transport::TransportFailed.new(''))
150
+ end
151
+
152
+ it 'sets the fqdn to nil' do
153
+ subject.create_node
154
+ expect(node[:automatic][:fqdn]).to be_nil
155
+ end
156
+ end
157
+
158
+ context 'no environment explicitly set' do
159
+ before { config.delete(:client_rb) }
160
+
161
+ it 'sets the environment' do
162
+ subject.create_node
163
+
164
+ expect(node[:chef_environment]).to eq '_default'
165
+ end
166
+ end
167
+
168
+ context 'instance is localhost' do
169
+ let(:state) { { hostname: '127.0.0.1' } }
170
+ let(:machine_ips) { ['192.168.1.1', '192.168.1.2', '192.168.1.3'] }
171
+
172
+ before do
173
+ allow_any_instance_of(Net::Ping::External).to receive(:ping)
174
+ .and_return(true)
175
+ end
176
+
177
+ context 'cannot find an ip' do
178
+ let(:ifconfig_response) do
179
+ FakeFS.deactivate!
180
+ template = File.read('spec/unit/stubs/ifconfig.txt')
181
+ FakeFS.activate!
182
+ template.gsub!('', machine_ips[0])
183
+ template.gsub!('', machine_ips[1])
184
+ template.gsub!('', machine_ips[2])
185
+ end
186
+ let(:transport) { Kitchen::Transport::Ssh.new }
187
+
188
+ before do
189
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
190
+ .to receive(:node_execute).and_return(ifconfig_response)
191
+ end
192
+
193
+ it 'fails' do
194
+ expect { subject.create_node }.to raise_error('Unable to retrieve IPs')
195
+ end
196
+ end
197
+
198
+ context 'platform is windows' do
199
+ let(:transport) { Kitchen::Transport::Winrm.new }
200
+
201
+ before do
202
+ data = WinRM::Output.new
203
+ data << { stdout: "\r\n" }
204
+ machine_ips.map { |ip| data << { stdout: "IPv4 Address .: #{ip}\r\n" } }
205
+ allow_any_instance_of(Kitchen::Transport::Base::Connection).to(
206
+ receive(:node_execute).and_return(data)
207
+ )
208
+ allow(platform).to receive(:name).and_return('windows')
209
+ end
210
+
211
+ it 'sets the ip address to the first reachable IP' do
212
+ subject.create_node
213
+
214
+ expect(node[:automatic][:ipaddress]).to eq machine_ips.first
215
+ end
216
+
217
+ context 'only the last ip is reachable' do
218
+ before do
219
+ allow_any_instance_of(Net::Ping::TCP).to receive(:ping)
220
+ .and_return(false)
221
+ allow_any_instance_of(Net::Ping::External).to receive(:ping)
222
+ .and_return(false)
223
+ allow_any_instance_of(Net::Ping::External).to receive(:ping)
224
+ .with(machine_ips.last).and_return(true)
225
+ end
226
+
227
+ it 'sets the ip address to the last IP' do
228
+ subject.create_node
229
+
230
+ expect(node[:automatic][:ipaddress]).to eq machine_ips.last
231
+ end
232
+ end
233
+ end
234
+
235
+ context 'platform is *nix' do
236
+ let(:ifconfig_response) do
237
+ FakeFS.deactivate!
238
+ template = File.read('spec/unit/stubs/ifconfig.txt')
239
+ FakeFS.activate!
240
+ template.gsub!('1.1.1.1', machine_ips[0])
241
+ template.gsub!('2.2.2.2', machine_ips[1])
242
+ template.gsub!('3.3.3.3', machine_ips[2])
243
+ end
244
+ let(:transport) { Kitchen::Transport::Ssh.new }
245
+
246
+ before do
247
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
248
+ .to receive(:node_execute).and_return(ifconfig_response)
249
+ end
250
+
251
+ it 'sets the ip address to the RUNNING IP that is not localhost' do
252
+ subject.create_node
253
+
254
+ expect(node[:automatic][:ipaddress]).to eq machine_ips[1]
255
+ end
256
+
257
+ context 'ifconfig not supported' do
258
+ let(:ip_response) do
259
+ FakeFS.deactivate!
260
+ template = File.read('spec/unit/stubs/ip.txt')
261
+ FakeFS.activate!
262
+ template.gsub!('1.1.1.1', machine_ips[0])
263
+ template.gsub!('2.2.2.2', machine_ips[1])
264
+ template.gsub!('3.3.3.3', machine_ips[2])
265
+ end
266
+
267
+ before do
268
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
269
+ .to receive(:node_execute).with('/sbin/ifconfig -a')
270
+ .and_raise(Kitchen::Transport::TransportFailed.new(''))
271
+
272
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
273
+ .to receive(:node_execute).with('/sbin/ip -4 addr show')
274
+ .and_return(ip_response)
275
+ end
276
+
277
+ it 'sets the ip address to the connected IP that is not localhost' do
278
+ subject.create_node
279
+
280
+ expect(node[:automatic][:ipaddress]).to eq machine_ips[0]
281
+ end
282
+ end
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,36 @@
1
+ bash: warning: setlocale: LC_ALL: cannot change locale (en_US)
2
+ docker0 Link encap:Ethernet HWaddr 56:84:7a:fe:97:99
3
+ inet addr:1.1.1.1 Bcast:0.0.0.0 Mask:255.255.0.0
4
+ UP BROADCAST MULTICAST MTU:1500 Metric:1
5
+ RX packets:0 errors:0 dropped:0 overruns:0 frame:0
6
+ TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
7
+ collisions:0 txqueuelen:0
8
+ RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
9
+
10
+ eth0 Link encap:Ethernet HWaddr 08:00:27:88:0c:a6
11
+ inet addr:2.2.2.2 Bcast:10.0.2.255 Mask:255.255.255.0
12
+ inet6 addr: fe80::a00:27ff:fe88:ca6/64 Scope:Link
13
+ UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
14
+ RX packets:10262 errors:0 dropped:0 overruns:0 frame:0
15
+ TX packets:7470 errors:0 dropped:0 overruns:0 carrier:0
16
+ collisions:0 txqueuelen:1000
17
+ RX bytes:1497781 (1.4 MB) TX bytes:1701791 (1.7 MB)
18
+
19
+ lo Link encap:Local Loopback
20
+ inet addr:127.0.0.1 Mask:255.0.0.0
21
+ inet6 addr: ::1/128 Scope:Host
22
+ UP LOOPBACK RUNNING MTU:65536 Metric:1
23
+ RX packets:0 errors:0 dropped:0 overruns:0 frame:0
24
+ TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
25
+ collisions:0 txqueuelen:0
26
+ RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
27
+
28
+ # The following represents the format of ifconfig from CentOS 7.1
29
+ enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
30
+ inet 3.3.3.3 netmask 255.255.255.0 broadcast 3.3.3.0
31
+ inet6 fe80::a00:27ff:fe5e:e9b0 prefixlen 64 scopeid 0x20<link>
32
+ ether 08:00:27:5e:e9:b0 txqueuelen 1000 (Ethernet)
33
+ RX packets 7961 bytes 823710 (804.4 KiB)
34
+ RX errors 0 dropped 0 overruns 0 frame 0
35
+ TX packets 263 bytes 50868 (49.6 KiB)
36
+ TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
@@ -0,0 +1,15 @@
1
+ bash: warning: setlocale: LC_ALL: cannot change locale (en_US)
2
+ 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
3
+ inet 127.0.0.1/8 scope host lo
4
+ valid_lft forever preferred_lft forever
5
+ 3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
6
+ inet 1.1.1.1/24 brd 192.168.1.255 scope global wlan0
7
+ valid_lft forever preferred_lft forever
8
+ 5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
9
+ inet 2.2.2.2/16 scope global docker0
10
+ valid_lft forever preferred_lft forever
11
+ # The following represents the format of ipaddr from CentOS 7.1 (which is the same in this case, but
12
+ # adding for completeness)
13
+ 6: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
14
+ inet 3.3.3.3/24 brd 3.3.3.255 scope global dynamic enp0s8
15
+ valid_lft 966sec preferred_lft 966sec
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "test_json_role",
3
+ "chef_type": "role",
4
+ "json_class": "Chef::Role",
5
+ "default_attributes": {
6
+ },
7
+ "run_list": [
8
+ "recipe[hurry-up-and-test::set_non_nat_vbox_ip]"
9
+ ]
10
+ }
@@ -0,0 +1,2 @@
1
+ name('test_ruby_role')
2
+ run_list 'recipe[hurry-up-and-test::set_non_nat_vbox_ip]'
@@ -0,0 +1,18 @@
1
+ require 'timeout'
2
+
3
+ def search_for_nodes(query, timeout = 120)
4
+ nodes = []
5
+ Timeout.timeout(timeout) do
6
+ nodes = search(:node, query)
7
+ until nodes.count > 0 && nodes[0].key?('ipaddress')
8
+ sleep 5
9
+ nodes = search(:node, query)
10
+ end
11
+ end
12
+
13
+ if nodes.count.zero? || !nodes[0].key?('ipaddress')
14
+ raise "Unable to find any nodes meeting the search criteria '#{query}'!"
15
+ end
16
+
17
+ nodes
18
+ end
@@ -0,0 +1,4 @@
1
+ name 'node-tests'
2
+ version '0.1.0'
3
+ maintainer ''
4
+ maintainer_email ''
@@ -0,0 +1,10 @@
1
+ first_node = search_for_nodes(
2
+ "run_list:*node1* AND platform:#{node['platform']}"
3
+ )
4
+
5
+ ruby_block 'Save first attributes' do
6
+ block do
7
+ parent = File.join(ENV['TEMP'] || '/tmp', 'kitchen')
8
+ IO.write(File.join(parent, 'other_node.json'), first_node[0].to_json)
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'winrm' if RUBY_PLATFORM =~ /mingw/
@@ -0,0 +1,69 @@
1
+ require 'serverspec'
2
+ require 'json'
3
+
4
+ if RUBY_PLATFORM =~ /mingw/
5
+ set :backend, :cmd
6
+ set :os, family: 'windows'
7
+ else
8
+ set :backend, :exec
9
+ end
10
+
11
+ describe 'other node' do
12
+ let(:node) do
13
+ JSON.parse(
14
+ IO.read(File.join(ENV['TEMP'] || '/tmp', 'kitchen/other_node.json'))
15
+ )
16
+ end
17
+ let(:ip) { node['automatic']['ipaddress'] }
18
+ let(:fqdn) { node['automatic']['fqdn'] }
19
+ let(:connection) do
20
+ if RUBY_PLATFORM =~ /mingw/
21
+ require 'winrm'
22
+ ::WinRM::Connection.new(
23
+ endpoint: "http://#{ip}:5985/wsman",
24
+ user: 'vagrant',
25
+ password: 'vagrant'
26
+ ).shell(:cmd)
27
+ else
28
+ Net::SSH.start(
29
+ ip,
30
+ 'vagrant',
31
+ password: 'vagrant',
32
+ paranoid: false
33
+ )
34
+ end
35
+ end
36
+
37
+ it 'has an non localhost ip' do
38
+ expect(ip).not_to eq('127.0.0.1')
39
+ end
40
+
41
+ it 'has a valid ip' do
42
+ expect(ip).to match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)
43
+ end
44
+
45
+ # Skip this test on the 2008 box bc its not sysprepped....
46
+ unless ENV['computername'] =~ /VAGRANT\-2008R2/i
47
+ describe command('hostname') do
48
+ its(:stdout) { should_not match(/#{Regexp.quote(fqdn)}/) }
49
+ end
50
+ end
51
+
52
+ if RUBY_PLATFORM =~ /mingw/
53
+ it 'has a computername matching node fqdn' do
54
+ expect(connection.run('hostname').stdout.chomp).to eq(fqdn)
55
+ end
56
+ else
57
+ it 'has a computername matching node fqdn' do
58
+ connection.open_channel do |channel|
59
+ channel.request_pty
60
+ channel.exec('hostname') do |_ch, _success|
61
+ channel.on_data do |_ch, data|
62
+ expect(data.chomp).to eq(fqdn)
63
+ end
64
+ end
65
+ end
66
+ connection.loop
67
+ end
68
+ end
69
+ end