Some more pep8 formatting tidying up.

This commit is contained in:
adriant 2014-01-15 15:46:07 +13:00
parent 5cb1ba97f3
commit 757adef5e2
2 changed files with 47 additions and 44 deletions

View File

@ -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

View File

@ -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