This repository has been archived by the owner on May 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
kitchen.rb
279 lines (256 loc) · 9.77 KB
/
kitchen.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#
# Copyright 2015-2016, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'halite/helper_base'
module PoiseBoiler
module Helpers
# Helpers for Test Kitchen and .kitchen.yml configuration.
#
# @see PoiseBoiler::Kitchen.kitchen
# @since 1.7.0
class Kitchen < Halite::HelperBase
# Shorthand names for Test Kitchen platforms.
#
# @see #expand_platforms
PLATFORM_ALIASES = {
'windows' => %w{windows-2012r2},
'windows32' => %w{windows-2008sp2},
'ubuntu' => %w{ubuntu-14.04 ubuntu-16.04},
'rhel' => %w{centos},
'centos' => %w{centos-6 centos-7},
'linux' => %w{ubuntu rhel centos},
'unix' => %w{linux}, #, freebsd},
'all' => %w{unix windows},
'any' => %w{ubuntu-16.04}, # For cookbooks that don't actually use platform-specific bits.
}
# Default EC2 subnet ID when not overridden in the environment or config.
DEFAULT_EC2_SUBNET_ID = 'subnet-ca674af7'
# Default EC2 subnet ID for previous-generation instance types.
DEFAULT_EC2_LEGACY_INSTANCES_SUBNET_ID = 'subnet-1ffec232'
# Default EC2 security group when not overridden in the environment or config.
DEFAULT_EC2_SECURITY_GROUP_ID = 'sg-ed1ad892'
def initialize(**options)
# Figure out the directory that contains the kitchen.yml by looking for
# the first entry in the stack that isn't inside poise-boiler.
options[:base] ||= if caller.find {|line| !line.start_with?(File.expand_path('../../..', __FILE__)) } =~ /^(.*?):\d+:in/
File.expand_path('..', $1)
else
# ¯\_(ツ)_/¯ hope for the best.
Dir.pwd
end
super(**options)
end
# Generate YAML text for inclusion in a config file.
#
# @return [String]
def to_yaml
kitchen_config.to_yaml.gsub(/---[ \n]/, '')
end
# The Chef version to use for Test Kitchen or nil for any version.
#
# @return [String, nil]
def chef_version
# SPEC_BLOCK_CI is used to force non-locking behavior inside tests.
@chef_version ||= ENV['CHEF_VERSION'] || if ENV['POISE_MASTER_BUILD']
# We're going to install the latest nightly via Omnitruck later on.
nil
elsif ENV['SPEC_BLOCK_CI'] != 'true'
# If there isn't a specific override, lock TK to use the same version of Chef as the Gemfile.
require 'chef/version'
Chef::VERSION.to_s
end
end
def cookbook_name
options[:cookbook_name] || cookbook.cookbook_name
end
# Make this public for use in {PoiseBoiler::Helpers::Kitchen::Provisioner}.
public :cookbook
private
# Which Test Kitchen driver are we going to use.
#
# @return [String]
def kitchen_driver
@kitchen_driver ||= if options[:driver]
# Manual override.
options[:driver]
elsif File.exist?(File.expand_path('test/docker/docker.key', base))
# Look for the decrypted private key. In CI this is generated by `rake travis`.
'docker'
elsif ENV['CI']
# Don't try to use Vagrant on CI ever.
'dummy'
else
'vagrant'
end
end
# Expand the requested platforms using {PLATFORM_ALIASES}.
#
# @return [Array<String>]
def expand_platforms
# Default platform is linux unless overridden from the helper options.
platforms = Array(options[:platforms] || (ENV['CI'] ? 'linux' : 'all'))
last_platforms = []
# This is probably not the most effcient solution but oh well.
while platforms != last_platforms
last_platforms = platforms
platforms = platforms.map {|p| PLATFORM_ALIASES[p] || p}
platforms.flatten!
platforms.uniq!
end
platforms
end
# Generate a Test Kitchen configuration hash.
#
# @return [Hash]
def kitchen_config
{
'driver' => driver_config,
'transport' => transport_config,
'provisioner' => provisioner_config,
'platforms' => expand_platforms.map {|name| platform_config(name) },
'suites' => [suite_config],
}
end
# Generate a Test Kitchen driver configuration hash.
#
# @return [Hash]
def driver_config
# Default config for all drivers. {#chef_version} returns nil for "any
# version" so use true to prevent reinstall attempts.
config = {'name' => kitchen_driver, 'require_chef_omnibus' => chef_version || true}
case kitchen_driver
when 'docker'
# Docker-specific configuration.
config.update(
# Custom Dockerfile.
'dockerfile' => File.expand_path('../kitchen/Dockerfile.erb', __FILE__),
# No password for securiteeeee.
'password' => nil,
# Our docker settings.
'binary' => (ENV['TRAVIS'] == 'true' ? './' : '') + 'docker',
'socket' => 'tcp://docker.poise.io:443',
'tls_verify' => 'true',
'tls_cacert' => 'test/docker/docker.ca',
'tls_cert' => 'test/docker/docker.pem',
'tls_key' => 'test/docker/docker.key',
)
when 'rackspace'
# Set a default instance size.
config['flavor_id'] = options[:rackspace_flavor] || 'general1-1'
when 'ec2'
config.update(ec2_driver_config)
end
config
end
# Generate a Test Kitchen transport configuration hash.
#
# @return [Hash]
def transport_config
{
# Use the sftp transport from kitchen-sync.
'name' => 'sftp',
# Use the SSH key for this driver.
'ssh_key' => case kitchen_driver
when 'docker'
"#{base}/.kitchen/docker_id_rsa"
when 'ec2'
"#{base}/test/ec2/ssh.key"
else
nil
end,
}
end
# Generate a Test Kitchen provisioner configuration hash.
#
# @return [Hash]
def provisioner_config
{
'log_level' => (ENV['DEBUG'] ? 'debug' : (ENV['CHEF_LOG_LEVEL'] || 'auto')),
# Use the poise_solo provisioner, also part of kitchen-docker.
'name' => 'poise_solo',
'attributes' => {
# Pass through $CI to know if we are on Travis.
'CI' => ENV['CI'],
# Pass through debug/poise_debug settings to the test instance.
'POISE_DEBUG' => !!((ENV['POISE_DEBUG'] && ENV['POISE_DEBUG'] != 'false') ||
(ENV['poise_debug'] && ENV['poise_debug'] != 'false') ||
(ENV['DEBUG'] && ENV['DEBUG'] != 'false')
),
}
}
end
# Generate a Test Kitchen platform configuration hash.
#
# @return [Hash]
def platform_config(name)
{
'name' => name,
# On CI enable poise-profiler automatically. Load it here in case the
# user defines their own suites.
'run_list' => ((ENV['CI'] || ENV['DEBUG'] || ENV['PROFILE']) ? %w{poise-profiler} : []),
}.tap {|cfg| cfg.update(windows_platform_config(name)) if name.include?('windows') }
end
# Generate extra Test Kitchen platform configuration for Windows hosts.
def windows_platform_config(name)
{
'driver' => ec2_driver_config.merge({
'instance_type' => 'm3.medium',
'retryable_tries' => 120,
}),
'provisioner' => {
'product_name' => 'chef',
'channel' => chef_version ? 'stable' : 'current',
'product_version' => chef_version,
},
'transport' => {
'name' => 'winrm',
'ssh_key' => "#{base}/test/ec2/ssh.key",
},
}.tap do |cfg|
if name == 'windows-2008sp2'
cfg['driver']['image_id'] = 'ami-f6a043e0'
cfg['driver']['instance_type'] = 'm1.medium'
cfg['driver']['subnet_id'] = ENV['AWS_SUBNET_ID'] || DEFAULT_EC2_LEGACY_INSTANCES_SUBNET_ID
cfg['provisioner']['architecture'] = 'i386'
end
end
end
# Generate a Test Kitchen suite configuration hash. This is a single suite
# that runs the fixture cookbook if present otherwise the main cookbook.
#
# @return [Hash]
def suite_config
{
'name' => 'default',
'run_list' => (File.exist?(File.join(base, 'test', 'cookbook')) || File.exist?(File.join(base, 'test', 'cookbooks'))) ? ["#{cookbook_name}_test"] : [cookbook_name],
}
end
# Generate a Test Kitchen driver configuration hash with basic settings
# for kitchen-ec2.
#
# @return [Hash]
def ec2_driver_config
{
'name' => 'ec2',
'aws_ssh_key_id' => "#{cookbook_name}-kitchen",
'security_group_ids' => ENV['AWS_SECURITY_GROUP_ID'] ? [ENV['AWS_SECURITY_GROUP_ID']] : [DEFAULT_EC2_SECURITY_GROUP_ID],
'subnet_id' => ENV['AWS_SUBNET_ID'] || DEFAULT_EC2_SUBNET_ID,
# Because kitchen-rackspace also has a thing called flavor_id.
'flavor_id' => nil,
}
end
end
end
end