Skip to content

Commit 8f51707

Browse files
authored
Serverspec fixes (#165)
* Fix parallel execution environment * Add more verbose messages for spec init/run * Reduce python cpu usage for wait loop * Set threads to auto for test target
1 parent c46c05f commit 8f51707

38 files changed

+237
-253
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ requirements:
3636
cd tests/serverspec && bundle install --path=vendor
3737

3838
test:
39-
python bin/console test:serverspec --threads=auto/2 -v
39+
python bin/console test:serverspec --threads=auto -v
4040

4141
baselayout:
4242
python bin/console generate:provision --baselayout

bin/webdevops/Command.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1919
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2020

21-
import os, subprocess, tempfile
21+
import os, subprocess, tempfile, copy, time
2222

2323
def execute(cmd, cwd=False, env=None):
2424
"""
@@ -27,9 +27,20 @@ def execute(cmd, cwd=False, env=None):
2727

2828
print 'Execute: %s' % ' '.join(cmd)
2929

30-
# remove _ from env (prevent errors)
31-
if env is not None and '_' in env:
32-
del env['_']
30+
if env is not None:
31+
env = copy.deepcopy(env)
32+
env['PWD'] = os.environ['PWD']
33+
env['LC_CTYPE'] = os.environ['LC_CTYPE']
34+
env['SHELL'] = os.environ['SHELL']
35+
36+
if '_' in env:
37+
del env['_']
38+
39+
# add system env vars
40+
system_env_vars = ['PWD', 'PATH', 'LC_CTYPE', 'SHELL', 'DOCKER_HOST', 'DOCKER_CERT_PATH', 'DOCKER_MACHINE_NAME', 'DOCKER_TLS_VERIFY']
41+
for var_name in system_env_vars:
42+
if not var_name in env and var_name in os.environ:
43+
env[var_name] = os.environ[var_name]
3344

3445
# set current working directory
3546
path_current = os.getcwd()
@@ -51,7 +62,7 @@ def execute(cmd, cwd=False, env=None):
5162

5263
# wait for process end
5364
while proc.poll() is None:
54-
pass
65+
time.sleep(1)
5566

5667
# output stdout
5768
with open(file_stdout.name, 'r') as f:

bin/webdevops/command/DoitCommand.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def run_doit(self, task_loader, configuration):
2828
extra_configuration = {}
2929

3030
if 'threads' in configuration and configuration.get('threads') > 1:
31-
arguments.extend(['-n', str(configuration.get('threads'))])
31+
arguments.extend(['-n', str(configuration.get('threads')), '--parallel-type', 'process'])
3232

3333
if 'doitConfig' in configuration:
3434
extra_configuration = configuration.get('doitConfig')

bin/webdevops/taskloader/DockerTestServerspecTaskLoader.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1919
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2020

21-
import os, re, tempfile, json
21+
import os, re, tempfile, json, base64
2222
from webdevops import Command
2323
from .BaseDockerTaskLoader import BaseDockerTaskLoader
2424
from .BaseTaskLoader import BaseTaskLoader
@@ -75,18 +75,18 @@ def task_run(dockerfile, configuration, task):
7575
tmp_suffix = '.%s_%s_%s.tmp' % (dockerfile['image']['repository'], dockerfile['image']['imageName'], dockerfile['image']['tag'])
7676
test_dockerfile = tempfile.NamedTemporaryFile(prefix='Dockerfile.', suffix=tmp_suffix, dir=configuration.get('serverspecPath'), bufsize=0, delete=False)
7777

78-
# serverspec options
79-
serverspec_opts = []
80-
serverspec_opts.extend(['--pattern', spec_path])
81-
82-
# serverspec env
83-
serverspec_env = DockerTestServerspecTaskLoader.generate_serverspec_environment(
78+
# serverspec conf
79+
serverspec_conf = DockerTestServerspecTaskLoader.generate_serverspec_configuration(
8480
path=os.path.basename(test_dockerfile.name),
8581
dockerfile=dockerfile,
8682
configuration=configuration,
8783
is_toolimage=is_toolimage
8884
)
8985

86+
# serverspec options
87+
serverspec_opts = []
88+
serverspec_opts.extend([spec_path, dockerfile['image']['fullname'], base64.b64encode(json.dumps(serverspec_conf)), os.path.basename(test_dockerfile.name)])
89+
9090
# dockerfile content
9191
dockerfile_content = DockerTestServerspecTaskLoader.generate_dockerfile(
9292
dockerfile=dockerfile,
@@ -103,15 +103,13 @@ def task_run(dockerfile, configuration, task):
103103
print ' path: %s' % (spec_path)
104104
print ' args: %s' % (' '.join(serverspec_opts))
105105
print ''
106-
print 'environment:'
107-
print '------------'
108-
print json.dumps(serverspec_env, indent=4, sort_keys=True)
106+
print 'spec configuration:'
107+
print '-------------------'
108+
print json.dumps(serverspec_conf, indent=4, sort_keys=True)
109109
print ''
110110
print 'Dockerfile:'
111111
print '-----------'
112112
print dockerfile_content
113-
114-
os.remove(test_dockerfile.name)
115113
return True
116114

117115
# check if we have any tests
@@ -123,10 +121,6 @@ def task_run(dockerfile, configuration, task):
123121
cmd = ['bash', 'serverspec.sh']
124122
cmd.extend(serverspec_opts)
125123

126-
# Set environment variables
127-
env = os.environ.copy()
128-
env.update(serverspec_env)
129-
130124
# create Dockerfile
131125
with open(test_dockerfile.name, mode='w', buffering=0) as f:
132126
f.write(dockerfile_content)
@@ -137,7 +131,7 @@ def task_run(dockerfile, configuration, task):
137131
test_status = False
138132
for retry_count in range(0, configuration.get('retry')):
139133
try:
140-
test_status = Command.execute(cmd, cwd=configuration.get('serverspecPath'), env=env)
134+
test_status = Command.execute(cmd, cwd=configuration.get('serverspecPath'))
141135
except Exception as e:
142136
print e
143137
pass
@@ -149,23 +143,22 @@ def task_run(dockerfile, configuration, task):
149143
else:
150144
print ' failed, giving up'
151145

152-
os.remove(test_dockerfile.name)
153146
return test_status
154147

155148
@staticmethod
156-
def generate_serverspec_environment(path, dockerfile, configuration, is_toolimage=False):
149+
def generate_serverspec_configuration(path, dockerfile, configuration, is_toolimage=False):
157150
"""
158-
Generate serverspec environment dict
151+
Generate serverspec configuration dict
159152
"""
160153
ret = {}
161154

162155
# add default vars
163-
default_env_list = configuration.get('dockerTest.environment.default', False)
156+
default_env_list = configuration.get('dockerTest.configuration.default', False)
164157
if default_env_list:
165158
ret = default_env_list.to_dict().copy()
166159

167160
# add docker image specific vars
168-
image_env_list = configuration.get('dockerTest.environment.image')
161+
image_env_list = configuration.get('dockerTest.configuration.image')
169162
if image_env_list:
170163
image_env_list = image_env_list.to_dict().copy()
171164
for term in image_env_list:
@@ -191,6 +184,7 @@ def generate_dockerfile(dockerfile, configuration, is_toolimage=False):
191184

192185
ret.append('FROM %s' % dockerfile['image']['fullname'])
193186
ret.append('COPY conf/ /')
187+
ret.append('RUN echo "%s" > /DOCKER.IMAGENAME' % dockerfile['image']['fullname'])
194188

195189
if is_toolimage:
196190
ret.append('RUN chmod +x /loop-entrypoint.sh')

conf/console.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ imagePath: 'documentation/docs/resources/images/'
77
baselayoutPath: 'baselayout'
88
testinfraPath: 'tests/testinfra'
99
serverspecPath: 'tests/serverspec'
10+
testDockerfilePath: 'tests/dockerfile'
1011
blacklistFile: 'BLACKLIST'
1112

1213
docker:
@@ -35,7 +36,7 @@ dockerTest:
3536
'/varnish':
3637
- 'ENV VARNISH_BACKEND_HOST webdevops.io'
3738

38-
environment:
39+
configuration:
3940
default:
4041
OS_FAMILY: 'ubuntu'
4142
OS_VERSION: '16.04'

tests/serverspec/Rakefile

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,36 @@
1-
require 'rake'
2-
require 'rspec/core/rake_task'
3-
4-
RSpec.configure do |config|
5-
# show retry status in spec process
6-
config.verbose_retry = true
7-
# show exception that triggers a retry if verbose_retry is set to true
8-
config.display_try_failure_messages = true
9-
end
1+
begin
2+
require 'rake'
3+
require 'json'
4+
require 'base64'
5+
require 'docker'
6+
require 'rspec'
7+
require 'serverspec'
8+
require 'rspec/retry'
9+
require 'rspec/core/rake_task'
10+
11+
RSpec::Core::RakeTask.new(:spec, :pattern, :dockerImageName, :configuration) do |t, task_args|
12+
t.pattern = task_args[:pattern]
13+
t.fail_on_error = true
14+
15+
# hide command
16+
t.verbose = false
17+
18+
$specConfiguration = JSON.parse(Base64.decode64(task_args[:configuration]))
19+
20+
$dockerImage = Docker::Image.build_from_dir('.', { 'dockerfile' => $specConfiguration['DOCKERFILE'] })
21+
$specConfiguration['DOCKERIMAGE_ID'] = $dockerImage.id
22+
23+
print "\n"
24+
print "Environment configuration\n"
25+
print "-------------------------\n"
26+
$specConfiguration.each do |key, value|
27+
print " " + key + ':' + value + "\n"
28+
ENV[key] = value
29+
end
30+
print "\n"
31+
print "\n"
32+
end
1033

11-
RSpec::Core::RakeTask.new(:"spec") do |t, args|
12-
#t.pattern = 'spec/base/*_spec.rb'
34+
rescue LoadError
35+
# no rspec available
1336
end

tests/serverspec/serverspec.sh

Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,19 @@
11
#!/usr/bin/env bash
22

3-
# Check if DOCKERFILE is set, needed for test
4-
if [[ -z "$DOCKERFILE" ]]; then
5-
echo "Environment variable 'DOCKERFILE' not set"
6-
exit 1
7-
fi
3+
set -o pipefail ## trace ERR through pipes
4+
set -o errtrace ## trace ERR through 'time command' and other functions
5+
set -o nounset ## set -u : exit the script if you try to use an uninitialised variable
6+
set -o errexit ## set -e : exit the script if any statement returns a non-true return value
87

9-
# Check if dockerfile exists
10-
if [[ ! -f "${DOCKERFILE}" ]]; then
11-
# Filesystem is maybe not synced?
12-
sync
8+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
139

14-
# recheck if file is now available
15-
if [[ ! -f "${DOCKERFILE}" ]]; then
16-
echo "Dockerfile $DOCKERFILE' not found"
17-
exit 1
18-
fi
19-
fi
10+
PARAM_SPEC_FILE="$1"
11+
PARAM_DOCKER_IMAGE="$2"
12+
PARAM_SPEC_CONF="$3"
2013

21-
# Check if DOCKER_IMAGE is set, needed for test
22-
if [[ -z "$DOCKER_IMAGE" ]]; then
23-
echo "Environment variable 'DOCKER_IMAGE' not set"
24-
exit 1
25-
fi
14+
# LOGFILE="${PARAM_DOCKER_IMAGE//:/_}"
15+
# LOGFILE="${PARAM_DOCKER_IMAGE//\//_}"
16+
# LOGFILE="${SCRIPT_DIR}/logs/${LOGFILE}.log"
2617

27-
# Check if DOCKER_TAG is set, needed for test
28-
if [[ -z "$DOCKER_TAG" ]]; then
29-
echo "Environment variable 'DOCKER_TAG' not set"
30-
exit 1
31-
fi
18+
exec bundle exec rake spec["$PARAM_SPEC_FILE","$PARAM_DOCKER_IMAGE","$PARAM_SPEC_CONF"]
3219

33-
# Check if OS_FAMILY is set, needed for test
34-
if [[ -z "$OS_FAMILY" ]]; then
35-
echo "Environment variable 'OS_FAMILY' not set"
36-
exit 1
37-
fi
38-
39-
# Check if OS_FAMILY is set, needed for test
40-
if [[ -z "$OS_VERSION" ]]; then
41-
echo "Environment variable 'OS_FAMILY' not set"
42-
exit 1
43-
fi
44-
45-
echo "Starting serverspec"
46-
echo " OS: ${OS_FAMILY} Version ${OS_VERSION}"
47-
echo " Docker image: ${DOCKER_IMAGE}:${DOCKER_TAG}"
48-
echo " Dockerfile: ${DOCKERFILE}"
49-
echo ""
50-
51-
exec bundle exec rspec "$@"

tests/serverspec/spec/docker/ansible_spec.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
require 'serverspec'
22
require 'docker'
3-
require 'spec_helper'
3+
require 'spec_init'
44

55
describe "Dockerfile" do
66
before(:all) do
7-
@image = Docker::Image.build_from_dir('.', { 'dockerfile' => ENV['DOCKERFILE'] })
8-
set :docker_image, @image.id
7+
set :docker_image, ENV['DOCKERIMAGE_ID']
98
end
109

1110
include_examples 'collection::bootstrap'

tests/serverspec/spec/docker/apache-dev_spec.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
require 'serverspec'
22
require 'docker'
3-
require 'spec_helper'
3+
require 'spec_init'
44

55
describe "Dockerfile" do
66
before(:all) do
7-
@image = Docker::Image.build_from_dir('.', { 'dockerfile' => ENV['DOCKERFILE'] })
8-
set :docker_image, @image.id
7+
set :docker_image, ENV['DOCKERIMAGE_ID']
98
end
109

1110
include_examples 'collection::bootstrap'

tests/serverspec/spec/docker/apache_spec.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
require 'serverspec'
22
require 'docker'
3-
require 'spec_helper'
3+
require 'spec_init'
44

55
describe "Dockerfile" do
66
before(:all) do
7-
@image = Docker::Image.build_from_dir('.', { 'dockerfile' => ENV['DOCKERFILE'] })
8-
set :docker_image, @image.id
7+
set :docker_image, ENV['DOCKERIMAGE_ID']
98
end
109

1110
include_examples 'collection::bootstrap'

0 commit comments

Comments
 (0)