Revision 452d2391 db/models.py
b/db/models.py | ||
---|---|---|
3 | 3 |
from django.conf import settings |
4 | 4 |
from django.db import models |
5 | 5 |
from django.contrib.auth.models import User |
6 |
from django.utils.translation import gettext_lazy as _ |
|
7 | 6 |
|
8 | 7 |
import datetime |
9 | 8 |
|
... | ... | |
50 | 49 |
|
51 | 50 |
def debit_account(self, amount, vm, description): |
52 | 51 |
"""Charges the user with the specified amount of credits for a vm (resource)""" |
53 |
return |
|
52 |
date_now = datetime.datetime.now() |
|
53 |
|
|
54 |
# first reduce the user's credits and save |
|
55 |
self.credit = self.credit - amount |
|
56 |
self.save() |
|
57 |
|
|
58 |
# then write the debit entry! |
|
59 |
debit = Debit() |
|
60 |
|
|
61 |
debit.user = self |
|
62 |
debit.vm = vm |
|
63 |
debit.when = date_now |
|
64 |
debit.description = description |
|
65 |
|
|
66 |
debit.save() |
|
54 | 67 |
|
55 | 68 |
def credit_account(self, amount, creditor, description): |
56 | 69 |
"""No clue :)""" |
... | ... | |
78 | 91 |
verbose_name = u'Image' |
79 | 92 |
|
80 | 93 |
def __unicode__(self): |
81 |
return u'%s' % (self.name)
|
|
94 |
return u'%s' % ( self.name, )
|
|
82 | 95 |
|
83 | 96 |
|
84 | 97 |
class ImageMetadata(models.Model): |
... | ... | |
107 | 120 |
verbose_name = u'Enforced limit for user' |
108 | 121 |
|
109 | 122 |
def __unicode__(self): |
110 |
return u'Limit %s for user %s: %d' % (self.limit, self.user, self.value)
|
|
123 |
return u'Limit %s for user %s: %d' % (self.value, self.user, self.value)
|
|
111 | 124 |
|
112 | 125 |
|
113 | 126 |
class Flavor(models.Model): |
... | ... | |
122 | 135 |
def _get_name(self): |
123 | 136 |
"""Returns flavor name (generated)""" |
124 | 137 |
return u'C%dR%dD%d' % (self.cpu, self.ram, self.disk) |
125 |
|
|
126 |
def _current_cost_active(self): |
|
138 |
|
|
139 |
def _current_cost(self, active): |
|
140 |
"""Returns active/inactive cost value |
|
141 |
|
|
142 |
set active = True to get active cost and False for the inactive. |
|
143 |
|
|
144 |
""" |
|
127 | 145 |
fch_list = FlavorCost.objects.filter(flavor=self).order_by('-effective_from') |
128 | 146 |
if len(fch_list) > 0: |
129 |
return fch_list[0].cost_active |
|
130 |
|
|
147 |
if active: |
|
148 |
return fch_list[0].cost_active |
|
149 |
else: |
|
150 |
return fch_list[0].cost_inactive |
|
151 |
|
|
131 | 152 |
return 0 |
153 |
|
|
154 |
|
|
155 |
def _current_cost_active(self): |
|
156 |
"""Returns current active cost (property method)""" |
|
157 |
return self._current_cost(True) |
|
132 | 158 |
|
133 | 159 |
def _current_cost_inactive(self): |
134 |
fch_list = FlavorCost.objects.filter(flavor=self).order_by('-effective_from') |
|
135 |
if len(fch_list) > 0: |
|
136 |
return fch_list[0].cost_inactive |
|
137 |
|
|
138 |
return 0 |
|
160 |
"""Returns current inactive cost (property method)""" |
|
161 |
return self._current_cost(False) |
|
139 | 162 |
|
140 | 163 |
name = property(_get_name) |
141 | 164 |
current_cost_active = property(_current_cost_active) |
... | ... | |
143 | 166 |
|
144 | 167 |
def __unicode__(self): |
145 | 168 |
return self.name |
146 |
|
|
169 |
|
|
170 |
def _get_costs(self, start_datetime, end_datetime, active): |
|
171 |
"""Return a list with FlavorCost objects for the specified duration""" |
|
172 |
def between(enh_fc, a_date): |
|
173 |
"""Checks if a date is between a FlavorCost duration""" |
|
174 |
if enh_fc.effective_from <= a_date and enh_fc.effective_to is None: |
|
175 |
return True |
|
176 |
|
|
177 |
return enh_fc.effective_from <= a_date and enh_fc.effective_to >= a_date |
|
178 |
|
|
179 |
def calculate_cost(start_date, end_date, cost): |
|
180 |
"""Calculate the total cost for the specified duration""" |
|
181 |
td = end_date - start_date |
|
182 |
sec = float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / float(10**6) |
|
183 |
total_hours = float(sec) / float(60.0*60.0) |
|
184 |
total_cost = float(cost)*total_hours |
|
185 |
|
|
186 |
return round(total_cost) |
|
187 |
|
|
188 |
price_list = FlavorCost.objects.filter(flavor=self).order_by('effective_from') |
|
189 |
|
|
190 |
for idx in range(0, len(price_list)): |
|
191 |
if idx + 1 == len(price_list): |
|
192 |
price_list[idx].effective_to = None |
|
193 |
else: |
|
194 |
price_list[idx].effective_to = price_list[idx + 1].effective_from |
|
195 |
|
|
196 |
price_result = [] |
|
197 |
found_start = False |
|
198 |
|
|
199 |
for p in price_list: |
|
200 |
if between(p, start_datetime): |
|
201 |
found_start = True |
|
202 |
p.effective_from = start_datetime |
|
203 |
if between(p, end_datetime): |
|
204 |
p.effective_to = end_datetime |
|
205 |
price_result.append(p) |
|
206 |
break |
|
207 |
if found_start: |
|
208 |
price_result.append(p) |
|
209 |
|
|
210 |
results = [] |
|
211 |
|
|
212 |
for p in price_result: |
|
213 |
if active: |
|
214 |
cost = p.cost_active |
|
215 |
else: |
|
216 |
cost = p.cost_inactive |
|
217 |
|
|
218 |
results.append( ( str(p.effective_from), calculate_cost(p.effective_from, p.effective_to, cost)) ) |
|
219 |
|
|
220 |
return results |
|
221 |
|
|
147 | 222 |
def get_cost_active(self, start_datetime, end_datetime): |
148 | 223 |
"""Returns a list with the active costs for the specified duration""" |
149 |
|
|
150 |
return [] |
|
151 |
|
|
224 |
return self._get_costs(start_datetime, end_datetime, True) |
|
225 |
|
|
152 | 226 |
def get_cost_inactive(self, start_datetime, end_datetime): |
153 | 227 |
"""Returns a list with the active costs for the specified duration""" |
154 |
return []
|
|
228 |
return self._get_costs(start_datetime, end_datetime, False)
|
|
155 | 229 |
|
156 | 230 |
|
157 | 231 |
class FlavorCost(models.Model): |
158 | 232 |
cost_active = models.PositiveIntegerField('Active Cost') |
159 | 233 |
cost_inactive = models.PositiveIntegerField('Inactive Cost') |
160 |
effective_from = models.DateField() |
|
234 |
effective_from = models.DateTimeField()
|
|
161 | 235 |
flavor = models.ForeignKey(Flavor) |
162 | 236 |
|
163 | 237 |
class Meta: |
... | ... | |
377 | 451 |
Charges the VM owner from vm.charged to datetime.now() |
378 | 452 |
|
379 | 453 |
""" |
380 |
return |
|
454 |
cur_datetime = datetime.datetime.now() |
|
455 |
cost_list = [] |
|
456 |
|
|
457 |
if self._operstate == 'STARTED': |
|
458 |
cost_list = self.flavor.get_cost_active(self.charged, cur_datetime) |
|
459 |
else: |
|
460 |
cost_list = self.flavot.get_cost_inactive(self.charged, cur_datetime) |
|
461 |
|
|
462 |
total_cost = 0 |
|
463 |
|
|
464 |
for cl in cost_list: |
|
465 |
total_cost = total_cost + cl[1] |
|
466 |
|
|
467 |
# still need to set correctly the message |
|
468 |
self.owner.debit_account(total_cost, self, "Charged Credits to User") |
|
469 |
|
|
470 |
self.charged = cur_datetime |
|
471 |
self.save() |
|
381 | 472 |
|
382 | 473 |
|
383 | 474 |
class VirtualMachineGroup(models.Model): |
... | ... | |
419 | 510 |
verbose_name = u'Accounting log' |
420 | 511 |
|
421 | 512 |
def __unicode__(self): |
422 |
return u'%s - %s - %s' % (self.vm.name, str(self.date), self.state)
|
|
513 |
return u'%s - %s - %s - %s' % ( self.user.id, self.vm.name, str(self.when), self.description)
|
|
423 | 514 |
|
424 | 515 |
|
425 | 516 |
class Disk(models.Model): |
Also available in: Unified diff