Removing usage again
This commit is contained in:
parent
e2405f5d8f
commit
383a7f4c3b
132
api/web.py
132
api/web.py
@ -15,6 +15,9 @@ db = Session()
|
||||
|
||||
config = load_config()
|
||||
|
||||
|
||||
# Some useful constants
|
||||
|
||||
iso_time = "%Y-%m-%dT%H:%M:%S"
|
||||
iso_date = "%Y-%m-%d"
|
||||
|
||||
@ -47,9 +50,14 @@ def keystone(func):
|
||||
|
||||
return _perform_keystone
|
||||
|
||||
# TODO: fill me in
|
||||
def must(*args):
|
||||
return lambda(func): func
|
||||
|
||||
@app.get("/usage")
|
||||
@app.get("/usage/{resource_id}") # also allow for querying by resource ID.
|
||||
@keystone
|
||||
@must("resource_id", "tenant")
|
||||
def retrieve_usage(resource_id=None):
|
||||
"""Retrieves usage for a given tenant ID.
|
||||
Tenant ID will be passed in via the query string.
|
||||
@ -99,33 +107,108 @@ def retrieve_usage(resource_id=None):
|
||||
|
||||
@app.post("/usage")
|
||||
@keystone
|
||||
def add_usage(self):
|
||||
@must("amount", "start", "end", "tenant")
|
||||
def add_usage():
|
||||
"""
|
||||
Adds usage for a given tenant T.
|
||||
Adds usage for a given tenant T and resource R.
|
||||
Expects to receive a Resource ID, a time range, and a volume.
|
||||
|
||||
The volume will be parsed from JSON as a Decimal object.
|
||||
"""
|
||||
|
||||
body = json.loads(request.body, parse_float=Decimal)
|
||||
db.begin()
|
||||
for resource in body["resources"]:
|
||||
start = datetime.strptime(resource.get("start"), date_iso)
|
||||
end = datetime.strptime(resource.get("end"), date_iso)
|
||||
id_ = resource["id"]
|
||||
u = usage.Usage(
|
||||
resource=id_,
|
||||
tenant=request.params["tenant"],
|
||||
value=resource["amount"],
|
||||
start=start,
|
||||
end=end)
|
||||
db.add(u)
|
||||
try:
|
||||
db.commit()
|
||||
except Exception as e:
|
||||
# Explodytime
|
||||
status(500)
|
||||
return(json.dumps(
|
||||
{"status": "error",
|
||||
"error" : "database transaction error"
|
||||
}))
|
||||
|
||||
status(201)
|
||||
return json.dumps({
|
||||
"status": "ok",
|
||||
"saved": len(body["resources"])
|
||||
})
|
||||
|
||||
@app.get("/bill")
|
||||
@app.get("/bill/{id}")
|
||||
@app.get("/bills/{id}")
|
||||
@keystone
|
||||
def get_bill():
|
||||
@must("tenant", "start", "end")
|
||||
def get_bill(id_):
|
||||
"""
|
||||
Returns either a single bill or a set of the most recent
|
||||
bills for a given Tenant.
|
||||
"""
|
||||
pass
|
||||
|
||||
# TODO: Put these into an input validator instead
|
||||
try:
|
||||
start = datetime.strptime(request.params["start"], date_iso)
|
||||
except:
|
||||
abort(
|
||||
403,
|
||||
json.dumps(
|
||||
{"status":"error",
|
||||
"error": "start date is not ISO-compliant"})
|
||||
)
|
||||
try:
|
||||
end = datetime.strptime(request.params["end"], date_iso)
|
||||
except:
|
||||
abort(
|
||||
403,
|
||||
json.dumps(
|
||||
{"status":"error",
|
||||
"error": "end date is not ISO-compliant"})
|
||||
)
|
||||
|
||||
try:
|
||||
bill = BillInterface(session).get(id_)
|
||||
except:
|
||||
abort(404)
|
||||
|
||||
if not bill:
|
||||
abort(404)
|
||||
|
||||
resp = {"status": "ok",
|
||||
"bill": [],
|
||||
"total": str(bill.total),
|
||||
"tenant": bill.tenant_id
|
||||
}
|
||||
|
||||
for resource in billed:
|
||||
resp["bill"].append({
|
||||
'resource_id': bill.resource_id,
|
||||
'volume': str( bill.volume ),
|
||||
'rate': str( bill.rate ),
|
||||
# 'metadata': # TODO: This will be filled in with extra data
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
@app.get("/bill/{bill_id}")
|
||||
return (200, json.dumps(resp))
|
||||
|
||||
@app.post("/usage/current")
|
||||
@keystone
|
||||
def get_bill_by_id(bill_id=None):
|
||||
@must("tenant_id")
|
||||
def get_current_usage():
|
||||
"""
|
||||
Is intended to return a running total of the current billing periods'
|
||||
dataset. Performs a Rate transformer on each transformed datapoint and
|
||||
returns the result.
|
||||
|
||||
TODO: Implement
|
||||
"""
|
||||
pass
|
||||
|
||||
@app.post("/bill")
|
||||
@ -147,6 +230,29 @@ def make_a_bill():
|
||||
end = body.get("end", None)
|
||||
if not start or not end:
|
||||
return abort(403) # All three *must* be defined
|
||||
bill = usage.Bill()
|
||||
|
||||
|
||||
# total =
|
||||
bill = BillInterface(session)
|
||||
thebill = bill.generate(body["tenant_id"], start, end)
|
||||
# assumes the bill is saved
|
||||
|
||||
if not thebill.is_saved:
|
||||
# raise an error
|
||||
abort(500)
|
||||
|
||||
resp = {"status":"created",
|
||||
"id": thebill.id,
|
||||
"contents": [],
|
||||
"total": None
|
||||
}
|
||||
for resource in thebill.resources:
|
||||
total += Decimal(billed.total)
|
||||
resp["contents"].append({
|
||||
'resource_id': bill.resource_id,
|
||||
'volume': str( bill.volume ),
|
||||
'rate': str( bill.rate ),
|
||||
# 'metadata': # TODO: This will be filled in with extra data
|
||||
})
|
||||
|
||||
resp["total"] = thebill.total
|
||||
return (201, json.dumps(resp))
|
||||
|
9
bin/bill
9
bin/bill
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
INSTALLED="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
ORIGIN=`pwd`
|
||||
|
||||
# Bring up our python environment
|
||||
# Pass through all our command line opts as expected
|
||||
|
||||
$INSTALLED/../env/bin/python $INSTALLED/bill.py $@
|
144
bin/bill.py
144
bin/bill.py
@ -1,144 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os
|
||||
|
||||
try:
|
||||
from artifice import interface
|
||||
except ImportError:
|
||||
loc, fn = os.path.split(__file__)
|
||||
print loc
|
||||
here = os.path.abspath(os.path.join(loc + "/../"))
|
||||
sys.path.insert(0, here)
|
||||
# # Are we potentially in a virtualenv? Add that in.
|
||||
# if os.path.exists( os.path.join(here, "lib/python2.7" ) ):
|
||||
# sys.path.insert(1, os.path.join(here, "lib/python2.7"))
|
||||
from artifice import interface
|
||||
|
||||
import datetime
|
||||
import yaml
|
||||
|
||||
date_format = "%Y-%m-%dT%H:%M:%S"
|
||||
other_date_format = "%Y-%m-%dT%H:%M:%S.%f"
|
||||
|
||||
date_fmt_fnc = lambda x: datetime.datetime.strptime(date_format)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
# Takes names to display.
|
||||
# none means display them all.
|
||||
parser.add_argument("-t", "--tenant", dest="tenants",
|
||||
help='Tenant to display', action="append", default=[])
|
||||
|
||||
# Add some sections to show data from.
|
||||
# Empty is display all
|
||||
parser.add_argument("-s", "--section", dest="sections",
|
||||
help="Sections to display", action="append")
|
||||
|
||||
# Ranging
|
||||
# We want to get stuff from, to.
|
||||
|
||||
parser.add_argument(
|
||||
"--from",
|
||||
dest="start",
|
||||
help="When to start our range, date format %s" % ( date_fmt.replace("%","%%") ) ,
|
||||
type=date_fmt_fnc,
|
||||
default=datetime.datetime.now() - datetime.timedelta(days=31)
|
||||
)
|
||||
parser.add_argument(
|
||||
"--to", dest="end",
|
||||
help="When to end our date range. Defaults to yesterday.",
|
||||
type=date_fmt_fnc,
|
||||
default=datetime.datetime.now() - datetime.timedelta(days=1))
|
||||
|
||||
parser.add_argument("--config", dest="config", help="Config file",
|
||||
default="/opt/stack/artifice/etc/artifice/conf.yaml")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
conf = yaml.load(open(args.config).read())
|
||||
except IOError:
|
||||
# Whoops
|
||||
print "couldn't load %s " % args.config
|
||||
sys.exit(1)
|
||||
|
||||
# Make ourselves a nice interaction object
|
||||
# Password needs to be loaded from /etc/artifice/database
|
||||
fh = open(conf["database"]["password_path"])
|
||||
password = fh.read()
|
||||
fh.close()
|
||||
# Make ourselves a nice interaction object
|
||||
conf["database"]["password"] = password.replace("\n", "")
|
||||
n = interface.Artifice(conf)
|
||||
tenants = args.tenants
|
||||
if not args.tenants:
|
||||
# only parse this list of tenants
|
||||
tenants = n.tenants
|
||||
|
||||
print "\n # ----------------- bill summary for: ----------------- # "
|
||||
print "Range: %s -> %s" % (args.start, args.end)
|
||||
|
||||
for tenant_name in tenants:
|
||||
# artifact = n.tenant(tenant_name).section(section).usage(args.start, args.end)
|
||||
# data should now be an artifact-like construct.
|
||||
# Data also knows about Samples, where as an Artifact doesn't.
|
||||
|
||||
# An artifact knows its section
|
||||
tenant = n.tenant(tenant_name)
|
||||
# Makes a new invoice up for this tenant.
|
||||
invoice = tenant.invoice(args.start, args.end)
|
||||
print "\n# ------------------------ Tenant: %s ------------------------ #" % tenant.name
|
||||
|
||||
# usage = tenant.usage(start, end)
|
||||
usage = tenant.usage(args.start, args.end)
|
||||
# A Usage set is the entirety of time for this Tenant.
|
||||
# It's not time-limited at all.
|
||||
# But the
|
||||
usage.save()
|
||||
invoice.bill(usage.vms)
|
||||
invoice.bill(usage.volumes)
|
||||
invoice.bill(usage.objects)
|
||||
invoice.bill(usage.networks)
|
||||
invoice.close()
|
||||
|
||||
print invoice.total()
|
||||
print "# --------------------- End of Tenant: %s --------------------- #" % tenant.name
|
||||
|
||||
# for datacenter, sections in usage.iteritems():
|
||||
# # DC is the name of the DC/region. Or the internal code. W/E.
|
||||
# print datacenter
|
||||
|
||||
# for section_name in args.sections:
|
||||
# assert section in sections
|
||||
|
||||
# # section = sections[ section ]
|
||||
# print sections[section_name]
|
||||
# for resources in sections[section_name]:
|
||||
# for resource in resources:
|
||||
# print resource
|
||||
# for meter in resource.meters:
|
||||
# usage = meter.usage(start, end)
|
||||
# if usage.has_been_saved():
|
||||
# continue
|
||||
# print usage.volume()
|
||||
# print usage.cost()
|
||||
# usage.save()
|
||||
# # Finally, bill it.
|
||||
# # All of these things need to be converted to the
|
||||
# # publicly-viewable version now.
|
||||
# invoice.bill(datacenter, resource, meter, usage)
|
||||
|
||||
# # Section is going to be in the set of vm, network, storage, image
|
||||
# # # or just all of them.
|
||||
# # # It's not going to be an individual meter name.
|
||||
# # artifacts = section.usage(args.start, args.end)
|
||||
# # for artifact in artifacts:
|
||||
# # if artifact.has_been_saved:
|
||||
# # # Does this artifact exist in the DB?
|
||||
# # continue
|
||||
# # artifact.save() # Save to the Artifact storage
|
||||
# # # Saves to the invoice.
|
||||
# # invoice.bill ( artifact )
|
||||
# # # artifact.bill( invoice.id )
|
||||
# # print "%s: %s" % (section.name, artifact.volume)
|
139
bin/bill.py~
139
bin/bill.py~
@ -1,139 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os
|
||||
|
||||
try:
|
||||
from artifice import interface
|
||||
except ImportError:
|
||||
loc, fn = os.path.split(__file__)
|
||||
print loc
|
||||
here = os.path.abspath(os.path.join(loc +"/../"))
|
||||
sys.path.insert(0, here)
|
||||
# # Are we potentially in a virtualenv? Add that in.
|
||||
# if os.path.exists( os.path.join(here, "lib/python2.7" ) ):
|
||||
# sys.path.insert(1, os.path.join(here, "lib/python2.7"))
|
||||
from artifice import interface
|
||||
|
||||
import datetime
|
||||
import yaml
|
||||
|
||||
date_format = "%Y-%m-%dT%H:%M:%S"
|
||||
other_date_format = "%Y-%m-%dT%H:%M:%S.%f"
|
||||
|
||||
date_fmt_fnc = lambda x: datetime.datetime.strptime(date_format)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
# Takes names to display.
|
||||
# none means display them all.
|
||||
parser.add_argument("-t", "--tenant", dest="tenants", help='Tenant to display', action="append", default=[])
|
||||
|
||||
# Add some sections to show data from.
|
||||
# Empty is display all
|
||||
parser.add_argument("-s", "--section", dest="sections", help="Sections to display", action="append")
|
||||
|
||||
|
||||
# Ranging
|
||||
# We want to get stuff from, to.
|
||||
|
||||
parser.add_argument(
|
||||
"--from",
|
||||
dest="start",
|
||||
help="When to start our range, date format %s",
|
||||
type=date_fmt_fnc,
|
||||
default=datetime.datetime.now() - datetime.timedelta(days=31)
|
||||
)
|
||||
parser.add_argument("--to", dest="end", help="When to end our date range. Defaults to yesterday.",
|
||||
type=date_fmt_fnc, default=datetime.datetime.now() - datetime.timedelta(days=1) )
|
||||
|
||||
parser.add_argument("--config", dest="config", help="Config file", default="/opt/stack/artifice/etc/artifice/conf.yaml")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
conf = yaml.load(open(args.config).read())
|
||||
except IOError:
|
||||
# Whoops
|
||||
print "couldn't load %s " % args.config
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Make ourselves a nice interaction object
|
||||
# Password needs to be loaded from /etc/artifice/database
|
||||
fh = open(conf["database"]["password_path"])
|
||||
password = fh.read()
|
||||
fh.close()
|
||||
# Make ourselves a nice interaction object
|
||||
conf["database"]["password"] = password
|
||||
n = interface.Artifice(conf)
|
||||
tenants = args.tenants
|
||||
if not args.tenants:
|
||||
# only parse this list of tenants
|
||||
tenants = n.tenants
|
||||
|
||||
print "\n # ----------------- bill summary for: ----------------- # "
|
||||
print "Range: %s -> %s" % (args.start, args.end)
|
||||
|
||||
for tenant_name in tenants:
|
||||
# artifact = n.tenant(tenant_name).section(section).usage(args.start, args.end)
|
||||
# data should now be an artifact-like construct.
|
||||
# Data also knows about Samples, where as an Artifact doesn't.
|
||||
|
||||
# An artifact knows its section
|
||||
tenant = n.tenant(tenant_name)
|
||||
# Makes a new invoice up for this tenant.
|
||||
invoice = tenant.invoice(args.start, args.end)
|
||||
print "\n# ------------------------ Tenant: %s ------------------------ #" % tenant.name
|
||||
|
||||
# usage = tenant.usage(start, end)
|
||||
usage = tenant.usage(args.start, args.end)
|
||||
# A Usage set is the entirety of time for this Tenant.
|
||||
# It's not time-limited at all.
|
||||
# But the
|
||||
usage.save()
|
||||
invoice.bill(usage.vms)
|
||||
invoice.bill(usage.volumes)
|
||||
# invoice.bill(usage.objects)
|
||||
invoice.close()
|
||||
|
||||
print invoice.total()
|
||||
print "# --------------------- End of Tenant: %s --------------------- #" % tenant.name
|
||||
|
||||
# for datacenter, sections in usage.iteritems():
|
||||
# # DC is the name of the DC/region. Or the internal code. W/E.
|
||||
# print datacenter
|
||||
|
||||
# for section_name in args.sections:
|
||||
# assert section in sections
|
||||
|
||||
# # section = sections[ section ]
|
||||
# print sections[section_name]
|
||||
# for resources in sections[section_name]:
|
||||
# for resource in resources:
|
||||
# print resource
|
||||
# for meter in resource.meters:
|
||||
# usage = meter.usage(start, end)
|
||||
# if usage.has_been_saved():
|
||||
# continue
|
||||
# print usage.volume()
|
||||
# print usage.cost()
|
||||
# usage.save()
|
||||
# # Finally, bill it.
|
||||
# # All of these things need to be converted to the
|
||||
# # publicly-viewable version now.
|
||||
# invoice.bill(datacenter, resource, meter, usage)
|
||||
|
||||
# # Section is going to be in the set of vm, network, storage, image
|
||||
# # # or just all of them.
|
||||
# # # It's not going to be an individual meter name.
|
||||
# # artifacts = section.usage(args.start, args.end)
|
||||
# # for artifact in artifacts:
|
||||
# # if artifact.has_been_saved:
|
||||
# # # Does this artifact exist in the DB?
|
||||
# # continue
|
||||
# # artifact.save() # Save to the Artifact storage
|
||||
# # # Saves to the invoice.
|
||||
# # invoice.bill ( artifact )
|
||||
# # # artifact.bill( invoice.id )
|
||||
# # print "%s: %s" % (section.name, artifact.volume)
|
@ -1,97 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os, sys
|
||||
|
||||
try:
|
||||
from artifice import interface
|
||||
except ImportError:
|
||||
loc, fn = os.path.split(__file__)
|
||||
print loc
|
||||
here = os.path.abspath(os.path.join(loc +"/../"))
|
||||
sys.path.insert(0, here)
|
||||
# # Are we potentially in a virtualenv? Add that in.
|
||||
# if os.path.exists( os.path.join(here, "lib/python2.7" ) ):
|
||||
# sys.path.insert(1, os.path.join(here, "lib/python2.7"))
|
||||
from artifice import interface
|
||||
|
||||
import datetime
|
||||
import yaml
|
||||
|
||||
date_format = "%Y-%m-%dT%H:%M:%S"
|
||||
other_date_format = "%Y-%m-%dT%H:%M:%S.%f"
|
||||
date_fmt = "%Y-%m-%d"
|
||||
|
||||
def date_fmt_fnc(val):
|
||||
return datetime.datetime.strptime(val, date_fmt)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
# Takes names to display.
|
||||
# none means display them all.
|
||||
parser.add_argument("-t", "--tenant", dest="tenants", help='Tenant to display', action="append", default=[])
|
||||
|
||||
# Add some sections to show data from.
|
||||
# Empty is display all
|
||||
parser.add_argument("-s", "--section", dest="sections", help="Sections to display", action="append")
|
||||
|
||||
|
||||
# Ranging
|
||||
# We want to get stuff from, to.
|
||||
|
||||
parser.add_argument(
|
||||
"--from",
|
||||
dest="start",
|
||||
help="When to start our range, date format %s",
|
||||
type=date_fmt_fnc,
|
||||
default=datetime.datetime.now() - datetime.timedelta(days=31)
|
||||
)
|
||||
parser.add_argument("--to", dest="end", help="When to end our date range. Defaults to yesterday.",
|
||||
type=date_fmt_fnc, default=datetime.datetime.now() - datetime.timedelta(days=1) )
|
||||
|
||||
parser.add_argument("-c", "--config", dest="config", help="Config file", default="/opt/stack/artifice/etc/artifice/conf.yaml")
|
||||
|
||||
args = parser.parse_args()
|
||||
print "\n # ----------------- usage summary for: ----------------- # "
|
||||
print "Range: %s -> %s" % (args.start, args.end)
|
||||
try:
|
||||
conf = yaml.load(open(args.config).read())
|
||||
except IOError:
|
||||
# Whoops
|
||||
print "couldn't load %s " % args.config
|
||||
sys.exit(1)
|
||||
|
||||
fh = open(conf["database"]["password_path"])
|
||||
password = fh.read()
|
||||
fh.close()
|
||||
# Make ourselves a nice interaction object
|
||||
conf["database"]["password"] = password
|
||||
instance = interface.Artifice(conf)
|
||||
tenants = args.tenants
|
||||
if not args.tenants:
|
||||
# only parse this list of tenants
|
||||
tenants = instance.tenants
|
||||
|
||||
for tenant_name in tenants:
|
||||
# artifact = n.tenant(tenant_name).section(section).usage(args.start, args.end)
|
||||
# data should now be an artifact-like construct.
|
||||
# Data also knows about Samples, where as an Artifact doesn't.
|
||||
|
||||
# An artifact knows its section
|
||||
tenant = instance.tenant(tenant_name)
|
||||
# Makes a new invoice up for this tenant.
|
||||
invoice = tenant.invoice(args.start, args.end)
|
||||
print "\n# ------------------------ Tenant: %s ------------------------ #" % tenant.name
|
||||
|
||||
|
||||
# usage = tenant.usage(start, end)
|
||||
usage = tenant.usage(args.start, args.end)
|
||||
# A Usage set is the entirety of time for this Tenant.
|
||||
# It's not time-limited at all.
|
||||
|
||||
invoice.bill(usage.vms)
|
||||
invoice.bill(usage.volumes)
|
||||
# invoice.bill(usage.objects)
|
||||
|
||||
print "Total invoice value: %s" % invoice.total()
|
||||
print "# --------------------- End of Tenant: %s --------------------- #" % tenant.name
|
Loading…
x
Reference in New Issue
Block a user