kitchen-nodes-fqdn 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d0f9f88c511094a729079500e92c7d9dfe693977
4
+ data.tar.gz: 6d1f9c7880fceb77c8ac872b727f9edd6e65a7be
5
+ SHA512:
6
+ metadata.gz: e5d82650f62fad201c711b1d858487428ef1861c493d41b1002918799192c850ea1c662c469dd55cc48161e8d54eaa7f4d0c8a0a42bbb3811105fc5f53a58399
7
+ data.tar.gz: 2c12c15d84dbbbfa19db155f09f605278e758cc7cfa1f40ac9f3bc73769ea21baf56251de0c723417f0b7712402fa8542c53e36333514f2a085c177dda3dc745
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,2 @@
1
+ Metrics/MethodLength:
2
+ Max: 20
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.0.0
5
+ - 1.9.3
6
+ - 1.9.2
7
+ - ruby-head
8
+
9
+ matrix:
10
+ allow_failures:
11
+ - rvm: ruby-head
@@ -0,0 +1,3 @@
1
+ ## 0.1.0 / Unreleased
2
+
3
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Author:: Matt Wrock (<matt@mattwrock.com>)
2
+
3
+ Copyright (C) 2015, Matt Wrock
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
@@ -0,0 +1,142 @@
1
+ # <a name="title"></a> Kitchen::Nodes
2
+
3
+ A Test Kitchen Provisioner that generates searchable Nodes.
4
+
5
+ The nodes provisioner extends the `chef-zero` provisioner along with all of its functionality and configuration. `chef-zero` can support chef searches by querying against node data stored in json files inside of the kitchen `nodes` folder. The `kitchen-nodes` plugin automatically generates a node file when a test instance is provisioned by test-kitchen.
6
+
7
+ ### Example nodes:
8
+
9
+ ```
10
+ {
11
+ "id": "server-community-ubuntu-1204",
12
+ "automatic": {
13
+ "ipaddress": "172.17.0.8",
14
+ "platform": "ubuntu"
15
+ },
16
+ "normal": {
17
+ "attr1": "val1"
18
+ }
19
+ "run_list": [
20
+ "recipe[apt]",
21
+ "recipe[couchbase-tests::ipaddress]",
22
+ "recipe[couchbase::server]",
23
+ "recipe[export-node]"
24
+ ]
25
+ }
26
+
27
+ {
28
+ "id": "second-node-ubuntu-1204",
29
+ "automatic": {
30
+ "ipaddress": "172.17.0.9",
31
+ "platform": "ubuntu"
32
+ },
33
+ "run_list": [
34
+ "recipe[apt]",
35
+ "recipe[couchbase-tests::ipaddress]",
36
+ "recipe[couchbase-tests::default]",
37
+ "recipe[export-node]"
38
+ ]
39
+ }
40
+ ```
41
+
42
+ The node data includes the node id based on the test-kitchen suite name, the run list assigned to the node, the normal attributes included in the `.kitchen.yml` file, the externally reachable ip address and the platform of the test instance os.
43
+
44
+ ## <a name="installation"></a> Installation
45
+
46
+ ```
47
+ gem install kitchen-nodes
48
+ ```
49
+
50
+ ## <a name="config"></a> Configuration
51
+
52
+ Use `nodes` instead of `chef-zero` for the kitchen provisioner name.
53
+
54
+ ```
55
+ provisioner:
56
+ name: nodes
57
+ ```
58
+
59
+ ## <a name="Usage"></a> Usage
60
+
61
+ Using `kitchen-nodes` one can expect all previously converged nodes to be represented in a node file and be searchable. For example consider this scenario looking for a primary node in a cluster in order to add a node to join:
62
+
63
+ ```
64
+ require 'timeout'
65
+
66
+ def search_for_nodes(query, timeout = 120)
67
+ nodes = []
68
+ Timeout::timeout(timeout) do
69
+ nodes = search(:node, query)
70
+ until nodes.count > 0 && nodes[0].has_key?('ipaddress')
71
+ sleep 5
72
+ nodes = search(:node, query)
73
+ end
74
+ end
75
+
76
+ if nodes.count == 0 || !nodes[0].has_key?('ipaddress')
77
+ raise "Unable to find nodes!"
78
+ end
79
+
80
+ nodes
81
+ end
82
+
83
+ primary = search_for_nodes("run_list:*couchbase??server* AND platform:#{node['platform']}")
84
+ node.normal["couchbase-tests"]["primary_ip"] = primary[0]['ipaddress']
85
+
86
+ ```
87
+ ### <a name="vagrant"></a> Using with Vagrant
88
+
89
+ When using kitchen-nodes with the vagrant driver, make sure you add the following to your `driver_config`:
90
+
91
+ ```
92
+ network:
93
+ - ["private_network", { type: "dhcp" }]
94
+ ```
95
+
96
+ This will add an additional non-NAT NIC to your vagrant box with an IP reachable from the host and other test nodes.
97
+
98
+ ### <a name="virtualbox"></a> Why is my ohai `ipaddress` different from my node ipaddress on vagrant with VirtualBox?
99
+
100
+ Ohai will pick up the localhost ipaddress on vagrant boxes using virtualbox. To reset the `node["ipaddress"]` to the reachable ip, add `hurry-up-and-test::set_non_nat_vbox_ip` to the top of your `run_list`.
101
+
102
+ ```
103
+ suites:
104
+ - name: my-suite
105
+ run_list:
106
+ - recipe[hurry-up-and-test::set_non_nat_vbox_ip]
107
+ - recipe[cookbook-under-test]
108
+ ```
109
+
110
+ You can add this even if you do not use virtualbox and the recipe will do nothing.
111
+
112
+
113
+ ## <a name="development"></a> Development
114
+
115
+ * Source hosted at [GitHub][repo]
116
+ * Report issues/questions/feature requests on [GitHub Issues][issues]
117
+
118
+ Pull requests are very welcome! Make sure your patches are well tested.
119
+ Ideally create a topic branch for every separate change you make. For
120
+ example:
121
+
122
+ 1. Fork the repo
123
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
124
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
125
+ 4. Push to the branch (`git push origin my-new-feature`)
126
+ 5. Create new Pull Request
127
+
128
+ ## <a name="authors"></a> Authors
129
+
130
+ Created and maintained by [Matt Wrock][author] (<matt@mattwrock.com>)
131
+
132
+ ## <a name="license"></a> License
133
+
134
+ Apache 2.0 (see [LICENSE][license])
135
+
136
+
137
+ [author]: https://github.com/mwrock
138
+ [issues]: https://github.com/mwrock/kitchen-nodes/issues
139
+ [license]: https://github.com/mwrock/kitchen-nodes/blob/master/LICENSE
140
+ [repo]: https://github.com/mwrock/kitchen-nodes
141
+ [driver_usage]: http://docs.kitchen-ci.org/drivers/usage
142
+ [chef_omnibus_dl]: http://www.getchef.com/chef/install/
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:test)
6
+
7
+ RuboCop::RakeTask.new(:style) do |task|
8
+ task.options << '--display-cop-names'
9
+ end
10
+
11
+ task default: [:test, :style]
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kitchen/provisioner/nodes_version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'kitchen-nodes-fqdn'
8
+ spec.version = Kitchen::Provisioner::NODES_VERSION
9
+ spec.authors = ['Matt Wrock', 'Marcin Cabaj']
10
+ spec.email = ['matt@mattwrock.com', 'mcabaj@gmail.com']
11
+ spec.description = 'A Test Kitchen Provisioner for Chef Nodes'
12
+ spec.summary = spec.description
13
+ spec.homepage = ''
14
+ spec.license = 'Apache 2.0'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = []
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'net-ping'
22
+ spec.add_dependency 'win32-security'
23
+ spec.add_dependency 'test-kitchen', '~> 1.4'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.3'
26
+ spec.add_development_dependency 'fakefs', '~> 0.4'
27
+ spec.add_development_dependency 'rake'
28
+ spec.add_development_dependency 'rspec', '~> 3.2'
29
+ spec.add_development_dependency 'rubocop', '~> 0.29'
30
+ end
@@ -0,0 +1,18 @@
1
+ module Kitchen
2
+ module Provisioner
3
+ # Locates active IPs that are not localhost
4
+ # there are separate implementations for
5
+ # different kitchen transports
6
+ module IpFinder
7
+ def self.for_transport(transport, state)
8
+ transport_string = transport.class.name.split('::').last
9
+ require("kitchen/provisioner/ip_finder/#{transport_string.downcase}")
10
+
11
+ connection = transport.connection(state)
12
+ klass = const_get(transport_string)
13
+ object = klass.new(connection)
14
+ object
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,97 @@
1
+ module Kitchen
2
+ module Transport
3
+ class Ssh < Kitchen::Transport::Base
4
+ # Monkey patch of test-kitchen ssh transport
5
+ # that returns stdout
6
+ class Connection < Kitchen::Transport::Base::Connection
7
+ def node_execute(command, &block)
8
+ return if command.nil?
9
+ out, exit_code = node_execute_with_exit_code(command, &block)
10
+
11
+ if exit_code != 0
12
+ fail Transport::SshFailed,
13
+ "SSH exited (#{exit_code}) for command: [#{command}]"
14
+ end
15
+ out
16
+ rescue Net::SSH::Exception => ex
17
+ raise SshFailed, "SSH command failed (#{ex.message})"
18
+ end
19
+
20
+ # rubocop:disable Metrics/AbcSize
21
+ def node_execute_with_exit_code(command)
22
+ exit_code = nil
23
+ out = []
24
+ session.open_channel do |channel|
25
+ channel.request_pty
26
+ channel.exec(command) do |_ch, _success|
27
+ channel.on_data do |_ch, data|
28
+ out << data
29
+ yield data if block_given?
30
+ end
31
+
32
+ channel.on_extended_data do |_ch, _type, data|
33
+ out << data
34
+ yield data if block_given?
35
+ end
36
+
37
+ channel.on_request('exit-status') do |_ch, data|
38
+ exit_code = data.read_long
39
+ end
40
+ end
41
+ end
42
+ session.loop
43
+ [out.join("\n"), exit_code]
44
+ end
45
+ # rubocop:enable Metrics/AbcSize
46
+ end
47
+ end
48
+ end
49
+
50
+ module Provisioner
51
+ module IpFinder
52
+ # SSH implementation for returning active non-localhost IPs
53
+ class Ssh
54
+ IP4REGEX = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
55
+ def initialize(connection)
56
+ @connection = connection
57
+ end
58
+
59
+ def find_ips
60
+ ips = []
61
+ (0..5).each do
62
+ begin
63
+ ips = run_ifconfig
64
+ rescue Kitchen::Transport::TransportFailed
65
+ ips = run_ip_addr
66
+ end
67
+ return ips unless ips.empty?
68
+ sleep 0.5
69
+ end
70
+ ips
71
+ end
72
+
73
+ def run_ifconfig
74
+ response = @connection.node_execute('/sbin/ifconfig -a')
75
+ ips = []
76
+ response.split(/^\S+/).each do |device|
77
+ next if !device.include?('RUNNING') || device.include?('LOOPBACK')
78
+ ips << IP4REGEX.match(device)[1]
79
+ end
80
+ ips.compact
81
+ end
82
+
83
+ def run_ip_addr
84
+ response = @connection.node_execute('/sbin/ip -4 addr show')
85
+ ips = []
86
+ response.split(/^[0-9]+: /).each do |device|
87
+ next if device.include?('LOOPBACK') || device.include?('NO-CARRIER')
88
+ next if device == ''
89
+ found_ips = IP4REGEX.match(device)
90
+ ips << IP4REGEX.match(device)[1] unless found_ips.nil?
91
+ end
92
+ ips.compact
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,35 @@
1
+ module Kitchen
2
+ module Transport
3
+ class Winrm < Kitchen::Transport::Base
4
+ # Monkey patch of test-kitchen winrm transport
5
+ # that returns stdout
6
+ class Connection < Kitchen::Transport::Base::Connection
7
+ def node_execute(command, &block)
8
+ session.run_powershell_script(command, &block)
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ module Provisioner
15
+ module IpFinder
16
+ # WinRM implementation for returning active non-localhost IPs
17
+ class Winrm
18
+ def initialize(connection)
19
+ @connection = connection
20
+ end
21
+
22
+ def find_ips
23
+ out = @connection.node_execute(
24
+ 'Get-NetIPConfiguration | % { $_.ipv4address.IPAddress }')
25
+ data = []
26
+ out[:data].each do |out_data|
27
+ stdout = out_data[:stdout]
28
+ data << stdout.chomp unless stdout.nil?
29
+ end
30
+ data
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,110 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Matt Wrock (<matt@mattwrock.com>)
4
+ #
5
+ # Copyright (C) 2015, Matt Wrock
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the 'License');
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an 'AS IS' BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'kitchen'
20
+ require 'kitchen/provisioner/chef_zero'
21
+ require 'kitchen/provisioner/ip_finder'
22
+ require 'net/ping'
23
+
24
+ module Kitchen
25
+ module Provisioner
26
+ # Nodes provisioner for Kitchen.
27
+ #
28
+ # @author Matt Wrock <matt@mattwrock.com>
29
+ class Nodes < ChefZero
30
+ def create_sandbox
31
+ FileUtils.rm(node_file) if File.exist?(node_file)
32
+ create_node
33
+ super
34
+ end
35
+
36
+ def create_node
37
+ FileUtils.mkdir_p(node_dir) unless Dir.exist?(node_dir)
38
+ template_to_write = node_template
39
+ File.open(node_file, 'w') do |out|
40
+ out << JSON.pretty_generate(template_to_write)
41
+ end
42
+ end
43
+
44
+ def ipaddress
45
+ state = Kitchen::StateFile.new(
46
+ config[:kitchen_root],
47
+ instance.name
48
+ ).read
49
+
50
+ if %w(127.0.0.1 localhost).include?(state[:hostname])
51
+ return get_reachable_guest_address(state)
52
+ end
53
+ state[:hostname]
54
+ end
55
+
56
+ def chef_environment
57
+ env = '_default'
58
+ if config[:client_rb] && config[:client_rb][:environment]
59
+ env = config[:client_rb][:environment]
60
+ end
61
+ env
62
+ end
63
+
64
+ def node_template
65
+ state = Kitchen::StateFile.new(
66
+ config[:kitchen_root],
67
+ instance.name
68
+ ).read
69
+ state[:username] = instance.driver[:username]
70
+ state[:password] = instance.driver[:password]
71
+ {
72
+ id: instance.name,
73
+ chef_environment: chef_environment,
74
+ automatic: {
75
+ ipaddress: ipaddress,
76
+ platform: instance.platform.name.split('-')[0].downcase,
77
+ fqdn: instance.transport.connection(state).node_execute('hostname -f')[/(\w|\.)+/]
78
+ },
79
+ normal: config[:attributes],
80
+ run_list: config[:run_list]
81
+ }
82
+ end
83
+
84
+ def node_dir
85
+ File.join(config[:test_base_path], 'nodes')
86
+ end
87
+
88
+ def node_file
89
+ File.join(node_dir, "#{instance.name}.json")
90
+ end
91
+
92
+ def get_reachable_guest_address(state)
93
+ active_ips(instance.transport, state).each do |address|
94
+ next if address == '127.0.0.1'
95
+ return address if Net::Ping::External.new.ping(address)
96
+ end
97
+ end
98
+
99
+ def active_ips(transport, state)
100
+ # inject creds into state for legacy drivers
101
+ [:username, :password].each do |prop|
102
+ state[prop] = instance.driver[prop] if instance.driver[prop]
103
+ end
104
+ ips = IpFinder.for_transport(transport, state).find_ips
105
+ fail 'Unable to retrieve IPs' if ips.empty?
106
+ ips
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Matt Wrock (<matt@mattwrock.com>)
4
+ #
5
+ # Copyright (C) 2015, Matt Wrock
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ module Kitchen
20
+ # Version string for Nodes Kitchen driver
21
+ module Provisioner
22
+ NODES_VERSION = '0.4.1'
23
+ end
24
+ end
@@ -0,0 +1,210 @@
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
+
10
+ describe Kitchen::Provisioner::Nodes do
11
+ let(:config) do
12
+ {
13
+ test_base_path: '/b',
14
+ kitchen_root: '/r',
15
+ run_list: 'cookbook:recipe',
16
+ attributes: { att_key: 'att_val' },
17
+ client_rb: { environment: 'my_env' }
18
+ }
19
+ end
20
+ let(:instance) do
21
+ double(
22
+ 'instance',
23
+ name: 'test_suite',
24
+ suite: suite,
25
+ platform: platform,
26
+ transport: transport,
27
+ driver: Kitchen::Driver::Dummy.new
28
+ )
29
+ end
30
+ let(:transport) { Kitchen::Transport::Dummy.new }
31
+ let(:platform) { double('platform', os_type: nil, name: 'ubuntu') }
32
+ let(:suite) { double('suite', name: 'suite') }
33
+ let(:state) { { hostname: '192.168.1.10' } }
34
+ let(:node) { JSON.parse(File.read(subject.node_file), symbolize_names: true) }
35
+
36
+ before do
37
+ FakeFS.activate!
38
+ FileUtils.mkdir_p(config[:test_base_path])
39
+ allow_any_instance_of(Kitchen::StateFile)
40
+ .to receive(:read).and_return(state)
41
+ end
42
+ after do
43
+ FakeFS.deactivate!
44
+ FakeFS::FileSystem.clear
45
+ end
46
+
47
+ subject { Kitchen::Provisioner::Nodes.new(config).finalize_config!(instance) }
48
+
49
+ it 'creates node' do
50
+ subject.create_node
51
+
52
+ expect(File).to exist(subject.node_file)
53
+ end
54
+
55
+ it 'sets the id' do
56
+ subject.create_node
57
+
58
+ expect(node[:id]).to eq instance.name
59
+ end
60
+
61
+ it 'sets the environment' do
62
+ subject.create_node
63
+
64
+ expect(node[:chef_environment]).to eq config[:client_rb][:environment]
65
+ end
66
+
67
+ it 'sets the runlist' do
68
+ subject.create_node
69
+
70
+ expect(node[:run_list]).to eq config[:run_list]
71
+ end
72
+
73
+ it 'sets the normal attributes' do
74
+ subject.create_node
75
+
76
+ expect(node[:normal]).to eq config[:attributes]
77
+ end
78
+
79
+ it 'sets the ip address' do
80
+ subject.create_node
81
+
82
+ expect(node[:automatic][:ipaddress]).to eq state[:hostname]
83
+ end
84
+
85
+ context 'no environment explicitly set' do
86
+ before { config.delete(:client_rb) }
87
+
88
+ it 'sets the environment' do
89
+ subject.create_node
90
+
91
+ expect(node[:chef_environment]).to eq '_default'
92
+ end
93
+ end
94
+
95
+ context 'instance is localhost' do
96
+ let(:state) { { hostname: '127.0.0.1' } }
97
+ let(:machine_ips) { ['192.168.1.1', '192.168.1.2', '192.168.1.3'] }
98
+
99
+ before do
100
+ allow_any_instance_of(Net::Ping::External).to receive(:ping)
101
+ .and_return(true)
102
+ allow(transport).to receive(:connection)
103
+ .and_return(Kitchen::Transport::Base::Connection.new)
104
+ end
105
+
106
+ context 'cannot find an ip' do
107
+ let(:ifconfig_response) do
108
+ FakeFS.deactivate!
109
+ template = File.read('spec/unit/stubs/ifconfig.txt')
110
+ FakeFS.activate!
111
+ template.gsub!('', machine_ips[0])
112
+ template.gsub!('', machine_ips[1])
113
+ template.gsub!('', machine_ips[2])
114
+ end
115
+ let(:transport) { Kitchen::Transport::Ssh.new }
116
+
117
+ before do
118
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
119
+ .to receive(:node_execute).and_return(ifconfig_response)
120
+ end
121
+
122
+ it 'fails' do
123
+ expect { subject.create_node }.to raise_error('Unable to retrieve IPs')
124
+ end
125
+ end
126
+
127
+ context 'platform is windows' do
128
+ let(:transport) { Kitchen::Transport::Winrm.new }
129
+
130
+ before do
131
+ data = machine_ips.map { |ip| { stdout: "#{ip}\r\n" } }
132
+ allow_any_instance_of(Kitchen::Transport::Base::Connection).to(
133
+ receive(:node_execute).and_return(data: data)
134
+ )
135
+ allow(platform).to receive(:name).and_return('windows')
136
+ end
137
+
138
+ it 'sets the ip address to the first reachable IP' do
139
+ subject.create_node
140
+
141
+ expect(node[:automatic][:ipaddress]).to eq machine_ips.first
142
+ end
143
+
144
+ context 'only the last ip is reachable' do
145
+ before do
146
+ allow_any_instance_of(Net::Ping::External).to receive(:ping)
147
+ .and_return(false)
148
+ allow_any_instance_of(Net::Ping::External).to receive(:ping)
149
+ .with(machine_ips.last).and_return(true)
150
+ end
151
+
152
+ it 'sets the ip address to the last IP' do
153
+ subject.create_node
154
+
155
+ expect(node[:automatic][:ipaddress]).to eq machine_ips.last
156
+ end
157
+ end
158
+ end
159
+
160
+ context 'platform is *nix' do
161
+ let(:ifconfig_response) do
162
+ FakeFS.deactivate!
163
+ template = File.read('spec/unit/stubs/ifconfig.txt')
164
+ FakeFS.activate!
165
+ template.gsub!('1.1.1.1', machine_ips[0])
166
+ template.gsub!('2.2.2.2', machine_ips[1])
167
+ template.gsub!('3.3.3.3', machine_ips[2])
168
+ end
169
+ let(:transport) { Kitchen::Transport::Ssh.new }
170
+
171
+ before do
172
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
173
+ .to receive(:node_execute).and_return(ifconfig_response)
174
+ end
175
+
176
+ it 'sets the ip address to the RUNNING IP that is not localhost' do
177
+ subject.create_node
178
+
179
+ expect(node[:automatic][:ipaddress]).to eq machine_ips[1]
180
+ end
181
+
182
+ context 'ifconfig not supported' do
183
+ let(:ip_response) do
184
+ FakeFS.deactivate!
185
+ template = File.read('spec/unit/stubs/ip.txt')
186
+ FakeFS.activate!
187
+ template.gsub!('1.1.1.1', machine_ips[0])
188
+ template.gsub!('2.2.2.2', machine_ips[1])
189
+ template.gsub!('3.3.3.3', machine_ips[2])
190
+ end
191
+
192
+ before do
193
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
194
+ .to receive(:node_execute).with('/sbin/ifconfig -a')
195
+ .and_raise(Kitchen::Transport::TransportFailed.new(''))
196
+
197
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
198
+ .to receive(:node_execute).with('/sbin/ip -4 addr show')
199
+ .and_return(ip_response)
200
+ end
201
+
202
+ it 'sets the ip address to the connected IP that is not localhost' do
203
+ subject.create_node
204
+
205
+ expect(node[:automatic][:ipaddress]).to eq machine_ips[0]
206
+ end
207
+ end
208
+ end
209
+ end
210
+ 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
metadata ADDED
@@ -0,0 +1,178 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kitchen-nodes-fqdn
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
5
+ platform: ruby
6
+ authors:
7
+ - Matt Wrock
8
+ - Marcin Cabaj
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-09-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: net-ping
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: win32-security
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: test-kitchen
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.4'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.4'
56
+ - !ruby/object:Gem::Dependency
57
+ name: bundler
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '1.3'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.3'
70
+ - !ruby/object:Gem::Dependency
71
+ name: fakefs
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '0.4'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '0.4'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rake
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rspec
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '3.2'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '3.2'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rubocop
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '0.29'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '0.29'
126
+ description: A Test Kitchen Provisioner for Chef Nodes
127
+ email:
128
+ - matt@mattwrock.com
129
+ - mcabaj@gmail.com
130
+ executables: []
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - ".gitignore"
135
+ - ".rubocop.yml"
136
+ - ".travis.yml"
137
+ - CHANGELOG.md
138
+ - Gemfile
139
+ - LICENSE
140
+ - README.md
141
+ - Rakefile
142
+ - kitchen-nodes.gemspec
143
+ - lib/kitchen/provisioner/ip_finder.rb
144
+ - lib/kitchen/provisioner/ip_finder/ssh.rb
145
+ - lib/kitchen/provisioner/ip_finder/winrm.rb
146
+ - lib/kitchen/provisioner/nodes.rb
147
+ - lib/kitchen/provisioner/nodes_version.rb
148
+ - spec/unit/nodes_spec.rb
149
+ - spec/unit/stubs/ifconfig.txt
150
+ - spec/unit/stubs/ip.txt
151
+ homepage: ''
152
+ licenses:
153
+ - Apache 2.0
154
+ metadata: {}
155
+ post_install_message:
156
+ rdoc_options: []
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ requirements: []
170
+ rubyforge_project:
171
+ rubygems_version: 2.4.5.1
172
+ signing_key:
173
+ specification_version: 4
174
+ summary: A Test Kitchen Provisioner for Chef Nodes
175
+ test_files:
176
+ - spec/unit/nodes_spec.rb
177
+ - spec/unit/stubs/ifconfig.txt
178
+ - spec/unit/stubs/ip.txt