Statistics
| Branch: | Tag: | Revision:

root / logic / credits.py @ dfd19c2d

History | View | Annotate | Download (4 kB)

1
#
2
# Business Logic for all Credit related activity
3
#
4
# Copyright 2010 Greek Research and Technology Network
5
#
6

    
7
from datetime import datetime
8

    
9
from db.models import Debit, FlavorCost
10

    
11
from django.db import transaction
12

    
13
@transaction.commit_on_success
14
def debit_account(user , amount, vm, description):
15
    """Charges the user with the specified amount of credits for a vm (resource)"""
16
    date_now = datetime.now()
17
    user.credit = user.credit - amount
18
    user.save()
19

    
20
    # then write the debit entry
21
    debit = Debit()
22
    debit.user = user
23
    debit.vm = vm
24
    debit.when = date_now
25
    debit.description = description
26
    debit.save()
27

    
28

    
29
@transaction.commit_on_success
30
def credit_account(self, amount, creditor, description):
31
    """No clue :)"""
32
    return
33

    
34

    
35
@transaction.commit_on_success
36
def charge(vm):
37
    """Charges the owner of this VM.
38

39
    Charges the owner of a VM for the period
40
    from vm.charged to datetime.now(), based on the
41
    current operating state.
42

43
    """
44
    charged_states = ('STARTED', 'STOPPED')
45

    
46
    start_datetime = vm.charged
47
    vm.charged = datetime.now()
48

    
49
    # Only charge for a specific set of states
50
    if vm.operstate in charged_states:
51
        cost_list = []
52

    
53
        # remember, we charge only for Started and Stopped
54
        if vm.operstate == 'STARTED':
55
            cost_list = get_cost_active(vm.flavor, start_datetime, vm.charged)
56
        elif vm.operstate == 'STOPPED':
57
            cost_list = get_cost_inactive(vm.flavor, start_datetime, vm.charged)
58

    
59
        # find the total vost
60
        total_cost = sum([x[1] for x in cost_list])
61

    
62
        # add the debit entry
63
        description = "Server = %s, charge = %d for state: %s" % (vm.name, total_cost, vm.operstate)
64
        debit_account(vm.owner, total_cost, vm, description)
65

    
66
    vm.save()
67

    
68

    
69
def get_costs(vm, start_datetime, end_datetime, active):
70
    """Return a list with FlavorCost objects for the specified duration"""
71
    def between(enh_fc, a_date):
72
        """Checks if a date is between a FlavorCost duration"""
73
        if enh_fc.effective_from <= a_date and enh_fc.effective_to is None:
74
            return True
75

    
76
        return enh_fc.effective_from <= a_date and enh_fc.effective_to >= a_date
77

    
78
    # Get the related FlavorCost objects, sorted.
79
    price_list = FlavorCost.objects.filter(flavor=vm).order_by('effective_from')
80

    
81
    # add the extra field FlavorCost.effective_to
82
    for idx in range(0, len(price_list)):
83
        if idx + 1 == len(price_list):
84
            price_list[idx].effective_to = None
85
        else:
86
            price_list[idx].effective_to = price_list[idx + 1].effective_from
87

    
88
    price_result = []
89
    found_start = False
90

    
91
    # Find the affected FlavorCost, according to the
92
    # dates, and put them in price_result
93
    for p in price_list:
94
        if between(p, start_datetime):
95
            found_start = True
96
            p.effective_from = start_datetime
97
        if between(p, end_datetime):
98
            p.effective_to = end_datetime
99
            price_result.append(p)
100
            break
101
        if found_start:
102
            price_result.append(p)
103

    
104
    results = []
105

    
106
    # Create the list and the result tuples
107
    for p in price_result:
108
        if active:
109
            cost = p.cost_active
110
        else:
111
            cost = p.cost_inactive
112

    
113
        results.append( ( p.effective_from, calculate_cost(p.effective_from, p.effective_to, cost)) )
114

    
115
    return results
116

    
117

    
118
def calculate_cost(start_date, end_date, cost):
119
    """Calculate the total cost for the specified duration"""
120
    td = end_date - start_date
121
    sec = float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / float(10**6)
122
    total_hours = float(sec) / float(60.0*60.0)
123
    total_cost = float(cost)*total_hours
124

    
125
    return round(total_cost)
126

    
127

    
128
def get_cost_active(vm, start_datetime, end_datetime):
129
    """Returns a list with the active costs for the specified duration"""
130
    return get_costs(vm, start_datetime, end_datetime, True)
131

    
132

    
133
def get_cost_inactive(vm, start_datetime, end_datetime):
134
    """Returns a list with the inactive costs for the specified duration"""
135
    return get_costs(vm, start_datetime, end_datetime, False)