test-kitchen 1.3.1 → 1.4.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.cane +2 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +45 -0
- data/Rakefile +15 -0
- data/features/kitchen_action_commands.feature +12 -9
- data/features/kitchen_defaults.feature +38 -0
- data/features/kitchen_init_command.feature +0 -1
- data/features/kitchen_list_command.feature +2 -2
- data/features/kitchen_login_command.feature +7 -1
- data/features/kitchen_test_command.feature +4 -4
- data/lib/kitchen.rb +40 -11
- data/lib/kitchen/cli.rb +38 -22
- data/lib/kitchen/command/list.rb +5 -2
- data/lib/kitchen/config.rb +45 -18
- data/lib/kitchen/configurable.rb +137 -1
- data/lib/kitchen/data_munger.rb +248 -17
- data/lib/kitchen/driver.rb +1 -1
- data/lib/kitchen/driver/base.rb +1 -83
- data/lib/kitchen/driver/dummy.rb +0 -5
- data/lib/kitchen/driver/ssh_base.rb +177 -22
- data/lib/kitchen/instance.rb +140 -20
- data/lib/kitchen/logger.rb +43 -8
- data/lib/kitchen/login_command.rb +14 -5
- data/lib/kitchen/platform.rb +19 -0
- data/lib/kitchen/provisioner.rb +5 -3
- data/lib/kitchen/provisioner/base.rb +46 -48
- data/lib/kitchen/provisioner/chef/common_sandbox.rb +322 -0
- data/lib/kitchen/provisioner/chef_base.rb +179 -286
- data/lib/kitchen/provisioner/chef_solo.rb +11 -5
- data/lib/kitchen/provisioner/chef_zero.rb +108 -94
- data/lib/kitchen/provisioner/dummy.rb +47 -0
- data/lib/kitchen/provisioner/shell.rb +45 -12
- data/lib/kitchen/rake_tasks.rb +1 -1
- data/lib/kitchen/ssh.rb +1 -1
- data/lib/kitchen/thor_tasks.rb +1 -1
- data/lib/kitchen/transport.rb +54 -0
- data/lib/kitchen/transport/base.rb +146 -0
- data/lib/kitchen/transport/dummy.rb +75 -0
- data/lib/kitchen/transport/ssh.rb +325 -0
- data/lib/kitchen/transport/winrm.rb +508 -0
- data/lib/kitchen/transport/winrm/command_executor.rb +188 -0
- data/lib/kitchen/transport/winrm/file_transporter.rb +454 -0
- data/lib/kitchen/transport/winrm/logging.rb +50 -0
- data/lib/kitchen/transport/winrm/template.rb +74 -0
- data/lib/kitchen/transport/winrm/tmp_zip.rb +187 -0
- data/lib/kitchen/verifier.rb +55 -0
- data/lib/kitchen/verifier/base.rb +191 -0
- data/lib/kitchen/verifier/busser.rb +266 -0
- data/lib/kitchen/verifier/dummy.rb +75 -0
- data/lib/kitchen/version.rb +1 -1
- data/spec/kitchen/cli_spec.rb +56 -0
- data/spec/kitchen/config_spec.rb +61 -20
- data/spec/kitchen/configurable_spec.rb +327 -1
- data/spec/kitchen/data_munger_spec.rb +777 -14
- data/spec/kitchen/driver/base_spec.rb +7 -38
- data/spec/kitchen/driver/dummy_spec.rb +0 -29
- data/spec/kitchen/driver/ssh_base_spec.rb +580 -236
- data/spec/kitchen/driver_spec.rb +1 -0
- data/spec/kitchen/instance_spec.rb +383 -83
- data/spec/kitchen/login_command_spec.rb +29 -10
- data/spec/kitchen/platform_spec.rb +58 -2
- data/spec/kitchen/provisioner/base_spec.rb +170 -18
- data/spec/kitchen/provisioner/chef_base_spec.rb +454 -104
- data/spec/kitchen/provisioner/chef_solo_spec.rb +307 -104
- data/spec/kitchen/provisioner/chef_zero_spec.rb +561 -230
- data/spec/kitchen/provisioner/dummy_spec.rb +91 -0
- data/spec/kitchen/provisioner/shell_spec.rb +158 -56
- data/spec/kitchen/provisioner_spec.rb +37 -0
- data/spec/kitchen/ssh_spec.rb +19 -19
- data/spec/kitchen/transport/base_spec.rb +89 -0
- data/spec/kitchen/transport/ssh_spec.rb +1147 -0
- data/spec/kitchen/transport/winrm/command_executor_spec.rb +400 -0
- data/spec/kitchen/transport/winrm/file_transporter_spec.rb +876 -0
- data/spec/kitchen/transport/winrm/logging_spec.rb +92 -0
- data/spec/kitchen/transport/winrm/template_spec.rb +51 -0
- data/spec/kitchen/transport/winrm/tmp_zip_spec.rb +132 -0
- data/spec/kitchen/transport/winrm_spec.rb +1069 -0
- data/spec/kitchen/transport_spec.rb +112 -0
- data/spec/kitchen/verifier/base_spec.rb +310 -0
- data/spec/kitchen/verifier/busser_spec.rb +540 -0
- data/spec/kitchen/verifier/dummy_spec.rb +91 -0
- data/spec/kitchen/verifier_spec.rb +120 -0
- data/spec/kitchen_spec.rb +7 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/powershell_max_size_spec.rb +40 -0
- data/support/busser_install_command.ps1 +14 -0
- data/support/busser_install_command.sh +15 -0
- data/support/check_files.ps1.erb +48 -0
- data/support/chef_base_init_command.ps1 +18 -0
- data/support/chef_base_init_command.sh +2 -0
- data/support/chef_base_install_command.ps1 +76 -0
- data/support/chef_base_install_command.sh +137 -0
- data/support/chef_zero_prepare_command_legacy.ps1 +9 -0
- data/support/chef_zero_prepare_command_legacy.sh +10 -0
- data/support/decode_files.ps1.erb +61 -0
- data/test-kitchen.gemspec +2 -0
- metadata +97 -8
- data/lib/kitchen/busser.rb +0 -316
- data/spec/kitchen/busser_spec.rb +0 -490
- data/support/chef_helpers.sh +0 -16
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2015, 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
|
+
module Kitchen
|
20
|
+
|
21
|
+
module Transport
|
22
|
+
|
23
|
+
class Winrm < Kitchen::Transport::Base
|
24
|
+
|
25
|
+
# Mixin to use an optionally provided logger for logging.
|
26
|
+
#
|
27
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
28
|
+
module Logging
|
29
|
+
|
30
|
+
# Logs a message on the logger at the debug level, if a logger is
|
31
|
+
# present.
|
32
|
+
#
|
33
|
+
# @param msg [String] a message to log
|
34
|
+
# @yield evaluates and uses return value as message to log. If msg
|
35
|
+
# parameter is set, it will take precedence over the block.
|
36
|
+
def debug(msg = nil, &block)
|
37
|
+
return if logger.nil? || !logger.debug?
|
38
|
+
logger.debug("[#{log_subject}] " << (msg || block.call))
|
39
|
+
end
|
40
|
+
|
41
|
+
# The subject for log messages.
|
42
|
+
#
|
43
|
+
# @return [String] log subject
|
44
|
+
def log_subject
|
45
|
+
@log_subject ||= self.class.to_s.split("::").last
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2015, 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 "erb"
|
20
|
+
require "ostruct"
|
21
|
+
|
22
|
+
module Kitchen
|
23
|
+
|
24
|
+
module Transport
|
25
|
+
|
26
|
+
class Winrm < Kitchen::Transport::Base
|
27
|
+
|
28
|
+
# Wraps an ERb template which can be called multiple times with
|
29
|
+
# different binding contexts.
|
30
|
+
#
|
31
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
32
|
+
# @api private
|
33
|
+
class Template
|
34
|
+
|
35
|
+
# Initializes an ERb template using a file as the template source.
|
36
|
+
#
|
37
|
+
# @param file [String] path to an ERb template file
|
38
|
+
def initialize(file)
|
39
|
+
@erb = ERB.new(IO.read(file))
|
40
|
+
end
|
41
|
+
|
42
|
+
# Renders the template using a hash as context.
|
43
|
+
#
|
44
|
+
# @param vars [Hash] a hash used for context
|
45
|
+
# @return [String] the rendered template
|
46
|
+
def render(vars)
|
47
|
+
@erb.result(Context.for(vars))
|
48
|
+
end
|
49
|
+
alias_method :%, :render
|
50
|
+
|
51
|
+
# Internal class which wraps a binding context for rendering
|
52
|
+
# an ERb template.
|
53
|
+
#
|
54
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
55
|
+
# @api private
|
56
|
+
class Context < OpenStruct
|
57
|
+
|
58
|
+
# Creates a new binding context for a hash of data.
|
59
|
+
#
|
60
|
+
# @param vars [Hash] a hash used for context
|
61
|
+
# @return [Binding] a binding context for the given hash
|
62
|
+
def self.for(vars)
|
63
|
+
new(vars).my_binding
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [Binding] a binding context
|
67
|
+
def my_binding
|
68
|
+
binding
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2015, 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 "delegate"
|
20
|
+
require "pathname"
|
21
|
+
require "tempfile"
|
22
|
+
require "zip"
|
23
|
+
|
24
|
+
require "kitchen/transport/winrm/logging"
|
25
|
+
|
26
|
+
module Kitchen
|
27
|
+
|
28
|
+
module Transport
|
29
|
+
|
30
|
+
class Winrm < Kitchen::Transport::Base
|
31
|
+
|
32
|
+
# A temporary Zip file for a given directory.
|
33
|
+
#
|
34
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
35
|
+
class TmpZip
|
36
|
+
|
37
|
+
include Logging
|
38
|
+
|
39
|
+
# Contructs a new Zip file for the given directory.
|
40
|
+
#
|
41
|
+
# There are 2 ways to interpret the directory path:
|
42
|
+
#
|
43
|
+
# * If the directory has no path separator terminator, then the
|
44
|
+
# directory basename will be used as the base directory in the
|
45
|
+
# resulting zip file.
|
46
|
+
# * If the directory has a path separator terminator (such as `/` or
|
47
|
+
# `\\`), then the entries under the directory will be added to the
|
48
|
+
# resulting zip file.
|
49
|
+
#
|
50
|
+
# The following emaples assume a directory tree structure of:
|
51
|
+
#
|
52
|
+
# src
|
53
|
+
# |-- alpha.txt
|
54
|
+
# |-- beta.txt
|
55
|
+
# \-- sub
|
56
|
+
# \-- charlie.txt
|
57
|
+
#
|
58
|
+
# @example Including the base directory in the zip file
|
59
|
+
#
|
60
|
+
# TmpZip.new("/path/to/src")
|
61
|
+
# # produces a zip file with entries:
|
62
|
+
# # - src/alpha.txt
|
63
|
+
# # - src/beta.txt
|
64
|
+
# # - src/sub/charlie.txt
|
65
|
+
#
|
66
|
+
# @example Excluding the base directory in the zip file
|
67
|
+
#
|
68
|
+
# TmpZip.new("/path/to/src/")
|
69
|
+
# # produces a zip file with entries:
|
70
|
+
# # - alpha.txt
|
71
|
+
# # - beta.txt
|
72
|
+
# # - sub/charlie.txt
|
73
|
+
#
|
74
|
+
# @param dir [String,Pathname,#to_s] path to the directory
|
75
|
+
# @param logger [#debug,#debug?] an optional logger/ui object that
|
76
|
+
# responds to `#debug` and `#debug?` (default `nil`)
|
77
|
+
def initialize(dir, logger = nil)
|
78
|
+
@logger = logger
|
79
|
+
@dir = Pathname.new(dir)
|
80
|
+
@method = ::Zip::Entry::DEFLATED
|
81
|
+
@compression = Zlib::BEST_COMPRESSION
|
82
|
+
@zip_io = Tempfile.open(["tmpzip-", ".zip"], :binmode => true)
|
83
|
+
write_zip
|
84
|
+
@zip_io.close
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Pathname] path to zip file
|
88
|
+
def path
|
89
|
+
Pathname.new(zip_io.path) if zip_io.path
|
90
|
+
end
|
91
|
+
|
92
|
+
# Unlinks (deletes) the zip file from the filesystem.
|
93
|
+
def unlink
|
94
|
+
zip_io.unlink
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# @return [Integer] the compression used for Zip entries. Possible
|
100
|
+
# values are `Zlib::BEST_COMPRESSION`, `Zlib::DEFAULT_COMPRESSION`,
|
101
|
+
# and `Zlib::NO_COMPRESSION`.
|
102
|
+
# @api private
|
103
|
+
attr_reader :compression
|
104
|
+
|
105
|
+
# @return [Pathname] the directory used to create the Zip file
|
106
|
+
# @api private
|
107
|
+
attr_reader :dir
|
108
|
+
|
109
|
+
# @return [#debug] the logger
|
110
|
+
# @api private
|
111
|
+
attr_reader :logger
|
112
|
+
|
113
|
+
# @return [Integer] compression method used for Zip entries. Possible
|
114
|
+
# values are `Zip::Entry::DEFLATED` and `Zip::Entry::STORED`.
|
115
|
+
# @api private
|
116
|
+
attr_reader :method
|
117
|
+
|
118
|
+
# @return [IO] the Zip file IO
|
119
|
+
# @api private
|
120
|
+
attr_reader :zip_io
|
121
|
+
|
122
|
+
# @return [Pathname] the path segement to be stripped off Zip entries
|
123
|
+
# @api private
|
124
|
+
def dir_strip
|
125
|
+
@dir_strip ||= if dir.to_s.end_with?("/", "\\")
|
126
|
+
Pathname.new(dir.to_s.chop)
|
127
|
+
else
|
128
|
+
dir.dirname
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# @return [Array<Pathname] all recursive files under the base
|
133
|
+
# directory, excluding directories
|
134
|
+
# @api private
|
135
|
+
def entries
|
136
|
+
Pathname.glob(dir.join("**/*")).delete_if(&:directory?).sort
|
137
|
+
end
|
138
|
+
|
139
|
+
# (see Logging.log_subject)
|
140
|
+
# @api private
|
141
|
+
def log_subject
|
142
|
+
@log_subject ||= [self.class.to_s.split("::").last, path].join("::")
|
143
|
+
end
|
144
|
+
|
145
|
+
# Adds all file entries to the Zip output stream.
|
146
|
+
#
|
147
|
+
# @param zos [Zip::OutputStream] zip output stream
|
148
|
+
# @api private
|
149
|
+
def produce_zip_entries(zos)
|
150
|
+
entries.each do |entry|
|
151
|
+
entry_path = entry.sub("#{dir_strip}/", "")
|
152
|
+
debug { "+++ Adding #{entry_path}" }
|
153
|
+
zos.put_next_entry(entry_path, nil, nil, method, compression)
|
154
|
+
entry.open("rb") { |src| IO.copy_stream(src, zos) }
|
155
|
+
end
|
156
|
+
debug { "=== All files added." }
|
157
|
+
end
|
158
|
+
|
159
|
+
# Writes out a temporary Zip file.
|
160
|
+
#
|
161
|
+
# @api private
|
162
|
+
def write_zip
|
163
|
+
debug { "Populating files" }
|
164
|
+
Zip::OutputStream.write_buffer(NoDupIO.new(zip_io)) do |zos|
|
165
|
+
produce_zip_entries(zos)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Simple delegate wrapper to prevent `#dup` calls being made on IO
|
170
|
+
# objects. This is used to bypass an issue in the `Zip::Outputstream`
|
171
|
+
# constructor where an incoming IO is duplicated, leading to races
|
172
|
+
# on flushing the final stream to disk.
|
173
|
+
#
|
174
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
175
|
+
# @api private
|
176
|
+
class NoDupIO < SimpleDelegator
|
177
|
+
|
178
|
+
# @return [self] returns self and does *not* return a duplicate
|
179
|
+
# object
|
180
|
+
def dup
|
181
|
+
self
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2015, 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 "thor/util"
|
20
|
+
|
21
|
+
require "kitchen/errors"
|
22
|
+
|
23
|
+
module Kitchen
|
24
|
+
|
25
|
+
# A verifier is responsible for running tests post-converge to confirm that
|
26
|
+
# the instance is in a known/consistent state.
|
27
|
+
#
|
28
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
29
|
+
module Verifier
|
30
|
+
|
31
|
+
# Default verifier to use
|
32
|
+
DEFAULT_PLUGIN = "busser".freeze
|
33
|
+
|
34
|
+
# Returns an instance of a verifier given a plugin type string.
|
35
|
+
#
|
36
|
+
# @param plugin [String] a verifier plugin type, to be constantized
|
37
|
+
# @param config [Hash] a configuration hash to initialize the verifier
|
38
|
+
# @return [Verifier::Base] a verifier instance
|
39
|
+
# @raise [ClientError] if a verifier instance could not be created
|
40
|
+
def self.for_plugin(plugin, config)
|
41
|
+
first_load = require("kitchen/verifier/#{plugin}")
|
42
|
+
|
43
|
+
str_const = Thor::Util.camel_case(plugin)
|
44
|
+
klass = const_get(str_const)
|
45
|
+
object = klass.new(config)
|
46
|
+
object.verify_dependencies if first_load
|
47
|
+
object
|
48
|
+
rescue LoadError, NameError
|
49
|
+
raise ClientError,
|
50
|
+
"Could not load the '#{plugin}' verifier from the load path." \
|
51
|
+
" Please ensure that your transport is installed as a gem or" \
|
52
|
+
" included in your Gemfile if using Bundler."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2015, 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 "kitchen/errors"
|
20
|
+
require "kitchen/configurable"
|
21
|
+
require "kitchen/logging"
|
22
|
+
|
23
|
+
module Kitchen
|
24
|
+
|
25
|
+
module Verifier
|
26
|
+
|
27
|
+
# Base class for a verifier.
|
28
|
+
#
|
29
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
30
|
+
class Base
|
31
|
+
|
32
|
+
include Configurable
|
33
|
+
include Logging
|
34
|
+
|
35
|
+
default_config :http_proxy, nil
|
36
|
+
|
37
|
+
default_config :https_proxy, nil
|
38
|
+
|
39
|
+
default_config :root_path do |verifier|
|
40
|
+
verifier.windows_os? ? "$env:TEMP\\verifier" : "/tmp/verifier"
|
41
|
+
end
|
42
|
+
|
43
|
+
default_config :sudo do |verifier|
|
44
|
+
verifier.windows_os? ? nil : true
|
45
|
+
end
|
46
|
+
|
47
|
+
default_config(:suite_name) { |busser| busser.instance.suite.name }
|
48
|
+
|
49
|
+
# Creates a new Verifier object using the provided configuration data
|
50
|
+
# which will be merged with any default configuration.
|
51
|
+
#
|
52
|
+
# @param config [Hash] provided verifier configuration
|
53
|
+
def initialize(config = {})
|
54
|
+
init_config(config)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Runs the verifier on the instance.
|
58
|
+
#
|
59
|
+
# @param state [Hash] mutable instance state
|
60
|
+
# @raise [ActionFailed] if the action could not be completed
|
61
|
+
def call(state)
|
62
|
+
create_sandbox
|
63
|
+
sandbox_dirs = Dir.glob(File.join(sandbox_path, "*"))
|
64
|
+
|
65
|
+
instance.transport.connection(state) do |conn|
|
66
|
+
conn.execute(install_command)
|
67
|
+
conn.execute(init_command)
|
68
|
+
info("Transferring files to #{instance.to_str}")
|
69
|
+
conn.upload(sandbox_dirs, config[:root_path])
|
70
|
+
debug("Transfer complete")
|
71
|
+
conn.execute(prepare_command)
|
72
|
+
conn.execute(run_command)
|
73
|
+
end
|
74
|
+
rescue Kitchen::Transport::TransportFailed => ex
|
75
|
+
raise ActionFailed, ex.message
|
76
|
+
ensure
|
77
|
+
cleanup_sandbox
|
78
|
+
end
|
79
|
+
|
80
|
+
# Deletes the sandbox path. Without calling this method, the sandbox path
|
81
|
+
# will persist after the process terminates. In other words, cleanup is
|
82
|
+
# explicit. This method is safe to call multiple times.
|
83
|
+
def cleanup_sandbox
|
84
|
+
return if sandbox_path.nil?
|
85
|
+
|
86
|
+
debug("Cleaning up local sandbox in #{sandbox_path}")
|
87
|
+
FileUtils.rmtree(sandbox_path)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Creates a temporary directory on the local workstation into which
|
91
|
+
# verifier related files and directories can be copied or created. The
|
92
|
+
# contents of this directory will be copied over to the instance before
|
93
|
+
# invoking the verifier's run command. After this method completes, it
|
94
|
+
# is expected that the contents of the sandbox is complete and ready for
|
95
|
+
# copy to the remote instance.
|
96
|
+
#
|
97
|
+
# **Note:** any subclasses would be well advised to call super first when
|
98
|
+
# overriding this method, for example:
|
99
|
+
#
|
100
|
+
# @example overriding `#create_sandbox`
|
101
|
+
#
|
102
|
+
# class MyVerifier < Kitchen::Verifier::Base
|
103
|
+
# def create_sandbox
|
104
|
+
# super
|
105
|
+
# # any further file copies, preparations, etc.
|
106
|
+
# end
|
107
|
+
# end
|
108
|
+
def create_sandbox
|
109
|
+
@sandbox_path = Dir.mktmpdir("#{instance.name}-sandbox-")
|
110
|
+
File.chmod(0755, sandbox_path)
|
111
|
+
info("Preparing files for transfer")
|
112
|
+
debug("Creating local sandbox in #{sandbox_path}")
|
113
|
+
end
|
114
|
+
|
115
|
+
# Generates a command string which will install and configure the
|
116
|
+
# verifier software on an instance. If no work is required, then `nil`
|
117
|
+
# will be returned.
|
118
|
+
#
|
119
|
+
# @return [String] a command string
|
120
|
+
def install_command
|
121
|
+
end
|
122
|
+
|
123
|
+
# Generates a command string which will perform any data initialization
|
124
|
+
# or configuration required after the verifier software is installed
|
125
|
+
# but before the sandbox has been transferred to the instance. If no work
|
126
|
+
# is required, then `nil` will be returned.
|
127
|
+
#
|
128
|
+
# @return [String] a command string
|
129
|
+
def init_command
|
130
|
+
end
|
131
|
+
|
132
|
+
# Generates a command string which will perform any commands or
|
133
|
+
# configuration required just before the main verifier run command but
|
134
|
+
# after the sandbox has been transferred to the instance. If no work is
|
135
|
+
# required, then `nil` will be returned.
|
136
|
+
#
|
137
|
+
# @return [String] a command string
|
138
|
+
def prepare_command
|
139
|
+
end
|
140
|
+
|
141
|
+
# Generates a command string which will invoke the main verifier
|
142
|
+
# command on the prepared instance. If no work is required, then `nil`
|
143
|
+
# will be returned.
|
144
|
+
#
|
145
|
+
# @return [String] a command string
|
146
|
+
def run_command
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns the absolute path to the sandbox directory or raises an
|
150
|
+
# exception if `#create_sandbox` has not yet been called.
|
151
|
+
#
|
152
|
+
# @return [String] the absolute path to the sandbox directory
|
153
|
+
# @raise [ClientError] if the sandbox directory has no yet been created
|
154
|
+
# by calling `#create_sandbox`
|
155
|
+
def sandbox_path
|
156
|
+
@sandbox_path || (raise ClientError, "Sandbox directory has not yet " \
|
157
|
+
"been created. Please run #{self.class}#create_sandox before " \
|
158
|
+
"trying to access the path.")
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
# Builds a complete command given a variables String preamble and a file
|
164
|
+
# containing shell code.
|
165
|
+
#
|
166
|
+
# @param vars [String] shell variables, as a String
|
167
|
+
# @param file [String] file basename (without extension) containing
|
168
|
+
# shell code
|
169
|
+
# @return [String] command
|
170
|
+
# @api private
|
171
|
+
def shell_code_from_file(vars, file)
|
172
|
+
src_file = File.join(
|
173
|
+
File.dirname(__FILE__),
|
174
|
+
%w[.. .. .. support],
|
175
|
+
file + (powershell_shell? ? ".ps1" : ".sh")
|
176
|
+
)
|
177
|
+
|
178
|
+
wrap_shell_code([vars, "", IO.read(src_file)].join("\n"))
|
179
|
+
end
|
180
|
+
|
181
|
+
# Conditionally prefixes a command with a sudo command.
|
182
|
+
#
|
183
|
+
# @param command [String] command to be prefixed
|
184
|
+
# @return [String] the command, conditionaly prefixed with sudo
|
185
|
+
# @api private
|
186
|
+
def sudo(script)
|
187
|
+
config[:sudo] ? "sudo -E #{script}" : script
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|