191 lines
5.0 KiB
Python
191 lines
5.0 KiB
Python
from . import Base
|
|
from sqlalchemy import Column, String, types, schema, ForeignKey
|
|
from sqlalchemy.orm import relationship, backref
|
|
# from .tenants import Tenant
|
|
from decimal import *
|
|
import math
|
|
|
|
|
|
class Resource(Base):
|
|
|
|
__tablename__ = "resources"
|
|
|
|
id = Column(String, primary_key=True)
|
|
type_ = Column(String)
|
|
tenant_id = Column(String, ForeignKey("tenants.id"), primary_key=True)
|
|
tenant = relationship("Tenant", backref=backref("tenants"))
|
|
|
|
|
|
class BaseModelConstruct(object):
|
|
|
|
def __init__(self, raw, start, end):
|
|
# raw is the raw data for this
|
|
self._raw = raw
|
|
self._location = None
|
|
self.start = start
|
|
self.end = end
|
|
|
|
@property
|
|
def amount(self):
|
|
return self.size
|
|
|
|
def __getitem__(self, item):
|
|
return self._raw[item]
|
|
|
|
def get(self, name):
|
|
# Returns a given name value thing?
|
|
# Based on patterning, this is expected to be a dict of usage
|
|
# information based on a meter, I guess?
|
|
return getattr(self, name)
|
|
|
|
def _fetch_meter_name(self, name):
|
|
return name
|
|
|
|
def usage(self):
|
|
dct = {}
|
|
for meter in self.relevant_meters:
|
|
meter = self._fetch_meter_name(meter)
|
|
try:
|
|
vol = self._raw.meter(meter, self.start, self.end).volume()
|
|
dct[meter] = vol
|
|
except AttributeError:
|
|
# This is OK. We're not worried about non-existent meters,
|
|
# I think. For now, anyway.
|
|
pass
|
|
return dct
|
|
|
|
def save(self):
|
|
for meter in self.relevant_meters:
|
|
meter = self._fetch_meter_name(meter)
|
|
try:
|
|
self._raw.meter(meter, self.start, self.end).save()
|
|
except AttributeError:
|
|
# This is OK. We're not worried about non-existent meters,
|
|
# I think. For now, anyway.
|
|
pass
|
|
|
|
|
|
class VM(BaseModelConstruct):
|
|
# The only relevant meters of interest are the type of the interest
|
|
# and the amount of network we care about.
|
|
# Oh, and floating IPs.
|
|
relevant_meters = ["state"]
|
|
|
|
type = "vm"
|
|
|
|
def _fetch_meter_name(self, name):
|
|
if name == "instance:<type>":
|
|
return "instance:%s" % self.type
|
|
return name
|
|
|
|
@property
|
|
def uptime(self):
|
|
|
|
# this NEEDS to be moved to a config file or
|
|
# possibly be queried from Clerk?
|
|
tracked = [1, 2, 3, 6, 7]
|
|
|
|
seconds = self.usage()['state'].uptime(tracked)
|
|
|
|
# in hours, rounded up:
|
|
uptime = math.ceil((seconds / 60.0) / 60.0)
|
|
|
|
class Amount(object):
|
|
def volume(self):
|
|
return Decimal(uptime)
|
|
|
|
def __str__(self):
|
|
return str(uptime) + " hr"
|
|
|
|
def __repr__(self):
|
|
return str(self)
|
|
return Amount()
|
|
|
|
@property
|
|
def flavor(self):
|
|
# TODO FIgure out what the hell is going on with ceilometer here,
|
|
# and why flavor.name isn't always there, and why
|
|
# sometimes instance_type is needed instead....
|
|
try:
|
|
# print "\"flavor.name\" was used"
|
|
return self._raw["metadata"]["flavor.name"]
|
|
except KeyError:
|
|
# print "\"instance_type\" was used"
|
|
return self._raw["metadata"]["instance_type"]
|
|
|
|
@property
|
|
def size(self):
|
|
return self.type
|
|
|
|
@property
|
|
def memory(self):
|
|
return self._raw["metadata"]["memory"]
|
|
|
|
@property
|
|
def cpus(self):
|
|
return self._raw["metadata"]["vcpus"]
|
|
|
|
@property
|
|
def state(self):
|
|
return self._raw["metadata"]["state"]
|
|
|
|
@property
|
|
def name(self):
|
|
return self._raw["metadata"]["display_name"]
|
|
|
|
|
|
class FloatingIP(BaseModelConstruct):
|
|
|
|
relevant_meters = ["ip.floating"]
|
|
|
|
type = "ip" # object storage
|
|
|
|
@property
|
|
def duration(self):
|
|
# How much use this had.
|
|
return Decimal(self.usage()["ip.floating"].volume())
|
|
# Size is a gauge measured every 10 minutes.
|
|
# So that needs to be compressed to 60-minute intervals
|
|
|
|
|
|
class Object(BaseModelConstruct):
|
|
|
|
relevant_meters = ["storage.objects.size"]
|
|
|
|
type = "object" # object storage
|
|
|
|
@property
|
|
def size(self):
|
|
# How much use this had.
|
|
return Decimal(self.usage()["storage.objects.size"].volume())
|
|
# Size is a gauge measured every 10 minutes.
|
|
# So that needs to be compressed to 60-minute intervals
|
|
|
|
|
|
class Volume(BaseModelConstruct):
|
|
|
|
relevant_meters = ["volume.size"]
|
|
|
|
type = "volume"
|
|
|
|
@property
|
|
def size(self):
|
|
# Size of the thing over time.
|
|
return Decimal(self.usage()["volume.size"].volume())
|
|
|
|
|
|
class Network(BaseModelConstruct):
|
|
relevant_meters = ["network.outgoing.bytes", "network.incoming.bytes"]
|
|
|
|
type = "network"
|
|
|
|
@property
|
|
def outgoing(self):
|
|
# Size of the thing over time.
|
|
return Decimal(self.usage()["network.outgoing.bytes"].volume())
|
|
|
|
@property
|
|
def incoming(self):
|
|
# Size of the thing over time.
|
|
return Decimal(self.usage()["network.incoming.bytes"].volume())
|