beaker 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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