beaker 2.1.0 → 2.2.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.
data/lib/beaker/host.rb CHANGED
@@ -48,7 +48,7 @@ module Beaker
48
48
  # a explict relationship between our defaults, our setup steps and how they're
49
49
  # related through 'type' and the differences between the assumption of our two
50
50
  # configurations we have for many of our products
51
- type = is_pe? ? :pe : :foss
51
+ type = @options.get_type
52
52
  @defaults = merge_defaults_for_type @options, type
53
53
  pkg_initialize
54
54
  end
@@ -312,7 +312,7 @@ module Beaker
312
312
  ignore_re = nil
313
313
  if has_ignore
314
314
  ignore_arr = Array(options[:ignore]).map do |entry|
315
- "((\/|\\A)#{entry}(\/|\\z))".sub(/\./, "\.")
315
+ "((\/|\\A)#{entry}(\/|\\z))".gsub(/\./, '\.')
316
316
  end
317
317
  ignore_re = Regexp.new(ignore_arr.join('|'))
318
318
  end
@@ -358,9 +358,9 @@ module Beaker
358
358
  dir_source.each do |s|
359
359
  s_path = Pathname.new(s)
360
360
  if s_path.absolute?
361
- file_path = File.join(target, s.gsub(source,''))
361
+ file_path = File.join(target, File.dirname(s).gsub(source,''))
362
362
  else
363
- file_path = File.join(target, s)
363
+ file_path = File.join(target, File.dirname(s))
364
364
  end
365
365
  result = connection.scp_to(s, file_path, options, $dry_run)
366
366
  @logger.trace result.stdout
@@ -55,5 +55,16 @@ module Unix
55
55
  'pathseparator' => ':',
56
56
  })
57
57
  end
58
+
59
+ def self.aio_defaults
60
+ h = self.foss_defaults
61
+ h['puppetbindir'] = '/opt/puppetlabs/agent/bin'
62
+ h['puppetpath'] = '/opt/puppetlabs/agent'
63
+ h['puppetvardir'] = '/opt/puppetlabs/agent/cache'
64
+ h['distmoduledir'] = '/opt/puppetlabs/agent/modules'
65
+ h['sitemoduledir'] = '/etc/puppetlabs/agent/modules'
66
+ h['hieraconf'] = ' /etc/puppetlabs/agent/hiera.conf'
67
+ h
68
+ end
58
69
  end
59
70
  end
@@ -1,3 +1,5 @@
1
+ require 'pathname'
2
+
1
3
  [ 'command', "dsl/patterns" ].each do |lib|
2
4
  require "beaker/#{lib}"
3
5
  end
@@ -18,7 +20,7 @@ module Beaker
18
20
  ETC_HOSTS_PATH = "/etc/hosts"
19
21
  ETC_HOSTS_PATH_SOLARIS = "/etc/inet/hosts"
20
22
  ROOT_KEYS_SCRIPT = "https://raw.githubusercontent.com/puppetlabs/puppetlabs-sshkeys/master/templates/scripts/manage_root_authorized_keys"
21
- ROOT_KEYS_SYNC_CMD = "curl -k -o - -L #{ROOT_KEYS_SCRIPT} %s"
23
+ ROOT_KEYS_SYNC_CMD = "curl -k -o - -L #{ROOT_KEYS_SCRIPT} | %s"
22
24
  APT_CFG = %q{ Acquire::http::Proxy "http://proxy.puppetlabs.net:3128/"; }
23
25
  IPS_PKG_REPO="http://solaris-11-internal-repo.delivery.puppetlabs.net"
24
26
 
@@ -126,18 +128,10 @@ module Beaker
126
128
  block_on host do |host|
127
129
  logger.notify "Sync root authorized_keys from github on #{host.name}"
128
130
  # Allow all exit code, as this operation is unlikely to cause problems if it fails.
129
- if host['platform'].include? 'solaris'
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))
131
+ if host['platform'] =~ /solaris|eos/
132
+ host.exec(Command.new(ROOT_KEYS_SYNC_CMD % "bash"), :acceptable_exit_codes => (0..255))
139
133
  else
140
- host.exec(Command.new(ROOT_KEYS_SYNC_CMD % "| env PATH=/usr/gnu/bin:$PATH bash"), :acceptable_exit_codes => (0..255))
134
+ host.exec(Command.new(ROOT_KEYS_SYNC_CMD % "env PATH=/usr/gnu/bin:$PATH bash"), :acceptable_exit_codes => (0..255))
141
135
  end
142
136
  end
143
137
  rescue => e
@@ -344,7 +338,7 @@ module Beaker
344
338
  if host['platform'] =~ /debian|ubuntu|cumulus/
345
339
  host.exec(Command.new("sudo su -c \"service ssh restart\""), {:pty => true})
346
340
  elsif host['platform'] =~ /centos|el-|redhat|fedora|eos/
347
- host.exec(Command.new("sudo -E service sshd restart"))
341
+ host.exec(Command.new("sudo -E /sbin/service sshd restart"))
348
342
  else
349
343
  @logger.warn("Attempting to update ssh on non-supported platform: #{host.name}: #{host['platform']}")
350
344
  end
@@ -479,39 +473,44 @@ module Beaker
479
473
  logger.debug("setting local environment on #{host.name}")
480
474
  case host['platform']
481
475
  when /windows/
482
- host.exec(Command.new("echo 'PermitUserEnvironment yes\n' >> /etc/sshd_config"))
476
+ host.exec(Command.new("echo '\nPermitUserEnvironment yes' >> /etc/sshd_config"))
483
477
  host.exec(Command.new("cygrunsrv -E sshd"))
484
478
  host.exec(Command.new("cygrunsrv -S sshd"))
485
479
  env['CYGWIN'] = 'nodosfilewarning'
486
480
  when /osx/
487
- host.exec(Command.new("echo 'PermitUserEnvironment yes\n' >> /etc/sshd_config"))
481
+ host.exec(Command.new("echo '\nPermitUserEnvironment yes' >> /etc/sshd_config"))
488
482
  host.exec(Command.new("launchctl unload /System/Library/LaunchDaemons/ssh.plist"))
489
483
  host.exec(Command.new("launchctl load /System/Library/LaunchDaemons/ssh.plist"))
490
484
  when /debian|ubuntu|cumulus/
491
- host.exec(Command.new("echo 'PermitUserEnvironment yes\n' >> /etc/ssh/sshd_config"))
485
+ host.exec(Command.new("echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
492
486
  host.exec(Command.new("service ssh restart"))
493
487
  when /el-|centos|fedora|redhat|oracle|scientific|eos/
494
- host.exec(Command.new("echo 'PermitUserEnvironment yes\n' >> /etc/ssh/sshd_config"))
495
- host.exec(Command.new("service sshd restart"))
488
+ host.exec(Command.new("echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
489
+ host.exec(Command.new("/sbin/service sshd restart"))
496
490
  when /sles/
497
- host.exec(Command.new("echo 'PermitUserEnvironment yes\n' >> /etc/ssh/sshd_config"))
491
+ host.exec(Command.new("echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
498
492
  host.exec(Command.new("rcsshd restart"))
499
493
  when /solaris/
500
- host.exec(Command.new("echo 'PermitUserEnvironment yes\n' >> /etc/ssh/sshd_config"))
494
+ host.exec(Command.new("echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
501
495
  host.exec(Command.new("svcadm restart svc:/network/ssh:default"))
502
496
  when /aix/
503
- host.exec(Command.new("echo 'PermitUserEnvironment yes\n' >> /etc/ssh/sshd_config"))
497
+ host.exec(Command.new("echo '\nPermitUserEnvironment yes' >> /etc/ssh/sshd_config"))
504
498
  host.exec(Command.new("stopsrc -g ssh"))
505
499
  host.exec(Command.new("startsrc -g ssh"))
506
500
  end
501
+
507
502
  #ensure that ~/.ssh/environment exists
503
+ host.exec(Command.new("mkdir -p #{Pathname.new(host[:ssh_env_file]).dirname}"))
504
+ host.exec(Command.new("chmod 0600 #{Pathname.new(host[:ssh_env_file]).dirname}"))
508
505
  host.exec(Command.new("touch #{host[:ssh_env_file]}"))
506
+
509
507
  #add the constructed env vars to this host
510
508
  host.add_env_var('RUBYLIB', '$RUBYLIB')
511
509
  host.add_env_var('PATH', '$PATH')
512
510
  env.each_pair do |var, value|
513
511
  host.add_env_var(var, value)
514
512
  end
513
+
515
514
  #close the host to re-establish the connection with the new sshd settings
516
515
  host.close
517
516
  end
@@ -95,6 +95,7 @@ module Beaker
95
95
  #Default configuration steps to be run for a given hypervisor. Any additional configuration to be done
96
96
  #to the provided SUT for test execution to be successful.
97
97
  def configure
98
+ return unless @options[:configure]
98
99
  if @options[:timesync]
99
100
  timesync(@hosts, @options)
100
101
  end
@@ -5,7 +5,7 @@ require 'beaker/hypervisor/ec2_helper'
5
5
 
6
6
  module Beaker
7
7
  # This is an alternate EC2 driver that implements direct API access using
8
- # Amazon's AWS-SDK library: http://aws.amazon.com/documentation/sdkforruby/
8
+ # Amazon's AWS-SDK library: {http://aws.amazon.com/documentation/sdkforruby/ SDK For Ruby}
9
9
  #
10
10
  # It is built for full control, to reduce any other layers beyond the pure
11
11
  # vendor API.
@@ -116,7 +116,7 @@ module Beaker
116
116
  end
117
117
 
118
118
  # Provided an id return an instance object.
119
- # Instance object will respond to methods described here: http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2/Instance.html
119
+ # Instance object will respond to methods described here: {http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2/Instance.html AWS Instance Object}.
120
120
  # @param [String] id The id of the instance to return
121
121
  # @return [AWS::EC2::Instance] An AWS::EC2 instance object
122
122
  def instance_by_id(id)
@@ -124,11 +124,42 @@ module Beaker
124
124
  end
125
125
 
126
126
  # Return all instances currently on ec2.
127
+ # @see AwsSdk#instance_by_id
127
128
  # @return [Array<AWS::EC2::Instance>] An array of AWS::EC2 instance objects
128
129
  def instances
129
130
  @ec2.instances
130
131
  end
131
132
 
133
+ # Provided an id return a VPC object.
134
+ # VPC object will respond to methods described here: {http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2/VPC.html AWS VPC Object}.
135
+ # @param [String] id The id of the VPC to return
136
+ # @return [AWS::EC2::VPC] An AWS::EC2 vpc object
137
+ def vpc_by_id(id)
138
+ @ec2.vpcs[id]
139
+ end
140
+
141
+ # Return all VPCs currently on ec2.
142
+ # @see AwsSdk#vpc_by_id
143
+ # @return [Array<AWS::EC2::VPC>] An array of AWS::EC2 vpc objects
144
+ def vpcs
145
+ @ec2.vpcs
146
+ end
147
+
148
+ # Provided an id return a security group object
149
+ # Security object will respond to methods described here: {http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2/SecurityGroup.html AWS SecurityGroup Object}.
150
+ # @param [String] id The id of the security group to return
151
+ # @return [AWS::EC2::SecurityGroup] An AWS::EC2 security group object
152
+ def security_group_by_id(id)
153
+ @ec2.security_groups[id]
154
+ end
155
+
156
+ # Return all security groups currently on ec2.
157
+ # @see AwsSdk#security_goup_by_id
158
+ # @return [Array<AWS::EC2::SecurityGroup>] An array of AWS::EC2 security group objects
159
+ def security_groups
160
+ @ec2.security_groups
161
+ end
162
+
132
163
  # Shutdown and destroy ec2 instances idenfitied by key that have been alive
133
164
  # longer than ZOMBIE hours.
134
165
  #
@@ -138,7 +169,6 @@ module Beaker
138
169
  @logger.notify("aws-sdk: Kill Zombies! (keyname: #{key}, age: #{max_age} hrs)")
139
170
  #examine all available regions
140
171
  kill_count = 0
141
- volume_count = 0
142
172
  time_now = Time.now.getgm #ec2 uses GM time
143
173
  @ec2.regions.each do |region|
144
174
  @logger.debug "Reviewing: #{region.name}"
@@ -150,17 +180,28 @@ module Beaker
150
180
  @logger.debug "Examining #{instance.id} (keyname: #{instance.key_name}, launch time: #{instance.launch_time}, status: #{instance.status})"
151
181
  if ((time_now - instance.launch_time) > max_age*60*60) and instance.status.to_s !~ /terminated/
152
182
  @logger.debug "Kill! #{instance.id}: #{instance.key_name} (Current status: #{instance.status})"
153
- instance.terminate()
154
- kill_count += 1
183
+ instance.terminate()
184
+ kill_count += 1
155
185
  end
156
186
  end
157
187
  rescue AWS::Core::Resource::NotFound, AWS::EC2::Errors => e
158
188
  @logger.debug "Failed to remove instance: #{instance.id}, #{e}"
159
189
  end
160
190
  end
161
- # Occasionaly, tearing down ec2 instances leaves orphaned EBS volumes behind -- these stack up quickly.
162
- # This simply looks for EBS volumes that are not in use
163
- # Note: don't use volumes.each here as that funtion doesn't allow proper rescue from error states
191
+ end
192
+
193
+ @logger.notify "#{key}: Killed #{kill_count} instance(s)"
194
+ end
195
+
196
+ # Destroy any volumes marked 'available', INCLUDING THOSE YOU DON'T OWN! Use with care.
197
+ def kill_zombie_volumes
198
+ # Occasionaly, tearing down ec2 instances leaves orphaned EBS volumes behind -- these stack up quickly.
199
+ # This simply looks for EBS volumes that are not in use
200
+ # Note: don't use volumes.each here as that funtion doesn't allow proper rescue from error states
201
+ @logger.notify("aws-sdk: Kill Zombie Volumes!")
202
+ volume_count = 0
203
+ @ec2.regions.each do |region|
204
+ @logger.debug "Reviewing: #{region.name}"
164
205
  volumes = @ec2.regions[region.name].volumes.map { |vol| vol.id }
165
206
  volumes.each do |vol|
166
207
  begin
@@ -175,7 +216,7 @@ module Beaker
175
216
  end
176
217
  end
177
218
  end
178
- @logger.notify "#{key}: Killed #{kill_count} instance(s), freed #{volume_count} volume(s)"
219
+ @logger.notify "Freed #{volume_count} volume(s)"
179
220
 
180
221
  end
181
222
 
@@ -43,12 +43,15 @@ module Beaker
43
43
  end
44
44
  port = container.json["NetworkSettings"]["Ports"]["22/tcp"][0]["HostPort"]
45
45
 
46
+ forward_ssh_agent = @options[:forward_ssh_agent] || false
47
+
46
48
  # Update host metadata
47
49
  host['ip'] = ip
48
50
  host['port'] = port
49
51
  host['ssh'] = {
50
52
  :password => root_password,
51
53
  :port => port,
54
+ :forward_agent => forward_ssh_agent,
52
55
  }
53
56
 
54
57
  @logger.debug("node available as ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@#{ip} -p #{port}")
@@ -22,6 +22,7 @@ module Beaker
22
22
  #HACK HACK HACK - add checks here to ensure that we have box + box_url
23
23
  #generate the VagrantFile
24
24
  v_file = "Vagrant.configure(\"2\") do |c|\n"
25
+ v_file << " c.ssh.forward_agent = true\n" if options[:forward_ssh_agent] == true
25
26
  hosts.each do |host|
26
27
  host['ip'] ||= randip #use the existing ip, otherwise default to a random ip
27
28
  v_file << " c.vm.define '#{host.name}' do |v|\n"
@@ -30,8 +31,7 @@ module Beaker
30
31
  v_file << " v.vm.box_url = '#{host['box_url']}'\n" unless host['box_url'].nil?
31
32
  v_file << " v.vm.box_version = '#{host['box_version']}'\n" unless host['box_version'].nil?
32
33
  v_file << " v.vm.box_check_update = '#{host['box_check_update'] ||= 'true'}'\n"
33
- v_file << " v.vm.base_mac = '#{randmac}'\n"
34
- v_file << " v.vm.network :private_network, ip: \"#{host['ip'].to_s}\", :netmask => \"#{host['netmask'] ||= "255.255.0.0"}\"\n"
34
+ v_file << " v.vm.network :private_network, ip: \"#{host['ip'].to_s}\", :netmask => \"#{host['netmask'] ||= "255.255.0.0"}\", :mac => \"#{randmac}\"\n"
35
35
 
36
36
  if /windows/i.match(host['platform'])
37
37
  v_file << " v.vm.network :forwarded_port, guest: 3389, host: 3389\n"
@@ -65,7 +65,7 @@ module Beaker
65
65
  stdout.read
66
66
  end
67
67
  #replace hostname with ip
68
- ssh_config = ssh_config.gsub(/#{host.name}/, host['ip']) unless not host['ip']
68
+ ssh_config = ssh_config.gsub(/Host #{host.name}/, "Host #{host['ip']}") unless not host['ip']
69
69
  if host['platform'] =~ /windows/
70
70
  ssh_config = ssh_config.gsub(/127\.0\.0\.1/, host['ip']) unless not host['ip']
71
71
  end
@@ -28,17 +28,19 @@ module Beaker
28
28
  raise "Couldn't find VM #{name} in vSphere!"
29
29
  end
30
30
 
31
- snapshot = vsphere_helper.find_snapshot(vm, snap) or
32
- raise "Could not find snapshot '#{snap}' for VM #{vm.name}!"
31
+ if snap
32
+ snapshot = vsphere_helper.find_snapshot(vm, snap) or
33
+ raise "Could not find snapshot '#{snap}' for VM #{vm.name}!"
33
34
 
34
- @logger.notify "Reverting #{vm.name} to snapshot '#{snap}'"
35
- start = Time.now
36
- # This will block for each snapshot...
37
- # The code to issue them all and then wait until they are all done sucks
38
- snapshot.RevertToSnapshot_Task.wait_for_completion
35
+ @logger.notify "Reverting #{vm.name} to snapshot '#{snap}'"
36
+ start = Time.now
37
+ # This will block for each snapshot...
38
+ # The code to issue them all and then wait until they are all done sucks
39
+ snapshot.RevertToSnapshot_Task.wait_for_completion
39
40
 
40
- time = Time.now - start
41
- @logger.notify "Spent %.2f seconds reverting" % time
41
+ time = Time.now - start
42
+ @logger.notify "Spent %.2f seconds reverting" % time
43
+ end
42
44
 
43
45
  unless vm.runtime.powerState == "poweredOn"
44
46
  @logger.notify "Booting #{vm.name}"
@@ -36,7 +36,11 @@ class VsphereHelper
36
36
  end
37
37
 
38
38
  def find_snapshot vm, snapname
39
- search_child_snaps vm.snapshot.rootSnapshotList, snapname
39
+ if vm.snapshot
40
+ search_child_snaps vm.snapshot.rootSnapshotList, snapname
41
+ else
42
+ raise "vm #{vm.name} has no snapshots to revert to"
43
+ end
40
44
  end
41
45
 
42
46
  def search_child_snaps tree, snapname
data/lib/beaker/logger.rb CHANGED
@@ -171,7 +171,7 @@ module Beaker
171
171
  else
172
172
  # Remove invalid and undefined UTF-8 character encodings
173
173
  string.to_s.force_encoding('UTF-8')
174
- return string.chars.select{|i| i.valid_encoding?}.join
174
+ return string.to_s.chars.select{|i| i.valid_encoding?}.join
175
175
  end
176
176
  end
177
177
 
@@ -66,6 +66,12 @@ module Beaker
66
66
  @cmd_options[:provision] = bool
67
67
  end
68
68
 
69
+ opts.on '--[no-]configure',
70
+ 'Do not configure vm images before testing',
71
+ '(default: true)' do |bool|
72
+ @cmd_options[:configure] = bool
73
+ end
74
+
69
75
  opts.on '--preserve-hosts [MODE]',
70
76
  'How should SUTs be treated post test',
71
77
  'Possible values:',
@@ -171,7 +177,7 @@ module Beaker
171
177
  end
172
178
 
173
179
  opts.on '--[no-]validate',
174
- 'Validate that SUTs are correctly configured before running tests',
180
+ 'Validate that SUTs are correctly provisioned before running tests',
175
181
  '(default: true)' do |bool|
176
182
  @cmd_options[:validate] = bool
177
183
  end
@@ -51,6 +51,28 @@ module Beaker
51
51
  self[:type] ? self[:type] =~ /pe/ : true
52
52
  end
53
53
 
54
+ # Determine the puppet type of the ObjectHash
55
+ #
56
+ # Default is FOSS
57
+ #
58
+ # @example Use this method to test if the :type setting is pe
59
+ # a['type'] = 'pe'
60
+ # a.get_type == :pe
61
+ #
62
+ # @return [Symbol] the type given in the options
63
+ def get_type
64
+ case self[:type]
65
+ when /pe/
66
+ :pe
67
+ when /foss/
68
+ :foss
69
+ when /aio/
70
+ :aio
71
+ else
72
+ :foss
73
+ end
74
+ end
75
+
54
76
  # Determine if key is stored in ObjectHash
55
77
  # @param [Object] k The key to find in ObjectHash, searches for
56
78
  # both k as String and k as Symbol
@@ -278,8 +278,8 @@ module Beaker
278
278
  end
279
279
 
280
280
  #check for valid type
281
- if @options[:type] !~ /(pe)|(git)|(foss)/
282
- parser_error "--type must be one of pe, git, or foss, not '#{@options[:type]}'"
281
+ if @options[:type] !~ /pe|git|foss|aio/
282
+ parser_error "--type must be one of pe, git, foss, or aio not '#{@options[:type]}'"
283
283
  end
284
284
 
285
285
  #check for valid fail mode
@@ -115,6 +115,7 @@ module Beaker
115
115
  :created_by => ENV['USER'] || ENV['USERNAME'] || 'unknown',
116
116
  :jenkins_build_url => nil,
117
117
  :validate => true,
118
+ :configure => true,
118
119
  :log_level => 'info',
119
120
  :trace_limit => 10,
120
121
  :"master-start-curl-retries" => 120,
data/lib/beaker/result.rb CHANGED
@@ -33,7 +33,7 @@ module Beaker
33
33
  def convert string
34
34
  # Remove invalid and undefined UTF-8 character encodings
35
35
  string.to_s.force_encoding('UTF-8')
36
- string.chars.select{|i| i.valid_encoding?}.join
36
+ string.to_s.chars.select{|i| i.valid_encoding?}.join
37
37
  end
38
38
 
39
39
  def log(logger)
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '2.1.0'
3
+ STRING = '2.2.0'
4
4
  end
5
5
  end