-
Notifications
You must be signed in to change notification settings - Fork 3
/
cimme.py
174 lines (136 loc) · 4.67 KB
/
cimme.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import yaml
import docker
import tempfile
import jinja2
import falcon
import threading
from wsgiref.simple_server import make_server
# Constants
restartPolicy = {'Name': 'on-failure', 'MaximumRetryCount': 0}
volumeDict = {'bind': '/tmp/workon', 'mode': 'rw'}
volumeDockerSocket = {'bind': '/var/run/docker.sock', 'mode': 'rw'}
class BuiltinVars:
COMMIT_HASH = None
REPO_CLONE_URL = ''
def get_vars(**kwargs):
print(kwargs)
vars = BuiltinVars()
for k, v in kwargs.items():
vars.__setattr__(k, v)
return vars
def get_pipeline(pipelineTemplate, vars):
# Render and load the pipeline YAML
renderedPipeline = jinja2.Template(pipelineTemplate).render(builtins=vars)
return yaml.safe_load(renderedPipeline)
def is_pipeline(pipeline):
# Check the type to ensure
if pipeline['type'] != 'pipeline':
print('type of YAML is not pipeline. Exiting with error.')
return False
return True
def streamLogs(container):
for logLine in container.logs(stream=True, timestamps=True):
print(logLine.decode(), end='')
def executeStep(client, step, workspace):
# Prepare Docker environment details for execution
stepImage = step['environment']
stepCommand = step.get('command')
stepEnvironments = step.get('params')
stepUser = step.get('user') or 0
volumesToMount = {workspace: volumeDict}
# Only mount Docker socket when explicitly requested
if step.get('dockersocket'):
volumesToMount['/var/run/docker.sock'] = volumeDockerSocket
# Run the step
stepContainer = client.containers.run(
stepImage,
command=stepCommand,
stderr=True,
remove=False,
detach=True,
user=stepUser,
volumes=volumesToMount,
working_dir='/tmp/workon',
environment=stepEnvironments,
)
return stepContainer
def executePipeline(client, pipeline):
if not is_pipeline(pipeline):
from sys import exit
exit(1)
workspace = tempfile.mkdtemp(dir='/tmp')
# Get and run the steps
steps = pipeline['steps']
for number, step in enumerate(steps):
print(f'** Executing: {number + 1}/{len(steps)}', step['name'], '**')
stepContainer = executeStep(client, step, workspace)
# Print logs realtime
streamLogs(stepContainer)
print('=' * 50, '\n')
# Evaluate exit code
result = stepContainer.wait()
if result['StatusCode'] != 0 or result['Error']:
print(
'Pipeline last step caused an error. See details in the log.\nExiting...'
)
break
def startABuild(repoURL, commitID):
examplePipeline = '''
---
type: pipeline
steps:
- name: Clone repo
environment: peptrnet/git:latest
params:
REPO_URL: https://github.com/gurayyildirim/rastgelesayi.git
- name: Check whether requirements installable
environment: python:3-alpine
command: pip install -r requirements.txt
- name: Build Docker image
environment: docker:stable
dockersocket: true
command: docker build -t 127.0.0.1:5000/guray/random:{{ builtins.COMMIT_HASH }} .
- name: Push Docker image
environment: docker:stable
dockersocket: true
command: docker push 127.0.0.1:5000/guray/random:{{ builtins.COMMIT_HASH }}
'''
# Initialize Docker client
client = docker.from_env()
# Get vars and render pipeline template
print(commitID)
vars = get_vars(COMMIT_HASH=commitID, REPO_CLONE_URL=repoURL)
pipeline = get_pipeline(examplePipeline, vars)
# Execute pipeline template
executePipeline(client, pipeline)
class PipelineExecution:
def __init__(self):
super().__init__()
def on_get(self, req, resp):
'''Handles GET requests'''
msg = {
'message': (
'please use post method to trigger'
)
}
resp.media = msg
def on_post(self, req, resp):
gitData = req.media
try:
commitID = gitData['commits'][0]['id']
repoURL = gitData['repository']['clone_url']
except:
resp.media = {'Status': 1,
'Detail': 'Cannot process because no key commits[0].id and repository.clone_url'}
resp.status = falcon.HTTP_422
return
t = threading.Thread(target=startABuild,
args=(repoURL, commitID)).start()
resp.media = {'Status': 0, 'Detail': 'Pipeline started.'}
api = falcon.API()
api.add_route('/', PipelineExecution())
if __name__ == '__main__':
with make_server('', 8000, api) as httpd:
print('Serving on port 8000...')
# Serve until process is killed
httpd.serve_forever()