Skip to content

Commit e02b9c0

Browse files
committed
chore(controller): add blocklist api
1 parent 4d8a20d commit e02b9c0

6 files changed

Lines changed: 140 additions & 20 deletions

File tree

rootfs/api/authentication.py

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,8 @@ def authenticate(self, request):
2121
return AnonymousUser(), None
2222

2323

24-
class AnonymousOrAuthenticatedAuthentication(authentication.BaseAuthentication):
25-
26-
def authenticate(self, request):
27-
"""
28-
Authenticate the request for anyone or if a valid token is provided, a user.
29-
"""
30-
try:
31-
return TokenAuthentication.authenticate(TokenAuthentication(), request)
32-
except Exception as e:
33-
logger.debug(e)
34-
return AnonymousUser(), None
35-
36-
3724
class DryccAuthentication(TokenAuthentication):
25+
3826
def authenticate(self, request):
3927
if 'Drycc' in request.META.get('HTTP_USER_AGENT', ''):
4028
auth = get_authorization_header(request).split()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Generated by Django 3.2.5 on 2021-12-08 02:08
2+
3+
from django.db import migrations, models
4+
import uuid
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('api', '0001_initial'),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name='Blocklist',
16+
fields=[
17+
('uuid', models.UUIDField(auto_created=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True, verbose_name='UUID')),
18+
('created', models.DateTimeField(auto_now_add=True)),
19+
('updated', models.DateTimeField(auto_now=True)),
20+
('id', models.CharField(db_index=True, max_length=128)),
21+
('type', models.PositiveIntegerField(choices=[(1, 'app'), (2, 'user')])),
22+
('remark', models.TextField(blank=True, default='Blocked for unknown reason', null=True)),
23+
],
24+
options={
25+
'ordering': ['-created'],
26+
'unique_together': {('id', 'type')},
27+
},
28+
),
29+
]

rootfs/api/models/blocklist.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from django.db import models
2+
from django.contrib.auth.models import User
3+
from api.models import UuidAuditedModel, App
4+
5+
6+
class Blocklist(UuidAuditedModel):
7+
"""
8+
You can block apps or users.
9+
If a user is blocked, all apps owned by the user will be stopped.
10+
The apps managed by the user will not be affected.
11+
"""
12+
type_choices = [(1, "app", ), (2, "user")]
13+
id = models.CharField(max_length=128, db_index=True)
14+
type = models.PositiveIntegerField(choices=type_choices)
15+
remark = models.TextField(blank=True, null=True, default="Blocked for unknown reason")
16+
17+
@property
18+
def related_apps(self):
19+
if self.type == 2:
20+
user = User.objects.get(id=self.id)
21+
return App.objects.filter(owner=user)
22+
else:
23+
return App.objects.filter(id=self.id)
24+
25+
@classmethod
26+
def get_type(cls, name: str):
27+
for _index, _name in cls.type_choices:
28+
if _name == name:
29+
return _index
30+
raise ValueError("This type was not found")
31+
32+
@classmethod
33+
def get_blocklist(cls, app: App):
34+
return cls.objects.filter(
35+
models.Q(id=app.id, type=1) | models.Q(id=app.owner_id, type=2)
36+
).first()
37+
38+
class Meta:
39+
ordering = ['-created']
40+
unique_together = (("id", "type"),)

rootfs/api/settings/testing.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,7 @@ def __getitem__(self, item):
6262

6363

6464
MIGRATION_MODULES = DisableMigrations()
65+
66+
# WORKFLOW_MANAGER_URL = "http://127.0.0.1:8000"
67+
WORKFLOW_MANAGER_ACCESS_KEY = "1234567890"
68+
WORKFLOW_MANAGER_SECRET_KEY = "1234567890"
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Unit tests for the Drycc api app.
4+
5+
Run the tests with "./manage.py test api"
6+
"""
7+
import base64
8+
from django.core.cache import cache
9+
from django.conf import settings
10+
from django.contrib.auth.models import User
11+
from rest_framework.authtoken.models import Token
12+
from api.tests import adapter, DryccTransactionTestCase
13+
import requests_mock
14+
15+
16+
@requests_mock.Mocker(real_http=True, adapter=adapter)
17+
class ManagerTest(DryccTransactionTestCase):
18+
"""Tests setting and updating config values"""
19+
20+
fixtures = ['tests.json']
21+
22+
def setUp(self):
23+
24+
self.user = User.objects.get(username='autotest')
25+
self.token = Token.objects.get(user=self.user).key
26+
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token)
27+
self.app_id = self.create_app()
28+
self.user_id = 7
29+
# workflow manager token
30+
token = base64.b85encode(b"%s:%s" % (
31+
settings.WORKFLOW_MANAGER_ACCESS_KEY.encode("utf8"),
32+
settings.WORKFLOW_MANAGER_SECRET_KEY.encode("utf8"),
33+
)).decode("utf8")
34+
self.client.credentials(HTTP_AUTHORIZATION='Token ' + token)
35+
36+
def tearDown(self):
37+
# Restore default tags to empty string
38+
settings.DRYCC_DEFAULT_CONFIG_TAGS = ''
39+
# make sure every test has a clean slate for k8s mocking
40+
cache.clear()
41+
42+
def test_block(self, mock_requests):
43+
response = self.client.post(
44+
'/v2/manager/{}/{}/block/'.format("users", 7),
45+
data={'remark': 'Arrears blockade'},
46+
)
47+
self.assertEqual(response.status_code, 201)
48+
49+
def test_unblock(self, mock_requests):
50+
response = self.client.post(
51+
'/v2/manager/{}/{}/block/'.format("users", 7),
52+
data={'remark': 'Arrears blockade'},
53+
)
54+
self.assertEqual(response.status_code, 201)
55+
response = self.client.delete(
56+
'/v2/manager/{}/{}/unblock/'.format("users", 7),
57+
)
58+
self.assertEqual(response.status_code, 204)

rootfs/api/views.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from rest_framework.response import Response
2020
from rest_framework.viewsets import GenericViewSet
2121

22-
from api import influxdb, models, permissions, serializers, viewsets
22+
from api import influxdb, models, permissions, serializers, viewsets, authentication
2323
from api.tasks import scale_app, restart_app
2424
from api.models import AlreadyExists, ServiceUnavailable, DryccException, \
2525
UnprocessableEntity
@@ -120,19 +120,19 @@ def list(self, request, **kwargs):
120120

121121

122122
class WorkflowManagerViewset(GenericViewSet):
123-
124123
permission_classes = (permissions.IsWorkflowManager, )
124+
authentication_classes = (authentication.AnonymousAuthentication, )
125125

126126
def block(self, request, **kwargs):
127127
try:
128-
blocklist = models.Blocklist(
128+
blocklist, _ = models.Blocklist.objects.get_or_create(
129129
id=kwargs['id'],
130130
type=models.Blocklist.get_type(kwargs["type"]),
131-
remark=request.data.get("remark")
131+
defaults={"remark": request.data.get("remark")}
132132
)
133-
apps = blocklist.related_apps
134-
[scale_app(app, app.owner, {key: 0 for key in app.structure.keys()}) for app in apps]
135-
blocklist.save()
133+
for app in blocklist.related_apps:
134+
scale_app.delay(app, app.owner, {key: 0 for key in app.structure.keys()})
135+
return HttpResponse(status=201)
136136
except ValueError as e:
137137
logger.info(e)
138138
raise DryccException("Unsupported block type: %s" % kwargs["type"])
@@ -143,6 +143,7 @@ def unblock(self, request, **kwargs):
143143
id=kwargs['id'],
144144
type=models.Blocklist.get_type(kwargs["type"])
145145
).delete()
146+
return HttpResponse(status=204)
146147
except ValueError as e:
147148
logger.info(e)
148149
raise DryccException("Unsupported block type: %s" % kwargs["type"])

0 commit comments

Comments
 (0)