-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcommon_docker_steps.py
117 lines (94 loc) · 3.86 KB
/
common_docker_steps.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# -*- coding: UTF-8 -*-
# Some useful functions for your docker container steps
from behave import step, given, then
import os
from time import sleep
@given(u'the project contains Dockerfile')
@given(u'the project contains docker file in "{filename}"')
def project_has_dockerfile(context, filename=None):
if not filename:
# Look for dockerfile passed from cli-tool
if 'DOCKERFILE' in context.config.userdata:
filename = context.config.userdata['DOCKERFILE']
else:
filename = 'Dockerfile'
abs_path = os.path.abspath(filename)
if not os.path.exists(abs_path):
context.scenario.skip(reason='File %s not found' % abs_path)
context.dockerfile = abs_path
@step(u'First dockerfile instruction is FROM')
def first_instruction_is_from(context):
with open(context.dockerfile, "r") as f:
first_line = f.readline()
# Skip blank lines and comments
while len(first_line.strip()) == 0 or first_line.strip()[0] == '#':
first_line = f.readline()
assert first_line.split(' ')[0] == 'FROM',\
"Expected first line to be FROM, but was '%s'" % first_line
@step(u"dockerfile doesn't contain unknown instructions")
def check_for_unknown_instructions(context):
valid_instructions = set([
'FROM', 'MAINTAINER', 'RUN', 'CMD', 'LABEL', 'EXPOSE', 'ENV', 'ADD', 'COPY',
'ENTRYPOINT', 'VOLUME', 'USER', 'WORKDIR', 'ONBUILD'])
lines = []
instructions = []
last_instruction = ''
with open(context.dockerfile, "r") as f:
lines = f.readlines()
line_continuation = False
for line in lines:
line = line.strip()
if not line or line[0] == '#':
# Skip comment lines
continue
# Set line continuation var
if not line_continuation:
last_instruction = line.split(' ')[0]
instructions.append(last_instruction)
if line[-1] == '\\':
line_continuation = True
else:
line_continuation = False
# Find the diff between two sets
instructions_set = set(instructions)
list_diff = list(instructions_set - valid_instructions)
assert list_diff == [], "Unknown instructions: %s" % list_diff
@step(u'Docker container is started')
@step(u'Docker container is started with params "{params}"')
def container_started(context, params=''):
# TODO: allow tables here
context.job = context.run('docker run -d --cidfile %s %s %s' % (
context.cid_file, params, context.image))
context.cid = context.open_file(context.cid_file).read().strip()
for attempts in xrange(0, 30):
try:
state = context.run(
"docker inspect --format='{{.State.Running}}' %s" % context.cid).strip()
if state == 'true':
return
exit_code = context.run(
"docker inspect --format='{{.State.ExitCode}}' %s" % context.cid).strip()
if exit_code != '':
break
except:
pass
sleep(1)
raise Exception("Container failed to start")
@then(u'Dockerfile_lint passes')
def dockefile_lint(context):
try:
context.run('which dockerfile_lint')
except AssertionError:
context.scenario.skip(reason='Dockerfile_lint not found')
return
print(context.run('dockerfile_lint -f Dockerfile'))
@then(u'Image can be build from Dockerfile')
def build_image_from_dockerfile(context):
# Due to behave bug (to-be-filed) we can't reuse 'the project contains Dockerfile' step
# also we don't seem to handle non-standart file paths here
abs_path = os.path.abspath('Dockerfile')
if not os.path.exists(abs_path):
context.scenario.skip(reason='File %s not found' % abs_path)
return
context.image = context.config.userdata.get('IMAGE', 'ctf')
context.run('docker build -t {0} .'.format(context.image))