示例#1
0
def migrate(replace=False,yearsback=10,dryrun=False):
    api = eeDbAPI()
    devices = api.getPeriphList()
    eetsdb  = eeTSDB('localhost',4242)
    client = RESTOpenTSDBClient("localhost",4242)
    for dev in devices:
        # check that the metric is in eetsdbMapping
        if not dev.periph_id in eetsdbMapping:
            print(("Skipping", dev.periph_id, dev.name, dev.room_name, dev.usage_name))
            continue
        # check if the TS is there already. If yes, look for the last point and continue from there
        ts = eetsdb.mkTimeseries(dev)
        if not dryrun: eetsdb.registerTS(ts)
        begin = datetime.now()-relativedelta(years=yearsback)
        try:
            res = client.search("LOOKUP",metric=ts.metric, tags=ts.tags)
            if res["totalResults"]>1 :
                print("Time series:")
                pprint.pprint(ts.getMap())
                print("Search result:")
                pprint.pprint(res)
                raise RuntimeError("The timeseries is ambiguous. This should not happen.")
            elif res["totalResults"]==1:
                tsuid = res["results"][0]["tsuid"]
                sq = OpenTSDBtsuidSubQuery("sum",[tsuid])
                if replace:
                    query = OpenTSDBQuery([sq],"%dy-ago"%yearsback,delete=True)
                    if not dryrun: answer = client.query(query)
                    begin = datetime.now()-relativedelta(years=yearsback)
                    time.sleep(5)
                else:
                    query = OpenTSDBQuery([sq],"%dy-ago"%yearsback)
                    answer = client.query(query)
                    if len(answer)>0:
                        last = max([ int(k) for k in list(answer[0]["dps"].keys()) ])
                        begin = datetime.fromtimestamp(last+1)
            # migrate that dev
            print(("migrating",dev.periph_id, dev.name, dev.room_name, dev.usage_name, "from", begin))
            if not dryrun: eetsdb.migrate(device=dev,start_date=begin, end_date=None)
        except OpenTSDBError as e:
            print(("Exception while processing",dev.periph_id, dev.name, dev.room_name, dev.usage_name,"Skipping."))
            raise
示例#2
0
def migrate(replace=False,yearsback=10):
    api = eeDbAPI()
    devices = api.getPeriphList()
    eetsdb  = eeTSDB('localhost',4242)
    client = RESTOpenTSDBClient("localhost",4242)
    for dev in devices:
        # check that the metric is in eetsdbMapping
        if not dev.periph_id in eetsdbMapping:
            print "Skipping", dev.periph_id, dev.name, dev.room_name, dev.usage_name
            continue
        # check if the TS is there already. If yes, look for the last point and continue from there
        ts = eetsdb.mkTimeseries(dev)
        eetsdb.registerTS(ts)
        begin = datetime.now()-relativedelta(years=yearsback)
        try:
            res = client.search("LOOKUP",metric=ts.metric, tags=ts.tags)
            if res["totalResults"]>1 :
                print "Time series:"
                pprint.pprint(ts.getMap())
                print "Search result:"
                pprint.pprint(res)
                raise RuntimeError("The timeseries is ambiguous. This should not happen.")
            elif res["totalResults"]==1:
                tsuid = res["results"][0]["tsuid"]
                sq = OpenTSDBtsuidSubQuery("sum",[tsuid])
                if replace:
                    query = OpenTSDBQuery([sq],"%dy-ago"%yearsback,delete=True)
                    answer = client.query(query)
                    begin = datetime.now()-relativedelta(years=yearsback)
                    time.sleep(5)
                else:
                    query = OpenTSDBQuery([sq],"%dy-ago"%yearsback)
                    answer = client.query(query)
                    if len(answer)>0:
                        last = max([ int(k) for k in answer[0]["dps"].keys() ])
                        begin = datetime.fromtimestamp(last+1)
            # migrate that dev
            print "migrating",dev.periph_id, dev.name, dev.room_name, dev.usage_name, "from", begin
            eetsdb.migrate(device=dev,start_date=begin, end_date=None)
        except OpenTSDBError as e:
            print "Exception while processing",dev.periph_id, dev.name, dev.room_name, dev.usage_name,"Skipping."
            raise
示例#3
0
class eeTSDB:
    """Simple utility to migrate the history from eedb to eetsdb"""

    def __init__(self,host,port):
        self.host_ = host
        self.port_ = port
        self.client_ = OpenTSDBClient(self.host_, self.port_)

    def migrate(self,device,start_date=None, end_date=None, history = None, lastValue=None): 
        """Main method: give device and time range to migrate to openTSDB"""
        self.debugId = device.periph_id
        timeseries = self.mkTimeseries(device)
        self.registerTS(timeseries)
        timeseries.loadFrom(self.client_)
        if history is None:
            history = device.getHistory(start_date, end_date)
        measurements = self.mkMeasurements(timeseries,history)
        if len(measurements)>0:
            print "Inserting %d measurements for the following timeseries:"%len(measurements)
            print timeseries.getMap(full=False).__str__()
        self.insertHistory(measurements)
        self.addAnnotation(timeseries)

    def registerTS(self, timeseries):
        try:
            res = self.client_.search("LOOKUP",metric=timeseries.metric, tags=timeseries.tags)
        except OpenTSDBError:
            timeseries.assign_uid(self.client_)

    def insertHistory(self, measurements):
        return self.client_.put_measurements(measurements, summary=True, compress=True)

    def mkTimeseries(self,device):
        try:
            lookup = self.client_.search("LOOKUP",tags={"periph_id":str(device.periph_id)})
            if lookup["totalResults"]==0: # create if needed
                metric = eetsdbMapping[int(device.periph_id)]
                tags = { "periph_id":str(device.periph_id), 
                         "room":self.cureString(device.room_name),
                         "name":self.cureString(device.name)}
                return OpenTSDBTimeSeries(metric,tags)
            elif lookup["totalResults"]==1: # take existing one if possible
                return OpenTSDBTimeSeries(tsuid=lookup["results"][0]["tsuid"]).loadFrom(self.client_)
            else: # abort in case of ambiguity
                raise RuntimeError("More than one time series with tsuid = %s"%str(device.periph_id),lookup)
        except OpenTSDBError:
                metric = eetsdbMapping[int(device.periph_id)]
                tags = { "periph_id":str(device.periph_id), 
                         "room":self.cureString(device.room_name),
                         "name":self.cureString(device.name)}
                return OpenTSDBTimeSeries(metric,tags)

    def mkMeasurements(self,timeseries,history):
        # history is a vector of pairs (measurement,timestamp)
        history = self.cureValues(timeseries,history)
        if eedbintegration[int(timeseries.tags["periph_id"])][0]:
            conversionFactor=eedbintegration[int(timeseries.tags["periph_id"])][2]
            samplingPeriod=eedbintegration[int(timeseries.tags["periph_id"])][1]
            last= self.getLastValue(timeseries)
            return [OpenTSDBMeasurement(timeseries, int(timestamp.strftime("%s")),value) for (value,timestamp) in self.cummulative(history, conversionFactor, samplingPeriod, last)]
        else:
            return [OpenTSDBMeasurement(timeseries, int(timestamp.strftime("%s")),value) for (value,timestamp) in history]

    def addAnnotation(self,timeseries, isGlobal=False):
        timeseries.loadFrom(self.client_)
        tsuid = timeseries.metadata.tsuid
        description = "Migrated from eedb"
        custom={"host":socket.gethostname()}
        self.client_.set_annotation(int(datetime.now().strftime("%s")), tsuid=tsuid, description=description, custom=custom)

    def cureString(self,thestring):
	asciichars = string.ascii_letters + "0123456789-_./"
        return ''.join([c for c in thestring.replace(" ","_").replace("[","_").replace("]","_") if c in asciichars or ud.category(unicode(c)) in ['Ll', 'Lu']])

    def cureValues(self,timeseries,history):
        recipeName = eetsdbrecipes.get(int(timeseries.tags["periph_id"]), None)
        recipe = getattr(cureValues, recipeName) if recipeName is not None else lambda x:x
        return [(recipe(self.translateValue(value)),timestamp) for (value,timestamp) in history]

    def translateValue(self,value):
	if unidecode(value).lower() in eetsdbvalues: return eetsdbvalues[unidecode(value).lower()]
        try:
            return float(''.join([c for c in value if c in "-0123456789."]))
        except:
            print value,"cannot be translated"
            return 0

    def cummulative(self,inputHistory, conversionFactor = 3600000., samplingPeriod = None, last = None, integrationMode="trapeze"):
    	""" Integrates the input to return a cummulative distribution.
    	    By default, it uses the trapeze integration rule.
    	    If samplingPeriod is set, each point is taken independently over that time.
    	    The default conversion factor works for both electricity (watt*s -> kWh) and gaz (dm3/h*s -> m3)
    	"""
        data = sorted(inputHistory, key=lambda entry:entry[1])
        output = []
    	for i,((d0,t0),(d1,t1)) in enumerate(pairwise(data)):
    		if last is None:
    			last = 0
                        output.append((0,t0))
    		if samplingPeriod is None:
                        if integrationMode=="trapeze":
        			last += (((d0+d1)/2.)*(t1-t0).total_seconds())/conversionFactor # good approximation for continuous functions
                        else:
                                last += d0*(t1-t0).total_seconds()/conversionFactor # best when the series "updates on changes"
    		else:
    			last += d0*samplingPeriod/conversionFactor # when measurements are defined on a fixed interval and are not continuous
                output.append((last,t1))
    	return output

    def getLastValue(self,timeseries):
        # issue with query last, so do it by hand with some large backsearch. Heavy...
        sq = OpenTSDBtsuidSubQuery("sum",[timeseries.metadata.tsuid])
        query = OpenTSDBQuery([sq],"1y-ago")
        answer = self.client_.query(query)
        if len(answer)>0:
            if len(answer[0]["dps"].keys()) >0:
                last = max([ int(k) for k in answer[0]["dps"].keys()  ])
                return answer[0]["dps"][str(last)]
            else:
                print answer
        else:
            return None
示例#4
0
class eeTSDB:
    """Simple utility to migrate the history from eedb to eetsdb"""
    def __init__(self, host, port):
        self.host_ = host
        self.port_ = port
        self.client_ = OpenTSDBClient(self.host_, self.port_)

    def migrate(self,
                device,
                start_date=None,
                end_date=None,
                history=None,
                lastValue=None):
        """Main method: give device and time range to migrate to openTSDB"""
        self.debugId = device.periph_id
        timeseries = self.mkTimeseries(device)
        self.registerTS(timeseries)
        timeseries.loadFrom(self.client_)
        if history is None:
            history = device.getHistory(start_date, end_date)
        measurements = self.mkMeasurements(timeseries, history)
        if len(measurements) > 0:
            print(("Inserting %d measurements for the following timeseries:" %
                   len(measurements)))
            print((timeseries.getMap(full=False).__str__()))
        self.insertHistory(measurements)
        self.addAnnotation(timeseries)

    def registerTS(self, timeseries):
        try:
            res = self.client_.search("LOOKUP",
                                      metric=timeseries.metric,
                                      tags=timeseries.tags)
        except OpenTSDBError:
            timeseries.assign_uid(self.client_)

    def insertHistory(self, measurements):
        return self.client_.put_measurements(measurements,
                                             summary=True,
                                             compress=True)

# TS METADATA:
# self.displayName = kwargs.get("displayName",'') # TODO: put most recent name in metadata
# self.units = kwargs.get("units",'') #TODO: put units in metadata. Should come from the yaml cfg
# self.custom = kwargs["custom"] if kwargs.get("custom",None) is not None else {} # TODO: other: creation_date,usage_name

    def mkTimeseries(self, device):
        try:
            lookup = self.client_.search(
                "LOOKUP", tags={"periph_id": str(device.periph_id)})
            if lookup["totalResults"] == 0:  # create if needed
                metric = eetsdbMapping[int(device.periph_id)]
                tags = {
                    "periph_id": str(device.periph_id),
                    "room": self.cureString(device.room_name),
                    "name": self.cureString(device.name)
                }
                return OpenTSDBTimeSeries(metric, tags)
            elif lookup["totalResults"] == 1:  # take existing one if possible
                return OpenTSDBTimeSeries(
                    tsuid=lookup["results"][0]["tsuid"]).loadFrom(self.client_)
            else:  # abort in case of ambiguity
                raise RuntimeError(
                    "More than one time series with tsuid = %s" %
                    str(device.periph_id), lookup)
        except OpenTSDBError:
            metric = eetsdbMapping[int(device.periph_id)]
            tags = {
                "periph_id": str(device.periph_id),
                "room": self.cureString(device.room_name),
                "name": self.cureString(device.name)
            }
            return OpenTSDBTimeSeries(metric, tags)

    def mkMeasurements(self, timeseries, history):
        # history is a vector of pairs (measurement,timestamp)
        history = self.cureValues(timeseries, history)
        if eedbintegration[int(timeseries.tags["periph_id"])][0]:
            conversionFactor = eedbintegration[int(
                timeseries.tags["periph_id"])][2]
            samplingPeriod = eedbintegration[int(
                timeseries.tags["periph_id"])][1]
            last = self.getLastValue(timeseries)
            return [
                OpenTSDBMeasurement(timeseries, int(timestamp.strftime("%s")),
                                    value)
                for (value, timestamp) in self.cummulative(
                    history, conversionFactor, samplingPeriod, last)
            ]
        else:
            return [
                OpenTSDBMeasurement(timeseries, int(timestamp.strftime("%s")),
                                    value) for (value, timestamp) in history
            ]

    def addAnnotation(self, timeseries, isGlobal=False):
        timeseries.loadFrom(self.client_)
        tsuid = timeseries.metadata.tsuid
        description = "Migrated from eedb"
        custom = {"host": socket.gethostname()}
        self.client_.set_annotation(int(datetime.now().strftime("%s")),
                                    tsuid=tsuid,
                                    description=description,
                                    custom=custom)

    def cureString(self, thestring):
        asciichars = string.ascii_letters + "0123456789-_./"
        return ''.join([
            c for c in thestring.replace(" ", "_").replace("[", "_").replace(
                "]", "_")
            if c in asciichars or ud.category(str(c)) in ['Ll', 'Lu']
        ])

    def cureValues(self, timeseries, history):
        recipeName = eetsdbrecipes.get(int(timeseries.tags["periph_id"]), None)
        recipe = getattr(cureValues,
                         recipeName) if recipeName is not None else lambda x: x
        return [
            x for x in [(recipe(self.translateValue(value)), timestamp)
                        for (value, timestamp) in history] if x[0] is not None
        ]

    def translateValue(self, value):
        if unidecode(value).lower() in eetsdbvalues:
            return eetsdbvalues[unidecode(value).lower()]
        try:
            return float(''.join([c for c in value if c in "-0123456789."]))
        except:
            print((value, "cannot be translated"))
            return 0

    def cummulative(self,
                    inputHistory,
                    conversionFactor=3600000.,
                    samplingPeriod=None,
                    last=None,
                    integrationMode="trapeze"):
        """ Integrates the input to return a cummulative distribution.
            By default, it uses the trapeze integration rule.
            If samplingPeriod is set, each point is taken independently over that time.
            The default conversion factor works for both electricity (watt*s -> kWh) and gaz (dm3/h*s -> m3)
        """
        data = sorted(inputHistory, key=lambda entry: entry[1])
        output = []
        for i, ((d0, t0), (d1, t1)) in enumerate(pairwise(data)):
            if last is None:
                last = 0
                output.append((0, t0))
            else:
                #TODO: fix this: have to add one entry for the first measurement.
                # for that, one needs last, d0, t0, but also the time of the last measurement
                pass
            if samplingPeriod is None:
                if integrationMode == "trapeze":
                    last += (
                        ((d0 + d1) / 2.) * (t1 - t0).total_seconds()
                    ) / conversionFactor  # good approximation for continuous functions
                else:
                    last += d0 * (t1 - t0).total_seconds(
                    ) / conversionFactor  # best when the series "updates on changes"
            else:
                last += d0 * samplingPeriod / conversionFactor  # when measurements are defined on a fixed interval and are not continuous
            output.append((last, t1))
        return output

    def getLastValue(self, timeseries):
        # issue with query last, so do it by hand with some large backsearch. Heavy...
        sq = OpenTSDBtsuidSubQuery("sum", [timeseries.metadata.tsuid])
        query = OpenTSDBQuery([sq], "1y-ago")
        answer = self.client_.query(query)
        if len(answer) > 0:
            if len(list(answer[0]["dps"].keys())) > 0:
                last = max([int(k) for k in list(answer[0]["dps"].keys())])
                return answer[0]["dps"][str(last)]
            else:
                print(answer)
        else:
            return None