Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions rootfs/api/models/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def restart(self, **kwargs): # noqa

def scale(self, user, structure):
err_msg = None
release = self.release_set.filter(failed=False).latest()
release = Release.latest(self)
if (PTYPE_RUN in structure or release.build is None):
if PTYPE_RUN in structure:
err_msg = 'Cannot set scale for reserved types, procfile type is: run'
Expand Down Expand Up @@ -348,9 +348,9 @@ def deploy(self, release, ptypes=None, force_deploy=False, rollback_on_failure=T
release.clean(ptypes)

def mount(self, user, volume, structure=None):
if self.release_set.filter(failed=False).latest().build is None:
release = Release.latest(self)
if release is None or release.build is None:
raise DryccException('No build associated with this release')
release = self.release_set.filter(failed=False).latest()
app_settings = self.appsettings_set.latest()
self._mount(user, volume, release, app_settings, structure=structure)

Expand Down Expand Up @@ -387,8 +387,8 @@ def pod_name(size=5, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))

"""Run a one-off command in an ephemeral app container."""
release = self.release_set.filter(failed=False).latest()
if release.build is None:
release = Release.latest(self)
if release is None or release.build is None:
raise DryccException('No build associated with this release to run this command')

app_settings = self.appsettings_set.latest()
Expand Down Expand Up @@ -656,8 +656,8 @@ def image_pull_secret(self, namespace, registry, image):
return name

def state_to_k8s(self):
release = self.release_set.filter(failed=False).latest()
if release.build is None:
release = Release.latest(self)
if release is None or release.build is None:
self.log('the last release does not have a build, skipping deployment...')
return
ptypes = set()
Expand Down
5 changes: 3 additions & 2 deletions rootfs/api/models/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from api.exceptions import DryccException
from .base import UuidAuditedModel, PTYPE_WEB
from .config import Config
from .release import Release

User = get_user_model()
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -72,7 +73,7 @@ def get_image(self, ptype, default_image=None):
return default_image if default_image else self.image

def create_release(self, user, *args, **kwargs):
latest_release = self.app.release_set.filter(failed=False).latest()
latest_release = Release.latest(self.app)
try:
new_release = latest_release.new(
user,
Expand Down Expand Up @@ -109,7 +110,7 @@ def _get_or_create_config(self):
"""
dryccfile to config
"""
latest_release = self.app.release_set.filter(failed=False).latest()
latest_release = Release.latest(self.app)
config_values, config_values_ref, config_healthcheck = [], {}, {}
for group, values in self.dryccfile.get('config', {}).items():
for value in values:
Expand Down
9 changes: 5 additions & 4 deletions rootfs/api/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,10 @@ def save(self, ignore_update_fields=None, *args, **kwargs):
"""merge the old config with the new"""
try:
# Get config from the latest available release
try:
previous_config = self.app.release_set.filter(failed=False).latest().config
except Release.DoesNotExist:
latest_releases = Release.latest(self.app)
if latest_releases:
previous_config = latest_releases.config
else:
# If that doesn't exist then fallback on app config
# usually means a totally new app
previous_config = self.app.config_set.latest()
Expand Down Expand Up @@ -174,7 +175,7 @@ def _update_values(self, previous_config):
else: # force to string
new_item['value'] = str(new_item['value'])
break
if added and new_item['value'] is not None:
if added and new_item['value'] is not None and new_item['value'] != "":
data.append(new_item)
setattr(self, 'values', data)

Expand Down
8 changes: 1 addition & 7 deletions rootfs/api/models/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def addresses(self):
def listeners(self):
auto_tls = self.app.tls_set.latest().certs_auto_enabled
listeners = []
domains = list(self._get_tls_domain(auto_tls))
domains = list(self.app.domain_set.all())
for item in self.ports:
port, protocol = item["port"], item["protocol"]
if item["protocol"] in HOSTNAME_PROTOCOLS:
Expand Down Expand Up @@ -146,12 +146,6 @@ def _check_port(self, port, protocol):
return False
return True

def _get_tls_domain(self, auto_tls):
domains = self.app.domain_set.all()
if not auto_tls:
domains = domains.exclude(certificate=None)
return domains

def _get_listener_name(self, port, protocol, index):
if protocol in ("TCP", "TLS", "HTTP"):
protocol = "TCP"
Expand Down
31 changes: 17 additions & 14 deletions rootfs/api/models/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,28 +211,31 @@ def deploy(self, ptypes=None, force_deploy=False):
raise DryccException(f"{msg}: {lock.locked(ptypes)}")
run_pipeline.delay(self, ptypes, force_deploy)

def previous(self, state="succeed"):
"""
Return the previous Release to this one.

:return: the previous :class:`Release`, or None
"""
releases = self.app.release_set
if self.pk:
releases = releases.exclude(pk=self.pk)
@classmethod
def latest(cls, app, state=None, exclude_pk=None):
releases = app.release_set
if exclude_pk:
releases = releases.exclude(pk=exclude_pk)
q = Q(failed=False, state="succeed") if state else Q(failed=False)
try:
app_settings = self.app.appsettings_set.latest()
app_settings = app.appsettings_set.latest()
if app_settings.autorollback is False:
q = Q(state__in=["crashed", "succeed"])
q = Q()
except AppSettings.DoesNotExist:
pass
try:
# Get the Release previous to this one
prev_release = releases.filter(q).latest()
release = releases.filter(q).latest()
except Release.DoesNotExist:
prev_release = None
return prev_release
release = None
return release

def previous(self, state="succeed"):
"""
Return the previous Release to this one.
:return: the previous :class:`Release`, or None
"""
return self.latest(self.app, state, self.pk)

def rollback(self, user, ptypes=None, version=None):
try:
Expand Down
44 changes: 32 additions & 12 deletions rootfs/api/tests/test_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,14 +328,24 @@ def test_change_tls(self):
app_id = self.create_app_with_domain_and_deploy()
response = self.client.get('/v2/apps/{}/gateways/'.format(app_id))
expect = [{
'allowedRoutes': {
'namespaces': {
'from': 'All'
"allowedRoutes": {
"namespaces": {
"from": "All"
}
},
'name': 'tcp-80-0',
'port': 80,
'protocol': 'HTTP'
"name": "tcp-80-1",
"port": 80,
"hostname": "test-domain.example.com",
"protocol": "HTTP"
}, {
"allowedRoutes": {
"namespaces": {
"from": "All"
}
},
"name": "tcp-80-0",
"port": 80,
"protocol": "HTTP"
}]
self.assertEqual(response.data["count"], 1, response.data)
self.assertEqual(response.data["results"][0]["listeners"], expect, response.data)
Expand Down Expand Up @@ -377,14 +387,24 @@ def test_change_tls(self):
self.change_certs_auto(app_id, False)
response = self.client.get('/v2/apps/{}/gateways/'.format(app_id))
expect = [{
'allowedRoutes': {
'namespaces': {
'from': 'All'
"allowedRoutes": {
"namespaces": {
"from": "All"
}
},
"name": "tcp-80-1",
"port": 80,
"hostname": "test-domain.example.com",
"protocol": "HTTP"
}, {
"allowedRoutes": {
"namespaces": {
"from": "All"
}
},
'name': 'tcp-80-0',
'port': 80,
'protocol': 'HTTP'
"name": "tcp-80-0",
"port": 80,
"protocol": "HTTP"
}]
self.assertEqual(response.data["count"], 1, response.data)
self.assertEqual(response.json()["results"][0]["listeners"], expect, response.data)
Expand Down
12 changes: 6 additions & 6 deletions rootfs/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ def get_object(self):
release = get_object_or_404(
models.release.Release, app=self.get_app(), version=int(version))
else:
release = self.get_app().release_set.filter(failed=False).latest()
release = models.release.Release.latest(self.get_app())
return getattr(release, self.model.__name__.lower())


Expand Down Expand Up @@ -321,7 +321,7 @@ def run(self, request, **kwargs):
expires = settings.KUBERNETES_JOB_MAX_TTL_SECONDS_AFTER_FINISHED
if not command:
raise DryccException('command is a required field, or it can be defined in Procfile')
release = app.release_set.filter(failed=False).latest()
release = models.release.Release.latest(app)
if release.build is None:
raise DryccException('no build available, please deploy a release')
volumes = request.data.get('volumes', None)
Expand Down Expand Up @@ -417,7 +417,7 @@ def delete(self, request, **kwargs):
return Response(status=status.HTTP_200_OK)

def post_save(self, config):
latest_release = config.app.release_set.filter(failed=False).latest()
latest_release = models.release.Release.latest(self.get_app())
try:
release = latest_release.new(
self.request.user, config=config, build=latest_release.build)
Expand Down Expand Up @@ -673,7 +673,7 @@ def rollback(self, request, **kwargs):
Create a new release as a copy of the state of the compiled slug and config vars of a
previous release.
"""
latest_release = self.get_app().release_set.filter(failed=False).latest()
latest_release = models.release.Release.latest(self.get_app())
ptypes = set(
[ptype for ptype in request.data.get("ptypes", "").split(",") if ptype])
ptypes = latest_release.app.check_ptypes(ptypes)
Expand Down Expand Up @@ -786,7 +786,7 @@ def create(self, request, *args, **kwargs):
# return the application databag
response = {
'release': {
'version': app.release_set.filter(failed=False).latest().version
'version': models.release.Release.latest(app).version
}
}
return Response(response, status=status.HTTP_200_OK)
Expand All @@ -807,7 +807,7 @@ def create(self, request, *args, **kwargs):
has_permission, message = permissions.has_app_permission(request.user, app, request.method)
if not has_permission:
return Response(message, status=status.HTTP_403_FORBIDDEN)
config = app.release_set.filter(failed=False).latest().config
config = models.release.Release.latest(app).config
serializer = self.get_serializer(config)
return Response(serializer.data, status=status.HTTP_200_OK)

Expand Down