beaker 1.10.0 → 1.11.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.
@@ -1,7 +1,7 @@
1
1
  module Unix::Pkg
2
2
  include Beaker::CommandFactory
3
3
 
4
- # This method overrides {Host::pkg_initialize} to provide
4
+ # This method overrides {Beaker::Host#pkg_initialize} to provide
5
5
  # unix-specific package management setup
6
6
  def pkg_initialize
7
7
  @apt_needs_update = true
@@ -111,7 +111,7 @@ module Unix::Pkg
111
111
  # DEBIAN_PLATFORM_CODENAMES map must be kept up-to-date as
112
112
  # support for new versions is added.
113
113
  #
114
- # @note See {Beaker::DSL::Helpers::deploy_package_repo} for info on
114
+ # @note See {Beaker::DSL::Helpers#deploy_package_repo} for info on
115
115
  # params
116
116
  def deploy_apt_repo(path, name, version)
117
117
  codename = DEBIAN_PLATFORM_CODENAMES[self['platform']]
@@ -127,7 +127,7 @@ module Unix::Pkg
127
127
 
128
128
  # Deploy yum configuration generated by the packaging tooling
129
129
  #
130
- # @note See {Beaker::DSL::Helpers::deploy_package_repo} for info on
130
+ # @note See {Beaker::DSL::Helpers#deploy_package_repo} for info on
131
131
  # params
132
132
  def deploy_yum_repo(path, name, version)
133
133
  repo_file = "#{path}/rpm/pl-#{name}-#{version}-repos-pe-#{self['platform']}.repo"
@@ -136,7 +136,7 @@ module Unix::Pkg
136
136
 
137
137
  # Deploy zypper repo configuration generated by the packaging tooling
138
138
  #
139
- # @note See {Beaker::DSL::Helpers::deploy_package_repo} for info on
139
+ # @note See {Beaker::DSL::Helpers#deploy_package_repo} for info on
140
140
  # params
141
141
  def deploy_zyp_repo(path, name, version)
142
142
  repo_file = "#{path}/rpm/pl-#{name}-#{version}-repos-pe-#{self['platform']}.repo"
@@ -148,10 +148,10 @@ module Unix::Pkg
148
148
 
149
149
  # Deploy configuration generated by the packaging tooling to this host.
150
150
  #
151
- # This method calls one of {deploy_apt_repo}, {deploy_yum_repo}, or
152
- # {deploy_zyp_repo} depending on the platform of this Host.
151
+ # This method calls one of #deploy_apt_repo, #deploy_yum_repo, or
152
+ # #deploy_zyp_repo depending on the platform of this Host.
153
153
  #
154
- # @note See {Beaker::DSL::Helpers::deploy_package_repo} for info on
154
+ # @note See {Beaker::DSL::Helpers#deploy_package_repo} for info on
155
155
  # params
156
156
  def deploy_package_repo(path, name, version)
157
157
  if not File.exists? path
@@ -26,6 +26,8 @@ module Windows
26
26
  'puppetservice' => 'pe-httpd',
27
27
  'puppetpath' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
28
28
  'puppetvardir' => '`cygpath -smF 35`/PuppetLabs/puppet/var',
29
+ 'distmoduledir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc/modules',
30
+ 'sitemoduledir' => 'C:/usr/share/puppet/modules',
29
31
  #if an x86 Program Files dir exists then use it, default to just Program Files
30
32
  'puppetbindir' => '$( [ -d "/cygdrive/c/Program Files (x86)" ] && echo "/cygdrive/c/Program Files (x86)" || echo "/cygdrive/c/Program Files" )/Puppet Labs/Puppet Enterprise/bin',
31
33
  'pathseparator' => ';',
@@ -39,6 +41,8 @@ module Windows
39
41
  'group' => 'Administrators',
40
42
  'puppetpath' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
41
43
  'puppetvardir' => '`cygpath -smF 35`/PuppetLabs/puppet/var',
44
+ 'distmoduledir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc/modules',
45
+ 'sitemoduledir' => 'C:/usr/share/puppet/modules',
42
46
  'hieralibdir' => '`cygpath -w /opt/puppet-git-repos/hiera/lib`',
43
47
  'hierapuppetlibdir' => '`cygpath -w /opt/puppet-git-repos/hiera-puppet/lib`',
44
48
  # PATH related variables need to be Unix, which cygwin converts
@@ -107,13 +107,19 @@ module Beaker
107
107
  end
108
108
 
109
109
  #Update /etc/hosts on the master node to include a rule for lookup of the master by name/ip.
110
- # @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon
110
+ # @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon
111
111
  # @param [Hash{Symbol=>String}] opts Options to alter execution.
112
112
  # @option opts [Beaker::Logger] :logger A {Beaker::Logger} object
113
113
  def add_master_entry hosts, opts
114
114
  logger = opts[:logger]
115
115
  master = only_host_with_role(hosts, :master)
116
116
  logger.notify "Add Master entry to /etc/hosts on #{master.name}"
117
+ if master["hypervisor"] and master["hypervisor"] =~ /docker/
118
+ # skip on docker because as of 0.8.1 /etc/hosts isn't modifiable
119
+ # https://github.com/dotcloud/docker/issues/2267
120
+ logger.debug "Don't update master entry on docker masters"
121
+ return
122
+ end
117
123
  if master["hypervisor"] and master["hypervisor"] =~ /vagrant/
118
124
  logger.debug "Don't update master entry on vagrant masters"
119
125
  return
@@ -325,7 +331,8 @@ module Beaker
325
331
  else
326
332
  logger.debug "Give root a copy of current user's keys, on #{host.name}"
327
333
  if host['platform'] =~ /windows/
328
- host.exec(Command.new('sudo su -c "cp -r .ssh /home/Administrator/."'))
334
+ host.exec(Command.new('cp -r .ssh /cygdrive/c/Users/Administrator/.'))
335
+ host.exec(Command.new('chown -R Administrator /cygdrive/c/Users/Administrator/.ssh'))
329
336
  else
330
337
  host.exec(Command.new('sudo su -c "cp -r .ssh /root/."'), {:pty => true})
331
338
  end
@@ -46,6 +46,8 @@ module Beaker
46
46
  Beaker::Vagrant
47
47
  when /google/
48
48
  Beaker::GoogleCompute
49
+ when /docker/
50
+ Beaker::Docker
49
51
  when /none/
50
52
  Beaker::Hypervisor
51
53
  else
@@ -104,7 +106,7 @@ module Beaker
104
106
  end
105
107
  end
106
108
 
107
- %w( vsphere_helper vagrant fusion blimper aws_sdk vsphere vcloud vcloud_pooled aixer solaris google_compute_helper google_compute).each do |lib|
109
+ %w( vsphere_helper vagrant fusion blimper aws_sdk vsphere vcloud vcloud_pooled aixer solaris docker google_compute_helper google_compute).each do |lib|
108
110
  begin
109
111
  require "hypervisor/#{lib}"
110
112
  rescue LoadError
@@ -0,0 +1,154 @@
1
+ module Beaker
2
+ class Docker < Beaker::Hypervisor
3
+
4
+ def initialize(hosts, options)
5
+ require 'docker'
6
+ @options = options
7
+ @logger = options[:logger]
8
+ @hosts = hosts
9
+
10
+ # increase the http timeouts as provisioning images can be slow
11
+ ::Docker.options = { :write_timeout => 300, :read_timeout => 300 }
12
+ # assert that the docker-api gem can talk to your docker
13
+ # enpoint. Will raise if there is a version mismatch
14
+ ::Docker.validate_version!
15
+ # Pass on all the logging from docker-api to the beaker logger instance
16
+ ::Docker.logger = @logger
17
+ end
18
+
19
+ def provision
20
+ @logger.notify "Provisioning docker"
21
+
22
+ @hosts.each do |host|
23
+ @logger.notify "provisioning #{host.name}"
24
+
25
+ @logger.debug("Creating image")
26
+ image = ::Docker::Image.build(dockerfile_for(host), { :rm => true })
27
+ @logger.debug("Tagging image #{image.id} as #{host.name}")
28
+ image.tag({
29
+ :repo => host.name,
30
+ :force => true,
31
+ })
32
+
33
+ @logger.debug("Creating container from image")
34
+ container = ::Docker::Container.create({
35
+ 'Image' => host.name,
36
+ 'Hostname' => host.name,
37
+ })
38
+
39
+ @logger.debug("Starting container #{container.id}")
40
+ container.start({"PublishAllPorts" => true})
41
+
42
+ # Find out where the ssh port is from the container
43
+ ip = container.json["NetworkSettings"]["Ports"]["22/tcp"][0]["HostIp"]
44
+ port = container.json["NetworkSettings"]["Ports"]["22/tcp"][0]["HostPort"]
45
+
46
+ # Update host metadata
47
+ host['ip'] = ip
48
+ host['port'] = port
49
+ host['ssh'] = {
50
+ :password => root_password,
51
+ :port => port,
52
+ }
53
+
54
+ @logger.debug("node available as ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@#{ip} -p #{port}")
55
+ host['docker_container'] = container
56
+ host['docker_image'] = image
57
+ end
58
+ end
59
+
60
+ def cleanup
61
+ @logger.notify "Cleaning up docker"
62
+ @hosts.each do |host|
63
+ if container = host['docker_container']
64
+ @logger.debug("stop container #{container.id}")
65
+ begin
66
+ container.stop
67
+ rescue Excon::Errors::ClientError => e
68
+ @logger.warn("stop of container #{container.id} failed: #{e.response.body}")
69
+ end
70
+ @logger.debug("delete container #{container.id}")
71
+ begin
72
+ container.delete
73
+ rescue Excon::Errors::ClientError => e
74
+ @logger.warn("deletion of container #{container.id} failed: #{e.response.body}")
75
+ end
76
+ end
77
+
78
+ if image = host['docker_image']
79
+ @logger.debug("delete image #{image.id}")
80
+ begin
81
+ image.delete
82
+ rescue Excon::Errors::ClientError => e
83
+ @logger.warn("deletion of image #{image.id} failed: #{e.response.body}")
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def root_password
92
+ 'root'
93
+ end
94
+
95
+ def dockerfile_for(host)
96
+ # specify base image
97
+ dockerfile = <<-EOF
98
+ FROM #{host['image']}
99
+ EOF
100
+
101
+ # additional options to specify to the sshd
102
+ # may vary by platform
103
+ sshd_options = ''
104
+
105
+ # add platform-specific actions
106
+ case host['platform']
107
+ when /ubuntu/, /debian/
108
+ dockerfile += <<-EOF
109
+ RUN apt-get update
110
+ RUN apt-get install -y openssh-server openssh-client
111
+ EOF
112
+ when /^el-/, /centos/, /fedora/, /redhat/
113
+ dockerfile += <<-EOF
114
+ RUN yum clean all
115
+ RUN yum install -y sudo openssh-server openssh-clients
116
+ RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
117
+ RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
118
+ EOF
119
+ when /opensuse/, /sles/
120
+ sshd_options = '-o "PermitRootLogin yes" -o "PasswordAuthentication yes" -o "UsePAM no"'
121
+ dockerfile += <<-EOF
122
+ RUN zypper -n in openssh
123
+ RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
124
+ RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
125
+ EOF
126
+ else
127
+ # TODO add more platform steps here
128
+ raise "platform #{host['platform']} not yet supported on docker"
129
+ end
130
+
131
+ # Make sshd directory, set root password
132
+ dockerfile += <<-EOF
133
+ RUN mkdir -p /var/run/sshd
134
+ RUN echo root:#{root_password} | chpasswd
135
+ EOF
136
+
137
+ # Any extra commands specified for the host
138
+ dockerfile += (host['docker_image_commands'] || []).map { |command|
139
+ "RUN #{command}\n"
140
+ }.join('')
141
+
142
+ # How to start a sshd on port 22. May be an init for more supervision
143
+ cmd = host['docker_cmd'] || "/usr/sbin/sshd -D #{sshd_options}"
144
+ dockerfile += <<-EOF
145
+ EXPOSE 22
146
+ CMD #{cmd}
147
+ EOF
148
+
149
+ @logger.debug("Dockerfile is #{dockerfile}")
150
+ return dockerfile
151
+ end
152
+
153
+ end
154
+ end
@@ -3,7 +3,7 @@ module Beaker
3
3
  # Return a list of open ports for testing based on a hosts role
4
4
  #
5
5
  # @todo horribly hard-coded
6
- # @param [Array<String>] an array of roles
6
+ # @param [Array<String>] roles An array of roles
7
7
  # @return [Array<Number>] array of port numbers
8
8
  # @api private
9
9
  def self.amiports(roles)
@@ -513,7 +513,7 @@ module Beaker
513
513
  end
514
514
 
515
515
  #Set tags on a Google Compute instance
516
- #@param [Array<String>] tags An array of tags to be added to an instance
516
+ #@param [Array<String>] data An array of tags to be added to an instance
517
517
  #@return [Hash] A correctly formatted Google Compute request hash
518
518
  def instance_setMetadata_req(name, fingerprint, data)
519
519
  { :api_method => @compute.instances.set_metadata,
@@ -195,6 +195,7 @@ module Beaker
195
195
  # - --fail-mode is one of 'fast', 'stop' or nil
196
196
  # - if using blimpy hypervisor an EC2 YAML file exists
197
197
  # - if using the aix, solaris, or vcloud hypervisors a .fog file exists
198
+ # - if using docker hypervisor are using RUBY 1.9+
198
199
  # - that one and only one master is defined per set of hosts
199
200
  # - that solaris/windows/aix hosts are agent only for PE tests OR
200
201
  # - that windows/aix host are agent only if type is not 'pe'
@@ -260,6 +261,12 @@ module Beaker
260
261
  check_yaml_file(@options[:dot_fog], "required by #{visor}")
261
262
  end
262
263
  end
264
+ #if using docker need ruby 1.9+
265
+ if hypervisors.include?('docker')
266
+ if RUBY_VERSION < '1.9'
267
+ parser_error "Cannot use the 'docker' hypervisor on Ruby < 1.9 (using #{RUBY_VERSION})"
268
+ end
269
+ end
263
270
 
264
271
  #check that roles of hosts make sense
265
272
  # - must be one and only one master
@@ -5,73 +5,93 @@ module Beaker
5
5
  module Presets
6
6
 
7
7
  # Generates an OptionsHash of the environment variables of interest to Beaker
8
- #
9
- # Currently supports:
10
- #
11
- # consoleport, IS_PE, pe_dist_dir, pe_version_file, pe_version_file_win, pe_ver
12
8
  #
13
9
  # @return [OptionsHash] The supported environment variables in an OptionsHash,
14
10
  # empty or nil environment variables are removed from the OptionsHash
15
11
  def self.env_vars
16
12
  h = Beaker::Options::OptionsHash.new
13
+ consoleport = ENV['BEAKER_CONSOLEPORT'] || ENV['consoleport']
17
14
  h.merge({
18
- :consoleport => ENV['consoleport'] ? ENV['consoleport'].to_i : nil,
19
- :type => ENV['IS_PE'] ? 'pe' : nil,
20
- :pe_dir => ENV['pe_dist_dir'],
21
- :pe_version_file => ENV['pe_version_file'],
22
- :pe_version_file_win => ENV['pe_version_file'],
23
- :pe_ver => ENV['pe_ver'],
24
- :project => ENV['BEAKER_project'],
25
- :department => ENV['BEAKER_department'],
26
- :jenkins_build_url => ENV['BUILD_URL'],
15
+ :home => ENV['HOME'],
16
+ :project => ENV['BEAKER_PROJECT'] || ENV['BEAKER_project'],
17
+ :department => ENV['BEAKER_DEPARTMENT'] || ENV['BEAKER_department'],
18
+ :jenkins_build_url => ENV['BEAKER_BUILD_URL'] || ENV['BUILD_URL'],
19
+ :consoleport => consoleport ? consoleport.to_i : nil,
20
+ :type => (ENV['BEAKER_IS_PE'] || ENV['IS_PE']) ? 'pe' : nil,
21
+ :pe_dir => ENV['BEAKER_PE_DIR'] || ENV['pe_dist_dir'],
22
+ :pe_version_file => ENV['BEAKER_PE_VERSION_FILE'] || ENV['pe_version_file'],
23
+ :pe_version_file_win => ENV['BEAKER_PE_VERSION_FILE'] || ENV['pe_version_file'],
24
+ :pe_ver => ENV['BEAKER_PE_VER'] || ENV['pe_ver'],
25
+ :forge_host => ENV['BEAKER_FORGE_HOST'] || ENV['forge_host'],
26
+ :answers => {
27
+ :q_puppet_enterpriseconsole_auth_user_email =>
28
+ ENV['q_puppet_enterpriseconsole_auth_user_email'] || 'admin@example.com',
29
+ :q_puppet_enterpriseconsole_auth_password =>
30
+ ENV['q_puppet_enterpriseconsole_auth_password'] || '~!@#$%^*-/ aZ',
31
+ :q_puppet_enterpriseconsole_smtp_host =>
32
+ ENV['q_puppet_enterpriseconsole_smtp_host'],
33
+ :q_puppet_enterpriseconsole_smtp_port =>
34
+ ENV['q_puppet_enterpriseconsole_smtp_port'] || 25,
35
+ :q_puppet_enterpriseconsole_smtp_username =>
36
+ ENV['q_puppet_enterpriseconsole_smtp_username'],
37
+ :q_puppet_enterpriseconsole_smtp_password =>
38
+ ENV['q_puppet_enterpriseconsole_smtp_password'],
39
+ :q_puppet_enterpriseconsole_smtp_use_tls =>
40
+ ENV['q_puppet_enterpriseconsole_smtp_use_tls'] || 'n',
41
+ :q_verify_packages =>
42
+ ENV['q_verify_packages'] || 'y',
43
+ :q_puppetdb_password =>
44
+ ENV['q_puppetdb_password'] || '~!@#$%^*-/ aZ',
45
+ }
27
46
  }.delete_if {|key, value| value.nil? or value.empty? })
28
47
  end
29
48
 
30
49
  # Generates an OptionsHash of preset values for arguments supported by Beaker
31
- #
50
+ #
32
51
  # @return [OptionsHash] The supported arguments in an OptionsHash
33
52
  def self.presets
34
53
  h = Beaker::Options::OptionsHash.new
35
54
  h.merge({
36
- :project => 'Beaker',
37
- :department => ENV['USER'] || ENV['USERNAME'] || 'unknown',
38
- :validate => true,
39
- :jenkins_build_url => nil,
40
- :log_level => 'verbose',
41
- :trace_limit => 10,
42
- :hosts_file => 'sample.cfg',
43
- :options_file => nil,
44
- :type => 'pe',
45
- :provision => true,
46
- :preserve_hosts => 'never',
47
- :root_keys => false,
48
- :quiet => false,
49
- :xml => false,
50
- :color => true,
51
- :dry_run => false,
52
- :timeout => 300,
53
- :fail_mode => 'slow',
54
- :timesync => false,
55
- :repo_proxy => false,
56
- :add_el_extras => false,
57
- :add_master_entry => false,
58
- :consoleport => 443,
59
- :pe_dir => '/opt/enterprise/dists',
60
- :pe_version_file => 'LATEST',
55
+ :project => 'Beaker',
56
+ :department => ENV['USER'] || ENV['USERNAME'] || 'unknown',
57
+ :validate => true,
58
+ :jenkins_build_url => nil,
59
+ :forge_host => 'vulcan-acceptance.delivery.puppetlabs.net',
60
+ :log_level => 'verbose',
61
+ :trace_limit => 10,
62
+ :hosts_file => 'sample.cfg',
63
+ :options_file => nil,
64
+ :type => 'pe',
65
+ :provision => true,
66
+ :preserve_hosts => 'never',
67
+ :root_keys => false,
68
+ :quiet => false,
69
+ :xml => false,
70
+ :color => true,
71
+ :dry_run => false,
72
+ :timeout => 300,
73
+ :fail_mode => 'slow',
74
+ :timesync => false,
75
+ :repo_proxy => false,
76
+ :add_el_extras => false,
77
+ :add_master_entry => false,
78
+ :consoleport => 443,
79
+ :pe_dir => '/opt/enterprise/dists',
80
+ :pe_version_file => 'LATEST',
61
81
  :pe_version_file_win => 'LATEST-win',
62
- :dot_fog => File.join(ENV['HOME'], '.fog'),
63
- :ec2_yaml => 'config/image_templates/ec2.yaml',
64
- :help => false,
65
- :ssh => {
66
- :config => false,
67
- :paranoid => false,
68
- :timeout => 300,
69
- :auth_methods => ["publickey"],
70
- :port => 22,
71
- :forward_agent => true,
72
- :keys => ["#{ENV['HOME']}/.ssh/id_rsa"],
73
- :user_known_hosts_file => "#{ENV['HOME']}/.ssh/known_hosts",
74
- }
82
+ :dot_fog => File.join(ENV['HOME'], '.fog'),
83
+ :ec2_yaml => 'config/image_templates/ec2.yaml',
84
+ :help => false,
85
+ :ssh => {
86
+ :config => false,
87
+ :paranoid => false,
88
+ :timeout => 300,
89
+ :auth_methods => ["publickey"],
90
+ :port => 22,
91
+ :forward_agent => true,
92
+ :keys => ["#{ENV['HOME']}/.ssh/id_rsa"],
93
+ :user_known_hosts_file => "#{ENV['HOME']}/.ssh/known_hosts",
94
+ }
75
95
  })
76
96
  end
77
97