From 5ee411ba2370ec13e4457a9aa5231f7b2aaa9e3b Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 1 Apr 2017 18:30:31 -0500 Subject: [PATCH] Add `rattail export-hotcooler` command, for initial hotcooler support ..we'll see where this goes.. --- rattail_tempmon/commands.py | 19 +- rattail_tempmon/config.py | 6 + rattail_tempmon/hotcooler/__init__.py | 0 .../hotcooler/importing/__init__.py | 0 .../hotcooler/importing/tempmon.py | 181 ++++++++++++++++++ setup.py | 6 +- 6 files changed, 205 insertions(+), 7 deletions(-) create mode 100644 rattail_tempmon/hotcooler/__init__.py create mode 100644 rattail_tempmon/hotcooler/importing/__init__.py create mode 100644 rattail_tempmon/hotcooler/importing/tempmon.py diff --git a/rattail_tempmon/commands.py b/rattail_tempmon/commands.py index 0980fc0..941cc72 100644 --- a/rattail_tempmon/commands.py +++ b/rattail_tempmon/commands.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8; -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2016 Lance Edgar +# Copyright © 2010-2017 Lance Edgar # # This file is part of Rattail. # @@ -26,10 +26,19 @@ Tempmon commands from __future__ import unicode_literals, absolute_import -from rattail.commands import Subcommand +from rattail import commands -class TempmonClient(Subcommand): +class ExportHotCooler(commands.ImportSubcommand): + """ + Export data from Rattail-Tempmon to HotCooler + """ + name = 'export-hotcooler' + description = __doc__.strip() + handler_spec = 'rattail_tempmon.hotcooler.importing.tempmon:FromTempmonToHotCooler' + + +class TempmonClient(commands.Subcommand): """ Manage the tempmon-client daemon """ @@ -59,7 +68,7 @@ class TempmonClient(Subcommand): daemon.stop() -class TempmonServer(Subcommand): +class TempmonServer(commands.Subcommand): """ Manage the tempmon-server daemon """ diff --git a/rattail_tempmon/config.py b/rattail_tempmon/config.py index 6cf8d27..99f2364 100644 --- a/rattail_tempmon/config.py +++ b/rattail_tempmon/config.py @@ -51,6 +51,12 @@ class TempmonConfigExtension(ConfigExtension): key = 'tempmon' def configure(self, config): + + # tempmon config.tempmon_engines = get_engines(config, section='rattail_tempmon.db') config.tempmon_engine = config.tempmon_engines.get('default') Session.configure(bind=config.tempmon_engine) + + # hotcooler + config.hotcooler_engines = get_engines(config, section='hotcooler.db') + config.hotcooler_engine = config.hotcooler_engines.get('default') diff --git a/rattail_tempmon/hotcooler/__init__.py b/rattail_tempmon/hotcooler/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rattail_tempmon/hotcooler/importing/__init__.py b/rattail_tempmon/hotcooler/importing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rattail_tempmon/hotcooler/importing/tempmon.py b/rattail_tempmon/hotcooler/importing/tempmon.py new file mode 100644 index 0000000..5299cc0 --- /dev/null +++ b/rattail_tempmon/hotcooler/importing/tempmon.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- +""" +HotCooler -> Tempmon importers +""" + +from __future__ import unicode_literals, absolute_import + +import datetime +from uuid import UUID + +import sqlalchemy as sa +from sqlalchemy import orm +import sqlsoup + +from rattail import importing +from rattail.util import OrderedDict +from rattail.time import make_utc +from rattail_tempmon.db import Session as TempmonSession, model as tempmon + + +class FromTempmonToHotCooler(importing.FromSQLAlchemyHandler, importing.ToSQLAlchemyHandler): + """ + Handler for Tempmon -> HotCooler data import + """ + host_title = "Tempmon" + local_title = "HotCooler" + + def make_host_session(self): + return TempmonSession() + + def make_session(self): + self.soup = sqlsoup.SQLSoup(self.config.hotcooler_engine) + return self.soup.session + + def get_importers(self): + importers = OrderedDict() + importers['Client'] = ClientImporter + importers['Probe'] = ProbeImporter + importers['Reading'] = ReadingImporter + return importers + + def get_importer_kwargs(self, key, **kwargs): + kwargs = super(FromTempmonToHotCooler, self).get_importer_kwargs(key, **kwargs) + kwargs['soup'] = self.soup + return kwargs + + +class FromTempmon(importing.FromSQLAlchemy): + """ + Base class for importers where Tempmon is host + """ + + def normalize_host_object(self, obj): + data = dict([(field, getattr(obj, field, None)) for field in self.fields]) + data['uuid'] = str(UUID(data['uuid'])) + for field in self.fields: + if isinstance(data[field], datetime.datetime): + data[field] = make_utc(data[field], tzinfo=True) + return data + + +class ToHotCooler(importing.ToSQLAlchemy): + """ + Base class for importers where HotCooler is local/target + """ + key = 'uuid' + + @property + def model_mapper(self): + soup_model = self.get_soup_model(self.soup) + return orm.class_mapper(soup_model) + + def cache_local_data(self, host_data=None): + soup_model = self.get_soup_model(self.soup) + return self.cache_model(soup_model, key=self.get_cache_key, + query=self.cache_query(), + normalizer=self.normalize_cache_object) + + def cache_query(self): + soup_model = self.get_soup_model(self.soup) + return self.session.query(soup_model) + + def normalize_local_object(self, obj): + data = super(ToHotCooler, self).normalize_local_object(obj) + for field in self.fields: + if isinstance(data[field], datetime.datetime): + data[field] = make_utc(data[field], tzinfo=True) + return data + + def make_object(self): + soup_model = self.get_soup_model(self.soup) + return soup_model() + + def create_object(self, key, host_data): + # TODO: this seems hacky..? + return super(importing.ToSQLAlchemy, self).create_object(key, host_data) + + +class ClientImporter(FromTempmon, ToHotCooler): + """ + Tempmon -> HotCooler importer for Client data + """ + host_model_class = tempmon.Client + supported_fields = [ + 'uuid', + 'config_key', + 'hostname', + 'location', + 'delay', + 'enabled', + 'online', + ] + + def get_soup_model(self, soup): + return soup.client + + +class ProbeImporter(FromTempmon, ToHotCooler): + """ + Tempmon -> HotCooler importer for Probe data + """ + host_model_class = tempmon.Probe + supported_fields = [ + 'uuid', + 'client_id', + 'config_key', + 'appliance_type', + 'description', + 'device_path', + 'enabled', + 'good_temp_min', + 'good_temp_max', + 'critical_temp_min', + 'critical_temp_max', + 'therm_status_timeout', + 'status_alert_timeout', + ] + + def get_soup_model(self, soup): + return soup.probe + + def setup(self): + self.clients = self.cache_model(self.soup.client, key='uuid') + + def normalize_host_object(self, probe): + data = super(ProbeImporter, self).normalize_host_object(probe) + uuid = str(UUID(probe.client_uuid)) + client = self.clients.get(uuid) + data['client_id'] = client.id + return data + + +class ReadingImporter(FromTempmon, ToHotCooler): + """ + Tempmon -> HotCooler importer for Reading data + """ + host_model_class = tempmon.Reading + supported_fields = [ + 'uuid', + 'client_id', + 'probe_id', + 'taken', + 'degrees_f', + ] + + def get_soup_model(self, soup): + return soup.reading + + def setup(self): + self.clients = self.cache_model(self.soup.client, key='uuid') + self.probes = self.cache_model(self.soup.probe, key='uuid') + + def normalize_host_object(self, reading): + data = super(ReadingImporter, self).normalize_host_object(reading) + uuid = str(UUID(reading.client_uuid)) + client = self.clients.get(uuid) + data['client_id'] = client.id + uuid = str(UUID(reading.probe_uuid)) + probe = self.probes.get(uuid) + data['probe_id'] = probe.id + return data diff --git a/setup.py b/setup.py index 2592bac..d554cc7 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8; -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2016 Lance Edgar +# Copyright © 2010-2017 Lance Edgar # # This file is part of Rattail. # @@ -66,6 +66,7 @@ requires = [ 'rattail[db]', # 0.7.46 'six', # 1.10.0 + 'sqlsoup', # 0.9.1 ] @@ -97,6 +98,7 @@ setup( entry_points = { 'rattail.commands': [ + 'export-hotcooler = rattail_tempmon.commands:ExportHotCooler', 'tempmon-client = rattail_tempmon.commands:TempmonClient', 'tempmon-server = rattail_tempmon.commands:TempmonServer', ],