test-kitchen-rsync 3.0.0.pre.1
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 +7 -0
- data/Gemfile +21 -0
- data/LICENSE +15 -0
- data/Rakefile +53 -0
- data/bin/zl-kitchen +11 -0
- data/lib/kitchen/base64_stream.rb +48 -0
- data/lib/kitchen/chef_utils_wiring.rb +40 -0
- data/lib/kitchen/cli.rb +413 -0
- data/lib/kitchen/collection.rb +52 -0
- data/lib/kitchen/color.rb +63 -0
- data/lib/kitchen/command/action.rb +41 -0
- data/lib/kitchen/command/console.rb +54 -0
- data/lib/kitchen/command/diagnose.rb +84 -0
- data/lib/kitchen/command/doctor.rb +39 -0
- data/lib/kitchen/command/exec.rb +37 -0
- data/lib/kitchen/command/list.rb +148 -0
- data/lib/kitchen/command/login.rb +39 -0
- data/lib/kitchen/command/package.rb +32 -0
- data/lib/kitchen/command/sink.rb +50 -0
- data/lib/kitchen/command/test.rb +47 -0
- data/lib/kitchen/command.rb +207 -0
- data/lib/kitchen/config.rb +344 -0
- data/lib/kitchen/configurable.rb +616 -0
- data/lib/kitchen/data_munger.rb +1024 -0
- data/lib/kitchen/diagnostic.rb +138 -0
- data/lib/kitchen/driver/base.rb +133 -0
- data/lib/kitchen/driver/dummy.rb +105 -0
- data/lib/kitchen/driver/exec.rb +70 -0
- data/lib/kitchen/driver/proxy.rb +70 -0
- data/lib/kitchen/driver/ssh_base.rb +351 -0
- data/lib/kitchen/driver.rb +40 -0
- data/lib/kitchen/errors.rb +243 -0
- data/lib/kitchen/generator/init.rb +254 -0
- data/lib/kitchen/instance.rb +726 -0
- data/lib/kitchen/lazy_hash.rb +148 -0
- data/lib/kitchen/lifecycle_hook/base.rb +78 -0
- data/lib/kitchen/lifecycle_hook/local.rb +53 -0
- data/lib/kitchen/lifecycle_hook/remote.rb +39 -0
- data/lib/kitchen/lifecycle_hooks.rb +92 -0
- data/lib/kitchen/loader/yaml.rb +377 -0
- data/lib/kitchen/logger.rb +422 -0
- data/lib/kitchen/logging.rb +52 -0
- data/lib/kitchen/login_command.rb +49 -0
- data/lib/kitchen/metadata_chopper.rb +49 -0
- data/lib/kitchen/platform.rb +64 -0
- data/lib/kitchen/plugin.rb +76 -0
- data/lib/kitchen/plugin_base.rb +60 -0
- data/lib/kitchen/provisioner/base.rb +269 -0
- data/lib/kitchen/provisioner/chef/berkshelf.rb +116 -0
- data/lib/kitchen/provisioner/chef/common_sandbox.rb +350 -0
- data/lib/kitchen/provisioner/chef/policyfile.rb +163 -0
- data/lib/kitchen/provisioner/chef_apply.rb +121 -0
- data/lib/kitchen/provisioner/chef_base.rb +705 -0
- data/lib/kitchen/provisioner/chef_infra.rb +167 -0
- data/lib/kitchen/provisioner/chef_solo.rb +82 -0
- data/lib/kitchen/provisioner/chef_zero.rb +12 -0
- data/lib/kitchen/provisioner/dummy.rb +75 -0
- data/lib/kitchen/provisioner/shell.rb +157 -0
- data/lib/kitchen/provisioner.rb +42 -0
- data/lib/kitchen/rake_tasks.rb +80 -0
- data/lib/kitchen/shell_out.rb +90 -0
- data/lib/kitchen/ssh.rb +289 -0
- data/lib/kitchen/state_file.rb +112 -0
- data/lib/kitchen/suite.rb +48 -0
- data/lib/kitchen/thor_tasks.rb +63 -0
- data/lib/kitchen/transport/base.rb +236 -0
- data/lib/kitchen/transport/dummy.rb +78 -0
- data/lib/kitchen/transport/exec.rb +145 -0
- data/lib/kitchen/transport/ssh.rb +579 -0
- data/lib/kitchen/transport/winrm.rb +546 -0
- data/lib/kitchen/transport.rb +40 -0
- data/lib/kitchen/util.rb +229 -0
- data/lib/kitchen/verifier/base.rb +243 -0
- data/lib/kitchen/verifier/busser.rb +275 -0
- data/lib/kitchen/verifier/dummy.rb +75 -0
- data/lib/kitchen/verifier/shell.rb +99 -0
- data/lib/kitchen/verifier.rb +39 -0
- data/lib/kitchen/version.rb +20 -0
- data/lib/kitchen/which.rb +26 -0
- data/lib/kitchen.rb +152 -0
- data/lib/vendor/hash_recursive_merge.rb +79 -0
- data/support/busser_install_command.ps1 +14 -0
- data/support/busser_install_command.sh +21 -0
- data/support/chef-client-fail-if-update-handler.rb +15 -0
- data/support/chef_base_init_command.ps1 +18 -0
- data/support/chef_base_init_command.sh +1 -0
- data/support/chef_base_install_command.ps1 +85 -0
- data/support/chef_base_install_command.sh +229 -0
- data/support/download_helpers.sh +109 -0
- data/support/dummy-validation.pem +27 -0
- data/templates/driver/CHANGELOG.md.erb +3 -0
- data/templates/driver/Gemfile.erb +3 -0
- data/templates/driver/README.md.erb +64 -0
- data/templates/driver/Rakefile.erb +21 -0
- data/templates/driver/driver.rb.erb +23 -0
- data/templates/driver/gemspec.erb +29 -0
- data/templates/driver/gitignore.erb +17 -0
- data/templates/driver/license_apachev2.erb +15 -0
- data/templates/driver/license_lgplv3.erb +16 -0
- data/templates/driver/license_mit.erb +22 -0
- data/templates/driver/license_reserved.erb +5 -0
- data/templates/driver/tailor.erb +4 -0
- data/templates/driver/travis.yml.erb +11 -0
- data/templates/driver/version.rb.erb +12 -0
- data/templates/init/chefignore.erb +2 -0
- data/templates/init/kitchen.yml.erb +18 -0
- data/test-kitchen.gemspec +52 -0
- metadata +528 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2012, Fletcher Nichol
|
|
5
|
+
# Copyright (C) 2018, Chef Software
|
|
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 "errors"
|
|
20
|
+
require_relative "util"
|
|
21
|
+
|
|
22
|
+
module Kitchen
|
|
23
|
+
module Plugin
|
|
24
|
+
# Returns an instance of a plugin given a type, name, and config.
|
|
25
|
+
#
|
|
26
|
+
# @param type [Module] a Kitchen::<Module> of one of the plugin types
|
|
27
|
+
# (Driver, Provisioner, Transport, Verifier)
|
|
28
|
+
# @param plugin [String] a plugin name, which will be constantized
|
|
29
|
+
# @param config [Hash] a configuration hash to initialize the plugin
|
|
30
|
+
# @return [Kitchen::<Module>::Base] a plugin instance
|
|
31
|
+
# @raise [ClientError] if a plugin instance could not be created
|
|
32
|
+
# @raise [UserError] if the plugin's dependencies could not be met
|
|
33
|
+
def self.load(type, plugin, config)
|
|
34
|
+
type_name = Kitchen::Util.snake_case(type.name.split("::").last)
|
|
35
|
+
first_load = require("kitchen/#{type_name}/#{plugin}")
|
|
36
|
+
|
|
37
|
+
str_const = Kitchen::Util.camel_case(plugin)
|
|
38
|
+
klass = type.const_get(str_const)
|
|
39
|
+
object = klass.new(config)
|
|
40
|
+
object.verify_dependencies if first_load
|
|
41
|
+
object
|
|
42
|
+
rescue UserError
|
|
43
|
+
raise
|
|
44
|
+
rescue NameError => e
|
|
45
|
+
raise ClientError, "Could not load the '#{plugin}' #{type_name}. Error: #{e.message}"
|
|
46
|
+
rescue LoadError => e
|
|
47
|
+
available_plugins = plugins_available(type_name)
|
|
48
|
+
error_message = if available_plugins.include?(plugin)
|
|
49
|
+
e.message
|
|
50
|
+
else
|
|
51
|
+
" Did you mean: #{available_plugins.join(", ")} ?" \
|
|
52
|
+
" Please ensure that your #{type_name} is installed as a gem or included" \
|
|
53
|
+
" in your Gemfile if using Bundler."
|
|
54
|
+
end
|
|
55
|
+
raise ClientError, "Could not load the '#{plugin}' #{type_name} from the load path." + error_message
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# given a type of plugin, searches the Ruby load path for plugins of that
|
|
59
|
+
# type based on the path+naming convention that plugin loading is based upon
|
|
60
|
+
#
|
|
61
|
+
# @param plugin_type [String] the name of a plugin type (e.g. driver,
|
|
62
|
+
# provisioner, transport, verifier)
|
|
63
|
+
# @return [Array<String>] a collection of Ruby filenames that are probably
|
|
64
|
+
# plugins of the given type
|
|
65
|
+
def self.plugins_available(plugin_type)
|
|
66
|
+
$LOAD_PATH.map { |load_path| Dir[File.expand_path("kitchen/#{plugin_type}/*.rb", load_path)] }
|
|
67
|
+
.reject(&:empty?)
|
|
68
|
+
.flatten
|
|
69
|
+
.uniq
|
|
70
|
+
.select { |plugin_path| File.readlines(plugin_path).grep(/^\s*class \w* </).any? }
|
|
71
|
+
.map { |plugin_path| File.basename(plugin_path).gsub(/\.rb$/, "") }
|
|
72
|
+
.reject { |plugin_name| plugin_name == "base" }
|
|
73
|
+
.sort
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2014, Fletcher Nichol
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
module Kitchen
|
|
19
|
+
module Plugin
|
|
20
|
+
class Base
|
|
21
|
+
class << self
|
|
22
|
+
# @return [Array<Symbol>] an array of action method names that cannot
|
|
23
|
+
# be run concurrently and must be run in serial via a shared mutex
|
|
24
|
+
attr_reader :serial_actions
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Registers certain driver actions that cannot be safely run concurrently
|
|
28
|
+
# in threads across multiple instances. Typically this might be used
|
|
29
|
+
# for create or destroy actions that use an underlying resource that
|
|
30
|
+
# cannot be used at the same time.
|
|
31
|
+
#
|
|
32
|
+
# A shared mutex for this driver object will be used to synchronize all
|
|
33
|
+
# registered methods.
|
|
34
|
+
#
|
|
35
|
+
# @example a single action method that cannot be run concurrently
|
|
36
|
+
#
|
|
37
|
+
# no_parallel_for :create
|
|
38
|
+
#
|
|
39
|
+
# @example multiple action methods that cannot be run concurrently
|
|
40
|
+
#
|
|
41
|
+
# no_parallel_for :create, :destroy
|
|
42
|
+
#
|
|
43
|
+
# @param methods [Array<Symbol>] one or more actions as symbols
|
|
44
|
+
# @raise [ClientError] if any method is not a valid action method name
|
|
45
|
+
def self.no_parallel_for(*methods)
|
|
46
|
+
action_methods = %i{create setup converge verify destroy}
|
|
47
|
+
|
|
48
|
+
Array(methods).each do |meth|
|
|
49
|
+
next if action_methods.include?(meth)
|
|
50
|
+
|
|
51
|
+
raise ClientError, "##{meth} is not a valid no_parallel_for method"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
@serial_actions ||= []
|
|
55
|
+
@serial_actions += methods
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2013, Fletcher Nichol
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
require_relative "../configurable"
|
|
19
|
+
require_relative "../errors"
|
|
20
|
+
require_relative "../logging"
|
|
21
|
+
require_relative "../plugin_base"
|
|
22
|
+
|
|
23
|
+
module Kitchen
|
|
24
|
+
module Provisioner
|
|
25
|
+
# Base class for a provisioner.
|
|
26
|
+
#
|
|
27
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
|
28
|
+
class Base < Kitchen::Plugin::Base
|
|
29
|
+
include Configurable
|
|
30
|
+
include Logging
|
|
31
|
+
|
|
32
|
+
default_config :http_proxy, nil
|
|
33
|
+
default_config :https_proxy, nil
|
|
34
|
+
default_config :ftp_proxy, nil
|
|
35
|
+
|
|
36
|
+
default_config :retry_on_exit_code, []
|
|
37
|
+
default_config :max_retries, 1
|
|
38
|
+
default_config :wait_for_retry, 30
|
|
39
|
+
|
|
40
|
+
default_config :root_path do |provisioner|
|
|
41
|
+
provisioner.windows_os? ? '$env:TEMP\\kitchen' : "/tmp/kitchen"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
default_config :sudo do |provisioner|
|
|
45
|
+
provisioner.windows_os? ? nil : true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
default_config :sudo_command do |provisioner|
|
|
49
|
+
provisioner.windows_os? ? nil : "sudo -E"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
default_config :command_prefix, nil
|
|
53
|
+
|
|
54
|
+
default_config :uploads, {}
|
|
55
|
+
default_config :downloads, {}
|
|
56
|
+
|
|
57
|
+
expand_path_for :test_base_path
|
|
58
|
+
|
|
59
|
+
# Constructs a new provisioner by providing a configuration hash.
|
|
60
|
+
#
|
|
61
|
+
# @param config [Hash] initial provided configuration
|
|
62
|
+
def initialize(config = {})
|
|
63
|
+
init_config(config)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Runs the provisioner on the instance.
|
|
67
|
+
#
|
|
68
|
+
# @param state [Hash] mutable instance state
|
|
69
|
+
# @raise [ActionFailed] if the action could not be completed
|
|
70
|
+
# rubocop:disable Metrics/AbcSize
|
|
71
|
+
def call(state)
|
|
72
|
+
create_sandbox
|
|
73
|
+
sandbox_dirs = Util.list_directory(sandbox_path)
|
|
74
|
+
|
|
75
|
+
instance.transport.connection(state) do |conn|
|
|
76
|
+
config[:uploads].to_h.each do |locals, remote|
|
|
77
|
+
debug("Uploading #{Array(locals).join(", ")} to #{remote}")
|
|
78
|
+
conn.upload(locals.to_s, remote)
|
|
79
|
+
end
|
|
80
|
+
conn.execute(install_command)
|
|
81
|
+
conn.execute(init_command)
|
|
82
|
+
info("Transferring files to #{instance.to_str} using rsync")
|
|
83
|
+
conn.rsyn_chef_repo(sandbox_path, config[:root_path])
|
|
84
|
+
debug("Transfer complete")
|
|
85
|
+
conn.execute(prepare_command)
|
|
86
|
+
conn.execute_with_retry(
|
|
87
|
+
run_command,
|
|
88
|
+
config[:retry_on_exit_code],
|
|
89
|
+
config[:max_retries],
|
|
90
|
+
config[:wait_for_retry]
|
|
91
|
+
)
|
|
92
|
+
info("Downloading files from #{instance.to_str}")
|
|
93
|
+
config[:downloads].to_h.each do |remotes, local|
|
|
94
|
+
debug("Downloading #{Array(remotes).join(", ")} to #{local}")
|
|
95
|
+
conn.download(remotes, local)
|
|
96
|
+
end
|
|
97
|
+
debug("Download complete")
|
|
98
|
+
end
|
|
99
|
+
rescue Kitchen::Transport::TransportFailed => ex
|
|
100
|
+
raise ActionFailed, ex.message
|
|
101
|
+
ensure
|
|
102
|
+
cleanup_sandbox
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Check system and configuration for common errors.
|
|
106
|
+
#
|
|
107
|
+
# @param state [Hash] mutable instance state
|
|
108
|
+
# @returns [Boolean] Return true if a problem is found.
|
|
109
|
+
def doctor(state)
|
|
110
|
+
false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Certain products that Test Kitchen uses to provision require accepting
|
|
114
|
+
# a license to use. Overwrite this method in the specific provisioner
|
|
115
|
+
# to implement this check.
|
|
116
|
+
def check_license; end
|
|
117
|
+
|
|
118
|
+
# Generates a command string which will install and configure the
|
|
119
|
+
# provisioner software on an instance. If no work is required, then `nil`
|
|
120
|
+
# will be returned.
|
|
121
|
+
#
|
|
122
|
+
# @return [String] a command string
|
|
123
|
+
def install_command; end
|
|
124
|
+
|
|
125
|
+
# Generates a command string which will perform any data initialization
|
|
126
|
+
# or configuration required after the provisioner software is installed
|
|
127
|
+
# but before the sandbox has been transferred to the instance. If no work
|
|
128
|
+
# is required, then `nil` will be returned.
|
|
129
|
+
#
|
|
130
|
+
# @return [String] a command string
|
|
131
|
+
def init_command; end
|
|
132
|
+
|
|
133
|
+
# Generates a command string which will perform any commands or
|
|
134
|
+
# configuration required just before the main provisioner run command but
|
|
135
|
+
# after the sandbox has been transferred to the instance. If no work is
|
|
136
|
+
# required, then `nil` will be returned.
|
|
137
|
+
#
|
|
138
|
+
# @return [String] a command string
|
|
139
|
+
def prepare_command; end
|
|
140
|
+
|
|
141
|
+
# Generates a command string which will invoke the main provisioner
|
|
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; end
|
|
147
|
+
|
|
148
|
+
# Creates a temporary directory on the local workstation into which
|
|
149
|
+
# provisioner related files and directories can be copied or created. The
|
|
150
|
+
# contents of this directory will be copied over to the instance before
|
|
151
|
+
# invoking the provisioner's run command. After this method completes, it
|
|
152
|
+
# is expected that the contents of the sandbox is complete and ready for
|
|
153
|
+
# copy to the remote instance.
|
|
154
|
+
#
|
|
155
|
+
# **Note:** any subclasses would be well advised to call super first when
|
|
156
|
+
# overriding this method, for example:
|
|
157
|
+
#
|
|
158
|
+
# @example overriding `#create_sandbox`
|
|
159
|
+
#
|
|
160
|
+
# class MyProvisioner < Kitchen::Provisioner::Base
|
|
161
|
+
# def create_sandbox
|
|
162
|
+
# super
|
|
163
|
+
# # any further file copies, preparations, etc.
|
|
164
|
+
# end
|
|
165
|
+
# end
|
|
166
|
+
def create_sandbox
|
|
167
|
+
@sandbox_path = Dir.mktmpdir("#{instance.name}-sandbox-")
|
|
168
|
+
File.chmod(0755, sandbox_path)
|
|
169
|
+
info("Preparing files for transfer")
|
|
170
|
+
debug("Creating local sandbox in #{sandbox_path}")
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Returns the absolute path to the sandbox directory or raises an
|
|
174
|
+
# exception if `#create_sandbox` has not yet been called.
|
|
175
|
+
#
|
|
176
|
+
# @return [String] the absolute path to the sandbox directory
|
|
177
|
+
# @raise [ClientError] if the sandbox directory has no yet been created
|
|
178
|
+
# by calling `#create_sandbox`
|
|
179
|
+
def sandbox_path
|
|
180
|
+
@sandbox_path ||= raise ClientError, "Sandbox directory has not yet " \
|
|
181
|
+
"been created. Please run #{self.class}#create_sandox before " \
|
|
182
|
+
"trying to access the path."
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Deletes the sandbox path. Without calling this method, the sandbox path
|
|
186
|
+
# will persist after the process terminates. In other words, cleanup is
|
|
187
|
+
# explicit. This method is safe to call multiple times.
|
|
188
|
+
def cleanup_sandbox
|
|
189
|
+
return if sandbox_path.nil?
|
|
190
|
+
|
|
191
|
+
debug("Cleaning up local sandbox in #{sandbox_path}")
|
|
192
|
+
FileUtils.rmtree(sandbox_path)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Sets the API version for this provisioner. If the provisioner does not
|
|
196
|
+
# set this value, then `nil` will be used and reported.
|
|
197
|
+
#
|
|
198
|
+
# Sets the API version for this provisioner
|
|
199
|
+
#
|
|
200
|
+
# @example setting an API version
|
|
201
|
+
#
|
|
202
|
+
# module Kitchen
|
|
203
|
+
# module Provisioner
|
|
204
|
+
# class NewProvisioner < Kitchen::Provisioner::Base
|
|
205
|
+
#
|
|
206
|
+
# kitchen_provisioner_api_version 2
|
|
207
|
+
#
|
|
208
|
+
# end
|
|
209
|
+
# end
|
|
210
|
+
# end
|
|
211
|
+
#
|
|
212
|
+
# @param version [Integer,String] a version number
|
|
213
|
+
#
|
|
214
|
+
def self.kitchen_provisioner_api_version(version)
|
|
215
|
+
@api_version = version
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
private
|
|
219
|
+
|
|
220
|
+
# Builds a complete command given a variables String preamble and a file
|
|
221
|
+
# containing shell code.
|
|
222
|
+
#
|
|
223
|
+
# @param vars [String] shell variables, as a String
|
|
224
|
+
# @param file [String] file basename (without extension) containing
|
|
225
|
+
# shell code
|
|
226
|
+
# @return [String] command
|
|
227
|
+
# @api private
|
|
228
|
+
def shell_code_from_file(vars, file)
|
|
229
|
+
src_file = File.join(
|
|
230
|
+
File.dirname(__FILE__),
|
|
231
|
+
%w{.. .. .. support},
|
|
232
|
+
file + (powershell_shell? ? ".ps1" : ".sh")
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
wrap_shell_code([vars, "", IO.read(src_file)].join("\n"))
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Conditionally prefixes a command with a sudo command.
|
|
239
|
+
#
|
|
240
|
+
# @param command [String] command to be prefixed
|
|
241
|
+
# @return [String] the command, conditionally prefixed with sudo
|
|
242
|
+
# @api private
|
|
243
|
+
def sudo(script)
|
|
244
|
+
"#{sudo_command} #{script}".lstrip
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Returns the sudo command to use or empty string if sudo is not configured
|
|
248
|
+
#
|
|
249
|
+
# @return [String] the sudo command if sudo config is true
|
|
250
|
+
# @api private
|
|
251
|
+
def sudo_command
|
|
252
|
+
config[:sudo] ? config[:sudo_command].to_s : ""
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Conditionally prefixes a command with a command prefix.
|
|
256
|
+
# This should generally be done after a command has been
|
|
257
|
+
# conditionally prefixed by #sudo as certain platforms, such as
|
|
258
|
+
# Cisco Nexus, require all commands to be run with a prefix to
|
|
259
|
+
# obtain outbound network access.
|
|
260
|
+
#
|
|
261
|
+
# @param command [String] command to be prefixed
|
|
262
|
+
# @return [String] the command, conditionally prefixed with the configured prefix
|
|
263
|
+
# @api private
|
|
264
|
+
def prefix_command(script)
|
|
265
|
+
config[:command_prefix] ? "#{config[:command_prefix]} #{script}" : script
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2013, Fletcher Nichol
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
require_relative "../../errors"
|
|
19
|
+
require_relative "../../logging"
|
|
20
|
+
|
|
21
|
+
module Kitchen
|
|
22
|
+
module Provisioner
|
|
23
|
+
module Chef
|
|
24
|
+
# Chef cookbook resolver that uses Berkshelf and a Berksfile to calculate
|
|
25
|
+
# dependencies.
|
|
26
|
+
#
|
|
27
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
|
28
|
+
class Berkshelf
|
|
29
|
+
include Logging
|
|
30
|
+
|
|
31
|
+
# Creates a new cookbook resolver.
|
|
32
|
+
#
|
|
33
|
+
# @param berksfile [String] path to a Berksfile
|
|
34
|
+
# @param path [String] path in which to vendor the resulting
|
|
35
|
+
# cookbooks
|
|
36
|
+
# @param logger [Kitchen::Logger] a logger to use for output, defaults
|
|
37
|
+
# to `Kitchen.logger`
|
|
38
|
+
def initialize(berksfile, path, logger: Kitchen.logger, always_update: false)
|
|
39
|
+
@berksfile = berksfile
|
|
40
|
+
@path = path
|
|
41
|
+
@logger = logger
|
|
42
|
+
@always_update = always_update
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Loads the library code required to use the resolver.
|
|
46
|
+
#
|
|
47
|
+
# @param logger [Kitchen::Logger] a logger to use for output, defaults
|
|
48
|
+
# to `Kitchen.logger`
|
|
49
|
+
def self.load!(logger: Kitchen.logger)
|
|
50
|
+
load_berkshelf!(logger)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Performs the cookbook resolution and vendors the resulting cookbooks
|
|
54
|
+
# in the desired path.
|
|
55
|
+
def resolve
|
|
56
|
+
version = ::Berkshelf::VERSION
|
|
57
|
+
info("Resolving cookbook dependencies with Berkshelf #{version}...")
|
|
58
|
+
debug("Using Berksfile from #{berksfile}")
|
|
59
|
+
|
|
60
|
+
::Berkshelf.ui.mute do
|
|
61
|
+
berksfile_obj = ::Berkshelf::Berksfile.from_file(berksfile)
|
|
62
|
+
berksfile_obj.update if always_update && berksfile_obj.lockfile.present?
|
|
63
|
+
# Berkshelf requires the directory to not exist
|
|
64
|
+
FileUtils.rm_rf(path)
|
|
65
|
+
berksfile_obj.vendor(path)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
# @return [String] path to a Berksfile
|
|
72
|
+
# @api private
|
|
73
|
+
attr_reader :berksfile
|
|
74
|
+
|
|
75
|
+
# @return [String] path in which to vendor the resulting cookbooks
|
|
76
|
+
# @api private
|
|
77
|
+
attr_reader :path
|
|
78
|
+
|
|
79
|
+
# @return [Kitchen::Logger] a logger to use for output
|
|
80
|
+
# @api private
|
|
81
|
+
attr_reader :logger
|
|
82
|
+
|
|
83
|
+
# @return [Boolean] If true, always update cookbooks in Berkshelf.
|
|
84
|
+
# @api private
|
|
85
|
+
attr_reader :always_update
|
|
86
|
+
|
|
87
|
+
class << self
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
# Load the Berkshelf-specific libary code.
|
|
91
|
+
#
|
|
92
|
+
# @param logger [Kitchen::Logger] the logger to use
|
|
93
|
+
# @raise [UserError] if the library couldn't be loaded
|
|
94
|
+
# @api private
|
|
95
|
+
def load_berkshelf!(logger)
|
|
96
|
+
first_load = require "berkshelf"
|
|
97
|
+
|
|
98
|
+
version = ::Berkshelf::VERSION
|
|
99
|
+
if first_load
|
|
100
|
+
logger.debug("Berkshelf #{version} library loaded")
|
|
101
|
+
else
|
|
102
|
+
logger.debug("Berkshelf #{version} previously loaded")
|
|
103
|
+
end
|
|
104
|
+
rescue LoadError => e
|
|
105
|
+
logger.fatal("The `berkshelf' gem is missing and must be installed" \
|
|
106
|
+
" or cannot be properly activated. Run" \
|
|
107
|
+
" `gem install berkshelf` or add the following to your" \
|
|
108
|
+
" Gemfile if you are using Bundler: `gem 'berkshelf'`.")
|
|
109
|
+
raise UserError,
|
|
110
|
+
"Could not load or activate Berkshelf (#{e.message})"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|