11import logging
22
3+ from datetime import datetime
4+ from django .utils import timezone
35from django .conf import settings
46from django .db import models
57from django .db .models import Q
68from django .contrib .auth import get_user_model
9+ from django .db .models import F , Func , Value , JSONField
710from api .tasks import run_pipeline
811from api .exceptions import DryccException , AlreadyExists
912from scheduler import KubeHTTPException
1013from scheduler .resources .pod import DEFAULT_CONTAINER_PORT
14+
15+ from ..utils import DeployLock
16+
1117from .base import UuidAuditedModel
1218from .appsettings import AppSettings
1319
@@ -34,6 +40,7 @@ class Release(UuidAuditedModel):
3440 summary = models .TextField (blank = True , null = True )
3541 failed = models .BooleanField (default = False )
3642 exception = models .TextField (blank = True , null = True )
43+ conditions = models .JSONField (default = list )
3744
3845 config = models .ForeignKey ('Config' , on_delete = models .CASCADE )
3946 build = models .ForeignKey ('Build' , null = True , on_delete = models .CASCADE )
@@ -46,10 +53,6 @@ class Meta:
4653 def __str__ (self ):
4754 return "{0}-{1}" .format (self .app .id , self .version_name )
4855
49- @property
50- def deploying (self ):
51- return self .build is not None and self .state == "created"
52-
5356 @property
5457 def procfile_types (self ):
5558 if self .build is not None :
@@ -77,6 +80,18 @@ def get_runners(self, procfile_types):
7780 break
7881 return results
7982
83+ def add_condition (self , ** kwargs ):
84+ if "created" not in kwargs :
85+ kwargs ["created" ] = datetime .now (timezone .utc ).strftime (settings .DRYCC_DATETIME_FORMAT )
86+ type (self ).objects .filter (pk = self .pk ).update (
87+ conditions = Func (
88+ F ("conditions" ),
89+ Value (["0" ]),
90+ Value (kwargs , JSONField ()),
91+ function = "jsonb_insert" ,
92+ )
93+ )
94+
8095 def get_deploy_image (self , container_type ):
8196 """
8297 In the deploy phase of dryccfile
@@ -147,6 +162,12 @@ def get_port(self, procfile_type):
147162 procfile_type , {}).get (
148163 'PORT' , self .config .values .get ('PORT' , DEFAULT_CONTAINER_PORT )))
149164
165+ def deploy (self , procfile_types = None , force_deploy = False ):
166+ lock = DeployLock (self .app .pk )
167+ if not lock .acquire (procfile_types , force = force_deploy ):
168+ raise DryccException ('there is an executing pipeline, please wait or force deploy' )
169+ run_pipeline .delay (self , procfile_types , force_deploy )
170+
150171 def previous (self ):
151172 """
152173 Return the previous Release to this one.
@@ -191,7 +212,7 @@ def rollback(self, user, procfile_types=None, version=None):
191212 summary = "{} rolled back to v{}" .format (user , version ),
192213 )
193214 if self .build is not None :
194- run_pipeline . delay ( new_release , procfile_types , force_deploy = True )
215+ new_release . deploy ( procfile_types , force_deploy = True )
195216 return new_release
196217 except Exception as e :
197218 # check if the exception is during create or publish
@@ -206,7 +227,8 @@ def rollback(self, user, procfile_types=None, version=None):
206227 self .owner )
207228 # Get the exception that has occured
208229 new_release .exception = "error: {}" .format (str (e ))
209- new_release .save ()
230+ # avoid overwriting other fields
231+ new_release .save (update_fields = ["state" , "failed" , "summary" , "exception" ])
210232 raise DryccException (str (e )) from e
211233
212234 def cleanup_old (self , procfile_types = None ):
@@ -378,5 +400,4 @@ def save(self, *args, **kwargs): # noqa
378400 else :
379401 # There were no changes to this release
380402 raise AlreadyExists ("{} changed nothing - release stopped" .format (self .owner ))
381-
382403 super (Release , self ).save (* args , ** kwargs )
0 commit comments