Skip to content

Commit 64b4ffc

Browse files
committed
feat(release): add ptypes filter
1 parent 963171d commit 64b4ffc

5 files changed

Lines changed: 93 additions & 5 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Generated by Django 4.2.16 on 2024-10-21 04:45
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('api', '0015_alter_appsettings_autodeploy_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name='route',
15+
name='port',
16+
),
17+
migrations.RemoveField(
18+
model_name='route',
19+
name='ptype',
20+
),
21+
migrations.AddField(
22+
model_name='release',
23+
name='deployed_ptypes',
24+
field=models.JSONField(default=list),
25+
),
26+
]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Generated by Django 4.2.15 on 2024-09-06 03:58
2+
3+
from django.db import migrations
4+
from api.models.release import Release
5+
6+
7+
def migration_deployed_ptypes(apps, schema_editor):
8+
for release in Release.objects.all():
9+
deployed_ptypes = set()
10+
for condition in release.conditions:
11+
if condition["ptypes"] is None:
12+
deployed_ptypes = release.ptypes
13+
break
14+
else:
15+
deployed_ptypes = deployed_ptypes.union(condition["ptypes"])
16+
release.deployed_ptypes = list(deployed_ptypes)
17+
release.save()
18+
19+
20+
class Migration(migrations.Migration):
21+
22+
dependencies = [
23+
('api', '0016_remove_route_port_remove_route_ptype_and_more'),
24+
]
25+
26+
operations = [
27+
migrations.RunPython(migration_deployed_ptypes),
28+
]

rootfs/api/models/release.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from scheduler import KubeHTTPException
1313
from scheduler.resources.pod import DEFAULT_CONTAINER_PORT
1414

15-
from ..utils import DeployLock
15+
from ..utils import CacheLock, DeployLock
1616

1717
from .base import UuidAuditedModel
1818
from .appsettings import AppSettings
@@ -41,6 +41,7 @@ class Release(UuidAuditedModel):
4141
failed = models.BooleanField(default=False)
4242
exception = models.TextField(blank=True, null=True)
4343
conditions = models.JSONField(default=list)
44+
deployed_ptypes = models.JSONField(default=list)
4445

4546
config = models.ForeignKey('Config', on_delete=models.CASCADE)
4647
build = models.ForeignKey('Build', null=True, on_delete=models.CASCADE)
@@ -163,9 +164,23 @@ def get_port(self, ptype):
163164
'PORT', self.config.values.get('PORT', DEFAULT_CONTAINER_PORT)))
164165

165166
def deploy(self, ptypes=None, force_deploy=False):
166-
lock = DeployLock(self.app.pk)
167-
if not lock.acquire(ptypes, force=force_deploy):
168-
raise DryccException('there is an executing pipeline, please wait or force deploy')
167+
msg = 'there is an executing pipeline, please wait or force deploy'
168+
# change deployed_ptypes lock
169+
lock = CacheLock("release:%s" % self.pk)
170+
try:
171+
if lock.acquire() or force_deploy:
172+
if ptypes is None:
173+
deployed_ptypes = self.ptypes
174+
else:
175+
deployed_ptypes = list(set(self.deployed_ptypes).union(ptypes))
176+
type(self).objects.filter(pk=self.pk).update(deployed_ptypes=deployed_ptypes)
177+
else:
178+
raise DryccException(msg)
179+
finally:
180+
lock.release()
181+
# deploy lock
182+
if not DeployLock(self.app.pk).acquire(ptypes, force=force_deploy):
183+
raise DryccException(msg)
169184
run_pipeline.delay(self, ptypes, force_deploy)
170185

171186
def previous(self):

rootfs/api/tests/test_release.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ def test_response_data(self, mock_requests):
220220
for key in response.data.keys():
221221
self.assertIn(key, ['uuid', 'owner', 'created', 'updated', 'app', 'build', 'config',
222222
'summary', 'version', 'state', 'failed', 'conditions',
223-
'exception'])
223+
'exception', 'deployed_ptypes'])
224224
expected = {
225225
'owner': self.user.username,
226226
'app': app_id,
@@ -260,6 +260,16 @@ def test_release_deploy(self, mock_requests):
260260
response = self.client.post(url, {"ptypes": "web"})
261261
self.assertEqual(response.status_code, 204)
262262

263+
url = f'/v2/apps/{app_id}/releases/?ptypes=web'
264+
response = self.client.get(url)
265+
self.assertEqual(response.data['count'], 1)
266+
url = f'/v2/apps/{app_id}/releases/?ptypes=web,worker'
267+
response = self.client.get(url)
268+
self.assertEqual(response.data['count'], 1)
269+
url = f'/v2/apps/{app_id}/releases/?ptypes=web,worker,noexists'
270+
response = self.client.get(url)
271+
self.assertEqual(response.data['count'], 0)
272+
263273
def test_release_rollback(self, mock_requests):
264274
app_id = self.create_app()
265275
app = App.objects.get(id=app_id)

rootfs/api/views.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,15 @@ def get_object(self, **kwargs):
621621
qs = self.get_queryset(**kwargs)
622622
return get_object_or_404(qs, version=self.kwargs['version'])
623623

624+
def get_queryset(self, **kwargs):
625+
ptypes = self.request.query_params.get('ptypes', '').strip()
626+
queryset = super(ReleaseViewSet, self).get_queryset(**kwargs)
627+
if ptypes:
628+
queryset = queryset.filter(Q(
629+
deployed_ptypes__contains=[
630+
ptype.lower() for ptype in re.split(r"\W+", ptypes)]))
631+
return queryset
632+
624633
def deploy(self, request, **kwargs):
625634
"""Deploy the latest release"""
626635
latest_release = self.get_app().release_set.latest()

0 commit comments

Comments
 (0)