beaker 1.21.0 → 2.0.0

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