root / logic / credits.py @ dfd19c2d
History | View | Annotate | Download (4 kB)
1 | 09c936a7 | Vassilios Karakoidas | #
|
---|---|---|---|
2 | 09c936a7 | Vassilios Karakoidas | # Business Logic for all Credit related activity
|
3 | 09c936a7 | Vassilios Karakoidas | #
|
4 | 09c936a7 | Vassilios Karakoidas | # Copyright 2010 Greek Research and Technology Network
|
5 | 09c936a7 | Vassilios Karakoidas | #
|
6 | 92c53da1 | Vassilios Karakoidas | |
7 | 7b7f9205 | Vassilios Karakoidas | from datetime import datetime |
8 | 09c936a7 | Vassilios Karakoidas | |
9 | 8d97deff | Vassilios Karakoidas | from db.models import Debit, FlavorCost |
10 | c8926262 | Vassilios Karakoidas | |
11 | 7b7f9205 | Vassilios Karakoidas | from django.db import transaction |
12 | c8926262 | Vassilios Karakoidas | |
13 | 7b7f9205 | Vassilios Karakoidas | @transaction.commit_on_success
|
14 | 7b7f9205 | Vassilios Karakoidas | def debit_account(user , amount, vm, description): |
15 | 7b7f9205 | Vassilios Karakoidas | """Charges the user with the specified amount of credits for a vm (resource)"""
|
16 | 92c53da1 | Vassilios Karakoidas | date_now = datetime.now() |
17 | 7b7f9205 | Vassilios Karakoidas | user.credit = user.credit - amount |
18 | 7b7f9205 | Vassilios Karakoidas | user.save() |
19 | 7b7f9205 | Vassilios Karakoidas | |
20 | 7b7f9205 | Vassilios Karakoidas | # then write the debit entry
|
21 | 7b7f9205 | Vassilios Karakoidas | debit = Debit() |
22 | 7b7f9205 | Vassilios Karakoidas | debit.user = user |
23 | 7b7f9205 | Vassilios Karakoidas | debit.vm = vm |
24 | 7b7f9205 | Vassilios Karakoidas | debit.when = date_now |
25 | 7b7f9205 | Vassilios Karakoidas | debit.description = description |
26 | 7b7f9205 | Vassilios Karakoidas | debit.save() |
27 | 7b7f9205 | Vassilios Karakoidas | |
28 | 7b7f9205 | Vassilios Karakoidas | |
29 | 7b7f9205 | Vassilios Karakoidas | @transaction.commit_on_success
|
30 | 7b7f9205 | Vassilios Karakoidas | def credit_account(self, amount, creditor, description): |
31 | 7b7f9205 | Vassilios Karakoidas | """No clue :)"""
|
32 | 7b7f9205 | Vassilios Karakoidas | return
|
33 | 92c53da1 | Vassilios Karakoidas | |
34 | 92c53da1 | Vassilios Karakoidas | |
35 | 92c53da1 | Vassilios Karakoidas | @transaction.commit_on_success
|
36 | 92c53da1 | Vassilios Karakoidas | def charge(vm): |
37 | 92c53da1 | Vassilios Karakoidas | """Charges the owner of this VM.
|
38 | 92c53da1 | Vassilios Karakoidas |
|
39 | 92c53da1 | Vassilios Karakoidas | Charges the owner of a VM for the period
|
40 | 92c53da1 | Vassilios Karakoidas | from vm.charged to datetime.now(), based on the
|
41 | 92c53da1 | Vassilios Karakoidas | current operating state.
|
42 | 92c53da1 | Vassilios Karakoidas |
|
43 | 92c53da1 | Vassilios Karakoidas | """
|
44 | 92c53da1 | Vassilios Karakoidas | charged_states = ('STARTED', 'STOPPED') |
45 | 92c53da1 | Vassilios Karakoidas | |
46 | 92c53da1 | Vassilios Karakoidas | start_datetime = vm.charged |
47 | 92c53da1 | Vassilios Karakoidas | vm.charged = datetime.now() |
48 | 92c53da1 | Vassilios Karakoidas | |
49 | 92c53da1 | Vassilios Karakoidas | # Only charge for a specific set of states
|
50 | dfd19c2d | Vassilios Karakoidas | if vm.operstate in charged_states: |
51 | 92c53da1 | Vassilios Karakoidas | cost_list = [] |
52 | 92c53da1 | Vassilios Karakoidas | |
53 | 92c53da1 | Vassilios Karakoidas | # remember, we charge only for Started and Stopped
|
54 | dfd19c2d | Vassilios Karakoidas | if vm.operstate == 'STARTED': |
55 | 8d97deff | Vassilios Karakoidas | cost_list = get_cost_active(vm.flavor, start_datetime, vm.charged) |
56 | dfd19c2d | Vassilios Karakoidas | elif vm.operstate == 'STOPPED': |
57 | 8d97deff | Vassilios Karakoidas | cost_list = get_cost_inactive(vm.flavor, start_datetime, vm.charged) |
58 | 92c53da1 | Vassilios Karakoidas | |
59 | 92c53da1 | Vassilios Karakoidas | # find the total vost
|
60 | 92c53da1 | Vassilios Karakoidas | total_cost = sum([x[1] for x in cost_list]) |
61 | 92c53da1 | Vassilios Karakoidas | |
62 | 92c53da1 | Vassilios Karakoidas | # add the debit entry
|
63 | dfd19c2d | Vassilios Karakoidas | description = "Server = %s, charge = %d for state: %s" % (vm.name, total_cost, vm.operstate)
|
64 | 92c53da1 | Vassilios Karakoidas | debit_account(vm.owner, total_cost, vm, description) |
65 | 92c53da1 | Vassilios Karakoidas | |
66 | 92c53da1 | Vassilios Karakoidas | vm.save() |
67 | 111b2cda | Vassilios Karakoidas | |
68 | 8d97deff | Vassilios Karakoidas | |
69 | 111b2cda | Vassilios Karakoidas | def get_costs(vm, start_datetime, end_datetime, active): |
70 | 111b2cda | Vassilios Karakoidas | """Return a list with FlavorCost objects for the specified duration"""
|
71 | 111b2cda | Vassilios Karakoidas | def between(enh_fc, a_date): |
72 | 111b2cda | Vassilios Karakoidas | """Checks if a date is between a FlavorCost duration"""
|
73 | 111b2cda | Vassilios Karakoidas | if enh_fc.effective_from <= a_date and enh_fc.effective_to is None: |
74 | 111b2cda | Vassilios Karakoidas | return True |
75 | 111b2cda | Vassilios Karakoidas | |
76 | 111b2cda | Vassilios Karakoidas | return enh_fc.effective_from <= a_date and enh_fc.effective_to >= a_date |
77 | 111b2cda | Vassilios Karakoidas | |
78 | 111b2cda | Vassilios Karakoidas | # Get the related FlavorCost objects, sorted.
|
79 | 111b2cda | Vassilios Karakoidas | price_list = FlavorCost.objects.filter(flavor=vm).order_by('effective_from')
|
80 | 111b2cda | Vassilios Karakoidas | |
81 | 111b2cda | Vassilios Karakoidas | # add the extra field FlavorCost.effective_to
|
82 | 111b2cda | Vassilios Karakoidas | for idx in range(0, len(price_list)): |
83 | 111b2cda | Vassilios Karakoidas | if idx + 1 == len(price_list): |
84 | 111b2cda | Vassilios Karakoidas | price_list[idx].effective_to = None
|
85 | 111b2cda | Vassilios Karakoidas | else:
|
86 | 111b2cda | Vassilios Karakoidas | price_list[idx].effective_to = price_list[idx + 1].effective_from
|
87 | 111b2cda | Vassilios Karakoidas | |
88 | 111b2cda | Vassilios Karakoidas | price_result = [] |
89 | 111b2cda | Vassilios Karakoidas | found_start = False
|
90 | 111b2cda | Vassilios Karakoidas | |
91 | 111b2cda | Vassilios Karakoidas | # Find the affected FlavorCost, according to the
|
92 | 111b2cda | Vassilios Karakoidas | # dates, and put them in price_result
|
93 | 111b2cda | Vassilios Karakoidas | for p in price_list: |
94 | 111b2cda | Vassilios Karakoidas | if between(p, start_datetime):
|
95 | 111b2cda | Vassilios Karakoidas | found_start = True
|
96 | 111b2cda | Vassilios Karakoidas | p.effective_from = start_datetime |
97 | 111b2cda | Vassilios Karakoidas | if between(p, end_datetime):
|
98 | 111b2cda | Vassilios Karakoidas | p.effective_to = end_datetime |
99 | 111b2cda | Vassilios Karakoidas | price_result.append(p) |
100 | 111b2cda | Vassilios Karakoidas | break
|
101 | 111b2cda | Vassilios Karakoidas | if found_start:
|
102 | 111b2cda | Vassilios Karakoidas | price_result.append(p) |
103 | 111b2cda | Vassilios Karakoidas | |
104 | 111b2cda | Vassilios Karakoidas | results = [] |
105 | 111b2cda | Vassilios Karakoidas | |
106 | 111b2cda | Vassilios Karakoidas | # Create the list and the result tuples
|
107 | 111b2cda | Vassilios Karakoidas | for p in price_result: |
108 | 111b2cda | Vassilios Karakoidas | if active:
|
109 | 111b2cda | Vassilios Karakoidas | cost = p.cost_active |
110 | 111b2cda | Vassilios Karakoidas | else:
|
111 | 111b2cda | Vassilios Karakoidas | cost = p.cost_inactive |
112 | 111b2cda | Vassilios Karakoidas | |
113 | c8926262 | Vassilios Karakoidas | results.append( ( p.effective_from, calculate_cost(p.effective_from, p.effective_to, cost)) ) |
114 | 111b2cda | Vassilios Karakoidas | |
115 | 111b2cda | Vassilios Karakoidas | return results
|
116 | c8926262 | Vassilios Karakoidas | |
117 | c8926262 | Vassilios Karakoidas | |
118 | c8926262 | Vassilios Karakoidas | def calculate_cost(start_date, end_date, cost): |
119 | c8926262 | Vassilios Karakoidas | """Calculate the total cost for the specified duration"""
|
120 | c8926262 | Vassilios Karakoidas | td = end_date - start_date |
121 | c8926262 | Vassilios Karakoidas | sec = float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / float(10**6) |
122 | c8926262 | Vassilios Karakoidas | total_hours = float(sec) / float(60.0*60.0) |
123 | c8926262 | Vassilios Karakoidas | total_cost = float(cost)*total_hours
|
124 | c8926262 | Vassilios Karakoidas | |
125 | c8926262 | Vassilios Karakoidas | return round(total_cost) |
126 | 8d97deff | Vassilios Karakoidas | |
127 | 8d97deff | Vassilios Karakoidas | |
128 | 8d97deff | Vassilios Karakoidas | def get_cost_active(vm, start_datetime, end_datetime): |
129 | 8d97deff | Vassilios Karakoidas | """Returns a list with the active costs for the specified duration"""
|
130 | 8d97deff | Vassilios Karakoidas | return get_costs(vm, start_datetime, end_datetime, True) |
131 | 8d97deff | Vassilios Karakoidas | |
132 | 8d97deff | Vassilios Karakoidas | |
133 | 8d97deff | Vassilios Karakoidas | def get_cost_inactive(vm, start_datetime, end_datetime): |
134 | 8d97deff | Vassilios Karakoidas | """Returns a list with the inactive costs for the specified duration"""
|
135 | 8d97deff | Vassilios Karakoidas | return get_costs(vm, start_datetime, end_datetime, False) |