beaker-docker 0.5.3 → 0.8.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.
- checksums.yaml +5 -5
- data/.github/dependabot.yml +8 -0
- data/.github/workflows/test.yml +32 -0
- data/README.md +94 -13
- data/Rakefile +2 -2
- data/acceptance/config/nodes/hosts.yaml +13 -11
- data/beaker-docker.gemspec +3 -13
- data/lib/beaker-docker/version.rb +1 -1
- data/lib/beaker/hypervisor/docker.rb +183 -81
- data/spec/beaker/hypervisor/docker_spec.rb +504 -479
- metadata +13 -54
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f21e88681130028d956057cc5d7e10242d3ab4b0dd3afdddc1e4a77b6a30376e
|
|
4
|
+
data.tar.gz: 27f935f63ebaf20d0eb18afcab7360dccdb6cc7e037cee4d6e9e3a45aed9ef33
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 419eee4542d7283b98c1c9e56fae980816123bd5b4f8f69920180815c0ac61d047f0a8523ac68dc091e6bff6c101d8782905ec18d8a8d571274e62588872f58d
|
|
7
|
+
data.tar.gz: 7aa8635232484d7b4ef171d1714ab59805cd82e1b8c0d44d70174b903805376cf08e8ce48030f33f0efeb8d4ce845b8f2ad6b0f3deeb30bef602ffa86b092387
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
- pull_request
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
test:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
strategy:
|
|
10
|
+
fail-fast: false
|
|
11
|
+
matrix:
|
|
12
|
+
ruby:
|
|
13
|
+
- "2.4"
|
|
14
|
+
- "2.5"
|
|
15
|
+
- "2.6"
|
|
16
|
+
- "2.7"
|
|
17
|
+
env:
|
|
18
|
+
BUNDLE_WITHOUT: release
|
|
19
|
+
name: Ruby ${{ matrix.ruby }}
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v2
|
|
22
|
+
- name: Install Ruby ${{ matrix.ruby }}
|
|
23
|
+
uses: ruby/setup-ruby@v1
|
|
24
|
+
with:
|
|
25
|
+
ruby-version: ${{ matrix.ruby }}
|
|
26
|
+
bundler-cache: true
|
|
27
|
+
- name: Run spec tests
|
|
28
|
+
run: bundle exec rake test:spec
|
|
29
|
+
# It seems some additonal setup of Docker may be needed for
|
|
30
|
+
# the acceptance tests to work.
|
|
31
|
+
# - name: Run acceptance tests
|
|
32
|
+
# run: bundle exec rake test:acceptance
|
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
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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-
|
|
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-
|
|
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
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
HOSTS:
|
|
3
|
-
|
|
4
|
-
platform:
|
|
3
|
+
centos8:
|
|
4
|
+
platform: el-8-x86_64
|
|
5
5
|
hypervisor: docker
|
|
6
|
-
image:
|
|
6
|
+
image: centos:8
|
|
7
7
|
roles:
|
|
8
8
|
- master
|
|
9
9
|
- agent
|
|
@@ -12,22 +12,24 @@ HOSTS:
|
|
|
12
12
|
- classifier
|
|
13
13
|
- default
|
|
14
14
|
docker_cmd: '["/sbin/init"]'
|
|
15
|
+
docker_cap_add:
|
|
16
|
+
- AUDIT_WRITE
|
|
15
17
|
dockeropts:
|
|
16
18
|
Labels:
|
|
17
19
|
one: '1'
|
|
18
20
|
two: '2'
|
|
19
|
-
|
|
20
|
-
platform:
|
|
21
|
+
centos7:
|
|
22
|
+
platform: el-7-x86_64
|
|
21
23
|
hypervisor: docker
|
|
22
|
-
image:
|
|
24
|
+
image: centos:7
|
|
23
25
|
roles:
|
|
24
26
|
- agent
|
|
25
|
-
docker_cmd: '
|
|
27
|
+
docker_cmd: '/usr/sbin/sshd -D -E /var/log/sshd.log'
|
|
28
|
+
use_image_entrypoint: true
|
|
29
|
+
dockeropts:
|
|
30
|
+
HostConfig:
|
|
31
|
+
Privileged: true
|
|
26
32
|
CONFIG:
|
|
27
33
|
nfs_server: none
|
|
28
34
|
consoleport: 443
|
|
29
35
|
log_level: verbose
|
|
30
|
-
dockeropts:
|
|
31
|
-
Labels:
|
|
32
|
-
one: '3'
|
|
33
|
-
two: '4'
|
data/beaker-docker.gemspec
CHANGED
|
@@ -20,24 +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
|
-
|
|
24
|
-
|
|
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
|
-
# Documentation dependencies
|
|
34
|
-
s.add_development_dependency 'yard'
|
|
35
|
-
s.add_development_dependency 'markdown'
|
|
36
|
-
s.add_development_dependency 'thin'
|
|
37
|
-
|
|
38
28
|
# Run time dependencies
|
|
39
29
|
s.add_runtime_dependency 'stringify-hash', '~> 0.0.0'
|
|
40
|
-
s.add_runtime_dependency 'docker-api'
|
|
30
|
+
s.add_runtime_dependency 'docker-api', '< 3.0.0'
|
|
41
31
|
|
|
42
32
|
end
|
|
43
33
|
|
|
@@ -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
|
-
|
|
23
|
-
#
|
|
22
|
+
|
|
23
|
+
# Ensure that we can correctly communicate with the docker API
|
|
24
24
|
begin
|
|
25
|
-
::Docker.
|
|
25
|
+
@docker_version = ::Docker.version
|
|
26
26
|
rescue Excon::Errors::SocketError => e
|
|
27
|
-
raise
|
|
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
|
|
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,45 @@ 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
|
+
# Talking against a remote docker host which is a normal docker host
|
|
139
|
+
if @docker_type == 'docker' && ENV['DOCKER_HOST'] && !ENV.fetch('DOCKER_HOST','').include?(':///')
|
|
140
|
+
ip = URI.parse(ENV['DOCKER_HOST']).host
|
|
141
|
+
else
|
|
142
|
+
# Swarm or local docker host
|
|
143
|
+
if in_container?
|
|
144
|
+
ip = container.json["NetworkSettings"]["Gateway"]
|
|
145
|
+
else
|
|
146
|
+
ip = container.json["NetworkSettings"]["Ports"]["22/tcp"][0]["HostIp"]
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
network_settings = container.json['NetworkSettings']
|
|
151
|
+
host_config = container.json['HostConfig']
|
|
152
|
+
|
|
153
|
+
port = '22'
|
|
154
|
+
if host_config['NetworkMode'] == 'bridge' && network_settings['IPAddress'] && !network_settings['IPAddress'].empty?
|
|
155
|
+
ssh_connection_info[:ip] = network_settings['IPAddress']
|
|
156
|
+
else
|
|
157
|
+
port = network_settings['Ports']['22/tcp'][0]['HostPort']
|
|
158
|
+
|
|
159
|
+
# Update host metadata
|
|
160
|
+
ssh_connection_info[:ip] = (ip == '0.0.0.0') ? '127.0.0.1' : ip
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
ssh_connection_info[:port] = port
|
|
164
|
+
ssh_connection_info
|
|
165
|
+
end
|
|
166
|
+
|
|
112
167
|
def provision
|
|
113
168
|
@logger.notify "Provisioning docker"
|
|
114
169
|
|
|
@@ -144,10 +199,9 @@ module Beaker
|
|
|
144
199
|
|
|
145
200
|
container = find_container(host)
|
|
146
201
|
|
|
147
|
-
# Provisioning - Only provision if
|
|
148
|
-
#
|
|
149
|
-
|
|
150
|
-
if @options[:provision] || container.nil?
|
|
202
|
+
# Provisioning - Only provision if the host's container can't be found
|
|
203
|
+
# via its name or ID
|
|
204
|
+
if container.nil?
|
|
151
205
|
unless host['mount_folders'].nil?
|
|
152
206
|
container_opts['HostConfig'] ||= {}
|
|
153
207
|
container_opts['HostConfig']['Binds'] = host['mount_folders'].values.map do |mount|
|
|
@@ -157,21 +211,50 @@ module Beaker
|
|
|
157
211
|
host_path = "/" + host_path.gsub(/^.\:/, host_path[/^(.)/].downcase)
|
|
158
212
|
end
|
|
159
213
|
a = [ host_path, mount['container_path'] ]
|
|
160
|
-
|
|
214
|
+
if mount.has_key?('opts')
|
|
215
|
+
a << mount['opts'] if mount.has_key?('opts')
|
|
216
|
+
else
|
|
217
|
+
a << mount['opts'] = 'z'
|
|
218
|
+
end
|
|
219
|
+
|
|
161
220
|
a.join(':')
|
|
162
221
|
end
|
|
163
222
|
end
|
|
164
223
|
|
|
224
|
+
if host['docker_env']
|
|
225
|
+
container_opts['Env'] = host['docker_env']
|
|
226
|
+
end
|
|
227
|
+
|
|
165
228
|
if host['docker_cap_add']
|
|
166
229
|
container_opts['HostConfig']['CapAdd'] = host['docker_cap_add']
|
|
167
230
|
end
|
|
168
231
|
|
|
169
232
|
if host['docker_container_name']
|
|
170
233
|
container_opts['name'] = host['docker_container_name']
|
|
234
|
+
else
|
|
235
|
+
container_opts['name'] = ['beaker', host.name, SecureRandom.uuid.split('-').last].join('-')
|
|
171
236
|
end
|
|
172
237
|
|
|
173
238
|
@logger.debug("Creating container from image #{image_name}")
|
|
174
|
-
|
|
239
|
+
|
|
240
|
+
ok=false
|
|
241
|
+
retries=0
|
|
242
|
+
while(!ok && (retries < 5))
|
|
243
|
+
container = ::Docker::Container.create(container_opts)
|
|
244
|
+
|
|
245
|
+
if (get_ssh_connection_info(container)[:port].to_i < 1024) && (Process.uid != 0)
|
|
246
|
+
@logger.debug("#{host} was given a port less than 1024 but you are not running as root, retrying")
|
|
247
|
+
|
|
248
|
+
container.delete
|
|
249
|
+
|
|
250
|
+
retries+=1
|
|
251
|
+
next
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
ok=true
|
|
255
|
+
end
|
|
256
|
+
else
|
|
257
|
+
host['use_existing_container'] = true
|
|
175
258
|
end
|
|
176
259
|
|
|
177
260
|
if container.nil?
|
|
@@ -184,41 +267,35 @@ module Beaker
|
|
|
184
267
|
@logger.debug("Starting container #{container.id}")
|
|
185
268
|
container.start
|
|
186
269
|
|
|
270
|
+
# Preserve the ability to talk directly to the underlying API
|
|
271
|
+
#
|
|
272
|
+
# You can use any method defined by the docker-api gem on this object
|
|
273
|
+
# https://github.com/swipely/docker-api
|
|
274
|
+
host[:docker_container] = container
|
|
275
|
+
|
|
276
|
+
ssh_connection_info = get_ssh_connection_info(container)
|
|
277
|
+
|
|
278
|
+
ip = ssh_connection_info[:ip]
|
|
279
|
+
port = ssh_connection_info[:port]
|
|
280
|
+
|
|
281
|
+
@logger.info("Using container connection at #{ip}:#{port}")
|
|
282
|
+
|
|
187
283
|
if install_and_run_ssh(host)
|
|
188
284
|
@logger.notify("Installing ssh components and starting ssh daemon in #{host} container")
|
|
189
285
|
install_ssh_components(container, host)
|
|
190
286
|
# run fixssh to configure and start the ssh service
|
|
191
287
|
fix_ssh(container, host)
|
|
192
288
|
end
|
|
193
|
-
# Find out where the ssh port is from the container
|
|
194
|
-
# When running on swarm DOCKER_HOST points to the swarm manager so we have to get the
|
|
195
|
-
# IP of the swarm slave via the container data
|
|
196
|
-
# When we are talking to a normal docker instance DOCKER_HOST can point to a remote docker instance.
|
|
197
|
-
|
|
198
|
-
# Talking against a remote docker host which is a normal docker host
|
|
199
|
-
if @docker_type == 'docker' && ENV['DOCKER_HOST']
|
|
200
|
-
ip = URI.parse(ENV['DOCKER_HOST']).host
|
|
201
|
-
else
|
|
202
|
-
# Swarm or local docker host
|
|
203
|
-
if in_container?
|
|
204
|
-
ip = container.json["NetworkSettings"]["Gateway"]
|
|
205
|
-
else
|
|
206
|
-
ip = container.json["NetworkSettings"]["Ports"]["22/tcp"][0]["HostIp"]
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
@logger.info("Using docker server at #{ip}")
|
|
211
|
-
port = container.json["NetworkSettings"]["Ports"]["22/tcp"][0]["HostPort"]
|
|
212
289
|
|
|
213
290
|
forward_ssh_agent = @options[:forward_ssh_agent] || false
|
|
214
291
|
|
|
215
|
-
|
|
216
|
-
host['ip'] = ip
|
|
292
|
+
host['ip'] = ip
|
|
217
293
|
host['port'] = port
|
|
218
294
|
host['ssh'] = {
|
|
219
295
|
:password => root_password,
|
|
220
296
|
:port => port,
|
|
221
297
|
:forward_agent => forward_ssh_agent,
|
|
298
|
+
:auth_methods => ['password', 'publickey', 'hostbased', 'keyboard-interactive']
|
|
222
299
|
}
|
|
223
300
|
|
|
224
301
|
@logger.debug("node available as ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@#{ip} -p #{port}")
|
|
@@ -226,10 +303,12 @@ module Beaker
|
|
|
226
303
|
host['docker_image_id'] = image.id
|
|
227
304
|
host['vm_ip'] = container.json["NetworkSettings"]["IPAddress"].to_s
|
|
228
305
|
|
|
306
|
+
def host.reboot
|
|
307
|
+
@logger.warn("Rebooting containers is ineffective...ignoring")
|
|
308
|
+
end
|
|
229
309
|
end
|
|
230
310
|
|
|
231
311
|
hack_etc_hosts @hosts, @options
|
|
232
|
-
|
|
233
312
|
end
|
|
234
313
|
|
|
235
314
|
# This sideloads sshd after a container starts
|
|
@@ -238,19 +317,23 @@ module Beaker
|
|
|
238
317
|
when /ubuntu/, /debian/
|
|
239
318
|
container.exec(%w(apt-get update))
|
|
240
319
|
container.exec(%w(apt-get install -y openssh-server openssh-client))
|
|
320
|
+
container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
|
|
241
321
|
when /cumulus/
|
|
242
322
|
container.exec(%w(apt-get update))
|
|
243
323
|
container.exec(%w(apt-get install -y openssh-server openssh-client))
|
|
324
|
+
container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
|
|
244
325
|
when /fedora-(2[2-9])/
|
|
245
326
|
container.exec(%w(dnf clean all))
|
|
246
327
|
container.exec(%w(dnf install -y sudo openssh-server openssh-clients))
|
|
247
328
|
container.exec(%w(ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key))
|
|
248
329
|
container.exec(%w(ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key))
|
|
330
|
+
container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
|
|
249
331
|
when /^el-/, /centos/, /fedora/, /redhat/, /eos/
|
|
250
332
|
container.exec(%w(yum clean all))
|
|
251
333
|
container.exec(%w(yum install -y sudo openssh-server openssh-clients))
|
|
252
334
|
container.exec(%w(ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key))
|
|
253
335
|
container.exec(%w(ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key))
|
|
336
|
+
container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
|
|
254
337
|
when /opensuse/, /sles/
|
|
255
338
|
container.exec(%w(zypper -n in openssh))
|
|
256
339
|
container.exec(%w(ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key))
|
|
@@ -279,38 +362,44 @@ module Beaker
|
|
|
279
362
|
def cleanup
|
|
280
363
|
@logger.notify "Cleaning up docker"
|
|
281
364
|
@hosts.each do |host|
|
|
282
|
-
container
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
@logger.
|
|
290
|
-
end
|
|
291
|
-
@logger.debug("delete container #{container.id}")
|
|
292
|
-
begin
|
|
293
|
-
container.delete
|
|
294
|
-
rescue Excon::Errors::ClientError => e
|
|
295
|
-
@logger.warn("deletion of container #{container.id} failed: #{e.response.body}")
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
# Do not remove the image if docker_preserve_image is set to true, otherwise remove it
|
|
300
|
-
unless host['docker_preserve_image']
|
|
301
|
-
image_id = host['docker_image_id']
|
|
302
|
-
|
|
303
|
-
if image_id
|
|
304
|
-
@logger.debug("deleting image #{image_id}")
|
|
365
|
+
# leave the container running if docker_preserve_container is set
|
|
366
|
+
# setting docker_preserve_container also implies docker_preserve_image
|
|
367
|
+
# is set, since you can't delete an image that's the base of a running
|
|
368
|
+
# container
|
|
369
|
+
unless host['docker_preserve_container']
|
|
370
|
+
container = find_container(host)
|
|
371
|
+
if container
|
|
372
|
+
@logger.debug("stop container #{container.id}")
|
|
305
373
|
begin
|
|
306
|
-
|
|
374
|
+
container.kill
|
|
375
|
+
sleep 2 # avoid a race condition where the root FS can't unmount
|
|
307
376
|
rescue Excon::Errors::ClientError => e
|
|
308
|
-
@logger.warn("
|
|
309
|
-
|
|
310
|
-
|
|
377
|
+
@logger.warn("stop of container #{container.id} failed: #{e.response.body}")
|
|
378
|
+
end
|
|
379
|
+
@logger.debug("delete container #{container.id}")
|
|
380
|
+
begin
|
|
381
|
+
container.delete
|
|
382
|
+
rescue Excon::Errors::ClientError => e
|
|
383
|
+
@logger.warn("deletion of container #{container.id} failed: #{e.response.body}")
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Do not remove the image if docker_preserve_image is set to true, otherwise remove it
|
|
388
|
+
unless host['docker_preserve_image']
|
|
389
|
+
image_id = host['docker_image_id']
|
|
390
|
+
|
|
391
|
+
if image_id
|
|
392
|
+
@logger.debug("deleting image #{image_id}")
|
|
393
|
+
begin
|
|
394
|
+
::Docker::Image.remove(image_id)
|
|
395
|
+
rescue Excon::Errors::ClientError => e
|
|
396
|
+
@logger.warn("deletion of image #{image_id} failed: #{e.response.body}")
|
|
397
|
+
rescue ::Docker::Error::DockerError => e
|
|
398
|
+
@logger.warn("deletion of image #{image_id} caused internal Docker error: #{e.message}")
|
|
399
|
+
end
|
|
400
|
+
else
|
|
401
|
+
@logger.warn("Intended to delete the host's docker image, but host['docker_image_id'] was not set")
|
|
311
402
|
end
|
|
312
|
-
else
|
|
313
|
-
@logger.warn("Intended to delete the host's docker image, but host['docker_image_id'] was not set")
|
|
314
403
|
end
|
|
315
404
|
end
|
|
316
405
|
end
|
|
@@ -360,64 +449,76 @@ module Beaker
|
|
|
360
449
|
case host['platform']
|
|
361
450
|
when /ubuntu/, /debian/
|
|
362
451
|
service_name = "ssh"
|
|
363
|
-
dockerfile +=
|
|
452
|
+
dockerfile += <<~EOF
|
|
364
453
|
RUN apt-get update
|
|
365
454
|
RUN apt-get install -y openssh-server openssh-client #{Beaker::HostPrebuiltSteps::DEBIAN_PACKAGES.join(' ')}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
455
|
+
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
|
|
456
|
+
EOF
|
|
457
|
+
when /cumulus/
|
|
458
|
+
dockerfile += <<~EOF
|
|
369
459
|
RUN apt-get update
|
|
370
460
|
RUN apt-get install -y openssh-server openssh-client #{Beaker::HostPrebuiltSteps::CUMULUS_PACKAGES.join(' ')}
|
|
371
|
-
|
|
461
|
+
EOF
|
|
372
462
|
when /fedora-(2[2-9])/
|
|
373
|
-
dockerfile +=
|
|
463
|
+
dockerfile += <<~EOF
|
|
374
464
|
RUN dnf clean all
|
|
375
465
|
RUN dnf install -y sudo openssh-server openssh-clients #{Beaker::HostPrebuiltSteps::UNIX_PACKAGES.join(' ')}
|
|
376
466
|
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
|
|
377
467
|
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
|
|
378
|
-
|
|
468
|
+
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
|
|
469
|
+
EOF
|
|
470
|
+
when /el-8/
|
|
471
|
+
dockerfile += <<~EOF
|
|
472
|
+
RUN dnf clean all
|
|
473
|
+
RUN dnf install -y sudo openssh-server openssh-clients #{Beaker::HostPrebuiltSteps::RHEL8_PACKAGES.join(' ')}
|
|
474
|
+
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
|
|
475
|
+
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
|
|
476
|
+
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
|
|
477
|
+
EOF
|
|
379
478
|
when /^el-/, /centos/, /fedora/, /redhat/, /eos/
|
|
380
|
-
dockerfile +=
|
|
479
|
+
dockerfile += <<~EOF
|
|
381
480
|
RUN yum clean all
|
|
382
481
|
RUN yum install -y sudo openssh-server openssh-clients #{Beaker::HostPrebuiltSteps::UNIX_PACKAGES.join(' ')}
|
|
383
482
|
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
|
|
384
483
|
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
|
|
385
|
-
|
|
484
|
+
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
|
|
485
|
+
EOF
|
|
386
486
|
when /opensuse/, /sles/
|
|
387
|
-
dockerfile +=
|
|
487
|
+
dockerfile += <<~EOF
|
|
388
488
|
RUN zypper -n in openssh #{Beaker::HostPrebuiltSteps::SLES_PACKAGES.join(' ')}
|
|
389
489
|
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
|
|
390
490
|
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
|
|
391
491
|
RUN sed -ri 's/^#?UsePAM .*/UsePAM no/' /etc/ssh/sshd_config
|
|
392
|
-
|
|
492
|
+
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
|
|
493
|
+
EOF
|
|
393
494
|
when /archlinux/
|
|
394
|
-
dockerfile +=
|
|
495
|
+
dockerfile += <<~EOF
|
|
395
496
|
RUN pacman --noconfirm -Sy archlinux-keyring
|
|
396
497
|
RUN pacman --noconfirm -Syu
|
|
397
498
|
RUN pacman -S --noconfirm openssh #{Beaker::HostPrebuiltSteps::ARCHLINUX_PACKAGES.join(' ')}
|
|
398
499
|
RUN ssh-keygen -A
|
|
399
500
|
RUN sed -ri 's/^#?UsePAM .*/UsePAM no/' /etc/ssh/sshd_config
|
|
400
501
|
RUN systemctl enable sshd
|
|
401
|
-
|
|
502
|
+
EOF
|
|
402
503
|
else
|
|
403
504
|
# TODO add more platform steps here
|
|
404
505
|
raise "platform #{host['platform']} not yet supported on docker"
|
|
405
506
|
end
|
|
406
507
|
|
|
407
508
|
# Make sshd directory, set root password
|
|
408
|
-
dockerfile +=
|
|
509
|
+
dockerfile += <<~EOF
|
|
409
510
|
RUN mkdir -p /var/run/sshd
|
|
410
511
|
RUN echo root:#{root_password} | chpasswd
|
|
411
|
-
|
|
512
|
+
EOF
|
|
412
513
|
|
|
413
514
|
# Configure sshd service to allowroot login using password
|
|
414
515
|
# Also, disable reverse DNS lookups to prevent every. single. ssh
|
|
415
516
|
# operation taking 30 seconds while the lookup times out.
|
|
416
|
-
dockerfile +=
|
|
517
|
+
dockerfile += <<~EOF
|
|
417
518
|
RUN sed -ri 's/^#?PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config
|
|
418
519
|
RUN sed -ri 's/^#?PasswordAuthentication .*/PasswordAuthentication yes/' /etc/ssh/sshd_config
|
|
419
520
|
RUN sed -ri 's/^#?UseDNS .*/UseDNS no/' /etc/ssh/sshd_config
|
|
420
|
-
|
|
521
|
+
EOF
|
|
421
522
|
|
|
422
523
|
|
|
423
524
|
# Any extra commands specified for the host
|
|
@@ -498,6 +599,7 @@ module Beaker
|
|
|
498
599
|
|
|
499
600
|
return container unless container.nil?
|
|
500
601
|
@logger.debug("Existing container not found")
|
|
602
|
+
return nil
|
|
501
603
|
end
|
|
502
604
|
|
|
503
605
|
# return true if we are inside a docker container
|