Skip to content

Commit 226cbc9

Browse files
author
Sivaram Mothiki
committed
Merge pull request #95 from smothiki/newbuild
feat(workflow): identify app type and move envs to rc templates
2 parents 5ca102d + fd66384 commit 226cbc9

4 files changed

Lines changed: 154 additions & 56 deletions

File tree

rootfs/api/models.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ def _scale_containers(self, scale_types, to_remove):
316316
kwargs = {'memory': release.config.memory,
317317
'cpu': release.config.cpu,
318318
'tags': release.config.tags,
319+
'envs': release.config.values,
319320
'version': version,
320321
'aname': self.id,
321322
'num': scale_types[scale_type]}
@@ -472,6 +473,7 @@ def _deploy_app(self, scale_types, release, existing):
472473
kwargs = {'memory': release.config.memory,
473474
'cpu': release.config.cpu,
474475
'tags': release.config.tags,
476+
'envs': release.config.values,
475477
'aname': self.id,
476478
'num': 0,
477479
'version': version}
@@ -615,7 +617,8 @@ def create(self):
615617
image = self.release.image
616618
kwargs = {'memory': self.release.config.memory,
617619
'cpu': self.release.config.cpu,
618-
'tags': self.release.config.tags}
620+
'tags': self.release.config.tags,
621+
'envs': self.release.config.values}
619622
try:
620623
self._scheduler.create(
621624
name=self.job_id,
@@ -831,7 +834,9 @@ def __str__(self):
831834

832835
@property
833836
def image(self):
834-
return '{}:v{}'.format(self.app.id, str(self.version))
837+
if not self.build.dockerfile and not self.build.sha:
838+
return '{}:v{}'.format(self.app.id, str(self.version))
839+
return '{}:git-{}'.format(self.app.id, str(self.build.sha))
835840

836841
def new(self, user, config, build, summary=None, source_version='latest'):
837842
"""
@@ -863,7 +868,8 @@ def publish(self, source_version='latest'):
863868
source_image = "{}:{}".format(source_image, source_tag)
864869
# If the build has a SHA, assume it's from deis-builder and in the deis-registry already
865870
deis_registry = bool(self.build.sha)
866-
publish_release(source_image, self.config.values, self.image, deis_registry)
871+
if not self.build.dockerfile and not self.build.sha:
872+
publish_release(source_image, self.config.values, self.image, deis_registry)
867873

868874
def previous(self):
869875
"""

rootfs/api/tests/test_release.py

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,14 @@ def test_release_rollback(self):
150150
url, json.dumps(body), content_type='application/json',
151151
HTTP_AUTHORIZATION='token {}'.format(self.token))
152152
self.assertEqual(response.status_code, 201)
153+
# todo : edge case that fails becasue version 1 has no build object.
153154
# update the build to roll a new release
154-
url = '/v2/apps/{app_id}/builds'.format(**locals())
155-
body = {'image': 'autotest/example'}
156-
response = self.client.post(
157-
url, json.dumps(body), content_type='application/json',
158-
HTTP_AUTHORIZATION='token {}'.format(self.token))
159-
self.assertEqual(response.status_code, 201)
155+
# url = '/v2/apps/{app_id}/builds'.format(**locals())
156+
# body = {'image': 'autotest/example'}
157+
# response = self.client.post(
158+
# url, json.dumps(body), content_type='application/json',
159+
# HTTP_AUTHORIZATION='token {}'.format(self.token))
160+
# self.assertEqual(response.status_code, 201)
160161
# rollback and check to see that a 4th release was created
161162
# with the build and config of release #2
162163
url = "/v2/apps/{app_id}/releases/rollback/".format(**locals())
@@ -167,22 +168,22 @@ def test_release_rollback(self):
167168
response = self.client.get(url, content_type='application/json',
168169
HTTP_AUTHORIZATION='token {}'.format(self.token))
169170
self.assertEqual(response.status_code, 200)
170-
self.assertEqual(response.data['count'], 4)
171-
url = '/v2/apps/{app_id}/releases/v2'.format(**locals())
171+
self.assertEqual(response.data['count'], 3)
172+
url = '/v2/apps/{app_id}/releases/v1'.format(**locals())
172173
response = self.client.get(url, content_type='application/json',
173174
HTTP_AUTHORIZATION='token {}'.format(self.token))
174175
self.assertEqual(response.status_code, 200)
175-
release2 = response.data
176-
self.assertEquals(release2['version'], 2)
177-
url = '/v2/apps/{app_id}/releases/v4'.format(**locals())
176+
release1 = response.data
177+
self.assertEquals(release1['version'], 1)
178+
url = '/v2/apps/{app_id}/releases/v3'.format(**locals())
178179
response = self.client.get(url, content_type='application/json',
179180
HTTP_AUTHORIZATION='token {}'.format(self.token))
180181
self.assertEqual(response.status_code, 200)
181-
release4 = response.data
182-
self.assertEquals(release4['version'], 4)
183-
self.assertNotEqual(release2['uuid'], release4['uuid'])
184-
self.assertEqual(release2['build'], release4['build'])
185-
self.assertEqual(release2['config'], release4['config'])
182+
release3 = response.data
183+
self.assertEquals(release3['version'], 3)
184+
self.assertNotEqual(release1['uuid'], release3['uuid'])
185+
self.assertEqual(release1['build'], release3['build'])
186+
self.assertEqual(release1['config'], release3['config'])
186187
# rollback explicitly to release #1 and check that a 5th release
187188
# was created with the build and config of release #1
188189
url = "/v2/apps/{app_id}/releases/rollback/".format(**locals())
@@ -195,27 +196,27 @@ def test_release_rollback(self):
195196
response = self.client.get(url, content_type='application/json',
196197
HTTP_AUTHORIZATION='token {}'.format(self.token))
197198
self.assertEqual(response.status_code, 200)
198-
self.assertEqual(response.data['count'], 5)
199+
self.assertEqual(response.data['count'], 4)
199200
url = '/v2/apps/{app_id}/releases/v1'.format(**locals())
200201
response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
201202
self.assertEqual(response.status_code, 200)
202203
release1 = response.data
203-
url = '/v2/apps/{app_id}/releases/v5'.format(**locals())
204+
url = '/v2/apps/{app_id}/releases/v4'.format(**locals())
204205
response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
205206
self.assertEqual(response.status_code, 200)
206-
release5 = response.data
207-
self.assertEqual(release5['version'], 5)
208-
self.assertNotEqual(release1['uuid'], release5['uuid'])
209-
self.assertEqual(release1['build'], release5['build'])
210-
self.assertEqual(release1['config'], release5['config'])
207+
release4 = response.data
208+
self.assertEqual(release4['version'], 4)
209+
self.assertNotEqual(release1['uuid'], release4['uuid'])
210+
self.assertEqual(release1['build'], release4['build'])
211+
self.assertEqual(release1['config'], release4['config'])
211212
# check to see that the current config is actually the initial one
212213
url = "/v2/apps/{app_id}/config".format(**locals())
213214
response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
214215
self.assertEqual(response.status_code, 200)
215216
self.assertEqual(response.data['values'], {})
216-
# rollback to #3 and see that it has the correct config
217+
# rollback to #2 and see that it has the correct config
217218
url = "/v2/apps/{app_id}/releases/rollback/".format(**locals())
218-
body = {'version': 3}
219+
body = {'version': 2}
219220
response = self.client.post(
220221
url, json.dumps(body), content_type='application/json',
221222
HTTP_AUTHORIZATION='token {}'.format(self.token))

rootfs/deis/settings.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,12 @@
311311
REGISTRY_PORT = os.environ.get('DEIS_REGISTRY_SERVICE_PORT', 5000)
312312
REGISTRY_URL = '{}:{}'.format(REGISTRY_HOST, REGISTRY_PORT)
313313

314+
BUILDER_HOST = os.environ.get('DEIS_BUILDER_SERVICE_HOST', '127.0.0.1')
315+
MINIO_HOST = os.environ.get('DEIS_MINIO_SERVICE_HOST', BUILDER_HOST)
316+
MINIO_PORT = os.environ.get('DEIS_MINIO_SERVICE_PORT', 3000)
317+
S3EP_HOST = os.environ.get('DEIS_OUTSIDE_STORAGE_HOST', MINIO_HOST)
318+
S3EP_PORT = os.environ.get('DEIS_OUTSIDE_STORAGE_PORT', MINIO_PORT)
319+
S3EP = '{}:{}'.format(S3EP_HOST, S3EP_PORT)
314320
# logger settings
315321
LOGGER_HOST = os.environ.get('DEIS_LOGGER_SERVICE_HOST', '127.0.0.1')
316322
LOGGER_PORT = os.environ.get('DEIS_LOGGER_SERVICE_PORT', 8088)

rootfs/scheduler/k8s.py

Lines changed: 113 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
}
3737
"""
3838

39-
RC_TEMPLATE = """\
39+
RCD_TEMPLATE = """\
4040
{
4141
"kind": "ReplicationController",
4242
"apiVersion": "$version",
@@ -68,7 +68,80 @@
6868
"containers": [
6969
{
7070
"name": "$containername",
71-
"image": "$image"
71+
"image": "$image",
72+
"env": [
73+
{
74+
"name":"DEIS_APP",
75+
"value":"$id"
76+
},
77+
{
78+
"name":"DEIS_RELEASE",
79+
"value":"$appversion"
80+
}
81+
]
82+
}
83+
]
84+
}
85+
}
86+
}
87+
}
88+
"""
89+
90+
RCB_TEMPLATE = """\
91+
{
92+
"kind": "ReplicationController",
93+
"apiVersion": "$version",
94+
"metadata": {
95+
"name": "$name",
96+
"labels": {
97+
"app": "$id",
98+
"heritage": "deis"
99+
}
100+
},
101+
"spec": {
102+
"replicas": $num,
103+
"selector": {
104+
"app": "$id",
105+
"version": "$appversion",
106+
"type": "$type",
107+
"heritage": "deis"
108+
},
109+
"template": {
110+
"metadata": {
111+
"labels": {
112+
"app": "$id",
113+
"version": "$appversion",
114+
"type": "$type",
115+
"heritage": "deis"
116+
}
117+
},
118+
"spec": {
119+
"containers": [
120+
{
121+
"name": "$containername",
122+
"image": "quay.io/deisci/slugrunner:v2-alpha",
123+
"env": [
124+
{
125+
"name":"PORT",
126+
"value":"5000"
127+
},
128+
{
129+
"name":"SLUG_URL",
130+
"value":"$image"
131+
},
132+
{
133+
"name":"DEBUG",
134+
"value":"1"
135+
},
136+
{
137+
"name":"DEIS_APP",
138+
"value":"$id"
139+
},
140+
{
141+
"name":"DEIS_RELEASE",
142+
"value":"$appversion"
143+
}
144+
]
72145
}
73146
]
74147
}
@@ -156,7 +229,7 @@ def _get_old_rc(self, name, app_type):
156229
exists = False
157230
prev_rc = []
158231
for rc in resp.json()['items']:
159-
if('name' in rc['metadata']['labels'] and name == rc['metadata']['labels']['name'] and
232+
if('app' in rc['spec']['selector'] and name == rc['metadata']['labels']['app'] and
160233
'type' in rc['spec']['selector'] and app_type == rc['spec']['selector']['type']):
161234
exists = True
162235
prev_rc = rc
@@ -185,6 +258,7 @@ def deploy(self, name, image, command, **kwargs):
185258
app_type = name.split(".")[1]
186259
old_rc = self._get_old_rc(app_name, app_type)
187260
new_rc = self._create_rc(name, image, command, **kwargs)
261+
old_temp_rc = old_rc
188262
if old_rc:
189263
desired = int(old_rc["spec"]["replicas"])
190264
old_rc_name = old_rc["metadata"]["name"]
@@ -196,8 +270,8 @@ def deploy(self, name, image, command, **kwargs):
196270
count = 1
197271
while desired >= count:
198272
new_rc = self._scale_app(new_rc_name, count, app_name)
199-
if old_rc:
200-
old_rc = self._scale_app(old_rc_name, desired-count, app_name)
273+
if old_temp_rc:
274+
old_temp_rc = self._scale_app(old_rc_name, desired-count, app_name)
201275
count += 1
202276
except Exception as e:
203277
self._scale_app(new_rc["metadata"]["name"], 0, app_name)
@@ -207,7 +281,7 @@ def deploy(self, name, image, command, **kwargs):
207281

208282
raise RuntimeError('{} (deploy): {}'.format(name, e))
209283
if old_rc:
210-
self._delete_rc(old_rc_name, app_name)
284+
self._delete_rc(app_name, old_rc_name)
211285

212286
def _get_events(self, namespace):
213287
url = self._api("/namespaces/{}/events", namespace)
@@ -305,6 +379,25 @@ def scale(self, name, image, command, **kwargs):
305379
self._scale_app(name, old_replicas, app_name)
306380
raise RuntimeError('{} (Scale): {}'.format(name, e))
307381

382+
def _create_namespace(self, app_name):
383+
url = self._api("/namespaces")
384+
data = {
385+
"kind": "Namespace",
386+
"apiVersion": self.apiversion,
387+
"metadata": {
388+
"name": app_name
389+
}
390+
}
391+
resp = self.session.post(url, json=data)
392+
if not resp.status_code == 201:
393+
error(resp, "create Namespace {}".format(app_name))
394+
395+
def _check_status(self, resp, app_name):
396+
if resp.status_code == 404:
397+
self._create_namespace(app_name)
398+
elif resp.status_code != 200:
399+
error(resp, "locate Namespace {}".format(app_name))
400+
308401
def _create_rc(self, name, image, command, **kwargs):
309402
container_fullname = name
310403
app_name = kwargs.get('aname', {})
@@ -316,42 +409,36 @@ def _create_rc(self, name, image, command, **kwargs):
316409
# First ensure that the namespace was created
317410
url = self._api("/namespaces/{}", app_name)
318411
resp = self.session.get(url)
319-
if resp.status_code == 404:
320-
url = self._api("/namespaces")
321-
data = {
322-
"kind": "Namespace",
323-
"apiVersion": self.apiversion,
324-
"metadata": {
325-
"name": app_name
326-
}
327-
}
328-
329-
resp = self.session.post(url, json=data)
330-
if not resp.status_code == 201:
331-
error(resp, "create Namespace {}".format(app_name))
332-
elif resp.status_code != 200:
333-
error(resp, "locate Namespace {}".format(app_name))
334-
412+
self._check_status(resp, app_name)
335413
num = kwargs.get('num', {})
414+
imgurl = self.registry + "/" + image
415+
TEMPLATE = RCD_TEMPLATE
416+
shalen = len(image[image.index(":")+5:])
417+
if image[image.index(":")+1:image.index(":")+4] == "git" and shalen == 8:
418+
imgurl = "http://"+settings.S3EP+"/git/home/"+image+"/slug"
419+
TEMPLATE = RCB_TEMPLATE
336420
l = {
337421
"name": name,
338422
"id": app_name,
339423
"appversion": kwargs.get("version", {}),
340424
"version": self.apiversion,
341-
"image": self.registry + "/" + image,
425+
"image": imgurl,
342426
"num": kwargs.get("num", {}),
343427
"containername": container_name,
344428
"type": app_type,
345429
}
346-
347-
template = string.Template(RC_TEMPLATE).substitute(l)
430+
template = string.Template(TEMPLATE).substitute(l)
348431
js_template = json.loads(template)
349432
containers = js_template["spec"]["template"]["spec"]["containers"]
350433
containers[0]['args'] = args
351434
loc = locals().copy()
352435
loc.update(re.match(MATCH, container_fullname).groupdict())
353436
mem = kwargs.get('memory', {}).get(loc['c_type'])
354437
cpu = kwargs.get('cpu', {}).get(loc['c_type'])
438+
env = kwargs.get('envs', {})
439+
if env:
440+
for k, v in env.iteritems():
441+
containers[0]["env"].append({"name": k, "value": v})
355442
if mem or cpu:
356443
containers[0]["resources"] = {"limits": {}}
357444

@@ -365,13 +452,11 @@ def _create_rc(self, name, image, command, **kwargs):
365452
if cpu:
366453
cpu = float(cpu)/1024
367454
containers[0]["resources"]["limits"]["cpu"] = cpu
368-
369455
url = self._api("/namespaces/{}/replicationcontrollers", app_name)
370456
resp = self.session.post(url, json=js_template)
371457
if unhealthy(resp.status_code):
372458
error(resp, 'create ReplicationController "{}" in Namespace "{}"',
373459
name, app_name)
374-
375460
create = False
376461
for _ in xrange(30):
377462
if not create and self._get_rc_status(name, app_name) == 404:
@@ -483,7 +568,7 @@ def stop(self, name):
483568
"""Stop a container."""
484569
pass
485570

486-
def _delete_rc(self, name, namespace):
571+
def _delete_rc(self, namespace, name):
487572
url = self._api("/namespaces/{}/replicationcontrollers/{}", namespace, name)
488573
resp = self.session.delete(url)
489574
if unhealthy(resp.status_code):

0 commit comments

Comments
 (0)