blob: a8d3aaee0cdbd854abd18c1a9cdcf385d00b68d2 [file] [log] [blame]
Scott Baker43105042013-12-06 23:23:36 -08001"""
Scott Baker8a818df2014-05-13 17:06:28 -07002 Generates billing sample data
Scott Baker43105042013-12-06 23:23:36 -08003"""
4
5import datetime
6import os
7import operator
8import pytz
9import json
10import random
11import sys
12import time
13
Scott Baker8a818df2014-05-13 17:06:28 -070014# The granularity at which the charge collection system collects charges. Once
15# per hour makes for a very slow UI, so I upped it to once per 8 hours.
16CHARGE_HOURS = 8
17
Scott Baker43105042013-12-06 23:23:36 -080018MINUTE_SECONDS = 60
19HOUR_SECONDS = MINUTE_SECONDS * 60
20DAY_SECONDS = HOUR_SECONDS * 24
21MONTH_SECONDS = DAY_SECONDS * 30
22
Scott Baker5867bbe2015-02-04 15:22:05 -080023# XXX hardcoded path
Scott Baker166f4b82015-02-09 11:18:46 -080024sys.path.append("/opt/xos")
Scott Baker43105042013-12-06 23:23:36 -080025
Scott Baker76a840e2015-02-11 21:38:09 -080026os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
Scott Baker43105042013-12-06 23:23:36 -080027#from openstack.manager import OpenStackManager
28from core.models import Slice, Sliver, ServiceClass, Reservation, Tag, Network, User, Node, Image, Deployment, Site, NetworkTemplate, NetworkSlice
29from core.models import Invoice, Charge, Account, UsableObject, Payment
30
31def delete_all(model):
32 for item in model.objects.all():
33 item.delete()
34
35def get_usable_object(name):
36 objs = UsableObject.objects.filter(name=name)
37 if objs:
38 return objs[0]
39 obj = UsableObject(name=name)
40 obj.save()
41 return obj
42
43def generate_invoice(account, batch):
44 invoice = Invoice(date=batch[-1].date, account=account)
45 invoice.save()
46 for charge in batch:
47 charge.invoice = invoice
48 charge.state = "invoiced"
49 charge.save()
50
51def generate_invoices(account):
52 invoices = sorted(Invoice.objects.filter(account=account), key=operator.attrgetter('date'))
53 charges = sorted(Charge.objects.filter(account=account, state="pending"), key=operator.attrgetter('date'))
54
55 if invoices:
56 latest_invoice_date = invoices[-1].date()
57 else:
58 latest_invoice_date = None
59
60 batch = []
61 last_week = 0
62 for charge in charges:
63 # check to see if we crossed a week boundary. If we did, then generate
64 # an invoice for the last week's batch of charges
65 week = charge.date.isocalendar()[1]
66 if (week != last_week) and (batch):
67 generate_invoice(account, batch)
68 batch = []
69 last_week = week
70 batch.append(charge)
71
72 # we might still have last week's data batched up, and no data for this week
73 # if so, invoice the batch
74 this_week = datetime.datetime.now().isocalendar()[1]
75 if (this_week != last_week) and (batch):
76 generate_invoice(account, batch)
77
78def generate_payments(account):
79 invoices = Invoice.objects.filter(account=account)
80 for invoice in invoices:
81 # let's be optomistic and assume everyone pays exactly two weeks after
82 # receiving an invoice
83 payment_time = int(invoice.date.strftime("%s")) + 14 * DAY_SECONDS
84 if payment_time < time.time():
85 payment_time = datetime.datetime.utcfromtimestamp(payment_time).replace(tzinfo=pytz.utc)
86 payment = Payment(account=account, amount=invoice.amount, date=payment_time)
87 payment.save()
88
Scott Baker8a818df2014-05-13 17:06:28 -070089print "deleting old stuff"
90
Scott Baker43105042013-12-06 23:23:36 -080091delete_all(Invoice)
92delete_all(Charge)
93delete_all(Payment)
94delete_all(Account)
95delete_all(UsableObject)
96
Scott Baker8a818df2014-05-13 17:06:28 -070097print "creating accounts"
98
Scott Baker43105042013-12-06 23:23:36 -080099for site in Site.objects.all():
100 # only create accounts for sites where some slices exist
101 if len(site.slices.all()) > 0:
102 account = Account(site=site)
103 account.save()
104
Scott Baker8a818df2014-05-13 17:06:28 -0700105print "generating charges"
106
Scott Baker43105042013-12-06 23:23:36 -0800107for slice in Slice.objects.all():
108 site = slice.site
109 account = site.accounts.all()[0]
110 serviceClass =slice.serviceClass
111
Scott Baker8a818df2014-05-13 17:06:28 -0700112 if not (slice.name in ["DnsRedir", "DnsDemux", "HyperCache", "Hadoop", "Owl", "Stork", "Syndicate", "test-slice-1", "test-slice-2", "test", "test2"]):
Scott Baker43105042013-12-06 23:23:36 -0800113 continue
114
Scott Baker8a818df2014-05-13 17:06:28 -0700115 print " generating charges for", slice.name
116
Scott Baker43105042013-12-06 23:23:36 -0800117 now = int(time.time())/HOUR_SECONDS*HOUR_SECONDS
118
119 charge_kind=None
Sapan Bhatiafb8707d2014-11-11 19:25:29 -0500120 for resource in slice.serviceClass.serviceresources.all():
Scott Baker8a818df2014-05-13 17:06:28 -0700121 if resource.name == "numberCores":
Scott Baker43105042013-12-06 23:23:36 -0800122 charge_kind = "reservation"
123 cost = resource.cost
Scott Baker8a818df2014-05-13 17:06:28 -0700124 elif (charge_kind==None) and (resource.name == "cycles") or (resource.name == "Cycles"):
Scott Baker43105042013-12-06 23:23:36 -0800125 charge_kind = "besteffort"
126 cost = resource.cost
127
128 if not charge_kind:
129 print "failed to find resource for", slice.serviceClass
130 continue
131
Scott Baker8a818df2014-05-13 17:06:28 -0700132 for sliver in slice.slivers.all()[:4]: # only do up to 4 slivers; it's way too much data otherwise
Scott Baker43105042013-12-06 23:23:36 -0800133 hostname = sliver.node.name
Scott Baker8a818df2014-05-13 17:06:28 -0700134 for i in range(now-MONTH_SECONDS, now, CHARGE_HOURS*HOUR_SECONDS):
Scott Baker43105042013-12-06 23:23:36 -0800135 if charge_kind == "besteffort":
Scott Baker8a818df2014-05-13 17:06:28 -0700136 core_hours = random.randint(20,60)/100.0
Scott Baker43105042013-12-06 23:23:36 -0800137 else:
138 core_hours = 1
139
Scott Baker8a818df2014-05-13 17:06:28 -0700140 core_hours = core_hours * CHARGE_HOURS
141
142 amount = float(core_hours * cost) / 100.0
Scott Baker43105042013-12-06 23:23:36 -0800143
144 object = get_usable_object(hostname)
145
146 date = datetime.datetime.utcfromtimestamp(i).replace(tzinfo=pytz.utc)
147
148 charge = Charge(account=account, slice=slice, kind=charge_kind, state="pending", date=date, object=object, coreHours=core_hours, amount=amount)
149 charge.save()
150
Scott Baker8a818df2014-05-13 17:06:28 -0700151print "doing invoices and payments"
152
Scott Baker43105042013-12-06 23:23:36 -0800153for account in Account.objects.all():
154 generate_invoices(account)
155 generate_payments(account)
156
157
158