Statistics
| Branch: | Tag: | Revision:

root / logic / credits.py @ fc30c430

History | View | Annotate | Download (4.1 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
from django.db import transaction
9

    
10
from synnefo.db.models import Debit, FlavorCost
11

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

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

    
27

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

    
33

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

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

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

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

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

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

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

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

    
65
    vm.save()
66

    
67

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

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

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

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

    
87
    price_result = []
88
    found_start = False
89

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

    
103
    results = []
104

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

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

    
114
    return results
115

    
116

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

    
124
    return round(total_cost)
125

    
126

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

    
131

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