Statistics
| Branch: | Tag: | Revision:

root / logic / credits.py @ 48130e66

History | View | Annotate | Download (5.5 kB)

1
# Copyright 2011 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
#
7
#   1. Redistributions of source code must retain the above copyright
8
#      notice, this list of conditions and the following disclaimer.
9
#
10
#  2. Redistributions in binary form must reproduce the above copyright
11
#     notice, this list of conditions and the following disclaimer in the
12
#     documentation and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
# SUCH DAMAGE.
25
#
26
# The views and conclusions contained in the software and documentation are
27
# those of the authors and should not be interpreted as representing official
28
# policies, either expressed or implied, of GRNET S.A.
29

    
30
# Business Logic for all Credit related activity
31

    
32
from datetime import datetime
33
from django.db import transaction
34

    
35
from synnefo.db.models import Debit, FlavorCost
36

    
37
@transaction.commit_on_success
38
def debit_account(user , amount, vm, description):
39
    """Charges the user with the specified amount of credits for a vm (resource)"""
40
    date_now = datetime.now()
41
    user.credit = user.credit - amount
42
    user.save()
43

    
44
    # then write the debit entry
45
    debit = Debit()
46
    debit.user = user
47
    debit.vm = vm
48
    debit.when = date_now
49
    debit.description = description
50
    debit.save()
51

    
52

    
53
@transaction.commit_on_success
54
def credit_account(self, amount, creditor, description):
55
    """No clue :)"""
56
    return
57

    
58

    
59
@transaction.commit_on_success
60
def charge(vm):
61
    """Charges the owner of this VM.
62

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

67
    """
68
    charged_states = ('STARTED', 'STOPPED')
69

    
70
    start_datetime = vm.charged
71
    vm.charged = datetime.now()
72

    
73
    # Only charge for a specific set of states
74
    if vm.operstate in charged_states:
75
        cost_list = []
76

    
77
        # remember, we charge only for Started and Stopped
78
        if vm.operstate == 'STARTED':
79
            cost_list = get_cost_active(vm.flavor, start_datetime, vm.charged)
80
        elif vm.operstate == 'STOPPED':
81
            cost_list = get_cost_inactive(vm.flavor, start_datetime, vm.charged)
82

    
83
        # find the total vost
84
        total_cost = sum([x[1] for x in cost_list])
85

    
86
        # add the debit entry
87
        description = "Server = %s, charge = %d for state: %s" % (vm.name, total_cost, vm.operstate)
88
        debit_account(vm.owner, total_cost, vm, description)
89

    
90
    vm.save()
91

    
92

    
93
def get_costs(vm, start_datetime, end_datetime, active):
94
    """Return a list with FlavorCost objects for the specified duration"""
95
    def between(enh_fc, a_date):
96
        """Checks if a date is between a FlavorCost duration"""
97
        if enh_fc.effective_from <= a_date and enh_fc.effective_to is None:
98
            return True
99

    
100
        return enh_fc.effective_from <= a_date and enh_fc.effective_to >= a_date
101

    
102
    # Get the related FlavorCost objects, sorted.
103
    price_list = FlavorCost.objects.filter(flavor=vm).order_by('effective_from')
104

    
105
    # add the extra field FlavorCost.effective_to
106
    for idx in range(0, len(price_list)):
107
        if idx + 1 == len(price_list):
108
            price_list[idx].effective_to = None
109
        else:
110
            price_list[idx].effective_to = price_list[idx + 1].effective_from
111

    
112
    price_result = []
113
    found_start = False
114

    
115
    # Find the affected FlavorCost, according to the
116
    # dates, and put them in price_result
117
    for p in price_list:
118
        if between(p, start_datetime):
119
            found_start = True
120
            p.effective_from = start_datetime
121
        if between(p, end_datetime):
122
            p.effective_to = end_datetime
123
            price_result.append(p)
124
            break
125
        if found_start:
126
            price_result.append(p)
127

    
128
    results = []
129

    
130
    # Create the list and the result tuples
131
    for p in price_result:
132
        if active:
133
            cost = p.cost_active
134
        else:
135
            cost = p.cost_inactive
136

    
137
        results.append( ( p.effective_from, calculate_cost(p.effective_from, p.effective_to, cost)) )
138

    
139
    return results
140

    
141

    
142
def calculate_cost(start_date, end_date, cost):
143
    """Calculate the total cost for the specified duration"""
144
    td = end_date - start_date
145
    sec = float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / float(10**6)
146
    total_hours = float(sec) / float(60.0*60.0)
147
    total_cost = float(cost)*total_hours
148

    
149
    return round(total_cost)
150

    
151

    
152
def get_cost_active(vm, start_datetime, end_datetime):
153
    """Returns a list with the active costs for the specified duration"""
154
    return get_costs(vm, start_datetime, end_datetime, True)
155

    
156

    
157
def get_cost_inactive(vm, start_datetime, end_datetime):
158
    """Returns a list with the inactive costs for the specified duration"""
159
    return get_costs(vm, start_datetime, end_datetime, False)