beaker 2.3.0 → 2.4.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.
Files changed (45) hide show
  1. checksums.yaml +8 -8
  2. data/HISTORY.md +366 -2
  3. data/ext/completion/beaker-completion.bash +1 -1
  4. data/lib/beaker.rb +1 -1
  5. data/lib/beaker/answers.rb +3 -1
  6. data/lib/beaker/answers/version40.rb +42 -0
  7. data/lib/beaker/cli.rb +0 -2
  8. data/lib/beaker/command.rb +10 -2
  9. data/lib/beaker/dsl/ezbake_utils.rb +195 -157
  10. data/lib/beaker/dsl/helpers.rb +9 -6
  11. data/lib/beaker/dsl/install_utils.rb +22 -8
  12. data/lib/beaker/dsl/structure.rb +67 -0
  13. data/lib/beaker/host.rb +14 -4
  14. data/lib/beaker/host/mac.rb +4 -0
  15. data/lib/beaker/host/pswindows.rb +79 -0
  16. data/lib/beaker/host/pswindows/exec.rb +29 -0
  17. data/lib/beaker/host/pswindows/file.rb +15 -0
  18. data/lib/beaker/host/pswindows/group.rb +36 -0
  19. data/lib/beaker/host/pswindows/pkg.rb +47 -0
  20. data/lib/beaker/host/pswindows/user.rb +32 -0
  21. data/lib/beaker/host/unix.rb +16 -6
  22. data/lib/beaker/host/windows.rb +6 -2
  23. data/lib/beaker/host_prebuilt_steps.rb +2 -0
  24. data/lib/beaker/hypervisor.rb +3 -1
  25. data/lib/beaker/hypervisor/aws_sdk.rb +6 -1
  26. data/lib/beaker/hypervisor/docker.rb +6 -1
  27. data/lib/beaker/hypervisor/vagrant.rb +1 -1
  28. data/lib/beaker/hypervisor/vagrant_parallels.rb +18 -0
  29. data/lib/beaker/logger.rb +8 -1
  30. data/lib/beaker/logger_junit.rb +157 -0
  31. data/lib/beaker/network_manager.rb +28 -0
  32. data/lib/beaker/options/presets.rb +6 -0
  33. data/lib/beaker/test_suite.rb +65 -136
  34. data/lib/beaker/version.rb +1 -1
  35. data/spec/beaker/answers_spec.rb +74 -0
  36. data/spec/beaker/dsl/ezbake_utils_spec.rb +167 -126
  37. data/spec/beaker/dsl/install_utils_spec.rb +5 -4
  38. data/spec/beaker/dsl/structure_spec.rb +28 -1
  39. data/spec/beaker/host_prebuilt_steps_spec.rb +2 -1
  40. data/spec/beaker/host_spec.rb +1 -7
  41. data/spec/beaker/hypervisor/docker_spec.rb +19 -1
  42. data/spec/beaker/hypervisor/vagrant_parallels_spec.rb +44 -0
  43. data/spec/beaker/logger_junit_spec.rb +93 -0
  44. data/spec/beaker/network_manager_spec.rb +52 -0
  45. metadata +14 -2
data/lib/beaker/cli.rb CHANGED
@@ -44,8 +44,6 @@ module Beaker
44
44
  require File.expand_path(helper)
45
45
  end
46
46
 
47
- @options[:log_dated_dir] = Beaker::Logger.generate_dated_log_folder(@options[:log_dir], @timestamp)
48
- @options[:xml_dated_dir] = Beaker::Logger.generate_dated_log_folder(@options[:xml_dir], @timestamp)
49
47
  end
50
48
 
51
49
  #Provision, validate and configure all hosts as defined in the hosts file
@@ -148,9 +148,17 @@ module Beaker
148
148
  env_array << "#{key.to_s.upcase}=\"#{val}\""
149
149
  end
150
150
 
151
- environment_string = env_array.join(' ')
151
+ if host['is_cygwin'].nil? or host['is_cygwin'] == true
152
+ environment_string = env_array.join(' ')
153
+ "env #{environment_string}"
154
+ else
155
+ environment_string = ''
156
+ env_array.each_with_index do |env|
157
+ environment_string += "set #{env} && "
158
+ end
159
+ environment_string
160
+ end
152
161
 
153
- "env #{environment_string}"
154
162
  end
155
163
 
156
164
  end
@@ -1,80 +1,176 @@
1
1
  require 'beaker/dsl/install_utils'
2
+ require 'fileutils'
2
3
 
3
4
  module Beaker
4
5
  module DSL
5
- #
6
6
  # This module contains methods to assist in installing projects from source
7
7
  # that use ezbake for packaging.
8
8
  #
9
9
  # @api dsl
10
10
  module EZBakeUtils
11
11
 
12
- REMOTE_PACKAGES_REQUIRED = ['make']
12
+ # @!group Public DSL Methods
13
+
14
+ # Installs leiningen project with given name and version on remote host.
15
+ #
16
+ # @param [Host] host A single remote host on which to install the
17
+ # specified leiningen project.
18
+ # @api dsl
19
+ def install_from_ezbake host
20
+ ezbake_validate_support host
21
+ ezbake_tools_available?
22
+ install_ezbake_tarball_on_host host
23
+ ezbake_installsh host, "service"
24
+ end
25
+
26
+ # Installs termini with given name and version on remote host.
27
+ #
28
+ # @param [Host] host A single remote host on which to install the
29
+ # specified leiningen project.
30
+ # @api dsl
31
+ def install_termini_from_ezbake host
32
+ ezbake_validate_support host
33
+ ezbake_tools_available?
34
+ install_ezbake_tarball_on_host host
35
+ ezbake_installsh host, "termini"
36
+ end
37
+
38
+ # Install a development version of ezbake into the local m2 repository
39
+ #
40
+ # This can be useful if you want to work on a development branch of
41
+ # ezbake that hasn't been released yet. Ensure your project dependencies
42
+ # in your development branch include a reference to the -SNAPSHOT
43
+ # version of the project for it to successfully pickup a pre-shipped
44
+ # version of ezbake.
45
+ #
46
+ # @param url [String] git url
47
+ # @param branch [String] git branch
48
+ # @api dsl
49
+ def ezbake_dev_build url = "git@github.com:puppetlabs/ezbake.git",
50
+ branch = "master"
51
+ ezbake_dir = 'tmp/ezbake'
52
+ conditionally_clone url, ezbake_dir, branch
53
+ lp = ezbake_lein_prefix
54
+
55
+ Dir.chdir(ezbake_dir) do
56
+ ezbake_local_cmd "#{lp} install",
57
+ :throw_on_failure => true
58
+ end
59
+ end
60
+
61
+ # @!endgroup
62
+
63
+ class << self
64
+ attr_accessor :config
65
+ end
66
+
67
+ # @!group Private helpers
68
+
69
+ # Test for support in one place
70
+ #
71
+ # @param [Host] host host to check for support
72
+ # @raise [RuntimeError] if OS is not supported
73
+ # @api private
74
+ def ezbake_validate_support host
75
+ variant, version, _, _ = host['platform'].to_array
76
+ unless variant =~ /^(fedora|el|centos|debian|ubuntu)$/
77
+ raise RuntimeError,
78
+ "No support for #{variant} within ezbake_utils ..."
79
+ end
80
+ end
81
+
82
+ # Build, copy & unpack tarball on remote host
83
+ #
84
+ # @param [Host] host installation destination
85
+ # @api private
86
+ def install_ezbake_tarball_on_host host
87
+ if not ezbake_config
88
+ ezbake_stage
89
+ end
90
+
91
+ # Skip installation if the remote directory exists
92
+ result = on host, "test -d #{ezbake_install_dir}", :acceptable_exit_codes => [0, 1]
93
+ return if result.exit_code == 0
94
+
95
+ ezbake_staging_dir = File.join('target', 'staging')
96
+ Dir.chdir(ezbake_staging_dir) do
97
+ ezbake_local_cmd 'rake package:tar'
98
+ end
99
+
100
+ local_tarball = ezbake_staging_dir + "/pkg/" + ezbake_install_name + ".tar.gz"
101
+ remote_tarball = ezbake_install_dir + ".tar.gz"
102
+ scp_to host, local_tarball, remote_tarball
103
+
104
+ # untar tarball on host
105
+ on host, "tar -xzf " + remote_tarball
106
+
107
+ # Check to ensure directory exists
108
+ on host, "test -d #{ezbake_install_dir}"
109
+ end
110
+
13
111
  LOCAL_COMMANDS_REQUIRED = [
14
112
  ['leiningen', 'lein --version', nil],
15
- ['lein-pprint', 'lein with-profile ci pprint :version',
113
+ ['lein-pprint', 'lein with-profile ci pprint :version',
16
114
  'Must have lein-pprint installed under the :ci profile.'],
17
115
  ['java', 'java -version', nil],
18
116
  ['git', 'git --version', nil],
19
117
  ['rake', 'rake --version', nil],
20
118
  ]
21
- class << self
22
- attr_accessor :config
119
+
120
+ # Checks given host for the tools necessary to perform
121
+ # install_from_ezbake.
122
+ #
123
+ # @raise [RuntimeError] if tool is not found
124
+ # @api private
125
+ def ezbake_tools_available?
126
+ LOCAL_COMMANDS_REQUIRED.each do |software_name, command, additional_error_message|
127
+ if not system command
128
+ error_message = "Must have #{software_name} installed on development system.\n"
129
+ if additional_error_message
130
+ error_message += additional_error_message
131
+ end
132
+ raise RuntimeError, error_message
133
+ end
134
+ end
23
135
  end
24
136
 
25
137
  # Return the ezbake config.
26
138
  #
139
+ # @return [Hash] configuration for ezbake, usually from ezbake.rb
140
+ # @api private
27
141
  def ezbake_config
28
142
  EZBakeUtils.config
29
143
  end
30
144
 
31
- # Checks given host for the tools necessary to perform
32
- # install_from_ezbake. If no host is given then check the local machine
33
- # for necessary available tools. If a tool is not found, then raise
34
- # RuntimeError.
35
- #
36
- def ezbake_tools_available? host = nil
37
- if host
38
- REMOTE_PACKAGES_REQUIRED.each do |package_name|
39
- if not check_for_package host, package_name
40
- raise "Required package, #{package_name}, not installed on #{host}"
41
- end
42
- end
43
- else
44
- LOCAL_COMMANDS_REQUIRED.each do |software_name, command, additional_error_message|
45
- if not system command
46
- error_message = "Must have #{software_name} installed on development system.\n"
47
- if additional_error_message
48
- error_message += additional_error_message
49
- end
50
- raise error_message
51
- end
52
- end
53
- end
145
+ # Returns a leiningen prefix with local m2 repo capability
146
+ #
147
+ # @return [String] lein prefix command that uses a local build
148
+ # m2 repository.
149
+ # @api private
150
+ def ezbake_lein_prefix
151
+ # Get the absolute path to the local repo
152
+ m2_repo = File.join(Dir.pwd, 'tmp', 'm2-local')
153
+
154
+ 'lein update-in : assoc :local-repo "\"' + m2_repo + '\"" --'
54
155
  end
55
156
 
56
157
  # Prepares a staging directory for the specified project.
57
158
  #
58
- # @param [String] project_name The name of the ezbake project being worked
59
- # on.
60
- # @param [String] project_param_string Parameters to be passed to ezbake
61
- # on the command line.
62
- # @param [String] ezbake_dir The local directory where the ezbake project
63
- # resides or should reside if it doesn't exist
64
- # already.
65
- #
66
- def ezbake_stage project_name, project_param_string, ezbake_dir="tmp/ezbake"
67
- ezbake_tools_available?
68
- conditionally_clone "gitmirror@github.delivery.puppetlabs.net:puppetlabs-ezbake.git", ezbake_dir
159
+ # @api private
160
+ def ezbake_stage
161
+ # Install the PuppetDB jar into the local repository
162
+ ezbake_local_cmd "#{ezbake_lein_prefix} install",
163
+ :throw_on_failure => true
69
164
 
70
- package_version = ''
71
- Dir.chdir(ezbake_dir) do
72
- `lein run -- stage #{project_name} #{project_param_string}`
73
- end
165
+ # Run ezbake stage
166
+ ezbake_local_cmd "#{ezbake_lein_prefix} with-profile ezbake ezbake stage",
167
+ :throw_on_failure => true
74
168
 
75
- staging_dir = File.join(ezbake_dir, 'target/staging')
169
+ # Boostrap packaging, and grab configuration info from project
170
+ staging_dir = File.join('target','staging')
76
171
  Dir.chdir(staging_dir) do
77
- output = `rake package:bootstrap`
172
+ ezbake_local_cmd 'rake package:bootstrap'
173
+
78
174
  load 'ezbake.rb'
79
175
  ezbake = EZBake::Config
80
176
  ezbake[:package_version] = `echo -n $(rake pl:print_build_param[ref] | tail -n 1)`
@@ -82,137 +178,79 @@ module Beaker
82
178
  end
83
179
  end
84
180
 
85
- # Installs ezbake dependencies on given host.
181
+ # Executes a local command using system, logging the prepared command
86
182
  #
87
- # @param [Host] host A single remote host on which to install the
88
- # packaging dependencies of the ezbake project configuration currently in
89
- # Beaker::DSL::EZBakeUtils.config
90
- #
91
- def install_ezbake_deps host
92
- ezbake_tools_available? host
183
+ # @param [String] cmd command to execute
184
+ # @param [Hash] opts options
185
+ # @option opts [bool] :throw_on_failure If true, throws an
186
+ # exception if the exit code is non-zero. Defaults to false.
187
+ # @return [bool] true if exit == 0 false if otherwise
188
+ # @raise [RuntimeError] if :throw_on_failure is true and
189
+ # command fails
190
+ # @api private
191
+ def ezbake_local_cmd cmd, opts={}
192
+ opts = {
193
+ :throw_on_failure => false,
194
+ }.merge(opts)
93
195
 
94
- if not ezbake_config
95
- ezbake_stage project_name, project_param_string
196
+ logger.notify "localhost $ #{cmd}"
197
+ result = system cmd
198
+ if opts[:throw_on_failure] && result == false
199
+ raise RuntimeError, "Command failure #{cmd}"
96
200
  end
97
-
98
- variant, version, arch, codename = host['platform'].to_array
99
- ezbake = ezbake_config
100
-
101
- case variant
102
- when /^(fedora|el|centos)$/
103
- dependency_list = ezbake[:redhat][:additional_dependencies]
104
- dependency_list.each do |dependency|
105
- package_name, _, package_version = dependency.split
106
- install_package host, package_name, package_version
107
- end
108
-
109
- when /^(debian|ubuntu|cumulus)$/
110
- dependency_list = ezbake[:debian][:additional_dependencies]
111
- dependency_list.each do |dependency|
112
- package_name, _, package_version = dependency.split
113
- if package_version
114
- package_version = package_version.chop
115
- end
116
- install_package host, package_name, package_version
117
- end
118
-
119
- else
120
- raise "No repository installation step for #{variant} yet..."
121
- end
122
-
201
+ result
123
202
  end
124
203
 
125
- # Installs leiningen project with given name and version on remote host.
204
+ # Retrieve the tarball installation name. This is the name of
205
+ # the tarball without the .tar.gz extension, and the name of the
206
+ # path where it will unpack to.
126
207
  #
127
- # @param [Host] host A single remote host on which to install the
128
- # specified leiningen project.
129
- # @param [String] project_name The name of the project. In ezbake context
130
- # this is the name of both a subdirectory of the ezbake_dir/configs dir
131
- # and the name of the .clj file in that directory which contains the
132
- # project map used by ezbake to create the staging directory.
133
- # @param [String] project_param_string The version of the project specified by
134
- # project_name which is to be built and installed on the remote host.
135
- # @param [String] ezbake_dir The directory to which ezbake should be
136
- # cloned; alternatively, if ezbake is already at that directory, it will
137
- # be updated from its github master before any ezbake operations are
138
- # performed.
139
- #
140
- def install_from_ezbake host, project_name, project_param_string, env_args={}, ezbake_dir='tmp/ezbake'
141
- ezbake_tools_available? host
142
-
143
- if not ezbake_config
144
- ezbake_stage project_name, project_param_string
145
- end
146
-
147
- variant, _, _, _ = host['platform'].to_array
148
-
149
- case variant
150
- when /^(osx|windows|solaris|aix)$/
151
- raise "Beaker::DSL::EZBakeUtils unsupported platform: #{variant}"
152
- end
153
-
208
+ # @return [String] name of the tarball and directory
209
+ # @api private
210
+ def ezbake_install_name
154
211
  ezbake = ezbake_config
155
212
  project_package_version = ezbake[:package_version]
156
213
  project_name = ezbake[:project]
214
+ "%s-%s" % [ project_name, project_package_version ]
215
+ end
157
216
 
158
- ezbake_staging_dir = File.join(ezbake_dir, "target/staging")
159
-
160
- remote_tarball = ""
161
- local_tarball = ""
162
- dir_name = ""
163
-
164
- Dir.chdir(ezbake_staging_dir) do
165
- output = `rake package:tar`
166
-
167
- pattern = "%s-%s"
168
- dir_name = pattern % [
169
- project_name,
170
- project_package_version
171
- ]
172
- local_tarball = "./pkg/" + dir_name + ".tar.gz"
173
- remote_tarball = "/root/" + dir_name + ".tar.gz"
174
-
175
- scp_to host, local_tarball, remote_tarball
176
- end
177
-
178
- # untar tarball on host
179
- on host, "tar -xzf " + remote_tarball
217
+ # Returns the full path to the installed software on the remote host.
218
+ #
219
+ # This only returns the path, it doesn't work out if its installed or
220
+ # not.
221
+ #
222
+ # @return [String] path to the installation dir
223
+ # @api private
224
+ def ezbake_install_dir
225
+ "/root/#{ezbake_install_name}"
226
+ end
180
227
 
181
- # "make" on target
182
- cd_to_package_dir = "cd /root/" + dir_name + "; "
183
- env = ""
184
- if not env_args.empty?
185
- env = "env " + env_args.map {|k, v| "#{k}=#{v} "}.join(' ')
186
- end
187
- on host, cd_to_package_dir + env + "make -e install-" + project_name
188
-
189
- # install init scripts and default settings, perform additional preinst
190
- # TODO: figure out a better way to install init scripts and defaults
191
- case variant
192
- when /^(fedora|el|centos)$/
193
- env += "defaultsdir=/etc/sysconfig "
194
- on host, cd_to_package_dir + env + "make -e install-rpm-sysv-init"
195
- when /^(debian|ubuntu|cumulus)$/
196
- env += "defaultsdir=/etc/default "
197
- on host, cd_to_package_dir + env + "make -e install-deb-sysv-init"
198
- else
199
- raise "No ezbake installation step for #{variant} yet..."
200
- end
228
+ # A helper that wraps the execution of install.sh in the proper
229
+ # ezbake installation directory.
230
+ #
231
+ # @param [Host] host Host to run install.sh on
232
+ # @param [String] task Task to execute with install.sh
233
+ # @api private
234
+ def ezbake_installsh host, task=""
235
+ on host, "cd #{ezbake_install_dir}; bash install.sh #{task}"
201
236
  end
202
237
 
203
238
  # Only clone from given git URI if there is no existing git clone at the
204
239
  # given local_path location.
205
240
  #
206
- # @!visibility private
207
- def conditionally_clone(upstream_uri, local_path)
208
- ezbake_tools_available?
209
- if system "git --work-tree=#{local_path} --git-dir=#{local_path}/.git status"
210
- system "git --work-tree=#{local_path} --git-dir=#{local_path}/.git fetch origin"
211
- system "git --work-tree=#{local_path} --git-dir=#{local_path}/.git checkout origin/HEAD"
241
+ # @param [String] upstream_uri git URI
242
+ # @param [String] local_path path to conditionally install to
243
+ # @param [String] branch to checkout
244
+ # @api private
245
+ def conditionally_clone upstream_uri, local_path, branch="origin/HEAD"
246
+ if ezbake_local_cmd "git --work-tree=#{local_path} --git-dir=#{local_path}/.git status"
247
+ ezbake_local_cmd "git --work-tree=#{local_path} --git-dir=#{local_path}/.git fetch origin"
248
+ ezbake_local_cmd "git --work-tree=#{local_path} --git-dir=#{local_path}/.git checkout #{branch}"
212
249
  else
213
250
  parent_dir = File.dirname(local_path)
214
251
  FileUtils.mkdir_p(parent_dir)
215
- system "git clone #{upstream_uri} #{local_path}"
252
+ ezbake_local_cmd "git clone #{upstream_uri} #{local_path}"
253
+ ezbake_local_cmd "git --work-tree=#{local_path} --git-dir=#{local_path}/.git checkout #{branch}"
216
254
  end
217
255
  end
218
256
 
@@ -553,7 +553,7 @@ module Beaker
553
553
  end
554
554
 
555
555
  begin
556
- backup_file = backup_the_file(host, host['puppetpath'], testdir, 'puppet.conf')
556
+ backup_file = backup_the_file(host, host['puppetconfdir'], testdir, 'puppet.conf')
557
557
  lay_down_new_puppet_conf host, conf_opts, testdir
558
558
 
559
559
  if host.use_service_scripts? && !service_args[:bypass_service_script]
@@ -612,7 +612,7 @@ module Beaker
612
612
 
613
613
  # @!visibility private
614
614
  def restore_puppet_conf_from_backup( host, backup_file )
615
- puppetpath = host['puppetpath']
615
+ puppetpath = host['puppetconfdir']
616
616
  puppet_conf = File.join(puppetpath, "puppet.conf")
617
617
 
618
618
  if backup_file
@@ -693,19 +693,22 @@ module Beaker
693
693
 
694
694
  # @!visibility private
695
695
  def lay_down_new_puppet_conf( host, configuration_options, testdir )
696
+ puppetconf_test = "#{testdir}/puppet.conf"
697
+ puppetconf_main = "#{host['puppetconfdir']}/puppet.conf"
698
+
696
699
  new_conf = puppet_conf_for( host, configuration_options )
697
- create_remote_file host, "#{testdir}/puppet.conf", new_conf.to_s
700
+ create_remote_file host, puppetconf_test, new_conf.to_s
698
701
 
699
702
  host.exec(
700
- Command.new( "cat #{testdir}/puppet.conf > #{host['puppetpath']}/puppet.conf" ),
703
+ Command.new( "cat #{puppetconf_test} > #{puppetconf_main}" ),
701
704
  :silent => true
702
705
  )
703
- host.exec( Command.new( "cat #{host['puppetpath']}/puppet.conf" ) )
706
+ host.exec( Command.new( "cat #{puppetconf_main}" ) )
704
707
  end
705
708
 
706
709
  # @!visibility private
707
710
  def puppet_conf_for host, conf_opts
708
- puppetconf = host.exec( Command.new( "cat #{host['puppetpath']}/puppet.conf" ) ).stdout
711
+ puppetconf = host.exec( Command.new( "cat #{host['puppetconfdir']}/puppet.conf" ) ).stdout
709
712
  new_conf = IniFile.new( puppetconf ).merge( conf_opts )
710
713
 
711
714
  new_conf