Some more pep8 formatting tidying up.
This commit is contained in:
parent
5cb1ba97f3
commit
757adef5e2
@ -4,6 +4,7 @@ from artifice import invoice
|
|||||||
import yaml
|
import yaml
|
||||||
from decimal import *
|
from decimal import *
|
||||||
|
|
||||||
|
|
||||||
class Csv(invoice.RatesFileMixin, invoice.NamesFileMixin, invoice.Invoice):
|
class Csv(invoice.RatesFileMixin, invoice.NamesFileMixin, invoice.Invoice):
|
||||||
|
|
||||||
def __init__(self, tenant, start, end, config):
|
def __init__(self, tenant, start, end, config):
|
||||||
@ -38,31 +39,32 @@ class Csv(invoice.RatesFileMixin, invoice.NamesFileMixin, invoice.Invoice):
|
|||||||
continue
|
continue
|
||||||
# What do we expect element to be?
|
# What do we expect element to be?
|
||||||
if key == "rate":
|
if key == "rate":
|
||||||
appendee.append(self.rate(self.pretty_name(element.type)))
|
appendee.append(self.rate(self.pretty_name(element.type)))
|
||||||
if key == "type":
|
if key == "type":
|
||||||
# Fetch the 'pretty' name from the mappings, if any
|
# Fetch the 'pretty' name from the mappings, if any
|
||||||
# The default is that this returns the internal name
|
# The default is that this returns the internal name
|
||||||
appendee.append(self.pretty_name( element.get( key ) ) )
|
appendee.append(self.pretty_name(element.get(key)))
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
appendee.append( element.get(key) )
|
appendee.append(element.get(key))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
appendee.append("")
|
appendee.append("")
|
||||||
try:
|
try:
|
||||||
x = self.config["row_layout"].index("cost")
|
x = self.config["row_layout"].index("cost")
|
||||||
appendee[ x ] = element.amount.volume() * \
|
appendee[x] = (element.amount.volume() *
|
||||||
self.rate( self.pretty_name(element.type) )
|
self.rate(self.pretty_name(element.type)))
|
||||||
# print (str(appendee[1]) + " - From: " + str(appendee[2]) +
|
# print (str(appendee[1]) + " - From: " + str(appendee[2]) +
|
||||||
# ", Until: " + str(appendee[3]))
|
# ", Until: " + str(appendee[3]))
|
||||||
print ("type: " + str(self.pretty_name(element.get("type"))))
|
print ("type: " + str(self.pretty_name(element.get("type"))))
|
||||||
try:
|
try:
|
||||||
print " - name : " + str(element.get("name"))
|
print " - name : " + str(element.get("name"))
|
||||||
except:
|
except:
|
||||||
# Just means it isn't a VM
|
# Just means it isn't a VM
|
||||||
pass
|
pass
|
||||||
print " - usage: " + str(element.amount.volume())
|
print " - usage: " + str(element.amount.volume())
|
||||||
print " - rate: " + str(self.rate(self.pretty_name(element.type)))
|
print (" - rate: " +
|
||||||
print " - cost: " + str(appendee[ x ])
|
str(self.rate(self.pretty_name(element.type))))
|
||||||
|
print " - cost: " + str(appendee[x])
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Not in this array. Well okay.
|
# Not in this array. Well okay.
|
||||||
@ -79,16 +81,18 @@ class Csv(invoice.RatesFileMixin, invoice.NamesFileMixin, invoice.Invoice):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def filename(self):
|
def filename(self):
|
||||||
|
fn_dict = dict(tenant=self.tenant.tenant['name'], start=self.start,
|
||||||
|
end=self.end)
|
||||||
|
|
||||||
fn = os.path.join(
|
fn = os.path.join(
|
||||||
self.config["output_path"],
|
self.config["output_path"],
|
||||||
self.config["output_file"] % dict(tenant=self.tenant.tenant['name'],
|
self.config["output_file"] % fn_dict
|
||||||
start=self.start, end=self.end)
|
|
||||||
)
|
)
|
||||||
return fn
|
return fn
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
try:
|
try:
|
||||||
read = open( self.filename )
|
open(self.filename)
|
||||||
raise RuntimeError("Can't write to an existing file!")
|
raise RuntimeError("Can't write to an existing file!")
|
||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
@ -99,7 +103,6 @@ class Csv(invoice.RatesFileMixin, invoice.NamesFileMixin, invoice.Invoice):
|
|||||||
csvwriter.writerow(["usage range: ", str(self.start), str(self.end)])
|
csvwriter.writerow(["usage range: ", str(self.start), str(self.end)])
|
||||||
csvwriter.writerow([])
|
csvwriter.writerow([])
|
||||||
|
|
||||||
|
|
||||||
csvwriter.writerow(self.config["row_layout"])
|
csvwriter.writerow(self.config["row_layout"])
|
||||||
for line in self.lines:
|
for line in self.lines:
|
||||||
# Line is expected to be an iterable row
|
# Line is expected to be an iterable row
|
||||||
|
@ -18,13 +18,10 @@ from keystoneclient.v2_0 import client as KeystoneClient
|
|||||||
# Provides hooks to ceilometer, which we need for data.
|
# Provides hooks to ceilometer, which we need for data.
|
||||||
from ceilometerclient.v2.client import Client as ceilometer
|
from ceilometerclient.v2.client import Client as ceilometer
|
||||||
|
|
||||||
# from .models import usage
|
|
||||||
from .models import Session, usage
|
|
||||||
|
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
|
|
||||||
# from .models.usage import Usage
|
# from .models.usage import Usage
|
||||||
from .models import resources, tenants, usage
|
from .models import Session, resources, tenants, usage
|
||||||
|
|
||||||
# from .models.tenants import Tenant
|
# from .models.tenants import Tenant
|
||||||
|
|
||||||
@ -41,6 +38,7 @@ date_format = "%Y-%m-%dT%H:%M:%S"
|
|||||||
# Because why not be annoying in all the ways?
|
# Because why not be annoying in all the ways?
|
||||||
other_date_format = "%Y-%m-%dT%H:%M:%S.%f"
|
other_date_format = "%Y-%m-%dT%H:%M:%S.%f"
|
||||||
|
|
||||||
|
|
||||||
def get_meter(meter, start, end, auth):
|
def get_meter(meter, start, end, auth):
|
||||||
# Meter is a href; in this case, it has a set of fields with it already.
|
# Meter is a href; in this case, it has a set of fields with it already.
|
||||||
# print meter.link
|
# print meter.link
|
||||||
@ -58,23 +56,25 @@ def get_meter(meter, start, end, auth):
|
|||||||
]
|
]
|
||||||
fields = []
|
fields = []
|
||||||
for field in date_fields:
|
for field in date_fields:
|
||||||
fields.append( ("q.field", field["field"]) )
|
fields.append(("q.field", field["field"]))
|
||||||
fields.append( ("q.op", field["op"]) )
|
fields.append(("q.op", field["op"]))
|
||||||
fields.append( ("q.value", field["value"]))
|
fields.append(("q.value", field["value"]))
|
||||||
|
|
||||||
# Combine.
|
# Combine.
|
||||||
url = "&".join((meter.link, urllib.urlencode(fields) ))
|
url = "&".join((meter.link, urllib.urlencode(fields)))
|
||||||
|
|
||||||
r = requests.get(
|
r = requests.get(
|
||||||
meter.link,
|
meter.link,
|
||||||
headers={
|
headers={
|
||||||
"X-Auth-Token": auth,
|
"X-Auth-Token": auth,
|
||||||
"Content-Type":"application/json"}
|
"Content-Type": "application/json"}
|
||||||
)
|
)
|
||||||
return json.loads(r.text)
|
return json.loads(r.text)
|
||||||
|
|
||||||
|
|
||||||
class NotFound(BaseException): pass
|
class NotFound(BaseException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class keystone(KeystoneClient.Client):
|
class keystone(KeystoneClient.Client):
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ class keystone(KeystoneClient.Client):
|
|||||||
authenticator = self.auth_url
|
authenticator = self.auth_url
|
||||||
url = "%(url)s/tenants?%(query)s" % {
|
url = "%(url)s/tenants?%(query)s" % {
|
||||||
"url": authenticator,
|
"url": authenticator,
|
||||||
"query": urllib.urlencode({"name":name})
|
"query": urllib.urlencode({"name": name})
|
||||||
}
|
}
|
||||||
r = requests.get(url, headers={
|
r = requests.get(url, headers={
|
||||||
"X-Auth-Token": self.auth_token,
|
"X-Auth-Token": self.auth_token,
|
||||||
@ -97,6 +97,7 @@ class keystone(KeystoneClient.Client):
|
|||||||
# couldn't find it
|
# couldn't find it
|
||||||
raise NotFound
|
raise NotFound
|
||||||
|
|
||||||
|
|
||||||
class Artifice(object):
|
class Artifice(object):
|
||||||
"""Produces billable artifacts"""
|
"""Produces billable artifacts"""
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
@ -125,12 +126,12 @@ class Artifice(object):
|
|||||||
|
|
||||||
self.ceilometer = ceilometer(
|
self.ceilometer = ceilometer(
|
||||||
self.config["ceilometer"]["host"],
|
self.config["ceilometer"]["host"],
|
||||||
# Uses a lambda as ceilometer apparently wants to use it as a callable?
|
# Uses a lambda as ceilometer apparently wants
|
||||||
|
# to use it as a callable?
|
||||||
token=lambda: self.auth.auth_token
|
token=lambda: self.auth.auth_token
|
||||||
)
|
)
|
||||||
self._tenancy = None
|
self._tenancy = None
|
||||||
|
|
||||||
|
|
||||||
def host_to_dc(self, host):
|
def host_to_dc(self, host):
|
||||||
"""
|
"""
|
||||||
:param host: The name to use.
|
:param host: The name to use.
|
||||||
@ -139,7 +140,7 @@ class Artifice(object):
|
|||||||
"""
|
"""
|
||||||
# :raises: AttributeError, KeyError
|
# :raises: AttributeError, KeyError
|
||||||
# How does this get implemented ? Should there be a module injection?
|
# How does this get implemented ? Should there be a module injection?
|
||||||
return "Data Center 1" # For the moment, passthrough
|
return "Data Center 1" # For the moment, passthrough
|
||||||
# TODO: FIXME.
|
# TODO: FIXME.
|
||||||
|
|
||||||
def tenant(self, name):
|
def tenant(self, name):
|
||||||
@ -166,6 +167,7 @@ class Artifice(object):
|
|||||||
self._tenancy[t["name"]] = t
|
self._tenancy[t["name"]] = t
|
||||||
return self._tenancy
|
return self._tenancy
|
||||||
|
|
||||||
|
|
||||||
class Tenant(object):
|
class Tenant(object):
|
||||||
|
|
||||||
def __init__(self, tenant, conn):
|
def __init__(self, tenant, conn):
|
||||||
@ -195,7 +197,6 @@ class Tenant(object):
|
|||||||
# return super(Tenant, self).__getattr__(attr)
|
# return super(Tenant, self).__getattr__(attr)
|
||||||
return self.tenant[attr]
|
return self.tenant[attr]
|
||||||
|
|
||||||
|
|
||||||
def invoice(self, start, end):
|
def invoice(self, start, end):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -212,7 +213,7 @@ class Tenant(object):
|
|||||||
if ":" not in invoice_type:
|
if ":" not in invoice_type:
|
||||||
raise AttributeError("Invoice configuration incorrect! %s" % invoice_type)
|
raise AttributeError("Invoice configuration incorrect! %s" % invoice_type)
|
||||||
module, call = invoice_type.split(":")
|
module, call = invoice_type.split(":")
|
||||||
_package = __import__(module, globals(), locals(), [ call ])
|
_package = __import__(module, globals(), locals(), [call])
|
||||||
|
|
||||||
funct = getattr(_package, call)
|
funct = getattr(_package, call)
|
||||||
self.invoice_type = funct
|
self.invoice_type = funct
|
||||||
@ -222,7 +223,7 @@ class Tenant(object):
|
|||||||
|
|
||||||
def resources(self, start, end):
|
def resources(self, start, end):
|
||||||
if not self._resources:
|
if not self._resources:
|
||||||
date_fields = [{ "field": "project_id",
|
date_fields = [{"field": "project_id",
|
||||||
"op": "eq",
|
"op": "eq",
|
||||||
"value": self.tenant["id"]
|
"value": self.tenant["id"]
|
||||||
},
|
},
|
||||||
@ -256,18 +257,18 @@ class Tenant(object):
|
|||||||
|
|
||||||
for resource in self.resources(start, end):
|
for resource in self.resources(start, end):
|
||||||
# print dir(resource)
|
# print dir(resource)
|
||||||
rels = [link["rel"] for link in resource.links if link["rel"] != 'self' ]
|
rels = [link["rel"] for link in resource.links if link["rel"] != 'self']
|
||||||
if "storage.objects" in rels:
|
if "storage.objects" in rels:
|
||||||
# Unknown how this data layout happens yet.
|
# Unknown how this data layout happens yet.
|
||||||
storage.append(Resource(resource, self.conn))
|
storage.append(Resource(resource, self.conn))
|
||||||
pass
|
pass
|
||||||
elif "network" in rels:
|
elif "network" in rels:
|
||||||
# Have we seen the VM that owns this yet?
|
# Have we seen the VM that owns this yet?
|
||||||
networks.append(Resource(resource , self.conn))
|
networks.append(Resource(resource, self.conn))
|
||||||
elif "volumne" in rels:
|
elif "volumne" in rels:
|
||||||
volumes.append( Resource(resource, self.conn) )
|
volumes.append(Resource(resource, self.conn))
|
||||||
elif 'instance' in rels:
|
elif 'instance' in rels:
|
||||||
vms.append(Resource(resource, self.conn ))
|
vms.append(Resource(resource, self.conn))
|
||||||
|
|
||||||
datacenters = {}
|
datacenters = {}
|
||||||
region_tmpl = {
|
region_tmpl = {
|
||||||
@ -296,7 +297,6 @@ class Usage(object):
|
|||||||
self._objects = []
|
self._objects = []
|
||||||
self._volumes = []
|
self._volumes = []
|
||||||
|
|
||||||
|
|
||||||
# Replaces all the internal references with better references to
|
# Replaces all the internal references with better references to
|
||||||
# actual metered values.
|
# actual metered values.
|
||||||
# self._replace()
|
# self._replace()
|
||||||
@ -309,7 +309,7 @@ class Usage(object):
|
|||||||
VM = resources.VM(vm, self.start, self.end)
|
VM = resources.VM(vm, self.start, self.end)
|
||||||
md = vm["metadata"]
|
md = vm["metadata"]
|
||||||
host = md["host"]
|
host = md["host"]
|
||||||
VM.location = self.conn.host_to_dc( vm["metadata"]["host"] )
|
VM.location = self.conn.host_to_dc(vm["metadata"]["host"])
|
||||||
vms.append(VM)
|
vms.append(VM)
|
||||||
self._vms = vms
|
self._vms = vms
|
||||||
return self._vms
|
return self._vms
|
||||||
@ -374,7 +374,7 @@ class Resource(object):
|
|||||||
# return self.resource
|
# return self.resource
|
||||||
|
|
||||||
def meter(self, name, start, end):
|
def meter(self, name, start, end):
|
||||||
pass # Return a named meter
|
pass # Return a named meter
|
||||||
for meter in self.resource.links:
|
for meter in self.resource.links:
|
||||||
if meter["rel"] == name:
|
if meter["rel"] == name:
|
||||||
m = Meter(self, meter["href"], self.conn, start, end)
|
m = Meter(self, meter["href"], self.conn, start, end)
|
||||||
@ -382,7 +382,6 @@ class Resource(object):
|
|||||||
return m
|
return m
|
||||||
raise AttributeError("no such meter %s" % name)
|
raise AttributeError("no such meter %s" % name)
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
# print name
|
# print name
|
||||||
# print self.resource
|
# print self.resource
|
||||||
@ -402,6 +401,7 @@ class Resource(object):
|
|||||||
self._meters = meters
|
self._meters = meters
|
||||||
return self._meters
|
return self._meters
|
||||||
|
|
||||||
|
|
||||||
class Meter(object):
|
class Meter(object):
|
||||||
|
|
||||||
def __init__(self, resource, link, conn, start=None, end=None):
|
def __init__(self, resource, link, conn, start=None, end=None):
|
||||||
@ -528,8 +528,7 @@ class Artifact(object):
|
|||||||
self.end,
|
self.end,
|
||||||
)
|
)
|
||||||
session.add(this_usage)
|
session.add(this_usage)
|
||||||
session.commit() # Persist to Postgres
|
session.commit() # Persist to Postgres
|
||||||
|
|
||||||
|
|
||||||
def volume(self):
|
def volume(self):
|
||||||
"""
|
"""
|
||||||
@ -537,6 +536,7 @@ class Artifact(object):
|
|||||||
"""
|
"""
|
||||||
return sum([x["counter_volume"] for x in self.usage])
|
return sum([x["counter_volume"] for x in self.usage])
|
||||||
|
|
||||||
|
|
||||||
class Cumulative(Artifact):
|
class Cumulative(Artifact):
|
||||||
|
|
||||||
def volume(self):
|
def volume(self):
|
||||||
@ -596,8 +596,8 @@ class Gauge(Artifact):
|
|||||||
# We are now sorted into 1-hour blocks
|
# We are now sorted into 1-hour blocks
|
||||||
totals = []
|
totals = []
|
||||||
for block in blocks:
|
for block in blocks:
|
||||||
usage = max( [v["counter_volume"] for v in block])
|
usage = max([v["counter_volume"] for v in block])
|
||||||
totals.append( usage )
|
totals.append(usage)
|
||||||
|
|
||||||
# totals = [max(x, key=lambda val: val["counter_volume"] ) for x in blocks]
|
# totals = [max(x, key=lambda val: val["counter_volume"] ) for x in blocks]
|
||||||
# totals is now an array of max values per hour for a given month.
|
# totals is now an array of max values per hour for a given month.
|
||||||
@ -639,8 +639,8 @@ class Gauge(Artifact):
|
|||||||
if val["counter_volume"] in billable:
|
if val["counter_volume"] in billable:
|
||||||
difference = val["timestamp"] - last["timestamp"]
|
difference = val["timestamp"] - last["timestamp"]
|
||||||
|
|
||||||
# TODO:
|
# TODO: rethink this:
|
||||||
# possibly might need to account for sudden jumps
|
# might need to account for sudden jumps
|
||||||
# caused due to ceilometer down time:
|
# caused due to ceilometer down time:
|
||||||
if difference > datetime.timedelta(hours=1):
|
if difference > datetime.timedelta(hours=1):
|
||||||
# the timedelta should be the ceilometer interval.
|
# the timedelta should be the ceilometer interval.
|
||||||
@ -650,7 +650,7 @@ class Gauge(Artifact):
|
|||||||
else:
|
else:
|
||||||
# otherwise just add difference.
|
# otherwise just add difference.
|
||||||
uptime = uptime + difference.seconds
|
uptime = uptime + difference.seconds
|
||||||
|
|
||||||
last = val
|
last = val
|
||||||
|
|
||||||
return uptime
|
return uptime
|
||||||
|
Loading…
x
Reference in New Issue
Block a user