Skip to content

Commit 886551f

Browse files
author
Gabriel Monroy
committed
Merge pull request #960 from deis/config-during-build
Expose runtime configuration during slugbuilder execution
2 parents f202918 + 1d46330 commit 886551f

5 files changed

Lines changed: 68 additions & 7 deletions

File tree

builder/templates/builder

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,21 @@ if __name__ == '__main__':
5656
if rc != 0:
5757
raise Exception('Could not extract git archive')
5858
dockerfile = os.path.join(temp_dir, 'Dockerfile')
59+
# pull config to be used during build
60+
body = {}
61+
body['receive_user'], body['receive_repo'] = user, app
62+
url = "{{ .deis_controller_protocol }}://{{ .deis_controller_host }}:{{ .deis_controller_port }}/api/hooks/config"
63+
headers = {'Content-Type': 'application/json', 'X-Deis-Builder-Auth': '{{ .deis_controller_builderKey }}'}
64+
r = requests.post(url, headers=headers, data=json.dumps(body))
65+
if r.status_code != 200:
66+
raise Exception('Config hook error: {} {}'.format(r.status_code, r.text))
67+
config_env = " ".join([ "-e {}='{}'".format(*kv) for kv in json.loads(r.json().get('values', '{}')).items()])
5968
# some applications do not have a Procfile, so only check for a Dockerfile
6069
if not os.path.exists(dockerfile):
6170
if os.path.exists('/buildpacks'):
62-
build_cmd = "docker run -i -a stdin -v {cache_dir}:/tmp/cache:rw -v /buildpacks:/tmp/buildpacks deis/slugbuilder".format(**locals())
71+
build_cmd = "docker run -i -a stdin {config_env} -v {cache_dir}:/tmp/cache:rw -v /buildpacks:/tmp/buildpacks deis/slugbuilder".format(**locals())
6372
else:
64-
build_cmd = "docker run -i -a stdin -v {cache_dir}:/tmp/cache:rw deis/slugbuilder".format(**locals())
73+
build_cmd = "docker run -i -a stdin {config_env} -v {cache_dir}:/tmp/cache:rw deis/slugbuilder".format(**locals())
6574
# run slugbuilder in the background
6675
p = subprocess.Popen("git archive master | " + build_cmd, shell=True, cwd=repo_dir, stdout=subprocess.PIPE)
6776
container = p.stdout.read().strip('\n')

controller/api/models.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,6 @@ def delete(self, *args, **kwargs):
129129

130130
def deploy(self, release):
131131
tasks.deploy_release.delay(self, release).get()
132-
if self.structure == {}:
133-
# scale the web process by 1 initially
134-
self.structure = {'web': 1}
135-
self.save()
136-
self.scale()
137132

138133
def destroy(self, *args, **kwargs):
139134
return self.delete(*args, **kwargs)

controller/api/tests/test_hooks.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,31 @@ def test_build_hook(self):
118118
self.assertIn('release', response.data)
119119
self.assertIn('version', response.data['release'])
120120
self.assertIn('domains', response.data)
121+
122+
def test_config_hook(self):
123+
"""Test reading Config via an API Hook"""
124+
url = '/api/apps'
125+
body = {'cluster': 'autotest'}
126+
response = self.client.post(url, json.dumps(body), content_type='application/json')
127+
self.assertEqual(response.status_code, 201)
128+
app_id = response.data['id']
129+
url = '/api/apps/{app_id}/config'.format(**locals())
130+
response = self.client.get(url)
131+
self.assertEqual(response.status_code, 200)
132+
self.assertIn('values', response.data)
133+
values = response.data['values']
134+
# prepare the config hook
135+
config = {'username': 'autotest', 'app': app_id}
136+
url = '/api/hooks/config'.format(**locals())
137+
body = {'receive_user': 'autotest',
138+
'receive_repo': app_id}
139+
# post without a session
140+
self.assertIsNone(self.client.logout())
141+
response = self.client.post(url, json.dumps(body), content_type='application/json')
142+
self.assertEqual(response.status_code, 403)
143+
# post with the builder auth key
144+
response = self.client.post(url, json.dumps(body), content_type='application/json',
145+
HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY)
146+
self.assertEqual(response.status_code, 200)
147+
self.assertIn('values', response.data)
148+
self.assertEqual(values, response.data['values'])

controller/api/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@
165165
166166
Create a new :class:`~api.models.Build`.
167167
168+
.. http:post:: /api/hooks/config/
169+
170+
Retrieve latest application :class:`~api.models.Config`.
171+
168172
169173
Auth
170174
====
@@ -279,6 +283,8 @@
279283
views.PushHookViewSet.as_view({'post': 'create'})),
280284
url(r'^hooks/build/?',
281285
views.BuildHookViewSet.as_view({'post': 'create'})),
286+
url(r'^hooks/config/?',
287+
views.ConfigHookViewSet.as_view({'post': 'create'})),
282288
# authn / authz
283289
url(r'^auth/register/?',
284290
views.UserRegistrationView.as_view({'post': 'create'})),

controller/api/views.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,11 @@ def post_save(self, build, created=False):
345345
release = build.app.release_set.latest()
346346
self.release = release.new(self.request.user, build=build)
347347
build.app.deploy(self.release)
348+
# scale the web process by 1 initially
349+
if build.app.structure == {}:
350+
build.app.structure = {'web': 1}
351+
build.app.save()
352+
build.app.scale()
348353

349354
def get_success_headers(self, data):
350355
headers = super(AppBuildViewSet, self).get_success_headers(data)
@@ -512,3 +517,21 @@ def post_save(self, build, created=False):
512517
release = build.app.release_set.latest()
513518
new_release = release.new(build.owner, build=build)
514519
build.app.deploy(new_release)
520+
521+
522+
class ConfigHookViewSet(BaseHookViewSet):
523+
"""API hook to grab latest :class:`~api.models.Config`"""
524+
525+
model = models.Config
526+
serializer_class = serializers.ConfigSerializer
527+
528+
def create(self, request, *args, **kwargs):
529+
app = get_object_or_404(models.App, id=request.DATA['receive_repo'])
530+
user = get_object_or_404(
531+
User, username=request.DATA['receive_user'])
532+
# check the user is authorized for this app
533+
if user == app.owner or user in get_users_with_perms(app):
534+
config = app.release_set.latest().config
535+
serializer = self.get_serializer(config)
536+
return Response(serializer.data, status=status.HTTP_200_OK)
537+
raise PermissionDenied()

0 commit comments

Comments
 (0)