beaker 1.21.0 → 2.0.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 (103) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -0
  4. data/CONTRIBUTING.md +1 -0
  5. data/HISTORY.md +17288 -2
  6. data/Rakefile +6 -2
  7. data/beaker.gemspec +15 -19
  8. data/lib/beaker.rb +2 -5
  9. data/lib/beaker/answers.rb +2 -0
  10. data/lib/beaker/answers/version34.rb +37 -1
  11. data/lib/beaker/cli.rb +4 -0
  12. data/lib/beaker/command.rb +16 -84
  13. data/lib/beaker/command_factory.rb +13 -2
  14. data/lib/beaker/dsl/assertions.rb +25 -2
  15. data/lib/beaker/dsl/ezbake_utils.rb +2 -2
  16. data/lib/beaker/dsl/helpers.rb +66 -12
  17. data/lib/beaker/dsl/install_utils.rb +128 -66
  18. data/lib/beaker/dsl/wrappers.rb +41 -3
  19. data/lib/beaker/host.rb +42 -6
  20. data/lib/beaker/host/mac.rb +62 -0
  21. data/lib/beaker/host/mac/group.rb +96 -0
  22. data/lib/beaker/host/mac/user.rb +93 -0
  23. data/lib/beaker/host/unix/exec.rb +1 -1
  24. data/lib/beaker/host/unix/pkg.rb +11 -11
  25. data/lib/beaker/host/windows.rb +4 -4
  26. data/lib/beaker/host_prebuilt_steps.rb +194 -58
  27. data/lib/beaker/hypervisor.rb +16 -9
  28. data/lib/beaker/hypervisor/aws_sdk.rb +61 -17
  29. data/lib/beaker/hypervisor/docker.rb +14 -2
  30. data/lib/beaker/hypervisor/ec2_helper.rb +15 -3
  31. data/lib/beaker/hypervisor/vagrant.rb +22 -10
  32. data/lib/beaker/hypervisor/vagrant_libvirt.rb +11 -0
  33. data/lib/beaker/hypervisor/vagrant_virtualbox.rb +1 -1
  34. data/lib/beaker/hypervisor/vcloud_pooled.rb +8 -39
  35. data/lib/beaker/logger.rb +15 -9
  36. data/lib/beaker/network_manager.rb +2 -2
  37. data/lib/beaker/options/command_line_parser.rb +1 -1
  38. data/lib/beaker/options/parser.rb +1 -8
  39. data/lib/beaker/options/presets.rb +70 -45
  40. data/lib/beaker/perf.rb +3 -4
  41. data/lib/beaker/platform.rb +2 -1
  42. data/lib/beaker/result.rb +3 -9
  43. data/lib/beaker/ssh_connection.rb +2 -0
  44. data/lib/beaker/test_case.rb +2 -21
  45. data/lib/beaker/test_suite.rb +21 -25
  46. data/lib/beaker/version.rb +1 -1
  47. data/spec/beaker/answers_spec.rb +36 -0
  48. data/spec/beaker/cli_spec.rb +45 -45
  49. data/spec/beaker/command_spec.rb +25 -36
  50. data/spec/beaker/dsl/assertions_spec.rb +20 -27
  51. data/spec/beaker/dsl/ezbake_utils_spec.rb +5 -5
  52. data/spec/beaker/dsl/helpers_spec.rb +293 -208
  53. data/spec/beaker/dsl/install_utils_spec.rb +310 -189
  54. data/spec/beaker/dsl/outcomes_spec.rb +6 -6
  55. data/spec/beaker/dsl/roles_spec.rb +27 -18
  56. data/spec/beaker/dsl/structure_spec.rb +11 -11
  57. data/spec/beaker/dsl/wrappers_spec.rb +35 -11
  58. data/spec/beaker/host/mac/group_spec.rb +124 -0
  59. data/spec/beaker/host/mac/user_spec.rb +134 -0
  60. data/spec/beaker/host/unix/pkg_spec.rb +40 -24
  61. data/spec/beaker/host/windows/group_spec.rb +1 -1
  62. data/spec/beaker/host_prebuilt_steps_spec.rb +194 -68
  63. data/spec/beaker/host_spec.rb +145 -67
  64. data/spec/beaker/hypervisor/aixer_spec.rb +6 -6
  65. data/spec/beaker/hypervisor/aws_sdk_spec.rb +22 -7
  66. data/spec/beaker/hypervisor/docker_spec.rb +71 -50
  67. data/spec/beaker/hypervisor/ec2_helper_spec.rb +25 -4
  68. data/spec/beaker/hypervisor/fusion_spec.rb +2 -2
  69. data/spec/beaker/hypervisor/hypervisor_spec.rb +20 -27
  70. data/spec/beaker/hypervisor/hypervisor_spec.rb.orig +80 -0
  71. data/spec/beaker/hypervisor/solaris_spec.rb +8 -8
  72. data/spec/beaker/hypervisor/vagrant_fusion_spec.rb +6 -8
  73. data/spec/beaker/hypervisor/vagrant_libvirt_spec.rb +34 -0
  74. data/spec/beaker/hypervisor/vagrant_spec.rb +34 -33
  75. data/spec/beaker/hypervisor/vagrant_virtualbox_spec.rb +18 -8
  76. data/spec/beaker/hypervisor/vagrant_workstation_spec.rb +6 -8
  77. data/spec/beaker/hypervisor/vcloud_pooled_spec.rb +8 -8
  78. data/spec/beaker/hypervisor/vcloud_spec.rb +10 -10
  79. data/spec/beaker/hypervisor/vsphere_helper_spec.rb +8 -8
  80. data/spec/beaker/hypervisor/vsphere_spec.rb +1 -1
  81. data/spec/beaker/logger_spec.rb +45 -31
  82. data/spec/beaker/options/command_line_parser_spec.rb +10 -2
  83. data/spec/beaker/options/hosts_file_parser_spec.rb +9 -2
  84. data/spec/beaker/options/options_hash_spec.rb +2 -2
  85. data/spec/beaker/options/parser_spec.rb +2 -2
  86. data/spec/beaker/options/pe_version_scaper_spec.rb +6 -1
  87. data/spec/beaker/options/presets_spec.rb +11 -1
  88. data/spec/beaker/shared/error_handler_spec.rb +5 -5
  89. data/spec/beaker/shared/host_manager_spec.rb +3 -2
  90. data/spec/beaker/shared/repetition_spec.rb +18 -18
  91. data/spec/beaker/ssh_connection_spec.rb +33 -4
  92. data/spec/beaker/test_case_spec.rb +9 -9
  93. data/spec/beaker/test_suite_spec.rb +14 -14
  94. data/spec/helpers.rb +4 -4
  95. data/spec/matchers.rb +4 -4
  96. data/spec/mocks.rb +5 -1
  97. data/spec/spec_helper.rb +2 -8
  98. metadata +114 -80
  99. data/lib/beaker/hypervisor/blimper.rb +0 -108
  100. data/spec/beaker/hypervisor/blimper_spec.rb +0 -42
  101. data/spec/beaker/options/data/LATEST +0 -1
  102. data/spec/beaker/puppet_command_spec.rb +0 -161
  103. data/spec/mock_blimpy.rb +0 -48
@@ -14,10 +14,11 @@ module Beaker
14
14
  WINDOWS_PACKAGES = ['curl']
15
15
  SLES_PACKAGES = ['curl', 'ntp']
16
16
  DEBIAN_PACKAGES = ['curl', 'ntpdate', 'lsb-release']
17
+ CUMULUS_PACKAGES = ['addons', 'ntpdate', 'lsb-release']
17
18
  ETC_HOSTS_PATH = "/etc/hosts"
18
19
  ETC_HOSTS_PATH_SOLARIS = "/etc/inet/hosts"
19
20
  ROOT_KEYS_SCRIPT = "https://raw.githubusercontent.com/puppetlabs/puppetlabs-sshkeys/master/templates/scripts/manage_root_authorized_keys"
20
- ROOT_KEYS_SYNC_CMD = "curl -k -o - -L #{ROOT_KEYS_SCRIPT} | %s"
21
+ ROOT_KEYS_SYNC_CMD = "curl -k -o - -L #{ROOT_KEYS_SCRIPT} %s"
21
22
  APT_CFG = %q{ Acquire::http::Proxy "http://proxy.puppetlabs.net:3128/"; }
22
23
  IPS_PKG_REPO="http://solaris-11-internal-repo.delivery.puppetlabs.net"
23
24
 
@@ -66,11 +67,15 @@ module Beaker
66
67
  report_and_raise(logger, e, "timesync (--ntp)")
67
68
  end
68
69
 
69
- #Validate that hosts are prepared to be used as SUTs, if packages are missing attempt to
70
- #install them. Verifies the presence of #{HostPrebuiltSteps::UNIX_PACKAGES} on unix platform hosts,
71
- #{HostPrebuiltSteps::SLES_PACKAGES} on SUSE platform hosts, #{HostPrebuiltSteps::DEBIAN_PACKAGES on debian platform
72
- #hosts and {HostPrebuiltSteps::WINDOWS_PACKAGES} on windows
73
- #platforms.
70
+ # Validate that hosts are prepared to be used as SUTs, if packages are missing attempt to
71
+ # install them.
72
+ #
73
+ # Verifies the presence of #{HostPrebuiltSteps::UNIX_PACKAGES} on unix platform hosts,
74
+ # {HostPrebuiltSteps::SLES_PACKAGES} on SUSE platform hosts,
75
+ # {HostPrebuiltSteps::DEBIAN_PACKAGES} on debian platform hosts,
76
+ # {HostPrebuiltSteps::CUMULUS_PACKAGES} on cumulus platform hosts,
77
+ # and {HostPrebuiltSteps::WINDOWS_PACKAGES} on windows platform hosts.
78
+ #
74
79
  # @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon
75
80
  # @param [Hash{Symbol=>String}] opts Options to alter execution.
76
81
  # @option opts [Beaker::Logger] :logger A {Beaker::Logger} object
@@ -79,35 +84,33 @@ module Beaker
79
84
  block_on host do |host|
80
85
  case
81
86
  when host['platform'] =~ /sles-/
82
- SLES_PACKAGES.each do |pkg|
83
- if not host.check_for_package pkg
84
- host.install_package pkg
85
- end
86
- end
87
+ check_and_install_packages_if_needed(host, SLES_PACKAGES)
87
88
  when host['platform'] =~ /debian/
88
- DEBIAN_PACKAGES.each do |pkg|
89
- if not host.check_for_package pkg
90
- host.install_package pkg
91
- end
92
- end
89
+ check_and_install_packages_if_needed(host, DEBIAN_PACKAGES)
90
+ when host['platform'] =~ /cumulus/
91
+ check_and_install_packages_if_needed(host, CUMULUS_PACKAGES)
93
92
  when host['platform'] =~ /windows/
94
- WINDOWS_PACKAGES.each do |pkg|
95
- if not host.check_for_package pkg
96
- host.install_package pkg
97
- end
98
- end
99
- when host['platform'] !~ /debian|aix|solaris|windows|sles-|osx-/
100
- UNIX_PACKAGES.each do |pkg|
101
- if not host.check_for_package pkg
102
- host.install_package pkg
103
- end
104
- end
93
+ check_and_install_packages_if_needed(host, WINDOWS_PACKAGES)
94
+ when host['platform'] !~ /debian|aix|solaris|windows|sles-|osx-|cumulus/
95
+ check_and_install_packages_if_needed(host, UNIX_PACKAGES)
105
96
  end
106
97
  end
107
98
  rescue => e
108
99
  report_and_raise(logger, e, "validate")
109
100
  end
110
101
 
102
+ # Installs the given packages if they aren't already on a host
103
+ #
104
+ # @param [Host] host Host to act on
105
+ # @param [Array<String>] package_list List of package names to install
106
+ def check_and_install_packages_if_needed host, package_list
107
+ package_list.each do |pkg|
108
+ if not host.check_for_package pkg
109
+ host.install_package pkg
110
+ end
111
+ end
112
+ end
113
+
111
114
  #Install a set of authorized keys using {HostPrebuiltSteps::ROOT_KEYS_SCRIPT}. This is a
112
115
  #convenience method to allow for easy login to hosts after they have been provisioned with
113
116
  #Beaker.
@@ -124,9 +127,17 @@ module Beaker
124
127
  logger.notify "Sync root authorized_keys from github on #{host.name}"
125
128
  # Allow all exit code, as this operation is unlikely to cause problems if it fails.
126
129
  if host['platform'].include? 'solaris'
127
- host.exec(Command.new(ROOT_KEYS_SYNC_CMD % "bash"), :acceptable_exit_codes => (0..255))
130
+ host.exec(Command.new(ROOT_KEYS_SYNC_CMD % "| bash"), :acceptable_exit_codes => (0..255))
131
+ elsif host['platform'].include? 'eos'
132
+ # this is a terrible terrible thing that I'm already in the process of fixing
133
+ # the only reason that I include this terrible implementation is that the
134
+ # fix relies on changes in another repo, so I'm not sure how long it'll take
135
+ # to get those in
136
+ host.exec(Command.new(ROOT_KEYS_SYNC_CMD % "> manage_root_authorized_keys"), :acceptable_exit_codes => (0..255))
137
+ host.exec(Command.new("sed -i 's|mv -f $SSH_HOME/authorized_keys.tmp $SSH_HOME/authorized_keys|cp -f $SSH_HOME/authorized_keys.tmp $SSH_HOME/authorized_keys|' manage_root_authorized_keys"), :acceptable_exit_codes => (0..255))
138
+ host.exec(Command.new("bash manage_root_authorized_keys"), :acceptable_exit_codes => (0..255))
128
139
  else
129
- host.exec(Command.new(ROOT_KEYS_SYNC_CMD % "env PATH=/usr/gnu/bin:$PATH bash"), :acceptable_exit_codes => (0..255))
140
+ host.exec(Command.new(ROOT_KEYS_SYNC_CMD % "| env PATH=/usr/gnu/bin:$PATH bash"), :acceptable_exit_codes => (0..255))
130
141
  end
131
142
  end
132
143
  rescue => e
@@ -144,10 +155,11 @@ module Beaker
144
155
  # @option opts [String] :epel_5_pkg Package to download from provided link for el-5
145
156
  # @raise [Exception] Raises an error if the host provided's platform != /el-(5|6)/
146
157
  def epel_info_for host, opts
147
- version = host['platform'].version
148
- if not version
149
- raise "epel_info_for not available for #{host.name} on platform #{host['platform']}"
158
+ if !el_based?(host)
159
+ raise "epel_info_for! not available for #{host.name} on platform #{host['platform']}"
150
160
  end
161
+
162
+ version = host['platform'].version
151
163
  if version == '6'
152
164
  url = "#{host[:epel_url] || opts[:epel_url]}/#{version}"
153
165
  pkg = host[:epel_pkg] || opts[:epel_6_pkg]
@@ -160,12 +172,13 @@ module Beaker
160
172
  return url, host[:epel_arch] || opts[:epel_arch] || 'i386', pkg
161
173
  end
162
174
 
163
- #Run 'apt-get update' on the provided host or hosts. If the platform of the provided host is not
164
- #ubuntu or debian do nothing.
175
+ # Run 'apt-get update' on the provided host or hosts.
176
+ # If the platform of the provided host is not ubuntu, debian or cumulus: do nothing.
177
+ #
165
178
  # @param [Host, Array<Host>] hosts One or more hosts to act upon
166
179
  def apt_get_update hosts
167
180
  block_on hosts do |host|
168
- if host[:platform] =~ /(ubuntu)|(debian)/
181
+ if host[:platform] =~ /ubuntu|debian|cumulus/
169
182
  host.exec(Command.new("apt-get update"))
170
183
  end
171
184
  end
@@ -185,24 +198,21 @@ module Beaker
185
198
  end
186
199
  end
187
200
 
188
- #Alter apt configuration on ubuntu and debian host or hosts to internal Puppet Labs
189
- # proxy {HostPrebuiltSteps::APT_CFG} proxy, alter pkg on solaris-11 host or hosts
190
- # to point to interal Puppetlabs proxy {HostPrebuiltSteps::IPS_PKG_REPO}. Do nothing
191
- # on non-ubuntu, debian or solaris-11 platform host or hosts.
201
+ # On ubuntu, debian, or cumulus host or hosts: alter apt configuration to use
202
+ # the internal Puppet Labs proxy {HostPrebuiltSteps::APT_CFG} proxy.
203
+ # On solaris-11 host or hosts: alter pkg to point to
204
+ # the internal Puppet Labs proxy {HostPrebuiltSteps::IPS_PKG_REPO}.
205
+ #
206
+ # Do nothing for other platform host or hosts.
207
+ #
192
208
  # @param [Host, Array<Host>] host One or more hosts to act upon
193
209
  # @param [Hash{Symbol=>String}] opts Options to alter execution.
194
210
  # @option opts [Beaker::Logger] :logger A {Beaker::Logger} object
195
211
  def proxy_config( host, opts )
196
- # repo_proxy
197
- # supports ubuntu, debian and solaris platforms
198
212
  logger = opts[:logger]
199
213
  block_on host do |host|
200
214
  case
201
- when host['platform'] =~ /ubuntu/
202
- host.exec(Command.new("if test -f /etc/apt/apt.conf; then mv /etc/apt/apt.conf /etc/apt/apt.conf.bk; fi"))
203
- copy_file_to_remote(host, '/etc/apt/apt.conf', APT_CFG)
204
- apt_get_update(host)
205
- when host['platform'] =~ /debian/
215
+ when host['platform'] =~ /ubuntu|debian|cumulus/
206
216
  host.exec(Command.new("if test -f /etc/apt/apt.conf; then mv /etc/apt/apt.conf /etc/apt/apt.conf.bk; fi"))
207
217
  copy_file_to_remote(host, '/etc/apt/apt.conf', APT_CFG)
208
218
  apt_get_update(host)
@@ -234,7 +244,7 @@ module Beaker
234
244
  debug_opt = opts[:debug] ? 'vh' : ''
235
245
  block_on host do |host|
236
246
  case
237
- when host['platform'] =~ /el-(5|6)/
247
+ when el_based?(host) && ['5','6'].include?(host['platform'].version)
238
248
  result = host.exec(Command.new('rpm -qa | grep epel-release'), :acceptable_exit_codes => [0,1])
239
249
  if result.exit_code == 1
240
250
  url, arch, pkg = epel_info_for host, opts
@@ -316,7 +326,10 @@ module Beaker
316
326
  end
317
327
  end
318
328
 
319
- #Update sshd_config on debian, ubuntu, centos, el, redhat and fedora boxes to allow for root login, does nothing on other platfoms
329
+ # Update sshd_config on debian, ubuntu, centos, el, redhat, cumulus, and fedora boxes to allow for root login
330
+ #
331
+ # Does nothing on other platfoms.
332
+ #
320
333
  # @param [Host, Array<Host>] host One or more hosts to act upon
321
334
  # @param [Hash{Symbol=>String}] opts Options to alter execution.
322
335
  # @option opts [Beaker::Logger] :logger A {Beaker::Logger} object
@@ -324,13 +337,14 @@ module Beaker
324
337
  logger = opts[:logger]
325
338
  block_on host do |host|
326
339
  logger.debug "Update /etc/ssh/sshd_config to allow root login"
327
- host.exec(Command.new("sudo su -c \"sed -i 's/PermitRootLogin no/PermitRootLogin yes/' /etc/ssh/sshd_config\""), {:pty => true}
328
- )
340
+ # note: this sed command only works on gnu sed
341
+ host.exec(Command.new("sudo su -c \"sed -ri 's/^#?PermitRootLogin no|^#?PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config\""), {:pty => true}
342
+ )
329
343
  #restart sshd
330
- if host['platform'] =~ /debian|ubuntu/
344
+ if host['platform'] =~ /debian|ubuntu|cumulus/
331
345
  host.exec(Command.new("sudo su -c \"service ssh restart\""), {:pty => true})
332
- elsif host['platform'] =~ /centos|el-|redhat|fedora/
333
- host.exec(Command.new("sudo su -c \"service sshd restart\""), {:pty => true})
346
+ elsif host['platform'] =~ /centos|el-|redhat|fedora|eos/
347
+ host.exec(Command.new("sudo -E service sshd restart"))
334
348
  else
335
349
  @logger.warn("Attempting to update ssh on non-supported platform: #{host.name}: #{host['platform']}")
336
350
  end
@@ -344,7 +358,7 @@ module Beaker
344
358
  def disable_se_linux host, opts
345
359
  logger = opts[:logger]
346
360
  block_on host do |host|
347
- if host['platform'] =~ /centos|el-|redhat|fedora/
361
+ if host['platform'] =~ /centos|el-|redhat|fedora|eos/
348
362
  @logger.debug("Disabling se_linux on #{host.name}")
349
363
  host.exec(Command.new("sudo su -c \"setenforce 0\""), {:pty => true})
350
364
  else
@@ -360,7 +374,7 @@ module Beaker
360
374
  def disable_iptables host, opts
361
375
  logger = opts[:logger]
362
376
  block_on host do |host|
363
- if host['platform'] =~ /centos|el-|redhat|fedora/
377
+ if host['platform'] =~ /centos|el-|redhat|fedora|eos/
364
378
  logger.debug("Disabling iptables on #{host.name}")
365
379
  host.exec(Command.new("sudo su -c \"/etc/init.d/iptables stop\""), {:pty => true})
366
380
  else
@@ -370,7 +384,7 @@ module Beaker
370
384
  end
371
385
 
372
386
  # Setup files for enabling requests to pass to a proxy server
373
- # This works for the APT package manager on debian and ubuntu
387
+ # This works for the APT package manager on debian, ubuntu, and cumulus
374
388
  # and YUM package manager on el, centos, fedora and redhat.
375
389
  # @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon
376
390
  # @param [Hash{Symbol=>String}] opts Options to alter execution.
@@ -381,9 +395,9 @@ module Beaker
381
395
  block_on host do |host|
382
396
  logger.debug("enabling proxy support on #{host.name}")
383
397
  case host['platform']
384
- when /ubuntu/, /debian/
398
+ when /ubuntu/, /debian/, /cumulus/
385
399
  host.exec(Command.new("echo 'Acquire::http::Proxy \"#{opts[:package_proxy]}/\";' >> /etc/apt/apt.conf.d/10proxy"))
386
- when /^el-/, /centos/, /fedora/, /redhat/
400
+ when /^el-/, /centos/, /fedora/, /redhat/, /eos/
387
401
  host.exec(Command.new("echo 'proxy=#{opts[:package_proxy]}/' >> /etc/yum.conf"))
388
402
  else
389
403
  logger.debug("Attempting to enable package manager proxy support on non-supported platform: #{host.name}: #{host['platform']}")
@@ -391,6 +405,128 @@ module Beaker
391
405
  end
392
406
  end
393
407
 
408
+
409
+ # Merge the two provided hashes so that an array of values is created from collisions
410
+ # @param [Hash] h1 The first hash
411
+ # @param [Hash] h2 The second hash
412
+ # @return [Hash] A merged hash with arrays of values where collisions between the two hashes occured.
413
+ # @example
414
+ # > h1 = {:PATH=>"/1st/path"}
415
+ # > h2 = {:PATH=>"/2nd/path"}
416
+ # > additive_hash_merge(h1, h2)
417
+ # => {:PATH=>["/1st/path", "/2nd/path"]}
418
+ def additive_hash_merge h1, h2
419
+ merged_hash = {}
420
+ normalized_h2 = h2.inject({}) { |h, (k, v)| h[k.to_s.upcase] = v; h }
421
+ h1.each_pair do |key, val|
422
+ normalized_key = key.to_s.upcase
423
+ if normalized_h2.has_key?(normalized_key)
424
+ merged_hash[key] = [h1[key], normalized_h2[normalized_key]]
425
+ merged_hash[key] = merged_hash[key].uniq #remove dupes
426
+ end
427
+ end
428
+ merged_hash
429
+ end
430
+
431
+ # 'echo' the provided value on the given host
432
+ # @param [Host] host The host to execute the 'echo' on
433
+ # @param [String] val The string to 'echo' on the host
434
+ def echo_on_host host, val
435
+ #val = val.gsub(/"/, "\"").gsub(/\(/, "\(")
436
+ host.exec(Command.new("echo \"#{val}\"")).stdout.chomp
437
+ end
438
+
439
+ # Create the hash of default environment from host (:host_env), global options hash (:host_env) and default PE/Foss puppet variables
440
+ # @param [Host] host The host to construct the environment hash for, host specific environment should be in :host_env in a hash
441
+ # @param [Hash] opts Hash of options, including optional global host_env to be applied to each provided host
442
+ # @return [Hash] A hash of environment variables for provided host
443
+ def construct_env host, opts
444
+ env = additive_hash_merge(host[:host_env], opts[:host_env])
445
+
446
+ #Add PATH and RUBYLIB
447
+
448
+ #prepend any PATH already set for this host
449
+
450
+ env['PATH'] = (%w(puppetbindir facterbindir hierabindir) << env['PATH']).compact.reject(&:empty?)
451
+ #get the PATH defaults
452
+ env['PATH'].map! { |val| host[val] }
453
+ env['PATH'] = env['PATH'].compact.reject(&:empty?)
454
+ #run the paths through echo to see if they have any subcommands that need processing
455
+ env['PATH'].map! { |val| echo_on_host(host, val) }
456
+
457
+ #prepend any RUBYLIB already set for this host
458
+ env['RUBYLIB'] = (%w(hieralibdir hierapuppetlibdir pluginlibpath puppetlibdir facterlibdir) << env['RUBYLIB']).compact.reject(&:empty?)
459
+ #get the RUBYLIB defaults
460
+ env['RUBYLIB'].map! { |val| host[val] }
461
+ env['RUBYLIB'] = env['RUBYLIB'].compact.reject(&:empty?)
462
+ #run the paths through echo to see if they have any subcommands that need processing
463
+ env['RUBYLIB'].map! { |val| echo_on_host(host, val) }
464
+
465
+ env.each_key do |key|
466
+ env[key] = env[key].join(':')
467
+ end
468
+ env
469
+ end
470
+
471
+ # Add a host specific set of env vars to each provided host's ~/.ssh/environment
472
+ # @param [Host, Array<Host>] host One or more hosts to act upon
473
+ # @param [Hash{Symbol=>String}] opts Options to alter execution.
474
+ def set_env host, opts
475
+ logger = opts[:logger]
476
+
477
+ block_on host do |host|
478
+ env = construct_env(host, opts)
479
+ logger.debug("setting local environment on #{host.name}")
480
+ case host['platform']
481
+ when /windows/
482
+ host.exec(Command.new("echo 'PermitUserEnvironment yes' >> /etc/sshd_config"))
483
+ host.exec(Command.new("cygrunsrv -E sshd"))
484
+ host.exec(Command.new("cygrunsrv -S sshd"))
485
+ env['CYGWIN'] = 'nodosfilewarning'
486
+ when /osx/
487
+ host.exec(Command.new("echo 'PermitUserEnvironment yes' >> /etc/sshd_config"))
488
+ host.exec(Command.new("launchctl unload /System/Library/LaunchDaemons/ssh.plist"))
489
+ host.exec(Command.new("launchctl load /System/Library/LaunchDaemons/ssh.plist"))
490
+ when /debian|ubuntu|cumulus/
491
+ host.exec(Command.new("echo 'PermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
492
+ host.exec(Command.new("service ssh restart"))
493
+ when /el-|centos|fedora|redhat|oracle|scientific|eos/
494
+ host.exec(Command.new("echo 'PermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
495
+ host.exec(Command.new("service sshd restart"))
496
+ when /sles/
497
+ host.exec(Command.new("echo 'PermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
498
+ host.exec(Command.new("rcsshd restart"))
499
+ when /solaris/
500
+ host.exec(Command.new("echo 'PermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
501
+ host.exec(Command.new("svcadm restart svc:/network/ssh:default"))
502
+ when /aix/
503
+ host.exec(Command.new("echo 'PermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
504
+ host.exec(Command.new("stopsrc -g ssh"))
505
+ host.exec(Command.new("startsrc -g ssh"))
506
+ end
507
+ #ensure that ~/.ssh/environment exists
508
+ host.exec(Command.new("touch #{host[:ssh_env_file]}"))
509
+ #add the constructed env vars to this host
510
+ host.add_env_var('RUBYLIB', '$RUBYLIB')
511
+ host.add_env_var('PATH', '$PATH')
512
+ env.each_pair do |var, value|
513
+ host.add_env_var(var, value)
514
+ end
515
+ #close the host to re-establish the connection with the new sshd settings
516
+ host.close
517
+ end
518
+ end
519
+
520
+ private
521
+
522
+ # A helper to tell whether a host is el-based
523
+ # @param [Host] host the host to act upon
524
+ #
525
+ # @return [Boolean] if the host is el_based
526
+ def el_based? host
527
+ ['centos','redhat','scientific','el','oracle'].include?(host['platform'].variant)
528
+ end
529
+
394
530
  end
395
531
 
396
532
  end
@@ -28,8 +28,6 @@ module Beaker
28
28
  Beaker::Vsphere
29
29
  when /^fusion$/
30
30
  Beaker::Fusion
31
- when /^blimpy$/
32
- Beaker::Blimper
33
31
  when /^ec2$/
34
32
  Beaker::AwsSdk
35
33
  when /^vcloud$/
@@ -40,6 +38,8 @@ module Beaker
40
38
  end
41
39
  when /^vagrant$/
42
40
  Beaker::Vagrant
41
+ when /^vagrant_libvirt$/
42
+ Beaker::VagrantLibvirt
43
43
  when /^vagrant_virtualbox$/
44
44
  Beaker::VagrantVirtualbox
45
45
  when /^vagrant_fusion$/
@@ -61,7 +61,7 @@ module Beaker
61
61
  rescue LoadError
62
62
  raise "Invalid hypervisor: #{type}"
63
63
  end
64
- const_get("Beaker::#{type.capitalize}")
64
+ Beaker.const_get(type.capitalize)
65
65
  end
66
66
 
67
67
  hypervisor = hyper_class.new(hosts_to_provision, options)
@@ -85,7 +85,15 @@ module Beaker
85
85
  nil
86
86
  end
87
87
 
88
- #Default configuration steps to be run for a given hypervisor
88
+ #Proxy package managers on tests hosts created by this hypervisor, runs before validation and configuration.
89
+ def proxy_package_manager
90
+ if @options[:package_proxy]
91
+ package_proxy(@hosts, @options)
92
+ end
93
+ end
94
+
95
+ #Default configuration steps to be run for a given hypervisor. Any additional configuration to be done
96
+ #to the provided SUT for test execution to be successful.
89
97
  def configure
90
98
  if @options[:timesync]
91
99
  timesync(@hosts, @options)
@@ -96,15 +104,14 @@ module Beaker
96
104
  if @options[:add_el_extras]
97
105
  add_el_extras(@hosts, @options)
98
106
  end
99
- if @options[:package_proxy]
100
- package_proxy(@hosts, @options)
101
- end
102
107
  if @options[:disable_iptables]
103
108
  disable_iptables @hosts, @options
104
109
  end
110
+ set_env(@hosts, @options)
105
111
  end
106
112
 
107
- #Default validation steps to be run for a given hypervisor
113
+ #Default validation steps to be run for a given hypervisor. Ensures that SUTs meet requirements to be
114
+ #beaker test nodes.
108
115
  def validate
109
116
  if @options[:validate]
110
117
  validate_host(@hosts, @options)
@@ -119,6 +126,6 @@ module Beaker
119
126
  end
120
127
  end
121
128
 
122
- [ 'vsphere_helper', 'vagrant', 'vagrant_virtualbox', 'vagrant_fusion', 'vagrant_workstation', 'fusion', 'blimper', 'aws_sdk', 'vsphere', 'vcloud', 'vcloud_pooled', 'aixer', 'solaris', 'docker', 'google_compute', 'openstack' ].each do |lib|
129
+ [ 'vsphere_helper', 'vagrant', 'vagrant_virtualbox', 'vagrant_libvirt', 'vagrant_fusion', 'vagrant_workstation', 'fusion', 'aws_sdk', 'vsphere', 'vcloud', 'vcloud_pooled', 'aixer', 'solaris', 'docker', 'google_compute', 'openstack' ].each do |lib|
123
130
  require "beaker/hypervisor/#{lib}"
124
131
  end
@@ -55,6 +55,9 @@ module Beaker
55
55
  # Grab the ip addresses and dns from EC2 for each instance to use for ssh
56
56
  populate_dns()
57
57
 
58
+ #enable root if user is not root
59
+ enable_root_on_hosts()
60
+
58
61
  # Set the hostname for each box
59
62
  set_hostnames()
60
63
 
@@ -88,10 +91,12 @@ module Beaker
88
91
  nil #void
89
92
  end
90
93
 
91
- #Print instances to the logger. Instances will be from all regions associated with provided key name and
92
- #limited by regex compared to instance status. Defaults to running instances.
93
- #@param [String] key The key_name to match for
94
- #@param [Regex] status The regular expression to match against the instance's status
94
+ # Print instances to the logger. Instances will be from all regions
95
+ # associated with provided key name and limited by regex compared to
96
+ # instance status. Defaults to running instances.
97
+ #
98
+ # @param [String] key The key_name to match for
99
+ # @param [Regex] status The regular expression to match against the instance's status
95
100
  def log_instances(key = key_name, status = /running/)
96
101
  instances = []
97
102
  @ec2.regions.each do |region|
@@ -110,9 +115,11 @@ module Beaker
110
115
  @logger.notify("#{output}")
111
116
  end
112
117
 
113
- #Shutdown and destroy ec2 instances idenfitied by key that have been alive longer than ZOMBIE hours.
114
- #@param [Integer] max_age The age in hours that a machine needs to be older than to be considered a zombie
115
- #@param [String] key The key_name to match for
118
+ # Shutdown and destroy ec2 instances idenfitied by key that have been alive
119
+ # longer than ZOMBIE hours.
120
+ #
121
+ # @param [Integer] max_age The age in hours that a machine needs to be older than to be considered a zombie
122
+ # @param [String] key The key_name to match for
116
123
  def kill_zombies(max_age = ZOMBIE, key = key_name)
117
124
  @logger.notify("aws-sdk: Kill Zombies! (keyname: #{key}, age: #{max_age} hrs)")
118
125
  #examine all available regions
@@ -176,6 +183,12 @@ module Beaker
176
183
  @hosts.each do |host|
177
184
  amitype = host['vmname'] || host['platform']
178
185
  amisize = host['amisize'] || 'm1.small'
186
+ subnet_id = host['subnet_id'] || nil
187
+ vpc_id = host['vpc_id'] || nil
188
+
189
+ if vpc_id and !subnet_id
190
+ raise RuntimeError, "A subnet_id must be provided with a vpc_id"
191
+ end
179
192
 
180
193
  # Use snapshot provided for this host
181
194
  image_type = host['snapshot']
@@ -188,6 +201,9 @@ module Beaker
188
201
  # Main region object for ec2 operations
189
202
  region = @ec2.regions[ami_region]
190
203
 
204
+ # Obtain the VPC object if it exists
205
+ vpc = vpc_id ? region.vpcs[vpc_id] : nil
206
+
191
207
  # Grab image object
192
208
  image_id = ami[:image][image_type.to_sym]
193
209
  @logger.notify("aws-sdk: Checking image #{image_id} exists and getting its root device")
@@ -220,11 +236,12 @@ module Beaker
220
236
  :image_id => image_id,
221
237
  :monitoring_enabled => true,
222
238
  :key_pair => ensure_key_pair(region),
223
- :security_groups => [ensure_group(region, Beaker::EC2Helper.amiports(host['roles']))],
239
+ :security_groups => [ensure_group(vpc || region, Beaker::EC2Helper.amiports(host))],
224
240
  :instance_type => amisize,
225
241
  :disable_api_termination => false,
226
242
  :instance_initiated_shutdown_behavior => "terminate",
227
243
  :block_device_mappings => block_device_mappings,
244
+ :subnet => subnet_id,
228
245
  }
229
246
  instance = region.instances.create(config)
230
247
 
@@ -273,7 +290,7 @@ module Beaker
273
290
  end
274
291
  end
275
292
 
276
- #Add metadata tags to all instances
293
+ # Add metadata tags to all instances
277
294
  #
278
295
  # @return [void]
279
296
  # @api private
@@ -334,6 +351,29 @@ module Beaker
334
351
  end
335
352
  end
336
353
 
354
+ # Enables root for instances with custom username like ubuntu-amis
355
+ #
356
+ # @return [void]
357
+ # @api private
358
+ def enable_root_on_hosts
359
+ @hosts.each do |host|
360
+ enable_root(host)
361
+ end
362
+ end
363
+
364
+ # Enables root access for a host when username is not root
365
+ #
366
+ # @return [void]
367
+ # @api private
368
+ def enable_root(host)
369
+ if host['user'] != 'root'
370
+ copy_ssh_to_root(host, @options)
371
+ enable_root_login(host, @options)
372
+ host['user'] = 'root'
373
+ host.close
374
+ end
375
+ end
376
+
337
377
  # Set the hostname of all instances to be the hostname defined in the
338
378
  # beaker configuration.
339
379
  #
@@ -431,18 +471,20 @@ module Beaker
431
471
 
432
472
  # Return an existing group, or create new one
433
473
  #
434
- # @param region [AWS::EC2::Region] the AWS region control object
474
+ # Accepts a region or VPC as input for checking & creation.
475
+ #
476
+ # @param rv [AWS::EC2::Region, AWS::EC2::VPC] the AWS region or vpc control object
435
477
  # @param ports [Array<Number>] an array of port numbers
436
478
  # @return [AWS::EC2::SecurityGroup] created security group
437
479
  # @api private
438
- def ensure_group(region, ports)
480
+ def ensure_group(rv, ports)
439
481
  @logger.notify("aws-sdk: Ensure security group exists for ports #{ports.to_s}, create if not")
440
482
  name = group_id(ports)
441
483
 
442
- group = region.security_groups.filter('group-name', name).first
484
+ group = rv.security_groups.filter('group-name', name).first
443
485
 
444
486
  if group.nil?
445
- group = create_group(region, ports)
487
+ group = create_group(rv, ports)
446
488
  end
447
489
 
448
490
  group
@@ -450,15 +492,17 @@ module Beaker
450
492
 
451
493
  # Create a new security group
452
494
  #
453
- # @param region [AWS::EC2::Region] the AWS region control object
495
+ # Accepts a region or VPC for group creation.
496
+ #
497
+ # @param rv [AWS::EC2::Region, AWS::EC2::VPC] the AWS region or vpc control object
454
498
  # @param ports [Array<Number>] an array of port numbers
455
499
  # @return [AWS::EC2::SecurityGroup] created security group
456
500
  # @api private
457
- def create_group(region, ports)
501
+ def create_group(rv, ports)
458
502
  name = group_id(ports)
459
503
  @logger.notify("aws-sdk: Creating group #{name} for ports #{ports.to_s}")
460
- group = region.security_groups.create(name,
461
- :description => "Custom Beaker security group for #{ports.to_a}")
504
+ group = rv.security_groups.create(name,
505
+ :description => "Custom Beaker security group for #{ports.to_a}")
462
506
 
463
507
  unless ports.is_a? Set
464
508
  ports = Set.new(ports)