Skip to content

Commit dc5a3a5

Browse files
author
Matthew Fisher
committed
Merge pull request #3068 from bacongobbler/2930-kill-processes-removed-from-procfile
fix(controller): kill processes removed from procfile
2 parents 9eae121 + 05c322c commit dc5a3a5

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

controller/api/models.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ def _start_containers(self, to_add):
256256
def _destroy_containers(self, to_destroy):
257257
"""Destroys containers via the scheduler"""
258258
destroy_threads = []
259+
if not to_destroy:
260+
# do nothing if we didn't request any containers
261+
return
259262
for c in to_destroy:
260263
destroy_threads.append(threading.Thread(target=c.destroy))
261264
[t.start() for t in destroy_threads]
@@ -589,6 +592,19 @@ def create(self, user, *args, **kwargs):
589592
new_release.delete()
590593
raise
591594

595+
def save(self, **kwargs):
596+
try:
597+
previous_build = self.app.build_set.latest()
598+
to_destroy = []
599+
for proctype in previous_build.procfile.keys():
600+
if proctype not in self.procfile.keys():
601+
for c in self.app.container_set.filter(type=proctype):
602+
to_destroy.append(c)
603+
self.app._destroy_containers(to_destroy)
604+
except Build.DoesNotExist:
605+
pass
606+
return super(Build, self).save(**kwargs)
607+
592608
def __str__(self):
593609
return "{0}-{1}".format(self.app.id, self.uuid[:7])
594610

controller/api/tests/test_container.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@ def test_container_release(self):
262262
self.assertEqual(response.data['results'][0]['release'], 'v2')
263263
# post a new build
264264
url = "/v1/apps/{app_id}/builds".format(**locals())
265-
body = {'image': 'autotest/example'}
265+
# a web proctype must exist on the second build or else the container will be removed
266+
body = {'image': 'autotest/example', 'procfile': {'web': 'echo hi'}}
266267
response = self.client.post(url, json.dumps(body), content_type='application/json',
267268
HTTP_AUTHORIZATION='token {}'.format(self.token))
268269
self.assertEqual(response.status_code, 201)
@@ -606,3 +607,30 @@ def test_scale_with_unauthorized_user_returns_403(self):
606607
response = self.client.post(url, json.dumps(body), content_type='application/json',
607608
HTTP_AUTHORIZATION='token {}'.format(unauthorized_token))
608609
self.assertEqual(response.status_code, 403)
610+
611+
def test_modified_procfile_from_build_removes_containers(self):
612+
"""
613+
When a new procfile is posted which removes a certain process type, deis should stop the
614+
existing containers.
615+
"""
616+
url = '/v1/apps'
617+
response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
618+
self.assertEqual(response.status_code, 201)
619+
app_id = response.data['id']
620+
# post a new build
621+
build_url = "/v1/apps/{app_id}/builds".format(**locals())
622+
body = {'image': 'autotest/example', 'sha': 'a'*40,
623+
'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
624+
response = self.client.post(build_url, json.dumps(body), content_type='application/json',
625+
HTTP_AUTHORIZATION='token {}'.format(self.token))
626+
url = "/v1/apps/{app_id}/scale".format(**locals())
627+
body = {'web': 4}
628+
response = self.client.post(url, json.dumps(body), content_type='application/json',
629+
HTTP_AUTHORIZATION='token {}'.format(self.token))
630+
self.assertEqual(response.status_code, 204)
631+
body = {'image': 'autotest/example', 'sha': 'a'*40,
632+
'procfile': json.dumps({'worker': 'node worker.js'})}
633+
response = self.client.post(build_url, json.dumps(body), content_type='application/json',
634+
HTTP_AUTHORIZATION='token {}'.format(self.token))
635+
self.assertEqual(response.status_code, 201)
636+
self.assertEqual(Container.objects.filter(type='web').count(), 0)

0 commit comments

Comments
 (0)