Navigation Menu

Skip to content
This repository has been archived by the owner on May 6, 2020. It is now read-only.

Commit

Permalink
feat(models): add routable flag to Config (#934)
Browse files Browse the repository at this point in the history
If an app is considered non-routable, it is removed from the router mesh.
  • Loading branch information
Matthew Fisher committed Aug 9, 2016
1 parent 544f492 commit a7cff7e
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 7 deletions.
21 changes: 21 additions & 0 deletions rootfs/api/migrations/0011_config_routable.py
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.8 on 2016-07-29 21:59
from __future__ import unicode_literals

import api.models.key
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api', '0010_config_healthcheck'),
]

operations = [
migrations.AddField(
model_name='config',
name='routable',
field=models.BooleanField(default=True),
),
]
7 changes: 4 additions & 3 deletions rootfs/api/models/app.py
Expand Up @@ -403,7 +403,7 @@ def _scale_pods(self, scale_types):
for scale_type, replicas in scale_types.items():
# only web / cmd are routable
# http://docs.deis.io/en/latest/using_deis/process-types/#web-vs-cmd-process-types
routable = True if scale_type in ['web', 'cmd'] else False
routable = True if scale_type in ['web', 'cmd'] and release.config.routable else False
# fetch application port and inject into ENV Vars as needed
port = release.get_port()
if port:
Expand Down Expand Up @@ -481,7 +481,7 @@ def deploy(self, release, force_deploy=False):
for scale_type, replicas in self.structure.items():
# only web / cmd are routable
# http://docs.deis.io/en/latest/using_deis/process-types/#web-vs-cmd-process-types
routable = True if scale_type in ['web', 'cmd'] else False
routable = True if scale_type in ['web', 'cmd'] and release.config.routable else False
# fetch application port and inject into ENV vars as needed
port = release.get_port()
if port:
Expand Down Expand Up @@ -580,7 +580,8 @@ def verify_application_health(self, **kwargs):
only run after kubernetes has reported all pods as healthy
"""
# Bail out early if the application is not routable
if not kwargs.get('routable', False):
release = self.release_set.latest()
if not kwargs.get('routable', False) and release.config.routable:
return

app_type = kwargs.get('app_type')
Expand Down
1 change: 1 addition & 0 deletions rootfs/api/models/config.py
Expand Up @@ -21,6 +21,7 @@ class Config(UuidAuditedModel):
tags = JSONField(default={}, blank=True)
registry = JSONField(default={}, blank=True)
healthcheck = JSONField(default={}, blank=True)
routable = models.BooleanField(default=True)

class Meta:
get_latest_by = 'created'
Expand Down
11 changes: 11 additions & 0 deletions rootfs/api/models/release.py
Expand Up @@ -481,6 +481,17 @@ def save(self, *args, **kwargs): # noqa
self.summary += ' and '
self.summary += "{} {}".format(self.config.owner, changes)

# if the routable flag changed, log that too
changes = []
old_routable = old_config.routable if old_config else True
enabled = "enabled routing" if self.config.routable and not old_routable else ''
disabled = "disabled routing" if not self.config.routable and old_routable else ''
changes = ', '.join(i for i in (enabled, disabled) if i)
if changes:
if self.summary:
self.summary += ' and '
self.summary += "{} {}".format(self.config.owner, changes)

if not self.summary:
if self.version == 1:
self.summary = "{} created the initial release".format(self.owner)
Expand Down
1 change: 1 addition & 0 deletions rootfs/api/serializers.py
Expand Up @@ -200,6 +200,7 @@ class ConfigSerializer(serializers.ModelSerializer):
tags = JSONFieldSerializer(required=False, binary=True)
registry = JSONFieldSerializer(required=False, binary=True)
healthcheck = JSONFieldSerializer(convert_to_str=False, required=False, binary=True)
routable = serializers.BooleanField(required=False)

class Meta:
"""Metadata options for a :class:`ConfigSerializer`."""
Expand Down
1 change: 1 addition & 0 deletions rootfs/api/tests/test_app.py
Expand Up @@ -498,6 +498,7 @@ def test_list_ordering(self, mock_requests):
self.assertEqual(apps[2]['id'], 'tango')
self.assertEqual(apps[3]['id'], 'zulu')


FAKE_LOG_DATA = """
2013-08-15 12:41:25 [33454] [INFO] Starting gunicorn 17.5
2013-08-15 12:41:25 [33454] [INFO] Listening at: http://0.0.0.0:5000 (33454)
Expand Down
22 changes: 20 additions & 2 deletions rootfs/api/tests/test_config.py
Expand Up @@ -131,7 +131,7 @@ def test_response_data(self, mock_requests):
response = self.client.post(url, body)
for key in response.data:
self.assertIn(key, ['uuid', 'owner', 'created', 'updated', 'app', 'values', 'memory',
'cpu', 'tags', 'registry', 'healthcheck'])
'cpu', 'tags', 'registry', 'healthcheck', 'routable'])
expected = {
'owner': self.user.username,
'app': app_id,
Expand All @@ -154,7 +154,7 @@ def test_response_data_types_converted(self, mock_requests):
self.assertEqual(response.status_code, 201, response.data)
for key in response.data:
self.assertIn(key, ['uuid', 'owner', 'created', 'updated', 'app', 'values', 'memory',
'cpu', 'tags', 'registry', 'healthcheck'])
'cpu', 'tags', 'registry', 'healthcheck', 'routable'])
expected = {
'owner': self.user.username,
'app': app_id,
Expand Down Expand Up @@ -325,3 +325,21 @@ def test_unauthorized_user_cannot_modify_config(self, mock_requests):
body = {'values': {'FOO': 'bar'}}
response = self.client.post(url, body)
self.assertEqual(response.status_code, 403)

def test_config_routable(self, mock_requests):
"""
Create an application with the routable flag turned on or off
"""
# create app, expecting routable to be true
body = {'id': 'myid'}
response = self.client.post('/v2/apps', body)
self.assertEqual(response.status_code, 201, response.data)
app = App.objects.get(id='myid')
self.assertTrue(app.config_set.latest().routable)
# Set routable to false
response = self.client.post(
'/v2/apps/{app.id}/config'.format(**locals()),
{'routable': False}
)
self.assertEqual(response.status_code, 201, response.data)
self.assertFalse(app.config_set.latest().routable)
17 changes: 15 additions & 2 deletions rootfs/api/tests/test_release.py
Expand Up @@ -194,10 +194,23 @@ def test_release_str(self, mock_requests):

def test_release_summary(self, mock_requests):
"""Test the text summary of a release."""
release3 = self.test_release()
release = Release.objects.get(uuid=release3['uuid'])
release = self.test_release()
app = App.objects.get(id=release['app'])
release = app.release_set.latest()
# check that the release has push and env change messages
self.assertIn('autotest deployed ', release.summary)
# add config and routable flags, confirm that routable
# and config objects are in the summary
url = '/v2/apps/{app.id}/config'.format(**locals())
body = {
'values': json.dumps({'FOO': 'bar'}),
'routable': False,
}
response = self.client.post(url, body)
self.assertEqual(response.status_code, 201, response.data)
self.assertEqual(
'autotest added FOO and autotest disabled routing',
app.release_set.latest().summary)

def test_admin_can_create_release(self, mock_requests):
"""If a non-user creates an app, an admin should be able to create releases."""
Expand Down

0 comments on commit a7cff7e

Please sign in to comment.