test-kitchen 1.0.0.alpha.7 → 1.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +70 -2
- data/README.md +2 -2
- data/Rakefile +14 -11
- data/lib/kitchen.rb +7 -2
- data/lib/kitchen/busser.rb +19 -7
- data/lib/kitchen/cli.rb +29 -7
- data/lib/kitchen/color.rb +5 -5
- data/lib/kitchen/config.rb +49 -10
- data/lib/kitchen/driver.rb +4 -0
- data/lib/kitchen/driver/base.rb +42 -25
- data/lib/kitchen/driver/ssh_base.rb +45 -139
- data/lib/kitchen/errors.rb +3 -0
- data/lib/kitchen/generator/init.rb +41 -31
- data/lib/kitchen/instance.rb +34 -20
- data/lib/kitchen/login_command.rb +34 -0
- data/lib/kitchen/platform.rb +22 -12
- data/lib/kitchen/provisioner.rb +50 -0
- data/lib/kitchen/provisioner/base.rb +63 -0
- data/lib/kitchen/provisioner/chef_base.rb +290 -0
- data/lib/kitchen/provisioner/chef_solo.rb +69 -0
- data/lib/kitchen/provisioner/chef_zero.rb +92 -0
- data/lib/kitchen/ssh.rb +160 -0
- data/lib/kitchen/suite.rb +53 -33
- data/lib/kitchen/version.rb +1 -1
- data/spec/kitchen/config_spec.rb +40 -8
- data/spec/kitchen/driver/base_spec.rb +123 -0
- data/spec/kitchen/instance_spec.rb +61 -54
- data/spec/kitchen/platform_spec.rb +20 -13
- data/spec/kitchen/suite_spec.rb +34 -28
- data/support/chef-client-zero.rb +59 -0
- data/templates/init/kitchen.yml.erb +4 -4
- data/test-kitchen.gemspec +1 -1
- metadata +55 -90
- data/lib/kitchen/chef_data_uploader.rb +0 -177
@@ -0,0 +1,123 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
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_relative '../../spec_helper'
|
20
|
+
require 'logger'
|
21
|
+
require 'stringio'
|
22
|
+
|
23
|
+
require 'kitchen'
|
24
|
+
|
25
|
+
module Kitchen
|
26
|
+
|
27
|
+
module Driver
|
28
|
+
|
29
|
+
class StaticDefaults < Base
|
30
|
+
|
31
|
+
default_config :beans, "kidney"
|
32
|
+
default_config :tunables, { 'flimflam' => 'positate' }
|
33
|
+
end
|
34
|
+
|
35
|
+
class ComputedDefaults < Base
|
36
|
+
|
37
|
+
default_config :beans, "kidney"
|
38
|
+
default_config :fetch_command, "curl"
|
39
|
+
default_config :beans_url do |driver|
|
40
|
+
"http://gim.me/#{driver[:beans]}"
|
41
|
+
end
|
42
|
+
default_config :command do |driver|
|
43
|
+
"#{driver[:fetch_command]} #{driver[:beans_url]}"
|
44
|
+
end
|
45
|
+
default_config :fetch_url do |driver|
|
46
|
+
"http://gim.me/beans-for/#{driver.instance.name}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe Kitchen::Driver::Base do
|
53
|
+
|
54
|
+
let(:logged_output) { StringIO.new }
|
55
|
+
let(:logger) { Logger.new(logged_output) }
|
56
|
+
let(:config) { Hash.new }
|
57
|
+
let(:state) { Hash.new }
|
58
|
+
|
59
|
+
let(:instance) do
|
60
|
+
stub(:name => "coolbeans", :logger => logger, :to_str => "instance")
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "user config" do
|
64
|
+
|
65
|
+
let(:driver) do
|
66
|
+
d = Kitchen::Driver::Base.new(config)
|
67
|
+
d.instance = instance
|
68
|
+
d
|
69
|
+
end
|
70
|
+
|
71
|
+
it "injects config into driver" do
|
72
|
+
config[:fruit] = %w{apples oranges}
|
73
|
+
config[:cool_enough] = true
|
74
|
+
|
75
|
+
driver[:fruit].must_equal ['apples', 'oranges']
|
76
|
+
driver[:cool_enough].must_equal true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "static default config" do
|
81
|
+
|
82
|
+
let(:driver) do
|
83
|
+
d = Kitchen::Driver::StaticDefaults.new(config)
|
84
|
+
d.instance = instance
|
85
|
+
d
|
86
|
+
end
|
87
|
+
|
88
|
+
it "uses default config" do
|
89
|
+
driver[:beans].must_equal "kidney"
|
90
|
+
driver[:tunables]['flimflam'].must_equal 'positate'
|
91
|
+
end
|
92
|
+
|
93
|
+
it "uses user config over default config" do
|
94
|
+
config[:beans] = "pinto"
|
95
|
+
|
96
|
+
driver[:beans].must_equal "pinto"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "computed default config" do
|
101
|
+
|
102
|
+
let(:driver) do
|
103
|
+
d = Kitchen::Driver::ComputedDefaults.new(config)
|
104
|
+
d.instance = instance
|
105
|
+
d
|
106
|
+
end
|
107
|
+
|
108
|
+
it "uses computed config" do
|
109
|
+
driver[:beans_url].must_equal "http://gim.me/kidney"
|
110
|
+
driver[:command].must_equal "curl http://gim.me/kidney"
|
111
|
+
end
|
112
|
+
|
113
|
+
it "has access to instance object" do
|
114
|
+
driver[:fetch_url].must_equal "http://gim.me/beans-for/coolbeans"
|
115
|
+
end
|
116
|
+
|
117
|
+
it "uses user config over default config" do
|
118
|
+
config[:command] = "echo listentome"
|
119
|
+
|
120
|
+
driver[:command].must_equal "echo listentome"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -98,65 +98,72 @@ describe Kitchen::Instance do
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
describe
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
101
|
+
describe 'Cheflike' do
|
102
|
+
|
103
|
+
describe "#run_list" do
|
104
|
+
|
105
|
+
def combo(suite_list, platform_list)
|
106
|
+
opts[:suite] = Kitchen::Suite.new(
|
107
|
+
:name => 'suite', :run_list => suite_list
|
108
|
+
).extend(Kitchen::Suite::Cheflike)
|
109
|
+
opts[:platform] = Kitchen::Platform.new(
|
110
|
+
:name => 'platform', :run_list => platform_list
|
111
|
+
).extend(Kitchen::Platform::Cheflike)
|
112
|
+
Kitchen::Instance.new(opts).extend(Kitchen::Instance::Cheflike)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "combines the platform then suite run_lists" do
|
116
|
+
combo(%w{s1 s2}, %w{p1 p2}).run_list.must_equal %w{p1 p2 s1 s2}
|
117
|
+
end
|
118
|
+
|
119
|
+
it "uses the suite run_list only when platform run_list is empty" do
|
120
|
+
combo(%w{sa sb}, nil).run_list.must_equal %w{sa sb}
|
121
|
+
end
|
122
|
+
|
123
|
+
it "returns an emtpy Array if both run_lists are empty" do
|
124
|
+
combo([], nil).run_list.must_equal []
|
125
|
+
end
|
123
126
|
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe "#attributes" do
|
127
127
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
128
|
+
describe "#attributes" do
|
129
|
+
|
130
|
+
def combo(suite_attrs, platform_attrs)
|
131
|
+
opts[:suite] = Kitchen::Suite.new(
|
132
|
+
:name => 'suite', :run_list => [], :attributes => suite_attrs
|
133
|
+
).extend(Kitchen::Suite::Cheflike)
|
134
|
+
opts[:platform] = Kitchen::Platform.new(
|
135
|
+
:name => 'platform', :attributes => platform_attrs
|
136
|
+
).extend(Kitchen::Platform::Cheflike)
|
137
|
+
Kitchen::Instance.new(opts).extend(Kitchen::Instance::Cheflike)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "merges suite and platform hashes together" do
|
141
|
+
combo(
|
142
|
+
{ :suite => { :s1 => 'sv1' } },
|
143
|
+
{ :suite => { :p1 => 'pv1' }, :platform => 'pp' }
|
144
|
+
).attributes.must_equal({
|
145
|
+
:suite => { :s1 => 'sv1', :p1 => 'pv1' },
|
146
|
+
:platform => 'pp'
|
147
|
+
})
|
148
|
+
end
|
149
|
+
|
150
|
+
it "merges suite values over platform values" do
|
151
|
+
combo(
|
152
|
+
{ :common => { :c1 => 'xxx' } },
|
153
|
+
{ :common => { :c1 => 'cv1', :c2 => 'cv2' } },
|
154
|
+
).attributes.must_equal({
|
155
|
+
:common => { :c1 => 'xxx', :c2 => 'cv2' }
|
156
|
+
})
|
157
|
+
end
|
136
158
|
end
|
137
159
|
|
138
|
-
it "
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
).attributes.must_equal({
|
143
|
-
:suite => { :s1 => 'sv1', :p1 => 'pv1' },
|
144
|
-
:platform => 'pp'
|
145
|
-
})
|
146
|
-
end
|
160
|
+
it "#dna combines attributes with the run_list" do
|
161
|
+
instance.extend(Kitchen::Instance::Cheflike)
|
162
|
+
instance.platform.extend(Kitchen::Platform::Cheflike)
|
163
|
+
instance.suite.extend(Kitchen::Suite::Cheflike)
|
147
164
|
|
148
|
-
|
149
|
-
|
150
|
-
{ :common => { :c1 => 'xxx' } },
|
151
|
-
{ :common => { :c1 => 'cv1', :c2 => 'cv2' } },
|
152
|
-
).attributes.must_equal({
|
153
|
-
:common => { :c1 => 'xxx', :c2 => 'cv2' }
|
154
|
-
})
|
165
|
+
instance.dna.must_equal({ :s => 'ss', :p => 'pp',
|
166
|
+
:run_list => ['platform_list', 'suite_list'] })
|
155
167
|
end
|
156
168
|
end
|
157
|
-
|
158
|
-
it "#dna combines attributes with the run_list" do
|
159
|
-
instance.dna.must_equal({ :s => 'ss', :p => 'pp',
|
160
|
-
:run_list => ['platform_list', 'suite_list'] })
|
161
|
-
end
|
162
169
|
end
|
@@ -31,18 +31,25 @@ describe Kitchen::Platform do
|
|
31
31
|
proc { Kitchen::Platform.new(opts) }.must_raise Kitchen::ClientError
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
34
|
+
describe 'Cheflike' do
|
35
|
+
|
36
|
+
let(:platform) do
|
37
|
+
Kitchen::Platform.new(opts).extend(Kitchen::Platform::Cheflike)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns an empty Array given no run_list" do
|
41
|
+
platform.run_list.must_equal []
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns an empty Hash given no attributes" do
|
45
|
+
platform.attributes.must_equal Hash.new
|
46
|
+
end
|
47
|
+
|
48
|
+
it "returns attributes from constructor" do
|
49
|
+
opts.merge!({ :run_list => ['a', 'b'], :attributes => { :c => 'd' } })
|
50
|
+
platform.name.must_equal 'plata'
|
51
|
+
platform.run_list.must_equal ['a', 'b']
|
52
|
+
platform.attributes.must_equal({ :c => 'd' })
|
53
|
+
end
|
47
54
|
end
|
48
55
|
end
|
data/spec/kitchen/suite_spec.rb
CHANGED
@@ -31,39 +31,45 @@ describe Kitchen::Suite do
|
|
31
31
|
proc { Kitchen::Suite.new(opts) }.must_raise Kitchen::ClientError
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
opts.delete(:run_list)
|
36
|
-
proc { Kitchen::Suite.new(opts) }.must_raise Kitchen::ClientError
|
37
|
-
end
|
34
|
+
describe 'Cheflike' do
|
38
35
|
|
39
|
-
|
40
|
-
suite.attributes.must_equal Hash.new
|
41
|
-
end
|
36
|
+
let(:suite) { Kitchen::Suite.new(opts).extend(Kitchen::Suite::Cheflike) }
|
42
37
|
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
it "returns an empty Hash given no attributes" do
|
39
|
+
suite.attributes.must_equal Hash.new
|
40
|
+
end
|
46
41
|
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
it "returns an empty Array given no excludes" do
|
43
|
+
suite.excludes.must_equal Array.new
|
44
|
+
end
|
50
45
|
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
it "returns nil given no data_bags_path" do
|
47
|
+
suite.data_bags_path.must_be_nil
|
48
|
+
end
|
54
49
|
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
it "returns nil given no roles_path" do
|
51
|
+
suite.roles_path.must_be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it "returns nil given no nodes_path" do
|
55
|
+
suite.nodes_path.must_be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns nil given no encrypted_data_bag_secret_key_path" do
|
59
|
+
suite.encrypted_data_bag_secret_key_path.must_be_nil
|
60
|
+
end
|
58
61
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
it "returns attributes from constructor" do
|
63
|
+
opts.merge!({ :attributes => { :a => 'b' }, :data_bags_path => 'crazy',
|
64
|
+
:roles_path => 'town', :nodes_path => 'woowoo',
|
65
|
+
:encrypted_data_bag_secret_key_path => 'secret' })
|
66
|
+
suite.name.must_equal 'suitezy'
|
67
|
+
suite.run_list.must_equal ['doowah']
|
68
|
+
suite.attributes.must_equal({ :a => 'b' })
|
69
|
+
suite.data_bags_path.must_equal 'crazy'
|
70
|
+
suite.roles_path.must_equal 'town'
|
71
|
+
suite.nodes_path.must_equal 'woowoo'
|
72
|
+
suite.encrypted_data_bag_secret_key_path.must_equal 'secret'
|
73
|
+
end
|
68
74
|
end
|
69
75
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
#
|
4
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
5
|
+
#
|
6
|
+
# Copyright (C) 2013, Fletcher Nichol
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
|
20
|
+
require 'rubygems'
|
21
|
+
require 'chef'
|
22
|
+
require 'chef/application/client'
|
23
|
+
require 'chef_zero/server'
|
24
|
+
require 'chef_fs/chef_fs_data_store'
|
25
|
+
require 'chef_fs/config'
|
26
|
+
require 'tmpdir'
|
27
|
+
|
28
|
+
client = Chef::Application::Client.new
|
29
|
+
client.reconfigure
|
30
|
+
|
31
|
+
data_store = ChefFS::ChefFSDataStore.new(
|
32
|
+
ChefFS::Config.new(Chef::Config).local_fs
|
33
|
+
)
|
34
|
+
|
35
|
+
server_opts = {
|
36
|
+
:host => "127.0.0.1",
|
37
|
+
:port => 8889,
|
38
|
+
:generate_real_keys => false,
|
39
|
+
:data_store => data_store
|
40
|
+
}
|
41
|
+
|
42
|
+
Chef::Log.info("Starting Chef Zero server in background")
|
43
|
+
server = ChefZero::Server.new(server_opts)
|
44
|
+
server.start_background
|
45
|
+
at_exit do
|
46
|
+
Chef::Log.info("Shutting down Chef Zero server")
|
47
|
+
server.stop
|
48
|
+
end
|
49
|
+
|
50
|
+
Dir.mktmpdir do |tmpdir|
|
51
|
+
File.open(File.join(tmpdir, "validation.pem"), "wb") do |f|
|
52
|
+
f.write(server.gen_key_pair.first)
|
53
|
+
end
|
54
|
+
Chef::Config[:validation_key] = File.join(tmpdir, "validation.pem")
|
55
|
+
Chef::Config[:client_key] = File.join(tmpdir, "client.pem")
|
56
|
+
Chef::Config[:chef_server_url] = server.url
|
57
|
+
client.setup_application
|
58
|
+
client.run_application
|
59
|
+
end
|
@@ -7,19 +7,19 @@ platforms:
|
|
7
7
|
- name: ubuntu-12.04
|
8
8
|
driver_config:
|
9
9
|
box: opscode-ubuntu-12.04
|
10
|
-
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box
|
10
|
+
box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box
|
11
11
|
- name: ubuntu-10.04
|
12
12
|
driver_config:
|
13
13
|
box: opscode-ubuntu-10.04
|
14
|
-
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-10.04_provisionerless.box
|
14
|
+
box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_ubuntu-10.04_provisionerless.box
|
15
15
|
- name: centos-6.4
|
16
16
|
driver_config:
|
17
17
|
box: opscode-centos-6.4
|
18
|
-
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-6.4_provisionerless.box
|
18
|
+
box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_centos-6.4_provisionerless.box
|
19
19
|
- name: centos-5.9
|
20
20
|
driver_config:
|
21
21
|
box: opscode-centos-5.9
|
22
|
-
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-5.9_provisionerless.box
|
22
|
+
box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_centos-5.9_provisionerless.box
|
23
23
|
|
24
24
|
suites:
|
25
25
|
- name: default
|