Statistics
| Branch: | Tag: | Revision:

root / logic / credits.py @ 583bfaa0

History | View | Annotate | Download (5.5 kB)

1 48130e66 Georgios Gousios
# Copyright 2011 GRNET S.A. All rights reserved.
2 09c936a7 Vassilios Karakoidas
#
3 48130e66 Georgios Gousios
# Redistribution and use in source and binary forms, with or without
4 48130e66 Georgios Gousios
# modification, are permitted provided that the following conditions
5 48130e66 Georgios Gousios
# are met:
6 48130e66 Georgios Gousios
#
7 48130e66 Georgios Gousios
#   1. Redistributions of source code must retain the above copyright
8 48130e66 Georgios Gousios
#      notice, this list of conditions and the following disclaimer.
9 48130e66 Georgios Gousios
#
10 48130e66 Georgios Gousios
#  2. Redistributions in binary form must reproduce the above copyright
11 48130e66 Georgios Gousios
#     notice, this list of conditions and the following disclaimer in the
12 48130e66 Georgios Gousios
#     documentation and/or other materials provided with the distribution.
13 09c936a7 Vassilios Karakoidas
#
14 48130e66 Georgios Gousios
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15 48130e66 Georgios Gousios
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 48130e66 Georgios Gousios
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 48130e66 Georgios Gousios
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18 48130e66 Georgios Gousios
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 48130e66 Georgios Gousios
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 48130e66 Georgios Gousios
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 48130e66 Georgios Gousios
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 48130e66 Georgios Gousios
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 48130e66 Georgios Gousios
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 48130e66 Georgios Gousios
# SUCH DAMAGE.
25 09c936a7 Vassilios Karakoidas
#
26 48130e66 Georgios Gousios
# The views and conclusions contained in the software and documentation are
27 48130e66 Georgios Gousios
# those of the authors and should not be interpreted as representing official
28 48130e66 Georgios Gousios
# policies, either expressed or implied, of GRNET S.A.
29 48130e66 Georgios Gousios
30 48130e66 Georgios Gousios
# Business Logic for all Credit related activity
31 92c53da1 Vassilios Karakoidas
32 7b7f9205 Vassilios Karakoidas
from datetime import datetime
33 7b7f9205 Vassilios Karakoidas
from django.db import transaction
34 c8926262 Vassilios Karakoidas
35 234f8b07 Vangelis Koukis
from synnefo.db.models import Debit, FlavorCost
36 234f8b07 Vangelis Koukis
37 7b7f9205 Vassilios Karakoidas
@transaction.commit_on_success
38 7b7f9205 Vassilios Karakoidas
def debit_account(user , amount, vm, description):
39 7b7f9205 Vassilios Karakoidas
    """Charges the user with the specified amount of credits for a vm (resource)"""
40 92c53da1 Vassilios Karakoidas
    date_now = datetime.now()
41 7b7f9205 Vassilios Karakoidas
    user.credit = user.credit - amount
42 7b7f9205 Vassilios Karakoidas
    user.save()
43 7b7f9205 Vassilios Karakoidas
44 7b7f9205 Vassilios Karakoidas
    # then write the debit entry
45 7b7f9205 Vassilios Karakoidas
    debit = Debit()
46 7b7f9205 Vassilios Karakoidas
    debit.user = user
47 7b7f9205 Vassilios Karakoidas
    debit.vm = vm
48 7b7f9205 Vassilios Karakoidas
    debit.when = date_now
49 7b7f9205 Vassilios Karakoidas
    debit.description = description
50 7b7f9205 Vassilios Karakoidas
    debit.save()
51 7b7f9205 Vassilios Karakoidas
52 7b7f9205 Vassilios Karakoidas
53 7b7f9205 Vassilios Karakoidas
@transaction.commit_on_success
54 7b7f9205 Vassilios Karakoidas
def credit_account(self, amount, creditor, description):
55 7b7f9205 Vassilios Karakoidas
    """No clue :)"""
56 7b7f9205 Vassilios Karakoidas
    return
57 92c53da1 Vassilios Karakoidas
58 92c53da1 Vassilios Karakoidas
59 92c53da1 Vassilios Karakoidas
@transaction.commit_on_success
60 92c53da1 Vassilios Karakoidas
def charge(vm):
61 92c53da1 Vassilios Karakoidas
    """Charges the owner of this VM.
62 92c53da1 Vassilios Karakoidas

63 92c53da1 Vassilios Karakoidas
    Charges the owner of a VM for the period
64 92c53da1 Vassilios Karakoidas
    from vm.charged to datetime.now(), based on the
65 92c53da1 Vassilios Karakoidas
    current operating state.
66 92c53da1 Vassilios Karakoidas

67 92c53da1 Vassilios Karakoidas
    """
68 92c53da1 Vassilios Karakoidas
    charged_states = ('STARTED', 'STOPPED')
69 92c53da1 Vassilios Karakoidas
70 92c53da1 Vassilios Karakoidas
    start_datetime = vm.charged
71 92c53da1 Vassilios Karakoidas
    vm.charged = datetime.now()
72 92c53da1 Vassilios Karakoidas
73 92c53da1 Vassilios Karakoidas
    # Only charge for a specific set of states
74 dfd19c2d Vassilios Karakoidas
    if vm.operstate in charged_states:
75 92c53da1 Vassilios Karakoidas
        cost_list = []
76 92c53da1 Vassilios Karakoidas
77 92c53da1 Vassilios Karakoidas
        # remember, we charge only for Started and Stopped
78 dfd19c2d Vassilios Karakoidas
        if vm.operstate == 'STARTED':
79 8d97deff Vassilios Karakoidas
            cost_list = get_cost_active(vm.flavor, start_datetime, vm.charged)
80 dfd19c2d Vassilios Karakoidas
        elif vm.operstate == 'STOPPED':
81 8d97deff Vassilios Karakoidas
            cost_list = get_cost_inactive(vm.flavor, start_datetime, vm.charged)
82 92c53da1 Vassilios Karakoidas
83 92c53da1 Vassilios Karakoidas
        # find the total vost
84 92c53da1 Vassilios Karakoidas
        total_cost = sum([x[1] for x in cost_list])
85 92c53da1 Vassilios Karakoidas
86 92c53da1 Vassilios Karakoidas
        # add the debit entry
87 dfd19c2d Vassilios Karakoidas
        description = "Server = %s, charge = %d for state: %s" % (vm.name, total_cost, vm.operstate)
88 92c53da1 Vassilios Karakoidas
        debit_account(vm.owner, total_cost, vm, description)
89 92c53da1 Vassilios Karakoidas
90 92c53da1 Vassilios Karakoidas
    vm.save()
91 111b2cda Vassilios Karakoidas
92 8d97deff Vassilios Karakoidas
93 111b2cda Vassilios Karakoidas
def get_costs(vm, start_datetime, end_datetime, active):
94 111b2cda Vassilios Karakoidas
    """Return a list with FlavorCost objects for the specified duration"""
95 111b2cda Vassilios Karakoidas
    def between(enh_fc, a_date):
96 111b2cda Vassilios Karakoidas
        """Checks if a date is between a FlavorCost duration"""
97 111b2cda Vassilios Karakoidas
        if enh_fc.effective_from <= a_date and enh_fc.effective_to is None:
98 111b2cda Vassilios Karakoidas
            return True
99 111b2cda Vassilios Karakoidas
100 111b2cda Vassilios Karakoidas
        return enh_fc.effective_from <= a_date and enh_fc.effective_to >= a_date
101 111b2cda Vassilios Karakoidas
102 111b2cda Vassilios Karakoidas
    # Get the related FlavorCost objects, sorted.
103 111b2cda Vassilios Karakoidas
    price_list = FlavorCost.objects.filter(flavor=vm).order_by('effective_from')
104 111b2cda Vassilios Karakoidas
105 111b2cda Vassilios Karakoidas
    # add the extra field FlavorCost.effective_to
106 111b2cda Vassilios Karakoidas
    for idx in range(0, len(price_list)):
107 111b2cda Vassilios Karakoidas
        if idx + 1 == len(price_list):
108 111b2cda Vassilios Karakoidas
            price_list[idx].effective_to = None
109 111b2cda Vassilios Karakoidas
        else:
110 111b2cda Vassilios Karakoidas
            price_list[idx].effective_to = price_list[idx + 1].effective_from
111 111b2cda Vassilios Karakoidas
112 111b2cda Vassilios Karakoidas
    price_result = []
113 111b2cda Vassilios Karakoidas
    found_start = False
114 111b2cda Vassilios Karakoidas
115 111b2cda Vassilios Karakoidas
    # Find the affected FlavorCost, according to the
116 111b2cda Vassilios Karakoidas
    # dates, and put them in price_result
117 111b2cda Vassilios Karakoidas
    for p in price_list:
118 111b2cda Vassilios Karakoidas
        if between(p, start_datetime):
119 111b2cda Vassilios Karakoidas
            found_start = True
120 111b2cda Vassilios Karakoidas
            p.effective_from = start_datetime
121 111b2cda Vassilios Karakoidas
        if between(p, end_datetime):
122 111b2cda Vassilios Karakoidas
            p.effective_to = end_datetime
123 111b2cda Vassilios Karakoidas
            price_result.append(p)
124 111b2cda Vassilios Karakoidas
            break
125 111b2cda Vassilios Karakoidas
        if found_start:
126 111b2cda Vassilios Karakoidas
            price_result.append(p)
127 111b2cda Vassilios Karakoidas
128 111b2cda Vassilios Karakoidas
    results = []
129 111b2cda Vassilios Karakoidas
130 111b2cda Vassilios Karakoidas
    # Create the list and the result tuples
131 111b2cda Vassilios Karakoidas
    for p in price_result:
132 111b2cda Vassilios Karakoidas
        if active:
133 111b2cda Vassilios Karakoidas
            cost = p.cost_active
134 111b2cda Vassilios Karakoidas
        else:
135 111b2cda Vassilios Karakoidas
            cost = p.cost_inactive
136 111b2cda Vassilios Karakoidas
137 c8926262 Vassilios Karakoidas
        results.append( ( p.effective_from, calculate_cost(p.effective_from, p.effective_to, cost)) )
138 111b2cda Vassilios Karakoidas
139 111b2cda Vassilios Karakoidas
    return results
140 c8926262 Vassilios Karakoidas
141 c8926262 Vassilios Karakoidas
142 c8926262 Vassilios Karakoidas
def calculate_cost(start_date, end_date, cost):
143 c8926262 Vassilios Karakoidas
    """Calculate the total cost for the specified duration"""
144 c8926262 Vassilios Karakoidas
    td = end_date - start_date
145 c8926262 Vassilios Karakoidas
    sec = float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / float(10**6)
146 c8926262 Vassilios Karakoidas
    total_hours = float(sec) / float(60.0*60.0)
147 c8926262 Vassilios Karakoidas
    total_cost = float(cost)*total_hours
148 c8926262 Vassilios Karakoidas
149 c8926262 Vassilios Karakoidas
    return round(total_cost)
150 8d97deff Vassilios Karakoidas
151 8d97deff Vassilios Karakoidas
152 8d97deff Vassilios Karakoidas
def get_cost_active(vm, start_datetime, end_datetime):
153 8d97deff Vassilios Karakoidas
    """Returns a list with the active costs for the specified duration"""
154 8d97deff Vassilios Karakoidas
    return get_costs(vm, start_datetime, end_datetime, True)
155 8d97deff Vassilios Karakoidas
156 8d97deff Vassilios Karakoidas
157 8d97deff Vassilios Karakoidas
def get_cost_inactive(vm, start_datetime, end_datetime):
158 8d97deff Vassilios Karakoidas
    """Returns a list with the inactive costs for the specified duration"""
159 8d97deff Vassilios Karakoidas
    return get_costs(vm, start_datetime, end_datetime, False)