This repository has been archived by the owner on May 6, 2020. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(model): Add new model to store settings
- Loading branch information
Showing
9 changed files
with
213 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# -*- coding: utf-8 -*- | ||
# Generated by Django 1.9.8 on 2016-08-12 19:05 | ||
from __future__ import unicode_literals | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
import uuid | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
('api', '0012_auto_20160810_1603'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='AppSettings', | ||
fields=[ | ||
('uuid', models.UUIDField(auto_created=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True, verbose_name='UUID')), | ||
('created', models.DateTimeField(auto_now_add=True)), | ||
('updated', models.DateTimeField(auto_now=True)), | ||
('maintenance', models.BooleanField(default=False)), | ||
('app', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.App')), | ||
('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), | ||
], | ||
options={ | ||
'get_latest_by': 'created', | ||
'ordering': ['-created'], | ||
}, | ||
), | ||
migrations.AlterUniqueTogether( | ||
name='appsettings', | ||
unique_together=set([('app', 'uuid')]), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import logging | ||
from django.conf import settings | ||
from django.db import models | ||
|
||
from api.models import UuidAuditedModel | ||
from api.exceptions import DeisException, AlreadyExists | ||
from scheduler import KubeException | ||
|
||
|
||
class AppSettings(UuidAuditedModel): | ||
""" | ||
Instance of Application settings used by scheduler | ||
""" | ||
|
||
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT) | ||
app = models.ForeignKey('App', on_delete=models.CASCADE) | ||
maintenance = models.BooleanField(default=False) | ||
|
||
class Meta: | ||
get_latest_by = 'created' | ||
unique_together = (('app', 'uuid')) | ||
ordering = ['-created'] | ||
|
||
def __str__(self): | ||
return "{}-{}".format(self.app.id, str(self.uuid)[:7]) | ||
|
||
def set_maintenance(self, maintenance): | ||
namespace = self.app.id | ||
service = self._fetch_service_config(namespace) | ||
old_service = service.copy() # in case anything fails for rollback | ||
|
||
try: | ||
service['metadata']['annotations']['router.deis.io/maintenance'] = str(maintenance) | ||
self._scheduler.update_service(namespace, namespace, data=service) | ||
except Exception as e: | ||
self._scheduler.update_service(namespace, namespace, data=old_service) | ||
raise KubeException(str(e)) from e | ||
|
||
def save(self, *args, **kwargs): | ||
summary = '' | ||
previous_settings = None | ||
try: | ||
previous_settings = self.app.appsettings_set.latest() | ||
except AppSettings.DoesNotExist: | ||
pass | ||
|
||
prev_maintenance = getattr(previous_settings, 'maintenance', None) | ||
new_maintenance = getattr(self, 'maintenance') | ||
|
||
try: | ||
if new_maintenance is None and prev_maintenance is not None: | ||
setattr(self, 'maintenance', prev_maintenance) | ||
elif prev_maintenance != new_maintenance: | ||
self.set_maintenance(new_maintenance) | ||
summary += "{} changed maintenance mode from {} to {}".format(self.owner, prev_maintenance, new_maintenance) # noqa | ||
except Exception as e: | ||
self.delete() | ||
raise DeisException(str(e)) from e | ||
|
||
if not summary and previous_settings: | ||
self.delete() | ||
raise AlreadyExists("{} changed nothing".format(self.owner)) | ||
self.app.log('summary of app setting changes: {}'.format(summary), logging.DEBUG) | ||
|
||
return super(AppSettings, self).save(**kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import requests_mock | ||
|
||
from django.core.cache import cache | ||
from django.contrib.auth.models import User | ||
from rest_framework.authtoken.models import Token | ||
|
||
from api.models import App | ||
from api.tests import adapter, DeisTransactionTestCase | ||
|
||
|
||
@requests_mock.Mocker(real_http=True, adapter=adapter) | ||
class TestAppSettings(DeisTransactionTestCase): | ||
"""Tests setting and updating config values""" | ||
|
||
fixtures = ['tests.json'] | ||
|
||
def setUp(self): | ||
self.user = User.objects.get(username='autotest') | ||
self.token = Token.objects.get(user=self.user).key | ||
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token) | ||
|
||
def tearDown(self): | ||
# make sure every test has a clean slate for k8s mocking | ||
cache.clear() | ||
|
||
def test_settings_maintenance(self, mock_requests): | ||
""" | ||
Test that maintenance can be applied | ||
""" | ||
app_id = self.create_app() | ||
app = App.objects.get(id=app_id) | ||
|
||
settings = {'maintenance': True} | ||
response = self.client.post( | ||
'/v2/apps/{app_id}/settings'.format(**locals()), | ||
settings) | ||
self.assertEqual(response.status_code, 201, response.data) | ||
self.assertTrue(response.data['maintenance']) | ||
self.assertTrue(app.appsettings_set.latest().maintenance) | ||
|
||
settings['maintenance'] = False | ||
response = self.client.post( | ||
'/v2/apps/{app_id}/settings'.format(**locals()), | ||
settings) | ||
self.assertEqual(response.status_code, 201, response.data) | ||
self.assertFalse(response.data['maintenance']) | ||
self.assertFalse(app.appsettings_set.latest().maintenance) | ||
|
||
response = self.client.post( | ||
'/v2/apps/{app_id}/settings'.format(**locals()), | ||
settings) | ||
self.assertEqual(response.status_code, 409, response.data) | ||
self.assertFalse(app.appsettings_set.latest().maintenance) | ||
|
||
settings = {} | ||
response = self.client.post( | ||
'/v2/apps/{app_id}/settings'.format(**locals()), | ||
settings) | ||
self.assertEqual(response.status_code, 409, response.data) | ||
self.assertFalse(app.appsettings_set.latest().maintenance) | ||
|
||
settings['maintenance'] = "test" | ||
response = self.client.post( | ||
'/v2/apps/{app_id}/settings'.format(**locals()), | ||
settings) | ||
self.assertEqual(response.status_code, 400, response.data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters