diff --git a/artifice/interface.py b/artifice/interface.py index b30b4d0..f075e8b 100644 --- a/artifice/interface.py +++ b/artifice/interface.py @@ -604,21 +604,23 @@ class Gauge(Artifact): # print totals return sum(totals) - def uptime(self): + def uptime(self, billable): """Calculates uptime accurately for the given 'billable' states. - Will ignore all other states. - - Relies heavily on the existence of a state meter.""" + - Will ignore all other states. + - Relies heavily on the existence of a state meter, and + should only ever be called on the state meter. - # this NEEDS to be moved to a config file - billable = [1, 2, 3, 6, 7] + Returns: uptime in seconds""" usage = sorted(self.usage, key=lambda x: x["timestamp"]) last = usage[0] try: - last["timestamp"] = datetime.datetime.strptime(last["timestamp"], date_format) + last["timestamp"] = datetime.datetime.strptime(last["timestamp"], + date_format) except ValueError: - last["timestamp"] = datetime.datetime.strptime(last["timestamp"], other_date_format) + last["timestamp"] = datetime.datetime.strptime(last["timestamp"], + other_date_format) except TypeError: pass @@ -626,15 +628,28 @@ class Gauge(Artifact): for val in usage[1:]: try: - val["timestamp"] = datetime.datetime.strptime(val["timestamp"], date_format) + val["timestamp"] = datetime.datetime.strptime(val["timestamp"], + date_format) except ValueError: - val["timestamp"] = datetime.datetime.strptime(val["timestamp"], other_date_format) + val["timestamp"] = datetime.datetime.strptime(val["timestamp"], + other_date_format) except TypeError: pass if val["counter_volume"] in billable: difference = val["timestamp"] - last["timestamp"] - uptime = uptime + difference.seconds + + # TODO: + # possibly might need to account for sudden jumps + # caused due to ceilometer down time: + if difference > datetime.timedelta(hours=1): + # the timedelta should be the ceilometer interval. + # do nothing if different greater than twice interval? + # or just add interval length to uptime. + pass + else: + # otherwise just add difference. + uptime = uptime + difference.seconds last = val diff --git a/artifice/models/resources.py b/artifice/models/resources.py index 1bcf67d..6f552fb 100644 --- a/artifice/models/resources.py +++ b/artifice/models/resources.py @@ -5,6 +5,7 @@ from sqlalchemy.orm import relationship, backref from decimal import * import math + class Resource(Base): __tablename__ = "resources" @@ -33,8 +34,8 @@ class BaseModelConstruct(object): 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? + # 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): @@ -68,7 +69,8 @@ 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", "instance", "cpu", "instance:", "network.incoming.bytes", "network.outgoing.bytes"] + relevant_meters = ["state", "instance", "cpu", "instance:", + "network.incoming.bytes", "network.outgoing.bytes"] def _fetch_meter_name(self, name): if name == "instance:": @@ -81,11 +83,16 @@ class VM(BaseModelConstruct): @property def amount(self): - seconds = self.usage()['state'].uptime() + + # this NEEDS to be moved to a config file or + # possibly be queried from Clerk? + billable = [1, 2, 3, 6, 7] + + seconds = self.usage()['state'].uptime(billable) # in hours, rounded up: - uptime = math.ceil((seconds/60.0)/60.0) - + uptime = math.ceil((seconds / 60.0) / 60.0) + class Amount(object): def volume(self): return Decimal(uptime) @@ -99,10 +106,10 @@ class VM(BaseModelConstruct): @property def type(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: + # 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: @@ -139,21 +146,22 @@ class VM(BaseModelConstruct): def name(self): return self._raw["metadata"]["display_name"] + class Object(BaseModelConstruct): relevant_meters = ["storage.objects.size"] - type = "object" # object storage + type = "object" # object storage @property def size(self): # How much use this had. - return self._raw.meter("storage.objects.size", self.start, self.end).volume() + return self._raw.meter("storage.objects.size", + self.start, self.end).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"] @@ -167,5 +175,6 @@ class Volume(BaseModelConstruct): # Size of the thing over time. return self._raw.meter("volume.size", self.start, self.end).volume() + class Network(BaseModelConstruct): - relevant_meters = ["ip.floating"] \ No newline at end of file + relevant_meters = ["ip.floating"]