2 # -------------------------------------------------------------------------
3 # Copyright (c) 2015-2017 AT&T Intellectual Property
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # -------------------------------------------------------------------------
25 from conductor.common.models import validate_uuid4
26 from conductor.common.music.model import base
29 def current_time_millis():
30 """Current time in milliseconds."""
31 return int(round(time.time() * 1000))
34 class Plan(base.Base):
37 DO NOT use this class directly!
39 Only create Plan-based classes using:
40 base.create_dynamic_model(keyspace=KEYSPACE,
41 baseclass=Plan, classname=CLASS).
42 The table will be automatically created if it doesn't exist.
45 __tablename__ = "plans"
48 id = None # pylint: disable=C0103
61 TEMPLATE = "template" # Template ready for translation
62 TRANSLATED = "translated" # Translation ready for solving
63 SOLVING = "solving" # Search for solutions in progress
64 # Search complete, solution with n>0 recommendations found
66 # Search failed, no recommendations found
67 NOT_FOUND = "not found"
68 ERROR = "error" # Error
69 # Solved, but reservation of resources in progress
70 RESERVING = "reserving"
71 # Final state, Solved and Reserved resources (if required)
73 STATUS = [TEMPLATE, TRANSLATED, SOLVING, SOLVED, NOT_FOUND,
74 ERROR, RESERVING, DONE, ]
75 WORKING = [TEMPLATE, TRANSLATED, SOLVING, RESERVING, ]
76 FINISHED = [SOLVED, NOT_FOUND, ERROR, DONE, ]
82 'id': 'text', # Plan ID in UUID4 format
83 'status': 'text', # Plan status (see STATUS for valid values)
84 'created': 'bigint', # Creation time in msec from epoch
85 'updated': 'bigint', # Last update time in msec from epoch
86 'name': 'text', # Plan name/alias
87 'timeout': 'int', # Timeout in seconds
88 'recommend_max': 'int', # Max recommendations
89 'message': 'text', # Message (e.g., error or other info)
90 'template': 'text', # Plan template
91 'translation': 'text', # Translated template for the solver
92 'solution': 'text', # The (ocean is the ultimate) solution (FZ)
93 'PRIMARY KEY': '(id)',
99 """Use atomic operations"""
104 """Primary key name"""
108 """Primary key value"""
113 return self.status == self.ERROR
117 return self.status in self.FINISHED
121 return self.status == self.SOLUTION
125 return self.status == self.DONE
129 """Calculate if a plan has timed out"""
130 elapsed_msec = (current_time_millis() - self.created)
131 return elapsed_msec >= self.timeout * 1000
135 return self.status in self.WORKING
140 Side-effect: Sets the updated field to the current time.
142 self.updated = current_time_millis()
143 super(Plan, self).update()
148 'status': self.status,
149 'created': self.created,
150 'updated': self.updated,
152 'timeout': self.timeout,
153 'recommend_max': self.recommend_max,
154 'message': self.message,
155 'template': json.dumps(self.template),
156 'translation': json.dumps(self.translation),
157 'solution': json.dumps(self.solution),
160 value_dict['id'] = self.id
163 def __init__(self, name, timeout, recommend_max, template,
164 id=None, created=None, updated=None, status=None,
165 message=None, translation=None, solution=None, _insert=True):
167 super(Plan, self).__init__()
168 self.status = status or self.TEMPLATE
169 self.created = created or current_time_millis()
170 self.updated = updated or current_time_millis()
172 self.timeout = timeout
173 self.recommend_max = recommend_max
174 self.message = message or ""
176 if validate_uuid4(id):
178 self.template = template or {}
179 self.translation = translation or {}
180 self.solution = solution or {}
183 self.template = json.loads(template)
184 self.translation = json.loads(translation)
185 self.solution = json.loads(solution)
188 """Object representation"""
189 return '<Plan {} ({})>'.format(self.name, self.id)
192 """JSON representation"""
194 json_['id'] = self.id
195 json_['status'] = self.status
196 json_['created'] = self.created
197 json_['updated'] = self.updated
198 json_['name'] = self.name
199 json_['timeout'] = self.timeout
200 json_['recommend_max'] = self.recommend_max
201 json_['message'] = self.message
202 json_['template'] = self.template
203 json_['translation'] = self.translation
204 json_['solution'] = self.solution