distil/artifice/database.py
adriant a0b8ec9b7f adding api call to get sales orders in a given range
udating the api to be able to return salesorders between a given range,
as well as the client/shell to make use of this.

Has resulted in a lot of duplicate code, but next patch will go through
and clean up a bunch of that, and extract a few validators into either decorators,
or at least helper functions.

Change-Id: I59ed58c32b8dd4a75babf70df188e965e5e94a16
2014-05-13 15:36:42 +12:00

111 lines
4.2 KiB
Python

from sqlalchemy import func
from .models import Resource, UsageEntry, Tenant, SalesOrder
import json
import config
class Database(object):
def __init__(self, session):
self.session = session
def insert_tenant(self, tenant_id, tenant_name, metadata, timestamp):
"""If a tenant exists does nothing,
and if it doesn't, creates and inserts it."""
# Have we seen this tenant before?
query = self.session.query(Tenant).\
filter(Tenant.id == tenant_id)
if query.count() == 0:
tenant = Tenant(id=tenant_id,
info=metadata,
name=tenant_name,
created=timestamp
)
self.session.add(tenant)
self.session.flush() # can't assume deferred constraints.
return tenant
else:
return query[0]
def insert_resource(self, tenant_id, resource_id, resource_type,
timestamp, entry):
query = self.session.query(Resource).\
filter(Resource.id == resource_id,
Resource.tenant_id == tenant_id)
if query.count() == 0:
info = self.merge_resource_metadata({'type': resource_type}, entry)
self.session.add(Resource(
id=resource_id,
info=json.dumps(info),
tenant_id=tenant_id,
created=timestamp))
self.session.flush() # can't assume deferred constraints.
else:
md_dict = json.loads(query[0].info)
md_dict = self.merge_resource_metadata(md_dict, entry)
query[0].info = json.dumps(md_dict)
def insert_usage(self, tenant_id, resource_id, entries, unit,
start, end, timestamp):
for service, volume in entries.items():
entry = UsageEntry(
service=service,
volume=volume,
unit=unit,
resource_id=resource_id,
tenant_id=tenant_id,
start=start,
end=end,
created=timestamp)
self.session.add(entry)
print entry
def enter(self, tenant, resource, entries, timestamp):
"""Creates a new database entry for every usage strategy
in a resource, for all the resources given"""
raise Exception("Dead!")
def usage(self, start, end, tenant_id):
"""Returns a query of usage entries for a given tenant,
in the given range.
start, end: define the range to query
tenant: a tenant entry (tenant_id for now)"""
# build a query set in the format:
# tenant_id | resource_id | service | sum(volume)
query = self.session.query(UsageEntry.tenant_id,
UsageEntry.resource_id,
UsageEntry.service,
UsageEntry.unit,
func.sum(UsageEntry.volume).label("volume")).\
filter(UsageEntry.start >= start, UsageEntry.end <= end).\
filter(UsageEntry.tenant_id == tenant_id).\
group_by(UsageEntry.tenant_id, UsageEntry.resource_id,
UsageEntry.service, UsageEntry.unit)
return query
def get_resource_metadata(self, resource_id):
info = self.session.query(Resource.info).\
filter(Resource.id == resource_id)
return json.loads(info[0].info)
def get_sales_orders(self, tenant_id, start, end):
query = self.session.query(SalesOrder).\
filter(SalesOrder.start <= end, SalesOrder.end >= start).\
filter(SalesOrder.tenant_id == tenant_id)
return query
def merge_resource_metadata(self, md_dict, entry):
fields = config.collection['metadata_def'].get(md_dict['type'], {})
for field, sources in fields.iteritems():
for i, source in enumerate(sources):
try:
md_dict[field] = entry['resource_metadata'][sources[0]]
break
except KeyError:
# Just means we haven't found the right value yet.
pass
return md_dict