beaker-docker 0.6.0 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6a95374c06ba06495a8435b46bc6427516e3b42d
4
- data.tar.gz: 233b9029a46dcdb030de83c4d55014032c4d2538
2
+ SHA256:
3
+ metadata.gz: 02eaf00011bdb77e04d6c2ba218c0d6cb2f0337f03ea9e8770bbc132e8532d78
4
+ data.tar.gz: 1df91fb159aca545ae67ece3c5b4dfc326a81ef5ee8ce307acf21ab16fa4459f
5
5
  SHA512:
6
- metadata.gz: 76f9a3904d76439386ea3e7576a49c7d574592199526dcbe5e4acc7ef379352b30a83e007aa12578d1bc5b7777be2121599769c9b39c5856e1968d2425c6d48b
7
- data.tar.gz: fb07544d1b3d2de996d0ddae9a664632180ba5a6eeef3473f244b95cbca9fe0730bdfbac145be268825e9251503fae41057fa1a5571e6727f06f45d244ae4583
6
+ metadata.gz: 312bf63f3ea66c8d75921c4314912b6451b2457e31452b5cf05b2edbd43c671cefc9c0157f89ea01fb1ed8bcd49769be5770c0c18c559f6ccc47df39620e7e60
7
+ data.tar.gz: e087e4e649f2e31db3425ffefa0c83532e89ae4b8c6d7fab090989a511ced8b3f71133d9e211ae15358312ff0106c82ebd050245feb3e9743fe6caa60aafda02
@@ -0,0 +1,8 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "13:00"
8
+ open-pull-requests-limit: 10
@@ -0,0 +1,24 @@
1
+ name: Release
2
+
3
+ on:
4
+ create:
5
+ ref_type: tag
6
+
7
+ jobs:
8
+ release:
9
+ runs-on: ubuntu-latest
10
+ if: github.repository == 'voxpupuli/beaker-docker'
11
+ env:
12
+ BUNDLE_WITHOUT: release
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - name: Install Ruby 2.7
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: '2.7'
19
+ - name: Build gem
20
+ run: gem build *.gemspec
21
+ - name: Publish gem
22
+ run: gem push *.gem
23
+ env:
24
+ GEM_HOST_API_KEY: '${{ secrets.RUBYGEMS_AUTH_TOKEN }}'
@@ -0,0 +1,105 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - test_me_github
7
+ pull_request:
8
+ branches:
9
+ - main
10
+ - master
11
+
12
+ jobs:
13
+ rspec:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: true
17
+ matrix:
18
+ ruby:
19
+ - "2.4"
20
+ - "2.5"
21
+ - "2.6"
22
+ - "2.7"
23
+ env:
24
+ BUNDLE_WITHOUT: release
25
+ name: RSpec - Ruby ${{ matrix.ruby }}
26
+ steps:
27
+ - uses: actions/checkout@v2
28
+ - name: Install Ruby ${{ matrix.ruby }}
29
+ uses: ruby/setup-ruby@v1
30
+ with:
31
+ ruby-version: ${{ matrix.ruby }}
32
+ bundler-cache: true
33
+ - name: install bundler
34
+ run: |
35
+ gem install bundler -v '~> 1.17.3'
36
+ bundle update
37
+ - name: spec tests
38
+ run: bundle exec rake test:spec
39
+
40
+ docker:
41
+ runs-on: ubuntu-latest
42
+ strategy:
43
+ fail-fast: true
44
+ matrix:
45
+ ruby:
46
+ - "2.6"
47
+ env:
48
+ BUNDLE_WITHOUT: release
49
+ name: Docker - Ruby ${{ matrix.ruby }}
50
+ steps:
51
+ - uses: actions/checkout@v2
52
+ - name: Install Ruby ${{ matrix.ruby }}
53
+ uses: ruby/setup-ruby@v1
54
+ with:
55
+ ruby-version: ${{ matrix.ruby }}
56
+ bundler-cache: true
57
+ - name: install bundler
58
+ run: |
59
+ gem install bundler -v '~> 1.17.3'
60
+ bundle update
61
+ - name: install container runtime
62
+ run: |
63
+ sudo apt-get remove -y docker docker-engine docker.io containerd runc ||:
64
+ sudo apt-get update -y
65
+ sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
66
+ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
67
+ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
68
+ sudo apt-get update -y
69
+ sudo apt-get install -y docker-ce docker-ce-cli containerd.io
70
+ sudo systemctl start docker
71
+ - name: Run acceptance tests
72
+ run: bundle exec rake test:acceptance
73
+
74
+ podman:
75
+ runs-on: ubuntu-latest
76
+ strategy:
77
+ fail-fast: true
78
+ matrix:
79
+ ruby:
80
+ - "2.6"
81
+ env:
82
+ BUNDLE_WITHOUT: release
83
+ name: Podman - Ruby ${{ matrix.ruby }}
84
+ steps:
85
+ - uses: actions/checkout@v2
86
+ - name: Install Ruby ${{ matrix.ruby }}
87
+ uses: ruby/setup-ruby@v1
88
+ with:
89
+ ruby-version: ${{ matrix.ruby }}
90
+ bundler-cache: true
91
+ - name: install bundler
92
+ run: |
93
+ gem install bundler -v '~> 1.17.3'
94
+ bundle update
95
+ # We need the latest version of podman for this to work
96
+ - name: install container runtime
97
+ run: |
98
+ . /etc/os-release
99
+ curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key | sudo apt-key add -
100
+ echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/podman.list > /dev/null
101
+ sudo apt-get update
102
+ sudo apt-get -y install podman
103
+ sudo systemctl start podman
104
+ - name: Run acceptance tests
105
+ run: bundle exec rake test:acceptance
data/Gemfile.local ADDED
@@ -0,0 +1,5 @@
1
+ group :acceptance_testing do
2
+ # Needed for podman testing
3
+ gem "docker-api", :git => 'https://github.com/trevor-vaughan/docker-api', :branch => 'podman-compat'
4
+ gem "beaker-rspec"
5
+ end
data/README.md CHANGED
@@ -6,25 +6,94 @@ Beaker library to use docker hypervisor
6
6
 
7
7
  This gem that allows you to use hosts with [docker](docker.md) hypervisor with [beaker](https://github.com/puppetlabs/beaker).
8
8
 
9
- Beaker will automatically load the appropriate hypervisors for any given hosts file, so as long as your project dependencies are satisfied there's nothing else to do. No need to `require` this library in your tests.
9
+ Beaker will automatically load the appropriate hypervisors for any given hosts
10
+ file, so as long as your project dependencies are satisfied there's nothing else
11
+ to do. No need to `require` this library in your tests.
10
12
 
11
- ## With Beaker 3.x
12
-
13
- This library is included as a dependency of Beaker 3.x versions, so there's nothing to do.
14
-
15
- ## With Beaker 4.x
16
-
17
- As of Beaker 4.0, all hypervisor and DSL extension libraries have been removed and are no longer dependencies. In order to use a specific hypervisor or DSL extension library in your project, you will need to include them alongside Beaker in your Gemfile or project.gemspec. E.g.
13
+ In order to use a specific hypervisor or DSL extension library in your project,
14
+ you will need to include them alongside Beaker in your Gemfile or
15
+ project.gemspec. E.g.
18
16
 
19
17
  ~~~ruby
20
18
  # Gemfile
21
- gem 'beaker', '~>4.0'
22
- gem 'beaker-aws'
19
+ gem 'beaker', '~> 4.0'
20
+ gem 'beaker-docker'
23
21
  # project.gemspec
24
- s.add_runtime_dependency 'beaker', '~>4.0'
25
- s.add_runtime_dependency 'beaker-aws'
22
+ s.add_runtime_dependency 'beaker', '~> 4.0'
23
+ s.add_runtime_dependency 'beaker-docker'
24
+ ~~~
25
+
26
+ ## Nodeset Options
27
+
28
+ The following is a sample nodeset:
29
+
30
+ ~~~yaml
31
+ HOSTS:
32
+ el8:
33
+ platform: el-8-x86_64
34
+ hypervisor: docker
35
+ image: centos:8
36
+ docker_cmd: '["/sbin/init"]'
37
+ # Run arbitrary things
38
+ docker_image_commands:
39
+ - 'touch /tmp/myfile'
40
+ dockeropts:
41
+ Labels:
42
+ thing: 'stuff'
43
+ HostConfig:
44
+ Privileged: true
45
+ el7:
46
+ platform: el-7-x86_64
47
+ hypervisor: docker
48
+ image: centos:7
49
+ # EL7 images do not support nested systemd
50
+ docker_cmd: '/usr/sbin/sshd -D -E /var/log/sshd.log'
51
+ CONFIG:
52
+ docker_cap_add:
53
+ - AUDIT_WRITE
54
+ ~~~
55
+
56
+ ## Privileged containers
57
+
58
+ Containers are **not** run in privileged mode by default for safety.
59
+
60
+ If you wish to enable privileged mode, simply set the following in your node:
61
+
62
+ ~~~yaml
63
+ dockeropts:
64
+ HostConfig:
65
+ Privileged: true
66
+ ~~~
67
+
68
+ ## Cleaning up after tests
69
+
70
+ Containers created by this plugin may not be destroyed unless the tests complete
71
+ successfully. Each container created is prefixed by `beaker-` to make filtering
72
+ for clean up easier.
73
+
74
+ A quick way to clean up all nodes is as follows:
75
+
76
+ ~~~sh
77
+ podman rm -f $( podman ps -q -f name="beaker-*" )
26
78
  ~~~
27
79
 
80
+ # Working with `podman`
81
+
82
+ If you're using a version of `podman` that has API socket support then you
83
+ should be able to simply set `DOCKER_HOST` to your socket and connect as usual.
84
+
85
+ You also need to ensure that you're using a version of the `docker-api` gem that
86
+ supports `podman`.
87
+
88
+ You may find that not all of your tests work as expected. This will be due to
89
+ the tighter system restrictions placed on containers by `podman`. You may need
90
+ to edit the `dockeropts` hash in your nodeset to include different flags in the
91
+ `HostConfig` section.
92
+
93
+ See the
94
+ [HostConfig](https://any-api.com/docker_com/engine/docs/Definitions/HostConfig)
95
+ portion of the docker API for more information.
96
+
28
97
  # Spec tests
29
98
 
30
99
  Spec test live under the `spec` folder. There are the default rake task and therefore can run with a simple command:
@@ -34,7 +103,8 @@ bundle exec rake test:spec
34
103
 
35
104
  # Acceptance tests
36
105
 
37
- There is a simple rake task to invoke acceptance test for the library:
106
+ There is a simple rake task to invoke acceptance test for the library:
107
+
38
108
  ```bash
39
109
  bundle exec rake test:acceptance
40
110
  ```
@@ -42,3 +112,14 @@ bundle exec rake test:acceptance
42
112
  # Contributing
43
113
 
44
114
  Please refer to puppetlabs/beaker's [contributing](https://github.com/puppetlabs/beaker/blob/master/CONTRIBUTING.md) guide.
115
+
116
+ # Releasing
117
+
118
+ To release new versions of beaker-docker, please use this [jenkins job](https://cinext-jenkinsmaster-sre-prod-1.delivery.puppetlabs.net/view/all/job/qe_beaker-docker_init-multijob_master/). This job
119
+ lives on Puppet-internal infrastructure, so you'll need to be a part of the Puppet org to do this.
120
+
121
+ To run the job, click on `Build with Parameters` in the menu on the left. Make
122
+ sure you check the box next to `PUBLIC` and enter the appropriate version. The
123
+ version should adhere to [semantic version standards](https://semver.org).
124
+ When in doubt, consult the [maintainers of Beaker](https://github.com/puppetlabs/beaker/blob/master/CODEOWNERS)
125
+ for guidance.
data/Rakefile CHANGED
@@ -6,14 +6,14 @@ namespace :test do
6
6
 
7
7
  desc "Run spec tests"
8
8
  RSpec::Core::RakeTask.new(:run) do |t|
9
- t.rspec_opts = ['--color']
9
+ t.rspec_opts = ['--color', '--format documentation']
10
10
  t.pattern = 'spec/'
11
11
  end
12
12
 
13
13
  desc "Run spec tests with coverage"
14
14
  RSpec::Core::RakeTask.new(:coverage) do |t|
15
15
  ENV['BEAKER_DOCKER_COVERAGE'] = 'y'
16
- t.rspec_opts = ['--color']
16
+ t.rspec_opts = ['--color', '--format documentation']
17
17
  t.pattern = 'spec/'
18
18
  end
19
19
 
@@ -32,11 +32,15 @@ A quick acceptance test, named because it has no pre-suites to run
32
32
  beaker_test_base_dir = File.join(beaker_gem_dir, 'acceptance/tests/base')
33
33
  load_path_option = File.join(beaker_gem_dir, 'acceptance/lib')
34
34
 
35
+ ENV['BEAKER_setfile'] = 'acceptance/config/nodes/hosts.yaml'
35
36
  sh("beaker",
36
37
  "--hosts", "acceptance/config/nodes/hosts.yaml",
37
- "--tests", beaker_test_base_dir,
38
+ # We can't run these tests until the rsync support in the main
39
+ # beaker/host.rb is updated to work with passwords.
40
+ # "--tests", beaker_test_base_dir,
41
+ # "--load-path", load_path_option,
42
+ "--tests", 'acceptance/tests/',
38
43
  "--log-level", "debug",
39
- "--load-path", load_path_option,
40
44
  "--debug")
41
45
  end
42
46
 
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  HOSTS:
3
- ubuntu1604-64-1:
4
- platform: ubuntu-1604-x86_64
3
+ centos8:
4
+ platform: el-8-x86_64
5
5
  hypervisor: docker
6
- image: ubuntu:16.04
6
+ image: centos:8
7
7
  roles:
8
8
  - master
9
9
  - agent
@@ -12,22 +12,29 @@ HOSTS:
12
12
  - classifier
13
13
  - default
14
14
  docker_cmd: '["/sbin/init"]'
15
- dockeropts:
16
- Labels:
17
- one: '1'
18
- two: '2'
19
- ubuntu1604-64-2:
20
- platform: ubuntu-1604-x86_64
15
+ centos7:
16
+ platform: el-7-x86_64
21
17
  hypervisor: docker
22
- image: ubuntu:16.04
18
+ image: centos:7
23
19
  roles:
24
20
  - agent
25
- docker_cmd: '["/sbin/init"]'
21
+ docker_cmd: '/usr/sbin/sshd -D -E /var/log/sshd.log'
22
+ use_image_entrypoint: true
26
23
  CONFIG:
27
24
  nfs_server: none
28
25
  consoleport: 443
29
26
  log_level: verbose
27
+ # Ubuntu runners need to run with full privileges
28
+ # RHEL derivitives just need the docker cap AUDIT_WRITE
30
29
  dockeropts:
31
- Labels:
32
- one: '3'
33
- two: '4'
30
+ HostConfig:
31
+ Privileged: true
32
+ # docker_cap_add:
33
+ # - AUDIT_WRITE
34
+ type: aio
35
+ ssh:
36
+ verify_host_key: false
37
+ user_known_hosts_file: '/dev/null'
38
+ password: root
39
+ auth_methods:
40
+ - password
@@ -0,0 +1,10 @@
1
+ require 'beaker'
2
+ require 'beaker-rspec'
3
+
4
+ RSpec.describe 'it can connect' do
5
+ hosts.each do |host|
6
+ context "on #{host}" do
7
+ on(host, 'ls /tmp')
8
+ end
9
+ end
10
+ end
@@ -20,19 +20,14 @@ Gem::Specification.new do |s|
20
20
  # Testing dependencies
21
21
  s.add_development_dependency 'rspec', '~> 3.0'
22
22
  s.add_development_dependency 'rspec-its'
23
- # pin fakefs for Ruby < 2.3
24
- if RUBY_VERSION < "2.3"
25
- s.add_development_dependency 'fakefs', '~> 0.6', '< 0.14'
26
- else
27
- s.add_development_dependency 'fakefs', '~> 0.6'
28
- end
29
- s.add_development_dependency 'rake', '~> 10.1'
23
+ s.add_development_dependency 'fakefs', '~> 1.3'
24
+ s.add_development_dependency 'rake', '~> 13.0'
30
25
  s.add_development_dependency 'simplecov'
31
26
  s.add_development_dependency 'pry', '~> 0.10'
32
27
 
33
28
  # Run time dependencies
34
29
  s.add_runtime_dependency 'stringify-hash', '~> 0.0.0'
35
- s.add_runtime_dependency 'docker-api'
30
+ s.add_runtime_dependency 'docker-api', '< 3.0.0'
36
31
 
37
32
  end
38
33
 
@@ -1,3 +1,3 @@
1
1
  module BeakerDocker
2
- VERSION = '0.6.0'
2
+ VERSION = '0.8.2'
3
3
  end
@@ -19,19 +19,25 @@ module Beaker
19
19
  default_docker_options = { :write_timeout => 300, :read_timeout => 300 }.merge(::Docker.options || {})
20
20
  # Merge docker options from the entry in hosts file
21
21
  ::Docker.options = default_docker_options.merge(@options[:docker_options] || {})
22
- # assert that the docker-api gem can talk to your docker
23
- # enpoint. Will raise if there is a version mismatch
22
+
23
+ # Ensure that we can correctly communicate with the docker API
24
24
  begin
25
- ::Docker.validate_version!
25
+ @docker_version = ::Docker.version
26
26
  rescue Excon::Errors::SocketError => e
27
- raise "Docker instance not connectable.\nError was: #{e}\nCheck your DOCKER_HOST variable has been set\nIf you are on OSX or Windows, you might not have Docker Machine setup correctly: https://docs.docker.com/machine/\n"
27
+ raise <<~ERRMSG
28
+ Docker instance not connectable
29
+ Error was: #{e}
30
+ * Check your DOCKER_HOST variable has been set
31
+ * If you are on OSX or Windows, you might not have Docker Machine setup correctly: https://docs.docker.com/machine/
32
+ * If you are using rootless podman, you might need to set up your local socket and service
33
+ ERRMSG
28
34
  end
29
35
 
30
36
  # Pass on all the logging from docker-api to the beaker logger instance
31
37
  ::Docker.logger = @logger
32
38
 
33
39
  # Find out what kind of remote instance we are talking against
34
- if ::Docker.version['Version'] =~ /swarm/
40
+ if @docker_version['Version'] =~ /swarm/
35
41
  @docker_type = 'swarm'
36
42
  unless ENV['DOCKER_REGISTRY']
37
43
  raise "Using Swarm with beaker requires a private registry. Please setup the private registry and set the 'DOCKER_REGISTRY' env var"
@@ -41,10 +47,21 @@ module Beaker
41
47
  else
42
48
  @docker_type = 'docker'
43
49
  end
44
-
45
50
  end
46
51
 
47
52
  def install_and_run_ssh(host)
53
+ def host.enable_root_login(host,opts)
54
+ logger.debug("Root login already enabled for #{host}")
55
+ end
56
+
57
+ # If the container is running ssh as its init process then this method
58
+ # will cause issues.
59
+ if host[:docker_cmd] =~ /sshd/
60
+ def host.ssh_service_restart
61
+ self[:docker_container].exec(%w(kill -1 1))
62
+ end
63
+ end
64
+
48
65
  host['dockerfile'] || host['use_image_entry_point']
49
66
  end
50
67
 
@@ -62,7 +79,6 @@ module Beaker
62
79
  '22/tcp' => [{ 'HostPort' => rand.to_s[2..5], 'HostIp' => '0.0.0.0'}]
63
80
  },
64
81
  'PublishAllPorts' => true,
65
- 'Privileged' => true,
66
82
  'RestartPolicy' => {
67
83
  'Name' => 'always'
68
84
  }
@@ -109,6 +125,48 @@ module Beaker
109
125
  { rm: true, buildargs: buildargs_for(host) })
110
126
  end
111
127
 
128
+ # Find out where the ssh port is from the container
129
+ # When running on swarm DOCKER_HOST points to the swarm manager so we have to get the
130
+ # IP of the swarm slave via the container data
131
+ # When we are talking to a normal docker instance DOCKER_HOST can point to a remote docker instance.
132
+ def get_ssh_connection_info(container)
133
+ ssh_connection_info = {
134
+ ip: nil,
135
+ port: nil
136
+ }
137
+
138
+ container_json = container.json
139
+ network_settings = container_json['NetworkSettings']
140
+ host_config = container_json['HostConfig']
141
+
142
+ ip = nil
143
+ port = nil
144
+ # Talking against a remote docker host which is a normal docker host
145
+ if @docker_type == 'docker' && ENV['DOCKER_HOST'] && !ENV.fetch('DOCKER_HOST','').include?(':///')
146
+ ip = URI.parse(ENV['DOCKER_HOST']).host
147
+ else
148
+ # Swarm or local docker host
149
+ if in_container?
150
+ gw = network_settings['Gateway']
151
+ ip = gw unless (gw.nil? || gw.empty?)
152
+ else
153
+ port22 = network_settings.dig('Ports','22/tcp')
154
+ ip = port22[0]["HostIp"] if port22
155
+ end
156
+ end
157
+
158
+ if host_config['NetworkMode'] != 'slirp4netns' && network_settings['IPAddress'] && !network_settings['IPAddress'].empty?
159
+ ip = network_settings['IPAddress']
160
+ else
161
+ port22 = network_settings.dig('Ports','22/tcp')
162
+ port = port22[0]['HostPort'] if port22
163
+ end
164
+
165
+ ssh_connection_info[:ip] = (ip == '0.0.0.0') ? '127.0.0.1' : ip
166
+ ssh_connection_info[:port] = port || '22'
167
+ ssh_connection_info
168
+ end
169
+
112
170
  def provision
113
171
  @logger.notify "Provisioning docker"
114
172
 
@@ -134,6 +192,8 @@ module Beaker
134
192
  image_name = image.id
135
193
  end
136
194
 
195
+ ### BEGIN CONTAINER OPTIONS MANGLING ###
196
+
137
197
  container_opts = get_container_opts(host, image_name)
138
198
  if host['dockeropts'] || @options[:dockeropts]
139
199
  dockeropts = host['dockeropts'] ? host['dockeropts'] : @options[:dockeropts]
@@ -156,7 +216,12 @@ module Beaker
156
216
  host_path = "/" + host_path.gsub(/^.\:/, host_path[/^(.)/].downcase)
157
217
  end
158
218
  a = [ host_path, mount['container_path'] ]
159
- a << mount['opts'] if mount.has_key?('opts')
219
+ if mount.has_key?('opts')
220
+ a << mount['opts'] if mount.has_key?('opts')
221
+ else
222
+ a << mount['opts'] = 'z'
223
+ end
224
+
160
225
  a.join(':')
161
226
  end
162
227
  end
@@ -165,16 +230,46 @@ module Beaker
165
230
  container_opts['Env'] = host['docker_env']
166
231
  end
167
232
 
233
+ # Fixup privileges
234
+ #
235
+ # If the user has specified CAPs, then we cannot be privileged
236
+ #
237
+ # If the user has not specified CAPs, we will default to privileged for
238
+ # compatibility with worst practice
168
239
  if host['docker_cap_add']
169
240
  container_opts['HostConfig']['CapAdd'] = host['docker_cap_add']
241
+ container_opts['HostConfig'].delete('Privileged')
242
+ else
243
+ container_opts['HostConfig']['Privileged'] = container_opts['HostConfig']['Privileged'].nil? ? true : container_opts['HostConfig']['Privileged']
170
244
  end
171
245
 
172
246
  if host['docker_container_name']
173
247
  container_opts['name'] = host['docker_container_name']
248
+ else
249
+ container_opts['name'] = ['beaker', host.name, SecureRandom.uuid.split('-').last].join('-')
174
250
  end
175
251
 
252
+ ### END CONTAINER OPTIONS MANGLING ###
253
+
176
254
  @logger.debug("Creating container from image #{image_name}")
177
- container = ::Docker::Container.create(container_opts)
255
+
256
+ ok=false
257
+ retries=0
258
+ while(!ok && (retries < 5))
259
+ container = ::Docker::Container.create(container_opts)
260
+
261
+ ssh_info = get_ssh_connection_info(container)
262
+ if ssh_info[:ip] == '127.0.0.1' && (ssh_info[:port].to_i < 1024) && (Process.uid != 0)
263
+ @logger.debug("#{host} was given a port less than 1024 but you are not running as root, retrying")
264
+
265
+ container.delete
266
+
267
+ retries+=1
268
+ next
269
+ end
270
+
271
+ ok=true
272
+ end
178
273
  else
179
274
  host['use_existing_container'] = true
180
275
  end
@@ -189,52 +284,55 @@ module Beaker
189
284
  @logger.debug("Starting container #{container.id}")
190
285
  container.start
191
286
 
287
+ begin
288
+ container.stats
289
+ rescue StandardError => e
290
+ container.delete
291
+ raise "Container '#{container.id}' in a bad state: #{e}"
292
+ end
293
+
294
+ # Preserve the ability to talk directly to the underlying API
295
+ #
296
+ # You can use any method defined by the docker-api gem on this object
297
+ # https://github.com/swipely/docker-api
298
+ host[:docker_container] = container
299
+
192
300
  if install_and_run_ssh(host)
193
301
  @logger.notify("Installing ssh components and starting ssh daemon in #{host} container")
194
302
  install_ssh_components(container, host)
195
303
  # run fixssh to configure and start the ssh service
196
304
  fix_ssh(container, host)
197
305
  end
198
- # Find out where the ssh port is from the container
199
- # When running on swarm DOCKER_HOST points to the swarm manager so we have to get the
200
- # IP of the swarm slave via the container data
201
- # When we are talking to a normal docker instance DOCKER_HOST can point to a remote docker instance.
202
-
203
- # Talking against a remote docker host which is a normal docker host
204
- if @docker_type == 'docker' && ENV['DOCKER_HOST']
205
- ip = URI.parse(ENV['DOCKER_HOST']).host
206
- else
207
- # Swarm or local docker host
208
- if in_container?
209
- ip = container.json["NetworkSettings"]["Gateway"]
210
- else
211
- ip = container.json["NetworkSettings"]["Ports"]["22/tcp"][0]["HostIp"]
212
- end
213
- end
214
306
 
215
- @logger.info("Using docker server at #{ip}")
216
- port = container.json["NetworkSettings"]["Ports"]["22/tcp"][0]["HostPort"]
307
+ ssh_connection_info = get_ssh_connection_info(container)
308
+
309
+ ip = ssh_connection_info[:ip]
310
+ port = ssh_connection_info[:port]
311
+
312
+ @logger.info("Using container connection at #{ip}:#{port}")
217
313
 
218
314
  forward_ssh_agent = @options[:forward_ssh_agent] || false
219
315
 
220
- # Update host metadata
221
- host['ip'] = ip
316
+ host['ip'] = ip
222
317
  host['port'] = port
223
318
  host['ssh'] = {
224
319
  :password => root_password,
225
320
  :port => port,
226
321
  :forward_agent => forward_ssh_agent,
322
+ :auth_methods => ['password', 'publickey', 'hostbased', 'keyboard-interactive']
227
323
  }
228
324
 
229
- @logger.debug("node available as ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@#{ip} -p #{port}")
325
+ @logger.debug("node available as ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@#{ip} -p #{port}")
230
326
  host['docker_container_id'] = container.id
231
327
  host['docker_image_id'] = image.id
232
328
  host['vm_ip'] = container.json["NetworkSettings"]["IPAddress"].to_s
233
329
 
330
+ def host.reboot
331
+ @logger.warn("Rebooting containers is ineffective...ignoring")
332
+ end
234
333
  end
235
334
 
236
335
  hack_etc_hosts @hosts, @options
237
-
238
336
  end
239
337
 
240
338
  # This sideloads sshd after a container starts
@@ -243,19 +341,23 @@ module Beaker
243
341
  when /ubuntu/, /debian/
244
342
  container.exec(%w(apt-get update))
245
343
  container.exec(%w(apt-get install -y openssh-server openssh-client))
344
+ container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
246
345
  when /cumulus/
247
346
  container.exec(%w(apt-get update))
248
347
  container.exec(%w(apt-get install -y openssh-server openssh-client))
348
+ container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
249
349
  when /fedora-(2[2-9])/
250
350
  container.exec(%w(dnf clean all))
251
351
  container.exec(%w(dnf install -y sudo openssh-server openssh-clients))
252
352
  container.exec(%w(ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key))
253
353
  container.exec(%w(ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key))
354
+ container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
254
355
  when /^el-/, /centos/, /fedora/, /redhat/, /eos/
255
356
  container.exec(%w(yum clean all))
256
357
  container.exec(%w(yum install -y sudo openssh-server openssh-clients))
257
358
  container.exec(%w(ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key))
258
359
  container.exec(%w(ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key))
360
+ container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
259
361
  when /opensuse/, /sles/
260
362
  container.exec(%w(zypper -n in openssh))
261
363
  container.exec(%w(ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key))
@@ -371,71 +473,76 @@ module Beaker
371
473
  case host['platform']
372
474
  when /ubuntu/, /debian/
373
475
  service_name = "ssh"
374
- dockerfile += <<-EOF
476
+ dockerfile += <<~EOF
375
477
  RUN apt-get update
376
478
  RUN apt-get install -y openssh-server openssh-client #{Beaker::HostPrebuiltSteps::DEBIAN_PACKAGES.join(' ')}
377
- EOF
479
+ RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
480
+ EOF
378
481
  when /cumulus/
379
- dockerfile += <<-EOF
482
+ dockerfile += <<~EOF
380
483
  RUN apt-get update
381
484
  RUN apt-get install -y openssh-server openssh-client #{Beaker::HostPrebuiltSteps::CUMULUS_PACKAGES.join(' ')}
382
- EOF
485
+ EOF
383
486
  when /fedora-(2[2-9])/
384
- dockerfile += <<-EOF
487
+ dockerfile += <<~EOF
385
488
  RUN dnf clean all
386
489
  RUN dnf install -y sudo openssh-server openssh-clients #{Beaker::HostPrebuiltSteps::UNIX_PACKAGES.join(' ')}
387
490
  RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
388
491
  RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
389
- EOF
492
+ RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
493
+ EOF
390
494
  when /el-8/
391
- dockerfile += <<-EOF
392
- RUN yum clean all
393
- RUN yum install -y sudo openssh-server openssh-clients #{Beaker::HostPrebuiltSteps::RHEL8_PACKAGES.join(' ')}
495
+ dockerfile += <<~EOF
496
+ RUN dnf clean all
497
+ RUN dnf install -y sudo openssh-server openssh-clients #{Beaker::HostPrebuiltSteps::RHEL8_PACKAGES.join(' ')}
394
498
  RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
395
499
  RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
396
- EOF
500
+ RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
501
+ EOF
397
502
  when /^el-/, /centos/, /fedora/, /redhat/, /eos/
398
- dockerfile += <<-EOF
503
+ dockerfile += <<~EOF
399
504
  RUN yum clean all
400
505
  RUN yum install -y sudo openssh-server openssh-clients #{Beaker::HostPrebuiltSteps::UNIX_PACKAGES.join(' ')}
401
506
  RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
402
507
  RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
403
- EOF
508
+ RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
509
+ EOF
404
510
  when /opensuse/, /sles/
405
- dockerfile += <<-EOF
511
+ dockerfile += <<~EOF
406
512
  RUN zypper -n in openssh #{Beaker::HostPrebuiltSteps::SLES_PACKAGES.join(' ')}
407
513
  RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
408
514
  RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
409
515
  RUN sed -ri 's/^#?UsePAM .*/UsePAM no/' /etc/ssh/sshd_config
410
- EOF
516
+ RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
517
+ EOF
411
518
  when /archlinux/
412
- dockerfile += <<-EOF
519
+ dockerfile += <<~EOF
413
520
  RUN pacman --noconfirm -Sy archlinux-keyring
414
521
  RUN pacman --noconfirm -Syu
415
522
  RUN pacman -S --noconfirm openssh #{Beaker::HostPrebuiltSteps::ARCHLINUX_PACKAGES.join(' ')}
416
523
  RUN ssh-keygen -A
417
524
  RUN sed -ri 's/^#?UsePAM .*/UsePAM no/' /etc/ssh/sshd_config
418
525
  RUN systemctl enable sshd
419
- EOF
526
+ EOF
420
527
  else
421
528
  # TODO add more platform steps here
422
529
  raise "platform #{host['platform']} not yet supported on docker"
423
530
  end
424
531
 
425
532
  # Make sshd directory, set root password
426
- dockerfile += <<-EOF
533
+ dockerfile += <<~EOF
427
534
  RUN mkdir -p /var/run/sshd
428
535
  RUN echo root:#{root_password} | chpasswd
429
- EOF
536
+ EOF
430
537
 
431
538
  # Configure sshd service to allowroot login using password
432
539
  # Also, disable reverse DNS lookups to prevent every. single. ssh
433
540
  # operation taking 30 seconds while the lookup times out.
434
- dockerfile += <<-EOF
541
+ dockerfile += <<~EOF
435
542
  RUN sed -ri 's/^#?PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config
436
543
  RUN sed -ri 's/^#?PasswordAuthentication .*/PasswordAuthentication yes/' /etc/ssh/sshd_config
437
544
  RUN sed -ri 's/^#?UseDNS .*/UseDNS no/' /etc/ssh/sshd_config
438
- EOF
545
+ EOF
439
546
 
440
547
 
441
548
  # Any extra commands specified for the host