beaker 2.7.1 → 2.8.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 +8 -8
- data/HISTORY.md +121 -2
- data/lib/beaker/dsl.rb +2 -2
- data/lib/beaker/dsl/helpers.rb +13 -1429
- data/lib/beaker/dsl/helpers/facter_helpers.rb +48 -0
- data/lib/beaker/dsl/helpers/hiera_helpers.rb +71 -0
- data/lib/beaker/dsl/helpers/host_helpers.rb +506 -0
- data/lib/beaker/dsl/helpers/puppet_helpers.rb +698 -0
- data/lib/beaker/dsl/helpers/tk_helpers.rb +101 -0
- data/lib/beaker/dsl/helpers/web_helpers.rb +115 -0
- data/lib/beaker/dsl/install_utils.rb +8 -1570
- data/lib/beaker/dsl/install_utils/ezbake_utils.rb +256 -0
- data/lib/beaker/dsl/install_utils/module_utils.rb +237 -0
- data/lib/beaker/dsl/install_utils/pe_utils.rb +518 -0
- data/lib/beaker/dsl/install_utils/puppet_utils.rb +722 -0
- data/lib/beaker/dsl/outcomes.rb +0 -4
- data/lib/beaker/dsl/roles.rb +0 -3
- data/lib/beaker/dsl/structure.rb +127 -4
- data/lib/beaker/dsl/wrappers.rb +0 -4
- data/lib/beaker/host.rb +23 -0
- data/lib/beaker/host/unix/pkg.rb +4 -4
- data/lib/beaker/host_prebuilt_steps.rb +11 -5
- data/lib/beaker/hypervisor/vagrant.rb +1 -0
- data/lib/beaker/hypervisor/vmpooler.rb +38 -0
- data/lib/beaker/logger.rb +10 -4
- data/lib/beaker/network_manager.rb +5 -4
- data/lib/beaker/options/command_line_parser.rb +7 -0
- data/lib/beaker/shared.rb +2 -1
- data/lib/beaker/shared/semvar.rb +41 -0
- data/lib/beaker/test_suite.rb +20 -6
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/dsl/helpers/facter_helpers_spec.rb +59 -0
- data/spec/beaker/dsl/helpers/hiera_helpers_spec.rb +96 -0
- data/spec/beaker/dsl/helpers/host_helpers_spec.rb +413 -0
- data/spec/beaker/dsl/{helpers_spec.rb → helpers/puppet_helpers_spec.rb} +2 -611
- data/spec/beaker/dsl/helpers/tk_helpers_spec.rb +83 -0
- data/spec/beaker/dsl/helpers/web_helpers_spec.rb +60 -0
- data/spec/beaker/dsl/install_utils/module_utils_spec.rb +241 -0
- data/spec/beaker/dsl/install_utils/pe_utils_spec.rb +475 -0
- data/spec/beaker/dsl/install_utils/puppet_utils_spec.rb +523 -0
- data/spec/beaker/dsl/structure_spec.rb +108 -0
- data/spec/beaker/host_prebuilt_steps_spec.rb +44 -0
- data/spec/beaker/host_spec.rb +41 -0
- data/spec/beaker/hypervisor/vagrant_spec.rb +2 -1
- data/spec/beaker/logger_spec.rb +9 -2
- data/spec/beaker/network_manager_spec.rb +7 -1
- data/spec/beaker/options/command_line_parser_spec.rb +3 -2
- data/spec/beaker/shared/semvar_spec.rb +36 -0
- data/spec/beaker/test_suite_spec.rb +48 -0
- data/spec/mocks.rb +10 -0
- metadata +23 -5
- data/lib/beaker/dsl/ezbake_utils.rb +0 -259
- data/spec/beaker/dsl/install_utils_spec.rb +0 -1242
@@ -0,0 +1,48 @@
|
|
1
|
+
module Beaker
|
2
|
+
module DSL
|
3
|
+
module Helpers
|
4
|
+
# Methods that help you interact with your facter installation, facter must be installed
|
5
|
+
# for these methods to execute correctly
|
6
|
+
#
|
7
|
+
module FacterHelpers
|
8
|
+
|
9
|
+
# @!macro common_opts
|
10
|
+
# @param [Hash{Symbol=>String}] opts Options to alter execution.
|
11
|
+
# @option opts [Boolean] :silent (false) Do not produce log output
|
12
|
+
# @option opts [Array<Fixnum>] :acceptable_exit_codes ([0]) An array
|
13
|
+
# (or range) of integer exit codes that should be considered
|
14
|
+
# acceptable. An error will be thrown if the exit code does not
|
15
|
+
# match one of the values in this list.
|
16
|
+
# @option opts [Hash{String=>String}] :environment ({}) These will be
|
17
|
+
# treated as extra environment variables that should be set before
|
18
|
+
# running the command.
|
19
|
+
#
|
20
|
+
|
21
|
+
# Get a facter fact from a provided host
|
22
|
+
#
|
23
|
+
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
24
|
+
# or a role (String or Symbol) that identifies one or more hosts.
|
25
|
+
# @param [String] name The name of the fact to query for
|
26
|
+
# @!macro common_opts
|
27
|
+
#
|
28
|
+
# @return String The value of the fact 'name' on the provided host
|
29
|
+
# @raise [FailTest] Raises an exception if call to facter fails
|
30
|
+
def fact_on(host, name, opts = {})
|
31
|
+
result = on host, facter(name, opts)
|
32
|
+
if result.kind_of?(Array)
|
33
|
+
result.map { |res| res.stdout.chomp }
|
34
|
+
else
|
35
|
+
result.stdout.chomp
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get a facter fact from the default host
|
40
|
+
# @see #fact_on
|
41
|
+
def fact(name, opts = {})
|
42
|
+
fact_on(default, name, opts)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Beaker
|
2
|
+
module DSL
|
3
|
+
module Helpers
|
4
|
+
# Methods that help you interact with your hiera installation, hiera must be installed
|
5
|
+
# for these methods to execute correctly
|
6
|
+
module HieraHelpers
|
7
|
+
|
8
|
+
# @!macro common_opts
|
9
|
+
# @param [Hash{Symbol=>String}] opts Options to alter execution.
|
10
|
+
# @option opts [Boolean] :silent (false) Do not produce log output
|
11
|
+
# @option opts [Array<Fixnum>] :acceptable_exit_codes ([0]) An array
|
12
|
+
# (or range) of integer exit codes that should be considered
|
13
|
+
# acceptable. An error will be thrown if the exit code does not
|
14
|
+
# match one of the values in this list.
|
15
|
+
# @option opts [Hash{String=>String}] :environment ({}) These will be
|
16
|
+
# treated as extra environment variables that should be set before
|
17
|
+
# running the command.
|
18
|
+
|
19
|
+
# Write hiera config file on one or more provided hosts
|
20
|
+
#
|
21
|
+
# @param[Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
22
|
+
# or a role (String or Symbol) that identifies one or more hosts.
|
23
|
+
# @param[Array] One or more hierarchy paths
|
24
|
+
def write_hiera_config_on(host, hierarchy)
|
25
|
+
|
26
|
+
block_on host do |host|
|
27
|
+
hiera_config=Hash.new
|
28
|
+
hiera_config[:backends] = 'yaml'
|
29
|
+
hiera_config[:yaml] = {}
|
30
|
+
hiera_config[:yaml][:datadir] = hiera_datadir(host)
|
31
|
+
hiera_config[:hierarchy] = hierarchy
|
32
|
+
hiera_config[:logger] = 'console'
|
33
|
+
create_remote_file host, host.puppet['hiera_config'], hiera_config.to_yaml
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Write hiera config file for the default host
|
38
|
+
# @see #write_hiera_config_on
|
39
|
+
def write_hiera_config(hierarchy)
|
40
|
+
write_hiera_config_on(default, hierarchy)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Copy hiera data files to one or more provided hosts
|
44
|
+
#
|
45
|
+
# @param[Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
46
|
+
# or a role (String or Symbol) that identifies one or more hosts.
|
47
|
+
# @param[String] Directory containing the hiera data files.
|
48
|
+
def copy_hiera_data_to(host, source)
|
49
|
+
scp_to host, File.expand_path(source), hiera_datadir(host)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Copy hiera data files to the default host
|
53
|
+
# @see #copy_hiera_data_to
|
54
|
+
def copy_hiera_data(source)
|
55
|
+
copy_hiera_data_to(default, source)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get file path to the hieradatadir for a given host.
|
59
|
+
# Handles whether or not a host is AIO-based & backwards compatibility
|
60
|
+
#
|
61
|
+
# @param[Host] host Host you want to use the hieradatadir from
|
62
|
+
#
|
63
|
+
# @return [String] Path to the hiera data directory
|
64
|
+
def hiera_datadir(host)
|
65
|
+
host[:type] =~ /aio/ ? File.join(host.puppet['codedir'], 'hieradata') : host[:hieradatadir]
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,506 @@
|
|
1
|
+
module Beaker
|
2
|
+
module DSL
|
3
|
+
module Helpers
|
4
|
+
# Methods that help you interact and manage the state of your Beaker SUTs, these
|
5
|
+
# methods do not require puppet to be installed to execute correctly
|
6
|
+
module HostHelpers
|
7
|
+
|
8
|
+
# @!macro common_opts
|
9
|
+
# @param [Hash{Symbol=>String}] opts Options to alter execution.
|
10
|
+
# @option opts [Boolean] :silent (false) Do not produce log output
|
11
|
+
# @option opts [Array<Fixnum>] :acceptable_exit_codes ([0]) An array
|
12
|
+
# (or range) of integer exit codes that should be considered
|
13
|
+
# acceptable. An error will be thrown if the exit code does not
|
14
|
+
# match one of the values in this list.
|
15
|
+
# @option opts [Hash{String=>String}] :environment ({}) These will be
|
16
|
+
# treated as extra environment variables that should be set before
|
17
|
+
# running the command.
|
18
|
+
#
|
19
|
+
|
20
|
+
# The primary method for executing commands *on* some set of hosts.
|
21
|
+
#
|
22
|
+
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
23
|
+
# or a role (String or Symbol) that identifies one or more hosts.
|
24
|
+
# @param [String, Command] command The command to execute on *host*.
|
25
|
+
# @param [Proc] block Additional actions or assertions.
|
26
|
+
# @!macro common_opts
|
27
|
+
#
|
28
|
+
# @example Most basic usage
|
29
|
+
# on hosts, 'ls /tmp'
|
30
|
+
#
|
31
|
+
# @example Allowing additional exit codes to pass
|
32
|
+
# on agents, 'puppet agent -t', :acceptable_exit_codes => [0,2]
|
33
|
+
#
|
34
|
+
# @example Using the returned result for any kind of checking
|
35
|
+
# if on(host, 'ls -la ~').stdout =~ /\.bin/
|
36
|
+
# ...do some action...
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# @example Using TestCase helpers from within a test.
|
40
|
+
# agents.each do |agent|
|
41
|
+
# on agent, 'cat /etc/puppet/puppet.conf' do
|
42
|
+
# assert_match stdout, /server = #{master}/, 'WTF Mate'
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# @example Using a role (defined in a String) to identify the host
|
47
|
+
# on "master", "echo hello"
|
48
|
+
#
|
49
|
+
# @example Using a role (defined in a Symbol) to identify the host
|
50
|
+
# on :dashboard, "echo hello"
|
51
|
+
# @return [Result] An object representing the outcome of *command*.
|
52
|
+
# @raise [FailTest] Raises an exception if *command* obviously fails.
|
53
|
+
def on(host, command, opts = {}, &block)
|
54
|
+
block_on host do | host |
|
55
|
+
cur_command = command
|
56
|
+
if command.is_a? Command
|
57
|
+
cur_command = command.cmd_line(host)
|
58
|
+
end
|
59
|
+
cmd_opts = {}
|
60
|
+
#add any additional environment variables to the command
|
61
|
+
if opts[:environment]
|
62
|
+
cmd_opts['ENV'] = opts[:environment]
|
63
|
+
end
|
64
|
+
@result = host.exec(Command.new(cur_command.to_s, [], cmd_opts), opts)
|
65
|
+
|
66
|
+
# Also, let additional checking be performed by the caller.
|
67
|
+
if block_given?
|
68
|
+
case block.arity
|
69
|
+
#block with arity of 0, just hand back yourself
|
70
|
+
when 0
|
71
|
+
yield self
|
72
|
+
#block with arity of 1 or greater, hand back the result object
|
73
|
+
else
|
74
|
+
yield @result
|
75
|
+
end
|
76
|
+
end
|
77
|
+
@result
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# The method for executing commands on the default host
|
82
|
+
#
|
83
|
+
# @param [String, Command] command The command to execute on *host*.
|
84
|
+
# @param [Proc] block Additional actions or assertions.
|
85
|
+
# @!macro common_opts
|
86
|
+
#
|
87
|
+
# @example Most basic usage
|
88
|
+
# shell 'ls /tmp'
|
89
|
+
#
|
90
|
+
# @example Allowing additional exit codes to pass
|
91
|
+
# shell 'puppet agent -t', :acceptable_exit_codes => [0,2]
|
92
|
+
#
|
93
|
+
# @example Using the returned result for any kind of checking
|
94
|
+
# if shell('ls -la ~').stdout =~ /\.bin/
|
95
|
+
# ...do some action...
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# @example Using TestCase helpers from within a test.
|
99
|
+
# agents.each do |agent|
|
100
|
+
# shell('cat /etc/puppet/puppet.conf') do |result|
|
101
|
+
# assert_match result.stdout, /server = #{master}/, 'WTF Mate'
|
102
|
+
# end
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# @return [Result] An object representing the outcome of *command*.
|
106
|
+
# @raise [FailTest] Raises an exception if *command* obviously fails.
|
107
|
+
def shell(command, opts = {}, &block)
|
108
|
+
on(default, command, opts, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @deprecated
|
112
|
+
# An proxy for the last {Beaker::Result#stdout} returned by
|
113
|
+
# a method that makes remote calls. Use the {Beaker::Result}
|
114
|
+
# object returned by the method directly instead. For Usage see
|
115
|
+
# {Beaker::Result}.
|
116
|
+
def stdout
|
117
|
+
return nil if @result.nil?
|
118
|
+
@result.stdout
|
119
|
+
end
|
120
|
+
|
121
|
+
# @deprecated
|
122
|
+
# An proxy for the last {Beaker::Result#stderr} returned by
|
123
|
+
# a method that makes remote calls. Use the {Beaker::Result}
|
124
|
+
# object returned by the method directly instead. For Usage see
|
125
|
+
# {Beaker::Result}.
|
126
|
+
def stderr
|
127
|
+
return nil if @result.nil?
|
128
|
+
@result.stderr
|
129
|
+
end
|
130
|
+
|
131
|
+
# @deprecated
|
132
|
+
# An proxy for the last {Beaker::Result#exit_code} returned by
|
133
|
+
# a method that makes remote calls. Use the {Beaker::Result}
|
134
|
+
# object returned by the method directly instead. For Usage see
|
135
|
+
# {Beaker::Result}.
|
136
|
+
def exit_code
|
137
|
+
return nil if @result.nil?
|
138
|
+
@result.exit_code
|
139
|
+
end
|
140
|
+
|
141
|
+
# Move a file from a remote to a local path
|
142
|
+
# @note If using {Beaker::Host} for the hosts *scp* is not
|
143
|
+
# required on the system as it uses Ruby's net/scp library. The
|
144
|
+
# net-scp gem however is required (and specified in the gemspec).
|
145
|
+
#
|
146
|
+
# @param [Host, #do_scp_from] host One or more hosts (or some object
|
147
|
+
# that responds like
|
148
|
+
# {Beaker::Host#do_scp_from}.
|
149
|
+
# @param [String] from_path A remote path to a file.
|
150
|
+
# @param [String] to_path A local path to copy *from_path* to.
|
151
|
+
# @!macro common_opts
|
152
|
+
#
|
153
|
+
# @return [Result] Returns the result of the SCP operation
|
154
|
+
def scp_from host, from_path, to_path, opts = {}
|
155
|
+
block_on host do | host |
|
156
|
+
@result = host.do_scp_from(from_path, to_path, opts)
|
157
|
+
@result.log logger
|
158
|
+
@result
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Move a local file to a remote host using scp
|
163
|
+
# @note If using {Beaker::Host} for the hosts *scp* is not
|
164
|
+
# required on the system as it uses Ruby's net/scp library. The
|
165
|
+
# net-scp gem however is required (and specified in the gemspec.
|
166
|
+
# When using SCP with Windows it will now auto expand path when
|
167
|
+
# using `cygpath instead of failing or requiring full path
|
168
|
+
#
|
169
|
+
# @param [Host, #do_scp_to] host One or more hosts (or some object
|
170
|
+
# that responds like
|
171
|
+
# {Beaker::Host#do_scp_to}.
|
172
|
+
# @param [String] from_path A local path to a file.
|
173
|
+
# @param [String] to_path A remote path to copy *from_path* to.
|
174
|
+
# @!macro common_opts
|
175
|
+
#
|
176
|
+
# @return [Result] Returns the result of the SCP operation
|
177
|
+
def scp_to host, from_path, to_path, opts = {}
|
178
|
+
block_on host do | host |
|
179
|
+
if host['platform'] =~ /windows/ && to_path.match('`cygpath')
|
180
|
+
result = on host, "echo #{to_path}"
|
181
|
+
to_path = result.raw_output.chomp
|
182
|
+
end
|
183
|
+
@result = host.do_scp_to(from_path, to_path, opts)
|
184
|
+
@result.log logger
|
185
|
+
@result
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Move a local file or directory to a remote host using rsync
|
190
|
+
# @note rsync is required on the local host.
|
191
|
+
#
|
192
|
+
# @param [Host, #do_scp_to] host A host object that responds like
|
193
|
+
# {Beaker::Host}.
|
194
|
+
# @param [String] from_path A local path to a file or directory.
|
195
|
+
# @param [String] to_path A remote path to copy *from_path* to.
|
196
|
+
# @!macro common_opts
|
197
|
+
#
|
198
|
+
# @return [Result] Returns the result of the rsync operation
|
199
|
+
def rsync_to host, from_path, to_path, opts = {}
|
200
|
+
block_on host do | host |
|
201
|
+
if host['platform'] =~ /windows/ && to_path.match('`cygpath')
|
202
|
+
result = host.echo "#{to_path}"
|
203
|
+
to_path = result.raw_output.chomp
|
204
|
+
end
|
205
|
+
@result = host.do_rsync_to(from_path, to_path, opts)
|
206
|
+
@result
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Deploy packaging configurations generated by
|
211
|
+
# https://github.com/puppetlabs/packaging to a host.
|
212
|
+
#
|
213
|
+
# @note To ensure the repo configs are available for deployment,
|
214
|
+
# you should run `rake pl:jenkins:deb_repo_configs` and
|
215
|
+
# `rake pl:jenkins:rpm_repo_configs` on your project checkout
|
216
|
+
#
|
217
|
+
# @param [Host] host
|
218
|
+
# @param [String] path The path to the generated repository config
|
219
|
+
# files. ex: /myproject/pkg/repo_configs
|
220
|
+
# @param [String] name A human-readable name for the repository
|
221
|
+
# @param [String] version The version of the project, as used by the
|
222
|
+
# packaging tools. This can be determined with
|
223
|
+
# `rake pl:print_build_params` from the packaging
|
224
|
+
# repo.
|
225
|
+
def deploy_package_repo host, path, name, version
|
226
|
+
host.deploy_package_repo path, name, version
|
227
|
+
end
|
228
|
+
|
229
|
+
# Create a remote file out of a string
|
230
|
+
# @note This method uses Tempfile in Ruby's STDLIB as well as {#scp_to}.
|
231
|
+
#
|
232
|
+
# @param [Host, #do_scp_to] hosts One or more hosts (or some object
|
233
|
+
# that responds like
|
234
|
+
# {Beaker::Host#do_scp_from}.
|
235
|
+
# @param [String] file_path A remote path to place *file_content* at.
|
236
|
+
# @param [String] file_content The contents of the file to be placed.
|
237
|
+
# @!macro common_opts
|
238
|
+
# @option opts [String] :protocol Name of the underlying transfer method.
|
239
|
+
# Valid options are 'scp' or 'rsync'.
|
240
|
+
#
|
241
|
+
# @return [Result] Returns the result of the underlying SCP operation.
|
242
|
+
def create_remote_file(hosts, file_path, file_content, opts = {})
|
243
|
+
Tempfile.open 'beaker' do |tempfile|
|
244
|
+
File.open(tempfile.path, 'w') {|file| file.puts file_content }
|
245
|
+
|
246
|
+
opts[:protocol] ||= 'scp'
|
247
|
+
case opts[:protocol]
|
248
|
+
when 'scp'
|
249
|
+
scp_to hosts, tempfile.path, file_path, opts
|
250
|
+
when 'rsync'
|
251
|
+
rsync_to hosts, tempfile.path, file_path, opts
|
252
|
+
else
|
253
|
+
logger.debug "Unsupported transfer protocol, returning nil"
|
254
|
+
nil
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# Move a local script to a remote host and execute it
|
260
|
+
# @note this relies on {#on} and {#scp_to}
|
261
|
+
#
|
262
|
+
# @param [Host, #do_scp_to] host One or more hosts (or some object
|
263
|
+
# that responds like
|
264
|
+
# {Beaker::Host#do_scp_from}.
|
265
|
+
# @param [String] script A local path to find an executable script at.
|
266
|
+
# @!macro common_opts
|
267
|
+
# @param [Proc] block Additional tests to run after script has executed
|
268
|
+
#
|
269
|
+
# @return [Result] Returns the result of the underlying SCP operation.
|
270
|
+
def run_script_on(host, script, opts = {}, &block)
|
271
|
+
# this is unsafe as it uses the File::SEPARATOR will be set to that
|
272
|
+
# of the coordinator node. This works for us because we use cygwin
|
273
|
+
# which will properly convert the paths. Otherwise this would not
|
274
|
+
# work for running tests on a windows machine when the coordinator
|
275
|
+
# that the harness is running on is *nix. We should use
|
276
|
+
# {Beaker::Host#temp_path} instead. TODO
|
277
|
+
remote_path = File.join("", "tmp", File.basename(script))
|
278
|
+
|
279
|
+
scp_to host, script, remote_path
|
280
|
+
on host, remote_path, opts, &block
|
281
|
+
end
|
282
|
+
|
283
|
+
# Move a local script to default host and execute it
|
284
|
+
# @see #run_script_on
|
285
|
+
def run_script(script, opts = {}, &block)
|
286
|
+
run_script_on(default, script, opts, &block)
|
287
|
+
end
|
288
|
+
|
289
|
+
# Install a package on a host
|
290
|
+
#
|
291
|
+
# @param [Host] host A host object
|
292
|
+
# @param [String] package_name Name of the package to install
|
293
|
+
#
|
294
|
+
# @return [Result] An object representing the outcome of *install command*.
|
295
|
+
def install_package host, package_name, package_version = nil
|
296
|
+
host.install_package package_name, '', package_version
|
297
|
+
end
|
298
|
+
|
299
|
+
# Check to see if a package is installed on a remote host
|
300
|
+
#
|
301
|
+
# @param [Host] host A host object
|
302
|
+
# @param [String] package_name Name of the package to check for.
|
303
|
+
#
|
304
|
+
# @return [Boolean] true/false if the package is found
|
305
|
+
def check_for_package host, package_name
|
306
|
+
host.check_for_package package_name
|
307
|
+
end
|
308
|
+
|
309
|
+
# Upgrade a package on a host. The package must already be installed
|
310
|
+
#
|
311
|
+
# @param [Host] host A host object
|
312
|
+
# @param [String] package_name Name of the package to install
|
313
|
+
#
|
314
|
+
# @return [Result] An object representing the outcome of *upgrade command*.
|
315
|
+
def upgrade_package host, package_name
|
316
|
+
host.upgrade_package package_name
|
317
|
+
end
|
318
|
+
|
319
|
+
# Configure a host entry on the give host
|
320
|
+
# @example: will add a host entry for forge.puppetlabs.com
|
321
|
+
# add_system32_hosts_entry(host, { :ip => '23.251.154.122', :name => 'forge.puppetlabs.com' })
|
322
|
+
#
|
323
|
+
# @return nil
|
324
|
+
def add_system32_hosts_entry(host, opts = {})
|
325
|
+
if host['platform'] =~ /windows/
|
326
|
+
hosts_file = "C:\\Windows\\System32\\Drivers\\etc\\hosts"
|
327
|
+
host_entry = "#{opts['ip']}`t`t#{opts['name']}"
|
328
|
+
on host, powershell("\$text = \\\"#{host_entry}\\\"; Add-Content -path '#{hosts_file}' -value \$text")
|
329
|
+
else
|
330
|
+
raise "nothing to do for #{host.name} on #{host['platform']}"
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# Back up the given file in the current_dir to the new_dir
|
335
|
+
#
|
336
|
+
# @!visibility private
|
337
|
+
#
|
338
|
+
# @param host [Beaker::Host] The target host
|
339
|
+
# @param current_dir [String] The directory containing the file to back up
|
340
|
+
# @param new_dir [String] The directory to copy the file to
|
341
|
+
# @param filename [String] The file to back up. Defaults to 'puppet.conf'
|
342
|
+
#
|
343
|
+
# @return [String, nil] The path to the file if the file exists, nil if it
|
344
|
+
# doesn't exist.
|
345
|
+
def backup_the_file host, current_dir, new_dir, filename = 'puppet.conf'
|
346
|
+
|
347
|
+
old_location = current_dir + '/' + filename
|
348
|
+
new_location = new_dir + '/' + filename + '.bak'
|
349
|
+
|
350
|
+
if host.file_exist? old_location
|
351
|
+
host.exec( Command.new( "cp #{old_location} #{new_location}" ) )
|
352
|
+
return new_location
|
353
|
+
else
|
354
|
+
logger.warn "Could not backup file '#{old_location}': no such file"
|
355
|
+
nil
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
#Run a curl command on the provided host(s)
|
360
|
+
#
|
361
|
+
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
362
|
+
# or a role (String or Symbol) that identifies one or more hosts.
|
363
|
+
# @param [String, Command] cmd The curl command to execute on *host*.
|
364
|
+
# @param [Proc] block Additional actions or assertions.
|
365
|
+
# @!macro common_opts
|
366
|
+
#
|
367
|
+
def curl_on(host, cmd, opts = {}, &block)
|
368
|
+
if options.is_pe? #check global options hash
|
369
|
+
on host, "curl --tlsv1 %s" % cmd, opts, &block
|
370
|
+
else
|
371
|
+
on host, "curl %s" % cmd, opts, &block
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
|
376
|
+
def curl_with_retries(desc, host, url, desired_exit_codes, max_retries = 60, retry_interval = 1)
|
377
|
+
opts = {
|
378
|
+
:desired_exit_codes => desired_exit_codes,
|
379
|
+
:max_retries => max_retries,
|
380
|
+
:retry_interval => retry_interval
|
381
|
+
}
|
382
|
+
retry_on(host, "curl -m 1 #{url}", opts)
|
383
|
+
end
|
384
|
+
|
385
|
+
# This command will execute repeatedly until success or it runs out with an error
|
386
|
+
#
|
387
|
+
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
388
|
+
# or a role (String or Symbol) that identifies one or more hosts.
|
389
|
+
# @param [String, Command] command The command to execute on *host*.
|
390
|
+
# @param [Hash{Symbol=>String}] opts Options to alter execution.
|
391
|
+
# @param [Proc] block Additional actions or assertions.
|
392
|
+
#
|
393
|
+
# @option opts [Array<Fixnum>, Fixnum] :desired_exit_codes (0) An array
|
394
|
+
# or integer exit code(s) that should be considered
|
395
|
+
# acceptable. An error will be thrown if the exit code never
|
396
|
+
# matches one of the values in this list.
|
397
|
+
# @option opts [Fixnum] :max_retries (60) number of times the
|
398
|
+
# command will be tried before failing
|
399
|
+
# @option opts [Float] :retry_interval (1) number of seconds
|
400
|
+
# that we'll wait between tries
|
401
|
+
# @option opts [Boolean] :verbose (false)
|
402
|
+
def retry_on(host, command, opts = {}, &block)
|
403
|
+
option_exit_codes = opts[:desired_exit_codes]
|
404
|
+
option_max_retries = opts[:max_retries].to_i
|
405
|
+
option_retry_interval = opts[:retry_interval].to_f
|
406
|
+
desired_exit_codes = option_exit_codes ? [option_exit_codes].flatten : [0]
|
407
|
+
desired_exit_codes = [0] if desired_exit_codes.empty?
|
408
|
+
max_retries = option_max_retries == 0 ? 60 : option_max_retries # nil & "" both return 0
|
409
|
+
retry_interval = option_retry_interval == 0 ? 1 : option_retry_interval
|
410
|
+
verbose = true.to_s == opts[:verbose]
|
411
|
+
|
412
|
+
log_prefix = host.log_prefix
|
413
|
+
logger.debug "\n#{log_prefix} #{Time.new.strftime('%H:%M:%S')}$ #{command}"
|
414
|
+
logger.debug " Trying command #{max_retries} times."
|
415
|
+
logger.debug ".", add_newline=false
|
416
|
+
|
417
|
+
result = on host, command, {:acceptable_exit_codes => (0...127), :silent => !verbose}, &block
|
418
|
+
num_retries = 0
|
419
|
+
until desired_exit_codes.include?(result.exit_code)
|
420
|
+
sleep retry_interval
|
421
|
+
result = on host, command, {:acceptable_exit_codes => (0...127), :silent => !verbose}, &block
|
422
|
+
num_retries += 1
|
423
|
+
logger.debug ".", add_newline=false
|
424
|
+
if (num_retries > max_retries)
|
425
|
+
logger.debug " Command \`#{command}\` failed."
|
426
|
+
fail("Command \`#{command}\` failed.")
|
427
|
+
end
|
428
|
+
end
|
429
|
+
logger.debug "\n#{log_prefix} #{Time.new.strftime('%H:%M:%S')}$ #{command} ostensibly successful."
|
430
|
+
result
|
431
|
+
end
|
432
|
+
|
433
|
+
# FIX: this should be moved into host/platform
|
434
|
+
# @visibility private
|
435
|
+
def run_cron_on(host, action, user, entry="", &block)
|
436
|
+
block_on host do | host |
|
437
|
+
platform = host['platform']
|
438
|
+
if platform.include?('solaris') || platform.include?('aix') then
|
439
|
+
case action
|
440
|
+
when :list then args = '-l'
|
441
|
+
when :remove then args = '-r'
|
442
|
+
when :add
|
443
|
+
on( host,
|
444
|
+
"echo '#{entry}' > /var/spool/cron/crontabs/#{user}",
|
445
|
+
&block )
|
446
|
+
end
|
447
|
+
|
448
|
+
else # default for GNU/Linux platforms
|
449
|
+
case action
|
450
|
+
when :list then args = '-l -u'
|
451
|
+
when :remove then args = '-r -u'
|
452
|
+
when :add
|
453
|
+
on( host,
|
454
|
+
"echo '#{entry}' > /tmp/#{user}.cron && " +
|
455
|
+
"crontab -u #{user} /tmp/#{user}.cron",
|
456
|
+
&block )
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
if args
|
461
|
+
case action
|
462
|
+
when :list, :remove then on(host, "crontab #{args} #{user}", &block)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
# Create a temp directory on remote host owned by specified user.
|
469
|
+
#
|
470
|
+
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
471
|
+
# or a role (String or Symbol) that identifies one or more hosts.
|
472
|
+
# @param [String] path_prefix A remote path prefix for the new temp
|
473
|
+
# directory.
|
474
|
+
# @param [String] user The name of user that should own the temp
|
475
|
+
# directory. If no username is specified defaults to the currently logged in user
|
476
|
+
# per host
|
477
|
+
#
|
478
|
+
# @return [String, Array<String>] Returns the name of the newly-created dir, or an array
|
479
|
+
# of names of newly-created dirs per-host
|
480
|
+
def create_tmpdir_on(host, path_prefix = '', user=nil)
|
481
|
+
|
482
|
+
block_on host do | host |
|
483
|
+
# use default user logged into this host
|
484
|
+
if not user
|
485
|
+
user = host['user']
|
486
|
+
end
|
487
|
+
|
488
|
+
if not on(host, "getent passwd #{user}").exit_code == 0
|
489
|
+
raise "User #{user} does not exist on #{host}."
|
490
|
+
end
|
491
|
+
|
492
|
+
if defined? host.tmpdir
|
493
|
+
dir = host.tmpdir(path_prefix)
|
494
|
+
on host, "chown #{user}:#{user} #{dir}"
|
495
|
+
dir
|
496
|
+
else
|
497
|
+
raise "Host platform not supported by `create_tmpdir_on`."
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|