kitchen-nodes 0.2.0.dev.1 → 0.2.0.dev.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 104ed45d9735c996dab66e5d6fe766f89d26de83
4
- data.tar.gz: ee67dc85d6d846ad09d596d836c958c07e0ac272
3
+ metadata.gz: df104b8a9c65cb392ef99bd85e28f14ee62cfdb3
4
+ data.tar.gz: 65a34cfe56147e033cff2a1f26462951ed57a3ac
5
5
  SHA512:
6
- metadata.gz: 69183b471a5fde3866af9c03795cefd17d4b69a165fb8a7352cdae1c52c7a2b90c991f17cf68aaa4c12e6002134cf97e7b4b8685d306ba78bce353b06074ff03
7
- data.tar.gz: bd99980e604067db6be768f536a2dc736f1bb1b24e81d897e5a38f5a12f5db51aa82c4a69188dbf822dcee0e8eab81125aec69ea7ff5777eb7253f7db81d5062
6
+ metadata.gz: f2be4f05d1f32d5b176a5c5249da504df90c14e65e77b1799822ac95f45f83dc623dda05d28ad8a0aae913496f796884e07aaaa1cf55f8532aaf9740420636df
7
+ data.tar.gz: abf853c558c37e6ba34a88562d99835d5bff52f4f6bc6ba1452e0d06debc39c1162a96422bb4f1eda7ddad099b5304dc1b6a2e223abe577a57d724b2bc18e625
@@ -20,7 +20,10 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency 'net-ping'
22
22
  spec.add_dependency 'win32-security'
23
+ spec.add_dependency 'test-kitchen', '1.4.0.rc.1'
23
24
 
24
25
  spec.add_development_dependency 'bundler', '~> 1.3'
26
+ spec.add_development_dependency "fakefs", "~> 0.4"
25
27
  spec.add_development_dependency 'rake'
28
+ spec.add_development_dependency 'rspec', '~> 3.2'
26
29
  end
@@ -0,0 +1,16 @@
1
+ module Kitchen
2
+ module Provisioner
3
+ module IpFinder
4
+
5
+ def self.for_transport(transport, state)
6
+ transport_string = transport.class.name.split('::').last
7
+ require("kitchen/provisioner/ip_finder/#{transport_string.downcase}")
8
+
9
+ connection = transport.connection(state)
10
+ klass = const_get(transport_string)
11
+ object = klass.new(connection)
12
+ object
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,93 @@
1
+ module Kitchen
2
+ module Transport
3
+ class Ssh < Kitchen::Transport::Base
4
+ class Connection < Kitchen::Transport::Base::Connection
5
+ def node_execute(command, &block)
6
+ return if command.nil?
7
+ out, exit_code = node_execute_with_exit_code(command, &block)
8
+
9
+ if exit_code != 0
10
+ raise Transport::SshFailed,
11
+ "SSH exited (#{exit_code}) for command: [#{command}]"
12
+ end
13
+ out
14
+ rescue Net::SSH::Exception => ex
15
+ raise SshFailed, "SSH command failed (#{ex.message})"
16
+ end
17
+
18
+ def node_execute_with_exit_code(command, &block)
19
+ exit_code = nil
20
+ out = []
21
+ session.open_channel do |channel|
22
+
23
+ channel.request_pty
24
+ channel.exec(command) do |_ch, _success|
25
+
26
+ channel.on_data do |_ch, data|
27
+ out << data
28
+ yield data if block_given?
29
+ end
30
+
31
+ channel.on_extended_data do |_ch, _type, data|
32
+ out << data
33
+ yield data if block_given?
34
+ end
35
+
36
+ channel.on_request("exit-status") do |_ch, data|
37
+ exit_code = data.read_long
38
+ end
39
+ end
40
+ end
41
+ session.loop
42
+ [out.join("\n"), exit_code]
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ module Provisioner
49
+ module IpFinder
50
+ class Ssh
51
+ def initialize(connection)
52
+ @connection = connection
53
+ end
54
+
55
+ def find_ips
56
+ run_ifconfig
57
+ rescue Kitchen::Transport::TransportFailed
58
+ run_ip_addr
59
+ end
60
+
61
+ def run_ifconfig
62
+ response = @connection.node_execute("ifconfig -a")
63
+ ips = []
64
+ start_token = "inet addr:"
65
+ response.split(/^\S+/).each do |device|
66
+ if device.include?("RUNNING") && !device.include?("LOOPBACK")
67
+ start_idx = device.index(start_token)
68
+ start_idx += start_token.length unless start_idx.nil?
69
+ end_idx = device.index(" ", start_idx) unless start_idx.nil?
70
+ ips << device[start_idx,end_idx - start_idx] unless end_idx.nil?
71
+ end
72
+ end
73
+ ips
74
+ end
75
+
76
+ def run_ip_addr
77
+ response = @connection.node_execute("ip -4 addr show")
78
+ ips = []
79
+ start_token = "inet "
80
+ response.split(/[0-9]+: /).each do |device|
81
+ unless device.include?("LOOPBACK") || device.include?("NO-CARRIER")
82
+ start_idx = device.index(start_token)
83
+ start_idx += start_token.length unless start_idx.nil?
84
+ end_idx = device.index("/", start_idx) unless start_idx.nil?
85
+ ips << device[start_idx,end_idx - start_idx] unless end_idx.nil?
86
+ end
87
+ end
88
+ ips
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,31 @@
1
+ module Kitchen
2
+ module Transport
3
+ class Winrm < Kitchen::Transport::Base
4
+ class Connection < Kitchen::Transport::Base::Connection
5
+ def node_execute(command, &block)
6
+ session.run_powershell_script(command, &block)
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ module Provisioner
13
+ module IpFinder
14
+ class Winrm
15
+ def initialize(connection)
16
+ @connection = connection
17
+ end
18
+
19
+ def find_ips
20
+ out = @connection.node_execute("Get-NetIPConfiguration | % { $_.ipv4address.IPAddress}")
21
+ data = []
22
+ out[:data].each do |out_data|
23
+ stdout = out_data[:stdout]
24
+ data << stdout.chomp unless stdout.nil?
25
+ end
26
+ data
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -18,20 +18,10 @@
18
18
 
19
19
  require "kitchen"
20
20
  require "kitchen/provisioner/chef_zero"
21
+ require "kitchen/provisioner/ip_finder"
21
22
  require "net/ping"
22
23
 
23
24
  module Kitchen
24
-
25
- module Transport
26
- class Winrm < Kitchen::Transport::Base
27
- class Connection < Kitchen::Transport::Base::Connection
28
- def node_session(retry_options = {})
29
- session(retry_options)
30
- end
31
- end
32
- end
33
- end
34
-
35
25
  module Provisioner
36
26
 
37
27
  # Nodes provisioner for Kitchen.
@@ -45,12 +35,9 @@ module Kitchen
45
35
  end
46
36
 
47
37
  def create_node
48
- node_dir = File.join(config[:test_base_path], "nodes")
49
- Dir.mkdir(node_dir) unless Dir.exist?(node_dir)
50
- node_file = File.join(node_dir, "#{instance.name}.json")
51
-
52
38
  state = Kitchen::StateFile.new(config[:kitchen_root], instance.name).read
53
- ipaddress = get_reachable_guest_address(state) || state[:hostname]
39
+ ip = state[:hostname]
40
+ ipaddress = (ip == "127.0.0.1" || ip == "localhost") ? get_reachable_guest_address(state) : ip
54
41
 
55
42
  node = {
56
43
  :id => instance.name,
@@ -65,14 +52,26 @@ module Kitchen
65
52
  end
66
53
  end
67
54
 
55
+ def node_file
56
+ node_dir = File.join(config[:test_base_path], "nodes")
57
+ Dir.mkdir(node_dir) unless Dir.exist?(node_dir)
58
+ File.join(node_dir, "#{instance.name}.json")
59
+ end
60
+
68
61
  def get_reachable_guest_address(state)
69
- instance.transport.connection(state).node_session.run_powershell_script("Get-NetIPConfiguration | % { $_.ipv4address.IPAddress}") do |address, _|
70
- address = address.chomp unless address.nil?
71
- next if address.nil? || address == "127.0.0.1"
62
+ active_ips(instance.transport, state).each do |address|
63
+ next if address == "127.0.0.1"
72
64
  return address if Net::Ping::External.new.ping(address)
73
65
  end
74
66
  return nil
75
- end
67
+ end
68
+
69
+ def active_ips(transport, state)
70
+ # inject creds into state for legacy drivers
71
+ state[:password] = instance.driver[:password] if instance.driver[:password]
72
+ state[:username] = instance.driver[:username] if instance.driver[:username]
73
+ IpFinder.for_transport(transport, state).find_ips
74
+ end
76
75
  end
77
76
  end
78
77
  end
@@ -21,6 +21,6 @@ module Kitchen
21
21
  module Provisioner
22
22
 
23
23
  # Version string for Nodes Kitchen driver
24
- NODES_VERSION = "0.2.0.dev.1"
24
+ NODES_VERSION = "0.2.0.dev.2"
25
25
  end
26
26
  end
@@ -0,0 +1,176 @@
1
+ require "fakefs/safe"
2
+ require "kitchen"
3
+ require "kitchen/driver/dummy"
4
+ require "kitchen/provisioner/nodes"
5
+ require "kitchen/transport/dummy"
6
+ require "kitchen/transport/winrm"
7
+ require "kitchen/transport/ssh"
8
+
9
+ describe Kitchen::Provisioner::Nodes do
10
+
11
+ let(:config) { {
12
+ :test_base_path => "/b",
13
+ :kitchen_root => "/r",
14
+ :run_list => "cookbook:recipe"
15
+ } }
16
+ let(:instance) { double(
17
+ "instance",
18
+ :name => "test_suite",
19
+ :suite => suite,
20
+ :platform => platform,
21
+ :transport => transport,
22
+ :driver => Kitchen::Driver::Dummy.new
23
+ ) }
24
+ let(:transport) { Kitchen::Transport::Dummy.new }
25
+ let(:platform) { double("platform", :os_type => nil) }
26
+ let(:suite) { double("suite", :name => "suite") }
27
+ let(:state) { { :hostname => "192.168.1.10" } }
28
+ let(:node) { JSON.parse(File.read(subject.node_file), :symbolize_names => true) }
29
+
30
+ before {
31
+ FakeFS.activate!
32
+ FileUtils.mkdir_p(config[:test_base_path])
33
+ allow_any_instance_of(Kitchen::StateFile).to receive(:read).and_return(state)
34
+ }
35
+ after {
36
+ FakeFS.deactivate!
37
+ FakeFS::FileSystem.clear
38
+ }
39
+
40
+ subject { Kitchen::Provisioner::Nodes.new(config).finalize_config!(instance) }
41
+
42
+ it "creates node" do
43
+ subject.create_node
44
+
45
+ expect(File).to exist(subject.node_file)
46
+ end
47
+
48
+ it "sets the id" do
49
+ subject.create_node
50
+
51
+ expect(node[:id]).to eq instance.name
52
+ end
53
+
54
+ it "sets the runlist" do
55
+ subject.create_node
56
+
57
+ expect(node[:run_list]).to eq config[:run_list]
58
+ end
59
+
60
+ it "sets the ip address" do
61
+ subject.create_node
62
+
63
+ expect(node[:automatic][:ipaddress]).to eq state[:hostname]
64
+ end
65
+
66
+ context "instance is localhost" do
67
+ let(:state) { { :hostname => "127.0.0.1" } }
68
+ let(:machine_ips) { [ "192.168.1.1", "192.168.1.2", "192.168.1.3" ] }
69
+
70
+ before {
71
+ allow_any_instance_of(Net::Ping::External).to receive(:ping).and_return(true)
72
+ allow(transport).to receive(:connection).and_return(Kitchen::Transport::Base::Connection.new)
73
+ }
74
+ context "platform is windows" do
75
+ let(:transport) { Kitchen::Transport::Winrm.new }
76
+
77
+ before {
78
+ data = machine_ips.map {|ip| { :stdout => "#{ip}\r\n" }}
79
+ allow_any_instance_of(Kitchen::Transport::Base::Connection).to(
80
+ receive(:node_execute).and_return({ :data => data })
81
+ )
82
+ }
83
+
84
+ it "sets the ip address to the first reachable IP" do
85
+ subject.create_node
86
+
87
+ expect(node[:automatic][:ipaddress]).to eq machine_ips.first
88
+ end
89
+
90
+ context "only the last ip is reachable" do
91
+ before {
92
+ allow_any_instance_of(Net::Ping::External).to receive(:ping).and_return(false)
93
+ allow_any_instance_of(Net::Ping::External).to receive(:ping).with(machine_ips.last).and_return(true)
94
+ }
95
+
96
+ it "sets the ip address to the last IP" do
97
+ subject.create_node
98
+
99
+ expect(node[:automatic][:ipaddress]).to eq machine_ips.last
100
+ end
101
+ end
102
+ end
103
+
104
+ context "platform is *nix" do
105
+ let(:transport) { Kitchen::Transport::Ssh.new }
106
+
107
+ before {
108
+ allow_any_instance_of(Kitchen::Transport::Base::Connection).to receive(:node_execute) do
109
+ <<-EOS
110
+ docker0 Link encap:Ethernet HWaddr 56:84:7a:fe:97:99
111
+ inet addr:#{machine_ips[0]} Bcast:0.0.0.0 Mask:255.255.0.0
112
+ UP BROADCAST MULTICAST MTU:1500 Metric:1
113
+ RX packets:0 errors:0 dropped:0 overruns:0 frame:0
114
+ TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
115
+ collisions:0 txqueuelen:0
116
+ RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
117
+
118
+ eth0 Link encap:Ethernet HWaddr 08:00:27:88:0c:a6
119
+ inet addr:#{machine_ips[1]} Bcast:10.0.2.255 Mask:255.255.255.0
120
+ inet6 addr: fe80::a00:27ff:fe88:ca6/64 Scope:Link
121
+ UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
122
+ RX packets:10262 errors:0 dropped:0 overruns:0 frame:0
123
+ TX packets:7470 errors:0 dropped:0 overruns:0 carrier:0
124
+ collisions:0 txqueuelen:1000
125
+ RX bytes:1497781 (1.4 MB) TX bytes:1701791 (1.7 MB)
126
+
127
+ lo Link encap:Local Loopback
128
+ inet addr:127.0.0.1 Mask:255.0.0.0
129
+ inet6 addr: ::1/128 Scope:Host
130
+ UP LOOPBACK RUNNING MTU:65536 Metric:1
131
+ RX packets:0 errors:0 dropped:0 overruns:0 frame:0
132
+ TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
133
+ collisions:0 txqueuelen:0
134
+ RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
135
+
136
+ EOS
137
+ end
138
+ }
139
+
140
+ it "sets the ip address to the RUNNING IP that is not localhost" do
141
+ subject.create_node
142
+
143
+ expect(node[:automatic][:ipaddress]).to eq machine_ips[1]
144
+ end
145
+
146
+ context "ifconfig not supported" do
147
+ before {
148
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
149
+ .to receive(:node_execute).with("ifconfig -a")
150
+ .and_raise(Kitchen::Transport::TransportFailed.new(""))
151
+
152
+ allow_any_instance_of(Kitchen::Transport::Base::Connection)
153
+ .to receive(:node_execute).with("ip -4 addr show") do
154
+ <<-EOS
155
+ 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
156
+ inet 127.0.0.1/8 scope host lo
157
+ valid_lft forever preferred_lft forever
158
+ 3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
159
+ inet #{machine_ips[0]}/24 brd 192.168.1.255 scope global wlan0
160
+ valid_lft forever preferred_lft forever
161
+ 5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
162
+ inet #{machine_ips[1]}/16 scope global docker0
163
+ valid_lft forever preferred_lft forever
164
+ EOS
165
+ end
166
+ }
167
+
168
+ it "sets the ip address to the connected IP that is not localhost" do
169
+ subject.create_node
170
+
171
+ expect(node[:automatic][:ipaddress]).to eq machine_ips[0]
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-nodes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.dev.1
4
+ version: 0.2.0.dev.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Wrock
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-28 00:00:00.000000000 Z
11
+ date: 2015-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-ping
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-kitchen
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.4.0.rc.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.4.0.rc.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: fakefs
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.4'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.4'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rake
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +94,20 @@ dependencies:
66
94
  - - ">="
67
95
  - !ruby/object:Gem::Version
68
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.2'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.2'
69
111
  description: A Test Kitchen Provisioner for Chef Nodes
70
112
  email:
71
113
  - matt@mattwrock.com
@@ -81,8 +123,12 @@ files:
81
123
  - README.md
82
124
  - Rakefile
83
125
  - kitchen-nodes.gemspec
126
+ - lib/kitchen/provisioner/ip_finder.rb
127
+ - lib/kitchen/provisioner/ip_finder/ssh.rb
128
+ - lib/kitchen/provisioner/ip_finder/winrm.rb
84
129
  - lib/kitchen/provisioner/nodes.rb
85
130
  - lib/kitchen/provisioner/nodes_version.rb
131
+ - spec/unit/nodes_spec.rb
86
132
  homepage: ''
87
133
  licenses:
88
134
  - Apache 2.0
@@ -107,5 +153,6 @@ rubygems_version: 2.4.1
107
153
  signing_key:
108
154
  specification_version: 4
109
155
  summary: A Test Kitchen Provisioner for Chef Nodes
110
- test_files: []
156
+ test_files:
157
+ - spec/unit/nodes_spec.rb
111
158
  has_rdoc: