kitchen-nodes-fqdn 0.4.1

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,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