kitchen-nodes-lobatoa 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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