test-kitchen 1.2.1 → 1.3.0
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.
- checksums.yaml +4 -4
- data/.cane +1 -1
- data/.rubocop.yml +3 -0
- data/.travis.yml +20 -9
- data/CHANGELOG.md +219 -108
- data/Gemfile +10 -6
- data/Guardfile +38 -9
- data/README.md +11 -1
- data/Rakefile +21 -37
- data/bin/kitchen +4 -4
- data/features/kitchen_action_commands.feature +161 -0
- data/features/kitchen_console_command.feature +34 -0
- data/features/kitchen_diagnose_command.feature +64 -0
- data/features/kitchen_init_command.feature +29 -17
- data/features/kitchen_list_command.feature +2 -2
- data/features/kitchen_login_command.feature +56 -0
- data/features/{sink_command.feature → kitchen_sink_command.feature} +0 -0
- data/features/kitchen_test_command.feature +88 -0
- data/features/step_definitions/gem_steps.rb +8 -6
- data/features/step_definitions/git_steps.rb +4 -2
- data/features/step_definitions/output_steps.rb +5 -0
- data/features/support/env.rb +12 -9
- data/lib/kitchen.rb +60 -38
- data/lib/kitchen/base64_stream.rb +55 -0
- data/lib/kitchen/busser.rb +124 -58
- data/lib/kitchen/cli.rb +121 -38
- data/lib/kitchen/collection.rb +3 -3
- data/lib/kitchen/color.rb +4 -4
- data/lib/kitchen/command.rb +78 -11
- data/lib/kitchen/command/action.rb +3 -2
- data/lib/kitchen/command/console.rb +12 -5
- data/lib/kitchen/command/diagnose.rb +17 -3
- data/lib/kitchen/command/driver_discover.rb +26 -7
- data/lib/kitchen/command/exec.rb +41 -0
- data/lib/kitchen/command/list.rb +44 -14
- data/lib/kitchen/command/login.rb +2 -1
- data/lib/kitchen/command/sink.rb +2 -1
- data/lib/kitchen/command/test.rb +5 -4
- data/lib/kitchen/config.rb +146 -14
- data/lib/kitchen/configurable.rb +314 -0
- data/lib/kitchen/data_munger.rb +522 -18
- data/lib/kitchen/diagnostic.rb +43 -4
- data/lib/kitchen/driver.rb +4 -4
- data/lib/kitchen/driver/base.rb +80 -115
- data/lib/kitchen/driver/dummy.rb +34 -6
- data/lib/kitchen/driver/proxy.rb +14 -3
- data/lib/kitchen/driver/ssh_base.rb +61 -7
- data/lib/kitchen/errors.rb +109 -9
- data/lib/kitchen/generator/driver_create.rb +39 -5
- data/lib/kitchen/generator/init.rb +130 -45
- data/lib/kitchen/instance.rb +162 -28
- data/lib/kitchen/lazy_hash.rb +79 -7
- data/lib/kitchen/loader/yaml.rb +159 -27
- data/lib/kitchen/logger.rb +267 -21
- data/lib/kitchen/logging.rb +30 -3
- data/lib/kitchen/login_command.rb +11 -2
- data/lib/kitchen/metadata_chopper.rb +2 -2
- data/lib/kitchen/provisioner.rb +4 -4
- data/lib/kitchen/provisioner/base.rb +107 -103
- data/lib/kitchen/provisioner/chef/berkshelf.rb +36 -8
- data/lib/kitchen/provisioner/chef/librarian.rb +40 -11
- data/lib/kitchen/provisioner/chef_base.rb +206 -167
- data/lib/kitchen/provisioner/chef_solo.rb +25 -7
- data/lib/kitchen/provisioner/chef_zero.rb +105 -29
- data/lib/kitchen/provisioner/dummy.rb +1 -1
- data/lib/kitchen/provisioner/shell.rb +21 -6
- data/lib/kitchen/rake_tasks.rb +8 -3
- data/lib/kitchen/shell_out.rb +15 -18
- data/lib/kitchen/ssh.rb +122 -27
- data/lib/kitchen/state_file.rb +24 -7
- data/lib/kitchen/thor_tasks.rb +9 -4
- data/lib/kitchen/util.rb +43 -118
- data/lib/kitchen/version.rb +1 -1
- data/lib/vendor/hash_recursive_merge.rb +10 -2
- data/spec/kitchen/base64_stream_spec.rb +77 -0
- data/spec/kitchen/busser_spec.rb +490 -0
- data/spec/kitchen/collection_spec.rb +10 -10
- data/spec/kitchen/color_spec.rb +2 -2
- data/spec/kitchen/config_spec.rb +234 -62
- data/spec/kitchen/configurable_spec.rb +490 -0
- data/spec/kitchen/data_munger_spec.rb +1070 -862
- data/spec/kitchen/diagnostic_spec.rb +79 -0
- data/spec/kitchen/driver/base_spec.rb +80 -85
- data/spec/kitchen/driver/dummy_spec.rb +43 -14
- data/spec/kitchen/driver/proxy_spec.rb +134 -0
- data/spec/kitchen/driver/ssh_base_spec.rb +644 -0
- data/spec/kitchen/driver_spec.rb +15 -15
- data/spec/kitchen/errors_spec.rb +309 -0
- data/spec/kitchen/instance_spec.rb +143 -46
- data/spec/kitchen/lazy_hash_spec.rb +36 -9
- data/spec/kitchen/loader/yaml_spec.rb +237 -226
- data/spec/kitchen/logger_spec.rb +419 -0
- data/spec/kitchen/logging_spec.rb +59 -0
- data/spec/kitchen/login_command_spec.rb +49 -0
- data/spec/kitchen/metadata_chopper_spec.rb +82 -0
- data/spec/kitchen/platform_spec.rb +4 -4
- data/spec/kitchen/provisioner/base_spec.rb +65 -125
- data/spec/kitchen/provisioner/chef_base_spec.rb +798 -0
- data/spec/kitchen/provisioner/chef_solo_spec.rb +316 -0
- data/spec/kitchen/provisioner/chef_zero_spec.rb +624 -0
- data/spec/kitchen/provisioner/shell_spec.rb +269 -0
- data/spec/kitchen/provisioner_spec.rb +6 -6
- data/spec/kitchen/shell_out_spec.rb +143 -0
- data/spec/kitchen/ssh_spec.rb +683 -0
- data/spec/kitchen/state_file_spec.rb +28 -21
- data/spec/kitchen/suite_spec.rb +7 -7
- data/spec/kitchen/util_spec.rb +68 -10
- data/spec/kitchen_spec.rb +107 -0
- data/spec/spec_helper.rb +18 -13
- data/support/chef-client-zero.rb +10 -9
- data/support/chef_helpers.sh +16 -0
- data/support/download_helpers.sh +109 -0
- data/test-kitchen.gemspec +42 -33
- metadata +107 -33
@@ -16,8 +16,8 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
require
|
20
|
-
require
|
19
|
+
require "kitchen/errors"
|
20
|
+
require "kitchen/logging"
|
21
21
|
|
22
22
|
module Kitchen
|
23
23
|
|
@@ -26,24 +26,36 @@ module Kitchen
|
|
26
26
|
module Chef
|
27
27
|
|
28
28
|
# Chef cookbook resolver that uses Librarian-Chef and a Cheffile to
|
29
|
-
# calculate
|
29
|
+
# calculate dependencies.
|
30
30
|
#
|
31
31
|
# @author Fletcher Nichol <fnichol@nichol.ca>
|
32
32
|
class Librarian
|
33
33
|
|
34
34
|
include Logging
|
35
35
|
|
36
|
-
|
36
|
+
# Creates a new cookbook resolver.
|
37
|
+
#
|
38
|
+
# @param cheffile [String] path to a Cheffile
|
39
|
+
# @param path [String] path in which to vendor the resulting
|
40
|
+
# cookbooks
|
41
|
+
# @param logger [Kitchen::Logger] a logger to use for output, defaults
|
42
|
+
# to `Kitchen.logger`
|
37
43
|
def initialize(cheffile, path, logger = Kitchen.logger)
|
38
44
|
@cheffile = cheffile
|
39
45
|
@path = path
|
40
46
|
@logger = logger
|
41
47
|
end
|
42
48
|
|
49
|
+
# Loads the library code required to use the resolver.
|
50
|
+
#
|
51
|
+
# @param logger [Kitchen::Logger] a logger to use for output, defaults
|
52
|
+
# to `Kitchen.logger`
|
43
53
|
def self.load!(logger = Kitchen.logger)
|
44
54
|
load_librarian!(logger)
|
45
55
|
end
|
46
56
|
|
57
|
+
# Performs the cookbook resolution and vendors the resulting cookbooks
|
58
|
+
# in the desired path.
|
47
59
|
def resolve
|
48
60
|
version = ::Librarian::Chef::VERSION
|
49
61
|
info("Resolving cookbook dependencies with Librarian-Chef #{version}...")
|
@@ -56,12 +68,29 @@ module Kitchen
|
|
56
68
|
::Librarian::Action::Install.new(env).run
|
57
69
|
end
|
58
70
|
|
59
|
-
|
71
|
+
private
|
72
|
+
|
73
|
+
# @return [String] path to a Cheffile
|
74
|
+
# @api private
|
75
|
+
attr_reader :cheffile
|
76
|
+
|
77
|
+
# @return [String] path in which to vendor the resulting cookbooks
|
78
|
+
# @api private
|
79
|
+
attr_reader :path
|
80
|
+
|
81
|
+
# @return [Kitchen::Logger] a logger to use for output
|
82
|
+
# @api private
|
83
|
+
attr_reader :logger
|
60
84
|
|
85
|
+
# Load the Librarian-specific libary code.
|
86
|
+
#
|
87
|
+
# @param logger [Kitchen::Logger] the logger to use
|
88
|
+
# @raise [UserError] if the library couldn't be loaded
|
89
|
+
# @api private
|
61
90
|
def self.load_librarian!(logger)
|
62
|
-
first_load = require
|
63
|
-
require
|
64
|
-
require
|
91
|
+
first_load = require "librarian/chef/environment"
|
92
|
+
require "librarian/action/resolve"
|
93
|
+
require "librarian/action/install"
|
65
94
|
|
66
95
|
version = ::Librarian::Chef::VERSION
|
67
96
|
if first_load
|
@@ -70,9 +99,9 @@ module Kitchen
|
|
70
99
|
logger.debug("Librarian-Chef #{version} previously loaded")
|
71
100
|
end
|
72
101
|
rescue LoadError => e
|
73
|
-
logger.fatal("The `librarian-chef' gem is missing and must be installed"
|
74
|
-
" or cannot be properly activated. Run"
|
75
|
-
" `gem install librarian-chef` or add the following to your"
|
102
|
+
logger.fatal("The `librarian-chef' gem is missing and must be installed" \
|
103
|
+
" or cannot be properly activated. Run" \
|
104
|
+
" `gem install librarian-chef` or add the following to your" \
|
76
105
|
" Gemfile if you are using Bundler: `gem 'librarian-chef'`.")
|
77
106
|
raise UserError,
|
78
107
|
"Could not load or activate Librarian-Chef (#{e.message})"
|
@@ -16,13 +16,13 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
19
|
+
require "fileutils"
|
20
|
+
require "pathname"
|
21
|
+
require "json"
|
22
22
|
|
23
|
-
require
|
24
|
-
require
|
25
|
-
require
|
23
|
+
require "kitchen/provisioner/chef/berkshelf"
|
24
|
+
require "kitchen/provisioner/chef/librarian"
|
25
|
+
require "kitchen/util"
|
26
26
|
|
27
27
|
module Kitchen
|
28
28
|
|
@@ -34,12 +34,17 @@ module Kitchen
|
|
34
34
|
class ChefBase < Base
|
35
35
|
|
36
36
|
default_config :require_chef_omnibus, true
|
37
|
-
default_config :chef_omnibus_url, "https://www.
|
37
|
+
default_config :chef_omnibus_url, "https://www.chef.io/chef/install.sh"
|
38
|
+
default_config :chef_omnibus_root, "/opt/chef"
|
39
|
+
default_config :chef_omnibus_install_options, nil
|
38
40
|
default_config :run_list, []
|
39
41
|
default_config :attributes, {}
|
40
|
-
default_config :
|
42
|
+
default_config :log_file, nil
|
43
|
+
default_config :cookbook_files_glob, %w[
|
44
|
+
README.* metadata.{json,rb}
|
41
45
|
attributes/**/* definitions/**/* files/**/* libraries/**/*
|
42
|
-
providers/**/* recipes/**/* resources/**/* templates/**/*
|
46
|
+
providers/**/* recipes/**/* resources/**/* templates/**/*
|
47
|
+
].join(",")
|
43
48
|
|
44
49
|
default_config :data_path do |provisioner|
|
45
50
|
provisioner.calculate_path("data")
|
@@ -72,79 +77,117 @@ module Kitchen
|
|
72
77
|
expand_path_for :clients_path
|
73
78
|
|
74
79
|
default_config :encrypted_data_bag_secret_key_path do |provisioner|
|
75
|
-
provisioner.calculate_path("encrypted_data_bag_secret_key", :file)
|
80
|
+
provisioner.calculate_path("encrypted_data_bag_secret_key", :type => :file)
|
76
81
|
end
|
77
82
|
expand_path_for :encrypted_data_bag_secret_key_path
|
78
83
|
|
84
|
+
# (see Base#install_command)
|
79
85
|
def install_command
|
80
86
|
return unless config[:require_chef_omnibus]
|
81
87
|
|
82
|
-
|
83
|
-
|
84
|
-
version = if flag.is_a?(String) && flag != "latest"
|
85
|
-
"-v #{flag.downcase}"
|
86
|
-
else
|
87
|
-
""
|
88
|
-
end
|
89
|
-
|
90
|
-
# use Bourne (/bin/sh) as Bash does not exist on all Unix flavors
|
91
|
-
<<-INSTALL.gsub(/^ {10}/, '')
|
92
|
-
sh -c '
|
93
|
-
#{Util.shell_helpers}
|
94
|
-
|
95
|
-
should_update_chef() {
|
96
|
-
case "#{flag}" in
|
97
|
-
true|`chef-solo -v | cut -d " " -f 2`) return 1 ;;
|
98
|
-
latest|*) return 0 ;;
|
99
|
-
esac
|
100
|
-
}
|
101
|
-
|
102
|
-
if [ ! -d "/opt/chef" ] || should_update_chef ; then
|
103
|
-
echo "-----> Installing Chef Omnibus (#{flag})"
|
104
|
-
do_download #{url} /tmp/install.sh
|
105
|
-
#{sudo('sh')} /tmp/install.sh #{version}
|
106
|
-
fi'
|
107
|
-
INSTALL
|
88
|
+
lines = [Util.shell_helpers, chef_shell_helpers, chef_install_function]
|
89
|
+
Util.wrap_command(lines.join("\n"))
|
108
90
|
end
|
109
91
|
|
92
|
+
# (see Base#init_command)
|
110
93
|
def init_command
|
111
|
-
dirs = %w
|
94
|
+
dirs = %w[cookbooks data data_bags environments roles clients].
|
112
95
|
map { |dir| File.join(config[:root_path], dir) }.join(" ")
|
113
|
-
"#{sudo(
|
96
|
+
lines = ["#{sudo("rm")} -rf #{dirs}", "mkdir -p #{config[:root_path]}"]
|
97
|
+
|
98
|
+
Util.wrap_command(lines.join("\n"))
|
114
99
|
end
|
115
100
|
|
101
|
+
# (see Base#create_sandbox)
|
116
102
|
def create_sandbox
|
117
103
|
super
|
118
104
|
prepare_json
|
119
105
|
prepare_cache
|
120
106
|
prepare_cookbooks
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
107
|
+
prepare(:data)
|
108
|
+
prepare(:data_bags)
|
109
|
+
prepare(:environments)
|
110
|
+
prepare(:nodes)
|
111
|
+
prepare(:roles)
|
112
|
+
prepare(:clients)
|
113
|
+
prepare(
|
114
|
+
:secret,
|
115
|
+
:type => :file,
|
116
|
+
:dest_name => "encrypted_data_bag_secret",
|
117
|
+
:key_name => :encrypted_data_bag_secret_key_path
|
118
|
+
)
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
# Load cookbook dependency resolver code, if required.
|
124
|
+
#
|
125
|
+
# (see Base#load_needed_dependencies!)
|
132
126
|
def load_needed_dependencies!
|
133
|
-
if File.
|
127
|
+
if File.exist?(berksfile)
|
134
128
|
debug("Berksfile found at #{berksfile}, loading Berkshelf")
|
135
129
|
Chef::Berkshelf.load!(logger)
|
136
|
-
elsif File.
|
130
|
+
elsif File.exist?(cheffile)
|
137
131
|
debug("Cheffile found at #{cheffile}, loading Librarian-Chef")
|
138
132
|
Chef::Librarian.load!(logger)
|
139
133
|
end
|
140
134
|
end
|
141
135
|
|
136
|
+
# Returns shell code with chef-related functions.
|
137
|
+
#
|
138
|
+
# @return [String] shell code
|
139
|
+
# @api private
|
140
|
+
def chef_shell_helpers
|
141
|
+
IO.read(File.join(
|
142
|
+
File.dirname(__FILE__), %w[.. .. .. support chef_helpers.sh]
|
143
|
+
))
|
144
|
+
end
|
145
|
+
|
146
|
+
# Generates the shell code to conditionally install a Chef Omnibus
|
147
|
+
# package onto an instance.
|
148
|
+
#
|
149
|
+
# @return [String] shell code
|
150
|
+
# @api private
|
151
|
+
def chef_install_function
|
152
|
+
version = config[:require_chef_omnibus].to_s.downcase
|
153
|
+
pretty_version = case version
|
154
|
+
when "true" then "install only if missing"
|
155
|
+
when "latest" then "always install latest version"
|
156
|
+
else version
|
157
|
+
end
|
158
|
+
install_flags = %w[latest true].include?(version) ? "" : "-v #{version}"
|
159
|
+
if config[:chef_omnibus_install_options]
|
160
|
+
install_flags += config[:chef_omnibus_install_options]
|
161
|
+
end
|
162
|
+
|
163
|
+
<<-INSTALL.gsub(/^ {10}/, "")
|
164
|
+
if should_update_chef "#{config[:chef_omnibus_root]}" "#{version}" ; then
|
165
|
+
echo "-----> Installing Chef Omnibus (#{pretty_version})"
|
166
|
+
do_download #{config[:chef_omnibus_url]} /tmp/install.sh
|
167
|
+
#{sudo("sh")} /tmp/install.sh #{install_flags}
|
168
|
+
else
|
169
|
+
echo "-----> Chef Omnibus installation detected (#{pretty_version})"
|
170
|
+
fi
|
171
|
+
INSTALL
|
172
|
+
end
|
173
|
+
|
174
|
+
# Generates a rendered client.rb/solo.rb/knife.rb formatted file as a
|
175
|
+
# String.
|
176
|
+
#
|
177
|
+
# @param data [Hash] a key/value pair hash of configuration
|
178
|
+
# @return [String] a rendered Chef config file as a String
|
179
|
+
# @api private
|
142
180
|
def format_config_file(data)
|
143
181
|
data.each.map { |attr, value|
|
144
|
-
[attr,
|
182
|
+
[attr, value.inspect].join(" ")
|
145
183
|
}.join("\n")
|
146
184
|
end
|
147
185
|
|
186
|
+
# Generates a Hash with default values for a solo.rb or client.rb Chef
|
187
|
+
# configuration file.
|
188
|
+
#
|
189
|
+
# @return [Hash] a configuration hash
|
190
|
+
# @api private
|
148
191
|
def default_config_rb
|
149
192
|
root = config[:root_path]
|
150
193
|
|
@@ -163,105 +206,78 @@ module Kitchen
|
|
163
206
|
:validation_key => "#{root}/validation.pem",
|
164
207
|
:client_key => "#{root}/client.pem",
|
165
208
|
:chef_server_url => "http://127.0.0.1:8889",
|
166
|
-
:encrypted_data_bag_secret => "#{root}/encrypted_data_bag_secret"
|
209
|
+
:encrypted_data_bag_secret => "#{root}/encrypted_data_bag_secret"
|
167
210
|
}
|
168
211
|
end
|
169
212
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
213
|
+
# Prepares a generic Chef component source directory or file for
|
214
|
+
# inclusion in the sandbox path. These components might includes nodes,
|
215
|
+
# roles, etc.
|
216
|
+
#
|
217
|
+
# @param component [Symbol,String] a component name such as `:node`
|
218
|
+
# @param opts [Hash] optional configuration
|
219
|
+
# @option opts [Symbol] :type whether the component is a directory or
|
220
|
+
# file (default: `:directory`)
|
221
|
+
# @option opts [Symbol] :key_name the key name in the config hash from
|
222
|
+
# which to pull the source path (default: `"#{component}_path"`)
|
223
|
+
# @option opts [String] :dest_name the destination file or directory
|
224
|
+
# basename in the sandbox path (default: `component.to_s`)
|
225
|
+
# @api private
|
226
|
+
def prepare(component, opts = {})
|
227
|
+
opts = { :type => :directory }.merge(opts)
|
228
|
+
key_name = opts.fetch(:key_name, "#{component}_path")
|
229
|
+
src = config[key_name.to_sym]
|
230
|
+
return if src.nil?
|
231
|
+
|
232
|
+
info("Preparing #{component}")
|
233
|
+
debug("Using #{component} from #{src}")
|
234
|
+
|
235
|
+
dest = File.join(sandbox_path, opts.fetch(:dest_name, component.to_s))
|
236
|
+
|
237
|
+
case opts[:type]
|
238
|
+
when :directory
|
239
|
+
FileUtils.mkdir_p(dest)
|
240
|
+
FileUtils.cp_r(Dir.glob("#{src}/*"), dest)
|
241
|
+
when :file
|
242
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
243
|
+
FileUtils.cp_r(src, dest)
|
175
244
|
end
|
176
245
|
end
|
177
246
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
tmpdata_dir = File.join(sandbox_path, "data")
|
185
|
-
FileUtils.mkdir_p(tmpdata_dir)
|
186
|
-
FileUtils.cp_r(Dir.glob("#{data}/*"), tmpdata_dir)
|
187
|
-
end
|
188
|
-
|
189
|
-
def prepare_data_bags
|
190
|
-
return unless data_bags
|
191
|
-
|
192
|
-
info("Preparing data bags")
|
193
|
-
debug("Using data bags from #{data_bags}")
|
194
|
-
|
195
|
-
tmpbags_dir = File.join(sandbox_path, "data_bags")
|
196
|
-
FileUtils.mkdir_p(tmpbags_dir)
|
197
|
-
FileUtils.cp_r(Dir.glob("#{data_bags}/*"), tmpbags_dir)
|
198
|
-
end
|
199
|
-
|
200
|
-
def prepare_roles
|
201
|
-
return unless roles
|
202
|
-
|
203
|
-
info("Preparing roles")
|
204
|
-
debug("Using roles from #{roles}")
|
205
|
-
|
206
|
-
tmproles_dir = File.join(sandbox_path, "roles")
|
207
|
-
FileUtils.mkdir_p(tmproles_dir)
|
208
|
-
FileUtils.cp_r(Dir.glob("#{roles}/*"), tmproles_dir)
|
209
|
-
end
|
210
|
-
|
211
|
-
def prepare_clients
|
212
|
-
return unless clients
|
213
|
-
|
214
|
-
info("Preparing clients")
|
215
|
-
debug("Using roles from #{clients}")
|
216
|
-
|
217
|
-
tmpclients_dir = File.join(sandbox_path, "clients")
|
218
|
-
FileUtils.mkdir_p(tmpclients_dir)
|
219
|
-
FileUtils.cp_r(Dir.glob("#{clients}/*"), tmpclients_dir)
|
220
|
-
end
|
221
|
-
|
222
|
-
def prepare_nodes
|
223
|
-
return unless nodes
|
224
|
-
|
225
|
-
info("Preparing nodes")
|
226
|
-
debug("Using nodes from #{nodes}")
|
227
|
-
|
228
|
-
tmpnodes_dir = File.join(sandbox_path, "nodes")
|
229
|
-
FileUtils.mkdir_p(tmpnodes_dir)
|
230
|
-
FileUtils.cp_r(Dir.glob("#{nodes}/*"), tmpnodes_dir)
|
231
|
-
end
|
232
|
-
|
233
|
-
def prepare_environments
|
234
|
-
return unless environments
|
235
|
-
|
236
|
-
info("Preparing environments")
|
237
|
-
debug("Using environments from #{environments}")
|
238
|
-
|
239
|
-
tmpenvs_dir = File.join(sandbox_path, "environments")
|
240
|
-
FileUtils.mkdir_p(tmpenvs_dir)
|
241
|
-
FileUtils.cp_r(Dir.glob("#{environments}/*"), tmpenvs_dir)
|
242
|
-
end
|
243
|
-
|
244
|
-
def prepare_secret
|
245
|
-
return unless secret
|
247
|
+
# Prepares a Chef JSON file, sometimes called a dna.json or
|
248
|
+
# first-boot.json, for inclusion in the sandbox path.
|
249
|
+
#
|
250
|
+
# @api private
|
251
|
+
def prepare_json
|
252
|
+
dna = config[:attributes].merge(:run_list => config[:run_list])
|
246
253
|
|
247
|
-
info("Preparing
|
248
|
-
debug("
|
254
|
+
info("Preparing dna.json")
|
255
|
+
debug("Creating dna.json from #{dna.inspect}")
|
249
256
|
|
250
|
-
|
257
|
+
File.open(File.join(sandbox_path, "dna.json"), "wb") do |file|
|
258
|
+
file.write(dna.to_json)
|
259
|
+
end
|
251
260
|
end
|
252
261
|
|
262
|
+
# Prepares a cache directory for inclusion in the sandbox path.
|
263
|
+
#
|
264
|
+
# @api private
|
253
265
|
def prepare_cache
|
254
266
|
FileUtils.mkdir_p(File.join(sandbox_path, "cache"))
|
255
267
|
end
|
256
268
|
|
269
|
+
# Prepares Chef cookbooks for inclusion in the sandbox path.
|
270
|
+
#
|
271
|
+
# @api private
|
257
272
|
def prepare_cookbooks
|
258
|
-
if File.
|
273
|
+
if File.exist?(berksfile)
|
259
274
|
resolve_with_berkshelf
|
260
|
-
elsif File.
|
275
|
+
elsif File.exist?(cheffile)
|
261
276
|
resolve_with_librarian
|
277
|
+
cp_site_cookbooks if File.directory?(site_cookbooks_dir)
|
262
278
|
elsif File.directory?(cookbooks_dir)
|
263
279
|
cp_cookbooks
|
264
|
-
elsif File.
|
280
|
+
elsif File.exist?(metadata_rb)
|
265
281
|
cp_this_cookbook
|
266
282
|
else
|
267
283
|
make_fake_cookbook
|
@@ -270,79 +286,86 @@ module Kitchen
|
|
270
286
|
filter_only_cookbook_files
|
271
287
|
end
|
272
288
|
|
289
|
+
# Removes all non-cookbook files in the sandbox path.
|
290
|
+
#
|
291
|
+
# @api private
|
273
292
|
def filter_only_cookbook_files
|
274
293
|
info("Removing non-cookbook files before transfer")
|
275
294
|
FileUtils.rm(all_files_in_cookbooks - only_cookbook_files)
|
276
295
|
end
|
277
296
|
|
297
|
+
# Generates a list of all files in the cookbooks directory in the
|
298
|
+
# sandbox path.
|
299
|
+
#
|
300
|
+
# @return [Array<String>] an array of absolute paths to files
|
301
|
+
# @api private
|
278
302
|
def all_files_in_cookbooks
|
279
303
|
Dir.glob(File.join(tmpbooks_dir, "**/*"), File::FNM_DOTMATCH).
|
280
|
-
select { |fn| File.file?(fn) && ! %w
|
304
|
+
select { |fn| File.file?(fn) && ! %w[. ..].include?(fn) }
|
281
305
|
end
|
282
306
|
|
307
|
+
# Generates a list of all typical cookbook files needed in a Chef run,
|
308
|
+
# located in the cookbooks directory in the sandbox path.
|
309
|
+
#
|
310
|
+
# @return [Array<String>] an array of absolute paths to files
|
311
|
+
# @api private
|
283
312
|
def only_cookbook_files
|
284
313
|
glob = File.join(tmpbooks_dir, "*", "{#{config[:cookbook_files_glob]}}")
|
285
314
|
|
286
315
|
Dir.glob(glob, File::FNM_DOTMATCH).
|
287
|
-
select { |fn| File.file?(fn) && ! %w
|
316
|
+
select { |fn| File.file?(fn) && ! %w[. ..].include?(fn) }
|
288
317
|
end
|
289
318
|
|
319
|
+
# @return [String] an absolute path to a Berksfile, relative to the
|
320
|
+
# kitchen root
|
321
|
+
# @api private
|
290
322
|
def berksfile
|
291
323
|
File.join(config[:kitchen_root], "Berksfile")
|
292
324
|
end
|
293
325
|
|
326
|
+
# @return [String] an absolute path to a Cheffile, relative to the
|
327
|
+
# kitchen root
|
328
|
+
# @api private
|
294
329
|
def cheffile
|
295
330
|
File.join(config[:kitchen_root], "Cheffile")
|
296
331
|
end
|
297
332
|
|
333
|
+
# @return [String] an absolute path to a metadata.rb, relative to the
|
334
|
+
# kitchen root
|
335
|
+
# @api private
|
298
336
|
def metadata_rb
|
299
337
|
File.join(config[:kitchen_root], "metadata.rb")
|
300
338
|
end
|
301
339
|
|
340
|
+
# @return [String] an absolute path to a cookbooks/ directory, relative
|
341
|
+
# to the kitchen root
|
342
|
+
# @api private
|
302
343
|
def cookbooks_dir
|
303
344
|
File.join(config[:kitchen_root], "cookbooks")
|
304
345
|
end
|
305
346
|
|
347
|
+
# @return [String] an absolute path to a site-cookbooks/ directory,
|
348
|
+
# relative to the kitchen root
|
349
|
+
# @api private
|
306
350
|
def site_cookbooks_dir
|
307
351
|
File.join(config[:kitchen_root], "site-cookbooks")
|
308
352
|
end
|
309
353
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
def roles
|
315
|
-
config[:roles_path]
|
316
|
-
end
|
317
|
-
|
318
|
-
def clients
|
319
|
-
config[:clients_path]
|
320
|
-
end
|
321
|
-
|
322
|
-
def nodes
|
323
|
-
config[:nodes_path]
|
324
|
-
end
|
325
|
-
|
326
|
-
def data
|
327
|
-
config[:data_path]
|
328
|
-
end
|
329
|
-
|
330
|
-
def environments
|
331
|
-
config[:environments_path]
|
332
|
-
end
|
333
|
-
|
334
|
-
def secret
|
335
|
-
config[:encrypted_data_bag_secret_key_path]
|
336
|
-
end
|
337
|
-
|
354
|
+
# @return [String] an absolute path to a cookbooks/ directory in the
|
355
|
+
# sandbox path
|
356
|
+
# @api private
|
338
357
|
def tmpbooks_dir
|
339
358
|
File.join(sandbox_path, "cookbooks")
|
340
359
|
end
|
341
360
|
|
361
|
+
# @return [String] an absolute path to a site cookbooks directory in the
|
362
|
+
# sandbox path
|
363
|
+
# @api private
|
342
364
|
def tmpsitebooks_dir
|
343
365
|
File.join(sandbox_path, "cookbooks")
|
344
366
|
end
|
345
367
|
|
368
|
+
# Copies a cookbooks/ directory into the sandbox path.
|
346
369
|
def cp_cookbooks
|
347
370
|
info("Preparing cookbooks from project directory")
|
348
371
|
debug("Using cookbooks from #{cookbooks_dir}")
|
@@ -351,9 +374,12 @@ module Kitchen
|
|
351
374
|
FileUtils.cp_r(File.join(cookbooks_dir, "."), tmpbooks_dir)
|
352
375
|
|
353
376
|
cp_site_cookbooks if File.directory?(site_cookbooks_dir)
|
354
|
-
cp_this_cookbook if File.
|
377
|
+
cp_this_cookbook if File.exist?(metadata_rb)
|
355
378
|
end
|
356
379
|
|
380
|
+
# Copies a site-cookbooks/ directory into the sandbox path.
|
381
|
+
#
|
382
|
+
# @api private
|
357
383
|
def cp_site_cookbooks
|
358
384
|
info("Preparing site-cookbooks from project directory")
|
359
385
|
debug("Using cookbooks from #{site_cookbooks_dir}")
|
@@ -362,12 +388,16 @@ module Kitchen
|
|
362
388
|
FileUtils.cp_r(File.join(site_cookbooks_dir, "."), tmpsitebooks_dir)
|
363
389
|
end
|
364
390
|
|
391
|
+
# Copies the current project, assumed to be a Chef cookbook into the
|
392
|
+
# sandbox path.
|
393
|
+
#
|
394
|
+
# @api private
|
365
395
|
def cp_this_cookbook
|
366
396
|
info("Preparing current project directory as a cookbook")
|
367
397
|
debug("Using metadata.rb from #{metadata_rb}")
|
368
398
|
|
369
|
-
cb_name = MetadataChopper.extract(metadata_rb).first
|
370
|
-
"The metadata.rb does not define the 'name' key."
|
399
|
+
cb_name = MetadataChopper.extract(metadata_rb).first || raise(UserError,
|
400
|
+
"The metadata.rb does not define the 'name' key." \
|
371
401
|
" Please add: `name '<cookbook_name>'` to metadata.rb and retry")
|
372
402
|
|
373
403
|
cb_path = File.join(tmpbooks_dir, cb_name)
|
@@ -378,23 +408,32 @@ module Kitchen
|
|
378
408
|
FileUtils.cp_r(glob, cb_path)
|
379
409
|
end
|
380
410
|
|
411
|
+
# Creates a minimal, no-op cookbook in the sandbox path.
|
412
|
+
#
|
413
|
+
# @api private
|
381
414
|
def make_fake_cookbook
|
382
|
-
info("Berksfile, Cheffile, cookbooks/, or metadata.rb not found "
|
415
|
+
info("Berksfile, Cheffile, cookbooks/, or metadata.rb not found " \
|
383
416
|
"so Chef will run with effectively no cookbooks. Is this intended?")
|
384
417
|
name = File.basename(config[:kitchen_root])
|
385
418
|
fake_cb = File.join(tmpbooks_dir, name)
|
386
419
|
FileUtils.mkdir_p(fake_cb)
|
387
420
|
File.open(File.join(fake_cb, "metadata.rb"), "wb") do |file|
|
388
|
-
file.write(%{name "#{name}\n
|
421
|
+
file.write(%{name "#{name}"\n})
|
389
422
|
end
|
390
423
|
end
|
391
424
|
|
425
|
+
# Performs a Berkshelf cookbook resolution inside a common mutex.
|
426
|
+
#
|
427
|
+
# @api private
|
392
428
|
def resolve_with_berkshelf
|
393
429
|
Kitchen.mutex.synchronize do
|
394
430
|
Chef::Berkshelf.new(berksfile, tmpbooks_dir, logger).resolve
|
395
431
|
end
|
396
432
|
end
|
397
433
|
|
434
|
+
# Performs a Librarin-Chef cookbook resolution inside a common mutex.
|
435
|
+
#
|
436
|
+
# @api private
|
398
437
|
def resolve_with_librarian
|
399
438
|
Kitchen.mutex.synchronize do
|
400
439
|
Chef::Librarian.new(cheffile, tmpbooks_dir, logger).resolve
|