44Data models for the Deis API.
55"""
66
7- from __future__ import unicode_literals
87import base64
98from datetime import datetime
109import etcd
1817from django .conf import settings
1918from django .core .exceptions import ValidationError , SuspiciousOperation
2019from django .db import models
21- from django .db .models import Count
22- from django .db .models import Max
20+ from django .db .models import Count , Max
2321from django .db .models .signals import post_delete , post_save
2422from django .dispatch import receiver
25- from django .utils .encoding import python_2_unicode_compatible
2623from jsonfield import JSONField
2724from OpenSSL import crypto
2825import requests
2926from rest_framework .authtoken .models import Token
3027
31- from api import utils
3228from registry import publish_release
33- from utils import dict_diff , dict_merge , fingerprint
29+ from api . utils import dict_diff , dict_merge , fingerprint , generate_app_name
3430
3531
3632User = settings .AUTH_USER_MODEL
@@ -82,9 +78,9 @@ def validate_id_is_docker_compatible(value):
8278def validate_app_structure (value ):
8379 """Error if the dict values aren't ints >= 0."""
8480 try :
85- if any (int (v ) < 0 for v in value .viewvalues ()):
81+ if any (int (v ) < 0 for v in value .values ()):
8682 raise ValueError ("Must be greater than or equal to zero" )
87- except ValueError , err :
83+ except ValueError as err :
8884 raise ValidationError (err )
8985
9086
@@ -141,7 +137,6 @@ class Meta:
141137 abstract = True
142138
143139
144- @python_2_unicode_compatible
145140class App (UuidAuditedModel ):
146141 """
147142 Application used to service requests on behalf of end-users
@@ -159,9 +154,9 @@ class Meta:
159154 @property
160155 def select_app_name (self ):
161156 """Select a unique randomly generated app name"""
162- name = utils . generate_app_name ()
157+ name = generate_app_name ()
163158 while App .objects .filter (id = name ).exists ():
164- name = utils . generate_app_name ()
159+ name = generate_app_name ()
165160
166161 return name
167162
@@ -174,9 +169,9 @@ def _scheduler(self):
174169
175170 def save (self , ** kwargs ):
176171 if not self .id :
177- self .id = utils . generate_app_name ()
172+ self .id = generate_app_name ()
178173 while App .objects .filter (id = self .id ).exists ():
179- self .id = utils . generate_app_name ()
174+ self .id = generate_app_name ()
180175
181176 return super (App , self ).save (** kwargs )
182177
@@ -265,15 +260,15 @@ def scale(self, user, structure): # noqa
265260 raise EnvironmentError (
266261 'Container type {} does not exist in application' .format (container_type ))
267262 msg = '{} scaled containers ' .format (user .username ) + ' ' .join (
268- "{}={}" .format (k , v ) for k , v in requested_structure .items ())
263+ "{}={}" .format (k , v ) for k , v in list ( requested_structure .items () ))
269264 log_event (self , msg )
270265 # iterate and scale by container type (web, worker, etc)
271266 changed = False
272267 to_add , to_remove = [], []
273268 scale_types = {}
274269
275270 # iterate on a copy of the container_type keys
276- for container_type in requested_structure .keys ():
271+ for container_type in list ( requested_structure .keys () ):
277272 containers = list (self .container_set .filter (type = container_type ).order_by ('created' ))
278273 # increment new container nums off the most recent container
279274 results = self .container_set .filter (type = container_type ).aggregate (Max ('num' ))
@@ -518,7 +513,6 @@ def run(self, user, command):
518513 return c .run (escaped_command )
519514
520515
521- @python_2_unicode_compatible
522516class Container (UuidAuditedModel ):
523517 """
524518 Docker container used to securely host an application process.
@@ -649,7 +643,6 @@ def run(self, command):
649643 raise
650644
651645
652- @python_2_unicode_compatible
653646class Push (UuidAuditedModel ):
654647 """
655648 Instance of a push used to trigger an application build
@@ -674,7 +667,6 @@ def __str__(self):
674667 return "{0}-{1}" .format (self .app .id , self .sha [:7 ])
675668
676669
677- @python_2_unicode_compatible
678670class Build (UuidAuditedModel ):
679671 """
680672 Instance of a software build used by runtime nodes
@@ -728,7 +720,6 @@ def __str__(self):
728720 return "{0}-{1}" .format (self .app .id , str (self .uuid )[:7 ])
729721
730722
731- @python_2_unicode_compatible
732723class Config (UuidAuditedModel ):
733724 """
734725 Set of configuration values applied as environment variables
@@ -778,15 +769,14 @@ def save(self, **kwargs):
778769
779770 data .update (new_data )
780771 # remove config keys if we provided a null value
781- [data .pop (k ) for k , v in new_data .viewitems () if v is None ]
772+ [data .pop (k ) for k , v in new_data .items () if v is None ]
782773 setattr (self , attr , data )
783774 except Config .DoesNotExist :
784775 pass
785776
786777 return super (Config , self ).save (** kwargs )
787778
788779
789- @python_2_unicode_compatible
790780class Release (UuidAuditedModel ):
791781 """
792782 Software release deployed by the application platform
@@ -953,7 +943,6 @@ def save(self, *args, **kwargs): # noqa
953943 super (Release , self ).save (* args , ** kwargs )
954944
955945
956- @python_2_unicode_compatible
957946class Domain (AuditedModel ):
958947 owner = models .ForeignKey (settings .AUTH_USER_MODEL )
959948 app = models .ForeignKey ('App' )
@@ -997,7 +986,7 @@ def _save_service_config(self, app, component, data):
997986 component = "%s.deis.io/" % component
998987
999988 # add component to data and flatten
1000- data = {"%s%s" % (component , key ): value for key , value in data .items ()}
989+ data = {"%s%s" % (component , key ): value for key , value in list ( data .items () )}
1001990 svc ['metadata' ]['annotations' ].update (morph .flatten (data ))
1002991
1003992 # Update the k8s service for the application with new domain information
@@ -1015,7 +1004,7 @@ def save(self, *args, **kwargs):
10151004 config ['domains' ] = ''
10161005
10171006 # convert from string to list to work with and filter out empty strings
1018- domains = filter ( None , config ['domains' ].split (',' ))
1007+ domains = [ _f for _f in config ['domains' ].split (',' ) if _f ]
10191008 if domain not in domains :
10201009 domains .append (domain )
10211010 config ['domains' ] = ',' .join (domains )
@@ -1037,7 +1026,7 @@ def delete(self, *args, **kwargs):
10371026 config ['domains' ] = ''
10381027
10391028 # convert from string to list to work with and filter out empty strings
1040- domains = filter ( None , config ['domains' ].split (',' ))
1029+ domains = [ _f for _f in config ['domains' ].split (',' ) if _f ]
10411030 if domain in domains :
10421031 domains .remove (domain )
10431032 config ['domains' ] = ',' .join (domains )
@@ -1051,7 +1040,6 @@ def __str__(self):
10511040 return self .domain
10521041
10531042
1054- @python_2_unicode_compatible
10551043class Certificate (AuditedModel ):
10561044 """
10571045 Public and private key pair used to secure application traffic at the router.
@@ -1077,13 +1065,17 @@ def save(self, *args, **kwargs):
10771065 certificate = self ._get_certificate ()
10781066 if not self .common_name :
10791067 self .common_name = certificate .get_subject ().CN
1068+
10801069 if not self .expires :
1070+ # https://pyopenssl.readthedocs.org/en/latest/api/crypto.html#OpenSSL.crypto.X509.get_notAfter
1071+ # Convert bytes to string
1072+ timestamp = certificate .get_notAfter ().decode (encoding = 'UTF-8' )
10811073 # convert openssl's expiry date format to Django's DateTimeField format
1082- self .expires = datetime .strptime (certificate .get_notAfter (), '%Y%m%d%H%M%SZ' )
1074+ self .expires = datetime .strptime (timestamp , '%Y%m%d%H%M%SZ' )
1075+
10831076 return super (Certificate , self ).save (* args , ** kwargs )
10841077
10851078
1086- @python_2_unicode_compatible
10871079class Key (UuidAuditedModel ):
10881080 """An SSH public key."""
10891081
0 commit comments